MCP (Model Context Protocol) Explained

How AI tools connect to LLMs through the universal open standard

AI & DevelopmentJuly 6, 202618 min readBy Keyur Patel

Every AI tool has its own custom way of connecting to the outside world. Claude has tool use. ChatGPT has plugins and function calling. Coding agents have their own bespoke integrations. If you build a tool — say, a database connector — you have to implement it separately for every AI platform that wants to use it.

This is the N×M problem. N tools times M platforms equals a lot of duplicated work. MCP (Model Context Protocol) solves this by creating a single, open standard for how AI models connect to external tools, data sources, and systems. Think of it as USB for AI — one protocol, universal compatibility.

In this guide, I'll break down what MCP is, how it works architecturally, how to build with it, and when you should (or shouldn't) reach for it. Whether you're evaluating MCP for your team or just trying to understand what's happening when your AI IDE connects to a database, this should cover it.

What Is MCP (Model Context Protocol)?

MCP stands for Model Context Protocol. It's an open standard created by Anthropic that defines a universal way for AI applications to connect to external tools, data sources, and systems. Released in late 2024 and rapidly adopted throughout 2025-2026, MCP has become the de facto standard for AI tool integration.

Before MCP, if you wanted your AI assistant to access a database, read files, or call an API, you needed a custom integration for each AI platform. MCP changes this by defining a common protocol — build one MCP server, and it works with any MCP-compatible host application (Claude Desktop, Kiro, Cursor, and dozens of others).

The key insight is separation of concerns. The AI model doesn't need to know the details of how to query Postgres or fetch GitHub issues. It just needs to know that a tool called query_database exists, what parameters it accepts, and what it returns. The MCP server handles all the implementation details.

MCP in One Sentence

MCP is a standardized JSON-RPC protocol that lets AI host applications discover and invoke tools provided by external server processes — turning the N×M integration problem into N+M.

Why MCP Matters

To understand why MCP matters, think about what existed before it. Every AI application had its own proprietary way to connect to tools:

  • OpenAI: Function calling with a specific JSON schema format
  • Anthropic: Tool use with its own parameter format
  • LangChain: Custom tool abstractions with Python classes
  • Individual IDEs: Each with proprietary extension APIs

If you built a useful tool — say, a Jira integration — you'd need to build it once for each platform. That's expensive, time-consuming, and fragile. When APIs change, you have multiple implementations to update.

MCP solves this the same way USB solved hardware connectivity. Before USB, every peripheral had its own connector. USB created one standard — and the entire hardware ecosystem benefited. MCP does the same for AI tool connectivity:

Without MCPWith MCP
N tools × M platforms = N×M integrationsN tools + M platforms = N+M implementations
Each platform has proprietary tool APIsOne standard protocol for all platforms
Tool authors maintain multiple versionsTool authors maintain one MCP server
Switching platforms means rebuilding integrationsSwitch platforms, keep your MCP servers
Limited ecosystem (high barrier to entry)Growing ecosystem (low barrier to build)

How MCP Works: Architecture Overview

MCP uses a client-server architecture with three main roles. Understanding these roles is key to understanding the entire protocol:

  • Host: The AI application the user interacts with (Claude Desktop, Kiro, Cursor). The host manages the user experience and coordinates between the model and MCP clients.
  • Client: A component inside the host that maintains a 1:1 connection with a specific MCP server. Each server gets its own client instance.
  • Server: A lightweight program that exposes specific capabilities (tools, resources, prompts) through the MCP protocol. Runs as a separate process.

The communication flow is straightforward: the user asks the AI something, the model decides it needs external data or an action, the host routes the request through the appropriate MCP client to the relevant server, the server executes the operation and returns results, and the model incorporates those results into its response.

MCP Architecture Diagram

┌─────────────────────────────────────────────────────────┐
│                    HOST APPLICATION                       │
│                 (Claude Desktop / Kiro / Cursor)          │
│                                                           │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐     │
│  │ MCP Client  │  │ MCP Client  │  │ MCP Client  │     │
│  └──────┬──────┘  └──────┬──────┘  └──────┬──────┘     │
└─────────┼────────────────┼────────────────┼─────────────┘
          │ JSON-RPC       │ JSON-RPC       │ JSON-RPC
          │ (stdio/HTTP)   │ (stdio/HTTP)   │ (stdio/HTTP)
          ▼                ▼                ▼
