Skip to main content
Glama
index.ts3.73 kB
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js' import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js' import { z } from 'zod' import { getOctokit, runGit } from './helpers/github.js' import { CreateIssuePrompt } from './helpers/prompt.js' const server = new McpServer({ name: 'github-issue-from-diff', version: '0.1.0', title: 'Create GitHub Issue from Diff by Gustavo Detoni', }) server.registerTool( 'git_diff', { title: 'Get Git diff', description: 'Retorna um diff do repositório atual. Use para entender alterações locais.', inputSchema: { mode: z.enum(['working', 'staged', 'range']).default('working'), base: z.string().optional(), head: z.string().optional(), pathSpec: z.array(z.string()).optional(), maxBytes: z .number() .int() .positive() .max(5 * 1024 * 1024) .optional(), }, }, async ({ mode = 'working', base, head, pathSpec, maxBytes = 200_000 }) => { let args: string[] = ['diff', '-U3'] if (mode === 'staged') { args = ['diff', '--staged', '-U3'] } if (mode === 'range' && (!base || !head)) { throw new Error('For mode=range informe base e head') } if (mode === 'range') { args = ['diff', `${base}...${head}`, '-U3'] } if (pathSpec && pathSpec.length) { args.push('--', ...pathSpec) } const nameStatus = await runGit( mode === 'range' ? ['diff', '--name-status', `${base}...${head}`] : mode === 'staged' ? ['diff', '--staged', '--name-status'] : ['diff', '--name-status'] ) const diff = await runGit(args) const truncated = diff.length > maxBytes ? diff.slice(0, maxBytes) + '\n\n[...truncated...]' : diff const files = nameStatus .split('\n') .filter(Boolean) .map((line) => { const [status, ...rest] = line.split(/\s+/) return { status, file: rest.join(' ') } }) return { content: [ { type: 'text', text: `Changed files:\n${files .map((f) => `${f.status}\t${f.file}`) .join('\n')}`, }, { type: 'text', text: '\n--- DIFF START ---\n' + truncated }, ], } } ) server.registerPrompt( 'draft_issue_from_diff', { title: 'Draft GitHub issue from git diff', description: 'Converte um diff em um rascunho de issue', argsSchema: { diff: z.string(), repoSlug: z.string().describe('owner/repo'), guidance: z.string().optional(), }, }, ({ diff, repoSlug, guidance }) => CreateIssuePrompt(diff, repoSlug, guidance) ) server.registerTool( 'create_github_issue', { title: 'Create GitHub Issue', description: 'Cria uma issue no GitHub usando Octokit', inputSchema: { owner: z.string().default(process.env.DEFAULT_OWNER || ''), repo: z.string().default(process.env.DEFAULT_REPO || ''), title: z.string(), body: z.string().default(''), labels: z.array(z.string()).default([]), assignees: z .array(z.string()) .default( process.env.DEFAULT_ASSIGNEE ? [process.env.DEFAULT_ASSIGNEE] : [] ), }, }, async ({ owner, repo, title, body, labels, assignees }) => { const octokit = getOctokit() const res = await octokit.request('POST /repos/{owner}/{repo}/issues', { owner, repo, title, body, labels, assignees, }) const url = res.data.html_url return { content: [{ type: 'text', text: `Issue criada: #${url}` }], } } ) const transport = new StdioServerTransport() await server.connect(transport)

Implementation Reference

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/gustavodetoni/mcp-issue'

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