ã«ã¹ã¿ã MCPãµãŒããŒã®ãã³ãã¬ãŒããšãã¹ãå®è£
ã¯ããã«
è¿å¹ŽãAIã®é²åãšãšãã«ãå€§èŠæš¡èšèªã¢ãã«ïŒLLMïŒãšå€éšããŒã«ã飿ºãããéèŠãæ¥éã«é«ãŸã£ãŠããŸããModel Context ProtocolïŒMCPïŒã¯ãAIã¢ãã«ãå€éšã®æ©èœãããŒã¿ã«ã¢ã¯ã»ã¹ããããã®æšæºåããããããã³ã«ãšããŠæ³šç®ãéããŠããŸãã
MCPãµãŒããŒãèªäœãã䟡å€ã¯äž»ã«3ã€ãããŸãïŒ
- ã«ã¹ã¿ã æ©èœã®å®çŸ: ç¹å®ã®ãã¡ã€ã³ãæ¥åã«ç¹åããããŒã«ãAIã«æäŸã§ãã
- ã»ãã¥ãªãã£ãšãã©ã€ãã·ãŒã®å¶åŸ¡: èªç€Ÿã®ããŒã¿ãAPIãžã®ã¢ã¯ã»ã¹ãå®å šã«ç®¡çã§ãã
- ããã©ãŒãã³ã¹ã®æé©å: ç¹å®ã®ãŠãŒã¹ã±ãŒã¹ã«åãããå¹ççãªå®è£ ãå¯èœ
ä»åã¯ãMCPãµãŒããŒã®çè§£ãæ·±ããããã«ãã·ã³ãã«ãªMCPãµãŒããŒãšãã®ãã¹ããå®è£ ããŠã¿ãŸããããã®èšäºãéããŠãMCPãµãŒããŒã®åºæ¬æ§é ãããŒã«ã®å®è£ æ¹æ³ããããŠãã¹ãæŠç¥ã«ã€ããŠåŠã¹ãŸãã
宿ã®ã€ã¡ãŒãžã¯ãã¡ã

