Skip to content
OpenSmartRoute
Skillv1.0.0

mcp-builder

Guide developers in creating Model Context Protocol (MCP) servers. Use for building MCP tools that enable LLMs to interact with external services. Covers TypeScript (primary) and Python FastMCP (secon

by oimiragieo(0) 0 installs
Free
Sign in to install

Free account. Installing gives you the manifest plus copy-paste snippets.

See reviews

About

Imported from oimiragieo/agent-studio (.claude/skills/mcp-builder/SKILL.md). Install upstream with npx skills add oimiragieo/agent-studio --skill mcp-builder. Copyright stays with the author.

MCP Server Development Guide

"The quality of an MCP server is measured by how well it enables LLMs to accomplish real-world tasks."

Overview

This skill guides you through creating Model Context Protocol (MCP) servers — tools that enable LLMs to interact with external services. MCP servers expose capabilities as typed tools that agents can discover and invoke.

When to Invoke

  • User asks to "build an MCP server" or "create MCP tools"
  • Integrating an external API with Claude
  • Exposing local system capabilities (files, databases, services) to an agent
  • Creating tools for an agent to call

Four-Phase Development Workflow

Phase 1: Deep Research and Planning

Before writing any code, understand the target API or service thoroughly.

  1. Study MCP protocol documentation

    • Visit https://modelcontextprotocol.io/sitemap.xml for current docs
    • Understand tool definitions, resource types, and prompt patterns
  2. Analyze the target service

    • What operations does the API support?
    • Which operations are read-only vs destructive?
    • What are the authentication requirements?
    • What are the rate limits and pagination patterns?
  3. Design tool coverage

    • Balance: API coverage (breadth) vs workflow tools (depth, combining multiple API calls)
    • Prefer workflow tools for common agent tasks
    • Design tool names as snake_case verb-noun pairs: get_user, create_issue, list_repos
  4. Choose transport

    • Remote servers: Streamable HTTP transport
    • Local servers: stdio transport
    • Default to stdio unless there's a specific need for HTTP

Phase 2: Implementation

Language Selection

TypeScript (recommended) — high-quality SDK, strong type safety, better IDE support:

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-service',
  version: '1.0.0',
});

Python (FastMCP) — simpler syntax, good for Python-native services:

from mcp.server.fastmcp import FastMCP
from pydantic import BaseModel

mcp = FastMCP("my-service")

Project Structure (TypeScript)

mcp-server/
├── src/
│   ├── index.ts          # Server entry point
│   ├── client.ts         # API client + auth
│   ├── tools/
│   │   ├── read.ts       # Read-only tools
│   │   └── write.ts      # Mutating tools
│   └── utils/
│       ├── pagination.ts
│       └── errors.ts
├── package.json
├── tsconfig.json
└── README.md

Tool Annotations (MANDATORY)

Every tool MUST declare intent annotations:

server.tool(
  'get_repository',
  'Fetch a GitHub repository by owner and name',
  {
    owner: z.string().describe('Repository owner (username or org)'),
    repo: z.string().describe('Repository name'),
  },
  {
    // Annotations
    readOnlyHint: true, // Does not modify external state
    destructiveHint: false, // Not destructive
    idempotentHint: true, // Safe to call multiple times
    openWorldHint: true, // Makes external network calls
  },
  async ({ owner, repo }) => {
    // implementation
  }
);

Annotation reference:

Annotation Type Meaning
readOnlyHint boolean Does not modify external state
destructiveHint boolean May destroy data irreversibly
idempotentHint boolean Multiple identical calls have same effect
openWorldHint boolean Interacts with external systems (network, disk)

Input Validation with Zod (TypeScript)

// Good: explicit, descriptive schemas
const schema = {
  query: z.string().min(1).max(500).describe('Search query'),
  limit: z.number().int().min(1).max(100).default(20).describe('Max results'),
  cursor: z.string().optional().describe('Pagination cursor from previous call'),
};

Input Validation with Pydantic (Python)

from pydantic import BaseModel, Field
from typing import Optional

