TL;DR: An MCP server is a small program that gives Claude access to a specific tool or data source, and a basic one can be running in under an hour. This guide builds one from scratch in Python, connects it to both Claude Desktop and Claude Code, and covers the plugin that lets Claude build it for you instead.
There are more than 10,000 public MCP servers running right now, and Anthropic recently handed the protocol's governance over to a vendor-neutral foundation under the Linux Foundation. Model Context Protocol has moved fast since Anthropic introduced it in late 2024, and building your own server is one of the more approachable pieces of the AI-agent stack. You write a small Python (or TypeScript) script, expose one or two functions as "tools," and Claude can call them mid-conversation. This guide builds a real one, connects it to both Claude Desktop and Claude Code, and covers the official Claude Code plugin that builds it for you if you'd rather skip the code entirely.
What Is an MCP Server?
An MCP server is a small program that exposes specific tools, data, or prompts to an AI model like Claude through a standard interface called the Model Context Protocol. Claude can call those tools mid-conversation instead of you copying information back and forth by hand.
Think of it less as a chatbot or a plugin-marketplace listing, and more as a small API wrapped in a format Claude already knows how to speak. Anthropic open-sourced the protocol in November 2024, and adoption moved quickly: MCP now runs across ChatGPT, Cursor, Gemini, Microsoft Copilot, and Visual Studio Code, not just Claude. A server can offer three things: tools (functions Claude can call), resources (data Claude can read), and prompts (templates Claude can reuse). Most beginner servers, including the one you'll build here, start with a single tool. In practice, that looks like this: you ask Claude something related to what your tool does, Claude recognizes the match, runs your function in the background, and folds the result into its answer, no copy-pasting required.
"More than 10,000 public MCP servers already exist, and Anthropic no longer even owns the protocol's governance."
Do You Need to Know Python or TypeScript?
Yes, for the manual path: you'll want basic comfort with Python or TypeScript syntax, functions, and running a script from a terminal. If that's not where you are yet, skip ahead to the plugin section, which builds a server without you writing the logic by hand.
MCP servers are ordinary code first, protocol second. The FastMCP framework for Python and the official TypeScript SDK both handle the protocol plumbing, so you're mostly writing a function, adding a decorator, and describing what it does in plain English. If you've written a script that calls an API before, you already have most of what you need. If you haven't, the code in this guide is simple enough to follow and adapt, but it's not the place to learn programming from scratch. 5 Best Anthropic Courses in 2026 rounds up the paid programs verified students rated highest, not the ones creators pitch, including one built specifically around Claude Code for non-technical builders. That will get you further, faster, than piecing syntax together from scattered docs.
Build Your Own vs. Use One That Already Exists
Building your own only makes sense if you need a tool that doesn't exist yet or want to learn the protocol firsthand. For everything else, there's likely already a server for it: more than 10,000 public MCP servers exist, and Claude's own connectors directory lists hundreds of pre-built, Anthropic-reviewed options, with new ones added most weeks.
Check two places before you write a line of code. Claude's connectors directory covers popular services like Notion, GitHub, and Slack with servers Anthropic has already reviewed. The community-run MCP Registry covers a much wider, less curated range. If your use case is genuinely custom, an internal tool, a niche API, a workflow specific to your team, building is the only option, and it's a good way to actually understand how the protocol works instead of treating it as a black box.
We pulled the five figures below from two separate Anthropic posts released 13 months apart: the original MCP launch and the December 2025 foundation donation plus Anthropic's connectors directory docs. No single page lists all five together. Verified July 2026.
📊 DATA TABLE: Model Context Protocol Where Things Stand
| Data Point | Value | Source |
|---|---|---|
| MCP introduced by Anthropic | November 25, 2024 | Anthropic |
| Active public MCP servers | 10,000+ | MCP Registry blog |
| Monthly SDK downloads (Python + TypeScript) | 97M+ | MCP Registry blog |
| Connectors in Claude's own directory | Hundreds, updated weekly | Claude docs |
| Governance | Agentic AI Foundation (Linux Foundation), since Dec 9, 2025 | Anthropic |
Swipe sideways to see all columns
Don't build if a server already exists for what you need check Claude's directory and the MCP Registry first. Build if your use case is custom, or if you want to actually understand the protocol.
Before You Start What You Need
You need Claude Desktop or Claude Code installed, a terminal, and about 30–45 minutes for the manual path (the plugin path later in this guide takes closer to 10). No prior MCP experience required.
Beyond that, the list is short: Python 3.10+ (or Node.js 1.8+ if you'd rather use TypeScript), a code editor, and the uv package manager, which the official SDK now assumes by default. You don't need a server, a domain, or any hosting; a local server only talks to Claude on your own machine. Everything in the next two steps runs entirely on your laptop.
Step 1: Set Up Your Environment Create a project folder, set up a Python virtual environment, and install the two packages you need: the MCP SDK and a small HTTP library. uv init mcp-github-infocd mcp-github-infouv venvsource .venv/bin/activateuv add "mcp[cli]" httpxtouch server.py On Windows, activate with .venv\Scripts\activate instead of the source command above. If uv isn't installed yet, grab it from astral.sh/uv first it's a one-line install and the same tool the official SDK docs now recommend. Step 2: Write Your First MCP Tool You'll write one function, get_repo_info, that fetches basic details about a public GitHub repository and hand it to Claude through a single decorator. from mcp.server.fastmcp import FastMCPimport httpxmcp = FastMCP("github-info")@mcp.tool()async def get_repo_info(owner: str, repo: str) -> str: """ Get basic info about a public GitHub repository. Args: owner: The GitHub username or org (e.g. "anthropics") repo: The repository name (e.g. "claude-code") """ url = f"https://api.github.com/repos/{owner}/{repo}" async with httpx.AsyncClient() as client: try: response = await client.get(url, timeout=10.0) response.raise_for_status() data = response.json() except httpx.HTTPStatusError: return f"Couldn't find {owner}/{repo}. Check the spelling." except Exception as e: return f"Error reaching GitHub: {str(e)}" return ( f"{data['full_name']}: {data['description'] or 'No description.'}\n" f"Stars: {data['stargazers_count']} | Language: {data['language']}\n" f"URL: {data['html_url']}" )if name == "main": mcp.run(transport="stdio") The @mcp.tool() decorator does the actual work of turning a normal async function into something Claude can call. FastMCP reads the type hints (owner: str, repo: str) and the docstring to figure out what arguments the tool needs and when to use it, so the docstring isn't just a comment here it's what Claude reads to decide whether this tool is relevant to your question. Skip it, or leave it vague, and Claude will either ignore the tool or call it wrong. "The docstring isn't just a comment here, it's what Claude reads to decide whether this tool is relevant to your question." The error handling matters more than it looks. A tool that crashes on a typo or a dropped connection leaves Claude guessing at what went wrong instead of reading a clear message it can relay to you. Catching HTTPStatusError separately from a generic exception is what makes that possible. Before wiring this into Claude at all, it's worth checking that the server itself works. Run npx @modelcontextprotocol/inspector uv run server.py from the project folder, and a browser-based tool opens where you can call get_repo_info directly and see the raw output. It's the fastest way to tell a bug in your code apart from a bug in your Claude config, and it saves a lot of restart-and-guess cycles later.
Step 3: Connect It to Claude Claude Desktop and Claude Code both read local MCP servers from a config file, though the file and the exact steps differ slightly between them. Claude Desktop Open (or create) ~/Library/Application Support/Claude/claude_desktop_config.json on macOS, or %AppData%\Claude\claude_desktop_config.json on Windows, and add: { "mcpServers": { "github-info": { "command": "uv", "args": ["--directory", "/absolute/path/to/mcp-github-info", "run", "server.py"] } }} Replace the path with the actual folder from Step 1 run pwd in that folder if you're not sure. Fully quit Claude Desktop (not just close the window) and reopen it. The tool shows up under the connectors icon, where you can toggle it on. Claude Code From any project, run: claude mcp add --transport stdio github-info -- uv --directory /absolute/path/to/mcp-github-info run server.py Run claude mcp list to confirm it shows as connected, then just ask: "What's the star count on anthropics/claude-code?" Claude finds the tool and calls it on its own.
The Fast Path: Let Claude Build It for You
Claude Code ships an official plugin that scaffolds an MCP server for you: it asks about your use case in plain English and writes the working code itself.
/plugin install mcp-server-dev@claude-plugins-official/mcp-server-dev:build-mcp-server
Run the first command once, then the second inside any Claude Code session. Claude asks what you want the server to do, whether it needs to run locally or as a remote HTTP service, and builds it from there. It's a genuinely fast way to end up with something working if you'd rather describe a tool than type one out, and it's a solid way to see a second, well-built example even if you did write the GitHub tool by hand yourself.
The plugin isn't a shortcut that skips real work; it produces the same shape of code you'd write by hand, generated by the tool that reads MCP's own specification most closely.
Manual Build vs. the Plugin
| Category | Manual (Steps 1–3) | Plugin |
|---|---|---|
| Time | 30–45 minutes | 5–10 minutes |
| Coding required | Yes, basic Python or TypeScript | No, a plain-English description |
| What you learn | How the protocol actually works | How to use the tool, not the internals |
| Best for | Your first server, or anything custom | Fast iteration, or skipping the syntax entirely |
Swipe sideways to see all columns
The plugin gets you a working server in minutes and writes real code you can still read and edit. Use the manual steps for your first server if you want to learn the pattern, then use the plugin for everything after that.
What to Expect After Your First Server Works
Your first server will probably need a restart or two before Claude picks it up, and that's normal, not a sign you did something wrong.
Claude Desktop and Claude Code both load the server list at startup, so a change to your code or your config needs a full restart to take effect, not just a new message. Once it's running, treat it like any other script: add tools as you need them, keep functions focused on one job each, and split into a second server if you find yourself covering an unrelated domain. Expect to add a second tool before you add a tenth. Most people's first real use case shows up once they've used the toy example for a day or two and start thinking about what else they wish Claude could just do for them.
Common Pitfalls and How to Avoid Them
Most first-server problems come down to three things: a path that isn't absolute, a JSON syntax error, or forgetting to fully quit Claude Desktop before restarting it.
Relative paths are the most common failure. ./mcp-github-info might work when you test the script directly, but Claude Desktop doesn't launch from your project folder, so it needs the full path every time. Run pwd and copy the output rather than typing it from memory.
JSON is unforgiving about trailing commas and matching brackets. If Claude Desktop doesn't show your server at all after a restart, check ~/Library/Logs/Claude/mcp.log (or the Windows equivalent) before assuming the code is broken the config file is a more common culprit.
And closing the window is not the same as quitting the app. On macOS, use Cmd+Q; on Windows, right-click the icon in the system tray and choose Quit. Claude Desktop only rereads its config on a full restart.
"Closing the window is not the same as quitting the app, and Claude Desktop only rereads its config on a full restart."
One more: if uv isn't in Claude Desktop's PATH, it may not find the command at all even though it works fine in your terminal. Using the full path to uv (find it with which uv on macOS or Linux) in the config's command field fixes this without changing anything else.
Almost every "my server won't show up" problem is a path, a restart, or a JSON comma, not a deep bug. Check those three before anything else.