Skip to main content
Glama

productive-mcp

Un servidor MCP para Productive.io: registra tiempo, inspecciona proyectos y gestiona entradas de tiempo desde cualquier cliente compatible con MCP (Claude Code, Claude Desktop, Cursor, etc.) usando inglés sencillo:

"log 2.5 hours on the Acme security review project"

"show me my time entries for last week"

"delete time entry 123456"

Construido sobre la API JSON:API v2 de Productive.io con coincidencia difusa de proyectos, caché de disco local y memoria de servicio predeterminado por proyecto, para que el caso común (registrar tiempo en un proyecto que usas regularmente) sea una sola frase.


Características

  • 9 herramientas que cubren proyectos, servicios y entradas de tiempo (listar / crear / actualizar / eliminar)

  • Coincidencia difusa de proyectos: "Acme", "1099 Acme" o "1099" se resuelven en el mismo proyecto

  • Recuerda tu servicio predeterminado por proyecto para que no tengas que especificarlo cada vez

  • Caché local para proyectos y servicios (TTL de 1 hora, actualizable manualmente)

  • Seguridad de credenciales: el token de API se lee del Llavero de macOS por defecto (se admiten variables de entorno como alternativa para Linux/WSL o uso sin interfaz gráfica)

  • Entrada en hours, salida en hours: la API usa minutos internamente, pero tú nunca los ves

  • Alcance "mío" por defecto: list_time_entries solo muestra tus propias entradas a menos que decidas lo contrario

Requisitos

  • Python 3.11+

  • Una cuenta de Productive.io con acceso a la API habilitado

  • macOS (recomendado, para la integración con el Llavero) — Linux / WSL funcionan mediante variables de entorno

Instalación

1. Clonar e instalar

git clone https://github.com/<you>/productive-mcp.git
cd productive-mcp
uv venv
uv pip install -e .

(o python -m venv .venv && .venv/bin/pip install -e . si no usas uv)

2. Obtén tus credenciales de Productive

Necesitas tres valores:

Valor

Dónde encontrarlo

Token de API

Productive → Ajustes → Integraciones de API → Generar nuevo token

ID de organización

El segmento numérico en tu URL de Productive: app.productive.io/<ORG_ID>/…

ID de persona

Tu propio ID de usuario: abre tu perfil en Productive; es el segmento numérico en la URL

3. Almacenar credenciales

Opción A — Llavero de macOS (recomendado en macOS)

security add-generic-password -s productive-mcp -a token      -w "<token>"      -U
security add-generic-password -s productive-mcp -a org_id     -w "<org_id>"     -U
security add-generic-password -s productive-mcp -a person_id  -w "<person_id>"  -U

El servidor busca estos valores al iniciar mediante la CLI security. Nunca se escriben en el disco por este proyecto.

Opción B — variables de entorno (Linux / WSL / CI / anulación)

export PRODUCTIVE_MCP_TOKEN="<token>"
export PRODUCTIVE_MCP_ORG_ID="<org_id>"
export PRODUCTIVE_MCP_PERSON_ID="<person_id>"

Las variables de entorno tienen prioridad sobre las búsquedas en el Llavero, por lo que también son la forma más sencilla de probar cuentas alternativas temporalmente.

4. Registra el servidor con tu cliente MCP

Claude Code (~/.claude.json)

Añade bajo mcpServers:

{
  "mcpServers": {
    "productive": {
      "type": "stdio",
      "command": "/path/to/productive-mcp/.venv/bin/productive-mcp",
      "args": []
    }
  }
}

Claude Desktop (claude_desktop_config.json)

{
  "mcpServers": {
    "productive": {
      "command": "/path/to/productive-mcp/.venv/bin/productive-mcp"
    }
  }
}

Reinicia el cliente después de editar su configuración.

5. (Opcional) Instalación global con el script de despliegue incluido

Si quieres una instalación compartida que no esté vinculada a un directorio de clonación:

bash scripts/install.sh

Esto crea ~/.local/share/productive-mcp/ conteniendo un venv nuevo y un lanzador run.sh. Apunta tu cliente MCP a ~/.local/share/productive-mcp/run.sh en lugar del binario del venv. Volver a ejecutar el script actualiza el venv en su lugar.


Herramientas

