# MCP Servers Explained: What They Are and How to Connect Them

> A complete guide to MCP (Model Context Protocol): architecture, connecting it to Claude Code and Cursor, the top 20 servers, and writing your own server in TypeScript and Python.
> Author: Roman Belov · Published: 2026-06-29 · Source: https://futurecraft.pro/blog/mcp-servers-explained/

MCP (Model Context Protocol) is an open standard for connecting AI models to external tools, data, and services. Created by Anthropic in November 2024, handed over to the Linux Foundation in December 2025. In 18 months: 110 million SDK installs per month, 10,000+ servers in the official registry (and over 20,000 counting PulseMCP and Smithery), support from 300+ clients: Claude, Cursor, VS Code, Gemini, ChatGPT, Windsurf, Microsoft Copilot, JetBrains, Xcode, and dozens of others.

This article is a complete guide: from concept to working code. Architecture, connecting ready-made servers to Claude Code and Cursor, writing your own server in TypeScript and Python, production considerations.

## What MCP (Model Context Protocol) Is

### The problem: every integration built from scratch

An AI assistant can generate text and code. But to work with the real world — databases, APIs, files, services — it needs integrations. Before MCP, every integration was custom-built.

Want to connect Claude to GitHub? Write a wrapper over the GitHub API. To PostgreSQL? Another wrapper. To Slack? A third one. Each with its own format, transport, and auth logic. Cursor does the same thing its own way. VS Code — its own way too.

The result: N AI platforms × M tools = N×M custom integrations. It doesn't scale.

### The solution: one protocol for everything

MCP solves this at the protocol level. One standard for how an AI assistant talks to external tools. Any MCP server works with any MCP client.

The analogy is USB. Before USB, every device had its own connector: keyboard — PS/2, printer — LPT, modem — COM port. USB standardized the connection: one port for everything. MCP does the same thing for AI.

- **One MCP server for GitHub** works in Claude Code, Cursor, VS Code, and ChatGPT alike
- **A tool developer** writes the server once — it's available on every platform
- **An AI platform developer** implements the client once — gets access to every server

The formula: N + M instead of N × M.

### Who supports MCP

As of June 2026, MCP is supported by:

- **Claude Code** and **Claude Desktop** (Anthropic) — native support, MCP was originally built for Claude
- **Cursor** — full support in Agent mode
- **VS Code** — native support since version 1.99 (March 2025), through GitHub Copilot Chat
- **ChatGPT** (OpenAI) — integrated via MCP
- **Gemini** (Google) — supports MCP servers
- **Microsoft Copilot** — integrated into Copilot, VS Code, and Windows 11
- **Windsurf** (Codeium) — supported in the IDE
- **JetBrains** — MCP client in AI Assistant since version 2025.1, built-in IDE MCP server since 2025.2
- **OpenAI Codex CLI** — supports MCP clients and servers (`codex mcp add`); since June 2026, Codex Plugins bundle MCP configuration, skills, and app integrations into a single unit
- **Xcode** — supported in Apple Intelligence Developer Mode (early access)
- **Eclipse** — via the MCP Bridge plugin
- **Zed** — built-in support through the Agent Panel

MCP isn't a proprietary protocol owned by one company. It's an open standard governed by the Linux Foundation through the Agentic AI Foundation (AAIF).

## MCP Architecture

### Four layers

MCP uses a client-server architecture with clearly separated responsibilities:

```
Host (Claude Code, Cursor)
  └── MCP Client
        └── MCP Server
              └── Resource (DB, API, files)
```

**Host** — the application the AI model runs inside: Claude Code, Cursor, VS Code with Copilot. The Host manages the lifecycle of MCP clients.

**MCP Client** — a component inside the Host that holds a connection to one MCP server. Three servers mean three clients.

**MCP Server** — a program implementing the protocol. It accepts requests from the client, translates them into calls against the resource, and returns the result. A local process or a remote HTTP server.

**Resource** — whatever the server exposes access to: a database, a REST API, a filesystem, a SaaS service, an internal tool.

### The protocol: JSON-RPC 2.0

