How to Connect a Remote MCP Server to Any AI Client

One remote MCP server, nine clients, nine slightly different config formats. Here is the exact file, key and header syntax for each, plus the fixes for the errors you will actually hit.

By the AlertMCP team11 min read

A remote MCP server is an MCP server your AI client reaches over HTTPS instead of launching it as a local process. To connect one you need three things: the server URL (usually ending in /mcp), an auth method (OAuth sign-in or a static Authorization: Bearer header), and your client's config syntax. The URL and the auth are the same everywhere. The syntax is not, and that is what this guide covers.

Every example below uses AlertMCP's endpoint, https://api.alertmcp.com/mcp, because it is a real remote server that needs a bearer header. Swap in your own URL and key; the same pattern works for GitHub, Notion, Context7 and most hosted servers. Every file path and key name was checked against each vendor's docs in October 2026.

Local vs remote MCP servers

The MCP specification defines two standard transports:

  • stdio. The client starts the server as a subprocess and exchanges newline-delimited JSON-RPC over stdin and stdout. Credentials come from environment variables.
  • Streamable HTTP. Each message is an HTTP POST to a single MCP endpoint, and the reply comes back as JSON or a request-scoped SSE stream.

The older HTTP+SSE transport (a separate /sse endpoint) is deprecated since the 2025-03-26 spec. Many guides still show /sse URLs. If a server offers both, use the /mcp one.

Choose local when the server needs your filesystem, a local database or a binary on your machine. Choose remote when the service already lives on the internet, when you want one config across several machines, or when the vendor runs the server for you. If you are new to the protocol itself, what MCP is and how it works covers the concepts.

Before you connect: URL, auth, secrets

The URL. Use the exact endpoint the vendor documents, including the path. https://api.alertmcp.com and https://api.alertmcp.com/mcp are different resources.

The auth method. Remote servers authenticate in one of two ways:

  • OAuth. The client discovers the server's authorization server, opens a browser and stores a token. The MCP authorization spec builds on OAuth 2.1 and requires servers to publish Protected Resource Metadata (RFC 9728). You configure only the URL and the client handles the rest.
  • A static bearer token. You send Authorization: Bearer <key> on every request. This is simpler for CLIs and CI, and it is how AlertMCP works in coding agents. Get a key by signing in to AlertMCP with Google or GitHub; keys start with amcp_sk_.

Where the secret lives. The spec says tokens must never go in the URL query string. Keep them out of committed files too. Most clients can read a header value from an environment variable, so the examples below use one:

# ~/.zshrc or ~/.bashrc
export ALERTMCP_API_KEY="amcp_sk_your_key"

Each client spells the reference differently. That one detail causes most of the 401s in the troubleshooting section.

Quick reference by client

Client Config file Top-level key Env var in headers
Claude Code .mcp.json or ~/.claude.json mcpServers ${VAR}, ${VAR:-default}
Cursor .cursor/mcp.json or ~/.cursor/mcp.json mcpServers ${env:VAR}
Codex (CLI, IDE, ChatGPT desktop) ~/.codex/config.toml [mcp_servers.<name>] bearer_token_env_var
Gemini CLI ~/.gemini/settings.json or .gemini/settings.json mcpServers $VAR, ${VAR}
VS Code / Copilot (portable) .mcp.json or ~/.copilot/mcp-config.json mcpServers ${VAR}
VS Code (classic) .vscode/mcp.json servers ${env:VAR}, ${input:id}
Devin Desktop ~/.config/devin/mcp_config.json mcpServers ${env:VAR} (Cascade)
Cline cline_mcp_settings.json mcpServers not documented
Zed ~/.config/zed/settings.json context_servers not documented
claude.ai Customize > Connectors n/a OAuth, or request headers (beta)
ChatGPT chatgpt.com/plugins n/a OAuth or none; see the ChatGPT guide

Claude Code

The Claude Code MCP docs give one command for HTTP servers:

claude mcp add --transport http --scope user alertmcp https://api.alertmcp.com/mcp \
  --header "Authorization: Bearer $ALERTMCP_API_KEY"

