MCP Worker (swapps-mcp-worker)

The MCP Worker (repository swapps-mcp-worker) is a remote Model Context Protocol (MCP) server that wraps the swapps-app REST API (Django + DRF, also known internally as the "IDK API"). It runs as a TypeScript Cloudflare Worker, so anyone in the organization can use it without installing anything locally — they only register a URL and a personal token in their MCP client.

It is read-only, and it is the remote equivalent of the local Python MCP server in tools/swapps-app-mcp/.

What it does

  • Exposes 18 read-only MCP tools that map onto swapps-app endpoints (clients, contracts, services, installments, level-rates, reports, tasks, time entries, Celery task status, plus a generic GET escape hatch). See Tools reference.
  • Speaks the MCP Streamable HTTP transport at the /mcp route, so MCP clients (Claude Code, Claude Desktop) can connect over plain HTTPS.
  • Authenticates each caller with a per-user edge token at the edge, then calls the downstream API with a single shared service token — the two are never the same and the edge token is never forwarded downstream.

Transport and routing

Aspect Value
Transport MCP Streamable HTTP (@modelcontextprotocol/sdk + the agents MCP handler)
MCP route POST /mcp (clients must send Accept: application/json, text/event-stream)
Health route GET /health{ "status": "OK", "ts": "<iso>" }
Production URL https://mcp.swapps.com/mcp (custom domain) or https://swapps-mcp-worker.<account>.workers.dev/mcp
Auth header Authorization: token <edge-token> (or Authorization: Bearer <edge-token>); fallback X-MCP-Token: <edge-token>

Read-only by design

Every tool issues a GET against the downstream API. There is no create / update / delete path, and even the generic api_request tool is a GET-only escape hatch. The downstream service token should belong to a dedicated read-only DRF user (defense in depth).

Role in the platform

flowchart LR Client["MCP client
(Claude Code / Desktop)"] -->|"Streamable HTTP
POST /mcp + edge token"| Worker subgraph CF["Cloudflare"] Worker["swapps-mcp-worker
(MCP server, TypeScript)"] Auth["validateEdgeToken
(EDGE_TOKENS map)"] Worker --> Auth end Worker -->|"Authorization: Token {service token}"| API["swapps-app API
(app.swapps.com/api)"]

The flow on each request:

  1. The MCP client sends POST /mcp with the user's edge token in a header.
  2. The Worker validates the edge token against the EDGE_TOKENS map (a JSON token -> username map). An unknown/missing token returns 401. A valid token resolves to a username and emits an audit log line.
  3. The Worker builds a fresh MCP server instance (required per request by the SDK) and dispatches the JSON-RPC method.
  4. Tool calls reach the downstream swapps-app API authenticated with the single read-only service token (SWAPPS_API_TOKEN), never the caller's edge token.

Bindings, vars and secrets

Name Kind Purpose
SWAPPS_API_TOKEN Secret Single read-only service DRF token used for all downstream API calls.
EDGE_TOKENS Secret JSON map of per-user edge token → username, e.g. {"<token>":"dev@swapps.com"}.
SWAPPS_API_BASE_URL Var Base URL of the swapps-app API. Defaults to https://app.swapps.com/api.
SWAPPS_API_USER_AGENT Var User-Agent sent downstream (keeps the Cloudflare WAF /api skip rule happy). Defaults to swapps-mcp/1.0.

There are no KV namespaces, Durable Objects, or queues; the Worker is stateless. See Architecture for details and Development for local setup and deployment.

Sections

  • Tools reference — every MCP tool, its inputs and behavior.
  • Architecture — project structure and how the MCP server/transport is wired on Workers.
  • Development — local dev, testing, env vars, deployment and registering it in an MCP client.