Sign In

MCP Server

Connect AI assistants to Coach Watts via the remote Model Context Protocol (MCP) server with OAuth 2.0 and PKCE.

Coach Watts exposes a remote MCP server so tools like Cursor can read and write your training data on your behalf. The endpoint uses OAuth 2.0 with PKCE and the same permission scopes as the REST API.

Endpoint

Remote MCP URL:

https://coachwatts.com/mcp

For local development:

http://localhost:3099/mcp

Quick start (Cursor)

Dynamic client registration (DCR) is enabled by default. Add the MCP URL to your mcp.json:

{
  "mcpServers": {
    "coach-watts": {
      "url": "https://coachwatts.com/mcp"
    }
  }
}

Cursor registers via OAuth automatically. When you connect, approve the requested scopes on the consent screen.

OAuth discovery

MCP clients can discover authorization metadata at:

  • /.well-known/oauth-authorization-server
  • /.well-known/oauth-protected-resource
  • /.well-known/oauth-protected-resource/mcp

Authorization requests must include:

  • resource={siteUrl}/mcp (exact MCP resource URL)
  • PKCE with code_challenge_method=S256
  • Scopes from the MCP allowlist (profile, workout, health, nutrition, planning, analysis, memory, and recommendations scopes)

Tool phases

Tools are grouped into read, write, and async phases. All phases are enabled by default in production.

PhaseDefaultExamples
ReadOnList workouts, read profile, fetch wellness
WriteOnLog nutrition, update profile, create planned workouts
AsyncOngenerate_report, sync_data, structure generation

Server operators can disable phases with environment variables:

VariableDefaultEffect
NUXT_MCP_READ_ENABLEDtrueExpose read tools
NUXT_MCP_WRITE_ENABLEDtrueExpose write tools
NUXT_MCP_ASYNC_ENABLEDtrueExpose async/AI tools
NUXT_MCP_EXECUTION_ENABLEDtrueKill switch for tool execution
NUXT_MCP_CLIENT_ALLOWLISTemptyComma-separated OAuth client IDs
NUXT_MCP_DCR_ENABLEDtrueAllow MCP clients to register via OAuth DCR

Write and async mutating tools support idempotency via the Mcp-Idempotency-Key request header.

Async jobs

Async tools return identifiers such as generation_run_id, report_id, or run_id. Poll completion with the get_async_job_status tool:

{
  "job_type": "structure_generation",
  "job_id": "<generation_run_id>"
}

Supported job_type values: structure_generation, report, trigger_run.

Client registration

When DCR is enabled, Cursor and other MCP clients connect with only the MCP URL. Compatible redirect URIs reuse the shared Cursor MCP OAuth app instead of creating a new client each time.

DCR owner resolution order:

  1. NUXT_MCP_DCR_OWNER_USER_ID
  2. NUXT_MCP_DCR_OWNER_EMAIL
  3. First admin user in the database

To disable DCR, set NUXT_MCP_DCR_ENABLED=false. A static auth.CLIENT_ID in mcp.json is only needed when DCR is disabled.

Manual bootstrap (self-hosted)

Pre-create the shared Cursor app explicitly:

pnpm cw:cli oauth create-cursor-mcp-app --owner-email [email protected]
pnpm cw:cli oauth create-cursor-mcp-app --owner-email [email protected] --prod

Local development

MCP is enabled by default locally. Set NUXT_MCP_ENABLED=false to disable the endpoint, or NUXT_MCP_WRITE_ENABLED=false / NUXT_MCP_ASYNC_ENABLED=false to turn off individual phases.

export NUXT_PUBLIC_SITE_URL=http://localhost:3099

Apply database migrations and run MCP-focused unit tests:

pnpm db:deploy
pnpm test:mcp

Operations

  • Manifest drift is logged at startup when MCP is enabled.
  • Admin dashboard data: GET /api/admin/mcp/stats (execution summary, latency, error codes, DCR counts).
  • Revoke MCP access any time from Settings → Apps.

Troubleshooting

401 on /mcp

  • Confirm the token was issued with resource={siteUrl}/mcp. REST developer tokens without a resource are rejected.
  • Check token expiry and that the user account is active.
  • Inspect the WWW-Authenticate challenge for the protected-resource metadata URL.

OAuth authorization fails

  • MCP clients must send PKCE with code_challenge_method=S256.
  • Requested scopes must be in the MCP allowlist.
  • Redirect URIs must match exactly (HTTPS required except loopback).

Tool missing from tools/list

  • Verify the tool phase flag (NUXT_MCP_WRITE_ENABLED, NUXT_MCP_ASYNC_ENABLED).
  • Confirm the token includes the required scopes.
  • Nutrition and feature-gated tools only appear when enabled for the user.
  • Chat-disabled async tools (sync_data, generate_report) require the async phase flag.

Async job stuck

  • Call get_async_job_status with the id returned by the async tool.
  • For structure generation use job_type=structure_generation and generation_run_id.
  • For reports use job_type=report and report_id.
  • For Trigger.dev-backed sync use job_type=trigger_run and run_id.

Security notes

  • MCP tokens are bound to the exact /mcp resource URL.
  • REST developer API tokens without a resource cannot call /mcp.
  • Refresh token rotation is enforced for MCP resource tokens; reuse revokes the grant chain.
Back to Index