MCP Operations

SkillMedia

Model Context Protocol server development, tool design, resource handling, and transport configuration. Use for: mcp, model context protocol, mcp server, mcp tool, mcp resource, fastmcp, mcp transport, stdio, sse, streamable http, mcp inspector, tool handler, mcp prompt.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the MCP Operations skill

What this skill tells your AI

The instructions your AI receives, as published by 0xdarkmatter/claude-mods in skills/mcp-ops/SKILL.md and read by ahel’s review.

Comprehensive patterns for building, testing, and deploying Model Context Protocol servers in Python and TypeScript.

Ecosystem facts verified as of 2026-07-05 (standalone FastMCP at major 3).

MCP Architecture Quick Reference

┌─────────────────────────────────────────────────────────┐
│                     MCP Host                            │
│  (Claude Desktop, Claude Code, Custom App)              │
│                                                         │
│  ┌───────────┐   ┌───────────┐   ┌───────────┐        │
│  │  Client A  │   │  Client B  │   │  Client C  │       │
│  └─────┬─────┘   └─────┬─────┘   └─────┬─────┘        │
└────────┼───────────────┼───────────────┼────────────────┘
         │               │               │
    ┌────┴────┐     ┌────┴────┐     ┌────┴────┐
    │Transport│     │Transport│     │Transport│
    │ (stdio) │     │  (SSE)  │     │ (HTTP)  │
    └────┬────┘     └────┬────┘     └────┬────┘
         │               │               │
┌────────┴──┐     ┌──────┴────┐   ┌──────┴────┐
│  Server A  │     │  Server B  │   │  Server C  │
│            │     │            │   │            │
│ ┌────────┐ │     │ ┌────────┐ │   │ ┌────────┐ │
│ │ Tools  │ │     │ │Resources│ │   │ │Prompts │ │
│ └────────┘ │     │ └────────┘ │   │ └────────┘ │
│ ┌────────┐ │     │ ┌────────┐ │   │ ┌────────┐ │
│ │Resources│ │     │ │Prompts │ │   │ │ Tools  │ │
│ └────────┘ │     │ └────────┘ │   │ └────────┘ │
└────────────┘     └────────────┘   └────────────┘

Protocol: JSON-RPC 2.0 over chosen transport
Flow:     Client → request → Server → response → Client

Server Type Decision Tree

What transport does your MCP server need?
│
├─ Local CLI tool / single-user desktop integration?
│  └─ stdio
│     - Simplest setup, no networking
│     - Claude Desktop, Claude Code native support
│     - Process lifecycle managed by host
│
├─ Web dashboard / browser-based client?
│  └─ SSE (Server-Sent Events)
│     - HTTP-based, works through firewalls
│     - Persistent connection for server→client events
│     - Good for development and internal tools
│
└─ Production API / multi-tenant / cloud deployment?
   └─ Streamable HTTP
      - HTTP POST for requests, SSE for streaming responses
      - Supports stateless and stateful modes
      - Full auth support, load balancer friendly
      - Recommended for production deployments

Tool vs Resource vs Prompt Decision Tree

