Skip to main content
Glama
digiti

teamhood-mcp

Official
by digiti

teamhood-mcp

Read-only MCP-server voor de Teamhood Open API. Draait lokaal via stdio, zodat je API-key je machine niet verlaat.

Waarom read-only, en hoe hard

src/client.ts is de enige module die het netwerk raakt. Er is geen codepad naar PUT, PATCH of DELETE.

POST kan wel, maar uitsluitend voor twee paden in POST_QUERY_ALLOWLIST:

  • /timelogs

  • /boards/{boardId}/item-activities

Teamhood modelleert die twee als zoekopdracht in plaats van als GET, omdat het filter te groot is voor een querystring. Ondanks het werkwoord zijn het leesoperaties: ze geven data terug en veranderen niets. Zonder die uitzondering kan deze server geen uren lezen, want een GET /timelogs bestaat niet.

De allowlist is een hardgecodeerde lijst reguliere expressies en wordt gecontroleerd voordat er een socket opengaat. Elk ander pad, inclusief POST /items, wordt geweigerd met een expliciete fout.

Belangrijker nog: de Teamhood Open API heeft geen endpoint om een tijdregistratie aan te maken. POST /api/v1/timelogs heet "List Timelogs" en verwacht een filter met startDate, endDate en optioneel userIds. Uren wegschrijven kan dus sowieso niet via deze API, door welke client dan ook. Een urenvoorstel blijft iets wat je met de hand overneemt.

Installeren

cd teamhood-mcp
npm install
npm run build

Configureren

Haal je API-URL en API-key op in Teamhood via Company Account → Integrations.

cp .env.example .env
# vul TEAMHOOD_API_URL en TEAMHOOD_API_KEY in

De server laadt dat .env-bestand zelf in, gezocht naast deze package en niet in je working directory. Een MCP-client start de server namelijk vanuit een willekeurige map. Geef je de waarden liever mee via een env-blok in je MCP-config, dan mag .env gewoon ontbreken: wat al in de omgeving staat, wint.

Twee soorten sleutels:

  • Account-key reikt over het hele bedrijfsaccount. Dat is wat je nodig hebt voor een volledig overzicht.

  • Workspace-key ziet alleen die ene workspace. Teamhood raadt die aan om de schade te beperken als een sleutel ooit lekt.

Zet de key nooit in de repository en deel hem niet in een chat.

Koppelen aan Claude

Voeg dit toe aan je MCP-configuratie:

{
  "mcpServers": {
    "teamhood": {
      "command": "node",
      "args": ["/Users/gaetanbols/Developer/Claude/Timetracking/teamhood-mcp/dist/index.js"],
      "env": {
        "TEAMHOOD_API_URL": "https://api-JOUWTENANT.teamhood.com",
        "TEAMHOOD_API_KEY": "je-key-hier",
        "TEAMHOOD_TIMEZONE": "Europe/Brussels"
      }
    }
  }
}

Voor Claude Code kan het ook in één regel:

claude mcp add teamhood \
  --env TEAMHOOD_API_URL=https://api-JOUWTENANT.teamhood.com \
  --env TEAMHOOD_API_KEY=je-key-hier \
  -- node /Users/gaetanbols/Developer/Claude/Timetracking/teamhood-mcp/dist/index.js

Eerst testen zonder Claude

npm run inspect

Dat opent de MCP Inspector, waar je elk tool los kan aanroepen en de ruwe respons ziet.

Tools

Tool

Waarvoor

teamhood_list_workspaces

Alle workspaces met hun ID. Begin hier.

teamhood_list_users

Gebruikers, met laatste activiteitsdatum waar beschikbaar.

teamhood_list_boards

Boards binnen een workspace.

teamhood_get_board_structure

Rijen en statussen van een board.

teamhood_search_items

Tickets zoeken, om te zien of er al één bestaat voor een stuk werk.

teamhood_get_item

Eén item volledig, inclusief geaggregeerde estimation en tracked time.

teamhood_get_item_activity

Activiteitenlog van een board over een periode. Teamhood biedt dit per board aan, niet per item.

teamhood_get_time_logs

Geregistreerde uren over een periode, per dag gegroepeerd. Zonder workspaceId loopt het tool alle workspaces af.

teamhood_describe_api

Haalt de Swagger van de host-root op en toont alle paden met hun methodes.

teamhood_raw_get

Vrije GET, als noodklep wanneer een endpoint anders heet.

Over tijdzones

De Teamhood API levert timestamps in UTC. Een registratie die je om 00:00 Belgische tijd dateert, is 22:00 UTC de dag ervoor. In een ruwe export ziet die er dus uit alsof hij op de vorige dag hoort.

teamhood_get_time_logs geeft daarom bij elk tijdstip zowel de ruwe UTC-waarde als localDate en localTime, berekend in TEAMHOOD_TIMEZONE. Groeperen gebeurt op localDate, dus dagtotalen kloppen met wat je in de interface ziet.

Als een tool een 404 geeft

De Open API verschilt licht per accountversie. De server probeert bij elk tool meerdere bekende spellingen van een pad en onthoudt welke werkte. Werkt geen enkele:

  1. Roep teamhood_describe_api aan voor de lijst met GET-paden in jouw omgeving.

  2. Test het juiste pad met teamhood_raw_get.

  3. Voeg dat pad toe aan de kandidatenlijst in src/index.ts.

Uren wegschrijven kan niet

Een eerdere versie van dit bestand schetste hoe je later een teamhood_log_time zou bouwen. Dat blijkt niet te kunnen: in de Swagger van Teamhood v1 staat onder Timelogs alleen POST /api/v1/timelogs, en dat is de leesquery. Er is geen endpoint dat een tijdregistratie aanmaakt, wijzigt of verwijdert.

Wat de API wel kan schrijven: items, boards, rijen, workspaces, attachments en relaties. Uren horen daar niet bij. Boeken blijft dus handwerk in de interface.

Zet daarbij het tijdstip op iets als 12:00 lokale tijd. Een registratie op 00:00 wordt 22:00 UTC de dag ervoor en verschuift in exports naar de verkeerde dag.