MCP server
Dock speaks the Model Context Protocol over HTTPS. Any MCP-capable client can add Dock as a remote connector with OAuth 2.1 + Dynamic Client Registration. No manual config.
Endpoint
https://trydock.ai/api/mcpOAuth metadata lives at the standard well-known paths:
/.well-known/oauth-authorization-server/.well-known/oauth-protected-resource
Adding Dock to a client
Claude.ai (Chat web + Projects)
- Settings → Connectors → Add custom connector
- Paste
https://trydock.ai/api/mcp - Click Connect. Approve in the Dock consent screen.
- Done. The agent can now call Dock tools in every Chat and Project.
Claude Code (remote MCP)
{
"mcpServers": {
"dock": {
"url": "https://trydock.ai/api/mcp",
"auth": { "type": "bearer", "token": "dk_..." }
}
}
}Claude Desktop, Cursor, Windsurf, Zed, Cline, Continue (local stdio)
Most desktop agents still prefer local stdio MCP. Use the official bridge @trydock/mcp — a thin Node process that forwards stdio JSON-RPC to Dock's hosted HTTPS endpoint. Same auth (Bearer API key), same tools, no OAuth dance.
{
"mcpServers": {
"dock": {
"command": "npx",
"args": ["-y", "@trydock/mcp"],
"env": {
"DOCK_API_KEY": "dk_..."
}
}
}
}Per-client config file paths + Zed/Continue variants live in the bridge repo: try-dock-ai/mcp/configs. Tool schemas are in try-dock-ai/mcp/schemas — audit them before installing.
Agent frameworks (LangChain, Mastra, CrewAI…)
Each framework has its own MCP adapter. Point it at https://trydock.ai/api/mcp with a Bearer token, or spawn npx -y @trydock/mcp as a stdio transport if the framework expects local MCP.
Step-by-step setup for your specific client lives in the full integrations directory: exact config snippets for Claude Code, Cursor, Continue, and 50+ other clients.
Tools
list_workspaces{}get_workspace{ "slug": "content-pipeline" }list_rows{ "slug": "content-pipeline", "surface_slug": "linkedin", "limit": 50 }get_row{ "slug": "content-pipeline", "rowId": "row_01HX..." }create_row{ "slug": "content-pipeline", "data": { "title": "...", "status": "drafted" }, "surface_slug": "linkedin" }update_row{ "slug": "content-pipeline", "rowId": "row_01HX...", "data": { "status": "sealed" }, "surface_slug": "outbox" }delete_row{ "slug": "content-pipeline", "rowId": "row_01HX..." }move_rows{ "slug": "content-pipeline", "rowIds": ["row_01HX...", "row_01HY..."], "target_surface_slug": "linkedin" }get_doc{ "slug": "content-pipeline" }update_doc{ "slug": "content-pipeline", "content": { "type": "doc", "content": [ ... ] } }get_workspace_schema{ "slug": "content-pipeline" }list_workspace_members{ "slug": "content-pipeline" }delete_workspace{ "slug": "content-pipeline" }update_workspace{ "slug": "content-pipeline", "name": "New name", "visibility": "org" }share_workspace{ "slug": "content-pipeline", "email": "teammate@example.com", "role": "editor" }update_workspace_member{ "slug": "content-pipeline", "member_id": "wm_01HX...", "role": "commenter" }remove_workspace_member{ "slug": "content-pipeline", "member_id": "wm_01HX..." }create_workspace{ "name": "New", "slug": "new", "mode": "table" }get_recent_events{ "slug": "content-pipeline", "limit": 50 }search{ "q": "launch plan", "kind": "all", "limit": 20 }get_billing{}upgrade_plan{ "plan": "pro" } // first call; add confirm_token on the seconddowngrade_plan{} // first call; add confirm_token on the secondrequest_limit_increase{ "limit": "workspaces", "reason": "Running one workspace per client; need 500." }list_surfaces{ "slug": "content-pipeline" }create_surface{ "slug": "content-pipeline", "kind": "table", "name": "Q3 brief" }update_surface{ "slug": "content-pipeline", "surface_slug": "q3-brief", "name": "Q3 launch brief" }delete_surface{ "slug": "content-pipeline", "surface_slug": "q3-brief" }list_api_keys{}rotate_api_key{ "id": "key_01HX..." } // omit when called by an agentrevoke_api_key{ "id": "key_01HX..." } // omit when called by an agentlist_webhooks{ "org_slug": "vector" }create_webhook{ "org_slug": "vector", "url": "https://hooks.example.com/dock", "events": ["row.created", "row.updated"] }update_webhook{ "org_slug": "vector", "webhook_id": "wh_01HX...", "active": false }rotate_webhook_secret{ "org_slug": "vector", "webhook_id": "wh_01HX..." }delete_webhook{ "org_slug": "vector", "webhook_id": "wh_01HX..." }create_support_ticket{ "kind": "bug", "title": "Row edits 409 on retry", "body": "Steps: ..." }Dangerous operations · two-call consent
A small set of tools never executes on the first call. They return a one-shot confirm_token and a summary message, and only run when the agent re-issues the same call with confirm_token set. The agent is expected to surface the summary to its user in chat (Claude Code, Cursor, etc.) and re-call only after the user says yes.
Consent-gated tools today: upgrade_plan, downgrade_plan. The pattern extends to any future tool that moves money or permanently changes org state.
Handshake shape
First call — no confirm_token:
// request
tools/call { "name": "upgrade_plan", "arguments": { "plan": "scale" } }
// response
{
"status": "confirmation_required",
"message": "Agent is requesting a plan switch: pro → scale ($49/mo flat, prorated mid-cycle). Confirm by re-calling upgrade_plan with confirm_token set to the token below, within 60s.",
"confirm_token": "H3kZ...base64url...",
"expires_in": 60,
"operation": "upgrade_plan",
"params": { "plan": "scale" }
}Second call — same arguments plus the token:
tools/call {
"name": "upgrade_plan",
"arguments": { "plan": "scale", "confirm_token": "H3kZ...base64url..." }
}Guarantees
- Single-use. A consumed token is permanently spent. Re-use returns a JSON-RPC error with
data.reason = "already_consumed". - 60-second TTL. Expired tokens return
data.reason = "expired". Re-call without a token to mint a fresh one. - Param-bound. A token minted for
{ plan: "pro" }cannot be consumed as{ plan: "scale" }. Returnsdata.reason = "params_mismatch". - Caller-bound. Token A minted by agent Alpha cannot be consumed by agent Bravo. Returns
data.reason = "principal_mismatch". - Org-bound. Tokens are scoped to the org the first call authenticated against — cross-org replay is rejected.
Fast paths that skip the gate
Some upgrade_planbranches don't move money and don't flip a live subscription. Those execute on the first call, no token required:
- No card on file. The tool returns a Stripe Checkout URL. The human entering a card in Checkout IS the consent signal.
- Design-partner orgs. Already on Scale at $0 — no-op.
- Same-plan resume. Cancelling a previously scheduled downgrade reverses a user-initiated request; nothing new gets charged.
Agent identity
When you authorize an MCP connector via OAuth, Dock auto-creates an agent identity for that connector in your org. The agent's name comes from the OAuth client's self-declared name (Claude Code, Cursor, Windsurf, etc.) and a small brand favicon overlays the agent's orb so the connector is recognizable at a glance. Activity log shows "Claude Code added 3 rows" instead of "Govind added 3 rows".
The agent inherits your workspace access — the workspaces you’re already a member of when you authorize, plus any new workspaces shared with you afterward, including ones that live in other teams. Trusting a person means trusting their tools, so anywhere you have access via a WorkspaceMember row, the agent can read and write at your role. The owner of the share manages you; you manage your agents. If the share is revoked or your role is downgraded, your agents follow in lock-step. Find or rename your agent under Settings → Agents; the brand badge stays even after a rename. Removing the agent revokes every key bound to it across every workspace.
Two different users authorizing the same connector get two separate agents (so attribution still tells you who ran it). One agent per (user, OAuth client) pair. Re-authorization is idempotent: it returns the existing agent and un-archives if the user previously removed it.
Cap behavior: OAuth-promoted agents count toward your org's agent cap. If you're at the limit, the OAuth flow returns 403 agent_cap_reached instead of issuing a token that would silently fall back to attributing activity to you. Upgrade or remove an agent to proceed.
How attribution works
The principal Dock stamps on every event, row write, and doc edit is picked based on the auth path the request used. Three cases:
- Agent API key (
Bearer dk_*) → attributes to the agent. Any MCP tool call, any REST write made with the key flows through asprincipalType: "agent",principalId: <agent.id>. - OAuth bearer token (
Bearer dock_at_*) → attributes to the OAuth-promoted agent for that (user, client) pair. If the user's org was at the agent cap at OAuth time and no agent was promoted, falls back to user attribution for that token. - Session cookie (dashboard) → attributes to the user.
Verify the attribution from any agent by reading get_recent_events — each event carries principalType + principalName so the agent sees itself in the feed the same way the dashboard does.
Protocol notes
- Transport: HTTP JSON-RPC (one request per call, no streaming).
- Auth: OAuth 2.1 with PKCE + Dynamic Client Registration for interactive clients. Bearer tokens (
dk_...) for headless / programmatic clients. - Errors follow the JSON-RPC error spec. An
x-request-idheader is also returned for cross-ref with server logs. - MCP tool responses mirror the REST endpoint shapes. A row returned from
create_rowis byte-for-byte the same asPOST /rows.
Manual JSON-RPC example
curl -X POST https://trydock.ai/api/mcp \
-H "Authorization: Bearer dk_..." \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'curl -X POST https://trydock.ai/api/mcp \
-H "Authorization: Bearer dk_..." \
-H "Content-Type: application/json" \
-d '{
"jsonrpc":"2.0","id":2,"method":"tools/call",
"params":{ "name":"create_row",
"arguments":{"slug":"content-pipeline",
"data":{"title":"Via MCP","status":"drafted"}}}
}'Related
- OAuth + DCR setup — how MCP-aware clients self-register and get tokens.
- Connecting clients — per-client config (Claude Desktop, Cursor, Windsurf, Cline, etc.).
- Tool catalog — every MCP tool, auto-generated from
src/lib/mcp-tools.ts. - Dangerous-ops handshake — two-call confirm for irreversible tools (upgrade / downgrade plan).
- Server card — JSON catalog at
/.well-known/mcp/server-card.jsonfor indexers. - Agent overview — agent identity + signed-agent inheritance.
- REST API — every MCP tool has a REST equivalent.