Skip to main content

MCP Connector Guide for Claude

Best practices for building, configuring, and deploying MCP connectors in Claude.ai, Claude Desktop, and Claude Code.


1. Overview​

MCP (Model Context Protocol) is an open standard based on JSON-RPC 2.0 that connects AI clients such as Claude, Cursor, and VS Code to external tools through a unified interface. An MCP server exposes tools, resources, and prompts that Claude discovers and calls at runtime.

Spec version: 2025-11-25 (current) Transport: Streamable HTTP (remote) / stdio (local) Official spec: https://modelcontextprotocol.io/specification/2025-11-25


2. Architecture​

+-------------+    JSON-RPC 2.0     +-------------+     API calls     +----------+
| Claude.ai | <------------------> | MCP Server | <--------------> | GitHub |
| (MCP Client)| Streamable HTTP | (your code) | | Slack |
| | | | | DB etc. |
+-------------+ +-------------+ +----------+

Primitives of an MCP server:

PrimitivePurposeExample
ToolExecutable action the LLM can callcreate_issue, search_repos
ResourceRead-only data addressed by URIgithub://repos/{owner}/{repo}/readme
PromptReusable prompt templatessummarize_pr

3. Prerequisites​

  • Claude plan: Pro, Max, Team, or Enterprise (Free: 1 custom connector)
  • SDK: TypeScript (@modelcontextprotocol/sdk) or Python (mcp with FastMCP)
  • Transport: Streamable HTTP for remote servers; HTTPS is required for Claude.ai
  • Auth: OAuth 2.0 or bearer token, depending on the target service

4. Technology Choice​

npm install @modelcontextprotocol/sdk zod

Advantages: type safety through Zod schemas, native Streamable HTTP, ideal for Cloudflare Workers, Vercel Edge, and Node.

pip install mcp

Advantages: FastMCP decorators, schema generation from type hints and docstrings, fast onboarding.

Decision guide​

CriterionTypeScriptPython
Type safetyExplicit strict Zod schemasType hints
Prototyping speedMediumHigh with FastMCP
Remote HTTP deployNative on edge and workersFastAPI / uvicorn
EcosystemNode.js infrastructureML/data pipelines

5. Build an MCP Server​

5.1 TypeScript: minimal example​

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";

const server = new McpServer({
name: "github-connector",
version: "1.0.0",
});

server.tool(
"search_issues",
"Search GitHub issues by query string",
{
repo: z.string().describe("owner/repo format"),
query: z.string().describe("Search query"),
state: z.enum(["open", "closed", "all"]).default("open"),
},
async ({ repo, query, state }) => {
const response = await fetch(
`https://api.github.com/search/issues?q=${encodeURIComponent(query)}+repo:${repo}+state:${state}`,
{ headers: { Authorization: `Bearer ${process.env.GITHUB_TOKEN}` } }
);
const data = await response.json();

return {
content: [
{
type: "text",
text: JSON.stringify(data.items?.map((i: any) => ({
number: i.number,
title: i.title,
state: i.state,
url: i.html_url,
})), null, 2),
},
],
};
}
);

5.2 Python: FastMCP minimal example​

from mcp.server.fastmcp import FastMCP
import httpx

mcp = FastMCP("github-connector")

@mcp.tool()
async def search_issues(repo: str, query: str, state: str = "open") -> str:
"""Search GitHub issues in a repository.

Args:
repo: Repository in owner/repo format
query: Search query string
state: Issue state filter (open, closed, all)
"""
async with httpx.AsyncClient() as client:
resp = await client.get(
"https://api.github.com/search/issues",
params={"q": f"{query} repo:{repo} state:{state}"},
headers={"Authorization": f"Bearer {os.environ['GITHUB_TOKEN']}"},
)
data = resp.json()
return json.dumps([
{"number": i["number"], "title": i["title"], "url": i["html_url"]}
for i in data.get("items", [])
], indent=2)

if __name__ == "__main__":
mcp.run(transport="streamable-http", host="0.0.0.0", port=8000)

6. Tool Design Best Practices​

6.1 Naming and descriptions​

  • Tool names: use snake_case with a verb_noun pattern, for example create_issue, list_repos, search_pull_requests.
  • Descriptions: write clearly for the LLM. The model decides whether to call a tool based on the description. Avoid marketing language and abbreviations without context.
  • Parameter descriptions: every parameter needs a .describe() call in Zod or a docstring entry in Python. Include format hints, for example "Repository in owner/repo format, e.g. 'anthropic-ai/claude-code'".

6.2 Granularity​

  • One tool equals one action. Avoid a god tool that can do everything.
  • Separate read and write operations: get_issue vs. update_issue.
  • Use searchable lists with filters instead of "give me everything": pagination and limit parameters are required.

6.3 Error handling​

// GOOD: return a structured error message
return {
content: [{ type: "text", text: `Error: Repository '${repo}' not found (404)` }],
isError: true,
};

// BAD: throwing an uncontrolled exception can terminate the connection
throw new Error("Not found");
  • Always return errors as isError: true content; never crash the connection.
  • Make error messages actionable: what went wrong, and what can the user do?

6.4 Structured responses​

  • Use JSON for machine-readable data and Markdown for human-readable summaries.
  • Keep large payloads short. The LLM has a context window. Do not return 500 issues at once; enforce pagination.

7. Transport and Deployment​

7.1 Streamable HTTP: remote Claude.ai connectors​

Streamable HTTP is the current standard transport for remote servers. SSE (Server-Sent Events) has been deprecated since the MCP 2025-03-26 spec, but is still supported for backward compatibility.

