Build an MCP Server from Scratch: A Complete Developer Guide

By June 2026, the MCP ecosystem exceeds 10,000 servers and ships natively in Cursor, Claude Desktop, and VS Code. This hands-on guide walks you from protocol fundamentals through Tools, Resources, and Prompts, HTTP remote deployment, and a personal knowledge base project — so you can ship a production-ready MCP Server on your own.

Your LLM cannot query your Postgres instance, call an internal billing API, or read yesterday's meeting notes — not because the model is weak, but because no standardized bridge connects it to your systems. The Model Context Protocol (MCP) is that bridge: an open JSON-RPC contract any compliant Host can use to discover and invoke the servers you build. This guide targets backend and AI engineers with Python or TypeScript experience. You will: (1) understand MCP architecture and the request lifecycle; (2) scaffold a project and ship Hello World; (3) implement Tools, Resources, and Prompts; (4) expose a remote HTTP endpoint and harden it for production; and (5) finish a personal knowledge base server end to end. For protocol background, read our MCP deep dive and Cursor Agent Skills guide in parallel.

00Why Build an MCP Server: The Gap Between Models and Your Stack

Large language models excel at reasoning over text, but they are deliberately sandboxed from live systems. Every useful agent workflow — "look up this customer in CRM," "open the failing test file," "summarize last week's Slack thread" — requires a programmatic hook the model can discover and invoke safely.

The industry tried several answers. Function Calling tied tool schemas to a single vendor API. Plugins locked you into one product's marketplace. Agent frameworks like LangChain abstracted tools but not transport — switching Hosts still meant rewriting glue code. MCP, released by Anthropic in November 2024, standardizes the wire format so you write the server once and connect it from Cursor, Claude Desktop, VS Code, or any compliant client. By the end of this guide, you will have built and deployed one yourself.

PainWhat Tool Integration Looks Like Without MCP

  • Duplicate adapters per Host: File-system access, database queries, and API wrappers get reimplemented separately for Cursor, Claude Desktop, and Continue.
  • Vendor lock-in on schemas: Tool definitions written for OpenAI's function format do not travel when you adopt Claude or Gemini.
  • No first-class read-only data: Function calling covers "do something" but not "expose this config file as context" — forcing awkward workarounds.
  • Opaque debugging: When a tool call fails mid-agent-loop, there is no shared Inspector or JSON-RPC trace to inspect.

01MCP Protocol Architecture: Client, Server, and the Three Capabilities

An MCP Client lives inside the Host application (Cursor, Claude Desktop, a custom agent runner). Your MCP Server is the process you write — it exposes capabilities and bridges to real systems. They communicate over JSON-RPC 2.0 via stdio (local subprocess) or HTTP + SSE (remote service). The session lifecycle: initialize handshake → capability negotiation → request/response loop → graceful shutdown.

Every MCP Server advertises up to three capability types:

  • Tools: Callable functions — search, calculate, write to a database.
  • Resources: Read-only data addressed by URI — files, configs, API snapshots.
  • Prompts: Reusable prompt templates with parameter slots.
DimensionMCPOpenAI Function CallingLangChain Tools
StandardizationOpen protocol specVendor-specificFramework-bound
Transportstdio / HTTPHTTP onlyIn-process / HTTP
Cross-modelYesNoPartial
Resources & PromptsNativeNot supportedNot supported
Ecosystem (2026)10,000+ serversMatureMature

02Development Environment: Python First, TypeScript Alongside

Python is the fastest path for most backend engineers — the official mcp package with FastMCP decorators keeps boilerplate minimal. TypeScript suits teams already on Node: install @modelcontextprotocol/sdk and mirror the same patterns. This guide uses Python as the primary language with TypeScript notes where they diverge.

Environment setup
# Python
python -m venv .venv
source .venv/bin/activate
pip install mcp httpx pydantic

# TypeScript (reference)
npm init -y
npm install @modelcontextprotocol/sdk

Recommended project layout:

my-mcp-server/
my-mcp-server/
├── server.py
├── tools/
│   ├── calculator.py
│   └── web_search.py
├── resources/
│   └── file_reader.py
├── prompts/
│   └── templates.py
├── tests/
│   └── test_tools.py
├── pyproject.toml
└── README.md

Debugging stack: MCP Inspector (official browser UI), Claude Desktop for local integration tests, and Cursor's .cursor/mcp.json for IDE-side validation. Full spec at modelcontextprotocol.io.

03Your First MCP Server: Hello World

FastMCP turns a Python function into a discoverable tool with a decorator. The function signature and docstring become the JSON Schema the model reads at runtime.

server.py
from mcp.server.fastmcp import FastMCP

mcp = FastMCP("my-first-server")

@mcp.tool()
def say_hello(name: str) -> str:
    """Greet a person by name."""
    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

Wire it into Cursor via .cursor/mcp.json or Claude Desktop via claude_desktop_config.json using a command + args entry pointing at python server.py. Restart the Host and confirm the tool appears in the MCP panel before asking the model to invoke it.