Your shell expands $ALERTMCP_API_KEY before Claude Code sees it, so the key itself is written to ~/.claude.json. That file is private to you, which is fine for local scope (the default, this project only) and user scope (all projects).

For project scope, Claude Code writes .mcp.json at the repo root, which you are meant to commit. There, keep a reference instead of the key:

{
  "mcpServers": {
    "alertmcp": {
      "type": "http",
      "url": "https://api.alertmcp.com/mcp",
      "headers": {
        "Authorization": "Bearer ${ALERTMCP_API_KEY}"
      }
    }
  }
}

Things to know:

  • Expansion works in command, args, env, url and headers, with ${VAR} and ${VAR:-default}.
  • If the variable is unset and has no default, Claude Code sends the literal text ${ALERTMCP_API_KEY} and shows a missing-variable warning in claude mcp list.
  • Claude Code reads its own credentials, such as ANTHROPIC_API_KEY and ANTHROPIC_AUTH_TOKEN, as empty in remote headers. Copy the value into a variable with your own name.
  • For OAuth servers, run /mcp inside a session or claude mcp login <name> from the shell.
  • MCP_TIMEOUT sets the startup timeout. A per-server "timeout" in milliseconds overrides MCP_TOOL_TIMEOUT for that server.
  • Claude Code tries HTTP first and falls back to SSE automatically from v2.1.265.

Once it is connected, Claude Code notifications covers hooks and getting alerts on your phone.

Cursor

Cursor reads .cursor/mcp.json in the project and ~/.cursor/mcp.json for global servers (Cursor MCP docs):

{
  "mcpServers": {
    "alertmcp": {
      "url": "https://api.alertmcp.com/mcp",
      "headers": {
        "Authorization": "Bearer ${env:ALERTMCP_API_KEY}"
      }
    }
  }
}

Cursor interpolates command, args, env, url and headers. Note the env: prefix; plain ${ALERTMCP_API_KEY} is not Cursor syntax. ${userHome} and ${workspaceFolder} also work.

There is no type field for remote servers and no CLI command to add one. Servers in the Cursor Marketplace install with one click and handle OAuth themselves. For what to do after connecting, see Cursor notifications.

OpenAI Codex

Codex keeps MCP servers in ~/.codex/config.toml, or .codex/config.toml for trusted projects. The Codex MCP docs say the Codex CLI, the IDE extension and the ChatGPT desktop app share this file:

[mcp_servers.alertmcp]
url = "https://api.alertmcp.com/mcp"
bearer_token_env_var = "ALERTMCP_API_KEY"

bearer_token_env_var takes the variable's name, not its value. Codex reads the variable at connect time and sends it as a bearer token, so store the raw amcp_sk_ key without the word Bearer.

The CLI equivalent is below. The --bearer-token-env-var flag exists in Codex's source but is not yet on the docs page, so run codex mcp add --help to confirm your version has it:

codex mcp add alertmcp --url https://api.alertmcp.com/mcp --bearer-token-env-var ALERTMCP_API_KEY

Other keys worth knowing:

  • http_headers sets static headers, and env_http_headers maps header names to variable names.
  • startup_timeout_sec defaults to 10 and tool_timeout_sec to 60. AlertMCP's get_answer waits at most 50 seconds per call, so the default is enough.
  • enabled_tools, disabled_tools and default_tools_approval_mode control which tools run and when Codex asks.
  • codex mcp login <name> starts OAuth for servers that use it. /mcp in the TUI lists active servers.

In the ChatGPT desktop app, the same server can be added from Settings > MCP servers > Add server with the Streamable HTTP option.

Gemini CLI and Antigravity CLI

A 2026 change first: Google replaced Gemini CLI with Antigravity CLI on June 18, 2026 for free-tier, Google AI Pro and Ultra users. Gemini CLI keeps working on Gemini Code Assist Standard and Enterprise licenses and with paid API keys.

