Table of Contents

  1. 01. Why MCP exists
  2. 02. What a custom MCP server is
  3. 03. From M×N integrations to one protocol
  4. 04. Where custom servers help
  5. 05. Choosing a language
  6. 06. Tutorial 1: a Python web inspector
  7. 07. Tutorial 2: a TypeScript Hacker News feed
  8. 08. Tutorial 3: a Rust file integrity checker
  9. 09. How Claude uses MCP
  10. 10. Security risks and defenses
  11. 11. Getting started
  12. 12. References

01Why MCP exists

A language model on its own can reason about a contract or refactor a Rust crate, but it cannot query your database, open a GitHub issue, or check whether your website is up. It needs a connection to those systems, and before late 2024 each connection was a custom integration.

The Model Context Protocol (MCP) standardizes that connection. Anthropic open-sourced it on November 25, 2024, describing it in Anthropic's original MCP launch post as an open standard for connecting AI assistants to the systems where data lives. A year later, the official MCP blog's foundation announcement reported more than 97 million monthly SDK downloads, 10,000 active servers, and client support in ChatGPT, Claude, Cursor, Gemini, Microsoft Copilot and VS Code.

97M+monthly SDK downloads
10,000+active servers by Dec 2025
6Tier 1 official SDKs
2026-07-28current stateless spec

Many public servers wrap commercial products such as Notion, Sentry or GitHub. This article covers the other kind: a custom server you write for your own systems, in a language you already use, which Claude can call once you register it.

02What a custom MCP server is

An MCP server is a program that exposes three kinds of capability: tools (functions the model can call), resources (data it can read) and prompts (reusable templates). A host application such as Claude Desktop, Claude Code or an app built on the Claude API runs an MCP client, and that client can connect to many servers at once.

A custom server wraps something specific to you, such as a billing API, a Postgres replica, an internal wiki or an old SOAP service. Once it speaks MCP, any MCP-compatible client can use it without new integration code.

Hosts (Claude) Your Custom MCP Servers Systems They Reach Claude Desktop MCP client Claude Code MCP client Claude API App MCP connector JSON-RPC over stdio or HTTP Web Inspector Python • stdio Hacker News Feed TypeScript • stdio File Integrity Rust • stdio Remote SaaS Server Any language • Streamable HTTP Any public website Hacker News REST API Local file system Notion, GitHub, Sentry
Diagram 1: Hosts, MCP clients, custom servers and the systems they reach. The three local servers correspond to the tutorials below.

03From M×N integrations to one protocol

Connecting M AI applications to N systems used to take M×N integrations. Anthropic's launch post described the problem directly: every new data source needed its own custom implementation. With MCP, each application implements a client once and each system implements a server once, so the count drops to M+N.

Before: M × N = 12 integrations With MCP: M + N = 7 implementations Claude IDE agent Your app Database GitHub Web APIs Files Claude IDE agent Your app MCP Database GitHub Web APIs Files
Diagram 2: Three apps and four systems need twelve point-to-point integrations without MCP and seven implementations with it.

The protocol also no longer belongs to one company. On December 9, 2025, Anthropic donated MCP to the Agentic AI Foundation, a directed fund under the Linux Foundation co-founded by Anthropic, Block and OpenAI, with support from Google, Microsoft, AWS, Cloudflare and Bloomberg.

04Where custom servers help

Anything with an API, a command line, a database driver or a file format can sit behind an MCP server. These are common starting points.

Engineering and DevOps

The Claude Code docs give this example: implement the feature described in a JIRA ticket and open a GitHub pull request, from one request.

Data and analytics

A server with read-only database credentials lets Claude answer questions such as monthly revenue against live tables.

Web monitoring

Uptime sweeps, title and metadata checks, price watching and public API polling. Tutorial 1 covers the first two.

Business apps

Notion, Asana, Stripe, HubSpot and Sentry already publish remote servers. Custom servers cover the in-house tools they don't.

Private and legacy systems