04Tools: Building Functions the AI Can Call

Treat every tool as a public API: clear naming (snake_case), typed parameters, descriptive docstrings, and structured error responses instead of raw stack traces. FastMCP introspects type hints; for complex inputs, use Pydantic models.

Pydantic input schema
from pydantic import BaseModel, Field

class SearchInput(BaseModel):
    query: str = Field(description="Search keywords")
    max_results: int = Field(default=5, description="Maximum results to return")
    language: str = Field(default="en", description="Result language code")

@mcp.tool()
def web_search(input: SearchInput) -> list[dict]:
    """Run a web search and return matching results."""
    ...

Five starter tools worth implementing as practice:

  • Calculator: Evaluate math expressions (sandbox eval — never pass unsanitized input).
  • File I/O: Read and write within an allowlisted directory.
  • HTTP client: Proxy calls to external REST APIs.
  • Database query: Execute read-only SQL against a configured DSN.
  • Datetime utility: Current time, timezone conversion, ISO formatting.
Async tool (network-bound)
import httpx

@mcp.tool()
async def fetch_url(url: str) -> str:
    """Fetch and return the body of a URL."""
    async with httpx.AsyncClient(timeout=30.0) as client:
        response = await client.get(url)
        response.raise_for_status()
        return response.text

Production habits: enforce a 30-second timeout on I/O-bound tools, validate permissions server-side, and keep API keys on the server — never in client config files.

05Resources: Exposing Read-Only Data to the Model

Resources differ from Tools: a Resource supplies data; a Tool performs an action. Resources are addressed by URI schemes — file://, https://, or custom schemes like config:// — and the Client fetches them without side effects.

Static and dynamic resources
@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)

Supported MIME types include text/plain, application/json, and binary formats for images or PDFs. A filesystem resource server typically implements directory listing, file reads, and optional change subscriptions so the Client refreshes when files update.

06Prompts: Reusable Template Libraries

MCP Prompts are parameterized message templates the Host can surface to users or agents. They standardize recurring workflows — code review, incident triage, interview prep — without copy-pasting instructions into every session.

Code review prompt template
from mcp.types import PromptMessage, TextContent

@mcp.prompt()
def code_review_prompt(language: str, code: str) -> list[PromptMessage]:
    return [
        PromptMessage(
            role="user",
            content=TextContent(
                type="text",
                text=f"Review the following {language} code for bugs, "
                     f"security issues, and style. Provide line-level feedback:\n\n{code}"
            )
        )
    ]

Multi-turn templates can include both user and assistant roles, enabling structured dialogues the Host renders as a single selectable prompt.

07Advanced: HTTP Transport for Remote MCP Servers

FeaturestdioHTTP + SSE
DeploymentLocal subprocessRemote server / cloud node
LatencyMinimal (pipes)Network-dependent
Multi-clientOne process per clientShared endpoint
Best forPersonal dev toolsTeam SaaS, 24/7 agents
HTTP mode startup
mcp = FastMCP("remote-server", transport="streamable-http")

if __name__ == "__main__":
    mcp.run(host="0.0.0.0", port=8000)

Remote deployments require Bearer Token authentication, rate limiting, CORS policy, and TLS termination at a reverse proxy. Centralize secrets on the server — clients should only hold connection URLs and auth tokens scoped to their role.

Citeable data point 1: As of 2026, the public MCP ecosystem lists more than 10,000 servers — each one immediately callable from every compliant Host without additional adapter code.

Citeable data point 2: Teams adopting MCP for internal tool integration report development cost reductions of 38–55% compared to per-vendor custom adapters (industry survey range, 2025–2026).

Citeable data point 3: The official MCP Python SDK surpassed 5 million monthly PyPI downloads in Q2 2026 — a practical signal that server-side MCP development has moved from experiment to default stack.

08Debugging and Testing Your Server

MCP Inspector launches a browser UI against your server process: browse the tool inventory, fire test calls, and inspect raw JSON-RPC request/response pairs. For CI, spin up the server as a subprocess and drive it programmatically:

pytest smoke test
from mcp.client.session import ClientSession
from mcp.client.stdio import StdioServerParameters, stdio_client

async with stdio_client(StdioServerParameters(
    command="python", args=["server.py"]
)) 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"
SymptomLikely causeFix
Tool missing in Host UIWrong config path or commandVerify mcp.json command and working directory
JSON serialization errorNon-serializable return typeReturn str, dict, or Pydantic model
Session timeoutBlocking I/O in sync toolConvert to async; add explicit timeout
Permission deniedPath outside allowlistConfigure server-side directory whitelist

09Production Deployment: Docker, Cloud, and Observability

Dockerfile
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["python", "server.py"]

Deployment targets by scale: Railway / Render for solo projects with minimal ops; AWS Lambda / Google Cloud Run for event-driven or bursty workloads; self-hosted VPS or cloud Mac with Nginx reverse proxy when you need persistent SSE sessions and low-latency tool calls.