┌─────────────┐  ┌─────────────┐  ┌─────────────┐
│ MCP Server  │  │ MCP Server  │  │ MCP Server  │
│ (Postgres)  │  │ (GitHub)    │  │ (Filesystem)│
└──────┬──────┘  └──────┬──────┘  └──────┬──────┘
       │                 │                 │
       ▼                 ▼                 ▼
  ┌─────────┐     ┌─────────┐      ┌─────────┐
  │Database │     │GitHub   │      │Local    │
  │         │     │API      │      │Files    │
  └─────────┘     └─────────┘      └─────────┘

Each MCP server is isolated — a crash in your GitHub server won't affect your database server. The host can connect to multiple servers simultaneously, giving the AI model access to a wide range of capabilities through a single protocol.

Transport Layer: How Messages Move

MCP uses JSON-RPC 2.0 as its message format — the same protocol used by the Language Server Protocol (LSP) that powers IDE features like autocomplete and go-to-definition. This wasn't accidental; MCP explicitly draws inspiration from LSP's success in standardizing IDE tooling.

Two transport mechanisms are supported:

stdio (Standard I/O)

The server runs as a child process of the host. Communication happens through stdin/stdout pipes. Simple, fast, no network configuration needed. Best for local tools like file system access, local databases, or CLI wrappers.

HTTP + Server-Sent Events (SSE)

The server runs as an HTTP endpoint. The client sends requests via POST and receives responses and notifications via SSE. Best for remote servers, shared team infrastructure, or servers that need to be accessible over the network.

A typical JSON-RPC message for invoking a tool looks like this:

// Request (Client → Server)
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "query_database",
    "arguments": {
      "sql": "SELECT * FROM users WHERE active = true LIMIT 10"
    }
  }
}

// Response (Server → Client)
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "[{"id": 1, "name": "Alice"}, {"id": 2, "name": "Bob"}]"
      }
    ]
  }
}

Core MCP Concepts

MCP servers can expose four types of capabilities. Each serves a different purpose in the interaction between the AI model and external systems:

Tools

Functions the model can call — like API endpoints for AI. Tools are the most common capability. They represent actions: query a database, create a file, send a message, search the web. The model decides when to call a tool based on the user's request and the tool's description.

Each tool has a name, a description (which the model reads to decide when to use it), and an input schema (JSON Schema defining the parameters). The host typically requires user approval before executing tools, since they can have side effects.

Resources

Data the model can read — files, database records, API responses, configuration. Resources are identified by URIs and are read-only. Unlike tools, resources don't have side effects. They provide context that helps the model understand the current state of things.

Example URIs: file:///project/src/app.ts, postgres://localhost/mydb/users, github://repo/issues/42

Prompts

Reusable prompt templates exposed by servers. Prompts are pre-written instructions that help users invoke complex workflows. A database server might expose a "explain-query" prompt that formats a SQL query analysis request. The user selects a prompt, fills in the arguments, and it generates a well-structured request for the model.

Prompts are user-controlled — they require explicit selection rather than being invoked automatically by the model. This makes them ideal for complex, multi-step workflows where you want consistent formatting.

Sampling

A capability that allows MCP servers to request the model to generate text. This flips the usual direction — instead of the model calling tools, the tool asks the model to think. Useful for agentic workflows where a server needs LLM reasoning as part of its operation (for example, summarizing search results before returning them).

Sampling is the most advanced MCP capability and requires careful implementation. The host mediates all sampling requests to maintain security and prevent loops.

MCP vs Function Calling vs LangChain

These three approaches solve overlapping problems but at different layers of the stack. Understanding the differences helps you choose the right tool for your situation:

AspectMCPFunction CallingLangChain
What it isOpen protocol (like HTTP)Model feature (like an API param)Framework/library (like Express)
ScopeTool discovery + execution + lifecycleSingle API call: model outputs tool callsChains, agents, memory, tools, RAG
StandardizationUniversal spec — works across platformsVendor-specific (OpenAI vs Anthropic formats)Python/JS library with its own abstractions
Runtime modelSeparate server processes (stdio/HTTP)Same process as your applicationSame process, orchestrated by framework
Tool discoveryDynamic — server advertises capabilitiesStatic — you define tools per requestStatic — defined in code at build time
EcosystemShared servers anyone can useCustom per applicationCommunity chains and tools (Python-centric)
ComplexityProtocol overhead (server process, config)Minimal — part of API callFramework learning curve, abstractions
Best forReusable tool infrastructure, IDE integrationsSimple tool use in your own appComplex AI pipelines, RAG, multi-step agents

