npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@doist/automations-mcp

v1.3.0

Published

MCP server and importable AI tools for Todoist Automations

Downloads

1,027

Readme

@doist/automations-mcp

The MCP server for Todoist Automations: the tools that give an agent the same access to a user's automations that the tda CLI gives, packaged for the hosted MCP server at ai.todoist.net. The design and the rollout it is part of are in the spec.

What it exports

getMcpServer({ token, baseUrl }) builds an McpServer over one user's Automations, bound to the bearer token it is given: a delegated Todoist OAuth token with the automations audience, or a Todoist personal token.

validateAutomationsToken(token, baseUrl) classifies a token before any tool runs, with one status-only call to the automations list: valid, invalid (401) or forbidden (403 with an insufficient_scope challenge). A 403 without that challenge counts as valid on purpose: it is a refusal consent cannot lift, such as the waiting list, so each tool surfaces the backend's own message instead of the client looping through OAuth. Any other status throws AutomationsTokenValidationError with the status on it, which the hosted server treats as transient for 5xx.

That is the whole published surface. The tools themselves are typed against @doist/automations-sdk, which is not published, so they are reached through the server rather than exported, and the build refuses to emit a declaration that would leave a consumer with an import it cannot resolve.

Chat turns

start-conversation and continue-conversation each run one durable server turn inside the tool call, the way tda chat does in a process: the call blocks until the agent stops, which can take minutes, and reports liveness every ten seconds through notifications/progress when the client sent a progress token, or a debug log message otherwise. Cancelling the call aborts the upstream turn; the partial reply is persisted and continue-conversation resumes it. The shared logic is @doist/automations-sdk/chat-turn, so the CLI and this package cannot drift on how a pending action is read or a connection resolved.

Running it locally

Everything here can run against a real account without the hosted server. AUTOMATIONS_API_KEY is a Todoist personal token or the output of tda auth token view; AUTOMATIONS_BASE_URL points at staging or a local backend and defaults to production.

npm run build:core                                   # once, from the monorepo root
npm run build:mcp                                    # produces apps/mcp/dist
npm --workspace=apps/mcp run inspect                 # the MCP inspector over stdio
npm --workspace=apps/mcp run tool -- find-automations '{"limit": 5}'
npm --workspace=apps/mcp run tool -- start-conversation '{"message": "Draft an automation that..."}'
npm --workspace=apps/mcp run tool:list

An MCP client can point at the stdio build directly, with the same environment:

{
    "mcpServers": {
        "automations": {
            "command": "node",
            "args": ["/path/to/automations/apps/mcp/dist/main.js"],
            "env": { "AUTOMATIONS_API_KEY": "..." }
        }
    }
}

Releases

@doist/automations-mcp is published from main by .github/workflows/release-mcp.yml, which runs semantic-release with the configuration in release.config.js. The version comes from the conventional-commit messages that touched this directory, so nothing is bumped by hand and the repository holds no version number of its own. Releases go to the latest dist tag: the consumer is the hosted server, which pins an exact version. After publishing, the workflow sends an automations-mcp-updated dispatch to Doist/todoist-ai-integrations, whose update workflow installs the version, runs its checks, commits and redeploys, so a release reaches ai.todoist.net without waiting for a dependency PR.

The workspace libraries the package uses are not published, so npm run build compiles them into dist/ and only the packages under dependencies stay external. Because a release is scoped to commits under apps/mcp, a change confined to one of those libraries does not trigger a release even though it changes what gets published; it ships with the next release instead. Publish it sooner by landing it together with a change here.

Adding a tool

src/tool-registry.ts is the single source of truth for the tool surface; the server, run-tool and the token-footprint baseline derive from it, and src/tool-registry.test.ts fails when the views drift.

  1. src/utils/tool-names.ts: add the name.
  2. src/tools/<tool-name>.ts: the definition, satisfies AutomationsTool<...>. Copy find-automations.ts.
  3. src/tool-registry.ts: add it to the map, in the section it belongs to.
  4. src/tools/tool-annotations.test.ts: add its annotation expectation.
  5. src/tools/<tool-name>.test.ts: tests against a faked AutomationsApi.
  6. src/mcp-server.ts: add to instructions only when the tool needs cross-tool routing guidance; per-tool detail belongs in its own description.

Output schemas never use .nullable(): nulls are stripped before the SDK validates the output, so a nullable field is a validation failure waiting to happen. Use .optional() and leave the key out. src/tools/output-schema-nullability.test.ts enforces it.

src/token-footprint.test.ts prints what the tool surface costs a model on every tools/list. If a change pushes the combined fixed cost over its budget, raise the budget in the same PR and say so.