Claude's MCP tunnels documentation describes reaching servers inside a private network without opening inbound ports.

Personal automation

Notes, local files, home-lab scripts and research pipelines become tools Claude can call one after another.

SerpApi's first-half 2026 MCP review counts roughly 9,400 to 17,000+ public servers across the major registries and finds that fewer than 5% are monetized. It also reports momentum moving toward vendor-built connectors and private servers that companies run for their own systems.

05Choosing a language

The official MCP SDK tier list places TypeScript, Python, C#, Go, Rust and Ruby at Tier 1, Java at Tier 2, and Swift, PHP and Kotlin at Tier 3. Every SDK can build servers that expose tools, resources and prompts.

Tier 1 TypeScript Python C# Go Rust Ruby Tier 2 Java Tier 3 Swift PHP Kotlin Tutorials below: Python • TypeScript • Rust Tier = feature completeness and support level
Diagram 3: Official MCP SDKs by tier, per modelcontextprotocol.io as of October 2026.

The tutorials target the 2026-07-28 specification, which became the stable 2026-07-28 MCP release on July 28, 2026. All three run over stdio, the transport Claude Desktop and Claude Code use when they start a local server as a child process.

06Tutorial 1: a Python web inspector

This server gives Claude two tools that report a public page's status code, response time and title. It uses the MCP Python SDK v2 repository, where the MCPServer class builds each tool's JSON Schema from its type hints.

Step 1 · Install
bash • uv project setup
# Create a project and add the MCP Python SDK v2 plus httpx for HTTP requests
uv init web-inspector && cd web-inspector
uv add "mcp[cli]" httpx
Step 2 · Write server.py
python • server.py
"""server.py - an MCP server that lets Claude inspect public web pages."""
import re
import time

import httpx                      # async HTTP client used to fetch pages
from mcp.server import MCPServer  # high-level server class in SDK v2

# The name hosts such as Claude Code display for this server
mcp = MCPServer("WebInspector")

# Precompiled pattern that pulls the <title> text out of raw HTML
TITLE_RE = re.compile(r"<title[^>]*>(.*?)</title>", re.IGNORECASE | re.DOTALL)


async def _inspect(client: httpx.AsyncClient, url: str) -> dict:
    # Shared helper: time one request and extract what Claude needs
    start = time.perf_counter()
    response = await client.get(url)
    elapsed_ms = round((time.perf_counter() - start) * 1000)
    match = TITLE_RE.search(response.text)
    return {
        "final_url": str(response.url),        # after any redirects
        "status": response.status_code,
        "response_ms": elapsed_ms,
        "title": match.group(1).strip() if match else "",
    }


@mcp.tool()
async def inspect_page(url: str) -> dict:
    """Fetch a public URL and report HTTP status, response time and page title."""
    # The docstring becomes the tool description Claude reads when choosing tools
    async with httpx.AsyncClient(follow_redirects=True, timeout=15) as client:
        return await _inspect(client, url)


@mcp.tool()
async def check_many(urls: list[str]) -> list[dict]:
    """Check several URLs in one call, reporting failures instead of raising."""
    results = []
    async with httpx.AsyncClient(follow_redirects=True, timeout=15) as client:
        for url in urls:
            try:
                results.append(await _inspect(client, url))
            except httpx.HTTPError as exc:
                # A down site is data for Claude, not a crash for the server
                results.append({"final_url": url, "error": str(exc)})
    return results


if __name__ == "__main__":
    # run() with no arguments starts a stdio server, the transport local hosts launch
    mcp.run()
Step 3 · Test, Then Connect To Claude Code
bash • registration & execution
# Open the server in the MCP Inspector to call each tool by hand
uv run mcp dev server.py

# Register it with Claude Code; everything after -- is the launch command
claude mcp add web-inspector -- uv run --with "mcp[cli]" --with httpx mcp run /absolute/path/to/server.py