ã³ãŒãã¯ãã¡ãã§å ¬éããŠããŸãïŒ
MCPã®ä»çµã¿ãšæŠå¿µ
MCPãçè§£ããäžã§éèŠãªã®ã¯ãAIã¢ãã«ãšããŒã«ã®é£æºã®æµãã§ãã以äžã®å³ã¯ãã®åºæ¬çãªä»çµã¿ã瀺ããŠããŸãïŒ
äž»ãªåŠçã®æµãã¯ïŒ
- ãŠãŒã¶ãŒãAIã«å¯ŸããŠã¯ãšãªãéä¿¡
- AIã¢ãã«ããã®ã¯ãšãªãåæããå€éšããŒã«ãå¿ èŠã倿
- å¿ èŠãšå€æããå ŽåãAIã¯MCPãµãŒããŒã«é©åãªããŒã«ãšåŒæ°ãæå®ããŠãªã¯ãšã¹ã
- MCPãµãŒããŒããã©ã¡ãŒã¿ãããªããŒã·ã§ã³ããæå®ãããããŒã«ãå®è¡
- å®è¡çµæãAIã«è¿ãããAIã¯çµæãèæ ®ããå¿çããŠãŒã¶ãŒã«æäŸ
new McpServer() ãš server.tool() ã®è©³çŽ°è§£èª¬
McpServerã®åæå
MCPãµãŒããŒãäœæããç¬¬äžæ©ã¯ãMcpServerã¯ã©ã¹ã®ã€ã³ã¹ã¿ã³ã¹ãåæåããããšã§ãã
const server = new McpServer({
name: 'quiz-mcp-server',
version: '1.0.0',
description: '詳现ãªèª¬æ...',
});
ããã§åãã©ã¡ãŒã¿ã®æå³ã詳ããèŠãŠãããŸãããïŒ
- name: ãµãŒããŒã®èå¥åãããã¯ã¯ã©ã€ã¢ã³ãããã®MCPãµãŒããŒãèªèããããã«äœ¿çšãããŸãã
- version: ãµãŒããŒã®ããŒãžã§ã³çªå·ãAPIã®äºææ§ç®¡çã倿Žè¿œè·¡ã«åœ¹ç«ã¡ãŸãã
- description: ãµãŒããŒã®è©³çްãªèª¬æããã®èª¬æã¯AIã¢ãã«ããã®ãµãŒããŒã®æ©èœãçè§£ããã®ã«åœ¹ç«ã¡ãé©åãªããŒã«éžæããµããŒãããŸãã詳现ãªèª¬æãæäŸããããšã§ãAIã¯ãµãŒããŒã®èœåãããæ£ç¢ºã«ææ¡ã§ããŸãã
MCPãµãŒããŒã®åæåæã«æäŸããæ å ±ã¯ããããã³ã«ã®ãã³ãã·ã§ã€ã¯ãã¯ã©ã€ã¢ã³ããžã®æ å ±æäŸã«äœ¿çšãããŸããç¹ã«èª¬ææã¯ååã«è©³çްã§å ·äœçã§ããããšãéèŠã§ããAIã¢ãã«ã¯ãã®èª¬æãèªã¿ãã©ã®ãããªå Žåã«ãã®ãµãŒããŒãšãã®ããŒã«ã䜿çšãã¹ããã倿ããŸãã
ããŒã«ã®ç»é²
server.tool()ã¡ãœããã¯ãMCPãµãŒããŒã«æ°ããããŒã«ãç»é²ããããã«äœ¿çšãããŸãã
server.tool(
'get_quiz', // ããŒã«å
'詳现ãªèª¬æ...', // ããŒã«ã®èª¬æ
QuizSchema.shape, // ãã©ã¡ãŒã¿ã®ã¹ããŒã
// å®è£
颿°ïŒã³ãŒãçç¥ïŒ
);
åãã©ã¡ãŒã¿ã®æå³ã¯ä»¥äžã®éãã§ãïŒ
-
ããŒã«å: AIã¢ãã«ããã®ããŒã«ãåŒã³åºãéã«äœ¿çšããäžæã®èå¥åãååã¯æ©èœãæç¢ºã«ç€ºãç°¡æœãªãã®ãæãŸããã§ãã
-
ããŒã«ã®èª¬æ: ãã®ããŒã«ãäœãããã®ããã©ã®ãããªå Žåã«äœ¿çšãã¹ããã®è©³çްãªèª¬æã説æã¯AIã¢ãã«ããã®ããŒã«ã®çšéãšæ©èœãçè§£ããããã«éåžžã«éèŠã§ããé©åãªãŠãŒã¹ã±ãŒã¹ãå ¥åãã©ã¡ãŒã¿ãæåŸ ãããåºåãªã©ãå«ããã¹ãã§ãã
-
ãã©ã¡ãŒã¿ã®ã¹ããŒã: ããŒã«ãåãä»ãããã©ã¡ãŒã¿ã®æ§é ãšåãå®çŸ©ããZodã¹ããŒããããã«ãããåå®å šæ§ã確ä¿ããããã©ã¡ãŒã¿ã®ããªããŒã·ã§ã³ãèªåçã«è¡ãããŸããäŸãã°ïŒ
const QuizSchema = z.object({ category: z.enum(['general', 'science', 'history']), difficulty: z.enum(['easy', 'medium', 'hard']), count: z.number().min(1).max(10), }); -
å®è£ 颿°: ããŒã«ã®å®éã®åŠçãè¡ã颿°ããã®é¢æ°ã¯ããªããŒã·ã§ã³æžã¿ã®ãã©ã¡ãŒã¿ãåãåããåŠççµæãè¿ããŸãã
ããŒã«ç»é²ã®éèŠãªãã€ã³ãã¯ãAIã¢ãã«ãããŒã«ã广çã«äœ¿çšã§ãããããæç¢ºã§å ·äœçãªèª¬æãæäŸããããšã§ããããŒã«ã®ååãšèª¬æã¯ãã¢ãã«ããŠãŒã¶ãŒã®æå³ãçè§£ããé©åãªã¿ã€ãã³ã°ã§ããŒã«ãåŒã³åºãããã®éèŠãªæããããšãªããŸãã
ããŒã«éžæãšå®è¡ã®ä»çµã¿
AIã¢ãã«ãã©ã®ããã«ããŒã«ãéžæããMCPãµãŒããŒãã©ãåŠçããããå³ã§è¡šããšïŒ
å®éã®äœ¿çšäŸ
äŸãã°ããŠãŒã¶ãŒããç§åŠã«é¢ããç°¡åãªã¯ã€ãºãåºããŠããšèŠæ±ããå ŽåãAIã¢ãã«ã¯ïŒ
- èŠæ±ãçè§£ããã¯ã€ãºããŒã«ã®äœ¿çšãé©åã ãšå€æ
-
get_quizããŒã«ãéžæ - é©åãªãã©ã¡ãŒã¿ïŒ
{category: "science", difficulty: "easy", count: 1}ïŒãèšå® - MCPãµãŒããŒã«ãªã¯ãšã¹ããéä¿¡
- ããŒã«ã®å®è¡çµæããŠãŒã¶ãŒã«æç€º
ãšããæµãã§åŠçãè¡ããŸãã
ãã®ä»çµã¿ã«ãããAIã¢ãã«ã¯ãµãŒããŒåŽã§å®è£ ãããããŸããŸãªæ©èœã«å®å šã«ã¢ã¯ã»ã¹ããããè±ããªå¿çããŠãŒã¶ãŒã«æäŸã§ããããã«ãªããŸãã
MCPãµãŒããŒã®æŠèŠ
MCP (Model Context Protocol) ã¯ãAIã¢ãã«ãšå€éšããŒã«ãæ¥ç¶ããããã®æšæºåããããããã³ã«ã§ãããã®ãããã³ã«ã¯ãAIã¢ãã«ãããŸããŸãªå€éšæ©èœãAPIã«ã¢ã¯ã»ã¹ããããã®äžè²«ããæ¹æ³ãæäŸããŸãã
MCPãµãŒããŒã®äž»ãªæ©èœïŒ
- AIã¢ãã«ããã®ãªã¯ãšã¹ããåŠç
- å€éšããŒã«ãžã®ã¢ã¯ã»ã¹ãæäŸ
- ããŒã«ã®å®è¡çµæãAIã¢ãã«ã«è¿ã
- åå®å šãªãã©ã¡ãŒã¿åŠç
ãã®ãããã³ã«ã䜿ãããšã§ãAIã¢ãã«ã¯å€©æ°æ å ±ã®ååŸãããŒã¿ããŒã¹ã®ã¯ãšãªãèšç®ã®å®è¡ãªã©ãå€éšã·ã¹ãã ãšã®ã€ã³ã¿ã©ã¯ã·ã§ã³ãå¯èœã«ãªããŸãã
ãã³ãã¬ãŒãæ§æ
ä»åäœæããMCPãµãŒããŒãã³ãã¬ãŒãã¯ä»¥äžã®ãããªæ§æã«ãªã£ãŠããŸãïŒ
mcp-server-template/
âââ src/
â âââ server.ts # MCPãµãŒããŒã®ã¡ã€ã³ã³ãŒã
â âââ tools/ # åçš®ããŒã«å®è£
â â âââ quiz.ts # ã¯ã€ãºããŒã«
â â âââ calculator.ts # èšç®ããŒã«
â âââ schemas/ # ãã©ã¡ãŒã¿ã®ã¹ããŒãå®çŸ©
â âââ quiz.ts # ã¯ã€ãºãã©ã¡ãŒã¿ã¹ããŒã
âââ tests/ # ãã¹ãã³ãŒã
â âââ server.test.ts # ãµãŒããŒã®ãã¹ã
â âââ tools/ # åããŒã«ã®ãã¹ã
â âââ quiz.test.ts # ã¯ã€ãºããŒã«ã®ãã¹ã
âââ package.json
äž»èŠãªäŸåé¢ä¿ïŒ
-
zod: ãã©ã¡ãŒã¿ããªããŒã·ã§ã³çšã©ã€ãã©ãª -
bun: é«éãªJavaScript/TypeScriptã©ã³ã¿ã€ã
ãã¹ãå®è£
以äžã®ãããªãã¹ããå®è£ ããŸããã
ããŒã«ã®ãŠããããã¹ã
åããŒã«ãæåŸ éãã®åäœãããããåå¥ã«ãã¹ãããŸãïŒ
// ã¯ã€ãºããŒã«ã®ãã¹ãäŸ
describe('Quiz Tool', () => {
// ãã¹ãæºå
const quizTool = new QuizTool();
test('æ£ãããã©ã¡ãŒã¿ã§æ£åžžã«ã¯ã€ãºãè¿ã', async () => {
const result = await quizTool.execute({
category: 'general',
difficulty: 'easy',
count: 1,
});
expect(result.status).toBe('success');
expect(result.quizzes).toBeDefined();
expect(result.quizzes.length).toBe(1);
});
test('ç¡å¹ãªãã©ã¡ãŒã¿ã§ãšã©ãŒãè¿ã', async () => {
// ZodããªããŒã·ã§ã³ããšã©ãŒãã¹ããŒãããã
await expect(async () => {
await quizTool.execute({
category: 'invalid', // ç¡å¹ãªã«ããŽãª
difficulty: 'easy',
count: 1,
});
}).rejects.toThrow();
});
});
ãµãŒããŒçµ±åãã¹ã
ãµãŒããŒå šäœã®åäœããã¹ãããŸãïŒ
describe('MCP Server', () => {
// ãã¹ãçšãµãŒããŒã®äœæ
const server = new McpServer({
name: 'test-server',
version: '1.0.0',
});
// ãã¹ãçšããŒã«ã®ç»é²
server.registerTool(new QuizTool());
test('ããŒã«ãæ£ããç»é²ãããŠãã', () => {
expect(server.getTools()).toContain('get_quiz');
});
test('ãªã¯ãšã¹ããæ£åžžã«åŠçã§ãã', async () => {
const response = await server.processRequest({
tool: 'get_quiz',
params: {
category: 'general',
difficulty: 'easy',
count: 1,
},
});
expect(response.status).toBe('success');
});
test('ååšããªãããŒã«ãžã®ãªã¯ãšã¹ããé©åã«åŠç', async () => {
const response = await server.processRequest({
tool: 'non_existent_tool',
params: {},
});
expect(response.status).toBe('error');
expect(response.error.message).toContain('Tool not found');
});
});
ããã©ãŒãã³ã¹ãã¹ã
MCPãµãŒããŒã®æ§èœããã¹ãããŸãïŒ
test('è€æ°ã®åæãªã¯ãšã¹ããåŠçã§ãã', async () => {
const requests = Array(50)
.fill(null)
.map(() =>
server.processRequest({
tool: 'get_quiz',
params: {
category: 'general',
difficulty: 'easy',
count: 1,
},
})
);
const results = await Promise.all(requests);
// ãã¹ãŠã®ãªã¯ãšã¹ããæåããŠããããšã確èª
expect(results.every((r) => r.status === 'success')).toBe(true);
});
ãŸãšã
MCPãµãŒããŒã®ãã³ãã¬ãŒããšãã¹ãå®è£ ãéããŠãAIã¢ãã«ãšå€éšããŒã«ãçµ±åããããã®å ç¢ãªåºç€ãæ§ç¯ããããšãã§ããŸãããç¹ã«éèŠãªãã€ã³ãã¯ä»¥äžã®éãã§ãïŒ
- åå®å šæ§: TypeScriptãšZodã«ãã峿 Œãªåãã§ãã¯ãšããªããŒã·ã§ã³
- ãã¹ãç¶²çŸ æ§: ãŠããããã¹ãããçµ±åãã¹ãããšã©ãŒã±ãŒã¹ãŸã§ã«ããŒ
- æ¡åŒµæ§: æ°ããããŒã«ã容æã«è¿œå ã§ããèšèš
MCPãããã³ã«ã¯ãŸã çºå±éäžã§ãããä»åŸAIãšå€éšã·ã¹ãã ã®é£æºã«ãããŠéèŠãªåœ¹å²ãæãããŠããã§ãããããã®ãã³ãã¬ãŒããåºã«ãæ§ã ãªAIã¢ããªã±ãŒã·ã§ã³ã®ããã¯ãšã³ããå¹ççã«æ§ç¯ã§ããããã«ãªããŸããã
Discussion