Skip to main content

Command Palette

Search for a command to run...

Agent SDK

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 inventory

The 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 }) or buildToolApprovalEvents in events.

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

ConnectionCredentials live inUse it when
cursorAccount: trueCursor's backendYou connected the server in the Cursor dashboard
url with oauth: trueThe serve hostThe serve host should own access
url with headersYour secretsThe 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.

  • Follow the bdk-mcp-auth skill, then run agent-sdk mcp oauth <connection>.
  • MCP connections