AI · 9 min read ·
How to Build an MCP Server in Python (Step by Step)
MCP is how AI assistants plug into your business tools. Here is how an MCP server works, how to build one in Python, and how to run it safely in production.

The Model Context Protocol (MCP) is an open standard that lets AI applications — Claude, ChatGPT, Cursor, IDE agents — call tools and read data from other systems in a consistent way. Instead of writing a custom integration for every assistant, you write one MCP server and every MCP-compatible client can use it.
This guide explains what an MCP server actually is, when you need one instead of a normal API, and how to build one in Python — from a minimal "hello tool" to a server you can put in front of Shopify, Meta Ads or your database.
What is an MCP server?
An MCP server is a small program that exposes capabilities to an AI client over JSON-RPC 2.0. It advertises three kinds of things:
- Tools — functions the model can call, such as
get_order,create_discountorsearch_products. Each tool has a name, a description and a JSON Schema for its inputs. - Resources — read-only data the client can load into context, such as a file, a product catalogue or a report.
- Prompts — reusable prompt templates the user can pick from the client.
The client (for example Claude Desktop) connects to the server, asks what it offers, and lets the model decide when to call a tool. The conversation between them is a short, predictable sequence:
initialize— client and server exchange protocol versions and capabilities.tools/list— the client discovers the available tools and their schemas.tools/call— the model calls a tool with arguments; the server returns the result as content.
MCP server vs API: what's the difference?
An MCP server usually wraps an API — it doesn't replace it. Your Shopify or CRM API stays the source of truth; the MCP server translates it into a shape a language model can use safely.
| REST / GraphQL API | MCP server | |
|---|---|---|
| Consumer | Your code | An AI model through a client |
| Discovery | Read the docs | Self-describing: tools/list returns names, descriptions and schemas |
| Granularity | Every endpoint | A small set of task-level tools |
| Auth | API keys, OAuth | The server holds credentials; the model never sees them |
The practical rule: expose fewer, higher-level tools than your API has endpoints. A model does better with refund_order(order_id, reason) than with five raw endpoints it has to chain correctly.
Transports: stdio or HTTP?
MCP defines two standard transports:
- stdio — the client launches your server as a local process and talks over standard input/output. Ideal for desktop assistants and developer tools; no network exposure at all.
- Streamable HTTP — the server runs as a web service that many clients can reach. This is what you use for a shared, hosted server, and it is where authentication and rate limiting become mandatory.
Start with stdio while you design your tools. Move to HTTP when more than one person or agent needs the server.
Step 1 — A minimal MCP server in Python
The official Python SDK (pip install mcp) includes FastMCP, which turns type-hinted functions into tools:
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("store-tools")
@mcp.tool()
def order_status(order_id: str) -> str:
"""Return the fulfilment status of an order."""
# Call your real API here (Shopify, your OMS, a database…)
return f"Order {order_id}: shipped"
if __name__ == "__main__":
mcp.run() # stdio by default
The docstring becomes the tool description and the type hints become the input schema. Write descriptions for the model, not for humans: say what the tool does, when to use it and what it returns.
Step 2 — Understand what happens underneath
SDKs hide the protocol, but it is worth seeing once. Our open-source mcp-server-skeleton implements the handshake with the Python standard library only — no dependencies — so you can read exactly how initialize, tools/list and tools/call are handled over JSON-RPC and stdio. It is a useful reference when you debug a client that "doesn't see" your tools.
Step 3 — Test with MCP Inspector
Before connecting a real assistant, run the official inspector:
npx @modelcontextprotocol/inspector python server.py
It shows the capabilities your server advertises, lets you call each tool by hand and displays raw JSON-RPC messages. Most integration bugs — wrong schema, missing description, an exception swallowed as empty output — are obvious here.
Step 4 — Connect it to Claude Desktop
Add the server to Claude Desktop's configuration file (claude_desktop_config.json):
{
"mcpServers": {
"store-tools": {
"command": "python",
"args": ["C:/path/to/server.py"]
}
}
}
Restart the app and the tools appear in the conversation. Other clients (Cursor, VS Code agents, ChatGPT connectors) use the same idea with their own config format.
Step 5 — Design tools the model can't misuse
- Read before write. Ship read-only tools first; add write tools once you trust the behaviour.
- Validate every argument on the server. The model's JSON matches your schema most of the time, not always.
- Return compact, structured results. Ten relevant fields beat a 5,000-line API dump that fills the context window.
- Make destructive actions explicit — separate tools, confirmation parameters, and a human approval step for anything irreversible. We cover this in AI agent guardrails.
MCP server examples for business
These are the servers we see creating value first:
- E-commerce — order lookup, stock checks, product search and draft discounts on Shopify.
- Marketing — read-only Meta Ads and GA4 reporting, so a team can ask "which ad set had the best ROAS last week?"
- Operations — CRM search, ticket creation, internal knowledge-base lookup.
- Websites — exposing a store's own actions (
search_products,add_to_cart,check_inventory) to browsing agents. Our webmcpify project generates and validates that kind of tool schema from a site description.
From one server to many: MCP in production
Once a company has several MCP servers, the questions change: who may call which tool, where are credentials stored, and what happened when something went wrong? A common answer is a single managed endpoint in front of all connectors. Our mcp-cloud module shows the core of that pattern — a connector registry, per-connector permissions, call routing and an audit record for every tool call.
For hosted servers, add authentication (OAuth for user-level access), per-client rate limits, structured logging and a kill switch per tool.
Where to start
Pick one repetitive question your team asks a system every day, expose it as a single read-only tool, and measure how often it gets used. That is the fastest way to find out where MCP pays off. If you want help designing the tools or running them securely, see our AI agent development service.
Frequently asked questions
What language should I use to build an MCP server?
Official SDKs exist for Python, TypeScript, Java, Kotlin, C# and more. Python with FastMCP is the quickest way to start; TypeScript is common for servers that live next to a Node.js stack.
Is MCP only for Claude?
No. MCP is an open protocol supported by many AI clients and IDEs. A well-built server works with any MCP-compatible client.
Should an MCP server replace my API?
No. The MCP server sits in front of your existing API or database and exposes a small set of task-level tools designed for a model to use safely.
How do I secure a remote MCP server?
Use the Streamable HTTP transport behind authentication, keep credentials on the server, validate every argument, rate-limit clients, log every tool call and require human approval for destructive actions.


