An MCP server is a small program that gives an AI assistant a set of tools it can call — read this database, search these documents, create a ticket in this system. MCP, the Model Context Protocol, is the standard that defines how the assistant discovers those tools and calls them. Any assistant that speaks MCP can use any MCP server, which is why the same server works in Claude Code, Cursor, VS Code and a growing list of others.
The problem it solves#
A language model on its own can only produce text. To be useful with your systems it needs to call things: run a query, fetch a page, read a file. Every assistant used to define its own way of describing and invoking those tools, so an integration written for one was useless in another.
MCP is a shared protocol for that. Think of it the way USB standardised device connections: the assistant is the computer, the server is the device, and the protocol means they do not need to know about each other in advance.
The pieces#
| Term | Meaning |
|---|---|
| Host | The application you are talking to: Claude Code, Cursor, a chat app |
| Client | The part of the host that speaks MCP to one server |
| Server | Your program, exposing tools over MCP |
| Tool | A function the model may call, with a name, description and typed parameters |
| Resource | Data the model may read, addressed by a URI: a file, a record, a page |
| Prompt | A reusable template the server offers, for common tasks |
Tools are the part almost everyone starts with. A server that only exposes tools is a complete, useful server.
How a call flows#
- The host starts your server (as a local process, or connects to it over HTTP) and asks what it offers. The server replies with its tools, each with a description and a JSON schema for the arguments.
- Those descriptions are placed in the model’s context, so it knows the tools exist.
- You ask “how many orders shipped yesterday?” The model decides a tool fits, and produces a structured call: tool name plus arguments.
- The host sends that call to your server. Your code runs, and returns a result.
- The result goes back into the context, and the model writes its answer using it.
The model never runs your code and never sees your credentials; it produces a request, and your server decides what to do with it. That separation is the whole security model, and it is also why the tool descriptions matter so much: they are the only thing the model knows about what a tool does.
A server in thirty lines#
from mcp.server.fastmcp import FastMCP
import sqlite3
mcp = FastMCP("orders")
@mcp.tool()
def orders_shipped_on(date: str) -> int:
"""Count orders with status 'shipped' on the given date (YYYY-MM-DD)."""
conn = sqlite3.connect("shop.db")
row = conn.execute(
"SELECT COUNT(*) FROM orders WHERE status = 'shipped' AND shipped_on = ?",
(date,),
).fetchone()
conn.close()
return row[0]
@mcp.tool()
def find_order(order_id: int) -> dict:
"""Return the customer, total and status for one order id."""
conn = sqlite3.connect("shop.db")
row = conn.execute(
"SELECT customer, total, status FROM orders WHERE id = ?", (order_id,)
).fetchone()
conn.close()
if row is None:
return {"error": "no such order"}
return {"customer": row[0], "total": row[1], "status": row[2]}
if __name__ == "__main__":
mcp.run()
Type hints become the argument schema; the docstring becomes the description the model reads. That is the entire server. Install the SDK with pip install "mcp[cli]", and the same shape exists for TypeScript.
Connecting it#
Each host has a configuration file listing servers. For a local server started as a process, the entry says how to run it:
{
"mcpServers": {
"orders": {
"command": "python",
"args": ["/path/to/orders_server.py"]
}
}
}
Claude Code adds servers with a command (claude mcp add); Cursor and VS Code have a settings entry with the same shape. Restart or reload, and the tools appear. Ask “which orders shipped on 2026-09-01?” and watch the call happen.
Remote servers use HTTP instead of a local process, with the same protocol; the configuration gives a URL rather than a command.
What makes a good tool#
- A precise description. “Count shipped orders for a date” beats “orders tool”. The model chooses tools by reading these.
- Narrow, typed parameters. A date string with a stated format, not a free-text query. Ambiguity in the schema becomes wrong calls.
- Small results. Everything returned goes into the context window. Return the ten rows that matter, not the table.
- Errors as data. Return a clear error message; do not crash. The model can recover from “no such order” and cannot from a stack trace.
Where MCP is used#
- Giving coding assistants access to a project’s database, issue tracker, or documentation.
- Letting a chat assistant read internal files or search a knowledge base.
- Connecting automation platforms to models without custom glue per tool.
- Exposing a company’s own systems to whichever assistant employees use.
Questions people ask#
Is MCP tied to one company’s models?
No. It was published as an open standard and is supported by assistants and tools from many vendors. A server does not know or care which model is calling it.
Do I need to know the protocol details?
Not to build a server; the SDKs handle the messaging. It is JSON-RPC over standard input and output for local servers, or HTTP for remote ones, if you are curious.
Is it the same as function calling?
Function calling is the model’s ability to produce a structured call. MCP is the standard for describing, discovering and executing those calls across hosts. MCP uses function calling underneath.
Can a server ask the model questions?
Yes; the protocol includes a way for a server to request a completion from the host’s model. It is an advanced feature and most servers never need it.
Where to go next#
- Build a simple AI agent in Python — the loop that calls tools.
- Claude Code not working — including MCP configuration problems.
- What is an API? — the thing most servers wrap.