What does the LLM need to do?
│
├─ Perform an action or computation?
│  └─ TOOL
│     - Has side effects (API calls, file writes, DB mutations)
│     - Accepts structured input, returns results
│     - Examples: run_query, create_issue, send_email
│
├─ Read data or context?
│  └─ RESOURCE
│     - Read-only data retrieval
│     - Identified by URI (file://, db://, api://)
│     - Examples: config://app, schema://users, file://readme.md
│
└─ Guide the LLM's behavior or workflow?
   └─ PROMPT
      - Templated instructions with arguments
      - Suggests conversation starters or workflows
      - Examples: code_review(language, file), summarize(topic)

Python SDK Quick Start

from mcp.server.fastmcp import FastMCP

mcp = FastMCP("my-server")

@mcp.tool()
def search_docs(query: str) -> str:
    """Search documentation by keyword."""
    results = perform_search(query)
    return "\n".join(f"- {r.title}: {r.snippet}" for r in results)

@mcp.tool()
def create_ticket(title: str, body: str, priority: str = "medium") -> str:
    """Create a support ticket."""
    ticket = api.create(title=title, body=body, priority=priority)
    return f"Created ticket #{ticket.id}: {ticket.url}"

@mcp.resource("config://app")
def get_config() -> str:
    """Return current application configuration."""
    return json.dumps(load_config(), indent=2)

@mcp.resource("schema://db/{table}")
def get_table_schema(table: str) -> str:
    """Return the schema for a database table."""
    return json.dumps(get_schema(table), indent=2)

@mcp.prompt()
def code_review(language: str, filepath: str) -> str:
    """Generate a code review prompt for the given file."""
    return f"Review this {language} code in {filepath} for bugs, style issues, and performance."

if __name__ == "__main__":
    mcp.run()  # Defaults to stdio transport

Install and run:

uv init my-mcp-server && cd my-mcp-server
uv add mcp[cli]
# Run with: uv run python server.py
# Or:       uv run mcp run server.py

Two Python FastMCPs — know which you're on. The official mcp SDK bundles a frozen 1.x-era FastMCP (from mcp.server.fastmcp import FastMCP, used in the samples above — stable, minimal). The standalone fastmcp package (gofastmcp.com) is where active development happens and is at major 3: same decorator surface, plus auth, proxying, OpenAPI generation, and a test client. To use it:

uv add fastmcp
from fastmcp import FastMCP   # standalone FastMCP 3 — not mcp.server.fastmcp

mcp = FastMCP("my-server")    # v3: constructor is identity/behaviour only;
                              # transport config moved to run()/serve time

FastMCP 3 breaking changes (from 2.x): 16 deprecated constructor kwargs removed (transport settings now passed at serve time), ui= replaced by app=, ctx.set_state()/ctx.get_state() are now async with session-scoped persistence, and the metadata namespace changed from _fastmcp to fastmcp.

TypeScript SDK Quick Start

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";

const server = new McpServer({
  name: "my-server",
  version: "1.0.0",
});

// Register a tool
server.tool(
  "search_docs",
  "Search documentation by keyword",
  { query: z.string().describe("Search query") },
  async ({ query }) => {
    const results = await performSearch(query);
    return {
      content: [{ type: "text", text: results.join("\n") }],
    };
  }
);

// Register a resource
server.resource(
  "config",
  "config://app",
  { description: "Current application configuration" },
  async (uri) => ({
    contents: [{
      uri: uri.href,
      mimeType: "application/json",
      text: JSON.stringify(loadConfig(), null, 2),
    }],
  })
);

// Register a prompt
server.prompt(
  "code_review",
  "Generate a code review prompt",
  { language: z.string(), filepath: z.string() },
  async ({ language, filepath }) => ({
    messages: [{
      role: "user",
      content: {
        type: "text",
        text: `Review this ${language} code in ${filepath} for bugs and style issues.`,
      },
    }],
  })
);

async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
}
main().catch(console.error);

Install and run:

npm init -y
npm install @modelcontextprotocol/sdk zod
npx tsx server.ts

Transport Selection Matrix

FeaturestdioSSEStreamable HTTP
Use caseLocal CLI tools, desktopWeb dashboards, devProduction APIs
Protocolstdin/stdout pipesHTTP + EventSourceHTTP POST + SSE
Auth supportEnv vars onlyBearer tokensFull OAuth2/PKCE
DeploymentLocal processSingle serverLoad balanced
ReconnectionProcess restartAuto-reconnectStateless resilient
Multi-client1:1 onlyMultiple clientsHorizontally scalable
FirewallN/A (local)HTTP-friendlyHTTP-friendly
StateProcess lifetimeConnection lifetimeSession or stateless
Best forClaude Desktop/CodeInternal toolsCloud/enterprise

Authentication Patterns Quick Reference

# Pattern 1: API keys from environment
import os
from mcp.server.fastmcp import FastMCP

mcp = FastMCP("api-server")

