AppHandoff MCP Setup for Coding Agents
AppHandoff exposes project context, OpenAPI contract scanning, and handoff tickets through a single hosted MCP server endpoint — the primary surface for agent orchestration and multi-agent development.
Endpoint
Section titled “Endpoint”| Setting | Value |
|---|---|
| URL | https://api.apphandoff.com/mcp |
| Auth | OAuth (Supabase access token) or a personal access token (ah_pat_*) |
| Discovery | GET https://api.apphandoff.com/.well-known/oauth-protected-resource |
Do not put project_id in the MCP config URL. The project is resolved at runtime by bootstrap.
API keys (ah_k_*) are not accepted on MCP.
Client setup
Section titled “Client setup”Cursor (Cursor MCP setup)
Section titled “Cursor (Cursor MCP setup)”Create or edit .cursor/mcp.json in your project:
{ "mcpServers": { "apphandoff": { "url": "https://api.apphandoff.com/mcp" } }}Restart Cursor or reconnect the server. Complete the OAuth consent prompt on first connect.
Claude Code (Claude Code MCP server)
Section titled “Claude Code (Claude Code MCP server)”claude mcp add apphandoff https://api.apphandoff.com/mcpLovable and other MCP clients
Section titled “Lovable and other MCP clients”Paste https://api.apphandoff.com/mcp into your client’s MCP server settings and follow its OAuth flow. See also the Lovable MCP server product page.
First session
Section titled “First session”AppHandoff serves exactly ten tools: bootstrap, get, find and read_skill (the skill guides, for clients that forward tools only) read; ticket, plan, message, project and question (agents ask a human a decision question) write; decide_lifecycle_proposal is the approval click a human makes. Every tool name from earlier releases is gone, with no alias.
With exactly one accessible project, the server binds it after you connect. With multiple projects, call bootstrap with a project (a repo slug, GitHub URL, UUID or project name) to resolve one; when the match is ambiguous it lists the projects you can reach.
Fastest start — bootstrap opens the session in one call: the project, the revision of the write rules (guidance_rev), your leases, your inbox and a board digest:
{ "name": "bootstrap", "arguments": { "project": "owner/app" } }Then read with get (by ref: HO-n tickets, MS-n milestones, PG-n programs, or $next for the ticket to start) and find (cards by type). Send several reads in parallel, or pass up to 10 refs to one get:
{ "name": "get", "arguments": { "refs": ["HO-12", "HO-13"] } }{ "name": "find", "arguments": { "type": "ticket", "filter": { "for_you": true } } }find with for_you returns open tickets you can start now: no live lease held by someone else and no open blocker, each with claim_paths and own. Add "milestone": "MS-n" (or "program": "PG-n") to scope it to that building milestone (or the program’s building milestones).
Every write takes the same envelope and one op per call (op.action names the action); ticket also takes ops, up to 20 ticket ops in one call. Send the guidance_rev from bootstrap; a refused write answers with a typed code and a remedy, and a write that needs a human answers awaiting_approval (a normal result, nothing applied) with a link to approve. Per-tool reference lives at apphandoff://tool/{name}/help, and tools/list is the authoritative catalogue.
Response size
Section titled “Response size”Reads are byte-budgeted: find returns 8 KB of cards by default (16 KB at most) and continues with next_cursor; get caps at 16 KB. Narrow with filter, limit or fields.
OAuth token refresh
Section titled “OAuth token refresh”Access tokens are Supabase JWTs (production lifetime: 8 hours).
GET /.well-known/oauth-protected-resource→authorization_servers[0]GET /.well-known/oauth-authorization-server→token_endpoint,scopes_supported,grant_types_supported
Refresh via AppHandoff’s proxy (not Supabase’s host directly):
POST /api/oauth/tokenContent-Type: application/json
{ "grant_type": "refresh_token", "refresh_token": "<token>", "client_id": "<uuid>"}Do not request offline_access — Supabase rejects it and spec-strict clients fail before consent renders.
Monitor X-Token-Expires-In on every MCP response. Refresh when it drops below 300 seconds.
Several tickets at once
Section titled “Several tickets at once”To read many tickets at once, pass up to 10 refs to get. To write up to 20 tickets in one project, send one ticket call with ops in place of op (each op carries its own ref and rev); the answer lists results[i], one per op, in order. A gated action such as close goes in its own call. Re-send a timed-out call with the same idempotency key so it replays instead of writing twice: for ops, the applied ops answer replayed and the rest run.
Error codes
Section titled “Error codes”| HTTP | domain_code | Action |
|---|---|---|
| 401 | TOKEN_EXPIRED | Refresh via token_endpoint, retry |
| 401 | AUTH_REQUIRED | Re-run OAuth flow |
| 404 | SESSION_EXPIRED | Reconnect MCP server |
Troubleshooting
Section titled “Troubleshooting”Connection closed (-32000) — transport dropped. Retry; reconnect if persistent. Check for requests exceeding the 25s timeout (a very large find or get).
Tool not found — the client is holding an old tool list. Older releases served more tool names; they are deleted, not aliased, so a call to one fails outright. Disconnect and reconnect AppHandoff MCP (Cursor in particular caches tools/list) to reload the eight-tool catalogue. Confirm the URL is exactly https://api.apphandoff.com/mcp.
401 after 20–60 minutes — access JWT expired. Reconnect or refresh via /api/oauth/token.
No OpenAPI spec found — set backend_repo to owner/repo. For subfolders use config.appSubDir; for custom paths use config.openApiPath.
Stale tool list after deploy — disconnect and reconnect the MCP server.
See also
Section titled “See also”- Handoff tickets — Kanban workflow for AI agent handoff
- REST API — programmatic access alongside MCP
- Shared Kanban for humans and bots — product overview