Build an MCP Server from Scratch: A Complete Developer Guide
No matter how capable a large language model is, it cannot query databases, call APIs, or read and write files on its own—AI tool calling determines whether an Agent can reach the real world. MCP (Model Context Protocol) is an open standard from Anthropic that lets clients like Claude and Cursor discover and invoke your Server through a unified interface. This article targets backend and AI developers with Python or TypeScript experience, walking you through protocol fundamentals, environment setup, the three core capabilities (Tools / Resources / Prompts), remote HTTP deployment, debugging, testing, and production rollout.
When you finish, you will be able to answer three questions: ① how MCP differs fundamentally from Function Calling and LangChain Tools; ② how to register tools, resources, and prompt templates with the official SDK; ③ how to wrap a personal knowledge base into a production-ready MCP Server and ask Cursor directly, "What did I write about MCP last week?"
01 What is MCP? Protocol fundamentals, communication, and comparison
Tool calling has evolved through three generations: Function Calling (vendor-specific formats) → Plugins (platform-bound) → MCP (open protocol standard). Anthropic designed MCP to unify "how AI clients discover, describe, and invoke external capabilities" with a JSON-RPC specification—ending the N models × M tools custom integration nightmare.
- Problem: Models lack access to external tools and live data—they cannot query databases, call APIs, or operate on files.
- Scenario: You want Claude / GPT to query databases, call REST APIs, and read local Markdown—exactly what an MCP Server exposes.
- Outcome: After reading this article, you can independently develop and deploy a production-ready MCP Server.
Architecturally, the MCP Client (Claude Desktop, Cursor, etc.) and MCP Server (the part you build) communicate bidirectionally via JSON-RPC; the Server then connects to external systems:
- Tools: Functions AI can invoke (search, compute, database queries)
- Resources: Data AI can read (files, URLs, streams)
- Prompts: Predefined prompt templates with parameter injection
Communication uses JSON-RPC 2.0 with two transport modes: stdio (local subprocess, extremely low latency) and HTTP + SSE / Streamable HTTP (remote service, multi-client support). Lifecycle: initialization handshake → capability negotiation → request/response → shutdown.
| Dimension | MCP | OpenAI Function Calling | LangChain Tools |
|---|---|---|---|
| Standardization | Open protocol standard | Vendor proprietary | Framework-bound |
| Transport | stdio / HTTP | HTTP | HTTP |
| Cross-model support | Yes | No | Partial |
| Resources / Prompts | Native support | Not supported | Not supported |
| Ecosystem | Rapid growth (10,000+ Servers) | Mature | Mature |
Further reading: Why MCP Is Becoming the HTTP of the AI Era; official spec at modelcontextprotocol.io.
02 Environment setup: language choice, dependencies, and project structure
Python (recommended for beginners): official SDK mcp, FastMCP decorators are concise and easy to learn. TypeScript (recommended for frontend / full-stack): official SDK @modelcontextprotocol/sdk. This article focuses on Python with TypeScript cross-references.
python -m venv .venv
source .venv/bin/activate
pip install mcp
npm init -y
npm install @modelcontextprotocol/sdk
Recommended project structure:
my-mcp-server/
├── server.py
├── tools/
│ ├── __init__.py
│ ├── calculator.py
│ └── web_search.py
├── resources/
│ └── file_reader.py
├── prompts/
│ └── templates.py
├── tests/
│ └── test_tools.py
├── pyproject.toml
└── README.md
Three essential debugging tools:
- MCP Inspector: Official debug UI for visually testing Tools / Resources / Prompts
- Claude Desktop: Edit
claude_desktop_config.jsonfor local integration testing - Cursor MCP config: Settings → MCP → add a stdio command-line launch entry
03 Hello World: the simplest MCP Server and Cursor integration
FastMCP gets your first Server running in about ten lines:
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("my-first-server")
@mcp.tool()
def say_hello(name: str) -> str:
"""Greet the specified person"""
return f"Hello, {name}! This is your first MCP tool."
if __name__ == "__main__":
mcp.run()
Run and verify:
python server.py
npx @modelcontextprotocol/inspector python server.py
Six steps to connect Cursor:
- Confirm Python path: In your virtual environment, run
which pythonand note the absolute path. - Open Cursor MCP settings: Settings → Features → MCP Servers.
- Add a stdio Server: Set command to the Python path and args to the absolute path of
server.py. - Restart Cursor: So the MCP configuration takes effect.
- Verify the tool list: In Agent mode, confirm
say_helloappears. - Trigger a call: In chat, ask the AI to "use say_hello to greet JEXCLOUD" and confirm the correct response.
Claude Desktop works the same way: edit ~/Library/Application Support/Claude/claude_desktop_config.json and register the same configuration under the mcpServers node.
04 Tools development: parameter types, five practical tools, and async patterns
A tool's basic contract: the function signature is the documentation—parameter types, return types, and docstrings are converted by MCP into JSON Schema for AI understanding. Use snake_case naming; prefer returning structured error information over raw exceptions.
Model complex parameters with Pydantic:
from pydantic import BaseModel, Field
class SearchInput(BaseModel):
query: str = Field(description="Search keywords")
max_results: int = Field(default=5, description="Maximum number of results")
language: str = Field(default="en", description="Result language")
@mcp.tool()
def web_search(input: SearchInput) -> list[dict]:
"""Perform a web search and return a list of relevant results"""
...
Five practical tools to use as a practice checklist:
- Calculator: Safely evaluate math expressions (
ast.literal_evalto prevent injection) - File read/write: Read / write within a whitelisted directory
- HTTP requests: Wrap GET / POST with unified timeouts and retries
- Database queries: Read-only SQL with parameterized queries to prevent injection
- Time utilities: Current time, timezone conversion, ISO 8601 formatting
Use async for IO-heavy tools:
import httpx
@mcp.tool()
async def fetch_url(url: str) -> str:
"""Fetch content from the specified URL"""
async with httpx.AsyncClient() as client:
response = await client.get(url, timeout=30.0)
return response.text
Error handling best practices: set timeouts, enforce permission checks (path whitelist / API Key), and return a {"error": "...", "code": "..."} structure so AI can self-correct.
05 Resources: URI addressing, static and dynamic resources, filesystem walkthrough
Resource vs Tool: A Resource is a data provider (read-only); a Tool is an action executor (can write, can have side effects). Addressing uses URI schemes: file://, http://, custom://.
@mcp.resource("config://app-settings")
def get_app_settings() -> str:
return json.dumps({"version": "1.0", "env": "production"})
@mcp.resource("user://{user_id}/profile")
def get_user_profile(user_id: str) -> str:
user = db.query_user(user_id)
return json.dumps(user)
Resource types covered:
- Text:
text/plain,application/json - Binary: Images, PDFs (Base64 or blob URI)
- Streaming: Live logs, market feeds (resource subscriptions)
Filesystem resource server walkthrough: list directories → read files by path → optionally use watchfiles to watch for changes and push resource update notifications.
06 Prompts: reusable prompt templates and multi-turn scenarios
An MCP Prompt is a predefined prompt fragment that AI clients can reuse directly, with dynamic parameter injection—improving team prompt consistency and maintainability.
from mcp.types import PromptMessage, TextContent
@mcp.prompt()
def code_review_prompt(language: str, code: str) -> list[PromptMessage]:
"""Code review prompt template"""
return [
PromptMessage(
role="user",
content=TextContent(
type="text",
text=f"Please review the following {language} code..."
)
)
]
Multi-turn templates can mix user and assistant roles. Typical scenarios: interview simulation (assistant asks first, user responds), code debugging assistant (assistant guides troubleshooting steps).
07 HTTP transport: remote MCP Server and security hardening
| Feature | stdio | HTTP + SSE |
|---|---|---|
| Deployment | Local process | Remote server |
| Latency | Extremely low | Network-dependent |
| Multi-client | Not supported | Supported |
| Use case | Local tools | SaaS / team sharing |
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("remote-server", transport="streamable-http")
if __name__ == "__main__":
mcp.run(host="0.0.0.0", port=8000)
Production environments must add: Bearer Token authentication, API Key middleware, CORS whitelist, and request rate limiting (e.g. slowapi). Remote Servers suit team-shared database queries, internal API gateways, and similar capabilities.
08 Debugging and testing: MCP Inspector, unit tests, and common errors
MCP Inspector workflow: launch Inspector → connect stdio command → test tools/call in the UI → inspect JSON-RPC request/response logs → simulate timeout and permission-denied scenarios.
import pytest
from mcp.client.session import ClientSession
from mcp.client.stdio import StdioServerParameters, stdio_client
@pytest.mark.asyncio
async def test_calculator_tool():
server_params = StdioServerParameters(command="python", args=["server.py"])
async with stdio_client(server_params) as (read, write):
async with ClientSession(read, write) as session:
await session.initialize()
result = await session.call_tool("calculate", {"expression": "2 + 2"})
assert result.content[0].text == "4"
| Error | Cause | Fix |
|---|---|---|
| Tool not appearing in AI | Config path error | Check absolute command / args paths in config.json |
| JSON serialization failure | Unsupported return type | Convert to string or dict |
| Timeout disconnect | Tool execution too slow | Switch to async + timeout control |
| Permission denied | File path restricted | Configure allowed directory whitelist |
09 Production deployment: Docker, cloud services, and observability
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["python", "server.py"]
Deployment options:
- Railway / Render: One-click deploy, suited for personal projects
- AWS Lambda / Google Cloud Run: Serverless, pay per invocation
- Self-hosted VPS: Nginx reverse proxy + TLS with Bearer Token
Observability essentials: structured request logs, Prometheus tool-call metrics, Sentry error alerts; expose a /health endpoint. Version management must declare the MCP protocol version; keep tool upgrades backward compatible and use capability negotiation to avoid client crashes.
- MCP Python SDK: github.com/modelcontextprotocol/python-sdk
- MCP TypeScript SDK: github.com/modelcontextprotocol/typescript-sdk
- MCP Inspector: github.com/modelcontextprotocol/inspector
10 Project walkthrough: building a personal knowledge base MCP Server
Requirements: Let AI search local Markdown notes, perform semantic retrieval, and create or update notes.
Tech stack:
- Vector database: ChromaDB or Qdrant (lightweight local options)
- Embedding model:
text-embedding-3-small(OpenAI) or localnomic-embed-text - File watching:
watchfilesfor incremental index rebuilds
Core modules:
index_notestool: Scan the notes directory, chunk, embed, and write to the vector storesemantic_searchtool: query → top-k relevant snippetswrite_notetool: Create / append Markdown filesnotes://{path}resource: Read full note content by URI
Demo: In Cursor, ask "What did I write about MCP last week?" → AI calls semantic_search → returns relevant snippets and synthesizes an answer. This is the shortest path to connecting private knowledge into an Agent workflow.
11 MCP ecosystem outlook, learning path, and production host selection
Recommended community Servers:
mcp-server-filesystem: Filesystem operationsmcp-server-github: GitHub repository operationsmcp-server-brave-search: Web searchmcp-server-postgres: Database queriesmcp-server-slack: Slack messaging
2026 ecosystem trends: Cursor, Claude Desktop, VS Code, OpenAI, and Google Gemini all natively support or plan to support MCP; MCP Marketplace accelerates Server distribution; enterprise security standards (OAuth 2.1, audit logs) are on the roadmap.
Next learning path: Study the MCP protocol spec in depth → publish your first public Server → explore MCP + Agent orchestration → contribute PRs to the open-source ecosystem.
- Protocol versions: Initial release 2024-11-05; from 2025, Streamable HTTP replaces pure SSE as the recommended remote transport
- Ecosystem scale: By 2026, community MCP Servers exceed 10,000
- SDK maintainers: Anthropic open-source + Linux Foundation AAIF governance; Python / TypeScript dual official SDKs with weekly updates
MCP is the standard protocol for AI tooling—mastering Server development means giving any LLM the ability to call your business systems. What tool do you plan to wrap with MCP? Share your use case in the comments.
The hidden cost of production-grade MCP Servers is host stability: closing a laptop kills STDIO subprocesses; home broadband jitter breaks HTTP long connections; shared VPS lacks macOS sandbox and TCC permissions. If you need 24/7 knowledge base indexing, remote HTTP MCP, or Cursor Agent CI workflows, JEXCLOUD multi-region bare-metal Mac offers dedicated Apple Silicon, fixed public IPs, 120-second delivery, and flexible monthly terms—better suited for production Agent workflows than "local workaround + constant reconnects." See nodes and pricing on the JEXCLOUD pricing page and deployment questions in the help center.