はじめに 「提供されているMCPでだけだと足りない...!」 「自分 or 自社用にカスタマイズされたMCPを使いたい...!」 そんな時のために、改めてMCPの構造と作り方を簡単に確認しておこうと思います。 MCPとは Model Context Protocol の略。 AIが外部のツールやリソースに簡単にアクセスできるやり取りを定義したもの。 以前であればAPIを毎回生やしてそれを叩いてみるみたいなことが必要なくなります。 また、AIがアクセスしやすくなるので、コンテキストの節約やコントロールがしやすくなるとかがありそうです。 (この辺りの説明は最近トレンドなのでもう見飽きましたよね...) ですが、今回はMCPの仕組みを理解して、ある程度自分で作れるようになるというところを目指します。 MCPのドキュメントやリソース類 MCPの公式ドキュメント: https://modelcontextprotocol.io/introduction GitHub: https://github.com/modelcontextprotocol MCPのSDK (今回はTypeScriptで書きます) TypeScript SDK Python SDK Java SDK Kotlin SDK C# SDK では早速作っていきます。 クイックスタートをやってみる TypeScript上に載っているクイックスタート をやってみます。 準備 最初にプロジェクトを作ります npm init -ynpm install @modelcontextprotocol/sdknpm install -D @types/node typescriptnpm install zod package.json と ts-configを修正します。 // package.json{ "type": "module", "bin": { "my-mcp-server": "./build/index.js" }, "scripts": { "build": "tsc && chmod 755 build/index.js" }, "files": [ "build" ], "description": "", "dependencies": { "@modelcontextprotocol/sdk": "^1.15.0", "zod": "^3.25.71" }, "devDependencies": { "@types/node": "^24.0.10", "typescript": "^5.8.3" }} // package.json { " type " : " module " , " bin " : { " my-mcp-server " : " ./build/index.js " }, " scripts " : { " build " : " tsc && chmod 755 build/index.js " }, " files " : [ " build " ] , " description " : "" , " dependencies " : { " @modelcontextprotocol/sdk " : " ^1.15.0 " , " zod " : " ^3.25.71 " }, " devDependencies " : { " @types/node " : " ^24.0.10 " , " typescript " : " ^5.8.3 " } } // 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"]} // 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 " ] } サーバーの実装 簡単に足し算をするMCPを作成してみます。 ↓動作イメージ // src/server.tsimport { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";import { z } from "zod";// Create an MCP serverconst server = new McpServer({ name: "demo-server", version: "1.0.0"});// Add an addition toolserver.registerTool("add", { title: "Addition Tool", description: "Add two numbers", inputSchema: { a: z.number(), b: z.number() } }, async ({ a, b }) => ({ content: [{ type: "text", text: String(a + b) }] }));// Add a dynamic greeting resourceserver.registerResource( "greeting", new ResourceTemplate("greeting://{name}", { list: undefined }), { title: "Greeting Resource", // Display name for UI description: "Dynamic greeting generator" }, async (uri, { name }) => ({ contents: [{ uri: uri.href, text: `Hello, ${name}!` }] }));// Start receiving messages on stdin and sending messages on stdoutconst transport = new StdioServerTransport();await server.connect(transport); // src/server.ts import { McpServer , ResourceTemplate } from " @modelcontextprotocol/sdk/server/mcp.js " ; import { StdioServerTransport } from " @modelcontextprotocol/sdk/server/stdio.js " ; import { z } from " zod " ; // Create an MCP server const server = new McpServer ( { name : " demo-server " , version : " 1.0.0 " } ) ; // Add an addition tool server . registerTool ( " add " , { title : " Addition Tool " , description : " Add two numbers " , inputSchema : { a : z . number () , b : z . number () } }, async ({ a , b }) => ( { content : [ { type : " text " , text : String ( a + b ) } ] } ) ) ; // Add a dynamic greeting resource server . registerResource ( " greeting " , new ResourceTemplate ( " greeting://{name} " , { list : undefined } ) , { title : " Greeting Resource " , // Display name for UI description : " Dynamic greeting generator " }, async ( uri , { name }) => ( { contents : [ { uri : uri . href , text : ` Hello, ${ name } ! ` } ] } ) ) ; // Start receiving messages on stdin and sending messages on stdout const transport = new StdioServerTransport () ; await server . connect ( transport ) ; 具体的にコードを解説していきます。 new McpServer でMCPサーバーのインスタンスを作成します。 import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";const server = new McpServer({ name: "demo-server", version: "1.0.0"}); import { McpServer , ResourceTemplate } from " @modelcontextprotocol/sdk/server/mcp.js " ; import { StdioServerTransport } from " @modelcontextprotocol/sdk/server/stdio.js " ; const server = new McpServer ( { name : " demo-server " , version : " 1.0.0 " } ) ; 次にツールを追加します。 inputSchemaで、zodで入力値を管理しています。 今回は、ただ足し算をするだけのツールを追加しています。 import { z } from "zod";// Add an addition toolserver.registerTool("add", { title: "Addition Tool", // ツールのタイトル description: "Add two numbers",// ツールの説明 inputSchema: { a: z.number(), b: z.number() } // 入力値 }, async ({ a, b }) => ({ content: [{ type: "text", text: String(a + b) }]// 実行関数: 2つの数値を受け取り、その合計を文字列として返す })); import { z } from " zod " ; // Add an addition tool server . registerTool ( " add " , { title : " Addition Tool " , // ツールのタイトル description : " Add two numbers " , // ツールの説明 inputSchema : { a : z . number () , b : z . number () } // 入力値 }, async ({ a , b }) => ( { content : [ { type : " text " , text : String ( a + b ) } ] // 実行関数: 2つの数値を受け取り、その合計を文字列として返す } ) ) ; 先ほど追加したコード中で、次に、リソースへの登録をします。 これを登録すると、AIが greeting://名前 みたいな感じで参照してくれるようになります。( リソースについて ) ※この後の動作確認では、リソースは検証せず、ツールのみ検証する方法記載しています。リソースとツールを 状況に応じて使い分けることをおすすめします。 // Add a dynamic greeting resourceserver.registerResource( "greeting", new ResourceTemplate("greeting://{name}", { list: undefined }), // リソースのURL { title: "Greeting Resource", // リソースのタイトル description: "Dynamic greeting generator" // リソースのディスクリプション }, async (uri, { name }) => ({ contents: [{ uri: uri.href, text: `Hello, ${name}!` }] })); // Add a dynamic greeting resource server . registerResource ( " greeting " , new ResourceTemplate ( " greeting://{name} " , { list : undefined } ) , // リソースのURL { title : " Greeting Resource " , // リソースのタイトル description : " Dynamic greeting generator " // リソースのディスクリプション }, async ( uri , { name }) => ( { contents : [ { uri : uri . href , text : ` Hello, ${ name } ! ` } ] } ) ) ; 最後にサーバーを実行する部分を書いたら完成です。 // Start receiving messages on stdin and sending messages on stdoutconst transport = new StdioServerTransport();await server.connect(transport); // Start receiving messages on stdin and sending messages on stdout const transport = new StdioServerTransport () ; await server . connect ( transport ) ; 動作確認までの準備 今回はツールまで実行してみようと思います。最初にビルドします。 npm run build build/index.js が生成されるはずなので、絶対パスをコピーしておきます。 そうすると、curosrの場合はこんな感じで設定しておきます。これで準備はOKです。 "my-mcp-server": { "command": "node", "args": ["${コピーした絶対パス}/build/index.js"] } " my-mcp-server " : { " command " : " node " , " args " : [ " ${コピーした絶対パス}/build/index.js " ] } cursorのツールの欄を確認すると、こんな感じで追加した、MCPが利用できるようになっているはずです。 こんな感じで、agentに投げると、mcpを叩いてくれるようになります。 最後に 今回は、MCPの構造を確認しながら、簡単なMCPを作ってみました...! 意外と簡単に作れたので、必要そうなツールは個人的に作っていこうと思います。 最後まで読んでいただきありがとうございました!