These aren't mutually exclusive. A LangChain agent could use MCP servers as its tool backend. A host application uses function calling internally while connecting to tools via MCP externally. Think of them as different layers: function calling is the model-level mechanism, MCP is the network protocol, and LangChain is the application framework.

Building an MCP Server (Node.js Example)

Building an MCP server is surprisingly straightforward. The official @modelcontextprotocol/sdk package handles the protocol details — you just define your tools and their logic. Here's a complete, working example of a weather MCP server:

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

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

// Define a tool
server.tool(
  "get_weather",
  "Get current weather for a city",
  {
    city: z.string().describe("City name (e.g., 'London')"),
    units: z.enum(["celsius", "fahrenheit"]).default("celsius"),
  },
  async ({ city, units }) => {
    // Your actual implementation here
    const response = await fetch(
      `https://api.weather.example/current?city=${city}&units=${units}`
    );
    const data = await response.json();

    return {
      content: [
        {
          type: "text",
          text: `Weather in ${city}: ${data.temperature}°${units === "celsius" ? "C" : "F"}, ${data.condition}`,
        },
      ],
    };
  }
);

// Define a resource
server.resource(
  "weather://forecast/{city}",
  "Get 5-day forecast for a city",
  async (uri) => {
    const city = uri.pathname.split("/").pop();
    const data = await fetchForecast(city);
    return {
      contents: [{ uri: uri.href, mimeType: "application/json", text: JSON.stringify(data) }],
    };
  }
);

// Start the server with stdio transport
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("Weather MCP server running on stdio");

That's it. The SDK handles JSON-RPC serialization, capability negotiation, error formatting, and transport management. You focus on what your tool actually does. To make this server available, you'd add it to your host application's MCP configuration:

// mcp.json (or equivalent config in your host app)
{
  "mcpServers": {
    "weather": {
      "command": "node",
      "args": ["./weather-server.js"],
      "env": {
        "WEATHER_API_KEY": "your-api-key-here"
      }
    }
  }
}

The host will spawn your server as a child process, negotiate capabilities, and the model will automatically see "get_weather" in its available tools. When a user asks "What's the weather in Tokyo?", the model calls your tool, gets the response, and incorporates it into a natural language reply.

Building an MCP Client

Most developers won't need to build an MCP client — that's the host application's job (Claude Desktop, Kiro, etc. already handle this). But understanding the client side helps you debug issues and test your servers. Here's what a minimal client looks like:

import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";

// Create client and connect to a server
const transport = new StdioClientTransport({
  command: "node",
  args: ["./weather-server.js"],
});

const client = new Client({ name: "my-app", version: "1.0.0" });
await client.connect(transport);

// Discover available tools
const { tools } = await client.listTools();
console.log("Available tools:", tools.map(t => t.name));
// → ["get_weather"]

// Call a tool
const result = await client.callTool({
  name: "get_weather",
  arguments: { city: "Tokyo", units: "celsius" },
});
console.log(result.content[0].text);
// → "Weather in Tokyo: 28°C, Partly Cloudy"

// List available resources
const { resources } = await client.listResources();

// Read a resource
const forecast = await client.readResource({
  uri: "weather://forecast/Tokyo",
});

The client handles connection lifecycle, capability negotiation, and message routing. In practice, host applications manage multiple client instances — one per configured server — and translate between the model's tool-calling format and MCP's JSON-RPC messages.

Popular MCP Servers

The MCP ecosystem has grown rapidly. Here are some widely-used servers that demonstrate the breadth of what MCP enables:

ServerWhat It DoesUse Case
@modelcontextprotocol/server-postgresQuery PostgreSQL databases, inspect schemas, run migrationsDatabase exploration and management
@modelcontextprotocol/server-githubCreate issues, PRs, search repos, manage branchesGit workflow automation
@modelcontextprotocol/server-filesystemRead/write files, search directories, watch changesLocal file operations
@aws/mcpInteract with AWS services — S3, Lambda, DynamoDB, CloudWatchCloud infrastructure management
@modelcontextprotocol/server-brave-searchWeb search with Brave Search APIReal-time information retrieval
@modelcontextprotocol/server-puppeteerBrowser automation, screenshots, web scrapingTesting and web interaction
@modelcontextprotocol/server-sqliteQuery SQLite databases, create tables, manage dataLocal database development
@modelcontextprotocol/server-slackSend messages, read channels, search historyTeam communication integration

These are just the official and most popular servers. The community has built hundreds more — for Notion, Linear, Confluence, Docker, Kubernetes, and pretty much any service with an API. The registry at the MCP hub lets you discover and install servers with a single command.

MCP in Practice: How Real Tools Use It

Let's look at how actual AI applications use MCP to provide their capabilities:

Kiro

Kiro uses MCP as its primary extensibility mechanism. Developers configure MCP servers in their project (or globally) through a "Powers" system. When Kiro's agent needs to interact with a database, fetch documentation, or use a specialized tool, it routes through MCP. This means you can extend Kiro's capabilities without modifying Kiro itself — just add an MCP server.

Kiro's approach is particularly interesting because it manages MCP server lifecycle automatically — starting servers on demand, handling reconnection, and cleaning up when they're no longer needed.

Claude Desktop

Claude Desktop was one of the first MCP hosts. Users configure servers in a JSON file, and Claude gains access to whatever tools those servers provide. Want Claude to access your local files? Add the filesystem server. Want it to query your database? Add the Postgres server. The model sees these tools alongside its built-in capabilities and uses them naturally in conversation.

Cursor

Cursor integrates MCP to extend its coding agent with custom tools. Teams can build internal MCP servers that expose company-specific operations — deploying to staging, querying internal APIs, or accessing proprietary documentation. The agent uses these tools alongside its built-in code editing capabilities.

Typical MCP Configuration (mcp.json)

{
  "mcpServers": {
    "postgres": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-postgres"],
      "env": { "DATABASE_URL": "postgresql://localhost:5432/myapp" }
    },
    "github": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": { "GITHUB_TOKEN": "ghp_xxxxxxxxxxxx" }
    },
    "aws": {
      "command": "npx",
      "args": ["-y", "@aws/mcp"],
      "env": { "AWS_PROFILE": "dev" }
    }
  }
}

When to Build an MCP Server vs Use Function Calling

This is one of the most common questions developers ask. The answer depends on your use case:

Build an MCP Server When:

  • You want reusability — the tool should work across multiple AI platforms (Claude, Kiro, Cursor, custom apps)
  • You're building developer tools — IDE integrations, CLI wrappers, documentation servers
  • The tool is general-purpose — database access, file operations, API integrations that many projects need
  • You want isolation — the tool runs in its own process with its own dependencies, separate from the host
  • You're building for a team — shared infrastructure that multiple developers can use with their preferred AI tools

Use Function Calling When:

  • You're building a single application — a chatbot, customer support agent, or internal tool that uses one LLM provider
  • Simplicity matters — you don't want the overhead of a separate server process
  • The tools are tightly coupled to your app — they depend on your app's state, session data, or user context
  • You're prototyping — function calling is faster to set up for quick experiments
  • Latency is critical — in-process function calls avoid the IPC overhead of MCP

Rule of Thumb

If the tool is about your app's domain logic, use function calling. If the tool is about connecting to external systems that multiple apps might need, build an MCP server.

Security Considerations

MCP gives AI models access to external systems, which means security is critical. A poorly secured MCP server could expose sensitive data or allow unintended actions. Here are the key security considerations:

Tool Approval

The host application should require user approval before executing tools — especially tools with side effects. Most MCP hosts implement a tiered system: read-only operations may auto-approve, while write operations require explicit confirmation. This is the primary defense against unintended actions.

Sandboxing

MCP servers run as separate processes, which provides natural isolation. A compromised server can't access the host's memory or other servers' data. For stronger isolation, run servers in containers or restricted environments with minimal permissions.

Data Access Control

Servers should implement the principle of least privilege. A database server doesn't need to expose DROP TABLE capabilities. A file system server should restrict access to specific directories. Environment variables (API keys, tokens) should be scoped to exactly what the server needs.

Input Validation