Gemini CLI. Use the CLI, which writes a valid entry for you (Gemini CLI MCP docs). Single quotes keep the variable reference literal so the key is not written to disk:

gemini mcp add --transport http --scope user \
  --header 'Authorization: Bearer ${ALERTMCP_API_KEY}' \
  alertmcp https://api.alertmcp.com/mcp

Gemini resolves $VAR and ${VAR} references in settings.json string values when it loads settings. User scope writes ~/.gemini/settings.json; the default, project scope, writes .gemini/settings.json. The manual form from the docs uses httpUrl:

{
  "mcpServers": {
    "alertmcp": {
      "httpUrl": "https://api.alertmcp.com/mcp",
      "headers": {
        "Authorization": "Bearer ${ALERTMCP_API_KEY}"
      }
    }
  }
}

Do not use a bare url key here. In the docs, url means SSE; the CLI pairs it with "type": "http" when it writes the entry. Avoid underscores in server names, because Gemini's policy parser splits tool names on them. Check status with /mcp list.

Antigravity CLI. The Antigravity MCP docs use ~/.gemini/config/mcp_config.json (global) or .agents/mcp_config.json (workspace), with serverUrl instead of httpUrl, which is not supported:

{
  "mcpServers": {
    "alertmcp": {
      "serverUrl": "https://api.alertmcp.com/mcp",
      "headers": {
        "Authorization": "Bearer amcp_sk_your_key"
      }
    }
  }
}

The docs do not document variable interpolation, so the key is literal. Keep that file out of any dotfiles repo. Type /mcp in a session to see server status.

VS Code and GitHub Copilot

VS Code now has two formats (VS Code MCP configuration reference), and the guided setup labels the older one deprecated.

Portable Copilot format. .mcp.json at the workspace root, or ~/.copilot/mcp-config.json ($COPILOT_HOME/mcp-config.json if set) for your user. Copilot sessions read it directly:

{
  "mcpServers": {
    "alertmcp": {
      "type": "http",
      "url": "https://api.alertmcp.com/mcp",
      "headers": {
        "Authorization": "Bearer ${ALERTMCP_API_KEY}"
      }
    }
  }
}

Use the braced ${NAME} form; VS Code treats bare $NAME as literal text. In a remote window or container, the variable must exist on the remote host.

Classic VS Code format. .vscode/mcp.json uses servers and can prompt for the key once and store it securely:

{
  "inputs": [
    {
      "type": "promptString",
      "id": "alertmcp-key",
      "description": "AlertMCP API key",
      "password": true
    }
  ],
  "servers": {
    "alertmcp": {
      "type": "http",
      "url": "https://api.alertmcp.com/mcp",
      "headers": {
        "Authorization": "Bearer ${input:alertmcp-key}"
      }
    }
  }
}

The catch: servers that need ${input:...} are not forwarded to Copilot harness sessions. If you use Copilot's agent sessions, use the portable file with an environment variable.

Devin Desktop (formerly Windsurf)

Windsurf is now Devin Desktop, and it has two agents with different MCP docs:

  • Devin Local, the default for new tabs, uses the Devin CLI config: devin mcp add alertmcp https://api.alertmcp.com/mcp writes .devin/mcp_config.local.json (gitignored), and -s user writes ~/.config/devin/mcp_config.json.
  • Cascade, the legacy agent, reads ~/.config/devin/mcp_config.json on macOS and Linux, or %APPDATA%\devin\mcp_config.json on Windows (Cascade MCP docs). The old ~/.codeium/windsurf/mcp_config.json path is only used as an import source.

The Devin CLI docs show no header flag for devin mcp add, so add the header by hand. Both agents read ~/.config/devin/mcp_config.json, which makes it the simplest place for a personal key reference:

{
  "mcpServers": {
    "alertmcp": {
      "url": "https://api.alertmcp.com/mcp",
      "headers": {
        "Authorization": "Bearer ${env:ALERTMCP_API_KEY}"
      }
    }
  }
}

