Crie um MCP Server que consome a API do GitHub — listar repos, buscar issues e criar issues via Claude.
A API do GitHub é uma das APIs REST mais bem documentadas e utilizadas do mundo. Ela permite acessar praticamente tudo que você faz na interface web — repositórios, issues, pull requests, commits, organizações — de forma programática. Para nosso MCP Server, vamos usar essa API como base para criar tools poderosas que o Claude poderá utilizar para interagir com seus projetos no GitHub.
A API REST do GitHub está disponível em api.github.com. Os principais endpoints que utilizaremos são: GET /user/repos para listar seus repositórios, GET /repos/{owner}/{repo}/issues para buscar issues de um repositório específico, e POST /repos/{owner}/{repo}/issues para criar novas issues. Todas as respostas são em formato JSON, facilitando o parsing e a formatação dos dados. A API possui rate limits — 5.000 requests por hora com autenticação — que devem ser respeitados no seu servidor.
A API do GitHub processa mais de bilhões de requests por dia e é usada por praticamente todas as ferramentas de desenvolvimento modernas — CI/CD, IDEs, bots, dashboards. Com autenticação via token, o rate limit sobe para 5.000 requests/hora, mais que suficiente para um MCP Server pessoal. Sem autenticação, o limite cai para apenas 60 requests/hora, tornando qualquer uso prático inviável.
Antes de escrever qualquer código, teste a API manualmente com curl ou com ferramentas como Insomnia/Postman. Execute curl https://api.github.com/users/{seu-usuario}/repos para ver a estrutura do JSON retornado. Isso facilita muito a implementação das tools do MCP Server, pois você já saberá exatamente quais campos extrair e formatar.
Para acessar a API do GitHub de forma autenticada — o que é essencial para ter rate limits decentes e acessar repositórios privados — você precisa de um Personal Access Token (PAT). Esse token funciona como uma senha temporária e com escopo controlado, permitindo que seu MCP Server acesse a API em seu nome sem precisar da sua senha real.
Para criar um Personal Access Token: acesse GitHub Settings → Developer settings → Personal access tokens → Fine-grained tokens. Selecione os escopos necessários — para nosso projeto, precisamos de acesso a repos e issues. O token gerado deve ser armazenado como variável de ambiente (ex: GITHUB_TOKEN) e passado via headers HTTP como Authorization: Bearer {token}. Nunca coloque o token diretamente no código-fonte.
NUNCA commitar tokens no repositório! Se você acidentalmente fizer push de um token para o GitHub, ele será automaticamente revogado pelo GitHub Secret Scanning — mas o dano pode já ter sido feito. Use sempre variáveis de ambiente, adicione .env ao .gitignore, e jamais logue o valor do token em outputs do servidor.
A primeira tool do nosso MCP Server GitHub será a listagem de repositórios. Usando o endpoint GET /user/repos, vamos buscar os repositórios do usuário autenticado, filtrar por visibilidade, ordenar por data de atualização e formatar os resultados de forma legível para o Claude apresentar ao usuário.
A tool de listar repositórios usa a biblioteca httpx para fazer requests assíncronos à API do GitHub. O código essencial:
@server.tool()
async def list_repos(visibility: str = "all") -> str:
"""Lista repositórios do usuário autenticado."""
async with httpx.AsyncClient() as client:
resp = await client.get(
"https://api.github.com/user/repos",
headers={"Authorization": f"Bearer {GITHUB_TOKEN}"},
params={"visibility": visibility, "sort": "updated"}
)
repos = resp.json()
lines = []
for r in repos:
stars = r["stargazers_count"]
lang = r.get("language", "N/A")
lines.append(f"⭐ {stars} | {r['name']} ({lang}) — {r.get('description', 'Sem descrição')}")
return "\n".join(lines)
Formate a saída de forma que o Claude consiga interpretar facilmente. Inclua nome, descrição, linguagem principal e número de estrelas. Use parâmetros opcionais como visibility (all, public, private) para dar ao Claude flexibilidade na consulta. O parâmetro sort=updated garante que os repos mais recentes apareçam primeiro.
Claude recebe pedido do usuário ("liste meus repos") e chama a tool list_repos com os parâmetros adequados.
O MCP Server faz GET /user/repos com o token de autenticação e recebe a lista de repositórios em JSON.
A tool formata os dados (nome, descrição, linguagem, stars) e retorna texto estruturado para o Claude apresentar.
A segunda tool permite buscar issues de um repositório específico. Usando o endpoint GET /repos/{owner}/{repo}/issues, o Claude poderá consultar issues abertas ou fechadas, filtrar por labels, e apresentar informações relevantes como número, título, autor e labels atribuídas.
A tool de buscar issues recebe owner (dono do repo), repo (nome do repositório) e parâmetros opcionais como state (open/closed/all) e labels (filtrar por etiquetas). O endpoint retorna um array JSON onde cada issue contém: number, title, user.login, state, labels[] e created_at. Formate a saída com número, título, autor e labels para facilitar a leitura.
Um detalhe importante: o endpoint /repos/{owner}/{repo}/issues retorna tanto issues quanto pull requests. Para filtrar apenas issues reais, verifique se o campo pull_request está ausente no objeto. A API suporta paginação via parâmetros page e per_page (máximo 100 por página).
A terceira tool é a mais poderosa — e a mais perigosa. Usando POST /repos/{owner}/{repo}/issues, o Claude poderá criar issues diretamente no seu repositório. Isso é uma ação de escrita, o que exige validação cuidadosa dos parâmetros e consciência de que estamos dando ao modelo a capacidade de modificar dados reais.
A tool de criar issue envia um POST com body JSON contendo title (obrigatório) e body (descrição, opcional mas recomendado). Valide que o título não esteja vazio e tenha comprimento razoável. Após a criação, retorne a URL da issue criada para que o usuário possa acessá-la diretamente:
@server.tool()
async def create_issue(owner: str, repo: str, title: str, body: str = "") -> str:
"""Cria uma nova issue em um repositório GitHub."""
if not title.strip():
return "Erro: o título da issue não pode ser vazio."
async with httpx.AsyncClient() as client:
resp = await client.post(
f"https://api.github.com/repos/{owner}/{repo}/issues",
headers={"Authorization": f"Bearer {GITHUB_TOKEN}"},
json={"title": title, "body": body}
)
if resp.status_code == 201:
issue = resp.json()
return f"Issue criada com sucesso! #{issue['number']}: {issue['html_url']}"
return f"Erro ao criar issue: {resp.status_code}"
Criar issues é uma ação de escrita — ela modifica dados reais no seu GitHub. Diferente de listar ou buscar, essa tool tem efeitos colaterais permanentes. Considere adicionar uma confirmação antes de executar a criação, ou pelo menos logar cada issue criada. Em um ambiente corporativo, essa tool deve ter controle de acesso rigoroso e audit trail completo.
Sempre retorne a URL da issue criada na resposta — isso permite que o Claude apresente um link clicável ao usuário. Valide os parâmetros antes de enviar o request: título não vazio, owner e repo no formato correto. Considere adicionar parâmetros opcionais como labels e assignees para criar issues mais completas.
Com as três tools implementadas — listar repos, buscar issues e criar issues — é hora de testar a integração completa. Configure o server no Claude Desktop e experimente comandos em linguagem natural para verificar que tudo funciona corretamente. O Claude deve ser capaz de escolher a tool certa automaticamente baseado no seu pedido.
Teste com estes prompts no Claude Desktop:
Peça ao Claude para listar seus repositórios. Verifique se os dados conferem com o que aparece na interface web do GitHub.
Peça para buscar issues de um repositório real. Confirme que os números, títulos e labels estão corretos.
Peça para criar uma issue de teste. Verifique no GitHub se a issue foi criada com o título e corpo corretos.
Peça para buscar issues de um repositório que não existe. Verifique se o erro é tratado graciosamente.
Próximo Módulo: 4.5 — Combinando Múltiplos Servers