All posts

#mcp#claude#python

How to Write an MCP Server: Connect Your Own Tool to Claude in 30 Lines of Python

Want Claude to reach your company's order system, database or internal API? A step-by-step guide to writing your own Model Context Protocol server and connecting it to Claude Desktop and Claude Code.

How to Write an MCP Server: Connect Your Own Tool to Claude in 30 Lines of Python
Contents 10

Claude knows a lot, but it doesn't know your company. It can't see which order is out for delivery, how many units are left in stock or what a customer bought last month. Copying that information into the chat every time is neither practical nor safe.

The Model Context Protocol (MCP) fills that gap. Released by Anthropic as an open standard in late 2024, MCP is a common language for connecting AI applications to external tools and data. In this post we'll write a small MCP server from scratch and connect it to Claude. By the end, when you ask Claude "where is order 12345?", it will get the answer from your own system.

In short:

  • MCP is like "USB-C" for AI apps: a server you write once works with every client that supports MCP.
  • An MCP server can offer three things: tools, resources and prompt templates.
  • With the official Python SDK, defining a tool is as easy as adding a decorator to a function.
  • You can connect the same server to Claude Desktop with a JSON setting and to Claude Code with one command.

What is MCP, and why do we need it?

Before MCP, every AI app had to write its own integration for every tool. Ten apps and ten tools meant a hundred separate integrations. MCP changes the equation: the tool owner writes an MCP server, the AI app becomes an MCP client, and the two talk over a shared protocol.

The architecture has three parts:

  • Host: the app the user interacts with, such as Claude Desktop, Claude Code or an IDE.
  • Client: the component inside the host that manages a one-to-one connection with each server.
  • Server: the program you write, which offers tools and data.

What can your server offer?

Building block What it does Example
Tools Functions the model can call Look up an order, create a record
Resources Data the model can read Product catalog, file contents
Prompts Ready-made prompt templates "Prepare the weekly sales report"

WebMCP, which lets websites offer tools to in-browser agents, is the same idea adapted for the web.

Setup

Start by installing the official Python SDK. You'll need Python 3.10 or later:

pip install "mcp[cli]"

Your first MCP server: order lookup

The example below simulates an e-commerce order system. In a real project you'd connect to your database or internal API instead of a dictionary.

# order_server.py
from mcp.server.fastmcp import FastMCP

mcp = FastMCP("orders")

ORDERS = {
    "12345": {"customer": "Jane D.", "status": "shipped", "tracking": "TR998877"},
    "12346": {"customer": "John K.", "status": "preparing", "tracking": None},
}

@mcp.tool()
def order_status(order_id: str) -> str:
    """Returns the current status and shipping tracking number of an order by its ID."""
    order = ORDERS.get(order_id)
    if order is None:
        return f"Order {order_id} was not found."
    tracking = order["tracking"] or "not yet available"
    return f"Status: {order['status']}, tracking number: {tracking}"

@mcp.tool()
def pending_orders() -> list[str]:
    """Lists the IDs of orders that haven't shipped yet."""
    return [oid for oid, o in ORDERS.items() if o["status"] != "shipped"]

@mcp.resource("catalog://products")
def product_catalog() -> str:
    """The list of products on sale."""
    return "Mug ($5), T-shirt ($15), Notebook ($3)"

if __name__ == "__main__":
    mcp.run()

That's it. Three things deserve attention:

  1. Docstrings matter a lot. Claude decides when to use a tool by looking at the function's name and description. Instead of "gets orders", write a clear description of what it returns and when to use it.
  2. Type hints become the schema. When you write order_id: str, the SDK automatically tells Claude the tool expects a text parameter.
  3. Return meaningful messages on errors. Returning a descriptive message when an order isn't found, rather than raising an exception, lets Claude give the user a proper answer.

Test it: MCP Inspector

Before connecting to Claude, test the server with the SDK's development mode:

mcp dev order_server.py

This opens the MCP Inspector in your browser. There you can list your server's tools, run them with parameters and see the response. You see what Claude will see, first.

Connecting to Claude Desktop

Claude Desktop reads local MCP servers from the claude_desktop_config.json file, which you can reach from the developer section of Claude Desktop's settings. Add this definition:

{
  "mcpServers": {
    "orders": {
      "command": "python",
      "args": ["/full/path/to/order_server.py"]
    }
  }
}

Use the full path for your system and restart Claude Desktop. Now when you ask Claude "where is my order 12345?", it will ask permission to call the order_status tool and answer from your own system.

Connecting to Claude Code

If you use Claude Code, it's even easier. One terminal command:

claude mcp add orders -- python /full/path/to/order_server.py

claude mcp list shows connected servers. Claude Code can now reach your order system while writing code; for example, ask it to "draft a reminder email template for pending orders" and it will work from real data. For general Claude Code usage, see our Claude Code guide.

Common mistakes

Printing to stdout. Local MCP servers talk to the client over standard input/output (stdio). If any part of your code writes to stdout with print(), the protocol messages get corrupted and the connection breaks. Send debug output to standard error with the logging module or print(..., file=sys.stderr).

Relative file paths. Claude Desktop may start your server from a different working directory. Use full paths in the config and in your code.

Vague tool descriptions. A description like "fetches data" leads Claude to use the tool at the wrong time, or not at all.

Too many tools. Putting dozens of tools in one server makes it harder for the model to choose the right one. Keep tools focused and merge ones that are very similar.

Security: how much power should Claude get?

Your MCP server means Claude can act on real systems on your behalf. That power needs care:

  • Least privilege: don't grant write access if read access is enough. Connect to the database with a read-only user.
  • Separate destructive actions: keep tools that delete, pay or send email separate, and make sure the client's approval mechanism is on.
  • Validate inputs: treat parameters from the model like input from a user. Write parameterized SQL.
  • Don't hardcode secrets: read API keys from environment variables. In Claude Desktop's config you can pass them to the server with the env field.
  • Don't install servers you don't trust: someone else's MCP server is a program running on your computer with your permissions.

Frequently asked questions

Does MCP only work with Claude?

No. MCP is an open standard supported by many AI apps and developer tools beyond Anthropic's. A server you write once works with any client that supports MCP.

Which languages besides Python can I use?

The official SDKs include TypeScript, Python, Java, Kotlin, C# and Go, among others. Picking the language your team already uses makes the most sense.

Local or remote server?

The example here is a local (stdio) server: it runs on your computer, for your use only. For servers a team or customers will use, MCP also supports remote servers over HTTP. Then authentication and authorization become mandatory.

Do I need AI expertise to write an MCP server?

No. Writing an MCP server is no different from writing a small API. You aren't training or tuning a model; you're only defining functions the model can call.

MCP is the cleanest way to bring AI together with your company's real data. If you want a secure MCP server or AI integration built for your systems, reach us through our enterprise software development page.

Sources

ShareLinkedInXWhatsApp
Need help with this?

If you would like to apply what this post covers to your own project, let’s look at it together.

Write to us
YE

Founder of EngerekTech. Builds web, mobile and enterprise software for businesses with Angular, Spring Boot and Flutter, and made the KPSS Düello and Kelime Kavanozu apps. On the blog he covers AI tools and software development as he uses them in his own projects.