Connect a private MCP server with OAuth
Host MCP OAuth lets the machine running your agent authorize a remote MCP server without putting tokens in your source or workspace.
Use a private MCP tool locally
Declare the server and authorize it once in the browser.
// bot/mcp-connections/inventory.tsimport { defineConnection } from "@grok/agent-sdk/connections";export default defineConnection({ url: "https://mcp.example.com/inventory", oauth: true, advertiseTools: true,});agent-sdk mcp oauth inventoryThe filename is the connection name. If you change the server URL, run
mcp oauth again.
Connect on first use
Without a prior mcp oauth, the first call to the server pauses the
turn, and the playground shows Connect. Finish the browser flow,
and the call retries in the running process.
A turn waits for Connect only when a person can click it:
- A playground or HTTP chat turn.
- A Slack message, when the channel shows Connect through
slackChannel({ toolApprovals: true })orbuildToolApprovalEventsinevents.
The wait stops after 10 minutes or when the turn is interrupted.
Schedules, reminders, webhooks, evals, and Slack channels without
Connect don't wait. A required connection fails the call with
Reconnect <connection>, and an optional one is skipped, even in the
playground. Authorize those ahead of time with mcp oauth.
Keep privileged tools behind a wrapper
The model never sees a connection under bot/host-connections/. A
server tool reaches it through ctx.host.mcp and exposes one narrow
operation.
// bot/host-connections/inventory.tsimport { defineConnection } from "@grok/agent-sdk/connections";export default defineConnection({ url: "https://mcp.example.com/inventory", oauth: true, tools: ["lookup_stock"],});// bot/tools/get_stock.tsimport { defineTool } from "@grok/agent-sdk/tools";import { z } from "zod";export default defineTool({ description: "Read stock for one approved region.", inputSchema: z.object({ sku: z.string(), region: z.enum(["us-east", "us-west"]), }), async execute(input, ctx) { const result = await ctx.host.mcp.callTool( "inventory", "lookup_stock", input ); return { ok: result.isError !== true, stock: result.structuredContent ?? null, }; },});Use an OAuth server from a hosted agent
Tokens from mcp oauth stay on the machine that authorized them. For a
Cursor-hosted agent, add the server under MCP in the Cursor dashboard,
reach it through a
cursorAccount: true connection,
and connect it from Deployed Agents.
Anyone who can use the agent can use that connection, so narrow its
servers list.
Choose where credentials live
| Connection | Credentials live in | Use it when |
|---|---|---|
cursorAccount: true | Cursor's backend | You connected the server in the Cursor dashboard |
url with oauth: true | The serve host | The serve host should own access |
url with headers | Your secrets | The server takes an API key or bearer token |
Host OAuth can't share a connection with per-session auth, which
gives each caller its own downstream identity.
Related
- Follow the
bdk-mcp-authskill, then runagent-sdk mcp oauth <connection>. - MCP connections