Skip to content

MCP server

conatus-mcp is a Model Context Protocol server for Conatus. It gives AI agents tools for projects, sections, tasks, labels, comments and reminders, going through the versioned /api/v1 API, never the database directly. Permanent deletion is deliberately not exposed.

It is released on its own schedule, so it has its own version (CONATUS_MCP_VERSION) and does not have to move with CONATUS_VERSION.

Both modes need one. In Conatus, go to Settings → API tokens and create a scoped token. It starts with tdm_ and is shown only once. Copy it before you leave the page. You can review and revoke tokens from the same screen.

Verify it works:

curl -H "Authorization: Bearer tdm_..." \
"https://tasks.example.com/api/v1/tasks?completed=false"

Use this unless an agent has to connect by URL. The AI host starts one MCP process for one account, and nothing is exposed to the network. Run the installer:

npx -y conatus-mcp setup

It validates the URL and the token before writing anything, never echoes the token, and registers the server with Claude Desktop, Claude Code, Cursor or another JSON MCP config. Restart the client afterwards.

The manual equivalent, if you would rather edit the config yourself:

{
"mcpServers": {
"my-tasks": {
"command": "npx",
"args": ["-y", "conatus-mcp"],
"env": {
"TASKS_BASE_URL": "https://tasks.example.com",
"TASKS_API_TOKEN": "tdm_replace_me"
}
}
}
}

TASKS_BASE_URL is the origin without /api/v1.

Use this when an agent has to connect by URL rather than spawn a process. The Compose file already contains an mcp service behind a profile.

In .env:

CONATUS_MCP_VERSION=latest
TASKS_API_TOKEN=tdm_replace_me
MCP_PUBLIC_URL=https://mcp.example.com/mcp
MCP_OAUTH_PASSWORD=generate-a-separate-long-random-password
MCP_ALLOWED_ORIGINS=https://your-ai-host.example

Then:

docker compose --profile mcp up -d

The sidecar publishes port 3001 on 127.0.0.1 only. Put your proxy in front of it on its own hostname. See Reverse proxy.

Give the AI client one thing: https://mcp.example.com/mcp. A compatible client discovers the protected-resource metadata, registers itself dynamically, opens the approval page and completes an authorization-code flow with S256 PKCE. You type MCP_OAUTH_PASSWORD on that page to approve it.

The MCP server is a single-user gateway. Its TASKS_API_TOKEN identifies the workspace and never leaves the server; each AI client gets its own one-hour access token and a rotating 30-day refresh token instead.

The server stores registrations and token hashes at MCP_OAUTH_STORE_PATH with mode 0600 in the mcp-oauth-data volume. It does not store raw tokens or the approval password. Run one MCP replica per store file.

  • MCP_PUBLIC_URL must be the exact external endpoint and must end in /mcp.
  • Production URLs must be HTTPS.
  • The server accepts a request carrying an Origin header only if that origin is in MCP_ALLOWED_ORIGINS. Native clients usually send no Origin at all.
  • The server refuses to bind to a non-loopback address without either complete OAuth configuration or MCP_BEARER_TOKEN.

For clients that cannot do OAuth: omit MCP_PUBLIC_URL and MCP_OAUTH_PASSWORD, set MCP_BEARER_TOKEN to a long random value, and have the client send it as a bearer token to /mcp. It is harder to rotate per client, and you should not paste it into prompts.

Pass credentials as environment variables. Not in prompts, not in tool arguments, not in command-line arguments, not in source control. Environment variables keep them out of MCP messages and out of most process listings.

The server’s own README carries the authoritative table: conatus-mcp § Environment variables.