Building AI agentsMiddleLesson 2017 min read

Writing your own MCP server

The Model Context Protocol lets any compatible app use your tools. Learn what a server exposes, how it is structured, and how to keep it to least privilege.

Lesson in motion

In 60 seconds

Writing your own MCP server

The Model Context Protocol lets any compatible app use your tools. Learn what a server exposes, how it is structured, and how to keep it to least privilege.

1/4
In simple words
A phone charger with a standard plug works with many phones. Before standard plugs, every phone needed its own charger. MCP is like a standard plug for AI tools: write your tool once, and many AI apps can plug into it.
The Model Context Protocol (MCP) is an open protocol for connecting AI applications to tools and data. An MCP server is a small program that offers capabilities. An MCP client, inside an AI app (a chat app, an IDE, your own agent), connects to servers and passes what they offer to the model. Messages use JSON-RPC.

What a server can expose

PrimitiveWhat it isWho usually decides to use itExample
ToolsFunctions the model can call, with a name, description and input schema.The model, inside the app's rules.get_bus_times(stop_id)
ResourcesData the app can read and add to context, identified by a URI.The app or the user.A file, a database record, a policy document.
PromptsReusable prompt templates the server offers.The user, often from a menu."Summarise this ticket for a manager".
Servers usually run in one of two ways: as a local process that talks over standard input and output (stdio), or as a remote service over HTTP. Local is simpler for personal tools. Remote needs proper authentication. Check the specification for the current transport details.

The structure of a small server

  1. 1

    Create the server

    Give it a name. The SDK handles the protocol messages for you.
  2. 2

    Register tools

    Each tool: a function, a clear description and typed parameters. The SDK builds the schema.
  3. 3

    Register resources and prompts

    Only if you need them. Many servers start with tools only.
  4. 4

    Run it

    Start it over stdio for a local app, or HTTP for a remote one.
  5. 5

    Connect a client

    Add the server to an MCP-capable app's settings and test each tool.
The official SDKs, including one for Python, are listed on modelcontextprotocol.io. The sketch below is written in the style of the Python SDK's high-level server helper. Treat it as illustrative: SDK names and imports change between versions, so copy the current quickstart from the official docs before you run anything.
bus_server.py: illustrative sketch of a tiny MCP server (check the official quickstart for exact API names)python
# Illustrative sketch. Install and API details: see https://modelcontextprotocol.io/
from mcp.server.fastmcp import FastMCP   # name may differ in your SDK version

server = FastMCP("city-bus-times")

TIMES = {"STOP-101": ["08:05", "08:25", "08:45"], "STOP-202": ["09:10", "09:40"]}

@server.tool()
def get_bus_times(stop_id: str) -> str:
    """Next departures for ONE bus stop. Use when the user gives a stop id
    like STOP-101. Read-only. Returns up to 3 times, or a clear error."""
    if stop_id not in TIMES:
        return "No stop " + stop_id + ". Stop ids look like STOP-101."
    return ", ".join(TIMES[stop_id][:3])

@server.resource("stops://list")
def list_stops() -> str:
    """All stop ids this server knows."""
    return "\n".join(sorted(TIMES))

if __name__ == "__main__":
    server.run()   # stdio by default in many versions; check the docs
Note
The code runs nothing dangerous: one read-only tool over a fixed table. That is a good first server. Add write tools only after the read side works well and you have thought about approval.

Least privilege for your server

  • Expose only what is needed. Do not wrap your whole API. Start with a few narrow tools.
  • Use the smallest credentials. If the server calls a database, give it a read-only account for read tools. Keep secrets in environment variables or a secrets manager, never in tool descriptions or results.
  • Check every input. Arguments come from a model that may have read malicious text. Validate like any public API: types, ranges, allowed ids, and the user's permissions.
  • Limit the file system and network. A file tool should only see one folder. A fetch tool should only reach allowed hosts.
  • Return small, clean results. Don't return secrets, internal stack traces or other users' data.
  • Version and review descriptions. Changing a tool description changes the model's behaviour. Treat it like a code change.
Watch out
The security side is covered in Hardening MCP servers and clients and Tool poisoning and rug pulls: authentication for remote servers, pinning versions, reviewing third-party servers, and why a server's descriptions must be trusted before a client loads them. Build with those lessons open next to you.
Try this. Name one small read-only tool from your own work that would be useful to an AI assistant, for example "look up a product's stock in our shop". Write its name, description and parameters as if for an MCP server.

Watch and read more

Lab

A design (and optionally a working version) of a small read-only MCP server with least-privilege notes.

~45 min

The problem

Design an MCP server for a college notice board. Do the paper part first; the coding part is optional.

  1. List two tools and one resource. For each tool: name, description with "use when", and typed parameters. Both tools must be read-only.
  2. Write a least-privilege table: what data the server can reach, with which credential, and what it can not do.
  3. Write three input checks and three error messages the model can act on.
  4. Optional: follow the Python quickstart on modelcontextprotocol.io to build it with fake data, and test it with the project's inspector tool or an MCP-capable app.
Starter codetext
Server name: college-notices

Tool 1: name | description (use when / do not use for) | parameters | read or write
Tool 2: ...
Resource: uri | what it returns

Least privilege:
  data it can reach:
  credential used:
  can NOT do:

Input checks:
Error messages:

You are done when

Hard questions

Try to answer before you reveal. If you can answer these, you understood the lesson.

Q1Later, the college wants a <code>post_notice</code> write tool. What would you add before shipping it?Reveal

A separate, narrower credential that can only create notices; a confirmation step shown to a person with the exact text before posting; checks on length and content; an idempotency key so retries do not post twice; a log of who asked and what was posted; and an easy way to remove a notice. Consider putting the write tool in a separate server so read-only users never load it.

Q2Why is changing a tool's description a security-relevant change, even if the code does not change?Reveal

The model decides what to do partly from descriptions. A changed description can make the model call a tool in new situations, pass different data, or follow hidden instructions. That is how "rug pull" attacks work with third-party servers. So descriptions should be reviewed, versioned and, for third-party servers, pinned.

Please sign in to continue.

Questions people ask

Do I need MCP to give tools to my own agent?

No. If one agent in one program uses the tools, plain function calling in your own loop is simpler. MCP helps when you want the same tools to work in several AI apps, or want others to use your tools without writing custom integration code.

What is the difference between a tool and a resource?

A tool is an action the model chooses to call, with arguments. A resource is data that the app or user chooses to add to the context, identified by a URI. If the model should decide when to fetch something, make it a tool.

How do I test an MCP server without an AI app?

The MCP project provides developer tools for this, such as an inspector that lets you connect to a server, list its tools and call them by hand. Check the official site for the current tools. Also write normal unit tests for the functions behind each tool.

Can a remote MCP server see my files?

Only what the client sends it. But a server's tool results and descriptions go into the model's context, so a malicious server can try to influence the model. Only connect servers you trust, and give each one the smallest access it needs.

Lesson test

5 questions. Get 3 right (60%) to pass and complete this lesson.

Sign in to take the test and save your progress