Skip to content
Agentic AI
Agentic AI8 min read0 views

Build Your First MCP Server: A Step-by-Step Guide

A hands-on walkthrough to build an MCP server and connect it to Claude Code — from scaffold and tool registration to your first real tool call.

Reading the MCP spec gives you the map. Building a server gives you the territory. The fastest way to understand Model Context Protocol is to stand up a tiny server, connect it to Claude Code, and watch the model call a function you wrote five minutes ago. This walkthrough takes you from an empty directory to a working tool call, and along the way it points out the spots where first-timers stumble.

We will build a small "order lookup" server that exposes one tool: given an order ID, return its status from a stand-in data store. It is deliberately minimal so the protocol mechanics stay visible, but the shape generalizes directly to a real backend.

Decide what your server does before you write it

Model Context Protocol is an open standard that connects Claude to external systems through servers exposing tools, resources, and prompts. The most common early mistake is to start coding before deciding which of those three you actually need. For an order lookup, you want a tool: the model takes an action — querying by ID — and gets a structured result back. If instead you wanted Claude to always have a product catalog in context, that would be a resource. Naming this up front saves you from building the wrong primitive.

Pin down the tool's contract on paper first. Name: get_order_status. Input: an order_id string. Output: a small object with status, last update, and carrier. Write the description as if explaining to a junior engineer who has never seen your system — Claude reads that description to decide when to call the tool, so vagueness here causes the model to call it at the wrong time or skip it entirely.

Scaffold the project and install the SDK

Create a directory and initialize a project. The MCP maintainers ship SDKs in several languages; the Python and TypeScript SDKs are the most common starting points. Install the SDK, create a single entry-point file, and you have everything you need — no framework, no boilerplate beyond imports. The server is just a program that speaks the protocol over a transport.

For local development, use the stdio transport. It runs your server as a child process of the host and exchanges messages over standard input and output, which means no ports, no network, and no authentication to configure. This is the right choice for a first server: you eliminate every variable except the protocol itself. You can graduate to streamable HTTP later when you need a remote, multi-user deployment.

Hear it before you finish reading

Talk to a live CallSphere AI voice agent in your browser — 60 seconds, no signup.

Try Live Demo →
flowchart TD
  A["Define tool contract"] --> B["Scaffold project + install SDK"]
  B --> C["Register get_order_status tool"]
  C --> D["Run server on stdio"]
  D --> E["Add to Claude Code config"]
  E --> F{"Tool appears in /mcp?"}
  F -->|No| G["Check command path & logs"]
  F -->|Yes| H["Ask Claude to look up an order"]
  G --> E

Register the tool

Registering a tool means giving the SDK three things: a name, a description, and an input schema. The schema is JSON Schema, and it is not optional decoration — it is how Claude knows that order_id is a required string rather than a number, and the host validates arguments against it before your handler ever runs. Be specific: mark the field required, give it a description, and if a field has a fixed set of values, express that as an enum so the model cannot pass garbage.

Then write the handler. It receives the validated arguments and returns content. For our example, it looks up the order in a dictionary and returns a text block describing the status. In a real server this is where you would query Postgres or call an internal API. Keep the handler's return shape clean — return structured content the model can read, and on failure return an error the model can reason about rather than throwing an opaque exception that the host surfaces as a dead end.

A subtle but important point: the handler should be idempotent for read operations and explicit about side effects for writes. get_order_status is a pure read, so calling it twice is harmless. If you later add cancel_order, you want to think hard about what happens when the model retries — but for a read-only first tool, you are safe.

Run it and connect to Claude Code

Start the server. On stdio it will sit quietly waiting for a host to speak to it — if you run it standalone and nothing happens, that is correct, not a bug. The server only comes alive when a client initializes a session against it.

Now register it with Claude Code. Add an entry to your MCP configuration that tells the host how to launch your server: the command to run and any arguments. When Claude Code starts, it will spawn your server as a client, perform the initialize handshake, and call tools/list to discover get_order_status. Run the /mcp command in Claude Code to confirm the server connected and the tool is listed. If it is not there, the culprit is almost always the launch command — a wrong path or a missing interpreter — so check that the exact command in your config runs your server from a clean shell.

Watch the first tool call happen

With the server connected, ask Claude something that requires it: "What's the status of order A-1043?" Claude reads the tool description, recognizes it as relevant, and emits a tool-use request with the order ID. The host routes it to your client, your handler runs, and the result flows back into the conversation. Claude then phrases a natural answer using the structured data you returned. The first time you see this loop close, the whole protocol clicks: you wrote a function, and the model called it because a schema and a sentence of description told it when to.

If Claude answers without calling the tool, your description is too weak — sharpen it so the trigger condition is unmistakable. If it calls the tool with a malformed ID, tighten the schema. These two levers, description and schema, are where you will spend most of your tuning time, and they are worth tuning because they are what the model actually reads.

Still reading? Stop comparing — try CallSphere live.

CallSphere ships complete AI voice agents per industry — 14 tools for healthcare, 10 agents for real estate, 4 specialists for salons. See how it actually handles a call before you book a demo.

Hardening before you ship

A toy server becomes a production server by adding three things. First, real error handling: catch failures in the handler and return a structured error message the model can act on, like "order not found," instead of crashing. Second, input validation beyond the schema — check that the order ID matches your real format before hitting the database. Third, observability: log every tool call with its arguments and outcome, because when an agent does something surprising in production, that log is the only way to reconstruct what happened.

When you outgrow stdio — multiple users, a hosted deployment — migrate to streamable HTTP and add authentication. But resist doing that on day one. Get the read-only stdio server working first; every concept you learned here carries forward unchanged, and you will debug the hard parts without auth and networking obscuring them.

Frequently asked questions

Do I need a framework to build an MCP server?

No. An MCP server is an ordinary program that speaks the protocol over a transport, and the official SDKs handle the protocol details. You import the SDK, register your tools, and run it. There is no web framework, router, or heavy scaffolding required for a basic server.

Why isn't my tool showing up in Claude Code?

Almost always the launch command in your MCP config is wrong — a relative path, a missing interpreter, or a typo. Run the exact command from your config in a fresh terminal; if the server does not start cleanly there, the host cannot start it either. Checking the host's MCP logs will show the spawn error.

Should my first server use stdio or HTTP?

stdio. It runs your server as a local subprocess with no ports and no authentication, which removes every variable except the protocol itself. Move to streamable HTTP only when you need a remote, multi-user deployment, since that introduces auth and networking concerns you do not want to debug on day one.

How does Claude know when to call my tool?

From the tool's name, description, and input schema, all delivered at runtime during the handshake. The description in particular is what the model reasons over to decide relevance, so writing it precisely — explaining exactly what the tool does and when to use it — is the single highest-leverage thing you can do.

Bringing agentic AI to your phone lines

The same build-a-tool, connect-the-host loop you just walked powers voice and chat agents at CallSphere — assistants that call your systems mid-conversation and book work 24/7. See a live agent doing it at callsphere.ai.


Source & attribution: This is an independent, original explainer inspired by Anthropic's coverage on the Claude blog. Claude, Claude Code, Claude Cowork, Claude Opus, and the Model Context Protocol are products and trademarks of Anthropic. CallSphere is not affiliated with or endorsed by Anthropic.

Share

Try CallSphere AI Voice Agents

See how AI voice agents work for your industry. Live demo available -- no signup required.