Run /mcp inside Claude Code to check that the server connected, then ask something like “Check thomascherickal.com and thomascherickal.github.io and tell me which responds faster.” For Claude Desktop, the Python SDK's connect-to-a-host guide shows uv run mcp install server.py writing the config entry for you.

07Tutorial 2: a TypeScript Hacker News feed

The official Hacker News Firebase API needs no key, so it works well as an example of wrapping a REST API. The server uses the @modelcontextprotocol/server package from the MCP TypeScript SDK v2 repository.

Step 1 · Install
bash • npm project setup
# ES module project with the v2 server package, Zod for schemas, tsx to run TypeScript directly
mkdir hn-feed && cd hn-feed
npm init -y && npm pkg set type=module
npm install @modelcontextprotocol/server zod
npm install -D tsx typescript
Step 2 · Write index.ts
typescript • index.ts
// index.ts - an MCP server that gives Claude a live Hacker News feed
import { McpServer } from '@modelcontextprotocol/server';
import { StdioServerTransport } from '@modelcontextprotocol/server/stdio';
import * as z from 'zod/v4';

// Base URL of the public, key-free Hacker News API
const HN = 'https://hacker-news.firebaseio.com/v0';

// Name and version are what MCP clients display for this server
const server = new McpServer({ name: 'hn-feed', version: '1.0.0' });

