Tempo MCP Server
Un servidor MCP para gestionar registros de trabajo de Tempo en Jira. Se conecta a los servicios de Jira y Tempo mediante tokens de API y variables de entorno.
Documentación
Servidor MCP de Tempo
Un servidor de Protocolo de Contexto de Modelo (MCP) para gestionar partes de trabajo de Tempo en Jira. Este servidor proporciona herramientas para registrar tiempo y gestionar partes de trabajo a través de la API de Tempo, haciéndolo accesible a través de Claude, Cursor y otros clientes compatibles con MCP.
Características
- Recuperar partes de trabajo: Obtén todos los partes de trabajo para un rango de fechas específico
- Crear parte de trabajo: Registra tiempo en incidencias de Jira
- Creación masiva: Crea múltiples partes de trabajo en una sola operación
- Editar parte de trabajo: Modifica tiempo invertido, fechas y descripciones
- Eliminar parte de trabajo: Elimina partes de trabajo existentes
- Informe de días faltantes: Encuentra días laborables donde registraste menos de lo esperado (usa el horario de usuario de Tempo, por lo que los días festivos y no laborables se omiten automáticamente)
- Analíticas de partes de trabajo: Agrega horas por incidencia, cuenta, día, semana o mes con totales y porcentajes
Requisitos del sistema
- Node.js 18+ (se recomienda LTS) — solo necesario para los modos stdio locales
- Instancia de Jira Cloud
- Token de API de Tempo
- Token de API de Jira (no requerido al usar autenticación OAuth 2.0 PKCE)
Opciones de uso
Hay tres formas de usar este servidor MCP:
- Remoto / Cloudflare Workers (sin instalación) — aloja una vez, comparte con tu equipo. Cada usuario genera su propia URL mediante una página de configuración y la pega en Claude.ai o ChatGPT. Funciona desde web y móvil.
- NPX: Ejecuta directamente con
npxen tu portátil, sin necesidad de clonar. - Clon local: Clona el repositorio para desarrollo o personalización.
Si solo quieres usar el servidor, la opción 1 es la más fácil y también funciona en teléfonos. Si eres un mantenedor que despliega para tu equipo, consulta la guía de despliegue remoto.
Opción 1: Remoto (Cloudflare Workers)
Para usuarios finales
Una vez que tu equipo haya desplegado el servidor, el flujo es:
- Abre
https://<your-deployment>.workers.dev/setup. - Pega tu token de API de Tempo, URL base de Jira, token de API de Jira y correo de Jira. Pulsa Generar URL MCP.
- La página devuelve una URL personal como
https://<your-deployment>.workers.dev/mcp/u_<random>. Cópiala. - En Claude.ai → Configuración → Conectores → Añadir conector personalizado, pega la URL.
- El conector se sincroniza en web, escritorio y móvil (iOS/Android).
Para ChatGPT: activa Configuración → Apps → Avanzado → Modo desarrollador (Pro/Plus/Business+), luego añade la URL como servidor MCP personalizado. Las cuentas Plus/Pro pueden leer; las herramientas de escritura (crear/editar partes de trabajo) requieren Business+ según el nivel de OpenAI.
La URL contiene tus credenciales — trátala como una contraseña, no la compartas ni la subas a un repositorio.
Despliegue remoto (Cloudflare Workers)
Alojamiento gratuito en Cloudflare Workers. Aproximadamente 5–10 minutos desde el clon hasta la URL en vivo. Cualquiera puede hacer un fork y autoalojarse — no se necesita coordinación con el mantenedor.
Requisitos previos
- Una cuenta de Cloudflare (el plan gratuito es suficiente).
- Node.js 18+ y
npmlocalmente — solo se usan para el CLI dewrangler; el runtime del Worker en sí no ejecuta Node.
Configuración 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
⚠️ Si hiciste un fork del repositorio: el
wrangler.jsonckv_namespaces[0].idcomprometido pertenece a la cuenta de Cloudflare del mantenedor original. Reemplázalo con el id que devolvió el paso 2, de lo contrariowrangler deployfallará conKV namespace … is not valid. Los ids de espacios de nombres KV son identificadores públicos por cuenta, no secretos, pero cada cuenta tiene los suyos.
# 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
Visita /setup en la URL desplegada para incorporar a tu primer usuario.
Actualizar un despliegue existente
Después de extraer nuevas confirmaciones del repositorio original:
npm install # picks up any new deps
npm run remote:deploy # ships the new Worker bundle
Los secretos y los datos de KV persisten entre despliegues. compatibility_date y compatibility_flags en wrangler.jsonc están fijados, por lo que el comportamiento no cambia silenciosamente cuando Cloudflare publica cambios en el runtime.
Desarrollo 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
Otros scripts útiles:
npm run remote:typecheck— comprueba los tipos del bundle del Worker (usatsconfig.worker.json).npm run remote:tail— transmite registros en vivo desde el Worker desplegado.
Solución de problemas
KV namespace … is not valid—kv_namespaces[0].idenwrangler.jsoncestá vacío (o es incorrecto). Ejecutanpx wrangler kv namespace create USERSy pega el nuevo id.ENCRYPTION_KEY is not defineden tiempo de ejecución — el secreto no se configuró. Vuelve a ejecutar el paso 3.Rate limit binding … not available— el plan de tu cuenta no incluye la API de Limitación de Tasa de Workers. O bien mejora el plan, o elimina el bloqueratelimitsenwrangler.jsoncy la llamada aSETUP_RATE_LIMITER.limit(...)ensrc/remote/worker.ts.- 404 de
/mcp/u_…— el id de usuario es desconocido (o nunca existió). El Worker devuelve 404 por diseño para ids inválidos/ausentes; haz que el usuario vuelva a ejecutar/setup. - Los usuarios existentes de repente no pueden conectarse — la causa más probable es un
ENCRYPTION_KEYrotado; los blobs AES-GCM existentes no se pueden descifrar con la nueva clave. Consulta la advertencia a continuación.
Cómo funciona
Almacenamiento de credenciales: el manejador POST de /setup cifra los datos del formulario con AES-GCM usando ENCRYPTION_KEY y los almacena en KV bajo user:u_<random>. Cada solicitud MCP lee y descifra ese registro, construye un McpServer para esa única solicitud y lo envía a través del createMcpHandler oficial de Cloudflare. No se mantienen credenciales en memoria entre solicitudes; no se usan Objetos Duraderos.
Trata
ENCRYPTION_KEYcomo de larga duración. Rotarlo invalida todos los registros de usuario existentes (la etiqueta AES-GCM no se validará con la nueva clave), y todos tus usuarios tendrán que volver a ejecutar/setup. Elige una clave deopenssl rand -base64 48una vez y nunca la cambies.
Modelo de autenticación: la URL /mcp/u_<id> es la credencial. El id base64url de 22 caracteres lleva ~128 bits de entropía. Nunca devolvemos 401 para esa ruta (Claude.ai web tiene errores conocidos con el flujo 401-luego-OAuth), y devolvemos 404 para ids desconocidos. Esto coincide con el patrón de token-URL usado por Zapier MCP, Pipedream MCP y similares.
Endurecimiento ya implementado:
- Límite de tasa por IP (5 solicitudes/min) en
POST /setup, mediante el enlace nativo de Limitación de Tasa de Cloudflare. Cache-Control: no-storeen las respuestas de/setuppara que la página de éxito (que contiene la URL MCP) y el re-renderizado de error (que devuelve los tokens) nunca queden en ninguna caché.Referrer-Policy: no-referreren cada página HTML para que la URL MCP no se filtre a través de las cabeceras de referrer.
Límites a tener en cuenta:
- Plan gratuito de Workers: 100k solicitudes/día, 50ms de CPU por solicitud (somos intensivos en E/S, cómodo).
- Plan gratuito de KV: 100k lecturas/día, 1k escrituras/día. La configuración escribe una vez por usuario; las lecturas ocurren por llamada MCP.
- El Worker solo admite autenticación básica de Jira (token de API clásico + correo). Bearer y el flujo OAuth 2.0 PKCE son solo stdio — bearer requiere enrutamiento de URL de puerta de enlace que el Worker aún no hace, y PKCE necesita una devolución de llamada de navegador que el Worker no puede alojar.
Opción 2: Uso con NPX
La forma más fácil de usar este servidor es mediante npx sin instalación:
Conexión a Claude Desktop (método NPX)
-
Abre tu archivo de configuración del 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):
-
Añade la siguiente configuración:
{
"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"
}
}
}
}
- Reinicia tu cliente de Claude Desktop
Instalación con un clic para Cursor
Opción 3: Clon del repositorio local
Instalación
# 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
Ejecución local
Hay dos formas de ejecutar el servidor localmente:
1. Usando el Inspector MCP (para desarrollo y depuración)
npm run inspect
2. Usando Node directamente
Puedes ejecutar el servidor directamente con Node apuntando al archivo JavaScript compilado:
Conexión a Claude Desktop (método local)
- Abre tu archivo de configuración del cliente MCP
- Añade la siguiente configuración:
{
"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"
}
}
}
}
- Reinicia tu cliente de Claude Desktop
Obtención de tokens de API
-
Token de API de Tempo:
- Ve a Tempo > Configuración > Integración de API
- Crea un nuevo token de API con Acceso personalizado y selecciona como mínimo:
- Partes de trabajo (Ver + Gestionar) — para todas las herramientas de partes de trabajo
- Esquemas (Ver) — requerido para
getMissingWorklogDays(lee el horario de usuario) - Cuentas (Ver) — solo si tus partes de trabajo usan cuentas de Tempo
- Equipos (Ver) — solo si usas los filtros
program/team(cubre Equipos y Programas)
- Tempo no permite editar los ámbitos de un token existente; crea uno nuevo si necesitas añadir ámbitos más adelante.
-
Token de API de Jira:
- Ve a Tokens de API de Atlassian
- Haz clic en "Crear token de API" (el flujo clásico sin ámbitos). Esto es lo que funciona con la autenticación
basicde forma predeterminada. - No uses "Crear token de API con ámbitos" — esos tokens deben enviarse a través de la URL de puerta de enlace de Atlassian (
https://api.atlassian.com/ex/jira/{cloudId}/...) con el id de nube, que la ruta de autenticaciónbasicde este servidor no enruta actualmente. Fallarán con 401 contra la URL de tu sitio. Si solo tienes disponible un token con ámbitos (por ejemplo, tu organización deshabilitó los tokens clásicos), usa el flujo OAuth 2.0 PKCE en su lugar — enruta a través de la puerta de enlace automáticamente.
Variables de entorno
El servidor requiere las siguientes variables de entorno:
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
Puedes configurarlas en tu entorno o proporcionarlas en la configuración del cliente MCP.
Tipos de autenticación
El servidor admite tres métodos de autenticación para la API de Jira:
Autenticación básica (predeterminada)
Usa correo y token de API. Este es el método tradicional:
{
"env": {
"JIRA_API_TOKEN": "your_api_token",
"JIRA_EMAIL": "your_email@example.com",
"JIRA_AUTH_TYPE": "basic"
}
}
Autenticación con token Bearer (OAuth 2.0)
Para usuarios que quieren usar tokens con ámbitos de OAuth 2.0 para mayor seguridad:
{
"env": {
"JIRA_API_TOKEN": "your_oauth_access_token",
"JIRA_AUTH_TYPE": "bearer"
}
}
Nota: Al usar autenticación bearer, JIRA_EMAIL no es necesario ya que el usuario se identifica desde el token.
Autenticación OAuth 2.0 PKCE
Algunas organizaciones de Atlassian restringen el acceso a tokens de API mediante política de administración, lo que hace que la autenticación básica y bearer fallen. El tipo oauth implementa el flujo completo de código de autorización OAuth 2.0 con PKCE y funciona independientemente de las restricciones de tokens de API — los tokens son de corta duración y se renuevan automáticamente sin gestión manual.
En el primer uso, se abre una ventana del navegador para que autorices el acceso. Los tokens se almacenan localmente en ~/.tempo-mcp-server/tokens.json y se renuevan automáticamente.
-
Crea una aplicación OAuth 2.0 en Consola de desarrollador de Atlassian con los ámbitos
read:jira-useryread:jira-workyhttp://localhost:7788/callbackcomo URL de devolución de llamada. -
Configura el 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 y JIRA_EMAIL no son necesarios al usar autenticación oauth.
Configuración de cuentas de Tempo
Si tu instancia de Tempo requiere que los partes de trabajo estén vinculados a cuentas, configura el id de campo personalizado que contiene la información de la cuenta:
JIRA_TEMPO_ACCOUNT_CUSTOM_FIELD_ID=10234
Para encontrar tu id de campo personalizado:
- Ve a Configuración de Jira → Incidencias → Campos personalizados
- Encuentra tu campo de cuenta de Tempo y anota el id desde la URL o la configuración del campo
Ver partes de trabajo de otros usuarios
Las herramientas de lectura (retrieveWorklogs, getWorklogAnalytics, getMissingWorklogDays) usan por defecto los partes de trabajo del propietario del token, pero aceptan filtros opcionales para apuntar a otras personas — útil para administradores, gestores de proyectos y líderes de equipo:
users— array de correos, nombres para mostrar o accountIds de Jira (por ejemplo,["ivan@company.com", "Maria Petrova"])program— nombre o id de Programa de Tempo; se expande a todos los miembros actuales de los equipos del programateam— nombre o id de Equipo de Tempo; se expande a todos los miembros actuales del equipo
Los filtros se combinan como una unión. Tempo aplica los permisos en el servidor: la API omite silenciosamente los partes de trabajo que el propietario del token no tiene permitido ver (no se devuelve ningún error). Para ver partes de trabajo de otros usuarios necesitas:
- Un Rol de permiso de Tempo con Ver partes de trabajo otorgado al propietario del token (Tempo > Configuración > Roles de permiso) — "Completo" para todos, o "Restringido" + equipos seleccionados
- Permiso de Explorar proyectos de Jira en los proyectos relevantes
- El ámbito Equipos en el token de API de Tempo si usas los filtros
program/teamgetWorklogAnalyticstambién admitegroupBy: "user"— combinado conprogram, produce un informe de horas por persona en una sola llamada.getMissingWorklogDayscon un filtro devuelve un informe por usuario de los días con tiempo faltante (ver los horarios de otros usuarios también está restringido por permisos).
Herramientas Disponibles
retrieveWorklogs
Obtiene los worklogs del usuario configurado (u otros usuarios mediante filtros) entre las fechas de inicio y fin.
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
Crea un nuevo worklog para un issue específico de 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
Crea múltiples worklogs en una sola operación.
Parameters:
- worklogEntries: Array of {
issueKey: String
timeSpentHours: Number
date: String (YYYY-MM-DD)
description: String (optional)
startTime: String (HH:MM format, optional)
}
editWorklog
Modifica un worklog existente.
Parameters:
- worklogId: String
- timeSpentHours: Number (positive)
- description: String (optional)
- date: String (YYYY-MM-DD, optional)
- startTime: String (HH:MM format, optional)
deleteWorklog
Elimina un worklog existente.
Parameters:
- worklogId: String
getMissingWorklogDays
Informa los días laborables en un rango de fechas donde el usuario ha registrado menos tiempo del esperado. Las horas esperadas por día provienen del horario del usuario en Tempo, por lo que los días festivos, los días no laborables y los horarios a tiempo parcial se respetan automáticamente. Con users / program / team comprueba a otras personas y devuelve un informe por usuario (ordenado por más horas faltantes).
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
Alcance de Tempo requerido: el
TEMPO_API_TOKENdebe incluir el alcance Schemes (cubre Workload Schemes, Holiday Schemes, User Schedule) además de Worklogs. Tempo no permite modificar los alcances en un token existente — si tu token actual solo tiene Worklogs, crea uno nuevo en Tempo > Settings > API Integration.
getWorklogAnalytics
Agrega worklogs en un rango de fechas y devuelve horas, número de worklogs y porcentaje por grupo, ordenados por horas en orden descendente. Combina groupBy: "user" con program / team / users para un informe por persona.
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
Estructura del Proyecto
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
Solución de Problemas
Si encuentras problemas:
- Verifica que todas las variables de entorno estén configuradas correctamente
- Verifica que tus tokens de API de Jira y Tempo tengan los permisos correctos
- Revisa la salida de la consola para ver mensajes de error
- Intenta ejecutar con el inspector:
npm run inspect
Licencia
Créditos
Este servidor implementa la especificación Model Context Protocol creada por Anthropic.
