deskhand

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

ToolScope needed
search_contactsread_crm
upsert_contact, update_contact, create_deal, move_deal, add_notewrite_crm
create_task, list_due_tasksmanage_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