// Register a tool; the Zod schema becomes the JSON Schema Claude sees
server.registerTool(
  'top_stories',
  {
    description: 'Return the current top Hacker News stories with title, score and link',
    inputSchema: z.object({
      count: z.number().int().min(1).max(20).default(5) // cap output to protect context
    })
  },
  async ({ count }) => {
    // 1. Fetch the ranked list of top story IDs (up to 500)
    const ids: number[] = await (await fetch(`${HN}/topstories.json`)).json();

    // 2. Fetch the first `count` stories in parallel
    const stories = await Promise.all(
      ids.slice(0, count).map(async (id) => (await fetch(`${HN}/item/${id}.json`)).json())
    );

    // 3. One readable line per story; text content is what Claude reads back
    const lines = stories.map((s: any, i: number) =>
      `${i + 1}. ${s.title} (${s.score} points) ${s.url ?? `https://news.ycombinator.com/item?id=${s.id}`}`
    );
    return { content: [{ type: 'text', text: lines.join('
') }] };
  }
);

// Serve over stdio so Claude Code can launch this file as a child process
async function main() {
  await server.connect(new StdioServerTransport());
}
main();
Step 3 · Connect
bash • claude code hookup
# Claude Code launches the server with tsx whenever a session starts
claude mcp add hn-feed -- npx tsx /absolute/path/to/hn-feed/index.ts

You can then ask Claude for the current top stories with a short summary of each. The same structure works for a weather service, a CRM or an internal REST API.

08Tutorial 3: a Rust file integrity checker

Rust suits tools that need speed and memory safety and that you want to ship as a single binary. The official Rust SDK, the rmcp crate, implements the 2026-07-28 spec, stays compatible with 2025-11-25, and generates tool routing from macros.

Step 1 · Create The Crate
bash • cargo dependencies
# rmcp with server and stdio transport features, plus tokio, serde, anyhow and sha2
cargo new integrity-mcp && cd integrity-mcp
cargo add rmcp --features server,transport-io
cargo add tokio --features full
cargo add serde --features derive
cargo add anyhow sha2
Step 2 · Write src/main.rs
rust • src/main.rs
// main.rs - an MCP server that lets Claude verify files with SHA-256
use rmcp::{handler::server::wrapper::Parameters, schemars, tool, tool_router, ServiceExt, transport::stdio};
use sha2::{Digest, Sha256};

// Tool input; field doc comments become descriptions in the generated JSON Schema
#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]
struct HashParams {
    /// Absolute path of the file to hash
    path: String,
}

// The server type; Clone lets rmcp hand a copy to each request
#[derive(Clone)]
struct Integrity;

// tool_router(server_handler) generates routing and the ServerHandler impl
#[tool_router(server_handler)]
impl Integrity {
    #[tool(description = "Compute the SHA-256 checksum of a local file")]
    fn sha256_file(&self, Parameters(HashParams { path }): Parameters<HashParams>) -> String {
        // Read the file and return a readable message on failure instead of panicking
        match std::fs::read(&path) {
            Ok(bytes) => format!("{:x}  {}", Sha256::digest(&bytes), path),
            Err(e) => format!("error reading {path}: {e}"),
        }
    }
}

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    // Serve over stdin/stdout and keep running until the host disconnects
    let service = Integrity.serve(stdio()).await?;
    service.waiting().await?;
    Ok(())
}
Step 3 · Build And Connect
bash • release compilation
# Compile a release binary, then hand its absolute path to Claude Code
cargo build --release
claude mcp add integrity -- /absolute/path/to/integrity-mcp/target/release/integrity-mcp

With the server registered, you can ask Claude to hash the installers in a folder and compare the results with published checksums. rmcp feature flags change between releases, so check the crate README if the build fails.

09How Claude uses MCP

Claude reaches MCP servers through three surfaces.

Claude Desktop and Claude Code

Both start local stdio servers and connect to remote HTTP servers. The Claude Code MCP reference documents claude mcp add with local, project and user scopes, a .mcp.json file a team can commit, OAuth sign-in through /mcp, and tool search, which loads tool definitions only when needed so a large set of servers doesn't fill the context window. Claude Code also offers an mcp-server-dev plugin whose build skill scaffolds a new server.

Anthropic's launch post noted that Claude 3.5 Sonnet could build MCP server implementations quickly. With today's tooling, Claude can write a server, Claude Code can register it, and Claude can then call its tools.

The Claude API MCP connector

For your own applications, the Claude API MCP connector documentation describes how the Messages API calls a remote MCP server directly, with no client code of your own. It currently supports tool calls only, requires a server reachable over public HTTPS, and lets you allowlist or denylist individual tools.

python • Messages API MCP Connector
import anthropic

client = anthropic.Anthropic()  # reads ANTHROPIC_API_KEY from the environment

response = client.beta.messages.create(
    model="claude-opus-5-5",
    max_tokens=1000,
    messages=[{"role": "user", "content": "Which of my monitored sites are down?"}],
    # Where the remote server lives and how to authenticate to it
    mcp_servers=[{
        "type": "url",
        "url": "https://mcp.example.com/mcp",
        "name": "web-inspector",
        "authorization_token": "YOUR_TOKEN",
    }],
    # Which of its tools Claude may use; here, all of them
    tools=[{"type": "mcp_toolset", "mcp_server_name": "web-inspector"}],
    betas=["mcp-client-2025-11-20"],
)
print(response.content)

What travels over the wire

The 2026-07-28 revision made the protocol stateless. WorkOS's breakdown of the stateless spec explains that the initialize handshake and the Mcp-Session-Id header were removed, so each request carries its own context. Cloudflare's next-generation MCP write-up adds that the new Mcp-Method and Mcp-Name headers let gateways route and rate-limit requests without parsing the JSON body.

Claude (model) Host MCP client Load balancer Any server instance External API 1. call inspect_page(url) POST /mcp Mcp-Method: tools/call 3. route by header, no sticky session 4. GET the page 5. 200 OK + HTML 6. result, carrying its own _meta 7. structured JSON 2026-07-28: no initialize handshake, no Mcp-Session-Id
Diagram 4: One stateless tool call from start to finish. Any server instance can handle any request, so an MCP server can sit behind an ordinary load balancer.

10Security risks and defenses

A server that can reach your database, inbox and cloud console also gives an attacker more to work with. SerpApi's review records more than thirty MCP-related CVEs filed in January and February 2026 and describes tool poisoning, where a server hides instructions inside a tool description, as a mainstream concern. The Claude Code docs tell users to verify that they trust each server, because servers that fetch external content can expose them to prompt injection.

The defenses in the sources above are ordinary security practice:

  • Read-only credentials: Give database servers read-only credentials, as the Claude Code docs do in their Postgres example.
  • Granular toolsets: Use the API's mcp_toolset to disable every tool by default and enable only the ones you name, or to deny destructive tools.
  • Code auditability: Prefer servers whose code you have read, including the ones you write yourself.
  • Idempotency keys: Add idempotency keys to tools that charge, send or provision, because WorkOS notes that the new spec removed stream resumability.
  • Gateway-level headers: Apply per-tool authorization at the gateway with the new routing headers, which avoids inspecting request bodies.

11Getting started

Pick one system you use often, wrap it with the SDK that matches your stack, and register it with claude mcp add. The three tutorials share one structure, so most of the work goes into the tool functions themselves.

When a local server proves useful, serve it over Streamable HTTP with OAuth so it can run behind a load balancer and the Claude API connector can reach it.

12References

  1. Anthropic, “Introducing the Model Context Protocol,” November 25, 2024. https://www.anthropic.com/news/model-context-protocol
  2. Anthropic, “Donating the Model Context Protocol and establishing the Agentic AI Foundation,” December 9, 2025. https://www.anthropic.com/news/donating-the-model-context-protocol-and-establishing-of-the-agentic-ai-foundation
  3. Model Context Protocol Blog, “MCP joins the Agentic AI Foundation,” December 9, 2025. https://blog.modelcontextprotocol.io/posts/2025-12-09-mcp-joins-agentic-ai-foundation/
  4. Model Context Protocol Blog, “Introducing the MCP Registry,” September 8, 2025. https://blog.modelcontextprotocol.io/posts/2025-09-08-mcp-registry-preview/
  5. Model Context Protocol, “SDKs (official SDK tiers).” https://modelcontextprotocol.io/docs/sdk
  6. Model Context Protocol, “Release 2026-07-28 (stable specification),” GitHub, July 28, 2026. https://github.com/modelcontextprotocol/modelcontextprotocol/releases/tag/2026-07-28
  7. MCP Python SDK (v2), GitHub repository. “Python SDK v2 on GitHub.” https://github.com/modelcontextprotocol/python-sdk
  8. MCP Python SDK docs, “Connect to a real host.” https://py.sdk.modelcontextprotocol.io/get-started/real-host/
  9. MCP TypeScript SDK (v2), GitHub repository. “TypeScript SDK v2 on GitHub.” https://github.com/modelcontextprotocol/typescript-sdk
  10. MCP Rust SDK (rmcp), GitHub repository. “Rust SDK rmcp on GitHub.” https://github.com/modelcontextprotocol/rust-sdk
  11. Hacker News, “Official Hacker News API,” GitHub repository. https://github.com/HackerNews/API
  12. Claude Code Docs, “Connect Claude Code to tools via MCP.” https://code.claude.com/docs/en/mcp
  13. Claude Platform Docs, “MCP connector.” https://platform.claude.com/docs/en/agents-and-tools/mcp-connector
  14. Claude Platform Docs, “MCP tunnels.” https://platform.claude.com/docs/agents-and-tools/mcp-tunnels/overview
  15. WorkOS, “MCP went stateless: What changed in the 2026-07-28 spec,” September 16, 2026. https://workos.com/blog/mcp-stateless-spec-2026-07-28
  16. Cloudflare Blog, “The next generation of MCP,” August 6, 2026. https://blog.cloudflare.com/mcp-v2/
  17. SerpApi, “The State of MCP: Everything That Changed in H1 2026,” June 3, 2026. https://serpapi.com/blog/the-state-of-mcp-everything-that-changed-in-h1-2026/

Build Enterprise-Grade MCP Servers & Agent Tooling

Architect type-safe Model Context Protocol servers in Python, TypeScript, and Rust connecting Claude to private VPC databases and microservices.

Free LinkedIn Consultation ↗ Start A Project → View Advisory Tiers →