Under the hood, MCP uses JSON-RPC 2.0 — a standard remote procedure call protocol. Every request is a JSON object with a method, parameters, and an identifier:

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "search_issues",
    "arguments": {
      "query": "bug in auth module",
      "state": "open"
    }
  }
}
```

The client sends a request, the server returns a result. The format is standardized — an implementation in any language is compatible with any MCP client.

### Transport: stdio and Streamable HTTP

Transport determines how the client and server exchange JSON-RPC messages. MCP supports two mechanisms:

**stdio** — standard input/output. The server runs as a child process of the Host. The client writes to stdin, reads from stdout. The simplest option for local servers.

```
Host launches: npx @modelcontextprotocol/server-filesystem /path/to/dir
         stdin  → JSON-RPC request
         stdout ← JSON-RPC response
```

When to use it: local development, CLI tools, servers that run on the developer's machine.

**Streamable HTTP** — an HTTP transport introduced in March 2025. The server runs as an independent HTTP process, accepting POST requests. It uses Server-Sent Events (SSE) for streaming responses when needed.

```
Client  →  POST /mcp  →  MCP Server (remote)
Client  ←  SSE stream  ←  MCP Server
```

When to use it: remote servers, production deployments, servers running in Docker/Kubernetes, multi-tenant architectures.

**HTTP+SSE (legacy)** — the previous transport for remote servers, deprecated in favor of Streamable HTTP. Existing servers on SSE keep working; new implementations move to Streamable HTTP.

### Comparing transports

| Characteristic | stdio | Streamable HTTP |
|---|---|---|
| Deployment | Local process | Remote server |
| Clients | One (the process owner) | Many concurrently |
| Scaling | No | Horizontal (load balancer) |
| Authentication | Via env | OAuth 2.1, bearer tokens |
| Latency | Minimal (IPC) | Network (HTTP) |
| Setup | Simple (command + args) | Needs an HTTP server |
| Typical use | Dev tools, CLI | SaaS, team servers, production |

Start with stdio. Move to Streamable HTTP once the server needs to serve multiple developers or run remotely.

### Connection lifecycle

Connecting an MCP client to a server goes through several stages:

1. **Initialize** — the client sends `initialize` with information about itself (name, version, supported capabilities)
2. **Server response** — the server replies with its own capabilities (which tools, resources, prompts are available)
3. **Initialized** — the client confirms readiness with an `notifications/initialized` notification
4. **Working** — request exchange: `tools/list`, `tools/call`, `resources/read`, and so on
5. **Shutdown** — the connection closes when the session ends

The entire exchange runs over JSON-RPC 2.0 — requests, responses, and notifications. Client and server can send notifications asynchronously (for instance, the server notifying about a change to the tools list).

### Capabilities: Tools, Resources, Prompts

An MCP server can offer three types of capabilities:

| Type | Who calls it | Analogy | Example |
|---|---|---|---|
| **Tools** | The AI model | POST endpoint | Create a GitHub issue, run a SQL query |
| **Resources** | The application (Host) | GET endpoint | Database schema, file contents |
| **Prompts** | The user | Template | "Review this code for security issues" |

More on each type in the "Resources vs. Tools vs. Prompts" section below.

## How to Connect an MCP Server to Claude Code

### Method 1: the claude mcp add command

The fastest way is the CLI command:

```bash
# Remote (recommended) — uses GitHub's official HTTP endpoint
claude mcp add-json github '{"type":"http","url":"https://api.githubcopilot.com/mcp","headers":{"Authorization":"Bearer YOUR_GITHUB_PAT"}}'
```

Format: `claude mcp add-json <name> '<JSON configuration>'`

Examples:

```bash
# Filesystem (access to a specific directory)
claude mcp add filesystem -- npx -y @modelcontextprotocol/server-filesystem /home/user/projects

# Brave Search (official package from Brave; the old @modelcontextprotocol/server-brave-search is archived)
claude mcp add brave-search -- npx -y @brave/brave-search-mcp-server

