Tempo MCP Server
Um servidor MCP para gerenciar registros de trabalho do Tempo no Jira. Ele se conecta aos serviços do Jira e do Tempo usando tokens de API e variáveis de ambiente.
Documentação
Tempo MCP Server
Um servidor Model Context Protocol (MCP) para gerenciar apontamentos de horas (worklogs) do Tempo no Jira. Este servidor fornece ferramentas para registrar tempo e gerenciar apontamentos através da API do Tempo, tornando-o acessível pelo Claude, Cursor e outros clientes compatíveis com MCP.
Recursos
- Consultar Apontamentos: Obtenha todos os apontamentos para um intervalo de datas específico
- Criar Apontamento: Registre horas em issues do Jira
- Criação em Lote: Crie múltiplos apontamentos em uma única operação
- Editar Apontamento: Modifique tempo gasto, datas e descrições
- Excluir Apontamento: Remova apontamentos existentes
- Relatório de Dias Ausentes: Encontre dias úteis onde você registrou menos do que o esperado (usa o agendamento do usuário do Tempo, então feriados e dias não úteis são ignorados automaticamente)
- Análise de Apontamentos: Agregue horas por issue, conta, dia, semana ou mês com totais e percentuais
Requisitos do Sistema
- Node.js 18+ (LTS recomendado) — necessário apenas para os modos stdio locais
- Instância do Jira Cloud
- Token da API do Tempo
- Token da API do Jira (não necessário ao usar autenticação OAuth 2.0 PKCE)
Opções de Uso
Existem três formas de usar este servidor MCP:
- Remoto / Cloudflare Workers (sem instalação) — hospede uma vez, compartilhe com sua equipe. Cada usuário gera sua própria URL através de uma página de configuração e a cola no Claude.ai ou ChatGPT. Funciona na web e no celular.
- NPX: Execute diretamente com
npxno seu laptop, sem necessidade de clonar. - Clone Local: Clone o repositório para desenvolvimento ou personalização.
Se você só quer usar o servidor, a opção 1 é a mais fácil e também funciona em celulares. Se você é um mantenedor implantando para sua equipe, veja o guia de implantação remota.
Opção 1: Remoto (Cloudflare Workers)
Para usuários finais
Quando sua equipe tiver o servidor implantado, o fluxo é:
- Abra
https://<your-deployment>.workers.dev/setup. - Cole seu token da API do Tempo, URL base do Jira, token da API do Jira e e-mail do Jira. Clique em Gerar URL MCP.
- A página retorna uma URL pessoal como
https://<your-deployment>.workers.dev/mcp/u_<random>. Copie-a. - Em Claude.ai → Configurações → Conectores → Adicionar conector personalizado, cole a URL.
- O conector sincroniza entre web, desktop e mobile (iOS/Android).
Para ChatGPT: ative Configurações → Apps → Avançado → Modo desenvolvedor (Pro/Plus/Business+), depois adicione a URL como um servidor MCP personalizado. Contas Plus/Pro podem ler; ferramentas de escrita (criar/editar apontamentos) exigem Business+ conforme os níveis da OpenAI.
A URL contém suas credenciais — trate-a como uma senha, não compartilhe nem a envie para repositórios.
Implantação remota (Cloudflare Workers)
Hospedagem gratuita no Cloudflare Workers. Cerca de 5–10 minutos do clone até a URL ativa. Qualquer pessoa pode fazer um fork e auto-hospedar — sem necessidade de coordenação com o upstream.
Pré-requisitos
- Uma conta Cloudflare (o plano gratuito é suficiente).
- Node.js 18+ e
npmlocalmente — usados apenas para a CLIwrangler; o runtime do Worker em si não executa Node.
Configuração inicial
git clone https://github.com/ivelin-web/tempo-mcp-server.git
cd tempo-mcp-server
npm install
# 1. Log in to Cloudflare (opens browser).
npx wrangler login
# 2. Create your own KV namespace for per-user credentials.
npx wrangler kv namespace create USERS
⚠️ Se você fez fork do repositório: o
wrangler.jsonckv_namespaces[0].idcommitado pertence à conta Cloudflare do mantenedor upstream. Substitua-o pelo id que o passo 2 acabou de retornar, caso contráriowrangler deployfalhará comKV namespace … is not valid. IDs de namespace KV são identificadores públicos por conta, não são segredos, mas cada conta tem o seu.
# 3. Generate and store the encryption key.
# Used to AES-GCM-encrypt per-user credentials in KV.
openssl rand -base64 48 | npx wrangler secret put ENCRYPTION_KEY
# 4. (Optional) Pin the CORS origin. Defaults to "*". Set it if you only
# want browsers from a specific app to call the Worker.
echo "https://claude.ai" | npx wrangler secret put ALLOWED_ORIGIN
# 5. Deploy.
npm run remote:deploy
# → outputs https://tempo-mcp-server.<your-account>.workers.dev
Visite /setup na URL implantada para cadastrar seu primeiro usuário.
Atualizando uma implantação existente
Após puxar novos commits do upstream:
npm install # picks up any new deps
npm run remote:deploy # ships the new Worker bundle
Segredos e dados KV persistem entre implantações. compatibility_date e compatibility_flags em wrangler.jsonc estão fixados, então o comportamento não muda silenciosamente quando o Cloudflare lança mudanças no runtime.
Desenvolvimento local
cp .dev.vars.example .dev.vars
# edit .dev.vars and put a real ENCRYPTION_KEY (any value works locally)
npm run remote:dev
# → http://localhost:8787 with a mock KV; data is wiped between sessions
Outros scripts úteis:
npm run remote:typecheck— verifica tipos do bundle do Worker (usatsconfig.worker.json).npm run remote:tail— transmite logs ao vivo do Worker implantado.
Solução de problemas
KV namespace … is not valid—kv_namespaces[0].idemwrangler.jsoncestá vazio (ou errado). Executenpx wrangler kv namespace create USERSe cole o novo id.ENCRYPTION_KEY is not definedem tempo de execução — o segredo não foi definido. Execute novamente o passo 3.Rate limit binding … not available— o plano da sua conta não inclui a API de Limitação de Taxa do Workers. Ou faça upgrade, ou remova o blocoratelimitsemwrangler.jsonce a chamadaSETUP_RATE_LIMITER.limit(...)emsrc/remote/worker.ts.- 404 de
/mcp/u_…— o id do usuário é desconhecido (ou nunca existiu). O Worker retorna 404 por design para ids inválidos/ausentes; peça ao usuário para executar/setupnovamente. - Usuários existentes de repente não conseguem conectar — a causa mais provável é uma
ENCRYPTION_KEYrotacionada; blobs AES-GCM existentes não podem ser descriptografados com a nova chave. Veja o aviso abaixo.
Como funciona
Armazenamento de credenciais: o handler POST /setup criptografa os dados do formulário com AES-GCM usando ENCRYPTION_KEY e os armazena no KV sob user:u_<random>. Cada requisição MCP lê e descriptografa esse registro, constrói um McpServer para aquela única requisição e despacha via createMcpHandler oficial do Cloudflare. Nenhuma credencial é mantida em memória entre requisições; nenhum Durable Object é usado.
Trate
ENCRYPTION_KEYcomo algo de longa duração. Rotacioná-la invalida todos os registros de usuários existentes (a tag AES-GCM não validará com a nova chave), e todos os seus usuários precisarão executar/setupnovamente. Escolha uma chave deopenssl rand -base64 48uma vez e nunca a altere.
Modelo de autenticação: a URL /mcp/u_<id> é a credencial. O id base64url de 22 caracteres carrega ~128 bits de entropia. Nunca retornamos 401 para esse caminho (o Claude.ai web tem bugs conhecidos com o fluxo 401-depois-OAuth), e retornamos 404 para ids desconhecidos. Isso corresponde ao padrão de token-URL usado pelo Zapier MCP, Pipedream MCP e similares.
Proteções já implementadas:
- Limite de taxa por IP (5 req/min) em
POST /setup, via binding nativo de Rate Limiting do Cloudflare. Cache-Control: no-storenas respostas de/setuppara que a página de sucesso (que contém a URL MCP) e a re-renderização de erro (que ecoa tokens de volta) nunca fiquem em cache.Referrer-Policy: no-referrerem todas as páginas HTML para que a URL MCP não vaze via cabeçalhos de referrer.
Limites a conhecer:
- Plano gratuito do Workers: 100k requisições/dia, 50ms de CPU por requisição (somos limitados por I/O, confortável).
- Plano gratuito do KV: 100k leituras/dia, 1k escritas/dia. A configuração escreve uma vez por usuário; leituras acontecem por chamada MCP.
- O Worker suporta apenas autenticação básica do Jira (token clássico de API + e-mail). Bearer e o fluxo OAuth 2.0 PKCE são apenas para stdio — bearer requer roteamento de URL de gateway que o Worker ainda não faz, e PKCE precisa de um callback de navegador que o Worker não pode hospedar.
Opção 2: Uso via NPX
A forma mais fácil de usar este servidor é via npx, sem instalação:
Conectando ao Claude Desktop (Método NPX)
-
Abra seu arquivo de configuração do cliente MCP:
- Claude Desktop (macOS):
~/Library/Application Support/Claude/claude_desktop_config.json - Claude Desktop (Windows):
%APPDATA%\Claude\claude_desktop_config.json
- Claude Desktop (macOS):
-
Adicione a seguinte configuração:
{
"mcpServers": {
"Jira_Tempo": {
"command": "npx",
"args": ["-y", "@ivelin-web/tempo-mcp-server"],
"env": {
"TEMPO_API_TOKEN": "your_tempo_api_token_here",
"JIRA_API_TOKEN": "your_jira_api_token_here",
"JIRA_EMAIL": "your_email@example.com",
"JIRA_BASE_URL": "https://your-org.atlassian.net"
}
}
}
}
- Reinicie seu cliente Claude Desktop
Instalação com um Clique para Cursor
Opção 3: Clone Local do Repositório
Instalação
# Clone the repository
git clone https://github.com/ivelin-web/tempo-mcp-server.git
cd tempo-mcp-server
# Install dependencies
npm install
# Build TypeScript files
npm run build
Executando Localmente
Existem duas formas de executar o servidor localmente:
1. Usando o MCP Inspector (para desenvolvimento e depuração)
npm run inspect
2. Usando Node diretamente
Você pode executar o servidor diretamente com Node apontando para o arquivo JavaScript compilado:
Conectando ao Claude Desktop (Método Local)
- Abra seu arquivo de configuração do cliente MCP
- Adicione a seguinte configuração:
{
"mcpServers": {
"Jira_Tempo": {
"command": "node",
"args": ["/ABSOLUTE/PATH/TO/tempo-mcp-server/build/index.js"],
"env": {
"TEMPO_API_TOKEN": "your_tempo_api_token_here",
"JIRA_API_TOKEN": "your_jira_api_token_here",
"JIRA_EMAIL": "your_email@example.com",
"JIRA_BASE_URL": "https://your-org.atlassian.net"
}
}
}
}
- Reinicie seu cliente Claude Desktop
Obtendo Tokens de API
-
Token da API do Tempo:
- Vá para Tempo > Configurações > Integração de API
- Crie um novo token de API com Acesso personalizado e selecione no mínimo:
- Apontamentos (Visualizar + Gerenciar) — para todas as ferramentas de apontamento
- Esquemas (Visualizar) — necessário para
getMissingWorklogDays(lê o agendamento do usuário) - Contas (Visualizar) — apenas se seus apontamentos usarem contas do Tempo
- Equipes (Visualizar) — apenas se você usar os filtros
program/team(cobre Equipes e Programas)
- O Tempo não permite editar escopos em um token existente; crie um novo se precisar adicionar escopos depois.
-
Token da API do Jira:
- Vá para Tokens de API do Atlassian
- Clique em "Criar token de API" (o fluxo clássico, sem escopos). É isso que funciona com a autenticação
basicpronta para uso. - Não use "Criar token de API com escopos" — esses tokens devem ser enviados através da URL de gateway do Atlassian (
https://api.atlassian.com/ex/jira/{cloudId}/...) com o cloud ID, que o caminho de autenticaçãobasicdeste servidor não roteia atualmente. Eles falharão com 401 contra a URL do seu site. Se você só tiver um token com escopos disponível (por exemplo, sua organização desativou tokens clássicos), use o fluxo OAuth 2.0 PKCE — ele roteia pelo gateway automaticamente.
Variáveis de Ambiente
O servidor requer as seguintes variáveis de ambiente:
TEMPO_API_TOKEN # Your Tempo API token
JIRA_API_TOKEN # Your Jira API token (required for basic and bearer auth)
JIRA_EMAIL # Your Jira account email (required for basic auth)
JIRA_BASE_URL # Your Jira instance URL (e.g., https://your-org.atlassian.net)
JIRA_AUTH_TYPE # Optional: 'basic' (default), 'bearer', or 'oauth'
JIRA_OAUTH_CLIENT_ID # OAuth 2.0 client ID (required for oauth auth)
JIRA_OAUTH_CLIENT_SECRET # OAuth 2.0 client secret (required for oauth auth)
JIRA_TEMPO_ACCOUNT_CUSTOM_FIELD_ID # Optional: Custom field ID for Tempo accounts
Você pode defini-las no seu ambiente ou fornecê-las na configuração do cliente MCP.
Tipos de Autenticação
O servidor suporta três métodos de autenticação para a API do Jira:
Autenticação Básica (padrão)
Usa e-mail e token de API. Este é o método tradicional:
{
"env": {
"JIRA_API_TOKEN": "your_api_token",
"JIRA_EMAIL": "your_email@example.com",
"JIRA_AUTH_TYPE": "basic"
}
}
Autenticação com Token Bearer (OAuth 2.0)
Para usuários que desejam usar tokens OAuth 2.0 com escopos para maior segurança:
{
"env": {
"JIRA_API_TOKEN": "your_oauth_access_token",
"JIRA_AUTH_TYPE": "bearer"
}
}
Nota: Ao usar autenticação bearer, JIRA_EMAIL não é necessário, pois o usuário é identificado pelo token.
Autenticação OAuth 2.0 PKCE
Algumas organizações Atlassian restringem o acesso a tokens de API por política administrativa, o que faz a autenticação básica e bearer falharem. O tipo oauth implementa o fluxo completo de código de autorização OAuth 2.0 com PKCE e funciona independentemente de restrições de token de API — os tokens são de curta duração e renovados automaticamente, sem gerenciamento manual.
No primeiro uso, uma janela do navegador abre para você autorizar o acesso. Os tokens são armazenados localmente em ~/.tempo-mcp-server/tokens.json e renovados automaticamente.
-
Crie um aplicativo OAuth 2.0 no Console de Desenvolvedor Atlassian com os escopos
read:jira-usereread:jira-workehttp://localhost:7788/callbackcomo URL de callback. -
Configure o servidor:
{
"env": {
"JIRA_BASE_URL": "https://your-org.atlassian.net",
"JIRA_AUTH_TYPE": "oauth",
"JIRA_OAUTH_CLIENT_ID": "your_client_id",
"JIRA_OAUTH_CLIENT_SECRET": "your_client_secret"
}
}
Nota: JIRA_API_TOKEN e JIRA_EMAIL não são necessários ao usar autenticação oauth.
Configuração de Conta do Tempo
Se sua instância do Tempo exigir que apontamentos sejam vinculados a contas, defina o ID do campo personalizado que contém as informações da conta:
JIRA_TEMPO_ACCOUNT_CUSTOM_FIELD_ID=10234
Para encontrar seu ID de campo personalizado:
- Vá para Configurações do Jira → Issues → Campos Personalizados
- Encontre seu campo de conta do Tempo e anote o ID da URL ou da configuração do campo
Visualizando Apontamentos de Outros Usuários
As ferramentas de leitura (retrieveWorklogs, getWorklogAnalytics, getMissingWorklogDays) usam por padrão os apontamentos do próprio dono do token, mas aceitam filtros opcionais para direcionar outras pessoas — útil para administradores, gerentes de projeto e líderes de equipe:
users— array de e-mails, nomes de exibição ou accountIds do Jira (ex.:["ivan@company.com", "Maria Petrova"])program— nome ou id do Programa do Tempo; expande para todos os membros atuais das equipes do programateam— nome ou id da Equipe do Tempo; expande para todos os membros atuais da equipe
Os filtros combinam como uma união. O Tempo aplica permissões no lado do servidor: a API omite silenciosamente apontamentos que o dono do token não tem permissão de ver (nenhum erro é retornado). Para visualizar outros usuários, você precisa de:
- Um Papel de Permissão do Tempo com Visualizar Apontamentos concedido ao dono do token (Tempo > Configurações > Papéis de Permissão) — "Completo" para todos, ou "Restrito" + equipes selecionadas
- Permissão Navegar Projetos do Jira nos projetos relevantes
- O escopo Equipes no token da API do Tempo se você usar os filtros
program/teamgetWorklogAnalyticstambém suportagroupBy: "user"— combinado comprogram, ele produz um relatório de horas por pessoa em uma única chamada.getMissingWorklogDayscom um filtro retorna um relatório por usuário dos dias com tempo ausente (visualizar as agendas de outros usuários também é controlado por permissões).
Ferramentas Disponíveis
retrieveWorklogs
Busca apontamentos para o usuário configurado (ou outros usuários via filtros) entre as datas de início e fim.
Parameters:
- startDate: String (YYYY-MM-DD)
- endDate: String (YYYY-MM-DD)
- users: String[] (optional) — emails, display names, or accountIds
- program: String (optional) — Tempo Program name or id
- team: String (optional) — Tempo Team name or id
createWorklog
Cria um novo apontamento para um problema específico do Jira.
Parameters:
- issueKey: String (e.g., "PROJECT-123")
- timeSpentHours: Number (positive)
- date: String (YYYY-MM-DD)
- description: String (optional)
- startTime: String (HH:MM format, optional)
bulkCreateWorklogs
Cria vários apontamentos em uma única operação.
Parameters:
- worklogEntries: Array of {
issueKey: String
timeSpentHours: Number
date: String (YYYY-MM-DD)
description: String (optional)
startTime: String (HH:MM format, optional)
}
editWorklog
Modifica um apontamento existente.
Parameters:
- worklogId: String
- timeSpentHours: Number (positive)
- description: String (optional)
- date: String (YYYY-MM-DD, optional)
- startTime: String (HH:MM format, optional)
deleteWorklog
Remove um apontamento existente.
Parameters:
- worklogId: String
getMissingWorklogDays
Relata os dias úteis em um intervalo de datas em que o usuário registrou menos tempo do que o esperado. As horas esperadas por dia vêm da agenda do usuário no Tempo, portanto feriados, dias não úteis e agendas de meio período são respeitados automaticamente. Com users / program / team, ele verifica outras pessoas e retorna um relatório por usuário (ordenado pelas horas ausentes mais altas).
Parameters:
- startDate: String (YYYY-MM-DD)
- endDate: String (YYYY-MM-DD)
- minHoursPerDay: Number (optional) — override the per-day threshold;
non-working days are still skipped
- users: String[] (optional) — emails, display names, or accountIds
- program: String (optional) — Tempo Program name or id
- team: String (optional) — Tempo Team name or id
Escopo do Tempo necessário: o
TEMPO_API_TOKENdeve incluir o escopo Schemes (cobre Workload Schemes, Holiday Schemes, User Schedule) além de Worklogs. O Tempo não permite modificar escopos em um token existente — se o seu token atual tiver apenas Worklogs, crie um novo em Tempo > Settings > API Integration.
getWorklogAnalytics
Agrega apontamentos em um intervalo de datas e retorna horas, contagem de apontamentos e porcentagem por grupo, ordenados por horas em ordem decrescente. Combine groupBy: "user" com program / team / users para um relatório por pessoa.
Parameters:
- startDate: String (YYYY-MM-DD)
- endDate: String (YYYY-MM-DD)
- groupBy: "issue" | "account" | "user" | "day" | "week" | "month" (optional, default "issue")
- users: String[] (optional) — emails, display names, or accountIds
- program: String (optional) — Tempo Program name or id
- team: String (optional) — Tempo Team name or id
Estrutura do Projeto
tempo-mcp-server/
├── src/ # Source code
│ ├── authors.ts # Author filter resolution (users/program/team → accountIds)
│ ├── config.ts # Configuration management
│ ├── index.ts # MCP server implementation
│ ├── jira.ts # Jira API integration
│ ├── oauth.ts # OAuth 2.0 PKCE flow and token management
│ ├── tools.ts # Tool implementations
│ ├── types.ts # TypeScript types and schemas
│ └── utils.ts # Utility functions
├── build/ # Compiled JavaScript (generated)
├── tsconfig.json # TypeScript configuration
└── package.json # Project metadata and scripts
Solução de Problemas
Se você encontrar problemas:
- Verifique se todas as variáveis de ambiente estão configuradas corretamente
- Confirme se os tokens de API do Jira e do Tempo têm as permissões corretas
- Verifique a saída do console para mensagens de erro
- Tente executar com o inspetor:
npm run inspect
Licença
Créditos
Este servidor implementa a especificação Model Context Protocol criada pela Anthropic.
