Agama — Redmine MCP Server
Servidor MCP para Redmine. Permite que agentes de IA trabalhem com issues usando comandos simples em linguagem natural. Funciona tanto como ferramenta pessoal para um desenvolvedor individual — quanto implantado uma vez e compartilhado por toda a equipe.
Documentação
🦎 Agama — Redmine MCP Server
Servidor MCP para Redmine. Permite que agentes de IA trabalhem com issues usando comandos simples em linguagem natural.
Funciona tanto como ferramenta pessoal para um desenvolvedor individual — ou implantado uma vez e compartilhado por toda a equipe.
┌──────────┐ MCP (stdio) ┌─────────────────────┐ REST/JSON ┌──────────┐
│ Agent │ ──────────────▶ │ Redmine MCP Server │ ────────────▶ │ Redmine │
│ (client) │ ◀────────────── │ (this project) │ ◀──────────── │ server │
└──────────┘ tool results └─────────────────────┘ HTTP └──────────┘
💬 Basta perguntar
"Quais issues estão atribuídas a mim? Ordene por prioridade."
"Crie um bug no projeto Web: o botão de login não responde no celular, marque como urgente."
"Resuma a issue #456 e todas as suas subtarefas."
"Quantas horas registrei esta semana, divididas por projeto?"
Requisitos
- Node.js 22+
- Uma instância do Redmine com a API REST habilitada (Administração → Configurações → API)
- Uma chave de API do Redmine — vá em Minha conta → Chave de acesso à API enquanto estiver conectado
Início rápido
A maioria dos clientes MCP (ex.: Claude Desktop) inicia o servidor para você — configure uma vez e esqueça:
{
"mcpServers": {
"redmine": {
"command": "npx",
"args": ["-y", "@0xkillaflow/agama-redmine-mcp"],
"env": {
"REDMINE_URL": "https://redmine.example.com",
"REDMINE_API_KEY": "your-redmine-api-key"
}
}
}
}
Para o Claude Desktop, isso vai em claude_desktop_config.json (Configurações → Desenvolvedor → Editar Config). Reinicie o cliente e as ferramentas do Redmine aparecerão na lista de ferramentas.
Para executar de forma independente a partir de um shell:
REDMINE_URL=https://redmine.example.com REDMINE_API_KEY=your-redmine-api-key \
npx -y @0xkillaflow/agama-redmine-mcp
O servidor fala MCP via stdio e registra logs no stderr, então o stdout permanece limpo para o protocolo.
Configuração
Definida por variáveis de ambiente, validadas na inicialização. Veja .env.example para um modelo.
| Variável | Obrigatória | Padrão | Finalidade |
|---|---|---|---|
REDMINE_URL | sim | — | URL base da instância do Redmine |
REDMINE_API_KEY | sim | — | Chave de API para o usuário atuante |
REDMINE_TIMEOUT_MS | não | 30000 | Tempo limite por requisição em milissegundos |
REDMINE_ALLOWED_DIRECTORIES | não | vazio | Diretórios que as ferramentas de anexo podem usar |
LOG_LEVEL | não | info | debug | info | warn | error |
MCP_TRANSPORT | não | stdio | stdio (único modo suportado hoje) |
Acesso a arquivos (REDMINE_ALLOWED_DIRECTORIES)
As ferramentas de anexo são as únicas que tocam no seu sistema de arquivos, e só podem tocar dentro desta lista de permissões — uma lista separada por : de diretórios absolutos (; no Windows). Ela governa ambas as direções: leituras para redmine_upload_attachment e gravações para redmine_download_attachment.
REDMINE_ALLOWED_DIRECTORIES=/Users/you/redmine-files:/tmp/redmine-downloads
O padrão é vazio, o que significa nenhum acesso a arquivos locais — ambas as ferramentas recusam qualquer caminho até que você opte por habilitar. Esse padrão é deliberado: um agente que pode ser convencido a enviar um arquivo é um agente que pode ser convencido a enviar ~/.ssh/id_rsa ou o .env que contém sua chave de API. Permita apenas o diretório mais restrito que atenda à necessidade. Os caminhos são totalmente resolvidos (segmentos .. e symlinks incluídos) antes da verificação, então um symlink dentro de um diretório permitido não pode apontar para fora dele, e downloads nunca sobrescrevem um arquivo existente.
Ferramentas
Dezenove ferramentas moldadas por intenção, cada uma marcada com anotações de segurança MCP. Referência completa: docs/tools.md.
| Ferramenta | Tipo | Descrição |
|---|---|---|
redmine_list_issues | leitura | Buscar/filtrar issues por status, responsável, tracker, datas… |
redmine_get_issue | leitura | Detalhe completo da issue, opcionalmente com diários e anexos |
redmine_create_issue | escrita | Criar uma issue |
redmine_update_issue | escrita | Editar status, responsável, notas… de uma issue |
redmine_delete_issue | escrita · destrutiva | Excluir permanentemente uma issue — sem desfazer, em cascata |
redmine_manage_issue_watchers | escrita | Adicionar/remover um observador (assinatura de notificação) |
redmine_list_issue_relations | leitura | Links de dependência de uma issue, ou uma relação pelo seu id |
redmine_create_issue_relation | escrita | Vincular duas issues (bloqueia, precede, duplica, relaciona…) |
redmine_delete_issue_relation | escrita · destrutiva | Remover um link — escopo restrito e reversível |
redmine_search | leitura | Busca em texto livre em issues, wiki, notícias, projetos |
redmine_list_projects | leitura | Listar projetos visíveis |
redmine_get_project | leitura | Detalhe completo do projeto, trackers/categorias/atividades |
redmine_list_time_entries | leitura | Consultar tempo registrado |
redmine_create_time_entry | escrita | Registrar horas em uma issue ou projeto |
redmine_get_current_user | leitura | "Quem sou eu" — usuário da chave de API, associações, grupos |
redmine_list_users | leitura | Encontrar usuários por nome/status/grupo — restrito a admin na maioria dos sites |
redmine_list_reference_data | leitura | Status, trackers, prioridades, atividades, categorias de documentos |
redmine_upload_attachment | escrita | Enviar um arquivo local → token para o array uploads de uma issue |
redmine_download_attachment | escrita | Salvar um anexo em um diretório local (grava no disco) |
Atenção:
redmine_delete_issueé a ferramenta que destrói dados — o Redmine não tem lixeira, e a exclusão leva junto os comentários, registros de tempo, anexos e relações da issue. Ela é anotada comodestructiveHint: truepara que um cliente MCP possa exigir confirmação; se o seu cliente não bloquear isso, trate cada chamada como definitiva.redmine_delete_issue_relationcarrega a mesma anotação, mas é muito mais restrita: remove um link entre duas issues, eredmine_create_issue_relationo restaura em uma única chamada.
Atenção: ao gravar, o Redmine ignora silenciosamente um
tracker_id,status_idoufixed_version_iddesconhecido em vez de retornar erro — sempre verifique a issue retornada. O mesmo se aplica ais_private, que é silenciosamente descartado se seu papel não tiver a permissão "definir público/privado".
Segurança
O servidor roda localmente e atua como um único usuário: seu REDMINE_API_KEY nunca sai da sua máquina, exceto como cabeçalho de requisição para sua própria instância do Redmine, e o servidor não pode fazer nada que sua conta já não pudesse. Transporte HTTP multiusuário está planejado, mas ainda não implementado — selecionar MCP_TRANSPORT=http encerra com um erro claro.
O acesso a arquivos locais está desativado por padrão e confinado a REDMINE_ALLOWED_DIRECTORIES quando você o habilita. Nada mais no servidor lê ou grava no seu sistema de arquivos.
Solução de problemas
| Sintoma | Causa provável |
|---|---|
| Cliente não mostra ferramentas | Algo além de JSON-RPC está gravando no stdout — verifique qualquer wrapper |
| Encerra imediatamente na inicialização | Uma variável de ambiente obrigatória está ausente ou inválida; o erro a nomeia |
401 Unauthorized | Chave de API ausente/incorreta, ou API REST desabilitada no lado do Redmine |
403 Forbidden | O usuário da chave não tem permissão para essa ação |
404 Not Found | O id não existe ou não é visível para a chave |
422 Unprocessable Entity | O Redmine rejeitou a gravação — verifique as mensagens de nível de campo retornadas |
Documentação
docs/architecture.md— design e ciclo de vida de requisiçõesdocs/tools.md— referência gerada por ferramentadocs/adding-a-tool.md— receita para adicionar uma nova ferramentaCONTRIBUTING.md— configuração de desenvolvimento e guia de contribuição
Desenvolvimento
npm install # install dependencies
npm run dev # watch-run the stdio server
npm test # run the test suite
npm run build # bundle to dist/