Skip to main content
Back to Documentation

Help

MCP Reference

Connecting AI agents to Deputise

MCP client contract

Audience: MCP clients and the developers building them. This contract is served as the deputise://docs/reference resource and at /developers/mcp. Creating assistants covers the setup workflow.

Connect to https://deputise.ai/mcp using MCP's HTTP transport. The endpoint accepts POST, GET and DELETE and acts on the signed-in user's behalf. Mobile clients use a separate API. Administrator access is a separate resource and registration.

Authentication

Use OAuth authorization-code flow with PKCE S256 and resource https://deputise.ai/mcp. Follow the WWW-Authenticate resource-metadata URL on an unauthenticated 401 response.

  • Protected-resource metadata: /.well-known/oauth-protected-resource/mcp.
  • Authorization server metadata: /.well-known/oauth-authorization-server/api/auth.
  • Register a client at POST /api/auth/oauth2/register, or use an HTTPS Client ID Metadata Document.
  • Authorize at GET /api/auth/oauth2/authorize; the browser handles sign-in and consent.
  • Exchange the code at POST /api/auth/oauth2/token with the original callback URI and PKCE verifier.

Request mcp and the tool scopes you need. Request offline_access for refresh tokens. Access tokens last 300 seconds; refresh tokens last 30 days and rotate on refresh, so store each replacement. Without offline_access, return to browser authorization when access expires. Revoking a grant prevents further refreshes; already-issued access tokens can remain valid for their remaining five minutes. MCP tokens and mobile /api tokens are not interchangeable.

A token without mcp gets 403 insufficient_scope. Invalid credentials or a missing account get 401; a suspended account gets 403 and cannot be fixed by reauthentication. A disabled client gets 403 access_denied.

Only tools whose scopes were granted appear in tools/list. Treat the listed schemas as the current input/output contract. A field that needs a further scope, listed in the tools table, fails the call with INSUFFICIENT_SCOPE when that scope was not granted. Tool discovery is private to the credential and may be cached for five minutes. Documentation resources are public content and may be cached for one hour.

A dynamically registered client's scope ceiling is fixed at registration. Register again to request a scope added later, such as memory:read and memory:write; CIMD clients use the current scope list. Registration allows two requests per minute per IP and answers 429 RATE_LIMITED, or 503 RATE_LIMIT_UNAVAILABLE when the counter is down. The token endpoint allows 30 requests per minute per IP. Subscription changes are managed on the website, not through MCP.

A new account has no plan until its holder chooses one on /subscribe and accepts the terms there, Free included. Until then create_agent fails with SUBSCRIPTION_REQUIRED and get_account_status reports a CHOOSE_PLAN step.

Callback configuration

Native loopback clients must register with application_type: "native". Registered HTTP loopback callbacks may use a different port while preserving the host and path. Hosted HTTPS callbacks match exactly. Use the exact callback selected for that login during code exchange. Run a callback receiver; a registered URL alone does not create one. If the browser and client run on different machines, forward the chosen callback port to the client machine.

Discovery

The initialize result carries instructions that point to the guidance resources. resources/list names seven: creating-agents, reference, account-setup, sharing, escalations, training and using-a-shared-assistant, each at deputise://docs/<slug>. prompts/list offers a workflow prompt only when the grant holds the scopes it uses:

Prompt Scopes
set_up_assistant assistants:read, assistants:write, facts:read, facts:write
share_assistant assistants:read, invitations:write
triage_escalations escalations:read, escalations:write
improve_assistant assistants:read, assistants:write, facts:read, facts:write, escalations:read

Tools

Read the descriptions and input/output schemas returned by tools/list before calling a tool. The shared read bucket is 60 calls per minute across every tool that uses it. Conversation turns are also capped at 300 per day; a turn over that cap fails with DAILY_ALLOWANCE_EXHAUSTED and a retryAfterSeconds that runs until the allowance renews.