MCP servers receive input from AI models, which can be unpredictable. Always validate and sanitize inputs. Use parameterized queries for databases (never string interpolation). Validate file paths to prevent directory traversal. Treat all tool arguments as untrusted input.

Prompt Injection Awareness

If your MCP server returns data that gets inserted into the model's context (which it does — that's the whole point), that data could contain prompt injection attempts. Design your server to sanitize output and be aware that malicious content in databases, files, or APIs could influence the model's behavior.

Low risk

Operations: Read-only resources, listing capabilities

→ Policy: Auto-approve

Medium risk

Operations: Writing files, creating records, API calls

→ Policy: Notify user, require approval

High risk

Operations: Deleting data, modifying permissions, production systems

→ Policy: Always require explicit confirmation

Common Mistakes When Working with MCP

After building and integrating several MCP servers, here are the mistakes I see most often:

  • Writing vague tool descriptions: The model decides which tool to call based on its description. "Handles database stuff" is useless. "Execute a read-only SQL query against the PostgreSQL database and return results as JSON" gives the model everything it needs to use the tool correctly.
  • Returning too much data: MCP tool responses go into the model's context window, which has limits. If your tool returns 50,000 rows from a database, you'll blow the context and get degraded responses. Paginate, summarize, or limit results by default.
  • Not handling errors gracefully: When a tool throws an unhandled exception, the model gets a cryptic error message it can't act on. Return structured error messages with enough detail for the model to understand what went wrong and potentially retry with different parameters.
  • Skipping input validation: The model might pass unexpected types, empty strings, or values outside expected ranges. Your server should validate everything and return helpful error messages rather than crashing.
  • Making tools too broad: A single tool that does 10 different things based on a "mode" parameter confuses models. Break it into focused tools with clear, single purposes. list_users, get_user, and create_user are better than manage_users with an action parameter.
  • Ignoring server lifecycle: MCP servers should handle startup, shutdown, and reconnection gracefully. Don't assume the connection will stay alive forever — the host might restart, lose connectivity, or timeout idle connections.

MCP Best Practices

