What Is an MCP Server? A Plain-English Guide for Indie Devs
What is an MCP server? It's a standard way to give AI agents discoverable tools for your app, explained with Shipyard's live server as the worked example.
An MCP server is a program that hands an AI agent a menu of things it can do, described in a format the agent can read and call on its own. That is the whole idea. If you have wondered what is an MCP server and why half your feed is suddenly running them, that is the one-sentence version: it turns your app's actions into tools an agent discovers and calls, instead of scraping your website or waiting for someone to hand-code an integration.
The problem it fixes is boring and real. Before MCP, giving an assistant access to your app meant one of two bad options. Teach it to click around your web UI, which is fragile and breaks on every redesign. Or write a bespoke integration for every assistant you wanted to support: Claude one way, Cursor another, ChatGPT a third. MCP (the Model Context Protocol, an open standard from Anthropic) is one protocol, so you build the tool surface once and every MCP-speaking client can use it.
I will use one example the whole way down: the server we run for Shipyard. It is live, it is small (eight tools), and I can show you exactly what it does rather than gesture at a diagram.
So, what is an MCP server, mechanically?
Three parts sit in the picture. The host is the AI application the person is using: Claude Code, Cursor, Claude Desktop, ChatGPT. Inside it runs a client, one per connected server, that handles the wire protocol. The server is your thing, the service that says "here are the tools I offer." They talk over JSON-RPC 2.0. That is it.
An MCP server can expose three kinds of thing: tools (actions that do something, like list_projects or ship_project), resources (data the agent can read), and prompts (reusable templates). Shipyard's server is all tools, so that is what I will focus on.
How it differs from a REST API (and a CLI)
This is the part people skate over, so here is the honest comparison. The difference is not the wire format. It is the caller and how the caller learns what is available.
A REST API's caller is a developer, or code a developer wrote. Discovery happens in advance, by a human reading your docs. You know GET /api/projects exists because you read that it does and then wrote a client that calls it.
A CLI's caller is a human at a terminal, or a script wrapping one. Discovery is --help. Same shape: a person reads the output, then types the command.
An MCP server's caller is the agent itself, and discovery happens at runtime. The client sends a tools/list request and gets back every tool's name, description, and a JSON schema for its arguments. The agent reads that and decides what to call. Nobody wrote a Shipyard client in advance.
Here is what that looks like against our server. An agent that wants the five most-liked projects sends:
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "list_projects",
"arguments": { "sort": "top", "limit": 5 }
}
}
The server answers with those projects as JSON. The agent knew list_projects existed, and that it takes sort and limit, because it asked tools/list first and read the schema back. That runtime discovery is the thing a REST API cannot do on its own.
One useful way to hold it: MCP does not replace your REST API, it sits on top. Your real logic stays where it is. Under the hood, Shipyard's REST endpoints and its MCP tools call the exact same service layer, the same functions the website runs. The tool is just a second front door built for a different kind of visitor.
What Shipyard's server actually exposes
Eight tools. Two of them, list_projects and get_project, work with no credentials at all, because an agent researching the feed ("what devtools shipped this week?") should not need a key to look. The other six write, so they need one: ship_project, add_review, like_project, unlike_project, wallet_balance, and fund_review_bounty.
Auth reuses the same personal API key as our REST API, passed as an Authorization: Bearer sk_live_… header. Connect without it and you still get in, just read-only. Call a write tool anonymously and you get a plain, actionable error pointing at the API-keys page, not a stack trace. That anonymous-reads, keyed-writes split is a design choice, and I think it is the right default for any public MCP server.
I will not re-run the setup here; the Shipyard MCP launch post covers connecting each client line by line. What I want you to notice is subtler. A tool is not just a function you exposed. Its description field and the server's instructions are text the model reads before it acts. Our add_review tool enforces a 20-character floor in code, but it also tells the agent, in writing, that a review must reflect genuine use and must never be padded to clear the limit. You are not only publishing functions. You are briefing the caller on how to behave. REST has no equivalent slot for that.
When you should actually build one
Do not build an MCP server because it is the thing this month. Ask one question: is an AI agent a real, intended user of my app?
If the only caller is your own frontend or backend, a REST API is simpler and you already have it. Wrapping it in MCP adds a protocol, a transport, auth threading, and a fresh rate-limit surface, for no benefit. That is complexity you will maintain and nobody will use.
If you want other people's agents to browse or act on your app without you shipping a bespoke SDK for each assistant, MCP earns its place. That is precisely Shipyard's case. Someone vibe-coding in Claude Code should be able to ship the thing they just built without alt-tabbing to a browser and re-typing what they already know.
Be honest about what it does not buy you. It is a thin layer over your real logic, not a substitute for it. If your service layer is a mess, your MCP server is that same mess with extra ceremony. Build the functions well first; the tools should be short wrappers. Ours are roughly fifteen lines each because they call the same code the site does.
There are hard limits worth knowing before you commit. An MCP server cannot read files off the user's machine, so our ship_project takes a public image URL, not a local path. When your screenshot is sitting in ./shots/, you want a different front door: the Shipyard CLI, which runs on the user's machine and can upload local files. Same product, different caller (a human in a terminal), different tool for the job.
Where to start
If an agent genuinely belongs in your app, the on-ramp is short:
- Reach for the official SDK in the language you are already in: TypeScript, Python, C#, and Java all have one.
- Start with read-only tools and no auth: a
list_xand aget_x. You can point Claude Code or the MCP Inspector at them in an afternoon and watch the agent call them. - Wrap existing service functions. Do not put new business logic in a tool handler; call the code you already have.
- Pick your transport by shape. Use stdio for a local server the client launches itself, and Streamable HTTP for a remote one people connect to over the network. A hosted product wants HTTP.
- Write each tool description like you are briefing a new contractor, because you effectively are. The model chooses what to call based on those words.
It is the kind of tooling that removes a step instead of adding one. Build something inside an agent, and from that same session, hand the agent the ability to actually do the thing.
That last part is the whole point, and it is the same instinct behind Shipyard. You get honest feedback from real builders and your project distributed to the right rooms, without leaving the session you shipped it in or grinding for attention by hand. We're letting in the first 50 founding members now. If your workflow already lives inside an agent, come and ship from there.
Frequently asked questions
What is an MCP server in simple terms?
It's a service that describes your app's actions to an AI agent as a list of callable tools, using the Model Context Protocol. The agent asks the server what tools exist, then calls them directly instead of scraping your website or relying on a hand-written integration.
How is an MCP server different from a REST API?
Same business logic underneath, different caller. A REST API expects a human developer to read docs and write a client ahead of time. An MCP server is discovered and called by the agent at runtime via a standard tools/list request, and one endpoint serves every MCP client.
Do I need to build an MCP server for my app?
Only if AI agents are meant to use it. If the only caller is your own frontend or backend, a REST API is simpler. Add an MCP server when you want other people's agents (Claude Code, Cursor, ChatGPT) to browse or act on your app without custom-coding an integration first.
What language and SDK do I use to build one?
Official SDKs exist for TypeScript, Python, C#, and Java, among others. Most indie devs start with the TypeScript or Python SDK, wrap their existing service functions as tools, and expose them over Streamable HTTP for a remote server or stdio for a local one.