Todas las herramientas tienen el prefijo productive_ para que se agrupen limpiamente junto a otros servidores MCP.

Herramienta

Propósito

productive_list_projects

Listar todos los proyectos activos (id, nombre, número, empresa)

productive_find_project

Búsqueda difusa de proyectos por nombre y/o número

productive_list_services

Listar servicios (tipos de actividad facturables) en un proyecto dado

productive_log_time

Crear una entrada de tiempo

productive_list_time_entries

Listar entradas de tiempo con filtros opcionales de fecha/proyecto/propietario

productive_update_time_entry

Editar horas / fecha / nota / servicio en una entrada existente

productive_delete_time_entry

Eliminar permanentemente una entrada de tiempo

productive_refresh_cache

Forzar una actualización inmediata de la caché (después de crear nuevos proyectos/servicios)

productive_set_default_service

Anular el servicio predeterminado recordado para un proyecto

Referencia de herramientas

productive_log_time

project       : str   — Project name (fuzzy) or numeric id. e.g. "1099 Acme", "42"
hours         : float — Hours worked (e.g. 2.5). Converted to minutes internally.
note          : str?  — Description of the work
date          : str?  — ISO date (YYYY-MM-DD). Defaults to today.
service_hint  : str?  — Service name or id (only needed when the project has
                        multiple services and no remembered default)

Si tiene éxito, devuelve la entrada creada más una nota service_resolution explicando cómo se eligió el servicio ("auto-selected only service" / "used remembered default" / "matched by name" etc.).

Si el proyecto tiene solo un servicio, se selecciona automáticamente y se guarda como predeterminado para la próxima vez. Si tiene varios, el servidor devuelve un error accionable listando las opciones.

productive_find_project

query : str — Partial name or number (e.g. "Acme", "1099 acme", "1099")
limit : int — Max matches (default 5)

Devuelve coincidencias puntuadas ordenadas de mejor a peor. El buscador difuso combina la coincidencia de subcadenas de tokens, una alternativa de coincidencia de secuencias para errores tipográficos y un impulso cuando la consulta contiene un número de proyecto exacto.

productive_list_time_entries

after     : str?  — Include entries on/after this ISO date
before    : str?  — Include entries on/before this ISO date
project   : str?  — Filter by project name or id
mine_only : bool  — Default True; set False to see the whole team's entries

Las entradas se devuelven de más reciente a más antigua, con totales acumulados en total_hours.


Cómo funciona

Arquitectura

┌─────────────────────┐   stdio    ┌──────────────────────┐   HTTPS   ┌─────────────────┐
│  MCP client         │ ─────────► │  productive-mcp      │ ────────► │  Productive.io  │
│  (Claude Code etc.) │            │  (FastMCP server)    │           │  JSON:API v2    │
└─────────────────────┘            └──────────┬───────────┘           └─────────────────┘
                                              │
                                              ▼
                                    ~/.config/productive-mcp/
                                    ├── cache.json        (projects, services; 1h TTL)
                                    └── preferences.json  (per-project default service)

Decisiones clave de diseño

  • Los servicios están vinculados a Deals, que pertenecen a Proyectos. El modelo de datos de Productive hace esto visible; el MCP recorre la jerarquía de forma transparente para que "servicios en el proyecto X" simplemente funcione.

  • Las horas son la única unidad orientada al usuario. La API almacena el tiempo en minutos; esta capa realiza la conversión en el límite.

  • Los valores predeterminados recordados reducen el ir y venir. Después de registrar tiempo en un proyecto una vez, las llamadas posteriores pueden omitir service_hint: el valor predeterminado se recuerda por proyecto en preferences.json.

  • Coincidencia difusa sobre coincidencia exacta. La mayoría de las solicitudes de registro de tiempo dicen algo como "esa revisión de seguridad para Acme", no "proyecto #1099". El resolutor se inclina hacia el lenguaje natural.

  • Solo "mío" por defecto. Casi siempre estás registrando tiempo para ti mismo; la única persona que necesita visibilidad de todo el equipo puede pasar mine_only=False.

Estado local

Dos archivos viven bajo ~/.config/productive-mcp/, ambos creados con permisos 0600:

  • cache.json: lista de proyectos recortada y búsqueda de servicios por proyecto. Se actualiza automáticamente al expirar el TTL o mediante productive_refresh_cache.

  • preferences.json: { "default_services": { "<project_id>": "<service_id>" } }.

