MCP 助手
- 作者仓库星标 0
- 作者仓库 skills-registry
MCP Server Development
Guide for designing and building MCP (Model Context Protocol) servers that connect Claude to external tools, APIs, and data sources.
Overview
MCP servers bridge Claude with external systems using a standardized protocol. Three primitives are available:
| Primitive | Controlled By | Purpose |
|---|---|---|
| Tools | Model (Claude) | Functions Claude can invoke |
| Resources | Application | Contextual data Claude can read |
| Prompts | User | Templates users can invoke |
Phase 1: Discovery
Before coding, understand the use case. Ask these questions:
1. What does it connect to?
| Connection Type | Recommended Approach |
|---|---|
| Cloud API (SaaS, REST, GraphQL) | Remote HTTP server |
| Local process, filesystem, desktop app | MCPB or local stdio |
| Hardware, OS-level APIs | MCPB |
| Pure logic/computation | Either - default to remote |
2. Who will use it?
- Just me / my team → Local stdio acceptable
- Anyone who installs it → Remote HTTP (preferred) or MCPB
- Claude desktop with UI widgets → MCP app
3. How many distinct actions?
- Under ~15 actions → One tool per action
- Dozens to hundreds → Search + execute pattern
4. Does a tool need user input mid-call?
- Simple forms (pick, enter, confirm) → Elicitation (spec-native)
- Rich UI (charts, search, dashboards) → MCP app widgets
- Neither → Plain tool returning text/JSON
5. What authentication does the service use?
- None / API key → Straightforward
- OAuth 2.0 → Remote server with CIMD or DCR support
Phase 2: Recommend Deployment Model
Based on discovery answers, recommend ONE path:
⭐ Remote HTTP Server (Default)
Hosted service speaking MCP over streamable HTTP. Best for cloud API wrappers.
Benefits:
- Zero install friction - users add a URL
- One deployment serves all users
- OAuth flows work properly
- Works across Claude desktop, Claude Code, Claude.ai
Choose unless server must touch local machine.
MCPB (Bundled Local Server)
Local server packaged with its runtime. No Node/Python needed on user machine.
Choose when server must run on user's machine:
- Reads local files
- Drives desktop apps
- Talks to localhost services
- Needs OS-level access
Local stdio (Prototypes Only)
Script launched via npx / uvx. Fine for personal tools and prototypes.
Not recommended for distribution - users need runtime, no update mechanism.
Phase 3: Pick Tool Design Pattern
Pattern A: One Tool Per Action (Small Surface)
When action space is small (< ~15 operations), each gets a dedicated tool.
create_issue — Create a new issue
update_issue — Update an existing issue
search_issues — Search issues by query
add_comment — Add a comment
Benefits: Claude reads tool list once, knows exactly what's possible.
Pattern B: Search + Execute (Large Surface)
When wrapping large APIs (dozens+ endpoints), use TWO tools:
search_actions — Return matching actions with IDs and schemas
execute_action — Run an action by ID with params
Benefits: Server holds catalog internally, context stays lean.
Hybrid: Promote 3-5 most-used actions to dedicated tools.
Phase 4: Pick Framework
| Framework | Language | When to Use |
|---|---|---|
| FastMCP 3.x | Python | Python preference, wrapping Python libraries |
| TypeScript SDK | TypeScript | Default choice, best spec coverage |
Both produce identical wire protocol.
Phase 5: Scaffold Server
FastMCP (Python)
from fastmcp import FastMCP
mcp = FastMCP("server-name")
@mcp.tool
def my_tool(query: str) -> dict:
"""Tool description Claude sees."""
return process(query)
if __name__ == "__main__":
mcp.run() # stdio (default)
# mcp.run(transport="http", port=8000) # HTTP
TypeScript SDK
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
const server = new McpServer({
name: "server-name",
version: "1.0.0"
});
server.tool("myTool", { query: z.string() }, async ({ query }) => ({
content: [{ type: "text", text: JSON.stringify(process(query)) }]
}));
server.connect(transport);
Phase 6: Test and Publish
Testing
# MCP Inspector - official testing tool
npx @modelcontextprotocol/inspector uv run python -m my_mcp
Critical: Log to stderr, NOT stdout (stdout is the protocol).
Testing Before Release:
- Test ALL tools with MCP Inspector before releasing
- Test with actual provider (e.g., real IMAP server) if wrapping external APIs
- Verify environment variables are passed correctly
- Check provider-specific quirks (see Provider Quirks section)
Claude Code Plugin Deployment
When bundling MCP servers in Claude Code plugins:
The cwd Bug (Issue #17565)
CRITICAL: Claude Code ignores the cwd field in .mcp.json. Always use the bash -c workaround:
{
"mcpServers": {
"my-server": {
"command": "bash",
"args": ["-c", "cd \"${CLAUDE_PLUGIN_ROOT}/my-server\" && exec uv run python -m my_mcp"]
}
}
}
Dependency Management
Use uv run for portable dependency management:
"command": "bash",
"args": ["-c", "cd \"${CLAUDE_PLUGIN_ROOT}/server\" && exec uv run python -m server"]
This ensures dependencies are automatically installed from pyproject.toml.
Environment Variables
Only include required environment variables in .mcp.json. Optional variables should use defaults in code:
# Bad - will fail if EMAIL_OAUTH2_TOKEN is empty
oauth2_token: str = Field(alias="OAUTH2_TOKEN")
# Good - optional with default
oauth2_token: str | None = Field(default=None, alias="OAUTH2_TOKEN")
For Pydantic settings, use env_parse_none_str="" to treat empty strings as None:
model_config = SettingsConfigDict(
env_prefix="MY_",
env_parse_none_str="", # Empty strings become None
)
Provider Quirks
When wrapping external services, test with the actual provider:
| Provider | Quirk | Solution |
|---|---|---|
| iCloud IMAP | SEARCH returns status message instead of IDs | Check for "completed" in response |
| iCloud IMAP | LIST requires specific quoting | Use list('""', '"*"') |
| iCloud IMAP | FETCH returns bytearray | Handle both bytes and bytearray |
Pre-submission Checklist
- Read/write tool split for destructive operations
- Required annotations on all tools
- Tool names under 128 characters
- No prompt injection in tool output
- Input validation on all parameters
- Tested with MCP Inspector
- Tested with actual provider (not just mocks)
Distribution
- Submit to Anthropic Directory
- Create plugin wrapper for skills
- Document installation clearly
- Require
uvfor dependency management
Security Essentials
| Priority | Practice |
|---|---|
| CRITICAL | Use stdio for local servers (no network) |
| CRITICAL | Require TLS for remote servers |
| CRITICAL | Validate all inputs (types, ranges, formats) |
| CRITICAL | Reject path traversal (../) |
| CRITICAL | Load credentials from environment only |
| CRITICAL | Never return secrets in tool output |
| HIGH | Run as non-root user |
| HIGH | Use argument lists, never shell strings |
Additional Resources
Reference Files
Consult these for detailed implementation guidance:
references/fastmcp-patterns.md— FastMCP decorator patterns, type hints, context injectionreferences/security-best-practices.md— Input validation, credential management, path traversal preventionreferences/testing-debugging.md— MCP Inspector, stderr logging, CI/CD integrationreferences/deployment-options.md— stdio, HTTP/SSE, Cloudflare Workers, Docker, MCPB
External Links
<!-- tomevault:4.0:skill_md:2026-05-23 -->Source: christophevg/c3 — distributed by TomeVault.
- 流狐分类
- 运维部署
- 作者声明 Agent
- 未找到明确声明;不据此推断已兼容或已测试
- 静态检查
- 88 / 100 · 启发式扫描,不代表运行安全
- 作者 / 版本 / 许可
- @tomevault-io · 未声明 license
- 流狐 Token 估算
- 低消耗
- 流狐接入估算
- 需手动接入
- 是否需要外部 API Key
- 需要 · Vendor-specific
- 检测到的系统要求
- Docker
- 底层运行要求
- Node.js · Python · Docker
- 检测到的文件与系统行为
-
- 只读
- 允许写入 / 修改
- Shell 执行
- 读取环境变量
- 检测到的网络行为
- 允许外网请求
- 安装命令数
- 无(仅作为资料)
档案由构建时根据 SKILL.md 与安装命令自动衍生,可能与作者实际意图存在差异。
需要注意: 未限定 allowed-tools,默认拥有全部工具权限。
作者没有在当前 SKILL.md 中定义固定输出样例。 Before coding, understand the use case. Ask these questions:
Based on discovery answers, recommend ONE path:
# MCP Server Development
Guide for designing and building MCP (Model Context Protocol) servers that connect Claude to external tools, APIs, and data sources.
## Overview
MCP servers bridge Claude with external systems using a standardized protocol. Three primitives are available:
| Primitive | Controlled By | Purpose |
|-----------|---------------|---------|
| **Tools** | Model (Claude) | Functions Claude can invoke |
| **Resources** | Application | Contextual data Claude can read |
| **Prompts** | User | Templates users can invoke |
---
## Phase 1: Discovery
Before coding, understand the use case. Ask these questions:
### 1. What does it connect to?
| Connection Type | Recommended Approach |
|-----------------|----------------------|
| Cloud API (SaaS, REST, GraphQL) | Remote HTTP server |
| Local process, filesystem, desktop app | MCPB or local stdio |
| Hardware, OS-level APIs | MCPB |
| Pure logic/computation | Either - default to remote |
### 2. Who will use it?
- **Just me / my team** → Local stdio acceptable
- **Anyone who installs it** → Remote HTTP (preferred) or MCPB
- **Claude desktop with UI widgets** → MCP app
### 3. How many distinct actions?
- **Under ~15 actions** → One tool per action
- **Dozens to hundreds** → Search + execute pattern
### 4. Does a tool need user input mid-call?
- **Simple forms (pick, enter, confirm)** → Elicitation (spec-native)
- **Rich UI (charts, search, dashboards)** → MCP app widgets
- **Neither** → Plain tool returning text/JSON
### 5. What authentication does the service use?
- None / API key → Straightforward
- OAuth 2.0 → Remote server with CIMD or DCR support
---
## Phase 2: Recommend Deployment Model
Based on discovery answers, recommend ONE path:
### ⭐ Remote HTTP Server (Default)
… 作者原文负责流程事实;流狐只索引当前章节、要点、文件与命令。
章节 -> Overview → Phase 1: Discovery → 1. What does it connect to? → 2. Who will use it? → 3. How many distinct actions? → 4. Does a tool need user input mid-call?
要点 -> Tools · Resources · Prompts · Just me / my team · Anyone who installs it · Claude desktop with UI widgets · Under ~15 actions · Dozens to hundreds
文件/命令 -> npx · uvx · cwd · .mcp.json · bash -c · uv run · pyproject.toml · envparsenonestr=""
内容 SHA-256 -> 615bf40b8f20
方法与流程
适用与边界
原文中的明确线索
npx、uvx、cwd、.mcp.json、bash -c、uv run、pyproject.toml、envparsenonestr=""