Cascade documents ${env:VAR} and ${file:/path} interpolation in headers, and an unset variable becomes an empty string. The Devin CLI docs show the same syntax for OAuth fields but not for headers. If the Local agent returns a 401, put the literal key in .devin/mcp_config.local.json. Cascade also caps you at 100 tools across all servers.

Cline

Cline's one trap is the transport. If you omit type, Cline defaults to legacy SSE (Cline MCP docs):

{
  "mcpServers": {
    "alertmcp": {
      "type": "streamableHttp",
      "url": "https://api.alertmcp.com/mcp",
      "headers": {
        "Authorization": "Bearer amcp_sk_your_key"
      },
      "disabled": false,
      "autoApprove": []
    }
  }
}

In the IDE extension, open the MCP Servers icon, then Configure > Configure MCP Servers to edit this JSON. The Cline CLI uses ~/.cline/data/settings/cline_mcp_settings.json and has a one-liner:

cline mcp add alertmcp https://api.alertmcp.com/mcp --transport http \
  --header "Authorization: Bearer $ALERTMCP_API_KEY" --yes

Cline's docs recommend environment variables for secrets but document no interpolation syntax for headers, so the key ends up literal in the settings file either way.

Zed

Zed calls MCP servers context servers. Add one from Settings > AI > MCP Servers > Add Server > Add Remote Server, or edit your settings file (~/.config/zed/settings.json on macOS and Linux) directly, per the Zed MCP docs:

{
  "context_servers": {
    "alertmcp": {
      "url": "https://api.alertmcp.com/mcp",
      "headers": {
        "Authorization": "Bearer amcp_sk_your_key"
      }
    }
  }
}

If you leave out the Authorization header, Zed runs the standard MCP OAuth flow instead. A green dot next to the server in the MCP Servers settings means "Server is active". Zed's agent asks before every tool call by default; per-tool rules use keys like mcp:alertmcp:notify.

Claude.ai and the Claude apps

Claude's web, desktop and mobile apps connect from Anthropic's cloud, not your machine, so the server must be reachable from the public internet (Claude custom connector docs).

  • Free, Pro, Max: Customize > Connectors > + Add > Add custom connector. Free accounts get one custom connector.
  • Team, Enterprise: an Owner goes to Organization settings > Connectors > Add > Custom > Web. Members then connect from Customize > Connectors.

