Skip to main content
Glama
borgels

mcp-server-productive

by borgels

mcp-server-productive

MCP-Server für die Productive.io API v2 – Projekte, Aufgaben, Zeiterfassung, Ressourcenplanung, Finanzen, CRM und Berichte für eine Organisation.

Productive stellt etwa 650 Operationen über 132 Ressourcen bereit. Diese in 650 MCP-Tools zu verwandeln, würde die Tool-Liste jedes Clients überfluten, daher ist dieser Server zwölf Tools, gesteuert von einer generierten Registry: Die Tools sind generisch, und die Registry weiß, was jede Ressource tatsächlich akzeptiert.

Tools

Discoveryproductive_search_capabilities, productive_describe_resource, productive_check_connection, productive_describe_custom_fields

Readproductive_list (Filter, Sortierungen, Includes, Paginierung und die 26 Berichts-Endpunkte mit Gruppierung), productive_get

Writeproductive_create, productive_update, productive_delete, productive_run_action (150 benannte Verben: archive, restore, approve, close, copy, finalize, send…), productive_track_time, productive_commit_operation

Per-user auth (opt-in)productive_connect, productive_status, productive_disconnect – siehe Authentifizierung

Beginnen Sie mit productive_search_capabilities. Die Ressourcennamen von Productive sind eigenwillig – ein Budget ist ein deal, eine Board-Spalte ein workflow_status, eine Zeiterfassungs-Genehmigung lebt auf time_entries – und Raten kostet Aufrufe.

Related MCP server: productive-mcp-rb2

Die Registry

src/productive/registry.generated.ts wird aus dem veröffentlichten OpenAPI-Dokument von Productive von scripts/generate-registry.mjs abgeleitet und eingecheckt, sodass CI nie das Netzwerk benötigt und eine Spezifikationsänderung als überprüfbarer Diff erscheint. Für jede Ressource erfasst es die Filterfelder, Sortierschlüssel, Berichts-Gruppenschlüssel, einbindbaren Beziehungen, die beschreibbaren Attribute für Create und Update mit den als erforderlich markierten sowie jede benannte Aktion.

Das ist es, was zwölf Tools ehrlich bleiben lässt. productive_describe_resource gibt den genauen Vertrag für eine Ressource zurück, und jedes Argument wird dagegen geprüft, bevor eine Anfrage rausgeht.

Regenerieren Sie mit npm run registry:generate (fügen Sie ein Pfadargument hinzu, um eine lokale Kopie der Spezifikation zu verwenden). Der Generator lässt den Build fehlschlagen, wenn eine handgeschriebene Klassifizierung – eine Risikostufe, ein nach außen gerichtetes Flag, eine blockierte Operation – keinem Pfad in der Spezifikation mehr entspricht, sodass eine Umbenennung upstream nicht stillschweigend eine Schutzmaßnahme entfernen kann.

Was die API tut, gemessen

Alles hier wurde gegen eine Live-Organisation verifiziert, weil sich Spezifikation und API an Stellen unterscheiden, die wichtig sind.

Zeit ist Minuten. Geld ist Untereinheiten. Ein Zeiteintrag von 2 sind zwei Minuten. Beides kommt auch so zurück.

Unbekannte Filter, Sortierungen und Includes schlagen laut fehl. HTTP 400 mit unsupported_filter, sort_param_unsupported, unsupported_include. Sie hier zu validieren ist also ein besserer Fehler, kein Sicherheitsnetz.

Unbekannte Schreibattribute schlagen still fehl. PATCH mit einem falsch geschriebenen Attribut gibt HTTP 200 zurück und ändert nichts – nicht von Erfolg zu unterscheiden. Dieser Server lehnt daher ein Attribut ab, das die Ressource nicht deklariert, anstatt einen Schreibvorgang zu melden, der nicht stattgefunden hat. Das ist das mit Abstand Nützlichste, was die Registry tut.

Es gibt genau sechs Filteroperatoren, auf jedem Feld: contains, eq, gt, lt, not_contain, not_eq. Die Spezifikation listet vier pro Feld auf und lässt gt/lt aus, die aber funktionieren; gte, lte, in, not_in, starts_with, ends_with, blank und present werden alle mit unsupported_filter_operation abgelehnt. Es gibt keinen inklusiven Vergleich, daher benötigt ein inklusiver Bereich die eigenen after/before- oder <field>_after/<field>_before-Filterfelder der Ressource.