Requirements:

  • HTTPS is required; self-signed certificates do not work for Claude.ai.
  • The endpoint must implement MCP Streamable HTTP.
  • CORS headers must be correct when the server is called directly from a browser-based client.

Deployment options:

PlatformStackNotes
Cloudflare WorkersTypeScriptEdge, global, inexpensive
Vercel Edge FunctionsTypeScriptGood for Next.js stacks
Fly.ioTypeScript / PythonContainer-based, persistent
Railway / RenderAnySimple container hosting
Own VPS with Nginx and DockerAnyFull control

7.2 stdio: local Claude Desktop / Claude Code servers​

Use stdio for local MCP servers that run on your machine. Configure them through claude_desktop_config.json in Claude Desktop or claude mcp add in Claude Code.

Claude Desktop config (~/.config/Claude/claude_desktop_config.json):

{
"mcpServers": {
"github": {
"command": "docker",
"args": [
"run", "-i", "--rm",
"-e", "GITHUB_PERSONAL_ACCESS_TOKEN",
"ghcr.io/github/github-mcp-server"
],
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "ghp_xxx"
}
}
}
}

Claude Code:

# HTTP remote server
claude mcp add-json github \
'{"type":"http","url":"https://api.githubcopilot.com/mcp/","headers":{"Authorization":"Bearer YOUR_PAT"}}'

# Local stdio server
claude mcp add github -s user -- docker run -i --rm \
-e GITHUB_PERSONAL_ACCESS_TOKEN ghcr.io/github/github-mcp-server

8. Authentication​

Claude.ai supports OAuth flows for custom connectors. Your MCP server must implement the OAuth flow so Claude can authenticate the user during connection setup.

8.2 Bearer token / PAT​

Use bearer tokens or personal access tokens for local servers or API-only setups. Inject tokens through environment variables; never hardcode them.

8.3 Security checklist​

  • Tokens only through environment variables, never in code
  • Keep scopes minimal with least privilege
  • Implement rate limiting; the LLM can call tools aggressively
  • Validate input on every tool parameter to prevent SQL injection, path traversal, and related issues
  • Do not include sensitive data in tool responses unless requested
  • Log only to stderr or files, never stdout when using stdio transport

9. Configure the Connector in Claude.ai​

9.1 Add a custom connector​

  1. Open Claude.ai -> Customize -> Connectors or claude.ai/settings/connectors.
  2. Select "+" -> "Add custom connector".
  3. Name: choose a clear name, for example "GitHub - Production".
  4. URL: enter the HTTPS URL of your MCP server.
  5. Advanced Settings (optional): add OAuth Client ID / Client Secret if OAuth is implemented.
  6. Authenticate through the browser popup for OAuth or through token entry.

9.2 Existing connectors from the directory​

The connector directory contains more than 200 prebuilt connectors. Some are interactive and render UI in the chat, such as Figma, Canva, Asana, Slack, and Box.

9.3 GitHub connector specifics​

As of June 2026, the official GitHub MCP server (ghcr.io/github/github-mcp-server) requires OAuth through a registered GitHub App. Claude.ai Custom Connectors do not yet support this natively. Workarounds:

  1. Claude Desktop / Claude Code: local Docker-based stdio server with PAT; works immediately, see section 7.2.
  2. Custom proxy: build an MCP server that accepts PAT auth and wraps the GitHub API, then connect it as a custom connector in Claude.ai.
  3. GitHub Copilot MCP endpoint: https://api.githubcopilot.com/mcp/ with bearer PAT; works in Claude Code, experimental in Claude.ai.

10. Testing​

10.1 MCP Inspector​

The official debug tool for MCP servers:

# TypeScript
npx @modelcontextprotocol/inspector node build/index.js

# Python
npx @modelcontextprotocol/inspector python your_server.py

It opens a local web UI where you can call tools manually, verify the handshake, and inspect responses.

10.2 Pre-deployment checklist​

  • Every tool tested individually in the Inspector
  • Error cases tested: invalid parameters, auth errors, rate limits
  • Response sizes checked; no monster payloads
  • Capability negotiation correct; server declares tools, resources, prompts
  • Transport tested: local stdio and remote Streamable HTTP
  • CORS headers correct when using a browser-based client

11. Production Checklist​

  • Logging: stderr or file, never stdout; stdout is the stdio transport channel
  • Error handling: wrap every tool call in try/catch and return clean error messages
  • Input validation: Zod in TypeScript, type hints plus explicit checks in Python
  • Rate limiting: the LLM can call tools in bursts, so respect external API rate limits
  • Idempotency: write tools should not write duplicate data when called again
  • Timeouts: set timeouts for external API calls; the LLM will not wait forever
  • Health check: provide an endpoint for monitoring
  • Versioning: set the server version in the McpServer constructor

12. References​

ResourceURL
MCP Specificationhttps://modelcontextprotocol.io/specification/2025-11-25
TypeScript SDKhttps://github.com/modelcontextprotocol/typescript-sdk
Python SDKhttps://github.com/modelcontextprotocol/python-sdk
MCP Inspectornpx @modelcontextprotocol/inspector
Claude Connectors Docshttps://support.claude.com/en/articles/11175166
Claude API MCP Connectorhttps://docs.claude.com/en/docs/agents-and-tools/mcp-connector
GitHub MCP Serverhttps://github.com/github/github-mcp-server
GitHub MCP Server Install for Claudehttps://github.com/github/github-mcp-server/blob/main/docs/installation-guides/install-claude.md

This document is a draft and should be reviewed before external use.