class SearchParams(BaseModel):
    query: str = Field(..., min_length=1, max_length=500, description="Search query")
    limit: int = Field(20, ge=1, le=100, description="Max results")
    cursor: Optional[str] = Field(None, description="Pagination cursor")

Response Format

Include both text (for human-readable output) and structured data (for agent parsing):

return {
  content: [
    {
      type: 'text',
      text: `Found ${results.length} results for "${query}"`,
    },
    {
      type: 'text',
      text: JSON.stringify(results, null, 2),
    },
  ],
};

Shared Utilities

Always build these utilities before implementing tools:

  1. API client — centralized HTTP client with auth headers, retry logic
  2. Error handler — converts API errors to MCP-safe error messages
  3. Pagination helper — cursor/offset/page-based pagination abstraction

Error Handling Pattern

try {
  const result = await apiClient.getResource(id);
  return { content: [{ type: 'text', text: JSON.stringify(result) }] };
} catch (error) {
  if (error instanceof NotFoundError) {
    return {
      content: [{ type: 'text', text: `Resource ${id} not found` }],
      isError: true,
    };
  }
  throw error; // Re-throw unexpected errors
}

Phase 3: Review and Test

Code Review Checklist

  • DRY: No duplicated API call logic across tools
  • All tools have meaningful descriptions
  • All inputs have describe() annotations
  • All tools have intent annotations (readOnlyHint etc.)
  • Error messages are user-friendly, not stack traces
  • TypeScript: full type coverage, no any types
  • Python: all functions typed, Pydantic models for inputs

Build Verification

TypeScript:

npm run build            # Must succeed with 0 errors
npx tsc --noEmit        # Type-check without output

Python:

python -m py_compile src/server.py   # Syntax check
mypy src/                             # Type check

Testing with MCP Inspector

# TypeScript
npx @modelcontextprotocol/inspector node dist/index.js

# Python
npx @modelcontextprotocol/inspector python src/server.py

Use MCP Inspector to:

  1. Verify all tools appear with correct descriptions
  2. Test each tool with sample inputs
  3. Verify error handling with invalid inputs
  4. Check response format is parseable

Phase 4: Create Evaluations

Design 10 independent evaluation questions per server. These test whether the MCP server enables real-world tasks.

Evaluation question requirements:

  • Each question is independent (no prior context needed)
  • Questions use realistic scenarios an agent would encounter
  • Questions are specific enough to have verifiable answers
  • Mix of simple (1 tool call) and compound (2-3 tool calls) tasks
  • At least 3 questions test read-only operations
  • At least 2 questions test error handling

Output format:

<evaluations>
  <question id="1">
    <task>Get the description of the 'anthropics/claude-code' repository</task>
    <expected_tools>get_repository</expected_tools>
    <answer>Claude Code is Anthropic's official CLI for Claude</answer>
  </question>
  <question id="2">
    <task>List the open issues labeled 'bug' in 'anthropics/claude-code', limit to 5</task>
    <expected_tools>list_issues</expected_tools>
    <answer>Returns up to 5 open issues with 'bug' label</answer>
  </question>
  <!-- ... 8 more questions -->
</evaluations>

Memory Protocol

Before starting MCP server development:

cat .claude/context/memory/learnings.md | grep -i "mcp\|model context"
cat .claude/context/memory/issues.md | grep -i "mcp\|model context"

After completing the server, record findings:

  • Working patterns → .claude/context/memory/learnings.md
  • API integration gotchas → .claude/context/memory/issues.md
  • Architecture decisions → .claude/context/memory/decisions.md

Official MCP Server Templates

The modelcontextprotocol/servers repository provides production-ready reference implementations. Use these as starting templates before building custom servers.

PostgreSQL MCP Server

# Install and run directly
npx -y @modelcontextprotocol/server-postgres postgresql://localhost/mydb

Claude Desktop config:

{
  "mcpServers": {
    "postgres": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-postgres", "postgresql://localhost/mydb"]
    }
  }
}

