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

MseeP.ai Security Assessment Badge

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.

npm version License: MIT

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:

  1. 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.
  2. NPX: Ejecuta directamente con npx en tu portátil, sin necesidad de clonar.
  3. 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:

  1. Abre https://<your-deployment>.workers.dev/setup.
  2. Pega tu token de API de Tempo, URL base de Jira, token de API de Jira y correo de Jira. Pulsa Generar URL MCP.
  3. La página devuelve una URL personal como https://<your-deployment>.workers.dev/mcp/u_<random>. Cópiala.
  4. En Claude.ai → Configuración → Conectores → Añadir conector personalizado, pega la URL.
  5. 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 npm localmente — solo se usan para el CLI de wrangler; 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.jsonc kv_namespaces[0].id comprometido pertenece a la cuenta de Cloudflare del mantenedor original. Reemplázalo con el id que devolvió el paso 2, de lo contrario wrangler deploy fallará con KV 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 (usa tsconfig.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].id en wrangler.jsonc está vacío (o es incorrecto). Ejecuta npx wrangler kv namespace create USERS y pega el nuevo id.
  • ENCRYPTION_KEY is not defined en 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 bloque ratelimits en wrangler.jsonc y la llamada a SETUP_RATE_LIMITER.limit(...) en src/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_KEY rotado; 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_KEY como 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 de openssl rand -base64 48 una 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-store en las respuestas de /setup para 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-referrer en 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)

  1. 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
  2. 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"
      }
    }
  }
}
  1. Reinicia tu cliente de Claude Desktop

Instalación con un clic para Cursor

Install MCP Server

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)

  1. Abre tu archivo de configuración del cliente MCP
  2. 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"
      }
    }
  }
}
  1. Reinicia tu cliente de Claude Desktop

Obtención de tokens de API

  1. 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.
  2. 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 basic de 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ón basic de 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.

  1. Crea una aplicación OAuth 2.0 en Consola de desarrollador de Atlassian con los ámbitos read:jira-user y read:jira-work y http://localhost:7788/callback como URL de devolución de llamada.

  2. 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:

  1. Ve a Configuración de Jira → Incidencias → Campos personalizados
  2. 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 programa
  • team — 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:

  1. 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
  2. Permiso de Explorar proyectos de Jira en los proyectos relevantes
  3. El ámbito Equipos en el token de API de Tempo si usas los filtros program / team getWorklogAnalytics también admite groupBy: "user" — combinado con program, produce un informe de horas por persona en una sola llamada. getMissingWorklogDays con 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_TOKEN debe 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:

  1. Verifica que todas las variables de entorno estén configuradas correctamente
  2. Verifica que tus tokens de API de Jira y Tempo tengan los permisos correctos
  3. Revisa la salida de la consola para ver mensajes de error
  4. Intenta ejecutar con el inspector: npm run inspect

Licencia

MIT

Créditos

Este servidor implementa la especificación Model Context Protocol creada por Anthropic.