Endpoint
POST is accepted. GET and DELETE return 405 — the server is stateless with no sessions to manage.
OAuth flow
- Client hits
/api/mcpwithout a token → receives401withWWW-Authenticatepointing to/.well-known/oauth-protected-resource/api/mcp - Client fetches protected-resource metadata → discovers the authorization server at
{BACKEND_URL}/auth - Client fetches
/.well-known/oauth-authorization-server/auth→ gets authorize URL, token URL, JWKS URI, and supported scopes - User completes the authorization code flow and approves scopes on the consent screen
- Client exchanges the code for a JWT access token (audience =
{BACKEND_URL}/api/mcp) - Client sends
Authorization: Bearer <token>on every MCP request
{BACKEND_URL}/auth/jwks — no round-trip to the auth server per request.
Scopes
| Scope | Grants |
|---|---|
organizations:read | List organizations the user belongs to |
tasks:read | List and retrieve tasks |
tasks:write | Create and update tasks |
Tools
list_organizations
Scope: organizations:read
Returns the organizations the authorized user belongs to. Call this first when the user belongs to multiple organizations to get the correct organizationId for task tools.
Input: (none)
Output:
list_tasks
Scope: tasks:read
Returns up to 50 tasks (most recently updated) across all organizations the user belongs to.
| Input | Type | Description |
|---|---|---|
status | "TODO" | "IN_PROGRESS" | "DONE" | "CANCELLED" | Filter by status (optional) |
organizationId | integer | Restrict to one organization (optional) |
get_task
Scope: tasks:read
Returns full task detail including owners, subtasks, and parent task.
| Input | Type | Description |
|---|---|---|
taskId | integer | ID of the task to retrieve |
create_task
Scope: tasks:write
Creates a task. If the user belongs to exactly one organization, organizationId can be omitted — call list_organizations first if they belong to multiple.
| Input | Type | Description |
|---|---|---|
title | string | Task title (required) |
organizationId | integer | Target organization (optional if user has exactly one) |
description | any | Description in JSON format (optional) |
status | enum | Initial status — defaults to "TODO" (optional) |
assignee | string | Assignee identifier (optional) |
update_task
Scope: tasks:write
Updates one or more fields on an existing task. Only supplied fields are changed.
| Input | Type | Description |
|---|---|---|
taskId | integer | ID of the task to update (required) |
title | string | New title (optional) |
description | any | New description in JSON format (optional) |
status | enum | New status (optional) |
assignee | string | New assignee (optional) |
completedAt | string | Completion timestamp in ISO 8601 format (optional) |
Connecting a client
Claude Desktop
Add toclaude_desktop_config.json:
Claude Code
Cursor / VS Code
Add a remote MCP server pointing to{BACKEND_URL}/api/mcp. The client handles OAuth discovery and the login flow on first use.
Environment variables
| Variable | Default | Description |
|---|---|---|
BACKEND_URL | http://localhost:3001 | Public backend URL — used in OAuth metadata responses |
BETTER_AUTH_URL | http://localhost:8000 | Auth server base URL — used by the bearer guard to verify JWTs |