# PostgreSQL (@modelcontextprotocol/server-postgres is archived; use an actively maintained third-party package, e.g. mcp-postgres-server)
claude mcp add postgres -- npx -y mcp-postgres-server postgresql://localhost/mydb
```

The configuration is saved — the server is available the next time Claude Code starts.

### Method 2: the .mcp.json file

For project-level configuration, use a `.mcp.json` file at the project root:

```json
{
  "mcpServers": {
    "github": {
      "type": "http",
      "url": "https://api.githubcopilot.com/mcp",
      "headers": {
        "Authorization": "Bearer $GITHUB_PERSONAL_ACCESS_TOKEN"
      }
    },
    "filesystem": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/home/user/projects"],
      "env": {}
    },
    "postgres": {
      "command": "npx",
      "args": ["-y", "mcp-postgres-server", "postgresql://localhost/mydb"],
      "env": {}
    }
  }
}
```

- **Environment variables** — values in `env` support `$VAR` and `${VAR}` syntax. Variables are pulled from the shell environment at launch
- **No trailing commas in JSON** — a common mistake. JSON doesn't allow a comma after the last element
- **File location**: `.mcp.json` at the project root — for project-level servers; `~/.claude/.mcp.json` — for global (personal) ones

### Method 3: a remote HTTP server

For servers running over HTTP:

```json
{
  "mcpServers": {
    "my-remote-api": {
      "type": "http",
      "url": "https://mcp.example.com/v1",
      "headers": {
        "Authorization": "Bearer $MY_API_TOKEN"
      }
    }
  }
}
```

### Three configuration levels

Claude Code supports three scopes for MCP servers:

| Scope | File | Who sees it | When to use |
|---|---|---|---|
| Project (shared) | `.mcp.json` at project root | The whole team (committed to git) | Servers everyone on the project needs |
| Project (personal) | `.claude/.mcp.json` | You only | Personal servers for this project |
| Global | `~/.claude/.mcp.json` | You only, across all projects | Servers you need everywhere |

Shared project servers (GitHub, Sentry, Supabase) go in `.mcp.json`. Personal tools (Notion, Slack) go global.

### Verifying the connection

For a broader look at setting up and running Claude Code day to day — not just MCP servers — see the [complete Claude Code guide](/blog/claude-code-complete-guide/).

After setup, restart Claude Code and check:

```bash
claude mcp list
```

Or inside a Claude Code session: `/mcp` shows the status of every connected server.

### Common setup mistakes

**The server won't start.** For local servers, check that the package is reachable: `npx -y @modelcontextprotocol/server-filesystem --help`. Empty output means an npm or Node.js problem. For remote servers (GitHub), check that the token is set: `echo $GITHUB_PERSONAL_ACCESS_TOKEN`.

**Environment variables aren't substituted.** Check `echo $GITHUB_TOKEN`. If it's empty, add it to `.zshrc` / `.bashrc` or `.envrc`.

**JSON syntax error.** A trailing comma after the last element — JSON doesn't accept that. Validate with: `cat .mcp.json | python -m json.tool`.

**Server connects, but no tools show up.** Fully restart Claude Code (exit + new session). Some servers load with a delay — give it a few seconds.

## How to Connect an MCP Server to Cursor

### Configuration

Cursor uses the same configuration format, just different file locations.

**Project level** — the `.cursor/mcp.json` file at the project root:

```json
{
  "mcpServers": {
    "github": {
      "type": "http",
      "url": "https://api.githubcopilot.com/mcp",
      "headers": {
        "Authorization": "Bearer your-token-here"
      }
    }
  }
}
```

**Global level** — the `~/.cursor/mcp.json` file:

```json
{
  "mcpServers": {
    "brave-search": {
      "command": "npx",
      "args": ["-y", "@brave/brave-search-mcp-server"],
      "env": {
        "BRAVE_API_KEY": "your-key"
      }
    }
  }
}
```

### Cursor specifics

- MCP tools are only available in **Agent mode** (not in Ask or Edit)
- Server management: **Settings → Tools & MCP** — shows each server's status and lets you toggle individual tools on or off
- Cursor supports both stdio and HTTP transport
- The configuration format is identical to Claude Code — the same JSON with `mcpServers`

### Comparison: Claude Code vs. Cursor

| Parameter | Claude Code | Cursor |
|---|---|---|
| Configuration file | `.mcp.json` | `.cursor/mcp.json` |
| Global config | `~/.claude/.mcp.json` | `~/.cursor/mcp.json` |
| Transport | stdio, HTTP | stdio, HTTP |
| Management | CLI (`claude mcp add/list`) | GUI (Settings → MCP) |
| Agent mode | Always (the CLI itself is agentic) | Only in Agent mode |

## Top 20 MCP Servers

Out of 10,000+ available servers, here are twenty that cover a developer's core needs. All current as of June 2026. For a deeper ranked breakdown with setup notes, see our [best MCP servers for 2026](/blog/best-mcp-servers-2026/) roundup.

### Code and repositories

| Server | Package | Description |
|---|---|---|
| **GitHub** | Remote: `https://api.githubcopilot.com/mcp` or Docker: `ghcr.io/github/github-mcp-server` | Full GitHub access: issues, PRs, code search, files, actions. The most popular MCP server |
| **GitLab** | `gitlab-org/gitlab-mcp` (official, from GitLab) | The GitHub server's counterpart for GitLab: merge requests, issues, pipelines. The old `@modelcontextprotocol/server-gitlab` is archived |
| **Filesystem** | `@modelcontextprotocol/server-filesystem` | Safe filesystem access, restricted to specified directories |

