1import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3import { z } from 'zod';
4
5// 1. Create the server
6const server = new McpServer({ name: 'github-issues', version: '1.0.0' });
7
8// 2. Register a tool
9server.registerTool('search_issues', {
10 description: 'Search GitHub issues in a repo',
11 inputSchema: {
12 repo: z.string().describe('owner/repo'),
13 query: z.string(),
14 state: z.enum(['open','closed','all']).default('open'),
15 },
16}, async ({ repo, query, state }) => {
17 const res = await fetch(`https://api.github.com/search/issues?q=${encodeURIComponent(`${query} repo:${repo} state:${state}`)}`);
18 const data = await res.json();
19 return { content: [{ type: 'text', text: JSON.stringify(data.items.slice(0, 10), null, 2) }] };
20});
21
22// 3. Register a resource (read-only)
23server.registerResource('repo-readme', 'github://{owner}/{repo}/readme', {}, async (uri, { owner, repo }) => {
24 const res = await fetch(`https://api.github.com/repos/${owner}/${repo}/readme`);
25 const j = await res.json();
26 return { contents: [{ uri: uri.href, mimeType: 'text/markdown', text: atob(j.content) }] };
27});
28
29// 4. Connect over stdio
30const transport = new StdioServerTransport();
31await server.connect(transport);
32
33// 5. Client config (Claude Desktop):
34// {
35// "mcpServers": {
36// "github-issues": { "command": "node", "args": ["./server.js"], "env": { "GH_TOKEN": "..." } }
37// }
38// }