page[size] ist auf 200 begrenzt und wird still gekappt. Eine Anfrage für 500 liefert 200 ohne Fehler zurück. Ergebnisse enthalten total und nextPage, damit eine Seite nicht für die gesamte Antwort gehalten wird.

PATCH ist wirklich partiell. Ausgelassene Attribute behalten ihre Werte; es besteht keine Notwendigkeit, einen ganzen Datensatz erneut zu senden.

data.type wird nicht geprüft. Das Patchen einer Aufgabe mit type: "projects" gelingt und wendet die Änderung an. Dieser Server sendet den korrekten Typ trotzdem.

Eine 403 mit der Aussage, die Organisations-ID „muss angegeben werden“, kann bedeuten, dass sie falsch war, nicht fehlend. Derselbe Code no_organization_id deckt einen fehlenden Header und eine Organisation ab, die das Token nicht erreichen kann.

Eine fehlende Funktion antwortet mit 404, nicht 403. /boards liefert 404 bei einer Organisation ohne diese Funktion, was sich wie ein defekter Pfad liest.

Löschungen können wiederherstellbar sein. Eine gelöschte Aufgabe erscheint in deleted_items mit item_type und item_id und kann über die restore-Aktion dieser Ressource wiederhergestellt werden. Nur für Aufgaben verifiziert – gehen Sie nicht davon aus, dass es für jeden Typ gilt.

GET /users ist der einzige auf den Aufrufer bezogene Endpunkt. Er gibt genau einen Datensatz zurück – Sie – und so identifiziert dieser Server den Besitzer eines Tokens. Es gibt kein /users/me; dieser Pfad liefert 404. Vorsicht bei /organization_memberships: Es ist nicht auf die angeheftete Organisation beschränkt, sondern listet die Mitgliedschaften des Aufrufers in jeder Organisation, zu der er gehört, daher ist seine Zeilenzahl keine Mitarbeiterzahl.

Keine Rate-Limit-Header. Nur x-request-id, den Fehler dieses Servers zitieren. Bei 429 zurückziehen, anstatt das Limit auszuloten.

Berechtigungen

Vier Schalter, alle standardmäßig aus. Ein schreibgeschützter Server ist der nützliche, sichere Standard.

Schalter

Umfasst

PRODUCTIVE_ENABLE_WRITES

Master-Schalter. Ohne ihn wird nichts verändert.

PRODUCTIVE_ENABLE_FINANCIALS

Geld, Preisgestaltung, Gehaltsabrechnung, Dokumente, die ein Kunde erhält: Rechnungen, Einzelposten, Zahlungen, Eingangsrechnungen, Ausgaben, Bestellungen, Angebote, Verträge, Preise, Tarifkarten, Gehälter, Gemeinkosten, Steuersätze, Bankkonten, Tochtergesellschaften.

PRODUCTIVE_ENABLE_ADMIN

Zugriff und organisationsweite Konfiguration: Personen, Mitgliedschaften, Berechtigungssätze, Teams, Einladungen, benutzerdefinierte Felder, Webhooks, Integrationen, Genehmigungs- und Zeiterfassungsrichtlinien.

PRODUCTIVE_ENABLE_DELETES

Löschungen, zusätzlich zur Stufenfreigabe.

Ein einziger Master-Schalter reicht für Productive nicht aus: Dieselbe API verschiebt eine Aufgabe, stellt eine Rechnung aus und gewährt einen Berechtigungssatz – das sind drei verschiedene Entscheidungen. Ein Server, dem Projektarbeit anvertraut ist, sollte dadurch nicht auch eine Rechnung senden können.

PRODUCTIVE_ALLOWED_RESOURCES / PRODUCTIVE_DENIED_RESOURCES grenzen eine Instanz weiter ein und gelten auch für Lesezugriffe – eine auf Zeiterfassung beschränkte Instanz sollte auch keine Gehälter lesen können.