### Databases

| Server | Package | Description |
|---|---|---|
| **PostgreSQL** | `mcp-postgres-server` (third-party) | Queries against PostgreSQL, schema reading, data analysis. The official `@modelcontextprotocol/server-postgres` is archived |
| **Supabase** | MCP built into the Supabase CLI | SQL queries, migration management, edge functions. Respects Row Level Security |
| **SQLite** | `@modelcontextprotocol/server-sqlite` (Python, official) | Working with SQLite databases: queries, analysis, table creation |

### Search and data

| Server | Package | Description |
|---|---|---|
| **Brave Search** | `brave/brave-search-mcp-server` (official, from Brave) | Web search, news search, image and video search via the Brave API. The old `@modelcontextprotocol/server-brave-search` is archived |
| **Exa** | `exa-mcp-server` | Semantic web search. Finds content by meaning, not by keyword |
| **Fetch** | `@modelcontextprotocol/server-fetch` | Fetches web pages, converts them to Markdown for AI consumption |

### Communication and documentation

| Server | Package | Description |
|---|---|---|
| **Slack** | `zencoder-ai/mcp-server-slack` (maintained by Zencoder) | Reading channels, searching messages, sending, working with threads. The old `@modelcontextprotocol/server-slack` is archived |
| **Notion** | Official, from Notion | Searching pages, reading and editing content, working with databases |
| **Google Drive** | Official, from Google | Searching and reading files in Google Drive. The old `@modelcontextprotocol/server-gdrive` is archived |

### Monitoring and DevOps

| Server | Package | Description |
|---|---|---|
| **Sentry** | Official, from Sentry | Error search, stack trace analysis, correlation with releases |
| **Grafana** | Official, from Grafana Labs | Dashboards, alerts, Prometheus/Loki queries, incidents |
| **Kubernetes** | `@modelcontextprotocol/server-kubernetes` | Cluster management, pod diagnostics, log analysis |

### Design and browser

| Server | Package | Description |
|---|---|---|
| **Figma** | `figma-developer-mcp` (official, from Figma) | Reading design files: tokens, colors, typography, layout |
| **Playwright** | `@playwright/mcp` | Browser automation: navigation, clicks, screenshots, tests |

### AI and memory

| Server | Package | Description |
|---|---|---|
| **Memory** | `@modelcontextprotocol/server-memory` | Persistent memory for AI: storing facts across sessions in a knowledge graph |
| **Sequential Thinking** | `@modelcontextprotocol/server-sequential-thinking` | Structured reasoning: task decomposition, step-by-step analysis |

### Automation

| Server | Package | Description |
|---|---|---|
| **Zapier** | Via the Zapier MCP Bridge | Connects 7,000+ services: email, CRM, spreadsheets, notifications |

### Recommendations for picking servers

Three servers is optimal. Five is the ceiling — beyond that, the overhead from tool descriptions starts eating into context.

A minimal setup for a developer:

1. **GitHub** — code, issues, PRs
2. **Brave Search** or **Exa** — searching documentation and solutions
3. **Sentry** or **Grafana** — monitoring and debugging

Beyond that: PostgreSQL/Supabase for data, Slack/Notion for communication.

## Writing Your Own MCP Server in TypeScript

### Setup

```bash
mkdir my-mcp-server && cd my-mcp-server
npm init -y
npm install @modelcontextprotocol/sdk zod
```

### Full example: a server with a tool and a resource

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

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

