Appearance
Host MCP OAuth
Use host MCP OAuth when your agent talks to a remote MCP server that speaks OAuth, and you want credentials on the serve host (or the hosted engine) instead of a Cursor account connector. Local login writes tokens next to your Cursor credentials. --store copies them onto the deployment as secrets so prod can reconnect after a redeploy.
The companion skill is skills/mcp-auth/SKILL.md.
What can host MCP OAuth do?
- Authorize
defineConnection({ url, oauth: true })with a browser PKCE flow (agent-sdk mcp oauth <connection>) - Keep tokens in
~/.config/agent-serve/mcp-auth.json, bound to that connection's resource URL - Upsert deployment secrets with
--storeso hosted engines seed the same tokens from env - Keep privileged servers off the model with
hostOnly: truewhile tools still call them throughctx.host.mcp
Prefer a Cursor account MCP connection when the connector already lives in the signed-in account dashboard:
ts
defineConnection({ cursorAccount: true }) // every connected connector
// or servers: "*" / servers: ["Linear"]Use host OAuth when the server is yours (or private to your network) and the host must hold tokens.
How do I declare a host-OAuth connection?
Add one file under agent/mcp-connections/. The filename is the connection name you pass to the CLI and to host.mcp.
ts
// agent/mcp-connections/inventory.ts
import { defineConnection } from "@cursor/july/connections";
export default defineConnection({
url: "https://mcp.example.com/inventory",
oauth: true,
hostOnly: true,
description:
"Inventory MCP (privileged). Call only from host tools, not the model.",
});Rules of the road:
oauth: trueis required foragent-sdk mcp oauthhostOnly: truehides the server from the model;ctx.host.mcpand channel handlers still see it- Declare expected secret names on the agent when you plan to
--store:
ts
// agent/agent.ts
export default defineAgent({
// …
hosting: {
secretNames: [
"MCP_OAUTH_INVENTORY_ACCESS_TOKEN",
"MCP_OAUTH_INVENTORY_REFRESH_TOKEN",
"MCP_OAUTH_INVENTORY_CLIENT_ID",
],
// Hosted engines need an explicit allowlist for non-bootstrap hosts.
egressDomains: ["mcp.example.com"],
},
});Secret names follow MCP_OAUTH_<CONNECTION>_* where <CONNECTION> is the connection filename uppercased with non-alphanumerics turned into underscores (inventory → MCP_OAUTH_INVENTORY_…).
How do I authorize locally?
From the agent project (Node 22.13+, not Bun):
bash
agent-sdk mcp oauth inventoryWhat happens:
- The Agent SDK loads
agent/mcp-connections/inventory.tsand checksoauth: true - It opens the authorization URL in your browser
- The callback lands on
http://localhost:8787/callback - Tokens land in
~/.config/agent-serve/mcp-auth.json(override the config dir withAGENT_SERVE_CONFIG_DIR)
If you're already authorized, the command prints that and exits. Re-run it after rotating tokens on the MCP server, or after you change the connection URL (tokens are bound to the resource URL).
How do I store credentials on a hosted deployment?
Authorize once, then push secrets to the deployment:
bash
agent-sdk mcp oauth inventory --store
# optional:
# --slug my-agent
# --team <cursor-team-id>--store upserts:
| Secret | Source |
|---|---|
MCP_OAUTH_<NAME>_ACCESS_TOKEN | access token (required) |
MCP_OAUTH_<NAME>_REFRESH_TOKEN | refresh token when the server returns one |
MCP_OAUTH_<NAME>_CLIENT_ID | dynamic client id when registration returned one |
You must be signed in (agent-sdk login) with permission to set secrets on that slug. Secrets apply on the next deploy; run agent-sdk deploy (or wait for your usual deploy path) after --store.
On the engine, when mcp-auth.json is empty, serve seeds the OAuth provider from those env vars so host MCP calls work without a browser on the pod.
How do host tools call the server?
Keep privileged calls on the host:
ts
const result = await ctx.host.mcp.callTool(
"inventory",
"list_warehouses",
{ region: "us-east" }
);The model never sees hostOnly tools in its MCP namespace list. If the agent asks to "check IDE MCP" or run mcp_auth, point it at your host tool instead.
What if authorization fails?
| What you see | What to do |
|---|---|
must be defineConnection({ url, oauth: true }) | Add oauth: true on that connection, or pick the right connection name |
| Callback never completes | Keep port 8787 free; finish the browser login on this machine |
Hosted calls unauthorized after --store | Confirm secrets with agent-sdk secrets list <slug>, then redeploy |
| Tokens ignored after URL change | Expected: resource URL binding drops stale entries. Re-run mcp oauth |
What's next
- MCP connections: transports,
hostOnly, account MCP - CLI: full flag list for
mcp oauth - Deployment: secrets, egress, and hosted engines
- Fix common agent problems: more symptom → fix tables