Ninguno de los archivos contiene credenciales.

Orden de búsqueda de credenciales

  1. Variable de entorno (PRODUCTIVE_MCP_TOKEN / _ORG_ID / _PERSON_ID)

  2. Llavero de macOS (security find-generic-password -s productive-mcp -a <account>)

  3. Error: el servidor se niega a iniciar con un mensaje útil que apunta a ambas opciones.


Desarrollo

uv pip install -e ".[dev]"

# unit tests (no network required)
pytest

# integration tests (hit the real Productive API — requires credentials)
pytest -m integration

# lint + type check
ruff check .
mypy src

Ejecuta el servidor directamente para depurar:

.venv/bin/productive-mcp
# or
python -m productive_mcp

Habla JSON-RPC por stdio, así que para probarlo manualmente necesitarás un cliente MCP o mcp-inspector.

Diseño del proyecto

src/productive_mcp/
├── __main__.py      Entrypoint (`python -m productive_mcp`)
├── server.py        FastMCP tool definitions
├── client.py        Async Productive.io API client + fuzzy matcher
├── auth.py          Keychain / env-var credential loader
└── storage.py       Local cache + preferences persistence
scripts/
└── install.sh       One-shot deploy script for the global launcher
tests/
└── test_client.py   Unit tests for trimming + fuzzy matching

Solución de problemas

"Keychain lookup failed" O el elemento aún no existe (vuelve a ejecutar los comandos security add-generic-password en el paso 3) o no estás en macOS. Usa variables de entorno en su lugar.

"No project matches 'X'" Tu caché puede estar desactualizada si el proyecto se creó recientemente. Llama a productive_refresh_cache e inténtalo de nuevo.

"Ambiguous project query" Dos proyectos obtuvieron una puntuación casi idéntica. Sé más específico: añade el número de proyecto o el nombre de la empresa.

"Project has multiple services; pass service_hint" El proyecto aún no tiene un valor predeterminado establecido. Pasa service_hint="…" en esta llamada (se recordará) o llama a productive_set_default_service una vez por adelantado.

El servidor inicia, pero el cliente informa "no tools" Asegúrate de que tu cliente MCP apunte al binario productive-mcp del venv (o al lanzador run.sh), no a un archivo fuente. FastMCP anuncia las herramientas en el momento del saludo: si el proceso no puede importar mcp, no aparecerá ninguna herramienta.


Notas de seguridad

  • Los tokens de API nunca son escritos en el disco por este proyecto. Solo viven en el Llavero o en variables de entorno.

  • Los archivos de caché y preferencias se crean con permisos 0600 y no contienen credenciales.

  • El token de la API de Productive otorga el mismo acceso que tiene tu usuario. Trátalo en consecuencia. Rótalo a través de Productive → Ajustes → Integraciones de API si sospechas de exposición.

Alternativas

Existen otros servidores MCP de Productive.io; vale la pena revisarlos antes de adoptar este:

¿Por qué elegir este? Este servidor está estrechamente enfocado en el flujo de trabajo de "registrar tiempo y gestionar entradas", y la UX está construida en torno a tres decisiones:

  1. Credenciales en el Llavero de macOS por defecto, no en un .env: sin riesgo de que un token termine en git status.

  2. Coincidencia difusa de proyectos con impulso por número de proyecto: di "1099 Acme" o solo "Acme"; ambos funcionan.

  3. Memoria de servicio predeterminado por proyecto: después del primer productive_log_time en un proyecto, las llamadas posteriores no necesitan especificar un servicio.

Si necesitas principalmente tareas/tableros/flujos de trabajo en lugar de registro de tiempo, usa berwickgeek/productive-mcp en su lugar, o ejecuta ambos lado a lado (usan prefijos de herramienta diferentes).

Licencia

MIT: consulta LICENSE.

Contribución

Las incidencias y PRs son bienvenidos. Este es un proyecto pequeño; por favor, mantén los cambios enfocados e incluye pruebas para cualquier comportamiento nuevo en client.py.


No afiliado a Productive.io. "Productive" es una marca comercial de sus respectivos propietarios.

Install Server
A
security – no known vulnerabilities
A
license - permissive license
A
quality - A tier

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/cameronfairbairn/productive-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server