// Tool: get weather for a city
server.registerTool(
  "get_weather",
  {
    title: "Get Weather",
    description: "Get current weather for a city",
    inputSchema: {
      city: z.string().describe("City name, e.g. 'Moscow'"),
    },
  },
  async ({ city }) => {
    // In a real server, this would call a weather API
    const weather = {
      city,
      temperature: 18,
      condition: "cloudy",
      humidity: 65,
    };
    return {
      content: [
        {
          type: "text" as const,
          text: JSON.stringify(weather, null, 2),
        },
      ],
    };
  }
);

// Resource: list of supported cities
server.registerResource(
  "supported-cities",
  "cities://supported",
  {
    description: "List of supported cities",
    mimeType: "application/json",
  },
  async () => ({
    contents: [
      {
        uri: "cities://supported",
        text: JSON.stringify(["Moscow", "London", "Tokyo", "New York"]),
      },
    ],
  })
);

// Start over the stdio transport
const transport = new StdioServerTransport();
await server.connect(transport);
```

### What's happening here

1. **McpServer** — a server instance with a name and version
2. **registerTool** — registers a tool. `inputSchema` uses Zod for validation. The AI model sees the description and schema, and calls the tool with the right parameters
3. **registerResource** — registers a resource with the signature `(name, uri, metadata, handler)`. Unlike a tool, a resource is invoked by the application (the Host), not directly by the AI model. That's how context gets into the model
4. **StdioServerTransport** — connects over stdio. The server runs as a child process of Claude Code or Cursor

### Connecting it to Claude Code

```json
{
  "mcpServers": {
    "weather": {
      "command": "npx",
      "args": ["tsx", "/path/to/my-mcp-server/index.ts"]
    }
  }
}
```

Or via the CLI:

```bash
claude mcp add weather -- npx tsx /path/to/my-mcp-server/index.ts
```

## Writing Your Own MCP Server in Python

### Setup

```bash
mkdir my-mcp-server && cd my-mcp-server
pip install "mcp[cli]"  # v1.28.1+
```

Or with `uv` (recommended):

```bash
uv init my-mcp-server && cd my-mcp-server
uv add "mcp[cli]"
```

### Full example: a server with a tool and a resource

```python
from mcp.server.fastmcp import FastMCP

mcp = FastMCP("weather-server")


@mcp.tool()
def get_weather(city: str) -> dict:
    """Get current weather for a city.

    Args:
        city: City name, e.g. 'Moscow'
    """
    # In a real server, this would call a weather API
    return {
        "city": city,
        "temperature": 18,
        "condition": "cloudy",
        "humidity": 65,
    }


@mcp.resource("cities://supported")
def supported_cities() -> str:
    """List of supported cities."""
    import json
    return json.dumps(["Moscow", "London", "Tokyo", "New York"])


@mcp.prompt()
def weather_report(city: str) -> str:
    """Generate a weather report prompt for a city."""
    return f"Provide a detailed weather analysis for {city}. Include temperature trends, precipitation forecast, and clothing recommendations."


if __name__ == "__main__":
    mcp.run()
```

### What's happening here

1. **FastMCP** — a high-level framework from the official SDK. It generates tool descriptions from docstrings and type hints automatically
2. **@mcp.tool()** — the registration decorator. The `city: str` type becomes the `inputSchema`, the docstring becomes the description
3. **@mcp.resource()** — the decorator for a resource with a URI pattern
4. **@mcp.prompt()** — the decorator for a prompt template
5. **mcp.run()** — starts the server (stdio by default)

FastMCP covers about 70% of servers in the ecosystem. Python type hints plus docstrings add up to a complete tool description — no extra boilerplate.

### Connecting it to Claude Code

```json
{
  "mcpServers": {
    "weather": {
      "command": "python",
      "args": ["/path/to/my-mcp-server/server.py"]
    }
  }
}
```

Or via `uv`:

```json
{
  "mcpServers": {
    "weather": {
      "command": "uv",
      "args": ["run", "--directory", "/path/to/my-mcp-server", "server.py"]
    }
  }
}
```

## Resources vs. Tools vs. Prompts

MCP defines three types of capabilities. Each fits its own scenario. Confusing them is a common mistake when designing servers.

### Tools — actions

Tools are what the AI model calls on its own. The equivalent of POST endpoints in a REST API.

**Characteristics:**
- Called by the AI model (model-controlled)
- Can have side effects (writing to a database, sending a message, creating a file)
- Accept structured input (JSON Schema / Zod)
- Return the result of execution

**Examples:**
- `create_issue` — create a GitHub issue
- `execute_sql` — run a SQL query
- `send_message` — send a Slack message
- `search_web` — search the internet

The model sees the list of tools with their descriptions and schemas — and decides for itself which one to call and with what parameters.

### Resources — data

Resources are data the Host provides to the AI model as context. The equivalent of GET endpoints.

**Characteristics:**
- Invoked by the application (application-controlled), not directly by the AI model
- Read-only — no side effects
- Use URI patterns (`file:///path`, `db://schema/table`, `config://app`)
- Provide context for decision-making

