On 5 November 2026, a Stack Overflow question asking whether Claude Desktop can open an authorization URL and accept a token without OAuth 2.0/PKCE had 749 views. Another, on how to pass an API key to tool calls in a Cloudflare remote MCP server, had 605. Authentication is where builders get stuck first when they put an MCP server over an existing API.

I checked the MCP specification and the Claude and ChatGPT connector docs the same day.

Your MCP server handles two credentials

The client presents one to your MCP server. Your MCP server presents the other to your API. Keep them separate.

Your API keeps its authentication, permissions and business logic, and the MCP server enforces them on every call. The MCP server can hold its own API key for those calls. If each user needs their own API permissions, give them a separate grant with your API instead of forwarding their MCP access token.

How the client authenticates to your MCP server

Claude and ChatGPT connectors reach a remote server over Streamable HTTP, one of the two transports in the MCP transports specification. A stdio server, which the client launches as a subprocess, fits local development and takes its credentials from the environment.

Authorization is optional in MCP. When you protect an HTTP server, the MCP authorization specification uses OAuth 2.1, and your MCP server acts as a resource server:

  1. It answers an unauthenticated request with 401 and a WWW-Authenticate header pointing at its Protected Resource Metadata document.
  2. The client discovers the authorization server from that document.
  3. Your server validates that each token was issued for it, and never accepts or forwards a token issued for another resource.
  4. Tokens never go in the URL query string.

For a shared credential, Claude and ChatGPT each document a static-key path:

  • Claude supports static_headers. An organization Owner enters an API key or bearer token when adding the connector, and Claude sends it in a request header on every call. Anthropic's authentication page marks it beta and limits it to a set of organizations. Standard header names such as authorization, x-api-key and x-auth-token work, and other names need Anthropic's approval.
  • ChatGPT plugins declare API key authentication in mcp.json under extensions["com.openai"].auth, with headerScheme set to bearer, basic or custom_header. OpenAI's packaging reference notes that the submission portal's connection form doesn't support these declarations.

For the first Stack Overflow question, the static-key route in Anthropic's docs is static_headers, with the limits above, and a shared key can't identify an individual user. For the second, both static-key paths carry the key in a request header. Keep it out of tool arguments, because a model that can see a key in a parameter can repeat it or send it somewhere else.

Choose OAuth when a tool reads one user's data or acts in their name. A static key fits a service account where everyone shares the same permissions. For a static key, document the header name and key source, and keep keys out of URLs and logs.

Map operations to focused tools

Start with a few read operations and one workflow you can test end to end, then add writes once the reads hold up.

Give each user goal its own tool, such as list_invoices, get_invoice and create_invoice. One generic api_request tool with a method parameter gives the model no useful guidance and fails directory review. Anthropic's connector review criteria require separate read and write tools and recommend splitting create, update and delete.

Each tool needs a name, a description that says when to use it, an explicit JSON Schema for its input (inputSchema in the MCP tools specification), and annotations that match its behavior. Annotations guide client confirmations but don't replace your own authorization.

For the Claude directory, the same criteria require a title, accurate readOnlyHint and destructiveHint annotations, and names of 64 characters or fewer. Descriptions have to match what the tool does, and they can't contain behavioral instructions or pull instructions from external sources.

Return the fields the next step needs, cap lists, and pass a continuation value for the next page. Anthropic's connector build guide caps a tool result at about 150,000 characters on claude.ai and Desktop, and at 25,000 tokens by default in Claude Code. OpenAI's build guide says to keep secrets and unnecessary personal data out of results.

For a workflow that spans calls, like a draft order, return an explicit handle from the creation tool and accept it on later calls. Check on every call that the handle belongs to the caller.

Write errors the model can act on

Use one input object for path, query and body fields, enums for fixed values, and formats in the parameter descriptions. If the caller can say "Acme" instead of a UUID, resolve the name inside the tool.

Return structuredContent for later tool calls and a text content block that says what happened. Stable IDs let the next call refer to the same record.

Return execution errors with isError: true and text the model can act on. Turn an upstream 404 into a message like this one:

No invoice with ID 123. Call list_invoices to find a valid ID. 

Give validation failures the expected format and rate limits a retry delay. Don't pass through stack traces or raw upstream bodies.

For rules that span tools, OpenAI supports server-wide instructions and advises putting the most important material in the first 512 characters. ChatGPT uses readOnlyHint to decide which calls need confirmation, and it treats any tool without it as a write action.

Test in the Inspector, then in Claude and ChatGPT

Run the MCP Inspector first:

npx @modelcontextprotocol/inspector 

Check initialization, the tool list, every tool with valid and invalid inputs, and the errors that come back. Then connect both clients:

  • In Claude, add the server as a custom connector by URL and run through the auth flow.
  • In ChatGPT, go to Plugins, choose Add custom MCP server, enter the HTTPS /mcp URL and set up authentication. OpenAI's quickstart includes a tunnel for local development.

Test prompts that should pick each tool, prompts that should pick none, wrong IDs, expired credentials and a write that needs confirmation. Refresh the connection after you change tool metadata.

Plan a review round for Claude's directory

Anthropic's criteria require testing every tool through the Inspector and as a custom connector before you submit. The review also requires a populated test account, public documentation by your publish date, actionable error messages, and first-party APIs or APIs you legitimately proxy.

If your connector already exists, my AI connector review checks it before you submit. It's an independent review of an existing MCP connector against Anthropic's connector pre-submission checklist, and every finding comes with reproduction steps.

What to prepare before an MCP build

Bring these to the first conversation:

  1. Your OpenAPI document, or a list of the operations with their request and response shapes.
  2. Three to five user requests the server should handle, written the way a user would type them.
  3. The operations to leave out, including admin, irreversible and billing actions.
  4. The auth decision: shared API key or per-user OAuth, and who issues each credential.
  5. A test account with realistic data and a way to reset it.
  6. The deployment target for an HTTPS endpoint and where its secrets live.

I build MCP servers over existing APIs for Claude and ChatGPT. The scope starts from that list: the tool map, the auth path, the error behavior and a tested connection to the client you use. If you want me to build yours, start on the AI connector build page with that list ready.