build-custom-mcp-server
关于
This skill guides developers in building custom MCP servers to expose domain-specific tools to AI assistants. It covers implementation in Node.js or R, including tool definition, transport setup, and testing in Claude Code. Use it when you need specialized integrations beyond standard tools, or to wrap existing APIs/services as MCP tools.
快速安装
Claude Code
推荐npx skills add pjt222/agent-almanac -a claude-code/plugin add https://github.com/pjt222/agent-almanacgit clone https://github.com/pjt222/agent-almanac.git ~/.claude/skills/build-custom-mcp-server在 Claude Code 中复制并粘贴此命令以安装该技能
技能文档
カスタムMCPサーバーの構築
AIアシスタントにドメイン固有のツールを公開するカスタムMCPサーバーを作成する。
使用タイミング
- Claude CodeまたはClaude Desktopにカスタム機能を公開する必要がある時
- mcptoolsが提供する以上の特化したツールを構築する時
- ドメイン固有のAIアシスタント統合を作成する時
- 既存のAPIやサービスをMCPツールとしてラップする時
入力
- 必須: 公開するツールのリスト(名前、説明、パラメータ、動作)
- 必須: 実装言語(Node.jsまたはR)
- 必須: トランスポートタイプ(stdioまたはHTTP)
- 任意: 認証要件
- 任意: Dockerパッケージングのニーズ
手順
ステップ1: ツール仕様の定義
コードを書く前に、各ツールを定義する:
tools:
- name: query_database
description: Execute a read-only SQL query against the analysis database
parameters:
query:
type: string
description: SQL SELECT query to execute
required: true
limit:
type: integer
description: Maximum rows to return
default: 100
returns: JSON array of result rows
- name: run_analysis
description: Execute a predefined statistical analysis by name
parameters:
analysis_name:
type: string
description: Name of the analysis to run
enum: [descriptive, regression, survival]
dataset:
type: string
description: Dataset identifier
required: true
期待結果: 各ツールのYAMLまたはmarkdown仕様。名前、説明、パラメータ(型、デフォルト、必須フラグを含む)、戻り値型がコードを書く前に文書化される。
失敗時: ツール仕様が不明確な場合、ドメイン専門家にインタビューするか、既存のAPIドキュメントをレビューしてパラメータの型と戻り値フォーマットを判定する。
ステップ2: Node.jsでの実装(MCP SDKを使用)
// server.js
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-analysis-server",
version: "1.0.0",
});
// Define tools
server.tool(
"query_database",
"Execute a read-only SQL query against the analysis database",
{
query: z.string().describe("SQL SELECT query"),
limit: z.number().default(100).describe("Max rows to return"),
},
async ({ query, limit }) => {
// Validate read-only
if (!/^\s*SELECT/i.test(query)) {
return {
content: [{ type: "text", text: "Error: Only SELECT queries allowed" }],
isError: true,
};
}
const results = await executeQuery(query, limit);
return {
content: [{ type: "text", text: JSON.stringify(results, null, 2) }],
};
}
);
server.tool(
"run_analysis",
"Execute a predefined statistical analysis",
{
analysis_name: z.enum(["descriptive", "regression", "survival"]),
dataset: z.string().describe("Dataset identifier"),
},
async ({ analysis_name, dataset }) => {
const result = await runAnalysis(analysis_name, dataset);
return {
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
};
}
);
// Start server with stdio transport
const transport = new StdioServerTransport();
await server.connect(transport);
期待結果: MCP SDKをインポートし、Zodスキーマでツールを定義し、stdioトランスポートで接続する動作するserver.jsファイル。node server.jsを実行するとエラーなしでサーバーが起動する。
失敗時: @modelcontextprotocol/sdkとzodがインストールされていることを確認する(npm install)。インポートパスがSDKバージョンと一致することを確認する(SDKはバージョン間でエクスポートを再構成した)。
ステップ3: Rでの実装(mcptoolsを使用)
# server.R
library(mcptools)
# Register custom tools
mcp_tool(
name = "query_database",
description = "Execute a read-only SQL query",
parameters = list(
query = list(type = "string", description = "SQL SELECT query"),
limit = list(type = "integer", description = "Max rows", default = 100)
),
handler = function(query, limit = 100) {
if (!grepl("^\\s*SELECT", query, ignore.case = TRUE)) {
stop("Only SELECT queries allowed")
}
result <- DBI::dbGetQuery(con, paste(query, "LIMIT", limit))
jsonlite::toJSON(result, auto_unbox = TRUE)
}
)
# Start server
mcptools::mcp_server()
期待結果: mcp_tool()でカスタムツールを登録し、mcp_server()でサーバーを起動する動作するserver.Rファイル。Rscript server.Rを実行するとMCPサーバーが起動する。
失敗時: mcptoolsがGitHubからインストールされていることを確認する(remotes::install_github("posit-dev/mcptools"))。ハンドラー関数のシグネチャがパラメータ定義と一致していることを確認する。
ステップ4: プロジェクト構造のセットアップ
my-mcp-server/
├── package.json # Node.js dependencies
├── server.js # Server implementation
├── tools/ # Tool implementations
│ ├── database.js
│ └── analysis.js
├── test/ # Tests
│ └── tools.test.js
├── Dockerfile # Container packaging
└── README.md # Setup instructions
期待結果: server.js(またはserver.R)、package.json、モジュラーなツール実装のためのtools/ディレクトリ、テスト用のtest/ディレクトリを含むプロジェクトディレクトリが作成される。
失敗時: ディレクトリ構造が実装言語と一致しない場合、適切に調整する。Rサーバーはtools/の代わりにR/を、test/の代わりにtests/testthat/を使用する場合がある。
ステップ5: サーバーのテスト
stdioでの手動テスト:
echo '{"jsonrpc":"2.0","method":"tools/list","id":1}' | node server.js
Claude Codeへの登録:
claude mcp add my-server stdio "node" "/path/to/server.js"
ツールの表示確認:
Claude Codeセッションを開始し、カスタムツールがリストされ機能することを確認する。
期待結果: tools/list JSON-RPC呼び出しが正しい名前とスキーマを持つすべての定義されたツールを返す。claude mcp listがサーバーの登録を表示する。Claude Codeセッションからツールが呼び出し可能。
失敗時: tools/listが空の配列を返す場合、ツールがserver.connect()の前に登録されていない。Claude Codeがサーバーを見つけられない場合、claude mcp addのコマンドパスが絶対パスでバイナリが実行可能であることを確認する。
ステップ6: エラーハンドリングの追加
server.tool("risky_operation", "...", schema, async (params) => {
try {
const result = await performOperation(params);
return {
content: [{ type: "text", text: JSON.stringify(result) }],
};
} catch (error) {
return {
content: [{ type: "text", text: `Error: ${error.message}` }],
isError: true,
};
}
});
期待結果: 各ツールハンドラーがtry/catchでラップされている。無効な入力はサーバープロセスをクラッシュさせるのではなく、説明的なメッセージ付きのisError: trueを返す。
失敗時: 不正な入力でサーバーがまだクラッシュする場合、try/catchが非同期操作を含むハンドラー本体全体をラップしていることを確認する。promiseがtryブロック内でawaitされていることを確認する。
ステップ7: 配布用パッケージング
binエントリ付きのpackage.jsonを作成する:
{
"name": "my-mcp-server",
"version": "1.0.0",
"bin": {
"my-mcp-server": "./server.js"
},
"dependencies": {
"@modelcontextprotocol/sdk": "^1.0.0",
"zod": "^3.22.0"
}
}
ユーザーはインストールと設定が可能:
npm install -g my-mcp-server
claude mcp add my-server stdio "my-mcp-server"
期待結果: サーバーエントリポイントを指すbinエントリ付きのpackage.json。ユーザーはnpm install -gでグローバルインストールし、claude mcp addで登録できる。
失敗時: グローバルインストール後にbinエントリが動作しない場合、server.jsにシバン行(#!/usr/bin/env node)があり実行可能としてマークされていることを確認する。パッケージ名が既存のnpmパッケージと競合しないことを確認する。
バリデーション
- サーバーがエラーなしで起動する
-
tools/listが正しいスキーマを持つすべての定義されたツールを返す - 各ツールが有効な入力で正しく実行される
- ツールが無効な入力に対して適切なエラーを返す
- サーバーがstdioトランスポートでClaude Codeと動作する
- ツールがClaudeセッションで検出可能かつ使用可能
よくある落とし穴
- ブロッキング操作: MCPサーバーはリクエストを非同期で処理すべき。長時間実行される操作は他のツール呼び出しをブロックする
- エラーハンドリングの欠如: 未処理の例外はサーバーをクラッシュさせる。常にツールハンドラーをtry/catchでラップする
- スキーマの不一致: ツールパラメータスキーマはハンドラーが期待するものと正確に一致しなければならない
- stdioバッファリング: stdioトランスポートを使用する時、出力がフラッシュされることを確認する。Node.jsはデフォルトでstdoutをバッファリングする
- セキュリティ: MCPサーバーはプロセスと同じアクセス権を持つ。入力を慎重に検証する、特にシェルコマンドやデータベースクエリ
関連スキル
configure-mcp-server-- 構築したサーバーをクライアントに接続するtroubleshoot-mcp-connection-- 接続性の問題をデバッグするcontainerize-mcp-server-- サーバーをDockerでパッケージングする
GitHub 仓库
相关推荐技能
content-collections
元Content Collections 是一个 TypeScript 优先的构建工具,可将本地 Markdown/MDX 文件转换为类型安全的数据集合。它专为构建博客、文档站和内容密集型 Vite+React 应用而设计,提供基于 Zod 的自动模式验证。该工具涵盖从 Vite 插件配置、MDX 编译到生产环境部署的完整工作流。
polymarket
元这个Claude Skill为开发者提供完整的Polymarket预测市场开发支持,涵盖API调用、交易执行和市场数据分析。关键特性包括实时WebSocket数据流,可监控实时交易、订单和市场动态。开发者可用它构建预测市场应用、实施交易策略并集成实时市场预测功能。
creating-opencode-plugins
元该Skill帮助开发者创建OpenCode插件,用于接入命令、文件、LSP等25+种事件。它提供了插件结构、事件API规范和JavaScript/TypeScript实现模式,适合需要拦截操作、扩展功能或自定义事件处理的场景。开发者可通过它快速构建响应式模块来增强OpenCode AI助手的能力。
sglang
元SGLang是一个专为LLM设计的高性能推理框架,特别适用于需要结构化输出的场景。它通过RadixAttention前缀缓存技术,在处理JSON、正则表达式、工具调用等具有重复前缀的复杂工作流时,能实现极速生成。如果你正在构建智能体或多轮对话系统,并追求远超vLLM的推理性能,SGLang是理想选择。
