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:
| Primitive | Purpose | Example |
|---|---|---|
| Tool | Executable action the LLM can call | create_issue, search_repos |
| Resource | Read-only data addressed by URI | github://repos/{owner}/{repo}/readme |
| Prompt | Reusable prompt templates | summarize_pr |
3. Prerequisites​
- Claude plan: Pro, Max, Team, or Enterprise (Free: 1 custom connector)
- SDK: TypeScript (
@modelcontextprotocol/sdk) or Python (mcpwith 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​
TypeScript: recommended for production​
npm install @modelcontextprotocol/sdk zod
Advantages: type safety through Zod schemas, native Streamable HTTP, ideal for Cloudflare Workers, Vercel Edge, and Node.
Python: recommended for prototyping​
pip install mcp
Advantages: FastMCP decorators, schema generation from type hints and docstrings, fast onboarding.
Decision guide​
| Criterion | TypeScript | Python |
|---|---|---|
| Type safety | Explicit strict Zod schemas | Type hints |
| Prototyping speed | Medium | High with FastMCP |
| Remote HTTP deploy | Native on edge and workers | FastAPI / uvicorn |
| Ecosystem | Node.js infrastructure | ML/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_casewith averb_nounpattern, for examplecreate_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_issuevs.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: truecontent; 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:
| Platform | Stack | Notes |
|---|---|---|
| Cloudflare Workers | TypeScript | Edge, global, inexpensive |
| Vercel Edge Functions | TypeScript | Good for Next.js stacks |
| Fly.io | TypeScript / Python | Container-based, persistent |
| Railway / Render | Any | Simple container hosting |
| Own VPS with Nginx and Docker | Any | Full 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​
8.1 OAuth 2.0: recommended for Claude.ai connectors​
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​
- Open Claude.ai -> Customize -> Connectors or
claude.ai/settings/connectors. - Select "+" -> "Add custom connector".
- Name: choose a clear name, for example "GitHub - Production".
- URL: enter the HTTPS URL of your MCP server.
- Advanced Settings (optional): add OAuth Client ID / Client Secret if OAuth is implemented.
- 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:
- Claude Desktop / Claude Code: local Docker-based stdio server with PAT; works immediately, see section 7.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.
- 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
McpServerconstructor
12. References​
| Resource | URL |
|---|---|
| MCP Specification | https://modelcontextprotocol.io/specification/2025-11-25 |
| TypeScript SDK | https://github.com/modelcontextprotocol/typescript-sdk |
| Python SDK | https://github.com/modelcontextprotocol/python-sdk |
| MCP Inspector | npx @modelcontextprotocol/inspector |
| Claude Connectors Docs | https://support.claude.com/en/articles/11175166 |
| Claude API MCP Connector | https://docs.claude.com/en/docs/agents-and-tools/mcp-connector |
| GitHub MCP Server | https://github.com/github/github-mcp-server |
| GitHub MCP Server Install for Claude | https://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.