These practices come from building servers, integrating them into real workflows, and watching where things break:

  • Write descriptive tool descriptions: The description is the model's only guide for when and how to use the tool. Include what it does, what it returns, when to use it vs alternatives, and any limitations. Think of it as documentation for an AI reader.
  • Use Zod or JSON Schema for input validation: Define strict schemas for all tool parameters. This serves double duty — it validates input at runtime and provides the model with structured parameter documentation through the schema.
  • Return structured, concise responses: Format output for model consumption. Use JSON for structured data, limit text length, and include metadata like result counts or pagination info. The model reads your response — make it easy to parse.
  • Implement idempotency where possible: Models sometimes retry tool calls. If your tool creates a resource, consider making it idempotent (creating the same resource twice doesn't cause duplicates). This makes the system more robust to retries and model uncertainty.
  • Log everything: MCP servers run as background processes. When something goes wrong, logs are your only debugging tool. Log incoming requests, outgoing responses, errors, and performance metrics. Write logs to stderr (stdout is reserved for the JSON-RPC protocol in stdio mode).
  • Keep servers focused: One server should serve one domain. A "postgres-server" that also handles Redis and MongoDB is harder to maintain, configure, and debug. Separate concerns into separate servers.
  • Version your servers: As you update tool schemas or behavior, version your server. This prevents breaking changes from affecting users who haven't updated their host application's expectations.
  • Test with real models: Unit tests for your tool logic are necessary but not sufficient. Test with an actual model to verify that descriptions are clear enough, responses are useful, and the overall interaction feels natural. Models interpret tools differently than humans read documentation.

MCP Connection Lifecycle

Understanding the connection lifecycle helps you build robust servers and debug connection issues:

MCP Connection Lifecycle:

1. INITIALIZE
   Client → Server: { method: "initialize", params: { capabilities, clientInfo } }
   Server → Client: { result: { capabilities, serverInfo } }
   
2. INITIALIZED (notification)
   Client → Server: { method: "notifications/initialized" }
   
3. NORMAL OPERATION
   - Client discovers tools:    tools/list → response
   - Client calls tools:        tools/call → response
   - Client reads resources:    resources/read → response
   - Server sends notifications: resource updates, log messages
   
4. SHUTDOWN
   Either side closes the transport
   Server performs cleanup (close DB connections, etc.)

During initialization, the client and server exchange capabilities — the client declares what it supports (like roots, sampling), and the server declares what it provides (tools, resources, prompts). This negotiation ensures both sides know what to expect.

The MCP Ecosystem in 2026

The MCP ecosystem has matured significantly since its 2024 launch. Here's where things stand:

  • Official SDKs: TypeScript/Node.js, Python, Kotlin, and community SDKs for Go, Rust, C#, and Java
  • Server registry: Centralized discovery of community-built servers with ratings, documentation, and installation instructions
  • Host applications: Support from major AI tools including Claude Desktop, Kiro, Cursor, Windsurf, Continue, Cline, and many others
  • Enterprise adoption: Companies building internal MCP servers for proprietary systems — deployment pipelines, internal APIs, compliance tools
  • Standardization progress: Working toward formal IETF standardization to cement MCP as an industry standard rather than just a popular convention

The trajectory mirrors what happened with LSP (Language Server Protocol) — once a critical mass of hosts and servers adopted the standard, the ecosystem became self-reinforcing. Every new server makes every host more capable, and every new host makes building servers more worthwhile.

Advanced: Building a Custom MCP Transport

While stdio and HTTP cover most use cases, you might need a custom transport for specific environments — WebSocket connections, message queues, or inter-process communication via shared memory. The SDK supports custom transports through a simple interface:

// Custom WebSocket transport (simplified example)
class WebSocketServerTransport {
  constructor(ws) {
    this.ws = ws;
  }

  async start() {
    this.ws.on("message", (data) => {
      const message = JSON.parse(data);
      this.onmessage?.(message);
    });
    this.ws.on("close", () => this.onclose?.());
  }

  async send(message) {
    this.ws.send(JSON.stringify(message));
  }

  async close() {
    this.ws.close();
  }
}

// Use with the standard MCP server
const server = new McpServer({ name: "ws-server", version: "1.0.0" });
// ... define tools ...

wss.on("connection", async (ws) => {
  const transport = new WebSocketServerTransport(ws);
  await server.connect(transport);
});

Custom transports open up possibilities like running MCP servers in browser extensions, embedding them in Electron apps, or connecting through enterprise message brokers. The protocol itself is transport-agnostic — as long as you can send and receive JSON-RPC messages, any transport works.

MCP and the Future of AI Tooling

MCP is still evolving. Here are the directions that seem most likely based on current development and community demand:

  • Authentication standards: Formal OAuth/OIDC integration for remote MCP servers, enabling secure multi-tenant deployments
  • Streaming responses: Better support for tools that return data incrementally (long-running queries, real-time feeds)
  • Server composition: Combining multiple simple servers into higher-level capabilities without writing new code
  • Marketplace dynamics: Paid MCP servers as a business model — premium tools with usage-based pricing
  • Model-specific optimizations: Servers that adapt their behavior based on which model is calling them (context window size, capability differences)

The bigger picture: MCP positions AI models as operating systems for tools. Just as an OS provides a standard interface for hardware (drivers), MCP provides a standard interface for AI capabilities. Applications don't need to know the details of every peripheral — they use the standard API. Models don't need to know the details of every external system — they use MCP.

Debugging MCP Connections

When your MCP server isn't working as expected, here's a systematic approach to debugging:

1. Check Server Startup

Run your server manually from the command line. Does it start without errors? Check stderr output for initialization messages. Common issue: missing environment variables or dependencies.

2. Verify Configuration

Double-check your mcp.json (or equivalent). Is the command path correct? Are args in the right format? Are required env vars defined? A single typo in the command path will silently fail.

3. Test with MCP Inspector

The MCP Inspector tool lets you connect to any server interactively, list its tools, and call them manually. This isolates whether the issue is in the server or the host application.

4. Check Transport Layer

For stdio servers: make sure nothing else is writing to stdout (only JSON-RPC messages belong there — use stderr for logs). For HTTP servers: verify the port isn't in use and CORS headers are correct.

5. Examine Tool Descriptions

If the model isn't calling your tool when expected, the description might be unclear. Try rephrasing it. If the model calls it with wrong parameters, your input schema descriptions need more detail.

Testing MCP Servers

A solid testing strategy for MCP servers covers three layers:

// Unit test: tool logic in isolation
describe("get_weather tool", () => {
  it("returns formatted weather data", async () => {
    const result = await getWeatherHandler({
      city: "London",
      units: "celsius",
    });
    expect(result.content[0].text).toContain("London");
    expect(result.content[0].type).toBe("text");
  });

  it("handles invalid city gracefully", async () => {
    const result = await getWeatherHandler({ city: "" });
    expect(result.isError).toBe(true);
  });
});

// Integration test: full MCP protocol
describe("weather server integration", () => {
  let client;

  beforeAll(async () => {
    const transport = new StdioClientTransport({
      command: "node",
      args: ["./weather-server.js"],
    });
    client = new Client({ name: "test", version: "1.0.0" });
    await client.connect(transport);
  });

  it("lists tools correctly", async () => {
    const { tools } = await client.listTools();
    expect(tools).toContainEqual(
      expect.objectContaining({ name: "get_weather" })
    );
  });

  it("calls tool and returns valid response", async () => {
    const result = await client.callTool({
      name: "get_weather",
      arguments: { city: "Tokyo" },
    });
    expect(result.content[0].type).toBe("text");
  });
});

Frequently Asked Questions

What is MCP (Model Context Protocol)?

MCP is an open standard created by Anthropic that defines how AI models connect to external tools, data sources, and systems. It provides a universal protocol so any AI host application can communicate with any compatible tool server — similar to how USB standardized hardware connections.

Who created MCP and is it open source?

MCP was created by Anthropic and released as an open standard in late 2024. The specification, SDKs, and reference implementations are all open source. Anyone can build MCP servers or clients without licensing restrictions.

How is MCP different from OpenAI function calling?

Function calling is a model-level feature where the LLM outputs structured tool invocations within a single API call. MCP is a communication protocol between applications. Function calling happens inside one request/response cycle; MCP defines how tools are discovered, described, and executed across separate processes. They work at different layers — you can use MCP to provide tools that the model invokes via function calling.

What transport protocols does MCP support?

MCP supports stdio (standard input/output) for local server processes, and HTTP with Server-Sent Events for remote servers. Both use JSON-RPC 2.0 as the message format. Custom transports (WebSocket, message queues) are also possible since the protocol is transport-agnostic.

Can I use MCP with GPT-4, Gemini, or other models?

Yes. MCP is model-agnostic. While Anthropic created it, the protocol works with any LLM that supports tool use. The host application translates between MCP tool descriptions and the model's native format. Kiro, for example, can use MCP servers regardless of which underlying model it uses.

How do I install an MCP server?

Most MCP servers are npm packages that you add to your host application's configuration. Typically you add an entry to your mcp.json (or equivalent config) specifying the command to run the server and any required environment variables. The host handles starting and managing the server process.

Is MCP secure? Can it access my data without permission?

MCP itself is just a protocol — security depends on implementation. Well-built host applications require user approval before executing tools, especially those with side effects. Servers run in separate processes with only the permissions you configure (via env vars and file system access). You control what servers can access.

What's the difference between MCP tools and MCP resources?

Tools are functions the model can call to perform actions (with potential side effects). Resources are read-only data the model can access for context. Tools are like POST endpoints; resources are like GET endpoints. The model typically needs user approval for tools but can read resources more freely.

Related Articles

Conclusion

MCP solves a real problem that was holding back AI tool ecosystems. Before it, every integration was a one-off. You'd build a GitHub connector for one platform and then rebuild it for another. That's not sustainable when the number of AI platforms and useful tools both grow rapidly.

The protocol itself is elegantly simple — JSON-RPC messages between a host and server processes, with a clean capability negotiation handshake. The complexity lives in the tools you build on top of it, not in the protocol itself. That's good design.

If you're building AI-powered applications, MCP is worth understanding even if you don't adopt it immediately. It represents where the industry is heading: standard protocols for AI capabilities, shared tooling ecosystems, and a clean separation between the model layer and the tool layer. The N×M problem is becoming N+M, and that makes the entire ecosystem grow faster.

Start by trying a few existing MCP servers with your preferred AI tool. Once you see the pattern, building your own server takes an afternoon. And once you've built one, you'll start seeing MCP opportunities everywhere — any API, database, or system your team interacts with is a candidate for an MCP server that makes your AI tools more capable.