@mcp.tool()
def call_api(endpoint: str) -> str:
    """Call external API with configured credentials."""
    api_key = os.environ["MY_API_KEY"]  # Set in client config
    resp = httpx.get(f"https://api.example.com/{endpoint}",
                     headers={"Authorization": f"Bearer {api_key}"})
    return resp.text
# Pattern 2: OAuth2 token refresh (in-memory cache)
import time

_token_cache: dict = {}

async def get_valid_token() -> str:
    if _token_cache.get("expires_at", 0) > time.time() + 60:
        return _token_cache["access_token"]
    resp = await httpx.AsyncClient().post("https://auth.example.com/token", data={
        "grant_type": "refresh_token",
        "refresh_token": os.environ["REFRESH_TOKEN"],
        "client_id": os.environ["CLIENT_ID"],
    })
    data = resp.json()
    _token_cache.update({
        "access_token": data["access_token"],
        "expires_at": time.time() + data["expires_in"],
    })
    return data["access_token"]
// Claude Desktop config with env vars
{
  "mcpServers": {
    "my-server": {
      "command": "uv",
      "args": ["run", "--directory", "/path/to/server", "python", "server.py"],
      "env": {
        "MY_API_KEY": "sk-...",
        "DATABASE_URL": "postgresql://..."
      }
    }
  }
}

Common Gotchas

GotchaWhyFix
Tool not appearing in clientinputSchema has invalid JSON SchemaValidate schema with jsonschema library; use Pydantic/Zod to generate
Tool returns raw objectResults must be content list with typed itemsAlways return {"content": [{"type": "text", "text": "..."}]}
Timeout on long operationsDefault client timeout is often 30-60sAdd progress notifications; break into smaller operations
Concurrent requests failTool handler uses shared mutable stateUse asyncio locks, or make handlers stateless
Large response crashes clientMCP messages have practical size limitsPaginate results; return summaries with detail-fetch tools
Error swallowed silentlyException in handler returns generic errorSet isError: true in response; include error message in content
SSE connection dropsNo keep-alive or reconnection logicImplement heartbeat; client auto-reconnects on SSE
Client ignores new toolsCapabilities not updated after tool changeCall server.request_context.session.send_resource_list_changed()
Tool name collisionTwo servers register same tool nameNamespace tools: myserver_search not just search
Resource URI too genericdata://info is ambiguousUse specific schemes: db://myapp/users, config://myapp/settings
async def missing on handlerFastMCP tools can be sync or async, but I/O should be asyncUse async def for any handler doing network/file I/O
Server works locally, fails in Claude DesktopDifferent working directory or PATHUse absolute paths; log os.getcwd() on startup

Reference Files

FileLinesContent
references/server-architecture.md~700Server lifecycle, FastMCP/TS SDK setup, capabilities, middleware, error handling
references/tool-handlers.md~650Schema design, validation, return types, composition, side effects, examples
references/resources-prompts.md~550Resource URIs, static/dynamic resources, templates, prompts, subscriptions
references/transport-auth.md~550stdio/SSE/HTTP transports, session management, OAuth2, rate limiting, TLS
references/testing-debugging.md~550MCP Inspector, unit/integration testing, protocol debugging, CI, performance

Staleness verifier

This skill encodes fast-moving facts (the MCP SDK package names + spec URL). scripts/check-mcp-facts.py guards them against silent drift:

# Structural (PR CI, no network): every catalogued package's prose_token is
# still named in this skill's prose, the spec URL is still cited, and the
# currency note still carries a year.
python scripts/check-mcp-facts.py --offline        # exit 0 consistent, 10 drift

# Live (freshness job, never blocks a PR): each SDK still resolves on
# npm/PyPI, no tracked major has moved off the sampled major, spec URL 200.
python scripts/check-mcp-facts.py --live            # exit 10 drift, 7 registries unreachable

The canonical fact set lives in assets/mcp-facts.json; when you add or drop a package, update it to match or --offline fails CI.

See Also

Signals

GitHub stars
36
Forks
5
Last commit
Aug 2026
Advanced
Catalog kind
skill
Gateway key
mcp-ops
Source
github.com/0xdarkmatter/claude-mods