Skip to main content
Glama
index.ts5.82 kB
#!/usr/bin/env node import { config } from 'dotenv'; import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, McpError, } from '@modelcontextprotocol/sdk/types.js'; // .envファイルを読み込む config(); import { BacklogClient } from './backlog/client.js'; import { searchIssuesSchema, getIssueSchema, updateIssueSchema, getProjectsSchema, SearchIssuesArgs, GetIssueArgs, UpdateIssueArgs } from './backlog/schemas.js'; // 環境変数から設定を取得 const BACKLOG_SPACE_URL = process.env.BACKLOG_SPACE_URL; const BACKLOG_API_KEY = process.env.BACKLOG_API_KEY; if (!BACKLOG_SPACE_URL || !BACKLOG_API_KEY) { throw new Error('BACKLOG_SPACE_URL and BACKLOG_API_KEY environment variables are required'); } class BacklogMcpServer { private server: Server; private backlogClient: BacklogClient; constructor() { this.server = new Server( { name: 'backlog-mcp-server', version: '0.1.0', }, { capabilities: { tools: {}, }, } ); // 環境変数の存在は上でチェック済みなので、型アサーションを使用 this.backlogClient = new BacklogClient( BACKLOG_SPACE_URL as string, BACKLOG_API_KEY as string ); this.setupToolHandlers(); // エラーハンドリング this.server.onerror = (error: Error) => console.error('[MCP Error]', error); process.on('SIGINT', async () => { await this.server.close(); process.exit(0); }); } private validateAndCastArguments<T>(args: Record<string, unknown> | undefined, schema: any): T { if (!args) { throw new McpError(ErrorCode.InvalidParams, 'Arguments are required'); } // 基本的な型チェック(実際のプロダクションコードではより厳密な検証が必要) for (const [key, value] of Object.entries(schema.properties)) { if (schema.required?.includes(key) && !(key in args)) { throw new McpError(ErrorCode.InvalidParams, `Missing required argument: ${key}`); } } return args as T; } private setupToolHandlers() { this.server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: [ { name: 'getProjects', description: 'Backlogのプロジェクト一覧を取得します', inputSchema: getProjectsSchema, }, { name: 'searchIssues', description: 'Backlogの課題を検索します', inputSchema: searchIssuesSchema, }, { name: 'getIssue', description: '特定のBacklog課題を取得します', inputSchema: getIssueSchema, }, { name: 'updateIssue', description: 'Backlog課題を更新します', inputSchema: updateIssueSchema, }, ], })); this.server.setRequestHandler(CallToolRequestSchema, async (request) => { try { switch (request.params.name) { case 'getProjects': { return { content: [ { type: 'text', text: JSON.stringify( await this.backlogClient.getProjects(), null, 2 ), }, ], }; } case 'searchIssues': { const args = this.validateAndCastArguments<SearchIssuesArgs>( request.params.arguments, searchIssuesSchema ); return { content: [ { type: 'text', text: JSON.stringify( await this.backlogClient.searchIssues(args), null, 2 ), }, ], }; } case 'getIssue': { const args = this.validateAndCastArguments<GetIssueArgs>( request.params.arguments, getIssueSchema ); return { content: [ { type: 'text', text: JSON.stringify( await this.backlogClient.getIssue(args), null, 2 ), }, ], }; } case 'updateIssue': { const args = this.validateAndCastArguments<UpdateIssueArgs>( request.params.arguments, updateIssueSchema ); return { content: [ { type: 'text', text: JSON.stringify( await this.backlogClient.updateIssue(args), null, 2 ), }, ], }; } default: throw new McpError( ErrorCode.MethodNotFound, `Unknown tool: ${request.params.name}` ); } } catch (error) { if (error instanceof McpError) { throw error; } console.error('[Tool Error]', error); throw new McpError( ErrorCode.InternalError, `Error executing tool ${request.params.name}: ${(error as Error).message}` ); } }); } async run() { const transport = new StdioServerTransport(); await this.server.connect(transport); console.error('Backlog MCP server running on stdio'); } } const server = new BacklogMcpServer(); server.run().catch(console.error);

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/jootsuki/backlog-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server