Tools provided: query (read-only SQL), list_tables, describe_table

Key implementation patterns from the reference server:

// Read-only query tool pattern
server.tool(
  'query',
  'Run a read-only SQL query',
  { sql: z.string().describe('SQL SELECT statement') },
  { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
  async ({ sql }) => {
    // Enforce read-only by setting transaction to read-only
    const result = await pool.query('BEGIN READ ONLY; ' + sql + '; COMMIT');
    return {
      content: [{ type: 'text', text: JSON.stringify(result.rows, null, 2) }],
    };
  }
);

SQLite MCP Server

# Install and run
npx -y @modelcontextprotocol/server-sqlite /path/to/database.db

Claude Desktop config:

{
  "mcpServers": {
    "sqlite": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-sqlite", "/path/to/database.db"]
    }
  }
}

Tools provided: read_query, write_query, create_table, list_tables, describe_table, insert_row, delete_rows

Schema introspection pattern:

server.tool(
  'describe_table',
  'Get the schema for a table',
  { table_name: z.string().describe('Name of the table') },
  { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
  async ({ table_name }) => {
    const rows = db.prepare(`PRAGMA table_info(?)`).all(table_name);
    return {
      content: [{ type: 'text', text: JSON.stringify(rows, null, 2) }],
    };
  }
);

Filesystem MCP Server

npx -y @modelcontextprotocol/server-filesystem /allowed/path

Tools provided: read_file, write_file, list_directory, create_directory, move_file, search_files, get_file_info

Path safety pattern (copy this for any filesystem tool):

function validatePath(requestedPath: string, allowedDir: string): string {
  const resolved = path.resolve(requestedPath);
  if (!resolved.startsWith(path.resolve(allowedDir))) {
    throw new Error(`Path ${requestedPath} is outside allowed directory`);
  }
  return resolved;
}

GitHub MCP Server

npx -y @modelcontextprotocol/server-github
# Requires: GITHUB_PERSONAL_ACCESS_TOKEN env var

Tools provided: create_repository, get_file_contents, push_files, create_issue, create_pull_request, search_repositories, search_code, fork_repository, list_commits

When to Use Official Servers vs Custom

Scenario Use Official Server Build Custom
Standard PostgreSQL/SQLite access YES No
GitHub repo operations YES No
Custom API integration No YES
Business-specific logic No YES
Combining multiple APIs No YES
Existing service with SDK No YES

Common Pitfalls

Pitfall Description Fix
Missing annotations Tools without readOnlyHint etc. Always declare all 4 annotations
Overly broad tools do_everything(action, params) One tool per distinct operation
Missing input descriptions query: z.string() Always add .describe()
Leaking auth tokens in errors Logging API key in error message Sanitize error messages
No pagination Returning all results at once Add cursor/limit to list operations
Blocking event loop Synchronous I/O in Node.js Always use async/await

Cross-IDE Agent Detection (Inspired by Skill_Seekers AgentDetector)

After building an MCP server, auto-detect which AI coding agents are installed on the user's system and generate the correct configuration for each. This eliminates the manual "copy this JSON into your settings" step.

Supported agents and their config locations:

Agent Transport Config Path (Windows) Config Path (macOS/Linux)
Claude Code stdio ~/.claude.json ~/.claude.json
Cursor HTTP %APPDATA%\Cursor\mcp_settings.json ~/Library/Application Support/Cursor/mcp_settings.json
Windsurf HTTP %APPDATA%\Windsurf\mcp_config.json ~/Library/Application Support/Windsurf/mcp_config.json
VS Code + Cline stdio %APPDATA%\Code\User\globalStorage\saoudrizwan.claude-dev\settings\cline_mcp_settings.json ~/.config/Code/User/globalStorage/...
IntelliJ IDEA HTTP %APPDATA%\JetBrains\IntelliJIdea2024.3\mcp.xml ~/Library/Application Support/JetBrains/...

Detection protocol:

  1. Check if each config file exists at the platform-appropriate path
  2. For each detected agent, generate the MCP server config snippet in the agent's format
  3. Present all detected agents to the user with one-click install instructions
  4. For agents using HTTP transport, include the default port and health check URL

Config generation template (Claude Code stdio example):

{
  "mcpServers": {
    "<server-name>": {
      "command": "node",
      "args": ["<path-to-server>/dist/index.js"],
      "env": {}
    }
  }
}

This step should be part of Phase 4 (Testing & Deployment) — after the server is built and tested, offer to install it into all detected agents.

Reference Documentation

  • MCP Protocol: https://modelcontextprotocol.io/
  • TypeScript SDK: https://github.com/modelcontextprotocol/typescript-sdk
  • Python SDK: https://github.com/modelcontextprotocol/python-sdk
  • FastMCP: https://github.com/jlowin/fastmcp
  • MCP Inspector: npx @modelcontextprotocol/inspector

Related Skills

  • typescript-expert — TypeScript type system, SDK patterns
  • api-development-expert — REST API design, authentication patterns
  • tdd — Test-driven development for MCP tool testing
  • verification-before-completion — Pre-completion quality gates

Use it

Copy one of these into your project. Installing also returns the manifest and these snippets.

yaml
targets:
  - https://api.opensmartroute.ai/api/v1/registry/oimiragieo-agent-studio-mcp-builder/manifest   # or paste the manifest below

Manifest

An Open Capability Manifest: the router reads it to know what this does, what it costs and when to pick it.

oimiragieo-agent-studio-mcp-builder.ocm.jsonjson
{
  "ocm": "1",
  "id": "oimiragieo-agent-studio-mcp-builder",
  "kind": "skill",
  "name": "mcp-builder",
  "description": "Guide developers in creating Model Context Protocol (MCP) servers. Use for building MCP tools that enable LLMs to interact with external services. Covers TypeScript (primary) and Python FastMCP (secondary), tool annotations, Zod/Pydantic validation, and evaluation question creation.",
  "publisher": "oimiragieo",
  "version": "1.0.0",
  "capabilities": {
    "domains": [
      "coding"
    ],
    "tags": [
      "skill-md",
      "mcp",
      "model-context-protocol",
      "typescript",
      "python",
      "api-integration",
      "tools",
      "skills-sh"
    ],
    "languages": [
      "en"
    ]
  },
  "quality_prior": 0.6,
  "examples": [
    "Guide developers in creating Model Context Protocol (MCP) servers. Use for building MCP tools that enable LLMs to interact with external services. Covers TypeScript (primary) and Python FastMCP (secondary), tool annotations, Zod/Pydantic validation, and evaluation question creation."
  ],
  "primary": false,
  "metadata": {
    "source": {
      "provider": "skills.sh",
      "repository": "https://github.com/oimiragieo/agent-studio",
      "path": ".claude/skills/mcp-builder/SKILL.md",
      "ref": "HEAD",
      "url": "https://github.com/oimiragieo/agent-studio/blob/HEAD/.claude/skills/mcp-builder/SKILL.md",
      "key": "oimiragieo/agent-studio/.claude/skills/mcp-builder/SKILL.md"
    }
  },
  "instructions": "# MCP Server Development Guide\n\n> \"The quality of an MCP server is measured by how well it enables LLMs to accomplish real-world tasks.\"\n\n## Overview\n\nThis skill guides you through creating Model Context Protocol (MCP) servers — tools that enable LLMs to interact with external services. MCP servers expose capabilities as typed tools that agents can discover and invoke.\n\n## When to Invoke\n\n- User asks to \"build an MCP server\" or \"create MCP tools\"\n- Integrating an external API with Claude\n- Exposing local system capabilities (files, databases, services) to an agent\n- Creating tools for an agent",
  "cost": {
    "context_tokens": 3913
  }
}

Fetch it by URL: GET /api/v1/registry/oimiragieo-agent-studio-mcp-builder/manifest?version=1.0.0

Reviews

Star ratings from people who tried it. One review per account; edit yours any time.

No reviews yet. Install it, try it, and be the first to rate it.