Nie ausgesetzt, unabhängig von den Schaltern: passwords, sessions, organization_subscriptions, die nicht authentifizierten public/*-Freigabelinks und PATCH /users/{id}/update_password. Diese fehlen in der Registry, anstatt abgesperrt zu sein, sodass kein Policy-Fehler sie wieder öffnen kann.

Schreibvorgänge in zwei Schritten

Gewöhnliche Projektarbeit – eine Aufgabe, ein Zeiteintrag, eine Buchung, ein Kommentar – wird in einem einzigen Aufruf geschrieben. Für jeden Zeiteintrag einen Handshake zu verlangen, würde den Server für das unbrauchbar machen, was Menschen am häufigsten tun.

Alles mit einem größeren Wirkungskreis ist gestaffelt: Das Tool gibt die exakte Anfrage plus einen Hash zurück und sendet nichts, und productive_commit_operation führt sie nur aus, wenn die Operation unverändert zurückkommt. Das umfasst die Finanz- und Admin-Stufen, jedes Löschen, alles, was die Organisation verlässt, und jede bulk_*-Aktion – diese wirken auf alle Datensätze, die ein Filter findet, und weigern sich daher auch, ohne expliziten Filter ausgeführt zu werden.

Sechs Operationen sind als outward gekennzeichnet, weil sie im Moment ihrer Ausführung jemanden außerhalb der Organisation erreichen: invoices.send, invoices.send_einvoice, people.invite, people.resend, organizations.resend_code und das Erstellen einer invitation.

Authentifizierung

Zwei Modi. PRODUCTIVE_ORGANIZATION_ID ist in beiden erforderlich und ist nie ein Tool-Argument.

Pro-Benutzer-Tokens (empfohlen)

Jede Person verknüpft ihr eigenes Productive-Token, sodass Productive ihre Berechtigungen anwendet und ihren Namen bei dem festhält, was sie tut.

Das ist bei Productive wichtiger als bei den meisten Systemen. Productive schreibt Arbeit Personen zu: Ein Zeiteintrag gehört zu einer person_id, und jede Änderung wird im Aktivitätsprotokoll mit dem Besitzer des Tokens gestempelt – das ist der Nachweis, mit dem eine Kundenrechnung verteidigt wird. Bei einem gemeinsamen Token sagt dieses Protokoll, dass das Dienstkonto alles getan hat.

PRODUCTIVE_PER_USER_AUTH=true
PRODUCTIVE_TRUST_FORWARDED_USER=true
PRODUCTIVE_ENCRYPTION_KEY=<min 16 chars>
PRODUCTIVE_STORE_PATH=/data/store.json
PRODUCTIVE_PUBLIC_BASE_URL=https://productive.example.com
# PRODUCTIVE_API_TOKEN deliberately unset

Der Ablauf:

  1. Der Aufrufer führt productive_connect aus und erhält einen Einmal-Link, 10 Minuten gültig, der an seine Identität gebunden ist.

  2. Sie öffnen ihn und fügen ein Token ein, das sie in Productive unter Settings → API integrations erstellt haben. Das Token geht von ihrem Browser direkt zum Server, sodass es nie in das Gesprächstranskript gelangt – ein Productive-Token ist bearer-äquivalent zu ihrem gesamten Konto und erreicht, wie unten gemessen, häufig mehr als eine Organisation.

  3. Bevor es gespeichert wird, ruft der Server GET /users mit diesem Token und der ID dieser Organisation auf. Ein Aufruf beweist drei Dinge: Das Token ist gültig, es kann diese Organisation erreichen, und wem es gehört. Die Seite bestätigt dann, welches Konto verknüpft wurde.

  4. Tokens werden im Ruhezustand mit AES-256-GCM verschlüsselt, eine Zeile pro verifizierter Identität.

Stolperfallen:

  • Identität kommt nur vom Gateway. X-MCP-User wird nur gelesen, wenn PRODUCTIVE_TRUST_FORWARDED_USER=true ist, niemals von etwas, das der MCP-Client kontrolliert. Aktivieren Sie es nur hinter einem Gateway, das den Header aus einem validierten Token setzt und eine vom Client gelieferte Kopie entfernt – andernfalls kann ein Aufrufer eine beliebige Identität angeben und als sie handeln.

  • Kein Fallback. Ein nicht eingeschriebener Aufrufer erhält NOT_CONNECTED, niemals das gemeinsame Token, selbst wenn PRODUCTIVE_API_TOKEN zufällig gesetzt ist. Ein Fallback würde ihnen geliehene Rechte aushändigen, was genau das Versagen ist, das dieser Modus beseitigen soll.

  • /productive/enroll muss vom Browser des Benutzers erreichbar sein, unter Umgehung des MCP-Gateways – ein Browser kann das Bearer-Token des Gateways nicht tragen. Leiten Sie /productive/* auf PRODUCTIVE_PUBLIC_BASE_URL direkt zum Container. Seine Sicherheit ist das einmalige, identitätsgebundene State-Token.

  • Persistieren Sie PRODUCTIVE_STORE_PATH auf einem Volume, und halten Sie PRODUCTIVE_ENCRYPTION_KEY stabil – ändern Sie ihn, und jedes gespeicherte Token wird unentschlüsselbar.

  • Wenn die eigene Productive-E-Mail eines Tokens von der Verzeichnisadresse des Aufrufers abweicht, wird das laut auf der Seite und in productive_status gemeldet und trotzdem verbunden. Setzen Sie PRODUCTIVE_REQUIRE_EMAIL_MATCH=true, um stattdessen abzulehnen. Es ist standardmäßig aus, weil jeder, der das Token einer anderen Person einfügt, es bereits besitzt, sodass Ablehnen wenig Sicherheit bringt, während ein Productive-Konto unter einer anderen Adresse durchaus plausibel ist.

  • Die Pro-Benutzer-Authentifizierung trennt Berechtigungen und Zuordnung, nicht Organisationen. Die Organisations-P

PRODUCTIVE_TRUST_FORWARDED_USER hilft auch hier weiter: personenbezogene Schreibvorgänge (ein Zeiteintrag, eine Buchung) werden standardmäßig dem aufgelösten Aufrufer zugeordnet und nicht dem Inhaber des Tokens, und der Server weigert sich zu raten, wenn die Adresse niemandem oder mehr als einer Person entspricht. productive_check_connection nennt den Inhaber des Tokens in jedem Fall, sodass die Zuordnung nie eine Überraschung ist.

Multi-Organisation

Eine Instanz bedient genau eine Organisation. X-Organization-Id stammt aus der Umgebung und ist nie ein Tool-Argument, sodass kein Codepfad — einschließlich der generischen Tools — einen anderen Mandanten erreichen kann. Führen Sie für eine zweite Organisation eine zweite Instanz aus; das Image ist dasselbe.

Das ist nicht theoretisch. Ein einzelnes Token erreicht routinemäßig mehrere Organisationen: Auf dem Konto, gegen das dies entwickelt wurde, lieferte GET /organizations drei zurück, und es genügte, nur den Header umzuschalten, um zwischen ihnen zu wechseln (die anderen beiden antworteten mit 403 subscription_expired, nicht mit „not found"). Der Header ist die gesamte Grenze, weshalb er festgelegt und nicht übergeben wird — und weshalb ein registriertes benutzerbezogenes Token gegen diese Organisation verifiziert wird, bevor es gespeichert wird.

Konfiguration

Siehe .env.example. Die beiden erforderlichen Variablen sind PRODUCTIVE_API_TOKEN (Einstellungen → API-Integrationen in Productive; es erbt die Berechtigungen des erstellenden Benutzers) und PRODUCTIVE_ORGANIZATION_ID (die numerische ID in Ihrer Productive-URL).

Setzen Sie PRODUCTIVE_AUDIT_LOG, damit pro Mutationsversuch eine JSON-Zeile angehängt wird, einschließlich derer, die die Richtlinie abgelehnt hat. Anfragekörper werden bewusst nicht aufgezeichnet: sie enthalten Gehälter, Tarife und personenbezogene Daten, und ein Prüfprotokoll, das so streng geschützt werden muss wie das Quellsystem, wird in der Regel nicht gelesen.

Ausführen

npm install
npm run dev          # stdio
npm run dev:http     # streamable HTTP on :3000/mcp (stateless), /healthz open
npm test
npm run smoke:live   # reads a real organization; stages one write, commits nothing

Docker-Images: ghcr.io/borgels/mcp-server-productive (werden bei Push auf main veröffentlicht).

Lizenz

Apache-2.0.

Install Server
A
license - permissive license
A
quality
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

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

Related MCP Servers

View all related MCP servers

Related MCP Connectors

  • ClickUp MCP — wraps the ClickUp REST API v2 (BYO API key)

  • Product Hunt MCP — wraps the Product Hunt GraphQL API v2 (api.producthunt.com)

  • Direct access to your Sanity projects (content, datasets, releases, schemas) and agent rules

View all MCP Connectors

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/borgels/mcp-server-productive'

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