Observability checklist: structured JSON logs per tools/call, Prometheus counters for call volume and latency, Sentry for unhandled exceptions, and a /health endpoint for load balancer probes. Pin the MCP protocol version in your server metadata and treat tool schema changes as semver — additive fields are safe; removing parameters breaks downstream agents.

10Project Walkthrough: Personal Knowledge Base MCP Server

Goal: Let any MCP Host search your local Markdown notes, retrieve semantically similar passages, and create or update files on command.

Stack choices: ChromaDB or Qdrant for local vector storage; text-embedding-3-small for embeddings; watchfiles to re-index on save.

  • Index tool: Scan a notes directory, chunk Markdown, embed, and upsert into the vector store.
  • Semantic search tool: Accept a natural-language query; return top-K relevant chunks with source paths.
  • Write tool: Create or append to a Markdown file inside the allowlisted folder.
  • Resource handler: Expose full note content via note://{filename} URIs for direct reads.

Demo scenario: in Cursor, ask "What did I write about MCP deployment last week?" — the agent calls your search tool, receives ranked snippets, and synthesizes an answer grounded in your actual notes rather than training data.

11MCP Ecosystem and What Comes Next

Community servers worth studying: mcp-server-filesystem (directory access), mcp-server-github (repo operations), mcp-server-brave-search (web search), mcp-server-postgres (SQL), and mcp-server-slack (messaging).

2026 trajectory: OpenAI, Google, and Microsoft have all committed to MCP support; governance moved to the Linux Foundation's AAIF; MCP marketplaces are proliferating; enterprise OAuth 2.1 integration remains on the near-term roadmap.

Learning path after this guide: Read the full MCP specification; publish a server to a registry; combine MCP with agent orchestration patterns from our Cursor Agent Skills guide; contribute to the Python SDK, TypeScript SDK, or Inspector repos.

12Six-Step Runbook: Run Your MCP Server 24/7 on Cloud Mac

  1. 01
    Choose transport mode: Use stdio for solo local development. Switch to HTTP+SSE when multiple teammates or remote agents need the same server — and keep API keys centralized on the server, not in each laptop's config.
  2. 02
    Provision a cloud Mac from the console: Sign in to the NUKCLOUD console and pick a 16 GB+ unified memory tier (32 GB if you run several MCP server processes in parallel). Hourly billing on the pricing page works well for pilot runs.
  3. 03
    Install Python 3.12 and dependencies: SSH in, run pip install mcp httpx pydantic, clone your server repo, and smoke-test locally with MCP Inspector before exposing any port.
  4. 04
    Deploy the HTTP server and open the port: Start with mcp.run(host="0.0.0.0", port=8000) behind Nginx TLS termination. Add Bearer Token middleware, CORS rules, and rate limits before sharing the URL.
  5. 05
    Connect clients and validate: Point Cursor .cursor/mcp.json or Claude Desktop config at the cloud endpoint. Confirm tools/list returns your inventory and run one tools/call smoke test; record baseline latency.
  6. 06
    Keep the process alive with launchd: Write ~/Library/LaunchAgents/com.team.mcp-server.plist for 24/7 uptime. After the pilot, lock your tier on the order page. For node provisioning details, see the NUKCLOUD production runbook.

Running HTTP MCP servers on a local MacBook or shared VPS routinely hits lid-close sleep killing SSE sessions, bandwidth jitter dropping long-lived connections, and port conflicts when multiple developers share one machine. When Cursor Background Agents or a personal knowledge base server needs stable 24/7 tool access, NUKCLOUD multi-region bare-metal Mac / cloud Mac nodes give you tenant isolation and spec elasticity aligned with MCP workflows — start hourly for a pilot, then move to fixed monthly capacity.

13Frequently Asked Questions

Python or TypeScript for my first MCP Server?
Start with Python + FastMCP if you want the shortest path — decorators handle schema generation automatically. Choose TypeScript if your team already ships Node services and wants shared types with a frontend. Both SDKs are officially maintained and wire-compatible.
How do Tools, Resources, and Prompts divide responsibility?
Tools perform actions (write a row, call an API). Resources expose read-only data (configs, file contents). Prompts ship reusable instruction templates. Together they cover every way an agent extends its context beyond the model's training cutoff.
When should I pick stdio vs HTTP?
Use stdio for personal local tools and single-user Cursor workflows. Choose HTTP+SSE when a team shares one server, you need remote access from Claude Code, or the server must stay online while laptops sleep. See the transport comparison table in Section 07.
How does this guide differ from your MCP protocol deep dive?
The MCP deep dive explains why the protocol exists and compares it to REST at the architecture level. This article is a build tutorial — complete code, deployment steps, and a knowledge base project you can ship today.
What MCP Server are you building next?
Share your project idea in the comments. MCP server development is becoming a core skill for AI engineers in 2026 — the earlier you ship one, the more compound leverage you get as the Host ecosystem grows.