Skip to content

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.

ts
// bot/mcp-connections/inventory.ts
import { defineConnection } from "@grok/agent-sdk/connections";

export default defineConnection({
  url: "https://mcp.example.com/inventory",
  oauth: true,
  advertiseTools: true,
});
bash
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.

ts
// bot/host-connections/inventory.ts
import { defineConnection } from "@grok/agent-sdk/connections";

export default defineConnection({
  url: "https://mcp.example.com/inventory",
  oauth: true,
  tools: ["lookup_stock"],
});
ts
// bot/tools/get_stock.ts
import { 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