**Examples:**
- `db://schema` — a database schema
- `file:///src/config.ts` — the contents of a config file
- `git://log/recent` — recent commits
- `env://variables` — available environment variables

Resources are a way to give the model context without calling a tool. The Host decides which resources to attach to a request.

### Prompts — templates

Prompts are ready-made interaction templates the user chooses from. The equivalent of saved queries.

**Characteristics:**
- Chosen by the user (user-controlled)
- Define the structure of a conversation: system prompt plus user message
- Can accept arguments for parameterization
- Help standardize routine tasks

**Examples:**
- `code_review` — a template for reviewing code with a security focus
- `sql_optimizer` — analyzing and optimizing a SQL query
- `bug_report` — a structured bug description

### When to use which

| Question | Tools | Resources | Prompts |
|---|---|---|---|
| Does the AI need to **do** something? | Yes | — | — |
| Does the AI need **context** to decide? | — | Yes | — |
| Does the user want a **standard workflow**? | — | — | Yes |
| Are there side effects? | Possibly | No | No |
| Who initiates it? | The AI model | The application | The user |

In practice: most servers provide tools. Resources are useful for database servers (schemas) and filesystem servers. Prompts are for specialized workflows (code review, security audits).

## MCP in Production

### Security

An MCP server performs actions on behalf of an AI — in production, that's an attack vector.

**Principle of least privilege.** Give the server only the permissions it needs. A PostgreSQL MCP doesn't need SUPERUSER. A GitHub MCP doesn't need access to private repos if the work is on public ones.

**Input validation.** The SDK validates against the schema (Zod in TypeScript, type hints in Python), but that's not enough. Check the business logic too — SQL injection through tool parameters is a real risk.

**Secrets through environment variables.** Never hardcode tokens in configuration. Use `$VAR` syntax in `.mcp.json`:

```json
{
  "env": {
    "DATABASE_URL": "$DATABASE_URL",
    "API_TOKEN": "$MY_SECRET_TOKEN"
  }
}
```

**Auditing.** Log every tool call — each one is potentially destructive: data deletion, sending messages, infrastructure changes. No log, no forensics. For a full walkthrough of hardening and shipping servers in production, see our guide on [building and running production-grade MCP servers](/blog/mcp-production-custom-servers/).

### Authorization

The MCP specification (current revision 2025-11-25; RC 2026-07-28 frozen since May 21, 2026, final publication July 28) describes authorization for the HTTP transport based on OAuth 2.1. For stdio, authorization happens at the environment level: variables and configuration files.

In June 2026, Enterprise-Managed Authorization (EMA) became stable — an extension for enterprise environments. EMA lets organizations manage MCP server authorization centrally through an IdP (Okta, Microsoft Entra ID, and others): the user signs in once via SSO and gets access to every connected server without a separate OAuth flow for each one. Already supported by Anthropic, Microsoft, Okta, Asana, Atlassian, Canva, Figma, Linear, and Supabase.

In production:
- HTTP servers — OAuth 2.1 with PKCE, bearer tokens in headers; in enterprise settings, EMA through an IdP
- Stdio servers — secrets via env, token rotation
- Scope restriction — a server should request only the minimum necessary permissions

### Monitoring

What to monitor:

- **Latency** — the server's response time adds to the AI response's overall latency
- **Error rate** — a broken MCP server takes down the whole workflow
- **Token overhead** — tool descriptions take up context. 20 tools at 200 tokens each is 4,000 tokens on every request
- **Cost** — every tool call adds an AI cycle. More servers mean higher token spend

