Quick takeaways
- An MCP server is a small program that exposes tools, resources, and prompts over stdio or HTTP.
- Start with one read-only tool, write a clear description and schema, and test locally.
- Use the official SDK for TypeScript or Python to avoid reimplementing the protocol.
Build your first MCP server
Anthropic's guide walks through building an MCP server from scratch with the official SDK.
What you will build
In this tutorial you will build a minimal MCP server that exposes a single tool: get_project_status. The tool returns a simple status message for a named project. Once it works, you will extend it with a resource and a prompt template, then connect it to Claude Desktop.
The goal is not to build production infrastructure. It is to understand the moving parts so you can design larger integrations safely.
Server/client model
MCP separates three concerns:
- Host: The application running the assistant, such as Claude Desktop.
- Client: The MCP client built into the host that manages server lifecycle and message routing.
- Server: Your program that exposes tools, resources, and prompts.
The server communicates with the client over standard input and output using JSON-RPC messages. You do not need to manage networking for local Claude Desktop integrations; stdio is enough.
Tools, resources, and prompts
Most first servers start with tools because they are the easiest to reason about. Add resources when the assistant needs structured read access to data, and prompts when you want to standardize how users interact with the server.
TypeScript starter
Install the official TypeScript SDK and create a new project:
mkdir my-mcp-server cd my-mcp-server npm init -y npm install @modelcontextprotocol/sdk zod npm install --save-dev @types/node typescript
Create src/index.ts with the following server:
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
const server = new Server(
{ name: "my-first-mcp-server", version: "0.1.0" },
{ capabilities: { tools: {} } }
);
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: "get_project_status",
description: "Return the current status of a named project",
inputSchema: {
type: "object",
properties: {
project: { type: "string", description: "Project name" }
},
required: ["project"]
}
}
]
};
});
server.setRequestHandler(CallToolRequestSchema, async (request) => {
if (request.params.name === "get_project_status") {
const project = String(request.params.arguments?.project ?? "unknown");
return {
content: [
{ type: "text", text: `Project "${project}" is active and on schedule.` }
]
};
}
throw new Error("Tool not found");
});
const transport = new StdioServerTransport();
await server.connect(transport);
Build and run the server from your terminal to verify it starts without errors:
npx tsc --init # Update tsconfig.json to use ES modules if needed node --experimental-strip-types src/index.ts
Python starter
If you prefer Python, use the official Python SDK:
pip install mcp python -m mcp new-project my_mcp_server cd my_mcp_server
Edit the generated server file to add your tool:
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("my_first_mcp_server")
@mcp.tool()
def get_project_status(project: str) -> str:
"""Return the current status of a named project."""
return f'Project "{project}" is active and on schedule.'
if __name__ == "__main__":
mcp.run()
Run it to confirm the server starts:
python server.py
Test in Claude Desktop
Add your new server to claude_desktop_config.json. Use the absolute path to the entry point and make sure Node or Python is available in the environment PATH.
{
"mcpServers": {
"my-first-server": {
"command": "node",
"args": ["/absolute/path/to/my-mcp-server/dist/index.js"]
}
}
}
For the Python version:
{
"mcpServers": {
"my-first-server": {
"command": "python",
"args": ["/absolute/path/to/my_mcp_server/server.py"]
}
}
}
Restart Claude Desktop, open a new conversation, and ask: "What tools are available?" Claude should list get_project_status. Then ask: "What is the status of the website project?"
Share or deploy
Once the server is stable, you can publish it to npm or PyPI, or distribute it as a Docker image. Include a clear README with:
- What tools, resources, and prompts the server exposes.
- Required environment variables and permissions.
- An example
claude_desktop_config.jsonentry. - Safety notes and any actions that require human approval.
Without AI vs. with AI
| Task | Without AI | With AI |
|---|---|---|
| Integration code | Every assistant integration is a one-off script with custom messaging. | An MCP server uses a standard protocol so any compatible host can connect. |
| Tool definition | Functions are described in comments or informal docs the model cannot read. | Tools declare names, descriptions, and JSON schemas the assistant uses to call them. |
| Testing | Integrations are tested only inside the full assistant conversation. | Servers are tested in isolation with direct tool calls before connecting to a host. |
| Deployment | Scripts are copied between machines with manual environment setup. | Servers are packaged as npm or PyPI modules, Docker images, or documented executables. |
| Security | Credentials are hardcoded or shared across environments. | Secrets are read from environment variables and scoped to the server's needs. |
FAQ
Do I need to use TypeScript or Python?
No. MCP is a protocol. You can implement it in any language that can read and write JSON over stdio, but the official SDKs make it much faster.
How do I debug a server that does not appear in Claude?
Run the server manually in a terminal and watch for startup errors. Check Claude Desktop logs for stderr output from the MCP process.
Can a server expose both tools and resources?
Yes. Declare both capabilities when you initialize the server and implement the corresponding request handlers.
Should I build one big server or many small ones?
Prefer small, focused servers. They are easier to test, scope, and maintain. One server per system or workflow is a good default.
How do I handle secrets in my server?
Read secrets from environment variables. Never hardcode credentials, and document which permissions the server needs.
Which SDK should I use for my first MCP server?
Use the official TypeScript or Python SDK. They handle protocol details so you can focus on tool logic.
How do I test an MCP server without Claude Desktop?
Run the server in stdio mode and send JSON-RPC messages, or use an MCP inspector if available.
What should my first tool do?
Start with a read-only tool that returns structured data. Avoid writes until the tool works reliably.
Can I expose resources and prompts too?
Yes. Resources provide structured read access; prompts standardize how users interact with your server.
How do I handle errors in an MCP server?
Return clear error messages, log failures, and never leak stack traces or secrets to the assistant.