For authentication you choose OAuth (Claude's published identity, automatic registration, or your own client) or No sign-in. A Request headers option for static keys exists but is in beta for a limited set of organizations. Claude sends the value exactly as entered, so include Bearer yourself. Auth settings can't be edited later; remove and re-add the connector to change them.

AlertMCP uses OAuth here: paste https://api.alertmcp.com/mcp, sign in, and approve on AlertMCP's consent screen with your API key.

ChatGPT

ChatGPT adds custom servers from chatgpt.com/plugins, with OAuth or no authentication and no static header option. Plan rules are stricter than Claude's: full MCP, including write tools, is for Business and Enterprise/Edu workspaces. The full flow, plan details and confirmation behavior are in how to add an MCP server to ChatGPT.

Clients without remote support: mcp-remote

If a client only speaks stdio, mcp-remote runs locally and proxies to the remote URL:

{
  "mcpServers": {
    "alertmcp": {
      "command": "npx",
      "args": [
        "mcp-remote",
        "https://api.alertmcp.com/mcp",
        "--header",
        "Authorization:${AUTH_HEADER}"
      ],
      "env": {
        "AUTH_HEADER": "Bearer amcp_sk_your_key"
      }
    }
  }
}

Leave no space after the colon in Authorization:${AUTH_HEADER}. Some clients do not escape spaces inside args, which is why the value goes through an env var. Every client above supports remote servers natively now, so use this only where you have to.

Test it with MCP Inspector

Before blaming a client, confirm the server, URL and key work on their own. The MCP Inspector's CLI mode lists tools in one command:

npx @modelcontextprotocol/inspector --cli https://api.alertmcp.com/mcp \
  --transport http --method tools/list \
  --header "Authorization: Bearer $ALERTMCP_API_KEY"

For AlertMCP you should see notify, ask, ask_text, get_answer and list_topics. Run npx @modelcontextprotocol/inspector with no flags for the web UI.

Make the agent use it

Connecting a server gives the agent tools; it does not make the agent call them. Add a line to CLAUDE.md, AGENTS.md or your rules file:

When a task takes longer than 2 minutes, or you need my approval, use alertmcp.notify / alertmcp.ask.

The model then decides when to call ask. AlertMCP does not intercept Claude Code's, Cursor's or Codex's built-in permission dialogs. Those have native phone options of their own: Claude Code Remote Control, the Cursor iOS app, and Codex in the ChatGPT app. For more servers worth connecting this way, see the best MCP servers in 2026, and for the bigger picture of AI agent notifications, start at our homepage.

Troubleshooting checklist

401 Unauthorized

  • The variable is unset in the process that connects. GUI editors launched from the Dock or Start menu often don't see variables exported in your shell profile. Start the editor from a terminal, or set the variable system-wide.
  • Wrong reference syntax for that client: ${env:VAR} in Cursor and Cascade, ${VAR} in Claude Code and the Copilot portable format, a variable name (not a value) in Codex.
  • A literal ${ALERTMCP_API_KEY} was sent. Claude Code does this when the variable is unset; claude mcp list shows the warning.
  • Missing or doubled Bearer . claude.ai request headers need it typed in; Codex's bearer_token_env_var must not include it.
  • You referenced ANTHROPIC_API_KEY or ANTHROPIC_AUTH_TOKEN in Claude Code, which reads them as empty.

Transport mismatch (404, 405 or a hang on connect)

  • Cline without "type": "streamableHttp" falls back to SSE.
  • Gemini CLI with url and no type is treated as SSE. Use httpUrl, or let gemini mcp add write the entry.
  • Antigravity CLI rejects httpUrl; use serverUrl.
  • In claude.ai, a URL ending in /sse selects the old transport.
  • You pointed at the host root instead of the /mcp path.

Tools missing or stale

  • Restart or reload after editing config. Codex needs a restart; VS Code has MCP: Reset Cached Tools.
  • Cascade caps you at 100 tools across all servers.

OAuth keeps asking you to sign in

  • Each client stores its own OAuth session, so signing in to Claude Code does not sign in Codex or Devin.
  • Re-run the login: claude mcp login, codex mcp login, devin mcp login, or /mcp auth in Gemini CLI.

A key ended up in git

  • Revoke it in the server's dashboard first, then move the value to an environment variable or a gitignored local file. .mcp.json, .cursor/mcp.json and .devin/mcp_config.json are meant to be shared, so they should only ever contain references.

Frequently asked questions

What is a remote MCP server?
A remote MCP server is one your AI client reaches over the network, usually at an HTTPS URL ending in /mcp, using the Streamable HTTP transport. A local server, by contrast, is a process the client launches on your machine and talks to over stdio.
How do I pass an API key to a remote MCP server?
Most clients take a headers object in their config file or a --header flag on the command line, for example Authorization: Bearer followed by your key. Reference the key from an environment variable where the client supports it, such as ${VAR} in Claude Code, ${env:VAR} in Cursor, or bearer_token_env_var in Codex.
Is the SSE transport still supported?
HTTP+SSE has been deprecated since the 2025-03-26 MCP specification and replaced by Streamable HTTP. Several clients still fall back to SSE for older servers, and Cline still defaults to SSE unless you set the type to streamableHttp.
Why can't I add a bearer-token MCP server to ChatGPT?
ChatGPT's custom MCP server flow offers OAuth, no authentication, or a mix of the two. It has no field for a static API-key header, so a server that only accepts a fixed bearer token needs to support OAuth before ChatGPT can connect to it.
How do I test a remote MCP server before using it in an agent?
Run the MCP Inspector in CLI mode against the server URL with --method tools/list and your Authorization header. If it lists the tools, the URL, transport and key are correct, and any remaining problem is in your client's config.
by PostMCP AI