{
  "type": "guide",
  "id": "connect-an-agent-to-a-remote-mcp-server",
  "title": "Connect an agent to a remote MCP server",
  "summary": "How remote MCP works over Streamable HTTP in the 2026-07-28 spec, how OAuth sign-in is discovered, and copy-paste configs for Claude Code, Codex, Cursor, Gemini CLI, VS Code and Claude connectors.",
  "author": "Agentica Author",
  "tags": [
    "mcp",
    "remote-mcp",
    "streamable-http",
    "oauth",
    "setup"
  ],
  "published": "2026-10-02",
  "last_verified": "2026-10-02",
  "difficulty": "intermediate",
  "time_estimate": "25 min",
  "entries": [
    "model-context-protocol",
    "mcp-authorization",
    "claude-code",
    "codex-cli",
    "cursor",
    "gemini-cli",
    "mcp-inspector",
    "context7",
    "deepwiki-mcp",
    "notion-mcp",
    "github-mcp-server",
    "official-mcp-registry",
    "fastmcp",
    "cloudflare-agents",
    "workos-authkit-mcp",
    "stytch-connected-apps"
  ],
  "links": {
    "html": "https://indexagentica.com/guides/connect-an-agent-to-a-remote-mcp-server/",
    "markdown": "https://indexagentica.com/guides/connect-an-agent-to-a-remote-mcp-server.md",
    "json": "https://indexagentica.com/api/longform/guides/connect-an-agent-to-a-remote-mcp-server.json",
    "source": "https://github.com/Drudley/indexagentica/blob/main/content-long/guides/connect-an-agent-to-a-remote-mcp-server.md"
  },
  "status": "published",
  "prerequisites": [
    "An MCP client (Claude Code, Codex, Cursor, Gemini CLI, VS Code or Claude)",
    "curl and jq for the protocol walkthrough"
  ],
  "entries_detail": [
    {
      "id": "model-context-protocol",
      "name": "Model Context Protocol (MCP)",
      "summary": "Open protocol that standardizes how AI applications connect to external tools, data sources and prompts via MCP servers.",
      "url": "https://indexagentica.com/entries/model-context-protocol/",
      "json": "https://indexagentica.com/api/entries/model-context-protocol.json"
    },
    {
      "id": "mcp-authorization",
      "name": "MCP Authorization (OAuth 2.1 for MCP)",
      "summary": "The MCP specification's transport-level authorization flow for HTTP-based MCP servers, based on a subset of OAuth 2.1 and related RFCs.",
      "url": "https://indexagentica.com/entries/mcp-authorization/",
      "json": "https://indexagentica.com/api/entries/mcp-authorization.json"
    },
    {
      "id": "claude-code",
      "name": "Claude Code",
      "summary": "Anthropic's agentic coding tool that reads your codebase, edits files, runs commands and integrates with dev tools; available in terminal, IDE, desktop and browser.",
      "url": "https://indexagentica.com/entries/claude-code/",
      "json": "https://indexagentica.com/api/entries/claude-code.json"
    },
    {
      "id": "codex-cli",
      "name": "OpenAI Codex CLI",
      "summary": "OpenAI's lightweight open-source coding agent that runs in your terminal.",
      "url": "https://indexagentica.com/entries/codex-cli/",
      "json": "https://indexagentica.com/api/entries/codex-cli.json"
    },
    {
      "id": "cursor",
      "name": "Cursor",
      "summary": "AI code editor and coding agent with Agent mode, Rules, Skills, MCP servers and a CLI.",
      "url": "https://indexagentica.com/entries/cursor/",
      "json": "https://indexagentica.com/api/entries/cursor.json"
    },
    {
      "id": "gemini-cli",
      "name": "Gemini CLI",
      "summary": "Open-source AI agent from Google that brings Gemini models directly into your terminal.",
      "url": "https://indexagentica.com/entries/gemini-cli/",
      "json": "https://indexagentica.com/api/entries/gemini-cli.json"
    },
    {
      "id": "mcp-inspector",
      "name": "MCP Inspector",
      "summary": "Official interactive developer tool for testing and debugging MCP servers in the browser, on the command line or in the terminal.",
      "url": "https://indexagentica.com/entries/mcp-inspector/",
      "json": "https://indexagentica.com/api/entries/mcp-inspector.json"
    },
    {
      "id": "context7",
      "name": "Context7",
      "summary": "Upstash's MCP server and platform that pulls up-to-date, version-specific library documentation and code examples into AI coding tools.",
      "url": "https://indexagentica.com/entries/context7/",
      "json": "https://indexagentica.com/api/entries/context7.json"
    },
    {
      "id": "deepwiki-mcp",
      "name": "DeepWiki MCP",
      "summary": "Official DeepWiki MCP server: programmatic access to DeepWiki's public repository documentation and search (Ask Devin).",
      "url": "https://indexagentica.com/entries/deepwiki-mcp/",
      "json": "https://indexagentica.com/api/entries/deepwiki-mcp.json"
    },
    {
      "id": "notion-mcp",
      "name": "Notion MCP",
      "summary": "Notion's hosted remote MCP server that lets MCP clients search, read and write in your Notion workspace.",
      "url": "https://indexagentica.com/entries/notion-mcp/",
      "json": "https://indexagentica.com/api/entries/notion-mcp.json"
    },
    {
      "id": "github-mcp-server",
      "name": "GitHub MCP Server",
      "summary": "GitHub's official MCP server: lets agents read repos and code, manage issues and PRs, analyze code and monitor Actions workflows.",
      "url": "https://indexagentica.com/entries/github-mcp-server/",
      "json": "https://indexagentica.com/api/entries/github-mcp-server.json"
    },
    {
      "id": "official-mcp-registry",
      "name": "Official MCP Registry",
      "summary": "Community-driven registry service from the MCP project listing published MCP servers, with a public REST API (like an app store for MCP servers).",
      "url": "https://indexagentica.com/entries/official-mcp-registry/",
      "json": "https://indexagentica.com/api/entries/official-mcp-registry.json"
    },
    {
      "id": "fastmcp",
      "name": "FastMCP",
      "summary": "The fast, Pythonic framework for building MCP servers, clients and interactive applications.",
      "url": "https://indexagentica.com/entries/fastmcp/",
      "json": "https://indexagentica.com/api/entries/fastmcp.json"
    },
    {
      "id": "cloudflare-agents",
      "name": "Cloudflare Agents SDK",
      "summary": "SDK for stateful AI agents on Cloudflare with persistent state, real-time WebSockets, scheduled tasks and remote MCP servers.",
      "url": "https://indexagentica.com/entries/cloudflare-agents/",
      "json": "https://indexagentica.com/api/entries/cloudflare-agents.json"
    },
    {
      "id": "workos-authkit-mcp",
      "name": "WorkOS AuthKit for MCP",
      "summary": "WorkOS AuthKit guide and support for securing MCP servers that require authentication.",
      "url": "https://indexagentica.com/entries/workos-authkit-mcp/",
      "json": "https://indexagentica.com/api/entries/workos-authkit-mcp.json"
    },
    {
      "id": "stytch-connected-apps",
      "name": "Stytch Connected Apps (MCP auth)",
      "summary": "Stytch Connected Apps: authorization for remote MCP servers and connected agent integrations.",
      "url": "https://indexagentica.com/entries/stytch-connected-apps/",
      "json": "https://indexagentica.com/api/entries/stytch-connected-apps.json"
    }
  ],
  "related": [
    {
      "type": "guide",
      "id": "add-mcp-servers-to-claude-code",
      "title": "Add MCP servers to Claude Code",
      "url": "https://indexagentica.com/guides/add-mcp-servers-to-claude-code/",
      "json": "https://indexagentica.com/api/longform/guides/add-mcp-servers-to-claude-code.json"
    },
    {
      "type": "skill",
      "id": "connect-remote-mcp",
      "title": "Connect a remote MCP server",
      "url": "https://indexagentica.com/skills/connect-remote-mcp/",
      "json": "https://indexagentica.com/api/longform/skills/connect-remote-mcp.json"
    },
    {
      "type": "skill",
      "id": "indexagentica-lookup",
      "title": "Index Agentica lookup",
      "url": "https://indexagentica.com/skills/indexagentica-lookup/",
      "json": "https://indexagentica.com/api/longform/skills/indexagentica-lookup.json"
    },
    {
      "type": "comparison",
      "id": "coding-agent-harnesses",
      "title": "Terminal coding agents compared",
      "url": "https://indexagentica.com/compare/coding-agent-harnesses/",
      "json": "https://indexagentica.com/api/longform/compare/coding-agent-harnesses.json"
    },
    {
      "type": "comparison",
      "id": "web-search-apis",
      "title": "Web search APIs for agents",
      "url": "https://indexagentica.com/compare/web-search-apis/",
      "json": "https://indexagentica.com/api/longform/compare/web-search-apis.json"
    }
  ],
  "sources": [
    {
      "title": "MCP specification, Versioning (current version 2026-07-28)",
      "url": "https://modelcontextprotocol.io/docs/2026-07-28/learn/versioning",
      "accessed": "2026-10-02"
    },
    {
      "title": "MCP specification 2026-07-28, Key changes",
      "url": "https://modelcontextprotocol.io/specification/2026-07-28/changelog",
      "accessed": "2026-10-02"
    },
    {
      "title": "MCP specification 2026-07-28, Streamable HTTP transport",
      "url": "https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http",
      "accessed": "2026-10-02"
    },
    {
      "title": "MCP specification 2026-07-28, Authorization",
      "url": "https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization",
      "accessed": "2026-10-02"
    },
    {
      "title": "Claude Code docs, Connect Claude Code to tools via MCP",
      "url": "https://code.claude.com/docs/en/mcp",
      "accessed": "2026-10-02"
    },
    {
      "title": "OpenAI Codex docs, Model Context Protocol",
      "url": "https://learn.chatgpt.com/docs/extend/mcp",
      "accessed": "2026-10-02"
    },
    {
      "title": "Cursor docs, Model Context Protocol",
      "url": "https://cursor.com/docs/mcp",
      "accessed": "2026-10-02"
    },
    {
      "title": "Gemini CLI docs, MCP servers",
      "url": "https://github.com/google-gemini/gemini-cli/blob/main/docs/tools/mcp-server.md",
      "accessed": "2026-10-02"
    },
    {
      "title": "VS Code docs, Add and manage MCP servers",
      "url": "https://code.visualstudio.com/docs/agent-customization/mcp-servers",
      "accessed": "2026-10-02"
    },
    {
      "title": "Claude Help Center, Getting started with custom connectors using remote MCP",
      "url": "https://support.claude.com/en/articles/11175166-get-started-with-custom-connectors-using-remote-mcp",
      "accessed": "2026-10-02"
    },
    {
      "title": "Notion MCP OAuth Protected Resource Metadata (live response)",
      "url": "https://mcp.notion.com/.well-known/oauth-protected-resource/mcp",
      "accessed": "2026-10-02"
    }
  ],
  "front_matter": {
    "id": "connect-an-agent-to-a-remote-mcp-server",
    "type": "guide",
    "title": "Connect an agent to a remote MCP server",
    "summary": "How remote MCP works over Streamable HTTP in the 2026-07-28 spec, how OAuth sign-in is discovered, and copy-paste configs for Claude Code, Codex, Cursor, Gemini CLI, VS Code and Claude connectors.",
    "description": "A client-side guide to remote Model Context Protocol servers. It explains the Streamable HTTP transport, the stateless 2026-07-28 revision and how to stay compatible with servers on 2025-11-25, OAuth 2.1 discovery through Protected Resource Metadata, and the exact configuration syntax for the major agent clients.",
    "author": "Agentica Author",
    "difficulty": "intermediate",
    "time_estimate": "25 min",
    "prerequisites": [
      "An MCP client (Claude Code, Codex, Cursor, Gemini CLI, VS Code or Claude)",
      "curl and jq for the protocol walkthrough"
    ],
    "tags": [
      "mcp",
      "remote-mcp",
      "streamable-http",
      "oauth",
      "setup"
    ],
    "entries": [
      "model-context-protocol",
      "mcp-authorization",
      "claude-code",
      "codex-cli",
      "cursor",
      "gemini-cli",
      "mcp-inspector",
      "context7",
      "deepwiki-mcp",
      "notion-mcp",
      "github-mcp-server",
      "official-mcp-registry",
      "fastmcp",
      "cloudflare-agents",
      "workos-authkit-mcp",
      "stytch-connected-apps"
    ],
    "sources": [
      {
        "title": "MCP specification, Versioning (current version 2026-07-28)",
        "url": "https://modelcontextprotocol.io/docs/2026-07-28/learn/versioning",
        "accessed": "2026-10-02"
      },
      {
        "title": "MCP specification 2026-07-28, Key changes",
        "url": "https://modelcontextprotocol.io/specification/2026-07-28/changelog",
        "accessed": "2026-10-02"
      },
      {
        "title": "MCP specification 2026-07-28, Streamable HTTP transport",
        "url": "https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http",
        "accessed": "2026-10-02"
      },
      {
        "title": "MCP specification 2026-07-28, Authorization",
        "url": "https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization",
        "accessed": "2026-10-02"
      },
      {
        "title": "Claude Code docs, Connect Claude Code to tools via MCP",
        "url": "https://code.claude.com/docs/en/mcp",
        "accessed": "2026-10-02"
      },
      {
        "title": "OpenAI Codex docs, Model Context Protocol",
        "url": "https://learn.chatgpt.com/docs/extend/mcp",
        "accessed": "2026-10-02"
      },
      {
        "title": "Cursor docs, Model Context Protocol",
        "url": "https://cursor.com/docs/mcp",
        "accessed": "2026-10-02"
      },
      {
        "title": "Gemini CLI docs, MCP servers",
        "url": "https://github.com/google-gemini/gemini-cli/blob/main/docs/tools/mcp-server.md",
        "accessed": "2026-10-02"
      },
      {
        "title": "VS Code docs, Add and manage MCP servers",
        "url": "https://code.visualstudio.com/docs/agent-customization/mcp-servers",
        "accessed": "2026-10-02"
      },
      {
        "title": "Claude Help Center, Getting started with custom connectors using remote MCP",
        "url": "https://support.claude.com/en/articles/11175166-get-started-with-custom-connectors-using-remote-mcp",
        "accessed": "2026-10-02"
      },
      {
        "title": "Notion MCP OAuth Protected Resource Metadata (live response)",
        "url": "https://mcp.notion.com/.well-known/oauth-protected-resource/mcp",
        "accessed": "2026-10-02"
      }
    ],
    "related": [
      "add-mcp-servers-to-claude-code",
      "connect-remote-mcp",
      "indexagentica-lookup",
      "coding-agent-harnesses",
      "web-search-apis"
    ],
    "last_verified": "2026-10-02",
    "published": "2026-10-02"
  },
  "markdown": "\nA **remote** MCP server is an MCP server you reach at a URL, such as `https://mcp.notion.com/mcp`, instead of a process your client launches. You don't install anything locally, every client can share it, and sign-in usually goes through OAuth in a browser. This guide covers what happens on the wire, how authorization is discovered, and the exact configuration for the major clients.\n\nIf you only need Claude Code commands, see [Add MCP servers to Claude Code](https://indexagentica.com/guides/add-mcp-servers-to-claude-code/).\n\n## Know which spec version you are dealing with\n\nThe [MCP specification](https://indexagentica.com/entries/model-context-protocol/)'s current version is **2026-07-28**, and it changed remote MCP a lot compared with **2025-11-25**:\n\n| | 2025-03-26 to 2025-11-25 (\"legacy\") | 2026-07-28 (\"modern\") |\n|---|---|---|\n| Handshake | `initialize` + `notifications/initialized` | None. Every request carries its version and capabilities in `_meta` |\n| Sessions | Optional `Mcp-Session-Id` header | Removed. Servers keep state in explicit handles passed as tool arguments |\n| Server-to-client stream | `GET` on the endpoint opens SSE | Removed. `subscriptions/listen` instead |\n| Server asking the client for input | Server sends requests (sampling, elicitation) | Returns `InputRequiredResult`, and the client retries with `inputResponses` |\n| Required HTTP headers | `MCP-Protocol-Version` (since 2025-06-18) | `MCP-Protocol-Version`, `Mcp-Method`, `Mcp-Name` |\n| Discovery | `initialize` result | Mandatory `server/discover` RPC |\n\nThe spec also now deprecates Roots, Sampling, Logging, the old HTTP+SSE transport and OAuth Dynamic Client Registration (in favor of Client ID Metadata Documents).\n\nIn practice both eras are live today. On 2026-10-02, a `server/discover` request to Context7's endpoint succeeded with `supportedVersions: [\"2026-07-28\"]`, and the same server still answered a legacy `initialize`. DeepWiki's endpoint rejected 2026-07-28 and listed `2024-11-05, 2025-03-26, 2025-06-18, 2025-11-25`. Clients are expected to negotiate. The spec's backward-compatibility rule: try a modern request first, and if you get `400` with no recognized modern JSON-RPC error in the body, fall back to `initialize`.\n\n## The transport: Streamable HTTP\n\nThe server exposes **one endpoint** that accepts `POST`. Each JSON-RPC message is its own POST, and the server replies with either a single `application/json` object or a short `text/event-stream` (SSE) stream scoped to that request, so clients must handle both. The client must send `Accept: application/json, text/event-stream`.\n\nYou can try this with curl. A modern request looks like this:\n\n```bash\ncurl -s https://mcp.context7.com/mcp \\\n  -H 'content-type: application/json' \\\n  -H 'accept: application/json, text/event-stream' \\\n  -H 'MCP-Protocol-Version: 2026-07-28' \\\n  -H 'Mcp-Method: server/discover' \\\n  -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"server/discover\",\"params\":{\"_meta\":{\"io.modelcontextprotocol/protocolVersion\":\"2026-07-28\",\"io.modelcontextprotocol/clientCapabilities\":{}}}}' | jq .\n```\n\nA legacy handshake looks like this:\n\n```bash\ncurl -s https://mcp.deepwiki.com/mcp \\\n  -H 'content-type: application/json' \\\n  -H 'accept: application/json, text/event-stream' \\\n  -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"initialize\",\"params\":{\"protocolVersion\":\"2025-11-25\",\"capabilities\":{},\"clientInfo\":{\"name\":\"curl\",\"version\":\"0\"}}}'\n```\n\nErrors worth recognizing:\n\n| Response | Meaning |\n|---|---|\n| `400` + JSON-RPC `-32022` (UnsupportedProtocolVersion) | Retry with a version from the `supported` list |\n| `400` + `-32020` (HeaderMismatch) | `MCP-Protocol-Version`, `Mcp-Method` or `Mcp-Name` doesn't match the body |\n| `404` + `-32601` | Method not found on a modern server |\n| `405` on GET | A modern server has no GET stream, which is normal |\n| `401` + `WWW-Authenticate` | Authorization required (next section) |\n\nFor interactive debugging, [MCP Inspector](https://indexagentica.com/entries/mcp-inspector/) is easier than curl.\n\n## Authorization: how OAuth sign-in is discovered\n\nAuthorization is optional in MCP, but when an HTTP server uses it, it must follow the spec's OAuth 2.1 profile. The server is an OAuth **resource server**, your client is an OAuth **client**, and an authorization server issues the tokens. See [MCP Authorization](https://indexagentica.com/entries/mcp-authorization/).\n\n```mermaid\nsequenceDiagram\n    participant C as MCP client\n    participant M as MCP server\n    participant A as Authorization server\n    C->>M: POST /mcp (no token)\n    M-->>C: 401 WWW-Authenticate: Bearer resource_metadata=\"...\"\n    C->>M: GET /.well-known/oauth-protected-resource (RFC 9728)\n    M-->>C: authorization_servers, scopes_supported\n    C->>A: GET /.well-known/oauth-authorization-server (RFC 8414) or OIDC discovery\n    Note over C,A: register: Client ID Metadata Document, pre-registered id, or DCR\n    C->>A: browser: authorization code + PKCE + resource=<server URL>\n    A-->>C: code (+ iss, checked against recorded issuer)\n    C->>A: token request + code_verifier + resource\n    A-->>C: access token\n    C->>M: POST /mcp, Authorization: Bearer <token>\n```\n\nYou can watch the first two steps against Notion's server:\n\n```bash\ncurl -s -o /dev/null -D - -X POST https://mcp.notion.com/mcp -H 'content-type: application/json' -d '{}' | grep -i www-authenticate\n# www-authenticate: Bearer realm=\"OAuth\", resource_metadata=\"https://mcp.notion.com/.well-known/oauth-protected-resource/mcp\", ...\ncurl -s https://mcp.notion.com/.well-known/oauth-protected-resource/mcp | jq .\n# {\"resource\":\"https://mcp.notion.com/mcp\",\"authorization_servers\":[\"https://mcp.notion.com\"],\"scopes_supported\":[\"default\"],...}\n```\n\nRules from the spec that matter to client authors and to anyone debugging sign-in:\n\n- The `resource` parameter (RFC 8707) **must** be in both the authorization and token requests, set to the server's canonical URI, for example `https://mcp.example.com/mcp` (no fragment, preferably no trailing slash).\n- Scopes: use the `scope` from the `WWW-Authenticate` challenge if present, otherwise `scopes_supported` from the metadata. A later `403` with `error=\"insufficient_scope\"` means step-up. Re-authorize with the **union** of old and new scopes.\n- The token goes in `Authorization: Bearer ...` on **every** request and never in the query string.\n- Servers must check that the token was issued for them (audience) and must not forward it to upstream APIs.\n- Client registration preference: Client ID Metadata Documents first, then a pre-registered client id, then Dynamic Client Registration (deprecated).\n- Clients must validate a returned `iss` against the expected issuer (RFC 9207) before redeeming the code. This is a 2026-07-28 change.\n\nMany servers skip OAuth and accept a static key in a header. Every client below supports headers.\n\n## Client configuration\n\n### Claude Code\n\n```bash\nclaude mcp add --transport http notion https://mcp.notion.com/mcp     # OAuth: then run /mcp or `claude mcp login notion`\nclaude mcp add --transport http secure-api https://api.example.com/mcp --header \"Authorization: Bearer $TOKEN\"\n```\n\nTo share a server with a project, put it in `.mcp.json`. **`type` is required.** An entry with a `url` and no `type` is read as a stdio server and skipped:\n\n```json\n{\n  \"mcpServers\": {\n    \"notion\": { \"type\": \"http\", \"url\": \"https://mcp.notion.com/mcp\" }\n  }\n}\n```\n\n`claude mcp login <name> --no-browser` works over SSH. Pre-registered OAuth apps use `--client-id`, `--client-secret` and `--callback-port`. Claude Code's v2 MCP runtime (TypeScript SDK 2.0) adds 2026-07-28 support. See [Claude Code](https://indexagentica.com/entries/claude-code/).\n\n### OpenAI Codex (CLI, IDE extension, ChatGPT desktop)\n\nAll three share `~/.codex/config.toml` (or a trusted project's `.codex/config.toml`):\n\n```toml\n[mcp_servers.notion]\nurl = \"https://mcp.notion.com/mcp\"\n\n[mcp_servers.figma]\nurl = \"https://mcp.figma.com/mcp\"\nbearer_token_env_var = \"FIGMA_OAUTH_TOKEN\"\n```\n\n```bash\ncodex mcp add notion --url https://mcp.notion.com/mcp\ncodex mcp login notion          # OAuth; supports CIMD and DCR\n```\n\nUseful keys: `http_headers`, `env_http_headers`, `enabled_tools`, `disabled_tools`, `tool_timeout_sec` (default 60) and `startup_timeout_sec` (default 10). See [Codex CLI](https://indexagentica.com/entries/codex-cli/).\n\n### Cursor\n\nUse `.cursor/mcp.json` in the project or `~/.cursor/mcp.json` globally. A remote server is just a `url`:\n\n```json\n{\n  \"mcpServers\": {\n    \"remote-server\": {\n      \"url\": \"https://api.example.com/mcp\",\n      \"headers\": { \"Authorization\": \"Bearer ${env:MY_SERVICE_TOKEN}\" }\n    }\n  }\n}\n```\n\nCursor handles OAuth automatically and accepts static OAuth credentials under `\"auth\": {\"CLIENT_ID\": \"...\", \"CLIENT_SECRET\": \"...\"}`. See [Cursor](https://indexagentica.com/entries/cursor/).\n\n### Gemini CLI\n\nIn `settings.json`, **`httpUrl` is Streamable HTTP and `url` is SSE**, which is an easy mistake to make:\n\n```json\n{\n  \"mcpServers\": {\n    \"notion\": { \"httpUrl\": \"https://mcp.notion.com/mcp\" }\n  }\n}\n```\n\nOAuth is discovered automatically after a `401`. Manage it with `/mcp auth`. Tokens are stored in `~/.gemini/mcp-oauth-tokens.json`. See [Gemini CLI](https://indexagentica.com/entries/gemini-cli/).\n\n### VS Code (GitHub Copilot)\n\nVS Code now prefers a **portable `.mcp.json`** at the workspace root (top-level `mcpServers`) or `~/.copilot/mcp-config.json`. It calls the older `.vscode/mcp.json` (top-level `servers`) deprecated but still reads it:\n\n```json\n{\n  \"servers\": {\n    \"github\": { \"type\": \"http\", \"url\": \"https://api.githubcopilot.com/mcp\" }\n  }\n}\n```\n\n### Claude (web and desktop) custom connectors\n\nGo to **Customize > Connectors > + Add > Add custom connector**, then enter a name and the server URL. Choose \"Sign in now\", \"Sign in when needed\" or \"No sign in\", and an OAuth client mode (Claude's published identity is recommended). On Team and Enterprise plans, Owners add connectors under Organization settings. Connectors you add on claude.ai also show up in Claude Code when you're signed in with that account.\n\n## Before you trust a server\n\n- **Prompt injection.** Tool results are untrusted text. Servers that fetch web or user content can carry instructions aimed at your agent.\n- **Scope.** Grant the narrowest OAuth scopes. Claude Code's `oauth.scopes` and Codex's `enabled_tools` let you pin them.\n- **Provenance.** Prefer servers that the vendor itself runs or lists. The [Official MCP Registry](https://indexagentica.com/entries/official-mcp-registry/) is a good place to check.\n- **Local servers** should bind to `127.0.0.1`, and every server must validate `Origin`, which blocks DNS-rebinding attacks.\n\n## Next steps\n\n- Load the [connect-remote-mcp skill](https://indexagentica.com/skills/connect-remote-mcp/) so an agent can set this up itself.\n- Building your own server: [FastMCP](https://indexagentica.com/entries/fastmcp/) and the [Cloudflare Agents SDK](https://indexagentica.com/entries/cloudflare-agents/) both deploy remote servers. [WorkOS AuthKit](https://indexagentica.com/entries/workos-authkit-mcp/) and [Stytch](https://indexagentica.com/entries/stytch-connected-apps/) provide the OAuth side.\n- To find servers, search [Index Agentica](https://indexagentica.com/skills/indexagentica-lookup/).\n",
  "raw": "---\nid: connect-an-agent-to-a-remote-mcp-server\ntype: guide\ntitle: Connect an agent to a remote MCP server\nsummary: How remote MCP works over Streamable HTTP in the 2026-07-28 spec, how OAuth sign-in is discovered, and copy-paste configs for Claude Code, Codex, Cursor, Gemini CLI, VS Code and Claude connectors.\ndescription: A client-side guide to remote Model Context Protocol servers. It explains the Streamable HTTP transport, the stateless 2026-07-28 revision and how to stay compatible with servers on 2025-11-25, OAuth 2.1 discovery through Protected Resource Metadata, and the exact configuration syntax for the major agent clients.\nauthor: Agentica Author\ndifficulty: intermediate\ntime_estimate: 25 min\nprerequisites:\n  - An MCP client (Claude Code, Codex, Cursor, Gemini CLI, VS Code or Claude)\n  - curl and jq for the protocol walkthrough\ntags: [mcp, remote-mcp, streamable-http, oauth, setup]\nentries: [model-context-protocol, mcp-authorization, claude-code, codex-cli, cursor, gemini-cli, mcp-inspector, context7, deepwiki-mcp, notion-mcp, github-mcp-server, official-mcp-registry, fastmcp, cloudflare-agents, workos-authkit-mcp, stytch-connected-apps]\nsources:\n  - title: MCP specification, Versioning (current version 2026-07-28)\n    url: https://modelcontextprotocol.io/docs/2026-07-28/learn/versioning\n    accessed: 2026-10-02\n  - title: MCP specification 2026-07-28, Key changes\n    url: https://modelcontextprotocol.io/specification/2026-07-28/changelog\n    accessed: 2026-10-02\n  - title: MCP specification 2026-07-28, Streamable HTTP transport\n    url: https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http\n    accessed: 2026-10-02\n  - title: MCP specification 2026-07-28, Authorization\n    url: https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization\n    accessed: 2026-10-02\n  - title: Claude Code docs, Connect Claude Code to tools via MCP\n    url: https://code.claude.com/docs/en/mcp\n    accessed: 2026-10-02\n  - title: OpenAI Codex docs, Model Context Protocol\n    url: https://learn.chatgpt.com/docs/extend/mcp\n    accessed: 2026-10-02\n  - title: Cursor docs, Model Context Protocol\n    url: https://cursor.com/docs/mcp\n    accessed: 2026-10-02\n  - title: Gemini CLI docs, MCP servers\n    url: https://github.com/google-gemini/gemini-cli/blob/main/docs/tools/mcp-server.md\n    accessed: 2026-10-02\n  - title: VS Code docs, Add and manage MCP servers\n    url: https://code.visualstudio.com/docs/agent-customization/mcp-servers\n    accessed: 2026-10-02\n  - title: Claude Help Center, Getting started with custom connectors using remote MCP\n    url: https://support.claude.com/en/articles/11175166-get-started-with-custom-connectors-using-remote-mcp\n    accessed: 2026-10-02\n  - title: Notion MCP OAuth Protected Resource Metadata (live response)\n    url: https://mcp.notion.com/.well-known/oauth-protected-resource/mcp\n    accessed: 2026-10-02\nrelated: [add-mcp-servers-to-claude-code, connect-remote-mcp, indexagentica-lookup, coding-agent-harnesses, web-search-apis]\nlast_verified: 2026-10-02\npublished: 2026-10-02\n---\n\nA **remote** MCP server is an MCP server you reach at a URL, such as `https://mcp.notion.com/mcp`, instead of a process your client launches. You don't install anything locally, every client can share it, and sign-in usually goes through OAuth in a browser. This guide covers what happens on the wire, how authorization is discovered, and the exact configuration for the major clients.\n\nIf you only need Claude Code commands, see [Add MCP servers to Claude Code](https://indexagentica.com/guides/add-mcp-servers-to-claude-code/).\n\n## Know which spec version you are dealing with\n\nThe [MCP specification](https://indexagentica.com/entries/model-context-protocol/)'s current version is **2026-07-28**, and it changed remote MCP a lot compared with **2025-11-25**:\n\n| | 2025-03-26 to 2025-11-25 (\"legacy\") | 2026-07-28 (\"modern\") |\n|---|---|---|\n| Handshake | `initialize` + `notifications/initialized` | None. Every request carries its version and capabilities in `_meta` |\n| Sessions | Optional `Mcp-Session-Id` header | Removed. Servers keep state in explicit handles passed as tool arguments |\n| Server-to-client stream | `GET` on the endpoint opens SSE | Removed. `subscriptions/listen` instead |\n| Server asking the client for input | Server sends requests (sampling, elicitation) | Returns `InputRequiredResult`, and the client retries with `inputResponses` |\n| Required HTTP headers | `MCP-Protocol-Version` (since 2025-06-18) | `MCP-Protocol-Version`, `Mcp-Method`, `Mcp-Name` |\n| Discovery | `initialize` result | Mandatory `server/discover` RPC |\n\nThe spec also now deprecates Roots, Sampling, Logging, the old HTTP+SSE transport and OAuth Dynamic Client Registration (in favor of Client ID Metadata Documents).\n\nIn practice both eras are live today. On 2026-10-02, a `server/discover` request to Context7's endpoint succeeded with `supportedVersions: [\"2026-07-28\"]`, and the same server still answered a legacy `initialize`. DeepWiki's endpoint rejected 2026-07-28 and listed `2024-11-05, 2025-03-26, 2025-06-18, 2025-11-25`. Clients are expected to negotiate. The spec's backward-compatibility rule: try a modern request first, and if you get `400` with no recognized modern JSON-RPC error in the body, fall back to `initialize`.\n\n## The transport: Streamable HTTP\n\nThe server exposes **one endpoint** that accepts `POST`. Each JSON-RPC message is its own POST, and the server replies with either a single `application/json` object or a short `text/event-stream` (SSE) stream scoped to that request, so clients must handle both. The client must send `Accept: application/json, text/event-stream`.\n\nYou can try this with curl. A modern request looks like this:\n\n```bash\ncurl -s https://mcp.context7.com/mcp \\\n  -H 'content-type: application/json' \\\n  -H 'accept: application/json, text/event-stream' \\\n  -H 'MCP-Protocol-Version: 2026-07-28' \\\n  -H 'Mcp-Method: server/discover' \\\n  -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"server/discover\",\"params\":{\"_meta\":{\"io.modelcontextprotocol/protocolVersion\":\"2026-07-28\",\"io.modelcontextprotocol/clientCapabilities\":{}}}}' | jq .\n```\n\nA legacy handshake looks like this:\n\n```bash\ncurl -s https://mcp.deepwiki.com/mcp \\\n  -H 'content-type: application/json' \\\n  -H 'accept: application/json, text/event-stream' \\\n  -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"initialize\",\"params\":{\"protocolVersion\":\"2025-11-25\",\"capabilities\":{},\"clientInfo\":{\"name\":\"curl\",\"version\":\"0\"}}}'\n```\n\nErrors worth recognizing:\n\n| Response | Meaning |\n|---|---|\n| `400` + JSON-RPC `-32022` (UnsupportedProtocolVersion) | Retry with a version from the `supported` list |\n| `400` + `-32020` (HeaderMismatch) | `MCP-Protocol-Version`, `Mcp-Method` or `Mcp-Name` doesn't match the body |\n| `404` + `-32601` | Method not found on a modern server |\n| `405` on GET | A modern server has no GET stream, which is normal |\n| `401` + `WWW-Authenticate` | Authorization required (next section) |\n\nFor interactive debugging, [MCP Inspector](https://indexagentica.com/entries/mcp-inspector/) is easier than curl.\n\n## Authorization: how OAuth sign-in is discovered\n\nAuthorization is optional in MCP, but when an HTTP server uses it, it must follow the spec's OAuth 2.1 profile. The server is an OAuth **resource server**, your client is an OAuth **client**, and an authorization server issues the tokens. See [MCP Authorization](https://indexagentica.com/entries/mcp-authorization/).\n\n```mermaid\nsequenceDiagram\n    participant C as MCP client\n    participant M as MCP server\n    participant A as Authorization server\n    C->>M: POST /mcp (no token)\n    M-->>C: 401 WWW-Authenticate: Bearer resource_metadata=\"...\"\n    C->>M: GET /.well-known/oauth-protected-resource (RFC 9728)\n    M-->>C: authorization_servers, scopes_supported\n    C->>A: GET /.well-known/oauth-authorization-server (RFC 8414) or OIDC discovery\n    Note over C,A: register: Client ID Metadata Document, pre-registered id, or DCR\n    C->>A: browser: authorization code + PKCE + resource=<server URL>\n    A-->>C: code (+ iss, checked against recorded issuer)\n    C->>A: token request + code_verifier + resource\n    A-->>C: access token\n    C->>M: POST /mcp, Authorization: Bearer <token>\n```\n\nYou can watch the first two steps against Notion's server:\n\n```bash\ncurl -s -o /dev/null -D - -X POST https://mcp.notion.com/mcp -H 'content-type: application/json' -d '{}' | grep -i www-authenticate\n# www-authenticate: Bearer realm=\"OAuth\", resource_metadata=\"https://mcp.notion.com/.well-known/oauth-protected-resource/mcp\", ...\ncurl -s https://mcp.notion.com/.well-known/oauth-protected-resource/mcp | jq .\n# {\"resource\":\"https://mcp.notion.com/mcp\",\"authorization_servers\":[\"https://mcp.notion.com\"],\"scopes_supported\":[\"default\"],...}\n```\n\nRules from the spec that matter to client authors and to anyone debugging sign-in:\n\n- The `resource` parameter (RFC 8707) **must** be in both the authorization and token requests, set to the server's canonical URI, for example `https://mcp.example.com/mcp` (no fragment, preferably no trailing slash).\n- Scopes: use the `scope` from the `WWW-Authenticate` challenge if present, otherwise `scopes_supported` from the metadata. A later `403` with `error=\"insufficient_scope\"` means step-up. Re-authorize with the **union** of old and new scopes.\n- The token goes in `Authorization: Bearer ...` on **every** request and never in the query string.\n- Servers must check that the token was issued for them (audience) and must not forward it to upstream APIs.\n- Client registration preference: Client ID Metadata Documents first, then a pre-registered client id, then Dynamic Client Registration (deprecated).\n- Clients must validate a returned `iss` against the expected issuer (RFC 9207) before redeeming the code. This is a 2026-07-28 change.\n\nMany servers skip OAuth and accept a static key in a header. Every client below supports headers.\n\n## Client configuration\n\n### Claude Code\n\n```bash\nclaude mcp add --transport http notion https://mcp.notion.com/mcp     # OAuth: then run /mcp or `claude mcp login notion`\nclaude mcp add --transport http secure-api https://api.example.com/mcp --header \"Authorization: Bearer $TOKEN\"\n```\n\nTo share a server with a project, put it in `.mcp.json`. **`type` is required.** An entry with a `url` and no `type` is read as a stdio server and skipped:\n\n```json\n{\n  \"mcpServers\": {\n    \"notion\": { \"type\": \"http\", \"url\": \"https://mcp.notion.com/mcp\" }\n  }\n}\n```\n\n`claude mcp login <name> --no-browser` works over SSH. Pre-registered OAuth apps use `--client-id`, `--client-secret` and `--callback-port`. Claude Code's v2 MCP runtime (TypeScript SDK 2.0) adds 2026-07-28 support. See [Claude Code](https://indexagentica.com/entries/claude-code/).\n\n### OpenAI Codex (CLI, IDE extension, ChatGPT desktop)\n\nAll three share `~/.codex/config.toml` (or a trusted project's `.codex/config.toml`):\n\n```toml\n[mcp_servers.notion]\nurl = \"https://mcp.notion.com/mcp\"\n\n[mcp_servers.figma]\nurl = \"https://mcp.figma.com/mcp\"\nbearer_token_env_var = \"FIGMA_OAUTH_TOKEN\"\n```\n\n```bash\ncodex mcp add notion --url https://mcp.notion.com/mcp\ncodex mcp login notion          # OAuth; supports CIMD and DCR\n```\n\nUseful keys: `http_headers`, `env_http_headers`, `enabled_tools`, `disabled_tools`, `tool_timeout_sec` (default 60) and `startup_timeout_sec` (default 10). See [Codex CLI](https://indexagentica.com/entries/codex-cli/).\n\n### Cursor\n\nUse `.cursor/mcp.json` in the project or `~/.cursor/mcp.json` globally. A remote server is just a `url`:\n\n```json\n{\n  \"mcpServers\": {\n    \"remote-server\": {\n      \"url\": \"https://api.example.com/mcp\",\n      \"headers\": { \"Authorization\": \"Bearer ${env:MY_SERVICE_TOKEN}\" }\n    }\n  }\n}\n```\n\nCursor handles OAuth automatically and accepts static OAuth credentials under `\"auth\": {\"CLIENT_ID\": \"...\", \"CLIENT_SECRET\": \"...\"}`. See [Cursor](https://indexagentica.com/entries/cursor/).\n\n### Gemini CLI\n\nIn `settings.json`, **`httpUrl` is Streamable HTTP and `url` is SSE**, which is an easy mistake to make:\n\n```json\n{\n  \"mcpServers\": {\n    \"notion\": { \"httpUrl\": \"https://mcp.notion.com/mcp\" }\n  }\n}\n```\n\nOAuth is discovered automatically after a `401`. Manage it with `/mcp auth`. Tokens are stored in `~/.gemini/mcp-oauth-tokens.json`. See [Gemini CLI](https://indexagentica.com/entries/gemini-cli/).\n\n### VS Code (GitHub Copilot)\n\nVS Code now prefers a **portable `.mcp.json`** at the workspace root (top-level `mcpServers`) or `~/.copilot/mcp-config.json`. It calls the older `.vscode/mcp.json` (top-level `servers`) deprecated but still reads it:\n\n```json\n{\n  \"servers\": {\n    \"github\": { \"type\": \"http\", \"url\": \"https://api.githubcopilot.com/mcp\" }\n  }\n}\n```\n\n### Claude (web and desktop) custom connectors\n\nGo to **Customize > Connectors > + Add > Add custom connector**, then enter a name and the server URL. Choose \"Sign in now\", \"Sign in when needed\" or \"No sign in\", and an OAuth client mode (Claude's published identity is recommended). On Team and Enterprise plans, Owners add connectors under Organization settings. Connectors you add on claude.ai also show up in Claude Code when you're signed in with that account.\n\n## Before you trust a server\n\n- **Prompt injection.** Tool results are untrusted text. Servers that fetch web or user content can carry instructions aimed at your agent.\n- **Scope.** Grant the narrowest OAuth scopes. Claude Code's `oauth.scopes` and Codex's `enabled_tools` let you pin them.\n- **Provenance.** Prefer servers that the vendor itself runs or lists. The [Official MCP Registry](https://indexagentica.com/entries/official-mcp-registry/) is a good place to check.\n- **Local servers** should bind to `127.0.0.1`, and every server must validate `Origin`, which blocks DNS-rebinding attacks.\n\n## Next steps\n\n- Load the [connect-remote-mcp skill](https://indexagentica.com/skills/connect-remote-mcp/) so an agent can set this up itself.\n- Building your own server: [FastMCP](https://indexagentica.com/entries/fastmcp/) and the [Cloudflare Agents SDK](https://indexagentica.com/entries/cloudflare-agents/) both deploy remote servers. [WorkOS AuthKit](https://indexagentica.com/entries/workos-authkit-mcp/) and [Stytch](https://indexagentica.com/entries/stytch-connected-apps/) provide the OAuth side.\n- To find servers, search [Index Agentica](https://indexagentica.com/skills/indexagentica-lookup/).\n",
  "html": "<p>A <strong>remote</strong> MCP server is an MCP server you reach at a URL, such as <code>https://mcp.notion.com/mcp</code>, instead of a process your client launches. You don&#39;t install anything locally, every client can share it, and sign-in usually goes through OAuth in a browser. This guide covers what happens on the wire, how authorization is discovered, and the exact configuration for the major clients.</p>\n<p>If you only need Claude Code commands, see <a href=\"/guides/add-mcp-servers-to-claude-code/\">Add MCP servers to Claude Code</a>.</p>\n<h2>Know which spec version you are dealing with</h2>\n<p>The <a href=\"/entries/model-context-protocol/\">MCP specification</a>&#39;s current version is <strong>2026-07-28</strong>, and it changed remote MCP a lot compared with <strong>2025-11-25</strong>:</p>\n<table><thead><tr><th scope=\"col\"></th><th scope=\"col\">2025-03-26 to 2025-11-25 (&quot;legacy&quot;)</th><th scope=\"col\">2026-07-28 (&quot;modern&quot;)</th></tr></thead><tbody><tr><td>Handshake</td><td><code>initialize</code> + <code>notifications/initialized</code></td><td>None. Every request carries its version and capabilities in <code>_meta</code></td></tr><tr><td>Sessions</td><td>Optional <code>Mcp-Session-Id</code> header</td><td>Removed. Servers keep state in explicit handles passed as tool arguments</td></tr><tr><td>Server-to-client stream</td><td><code>GET</code> on the endpoint opens SSE</td><td>Removed. <code>subscriptions/listen</code> instead</td></tr><tr><td>Server asking the client for input</td><td>Server sends requests (sampling, elicitation)</td><td>Returns <code>InputRequiredResult</code>, and the client retries with <code>inputResponses</code></td></tr><tr><td>Required HTTP headers</td><td><code>MCP-Protocol-Version</code> (since 2025-06-18)</td><td><code>MCP-Protocol-Version</code>, <code>Mcp-Method</code>, <code>Mcp-Name</code></td></tr><tr><td>Discovery</td><td><code>initialize</code> result</td><td>Mandatory <code>server/discover</code> RPC</td></tr></tbody></table>\n<p>The spec also now deprecates Roots, Sampling, Logging, the old HTTP+SSE transport and OAuth Dynamic Client Registration (in favor of Client ID Metadata Documents).</p>\n<p>In practice both eras are live today. On 2026-10-02, a <code>server/discover</code> request to Context7&#39;s endpoint succeeded with <code>supportedVersions: [&quot;2026-07-28&quot;]</code>, and the same server still answered a legacy <code>initialize</code>. DeepWiki&#39;s endpoint rejected 2026-07-28 and listed <code>2024-11-05, 2025-03-26, 2025-06-18, 2025-11-25</code>. Clients are expected to negotiate. The spec&#39;s backward-compatibility rule: try a modern request first, and if you get <code>400</code> with no recognized modern JSON-RPC error in the body, fall back to <code>initialize</code>.</p>\n<h2>The transport: Streamable HTTP</h2>\n<p>The server exposes <strong>one endpoint</strong> that accepts <code>POST</code>. Each JSON-RPC message is its own POST, and the server replies with either a single <code>application/json</code> object or a short <code>text/event-stream</code> (SSE) stream scoped to that request, so clients must handle both. The client must send <code>Accept: application/json, text/event-stream</code>.</p>\n<p>You can try this with curl. A modern request looks like this:</p>\n<pre><code class=\"language-bash\">curl -s https://mcp.context7.com/mcp \\\n  -H &#39;content-type: application/json&#39; \\\n  -H &#39;accept: application/json, text/event-stream&#39; \\\n  -H &#39;MCP-Protocol-Version: 2026-07-28&#39; \\\n  -H &#39;Mcp-Method: server/discover&#39; \\\n  -d &#39;{&quot;jsonrpc&quot;:&quot;2.0&quot;,&quot;id&quot;:1,&quot;method&quot;:&quot;server/discover&quot;,&quot;params&quot;:{&quot;_meta&quot;:{&quot;io.modelcontextprotocol/protocolVersion&quot;:&quot;2026-07-28&quot;,&quot;io.modelcontextprotocol/clientCapabilities&quot;:{}}}}&#39; | jq .</code></pre>\n<p>A legacy handshake looks like this:</p>\n<pre><code class=\"language-bash\">curl -s https://mcp.deepwiki.com/mcp \\\n  -H &#39;content-type: application/json&#39; \\\n  -H &#39;accept: application/json, text/event-stream&#39; \\\n  -d &#39;{&quot;jsonrpc&quot;:&quot;2.0&quot;,&quot;id&quot;:1,&quot;method&quot;:&quot;initialize&quot;,&quot;params&quot;:{&quot;protocolVersion&quot;:&quot;2025-11-25&quot;,&quot;capabilities&quot;:{},&quot;clientInfo&quot;:{&quot;name&quot;:&quot;curl&quot;,&quot;version&quot;:&quot;0&quot;}}}&#39;</code></pre>\n<p>Errors worth recognizing:</p>\n<table><thead><tr><th scope=\"col\">Response</th><th scope=\"col\">Meaning</th></tr></thead><tbody><tr><td><code>400</code> + JSON-RPC <code>-32022</code> (UnsupportedProtocolVersion)</td><td>Retry with a version from the <code>supported</code> list</td></tr><tr><td><code>400</code> + <code>-32020</code> (HeaderMismatch)</td><td><code>MCP-Protocol-Version</code>, <code>Mcp-Method</code> or <code>Mcp-Name</code> doesn&#39;t match the body</td></tr><tr><td><code>404</code> + <code>-32601</code></td><td>Method not found on a modern server</td></tr><tr><td><code>405</code> on GET</td><td>A modern server has no GET stream, which is normal</td></tr><tr><td><code>401</code> + <code>WWW-Authenticate</code></td><td>Authorization required (next section)</td></tr></tbody></table>\n<p>For interactive debugging, <a href=\"/entries/mcp-inspector/\">MCP Inspector</a> is easier than curl.</p>\n<h2>Authorization: how OAuth sign-in is discovered</h2>\n<p>Authorization is optional in MCP, but when an HTTP server uses it, it must follow the spec&#39;s OAuth 2.1 profile. The server is an OAuth <strong>resource server</strong>, your client is an OAuth <strong>client</strong>, and an authorization server issues the tokens. See <a href=\"/entries/mcp-authorization/\">MCP Authorization</a>.</p>\n<figure class=\"diagram\"><pre class=\"mermaid\">sequenceDiagram\n    participant C as MCP client\n    participant M as MCP server\n    participant A as Authorization server\n    C-&gt;&gt;M: POST /mcp (no token)\n    M--&gt;&gt;C: 401 WWW-Authenticate: Bearer resource_metadata=&quot;...&quot;\n    C-&gt;&gt;M: GET /.well-known/oauth-protected-resource (RFC 9728)\n    M--&gt;&gt;C: authorization_servers, scopes_supported\n    C-&gt;&gt;A: GET /.well-known/oauth-authorization-server (RFC 8414) or OIDC discovery\n    Note over C,A: register: Client ID Metadata Document, pre-registered id, or DCR\n    C-&gt;&gt;A: browser: authorization code + PKCE + resource=&lt;server URL&gt;\n    A--&gt;&gt;C: code (+ iss, checked against recorded issuer)\n    C-&gt;&gt;A: token request + code_verifier + resource\n    A--&gt;&gt;C: access token\n    C-&gt;&gt;M: POST /mcp, Authorization: Bearer &lt;token&gt;</pre><figcaption>Mermaid diagram (source shown; this site uses no JavaScript)</figcaption></figure>\n<p>You can watch the first two steps against Notion&#39;s server:</p>\n<pre><code class=\"language-bash\">curl -s -o /dev/null -D - -X POST https://mcp.notion.com/mcp -H &#39;content-type: application/json&#39; -d &#39;{}&#39; | grep -i www-authenticate\n# www-authenticate: Bearer realm=&quot;OAuth&quot;, resource_metadata=&quot;https://mcp.notion.com/.well-known/oauth-protected-resource/mcp&quot;, ...\ncurl -s https://mcp.notion.com/.well-known/oauth-protected-resource/mcp | jq .\n# {&quot;resource&quot;:&quot;https://mcp.notion.com/mcp&quot;,&quot;authorization_servers&quot;:[&quot;https://mcp.notion.com&quot;],&quot;scopes_supported&quot;:[&quot;default&quot;],...}</code></pre>\n<p>Rules from the spec that matter to client authors and to anyone debugging sign-in:</p>\n<ul><li>The <code>resource</code> parameter (RFC 8707) <strong>must</strong> be in both the authorization and token requests, set to the server&#39;s canonical URI, for example <code>https://mcp.example.com/mcp</code> (no fragment, preferably no trailing slash).</li><li>Scopes: use the <code>scope</code> from the <code>WWW-Authenticate</code> challenge if present, otherwise <code>scopes_supported</code> from the metadata. A later <code>403</code> with <code>error=&quot;insufficient_scope&quot;</code> means step-up. Re-authorize with the <strong>union</strong> of old and new scopes.</li><li>The token goes in <code>Authorization: Bearer ...</code> on <strong>every</strong> request and never in the query string.</li><li>Servers must check that the token was issued for them (audience) and must not forward it to upstream APIs.</li><li>Client registration preference: Client ID Metadata Documents first, then a pre-registered client id, then Dynamic Client Registration (deprecated).</li><li>Clients must validate a returned <code>iss</code> against the expected issuer (RFC 9207) before redeeming the code. This is a 2026-07-28 change.</li></ul>\n<p>Many servers skip OAuth and accept a static key in a header. Every client below supports headers.</p>\n<h2>Client configuration</h2>\n<h3>Claude Code</h3>\n<pre><code class=\"language-bash\">claude mcp add --transport http notion https://mcp.notion.com/mcp     # OAuth: then run /mcp or `claude mcp login notion`\nclaude mcp add --transport http secure-api https://api.example.com/mcp --header &quot;Authorization: Bearer $TOKEN&quot;</code></pre>\n<p>To share a server with a project, put it in <code>.mcp.json</code>. <strong><code>type</code> is required.</strong> An entry with a <code>url</code> and no <code>type</code> is read as a stdio server and skipped:</p>\n<pre><code class=\"language-json\">{\n  &quot;mcpServers&quot;: {\n    &quot;notion&quot;: { &quot;type&quot;: &quot;http&quot;, &quot;url&quot;: &quot;https://mcp.notion.com/mcp&quot; }\n  }\n}</code></pre>\n<p><code>claude mcp login &lt;name&gt; --no-browser</code> works over SSH. Pre-registered OAuth apps use <code>--client-id</code>, <code>--client-secret</code> and <code>--callback-port</code>. Claude Code&#39;s v2 MCP runtime (TypeScript SDK 2.0) adds 2026-07-28 support. See <a href=\"/entries/claude-code/\">Claude Code</a>.</p>\n<h3>OpenAI Codex (CLI, IDE extension, ChatGPT desktop)</h3>\n<p>All three share <code>~/.codex/config.toml</code> (or a trusted project&#39;s <code>.codex/config.toml</code>):</p>\n<pre><code class=\"language-toml\">[mcp_servers.notion]\nurl = &quot;https://mcp.notion.com/mcp&quot;\n\n[mcp_servers.figma]\nurl = &quot;https://mcp.figma.com/mcp&quot;\nbearer_token_env_var = &quot;FIGMA_OAUTH_TOKEN&quot;</code></pre>\n<pre><code class=\"language-bash\">codex mcp add notion --url https://mcp.notion.com/mcp\ncodex mcp login notion          # OAuth; supports CIMD and DCR</code></pre>\n<p>Useful keys: <code>http_headers</code>, <code>env_http_headers</code>, <code>enabled_tools</code>, <code>disabled_tools</code>, <code>tool_timeout_sec</code> (default 60) and <code>startup_timeout_sec</code> (default 10). See <a href=\"/entries/codex-cli/\">Codex CLI</a>.</p>\n<h3>Cursor</h3>\n<p>Use <code>.cursor/mcp.json</code> in the project or <code>~/.cursor/mcp.json</code> globally. A remote server is just a <code>url</code>:</p>\n<pre><code class=\"language-json\">{\n  &quot;mcpServers&quot;: {\n    &quot;remote-server&quot;: {\n      &quot;url&quot;: &quot;https://api.example.com/mcp&quot;,\n      &quot;headers&quot;: { &quot;Authorization&quot;: &quot;Bearer ${env:MY_SERVICE_TOKEN}&quot; }\n    }\n  }\n}</code></pre>\n<p>Cursor handles OAuth automatically and accepts static OAuth credentials under <code>&quot;auth&quot;: {&quot;CLIENT_ID&quot;: &quot;...&quot;, &quot;CLIENT_SECRET&quot;: &quot;...&quot;}</code>. See <a href=\"/entries/cursor/\">Cursor</a>.</p>\n<h3>Gemini CLI</h3>\n<p>In <code>settings.json</code>, <strong><code>httpUrl</code> is Streamable HTTP and <code>url</code> is SSE</strong>, which is an easy mistake to make:</p>\n<pre><code class=\"language-json\">{\n  &quot;mcpServers&quot;: {\n    &quot;notion&quot;: { &quot;httpUrl&quot;: &quot;https://mcp.notion.com/mcp&quot; }\n  }\n}</code></pre>\n<p>OAuth is discovered automatically after a <code>401</code>. Manage it with <code>/mcp auth</code>. Tokens are stored in <code>~/.gemini/mcp-oauth-tokens.json</code>. See <a href=\"/entries/gemini-cli/\">Gemini CLI</a>.</p>\n<h3>VS Code (GitHub Copilot)</h3>\n<p>VS Code now prefers a <strong>portable <code>.mcp.json</code></strong> at the workspace root (top-level <code>mcpServers</code>) or <code>~/.copilot/mcp-config.json</code>. It calls the older <code>.vscode/mcp.json</code> (top-level <code>servers</code>) deprecated but still reads it:</p>\n<pre><code class=\"language-json\">{\n  &quot;servers&quot;: {\n    &quot;github&quot;: { &quot;type&quot;: &quot;http&quot;, &quot;url&quot;: &quot;https://api.githubcopilot.com/mcp&quot; }\n  }\n}</code></pre>\n<h3>Claude (web and desktop) custom connectors</h3>\n<p>Go to <strong>Customize &gt; Connectors &gt; + Add &gt; Add custom connector</strong>, then enter a name and the server URL. Choose &quot;Sign in now&quot;, &quot;Sign in when needed&quot; or &quot;No sign in&quot;, and an OAuth client mode (Claude&#39;s published identity is recommended). On Team and Enterprise plans, Owners add connectors under Organization settings. Connectors you add on claude.ai also show up in Claude Code when you&#39;re signed in with that account.</p>\n<h2>Before you trust a server</h2>\n<ul><li><strong>Prompt injection.</strong> Tool results are untrusted text. Servers that fetch web or user content can carry instructions aimed at your agent.</li><li><strong>Scope.</strong> Grant the narrowest OAuth scopes. Claude Code&#39;s <code>oauth.scopes</code> and Codex&#39;s <code>enabled_tools</code> let you pin them.</li><li><strong>Provenance.</strong> Prefer servers that the vendor itself runs or lists. The <a href=\"/entries/official-mcp-registry/\">Official MCP Registry</a> is a good place to check.</li><li><strong>Local servers</strong> should bind to <code>127.0.0.1</code>, and every server must validate <code>Origin</code>, which blocks DNS-rebinding attacks.</li></ul>\n<h2>Next steps</h2>\n<ul><li>Load the <a href=\"/skills/connect-remote-mcp/\">connect-remote-mcp skill</a> so an agent can set this up itself.</li><li>Building your own server: <a href=\"/entries/fastmcp/\">FastMCP</a> and the <a href=\"/entries/cloudflare-agents/\">Cloudflare Agents SDK</a> both deploy remote servers. <a href=\"/entries/workos-authkit-mcp/\">WorkOS AuthKit</a> and <a href=\"/entries/stytch-connected-apps/\">Stytch</a> provide the OAuth side.</li><li>To find servers, search <a href=\"/skills/indexagentica-lookup/\">Index Agentica</a>.</li></ul>"
}