Tool Area Scope Limit
list_chats Chats chats:read Shared read bucket
chat_status Chats chats:read Shared read bucket
chat_thread Chats chats:read Shared read bucket
start_chat Chats chats:write 10 turns/minute and 300 turns/day
send_message Chats chats:write 12/minute when the caller is the assistant's creator answering an escalation in the thread, otherwise 10 turns/minute and 300 turns/day
list_agent_types Agents assistants:read Shared read bucket
list_my_agents Agents assistants:read Shared read bucket
create_agent Agents assistants:write, plus facts:write to send facts or topics and profiles:write to send communicationProfileId Subscription and assistant-count limits; idempotencyKey makes a retry return the assistant the first call created; topics creates topics with their facts and rules
get_agent_configuration Configuration assistants:read Shared read bucket; owner only
update_agent_configuration Configuration assistants:write Service validation; owner only
update_agent_settings Agents assistants:write Paid-plan requirement for Premium
share_agent Agents invitations:write 10 invitations/minute; a repeat for the same assistant and email while pending returns alreadyPending: true and sends no second email
get_agent_facts Facts & profiles facts:read Shared read bucket
set_agent_facts Facts & profiles facts:write Fact-count limit for the assistant type; at most five pinned
get_agent_topics Facts & profiles facts:read Shared read bucket
set_agent_topics Facts & profiles facts:write At most 15 topics; unique names; topic instructions count toward the assistant type's instruction limit
list_communication_profiles Facts & profiles profiles:read Shared read bucket
set_communication_profile Facts & profiles profiles:write 2 new profile forks/minute; selecting an existing profile consumes no fork
set_recipient_profile Facts & profiles profiles:write Service validation
list_escalated_questions Escalations escalations:read Shared read bucket
answer_escalation Escalations escalations:write 12 replies/minute; save keeps the answer as memory or a fact in the same call
save_escalation_answer Escalations escalations:write 30 notes per person; fact-count limit for the assistant type
list_memory Memory memory:read Shared read bucket
add_memory Memory memory:write 30 notes per person
update_memory Memory memory:write Service validation
remove_memory Memory memory:write Service validation
clear_memory Memory memory:write Service validation
respond_to_memory_suggestion Memory memory:write 30 notes per person
get_account_status Account account:read Shared read bucket
rate_message Feedback feedback:write 30 ratings/minute
report_message Feedback feedback:write 2 reports/minute

For the create/configure/facts/profile/share workflow and field guidance, read Creating assistants. set_agent_facts replaces the whole set; read first and preserve facts you want to retain. A fact with no topicId and pinned: true applies to every conversation; a fact with a topicId is used only when that topic comes up and cannot also be pinned; a fact sent with neither keeps its placement. set_agent_topics replaces the whole topic set: keep a topic's id (from get_agent_topics or an earlier set_agent_topics) to keep it, omit the id to add a topic, and a held topic left out is deleted with its facts and instructions. It returns each saved topic's id and name for placing facts. More than 15 topics returns TOPIC_LIMIT_EXCEEDED; two names that match case-insensitively, or the reserved name Other things recorded, return DUPLICATE_TOPIC_NAME. create_agent applies the same rules to the topics it creates and returns their ids.

Conversations, escalations and feedback

list_chats returns nextCursor; pass it back as cursor until null. chat_thread accepts before and returns earlierCursor and cursorIgnored. Cursors are opaque; invalid cursors fall back to the newest page. totalMessages counts the complete thread, including on older pages. chat_status checks state without loading messages or marking replies viewed.

list_escalated_questions returns up to limit questions (default 20, max 100), ordered by urgency then newest first, an opaque nextCursor, and hasMore. Expiry is applied as pages are read. An unparseable cursor here is refused with INVALID_TOOL_INPUT rather than falling back to the newest page. Each entry carries status (OPEN or IN_PROGRESS), createdAt and expiresAt (null once IN_PROGRESS). answer_escalation takes the question's escalationId, can answer a question without listing it first, and accepts save with the semantics of save_escalation_answer to keep the answer in the same call; the result carries saved with each part's outcome. An expired question returns ESCALATION_NOT_ACTIVE, and one whose assistant or conversation was deleted returns ESCALATION_GONE. A suspended assistant or creator returns AGENT_SUSPENDED. A save that fails after the answer was sent leaves the answer sent and reports each requested part as { saved: false, code }.

save_escalation_answer keeps an answer the caller gave, including one sent without save: memory ({ content }) as a note for the person who asked, fact ({ label, details, topicId }) in the assistant's facts, appended to a case-insensitively matching label or added as a new one, or both. topicId is required: the id of one of the assistant's topics, or null to hold the fact everywhere, of which at most five are held. Topic ids come from get_agent_topics, which needs the facts:read scope. A label that already exists keeps the place it is held in whatever topicId is sent. At least one part is required. An escalation that is missing, belongs to another creator or has lost its assistant or conversation returns ESCALATION_GONE. Each part saves independently; memory and fact in the result are each { saved: true, ... } with the new memoryId or the fact's label, or { saved: false, code }, for example MEMORY_FULL, FACT_LIMIT_EXCEEDED, PINNED_FACT_LIMIT_EXCEEDED (a sixth fact held everywhere) or TOPIC_NOT_FOUND (a new label's topicId is not one of the assistant's topics). Use it once the question has a reply from the caller. Granting escalations:write therefore lets an agent write memory and facts this way, and the consent page says so.

send_message returns CONVERSATION_AWAITING_CREATOR while the asker is waiting for the creator. The creator's reply or expiry of the 48-hour window lifts the lock. A conversation the creator has ended, or one locked by a report, returns CONVERSATION_CLOSED permanently.