Grafana MCP plus Prometheus for metrics, Sentry MCP for errors. Monitoring MCP through MCP — recursion that actually works.

### Scaling

Stdio is one process per client. It doesn't scale for team servers.

Streamable HTTP solves this: one server for many clients. A stateless architecture — horizontal scaling behind a load balancer.

A pattern for teams:
1. Local servers (filesystem, sqlite) — stdio, on the developer's machine
2. Shared servers (GitHub, Sentry, internal APIs) — Streamable HTTP, deployed in Docker/Kubernetes
3. Configuration — `.mcp.json` in the repo for project-level servers, `~/.cursor/mcp.json` / `~/.claude/.mcp.json` for personal ones

## The Future of MCP

### Agentic AI Foundation (AAIF)

In December 2025, Anthropic handed MCP over to the Linux Foundation, where the Agentic AI Foundation (AAIF) formed. This is a governance shift, not a cosmetic one:

- **Neutral governance** — MCP is no longer controlled by a single company. AAIF platinum members: AWS, Anthropic, Block, Bloomberg, Cloudflare, Google, Microsoft, OpenAI. By April 2026: 170+ members. Governing Board chair — David Nalley (AWS); executive director — Mazin Gilbert
- **Open specification** — development through the SEP process (Specification Enhancement Proposals) with public discussion
- **Interoperability** — AAIF is aligning MCP, Goose (Block), and AGENTS.md (OpenAI) into a coherent set of standards

### The A2A Protocol

Agent-to-Agent Protocol (A2A) — Google's standard for communication between AI agents, also handed over to the Linux Foundation. MCP covers the "AI ↔ tool" connection. A2A covers "agent ↔ agent."

The protocols complement each other:
- MCP: Claude Code calls GitHub through an MCP server
- A2A: Claude Code delegates a task to a specialized agent (say, a security reviewer) that works with its own MCP servers

A2A is its own standalone LF project, not part of AAIF, but it's positioned as a complementary standard. A2A's TSC includes AWS, Cisco, Google, IBM Research, Microsoft, Salesforce, SAP, and ServiceNow. MCP plus A2A together are the de facto standard for multi-agent systems — see our [multi-agent architecture guide](/blog/multi-agent-architecture/) for patterns on coordinating several agents in practice.

### 2026 roadmap

Key directions from the official roadmap:

- **Stateless core** — MCP 2026-07-28 (Release Candidate frozen May 21, 2026, final publication July 28) makes the protocol stateless at its core. This is the biggest specification change since launch — the spec no longer assumes server-side session state, which allows horizontal scaling behind any load balancer
- **Extensions framework** — extensions are identified by reverse-DNS IDs, versioned independently of the core spec, and live in separate `ext-*` repositories
- **Tasks Extension** — long-running async operations: polling via `tasks/get` instead of the blocking `tasks/result`
- **MCP Apps** — interactive UI applications inside MCP hosts
- **Enterprise readiness** — a formal deprecation policy (12 months between deprecated and removed), OAuth 2.1 hardening, audit logging

### The numbers

- **110M+** SDK installs per month (April 2026; 97M+ in March) — both SDKs combined
- **10,000+** servers in the official registry; counting PulseMCP (15,000+) and Smithery (~7,300), the ecosystem is considerably larger
- **4,750% growth** over 16 months (from 2M at launch)
- npm SDK: `@modelcontextprotocol/sdk` — v1.29.0 (stable, the latest in the v1 series); stable v2 expected Q3 2026
- Python SDK: `mcp` — v1.28.1 (stable), v2.0.0-beta published on PyPI; stable v2 due end of July 2026

MCP crossed the 100M monthly installs mark by April 2026 — roughly a year and a half after launch.

## Conclusion

MCP isn't a buzzword. It's an infrastructure standard solving a concrete problem: connecting AI to the real world through a single protocol.

What to do now:

1. **Connect 2-3 MCP servers** to Claude Code or Cursor. GitHub plus Brave Search or Exa is the minimum for any developer
2. **Write your own server** — 30 lines of TypeScript or Python. Wrap an internal API or a database
3. **Follow the specification** — the 2026 roadmap is changing both transport and multi-agent scenarios

MCP doesn't change what AI does — it changes what it has access to. The right tools in the right context are the difference between an AI assistant and an AI partner.
