What is the Dynobox MCP?
Dynobox ships a built-in Model Context Protocol (MCP) server alongside the main application. MCP is an open protocol that lets AI agents discover and call tools over a standard JSON-RPC 2.0 interface — the same way a browser calls a REST API.
Once connected, your agent can treat your inbox as a live data source: fetch threads, compose and send messages, apply labels, star leads, archive noise — all without a human in the loop.
- Transport: JSON-RPC 2.0 over HTTP POST
- Endpoint:
http://localhost:3001/api/mcp - Metadata:
GET /api/mcp/metadata - Protocol version:
2024-11-05 - Batch requests: not supported
ALLOW_REMOTE_CLIENT=true is set. This keeps your inbox safe when running locally.Up in 60 seconds
Make sure Dynobox is running, then pick your integration path below.
# Add Dynobox as an MCP server to Claude Code
claude mcp add --transport http dynobox http://localhost:3001/api/mcp
# Verify it's connected
claude mcp list
# → dynobox: http://localhost:3001/api/mcp (HTTP) - ✓ Connectedexport DYNOBOX_MCP_URL="http://localhost:3001/api/mcp"
export DYNOBOX_ACCOUNT_ID="you@example.com"
# 1. Initialize
curl -sS "$DYNOBOX_MCP_URL" \
-H "Content-Type: application/json" \
-H "x-account-id: $DYNOBOX_ACCOUNT_ID" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"curl-test","version":"1.0.0"}}}'
# 2. List tools
curl -sS "$DYNOBOX_MCP_URL" \
-H "Content-Type: application/json" \
-H "x-account-id: $DYNOBOX_ACCOUNT_ID" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}'async function mcpCall(method, params = {}) {
const res = await fetch('http://localhost:3001/api/mcp', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-account-id': process.env.DYNOBOX_ACCOUNT_ID,
},
body: JSON.stringify({ jsonrpc: '2.0', id: Date.now(), method, params }),
});
const json = await res.json();
return json.result?.structuredContent ?? json.result;
}
// Initialize, then call a tool
await mcpCall('initialize', {
protocolVersion: '2024-11-05',
capabilities: {},
clientInfo: { name: 'my-agent', version: '1.0.0' },
});
const result = await mcpCall('tools/call', {
name: 'dynobox_list_accounts',
arguments: {},
});
console.log(result.accounts);Headers & access control
The MCP server uses two optional request headers to control access and route calls to the right mailbox.
| Header | Required | Description |
|---|---|---|
x-account-id | When >1 account | Email address of the account to act on. Required when multiple accounts are configured. |
x-dynobox-key | If server-side key set | Shared secret. Only required when DYNOBOX_API_KEY is configured on the Dynobox server. |
ALLOW_REMOTE_CLIENT=true), always set a strong DYNOBOX_API_KEY and pass it as x-dynobox-key on every request. Do not expose the MCP port to the public internet without additional auth.curl -sS "http://localhost:3001/api/mcp" \
-H "Content-Type: application/json" \
-H "x-account-id: you@example.com" \
-H "x-dynobox-key: your-shared-secret" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'Recommended call sequence
Follow this four-step sequence when bootstrapping a new agent session.initialize is required before any tool calls.
initialize
Negotiate the protocol version and register your client. Required once per session before any tool calls.
tools/list
Discover all available tools and their schemas. Useful for dynamic agents that introspect capabilities at runtime.
dynobox_list_accounts (optional)
Resolve account IDs when you don't know them ahead of time. Returns all configured mailboxes.
tools/call → operational tools
Run any of the 11 inbox tools. Pass accountId to target a specific mailbox.
// 1. Initialize
await mcpCall('initialize', {
protocolVersion: '2024-11-05',
capabilities: {},
clientInfo: { name: 'my-agent', version: '1.0.0' },
});
// 2. (Optional) Discover tools
const { tools } = await mcpCall('tools/list', {});
// 3. (Optional) Resolve accounts
const { accounts } = await mcpCall('tools/call', {
name: 'dynobox_list_accounts',
arguments: {},
});
const accountId = accounts[0].id;
// 4. Call an operational tool
const result = await mcpCall('tools/call', {
name: 'dynobox_search_threads',
arguments: {
accountId,
query: 'invoice OR receipt',
unreadOnly: true,
maxResults: 10,
},
});Available tools
All tools are called via tools/call. Expand any row to see the full argument list. Tools tagged Gmail require a Gmail account.
List all configured Dynobox accounts.
List recent threads for an account with optional query and label filters.
Search threads with structured filters: query, sender, recipient, subject, unread.
Filter threads by mailbox or label with optional sender/recipient constraints.
Fetch the full message content of a specific thread.
Send a new message or reply through the target account.
Apply a lifecycle action to a Gmail thread.
List all Gmail labels, optionally including message counts.
Add or remove Gmail labels on a thread. At least one of addLabelIds or removeLabelIds is required.
List Google contacts available to the account.
Get Gmail profile details: address, total messages, history ID.
Product blueprints
The MCP is the foundation — what you build on top is up to you. Here are three real-world patterns to get started. Each chains multiple tools into a complete, automated workflow.
Invoice Processor
Automatically find, read, and label every invoice in your inbox.
const threads = await mcp.call('dynobox_search_threads', {
query: 'invoice OR receipt',
unreadOnly: true,
maxResults: 25,
});
for (const thread of threads.threads) {
const full = await mcp.call('dynobox_get_thread', {
threadId: thread.id,
});
// Parse body, extract totals...
await mcp.call('dynobox_update_thread_labels', {
threadId: thread.id,
addLabelIds: ['Label_invoice'],
});
await mcp.call('dynobox_thread_action', {
threadId: thread.id,
action: 'archive',
});
}Lead Capture Agent
Monitor inbound leads, send personalised replies, star hot prospects.
const inbox = await mcp.call('dynobox_filter_threads', {
label: 'INBOX',
unreadOnly: true,
});
for (const thread of inbox.threads) {
const full = await mcp.call('dynobox_get_thread', {
threadId: thread.id,
});
const isLead = classify(full.messages[0].body); // your logic
if (isLead.score > 0.8) {
await mcp.call('dynobox_send_message', {
threadId: thread.id,
to: full.messages[0].from,
body: generateReply(full),
});
await mcp.call('dynobox_thread_action', {
threadId: thread.id, action: 'star',
});
}
}Daily Digest
Compile a morning briefing from overnight email and send it to yourself.
const yesterday = Date.now() - 86_400_000;
const threads = await mcp.call('dynobox_list_threads', {
label: 'INBOX',
maxResults: 25,
});
const summaries = await Promise.all(
threads.threads.map(async (t) => {
const full = await mcp.call('dynobox_get_thread', {
threadId: t.id,
});
return summarise(full); // your LLM call
})
);
await mcp.call('dynobox_send_message', {
to: 'you@example.com',
subject: '☀️ Morning Digest',
body: summaries.join('\n\n'),
isHtml: false,
});dynobox_get_thread to feed raw email content into your model, then act on its structured output using dynobox_send_message, dynobox_thread_action, or dynobox_update_thread_labels. The full inbox is your context window.Response shape & errors
All successful responses wrap results in MCP-compatiblecontent and structuredContent fields. Use structuredContent for programmatic access — it contains the parsed JSON object directly.
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"content": [{ "type": "text", "text": "{...}" }],
"structuredContent": {
"threads": [ ... ],
"nextPageToken": "abc123"
}
}
}{
"jsonrpc": "2.0",
"id": 3,
"result": {
"isError": true,
"content": [{
"type": "text",
"text": "Account not found: unknown@example.com"
}]
}
}Check result.isError === true to detect failures — they are returned as successful JSON-RPC responses, not HTTP error codes.
Metadata endpoint
GET /api/mcp/metadata returns server name, version, endpoint URLs, required headers, and tool summaries. Use this for auto-configuration in dynamic agents.
curl http://localhost:3001/api/mcp/metadata