What an MCP Server Is and Why You Would Build One
An MCP server (Model Context Protocol server) is a program that connects AI assistants like Claude to tools, data sources, or services outside the AI itself. Instead of the AI having built-in knowledge of how to do something, an MCP server acts as a bridge — it receives requests from the AI, performs an action (like querying a database, reading a file, or calling an API), and sends the result back.
You build an MCP server when you want Claude or another AI assistant to interact with something specific to your work: your company's internal database, a custom tool you wrote, files on your computer, or a service that isn't publicly available. The server does the actual work; the AI decides when to ask for it.
This is different from just giving Claude instructions. An MCP server is a real program running on your machine or a server, with defined inputs and outputs, so the AI can call it reliably and repeatedly.
Key Takeaways
- An MCP server is a program that runs on your computer or a server and lets Claude or other AI assistants request specific actions, like reading files or querying databases.
- You write an MCP server in Python, JavaScript, or another language, define what actions it can perform, and the AI learns to call those actions when needed.
- The simplest MCP servers use the standard library and require no external dependencies, making them fast to build and deploy.
- You connect an MCP server to Claude through a configuration file that tells Claude where the server is running and what it can do.
- Testing your server with a straightforward client script before connecting it to Claude catches errors early and saves debugging time.
The Basic Structure of an MCP Server
An MCP server has three parts: a way to receive requests, logic that handles those requests, and a way to send responses back. The requests come over standard input (stdin) and responses go back over standard output (stdout), or the server listens on a network port.
The simplest approach is stdio transport: Claude's client sends JSON messages to your server's stdin, your server reads them, does work, and writes JSON responses to stdout. This works on any machine where your server can run, and Claude's client handles all the connection details.
A more complex approach is SSE transport (Server-Sent Events), where your server listens on a network port and Claude's client connects to it like a web service. This is useful if your server needs to run on a different machine or be accessible from multiple clients.
For a first MCP server, stdio transport is easier. You write a program that reads from stdin, parses JSON, does something, and writes JSON back to stdout. That's the whole pattern.
Writing Your First MCP Server in Python
Start with a Python script that reads JSON from stdin, handles a single straightforward request, and writes JSON back. Here is a working example that responds to a request to add two numbers:
Create a file called simple_server.py:
import json import sys def handle_request(request): method = request.get("method") params = request.get("params", {}) if method == "add": a = params.get("a", 0) b = params.get("b", 0) return {"result": a + b} return {"error": "Unknown method"} while True: line = sys.stdin.readline() if not line: break request = json.loads(line) response = handle_request(request) print(json.dumps(response)) sys.stdout.flush()
Run this with python simple_server.py. It will wait for input. Type a JSON request like {"method": "add", "params": {"a": 5, "b": 3}}, press Enter, and it will print {"result": 8}.
This is the core pattern: read JSON, decide what to do based on the method, do it, write JSON back. Real MCP servers add error handling, logging, and more methods, but the structure stays the same.
Defining What Your Server Can Do
Claude needs to know what methods your server supports and what parameters each one takes. You define this in a tools list — a JSON structure that describes each action your server can perform.
For the add example above, the tools list would be:
{ "tools": [ { "name": "add", "description": "Add two numbers together", "inputSchema": { "type": "object", "properties": { "a": {"type": "number", "description": "First number"}, "b": {"type": "number", "description": "Second number"} }, "required": ["a", "b"] } } ] }
The inputSchema uses JSON Schema format, which Claude understands. It tells Claude what parameters the method accepts, what type each one is, and which ones are required. Claude uses this to build the right request when it decides to call your tool.
Your server should send this tools list when Claude first connects, so Claude knows what it can ask for. The exact format depends on the MCP protocol version, but the idea is always the same: describe your capabilities in a standard format.
Testing Your Server Before Connecting It to Claude
Before you connect your server to Claude, write a straightforward test client that sends requests and checks responses. This catches bugs in your server logic before Claude tries to use it.
Create a file called test_client.py:
import subprocess import json process = subprocess.Popen( ["python", "simple_server.py"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True ) request = {"method": "add", "params": {"a": 10, "b": 20}} process.stdin.write(json.dumps(request) + "\n") process.stdin.flush() response = process.stdout.readline() result = json.loads(response) print(f"Request: {request}") print(f"Response: {result}") assert result["result"] == 30, "Expected 30, got " + str(result["result"]) print("Test passed!")
Run this with python test_client.py. It starts your server, sends a request, reads the response, and checks that the answer is correct. If your server has a bug, you will see it here instead of when Claude tries to use it.
Add more test cases for edge cases: what happens if a parameter is missing, what if it is the wrong type, what if the method doesn't exist. Test these now so your server handles them gracefully.
Connecting Your Server to Claude
Claude's desktop client (Claude.app on Mac or Windows) reads a configuration file that tells it where to find your MCP servers. The file is usually at ~/.claude/claude_desktop_config.json on Mac or %APPDATA%\Claude\claude_desktop_config.json on Windows.
Add your server to the config like this:
{ "mcpServers": { "my_math_server": { "command": "python", "args": ["/path/to/simple_server.py"] } } }
Replace /path/to/simple_server.py with the full path to your server script. Save the file, then restart Claude.app. Claude will start your server in the background and show you in the interface that the server is connected.
If the server fails to start, Claude will show an error. Check that the path is correct, that the script runs without errors when you test it manually, and that all dependencies are installed.
Common Patterns for Real MCP Servers
Most MCP servers do one of a few things: read and write files, query a database, call an external API, or run a command on your machine. Here are the patterns for each.
File operations: Your server reads a file, processes it, and returns the result. For example, a server that reads a CSV file and returns rows matching a search term. Use Python's built-in open() and csv module — no external dependencies needed.
Database queries: Your server connects to a database (SQLite, PostgreSQL, MySQL) and runs a query. Use the database's Python driver (sqlite3 is built in, psycopg2 for PostgreSQL). Define tools for common queries: "get user by ID", "list all orders", "count records". Never let Claude write arbitrary SQL — define specific, safe queries and let Claude choose which one to run.
API calls: Your server calls an external API (like a weather service or your company's internal API) and returns the result. Use Python's built-in urllib or the requests library. Handle errors gracefully — if the API is down or returns an error, your server should return a clear error message, not crash.
System commands: Your server runs a command on your machine (like git status or ls) and returns the output. Use subprocess.run() and be careful about security — only allow specific commands, never let Claude run arbitrary shell commands.
Frequently Asked Questions
Do I need to know JavaScript or just Python?
You can write MCP servers in Python, JavaScript (Node.js), or any language that can read stdin and write stdout. Python is simpler for beginners because it has fewer setup steps. JavaScript is common because Node.js is widely installed. Pick whichever you know better.
What if my server crashes or hangs?
Claude will show an error in the interface and stop trying to use that server. Check your server's output (Claude usually logs it) to see what went wrong. Add try-catch blocks around risky code and always send a response, even if it's an error message. Never let your server hang waiting for input that never comes.
Can my MCP server talk to other services on the internet?
Yes. Your server can call APIs, connect to databases, or reach any service your machine can reach. Be careful with credentials — don't hardcode API keys in your server code. Use environment variables or a config file that you don't commit to version control.
How do I update my server without restarting Claude?
You have to restart Claude.app. It starts your server when it launches and keeps it running. If you change your server code, close Claude, make your changes, and open Claude again. For development, you might want to write a wrapper script that reloads your server code automatically, but that's advanced.
What's the difference between an MCP server and a regular API?
An MCP server is designed specifically for Claude to call — it uses the MCP protocol and runs locally or on a machine you control. A regular API is a web service that anyone can call over the internet. An MCP server is simpler to set up for personal use, but a regular API is better if multiple people or services need to use it.