Guide
An MCP server for a CRM: per-agent keys, scopes and a pause switch
Most CRM connectors authorise a person once and hand the agent that person's access. That makes the agent indistinguishable from you in the audit trail and impossible to stop without logging you out. Deskhand's MCP endpoint authenticates each agent with its own key, checks the key's scopes on every call, and records which agent did what.
Connect any MCP client
Endpoint: POST https://deskhand.grain64.com/api/mcp (streamable HTTP, JSON-RPC). Authenticate with the agent's key as a bearer token. Generic client config:
{
"mcpServers": {
"deskhand": {
"type": "http",
"url": "https://deskhand.grain64.com/api/mcp",
"headers": { "Authorization": "Bearer ${DESKHAND_KEY}" }
}
}
}
Tools
| Tool | Scope needed |
|---|---|
search_contacts | read_crm |
upsert_contact, update_contact, create_deal, move_deal, add_note | write_crm |
create_task, list_due_tasks | manage_tasks |
What a stopped agent sees
Pause an agent in the console and its next call returns a 403 with a code the agent can act on:
HTTP/1.1 403 Forbidden
{"error":{"code":"agent_paused","message":"This agent is paused by the operator.","request_id":"..."}}
A key without the right scope returns missing_scope and names the scope it needed. Keys are stored hashed and never returned after creation; rotate one with a click and the old key stops working.
Retries
Write tools take an optional idempotency_key. Repeating a call with the same key and arguments returns the first result instead of writing again, so an agent that retries after a timeout does not create duplicates.
Try it
The Free plan covers one agent with its own key, a pause switch and the full audit log. Get started free
Related: A CRM for Claude Code agents: one command, one key per agent, Connect an agent to a CRM over MCP with the TypeScript SDK