chat_thread messages include id, role, content, createdAt, rating, reported and memorySuggestion, which is null unless an assistant message offered a memory note. list_chats entries carry the assistant's agentId. rating is the caller's own good, bad or null; reported indicates their existing report. For non-assistant messages these fields are null and false. Pass the message ID to rate_message with good, bad or none (clear), or to report_message with a trimmed summary of at most 500 characters. Reports request human review and do not automatically edit or remove an answer. A report permanently locks the chat: it stays readable, but further messages, ratings and reports in it return CONVERSATION_CLOSED, so warn the user before reporting. Inaccessible/non-assistant messages return MESSAGE_NOT_FOUND; reporting the same message again returns ALREADY_REPORTED.

Memory

Each person an assistant is shared with has up to 30 notes of at most 500 characters, which the assistant reads in every chat with them. Without recipientId, list_memory, add_memory and clear_memory act on the caller's own share of agentId; list_chats gives the agentId of an assistant shared with the caller. With recipientId, the caller must own the assistant. update_memory and remove_memory take a memoryId from list_memory, on a share the caller holds or an assistant they own. Notes from add_memory have source MCP. A share the caller cannot reach returns SHARE_NOT_FOUND, a note that is missing or on a share the caller cannot reach MEMORY_NOTE_NOT_FOUND, and a full share MEMORY_FULL.

When a reply offers a note, start_chat, send_message and chat_thread include memorySuggestion ({ content, status }) with the assistant message's id. respond_to_memory_suggestion settles a PENDING offer with action save (optionally with edited content) or dismiss, and returns the settled suggestion and the saved memoryId; a saved offer becomes a CHAT note, and a settled one returns MEMORY_SUGGESTION_NOT_PENDING, and a messageId that is not the caller's own assistant message returns MESSAGE_NOT_FOUND. Ask the user before saving. Never save passwords, codes, or financial details; a health detail that bears on how the assistant helps the person may be saved. The assistant's owner can read every note.

Results, failures and retries

Successful results include readable content and schema-validated structuredContent. Failures set isError: true, include readable guidance and put an error object in structuredContent.error, for example:

{"code":"RATE_LIMITED","requestRef":"a1b2c3d4","retryable":true,"retryAfterSeconds":60}

Switch on code, not prose. Respect retryAfterSeconds when present. A counter outage (RATE_LIMIT_UNAVAILABLE) has no fixed delay. DAILY_ALLOWANCE_EXHAUSTED means the day's turns are used up, not that the caller is sending too fast. Validation failures use INVALID_TOOL_INPUT or INVALID_TOOL_OUTPUT; unexpected failures use INTERNAL_ERROR. INVALID_TOOL_INPUT carries details, one entry per schema issue with the field's dotted path and its message:

{"code":"INVALID_TOOL_INPUT","requestRef":"a1b2c3d4","retryable":false,"details":[{"path":"email","message":"Invalid email"}]}

Failures an account holder resolves on the website (SUBSCRIPTION_REQUIRED, AGENT_LIMIT_REACHED, PREMIUM_MODEL_NOT_AVAILABLE) carry actionUrl, the page to open.

Uncertain start_chat/send_message outcomes set retryable: false and recovery: "read-before-retry". List chats after an uncertain start and read chat_thread before an explicit retry. Do not automatically repeat a mutation.

Respect each tool's side-effect annotations. Reading a thread marks replies viewed; status and escalation reads may expire requests and send notifications; reading credits can initialise a ledger. Starting/sending is not idempotent, and replacing facts, settings or ratings can discard previous values. Annotations describe effects; scopes enforce authorization.

Assistant configuration

Read the whole configuration of an assistant you own before replacing any array in it. get_agent_configuration takes the assistant's own id and nothing else:

{ "agentId": "agt_6f1b9a4c20e5" }

It answers with the assistant's settings, its additional instructions and its facts. The same ownership and assistant-type limits apply as in the web editor. Image attachments and web search are switched on in the assistant's settings on the website; no tool changes them.

update_agent_configuration changes one owned assistant. Send its id and the fields you are changing:

{
  "agentId": "agt_6f1b9a4c20e5",
  "name": "Dad's phone helper",
  "description": "Answers Dad's questions about his phone, one step at a time.",
  "introMessage": "Hello [Name]. Ask me anything about your phone.",
  "escalationGuidance": "Ask me before suggesting anything that costs money or changes his contract.",
  "additionalInstructions": ["Give one step at a time and wait for him to say he has done it."]
}

Omitted fields are preserved. additionalInstructions is replaced as a whole when supplied, so read the current rules first and send back the ones you are keeping. These are the assistant-wide rules; instructions under a topic count toward the same limit, which the assistant type sets.

Send create_agent an idempotencyKey. Repeating the call with the same key returns the first assistant with alreadyCreated: true. Without a key, read list_my_agents after an uncertain response before creating again. A key whose assistant has since been deleted returns IDEMPOTENCY_KEY_USED; send a new key.