Google Cloud Next 25でGCPがMCP (Model Context Protocol) を取り入れているのを見て、今更ながらMCPを勉強してみました。
本記事は、勉強過程の記録です。
STEP1: MCPサーバの概要を学ぶ
下記の「松尾研究所テックブログ」が分かりやすかったです。
STEP2: 公開されているMCP Serverをたててみる
MCPサーバ
公開されているMCPサーバは主に以下2種類に大別されます。
私はDockerを用いてサーバをたてており、サーバごとにコンテナを分けています。
TypeScript製・Python製いずれもDockerコンテナで立ちあげてしまえば、サーバごとに環境を分離できて便利です。
下記に実際にたてたMCPサーバを記載します。
MCPクライアント
MCPクライアントにはClaude Desktopを利用しました。
MCPの設定を記載するclaude_desktop_config.json
のパスはMac OSでは/Users//Library/Application Support/Claude/claude_desktop_config.json
です。
実際にたてたMCPサーバ
Anthoropic公式 MCPサーバ (Filesystem MCP Server)
GitHubリポジトリ:
解説記事:
GitHub
解説記事:
GitHubリポジトリ:
AWS Documentation MCP Server
解説記事:
公式ページ:
Notion
解説記事:
GitHubリポジトリ:
LINE
解説記事:
GitHubリポジトリ:
STEP3: MCPサーバを作って学ぶ
基本、下記Anthoropic公式Quick Startが参考になります。
Python
FastMCP
を利用します。
前提:
Claude Desktopアプリは立ち上がっていない状態
手順:
- 下記の通り各種ファイルを作成
- プロジェクトのルートディレクトリ (
Dockerfile
と同じ階層) でdocker build -t my-mcp-server-python .
を実行し、Docker image作成 - Claude Desktopを立ち上げる
ディレクトリ構造
.
├── Dockerfile
├── app.py
└── pyproject.toml
Dockerfile
FROM python:3.12-slim-bookworm
WORKDIR /app
COPY pyproject.toml ./
COPY app.py ./
RUN pip install uv
RUN uv venv
RUN . .venv/bin/activate
RUN uv add "mcp[cli]"
CMD ["uv", "run", "app.py"]
pyproject.toml
[project]
name = "my-mcp-server-python"
version = "0.1.0"
dependencies = [
"mcp[cli]"
]
app.py
# server.py
from mcp.server.fastmcp import FastMCP
# Create an MCP server with debug enabled
mcp = FastMCP("my-mcp-server-python", debug=True)
# Add an addition tool
@mcp.tool()
def add(a: int, b: int) -> int:
"""Add two numbers"""
return a + b
# Add this part to run the server
if __name__ == "__main__":
# stdioトランスポートを使用
print("Starting MCP server in stdio mode")
mcp.run(transport="stdio")
claude_desktop_config.json
{
"mcpServers": {
"my-mcp-server-python": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"my-mcp-server-python"
]
}
}
}
コード参考;
TypeScript
@modelcontextprotocol/sdk
を利用します。
前提:
- Claude Desktopアプリは立ち上がっていない状態
- node, npmのバージョンは下記の通り
- node: v22.7.0
- npm: 10.8.2
手順:
- プロジェクトのルートディレクトリ (
Dockerfile
と同じ階層) でnpm init -y
を実行 - プロジェクトのルートディレクトリで下記を実行
npm install @modelcontextprotocol/sdk zod npm install -D @types/node typescript vitest
- 下記の通り
Dockerfile
,package.json
,tsconfig.json
,src/index.test.ts
,src/index.ts
を作成 (package-lock.json
は自動生成されたものをそのまま使用) - プロジェクトのルートディレクトリで
npm run test
を実行し、パスするのを確認 - プロジェクトのルートディレクトリで
npm run build
を実行し、正常にビルドできることを確認 (build
ディレクトリ配下にindex.js
とindex.test.js
が作成される) - プロジェクトのルートディレクトリで
docker build -t my-mcp-server-typescript .
を実行し、Docker image作成 - Claude Desktopを立ち上げる
ディレクトリ構造
.
├── Dockerfile
├── build
│ ├── index.js
│ └── index.test.js
├── package-lock.json
├── package.json
├── src
│ ├── index.test.ts
│ └── index.ts
└── tsconfig.json
Dockerfile
FROM node:22-slim
WORKDIR /app
# 全てのファイルを一度にコピー
COPY . .
# 依存関係のインストール
RUN npm install
# TypeScriptのビルドとdistディレクトリの作成を確認
RUN npm run build && \
if [ -d "build" ]; then \
chmod +x build/*.js || true; \
else \
echo "Error: build directory was not created" && exit 1; \
fi
# コンテナ起動時のコマンド
CMD ["node", "build/index.js"]
package.json
{
"name": "my-mcp-server-typescript",
"version": "1.0.0",
"main": "index.js",
"type": "module",
"bin": {
"my-mcp-server": "./build/index.js"
},
"files": [
"build"
],
"scripts": {
"test": "vitest",
"build": "tsc && chmod 755 build/index.js"
},
"author": "",
"license": "ISC",
"description": "",
"dependencies": {
"@modelcontextprotocol/sdk": "^1.10.2",
"zod": "^3.24.3"
},
"devDependencies": {
"@types/jest": "^29.5.14",
"@types/node": "^22.15.3",
"typescript": "^5.8.3",
"vitest": "^3.1.2"
}
}
tsconfig.json
{
"compilerOptions": {
"target": "ES2022",
"module": "Node16",
"moduleResolution": "Node16",
"outDir": "./build",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*"],
"exclude": ["node_modules"],
"types": ["jest", "node"],
}
src/index.ts
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import * as z from "zod";
export const server = new McpServer({
name: "my-mcp-server",
version: "1.0.0",
});
server.tool(
"add", // 提供するtoolの名前
"足し算をする", // toolの説明
{
a: z.number().describe("数値1"),
b: z.number().describe("数値2"),
}, // toolのパラメータ定義
({ a, b }) => ({ content: [{ type: "text", text: (a + b).toString() }] }), // toolが提供する機能の本体
);
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("Example MCP Server running on stdio");
}
main().catch((error) => {
console.error("Fatal error in main():", error);
process.exit(1);
});
src/index.test.ts
import { describe, it, expect } from "vitest";
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js";
import { server } from "./index.js";
describe("my-mcp-serverのテスト", () => {
it("add: 足し算の結果を返す", async () => {
// テスト用クライアントの作成
const client = new Client({
name: "test client",
version: "0.1.0",
});
// インメモリ通信チャネルの作成
const [clientTransport, serverTransport] =
InMemoryTransport.createLinkedPair();
// クライアントとサーバーを接続
await Promise.all([
client.connect(clientTransport),
server.connect(serverTransport),
]);
// 6面サイコロを振る
const result = await client.callTool({
name: "add",
arguments: {
a: 3, b: 8
},
});
// 結果が1-6の範囲の数字であることを確認
expect(result).toEqual({
content: [
{
type: "text",
text: "11",
},
],
});
});
});
claude-desktop-config.json
{
"mcpServers": {
"my-mcp-server-typescript": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"my-mcp-server-typescript"
]
}
}
}
コード参考:
気がついたらPythonのuv
というライブラリが一世を風靡していた。
MCPとはなにか?はAnthoropicがMCPを公開した際に簡単に勉強しましたが、ここまで人気になるとは思わず、長らく放置してしまいました。
Node.js(TypeScript)があまり得意ではないというのも放置の原因ではありました。Pythonでも書けるのなら、もっと早く手をつけておけばよかったです(Node.jsも勉強しろ)。
個人的には、もっといろんなサービスが公式MCPを作成してくれると安心して使えるのになぁ…と思いました。
Views: 0