LarsZilch

teamup-mcp

Community LarsZilch
Updated

teamup-mcp

MCP server for the Teamup Calendar API, built with the official @modelcontextprotocol/sdk.

Tools

Tool Description
get_events Retrieve events in a date range — with optional title filters (title_contains, title_starts_with, title_regex)
create_event Create a new event
update_event Update an existing event
delete_event Delete an event
search_events Full-text search across title, notes, location and who fields
get_subcalendars List all sub-calendars
find_available_slots Find free court slots for a given day — returns all free windows per court that fit the requested game type

Prerequisites

  • Node.js 18+
  • A Teamup API key — generate one at teamup.com under Account → API Keys
  • Your calendar key — visible in the calendar URL: https://teamup.com/<calendar-key>

Installation

git clone https://github.com/your-user/teamup-mcp
cd teamup-mcp
npm install
npm run build

Running

TEAMUP_API_KEY=your_api_key node dist/index.js

During development you can skip the build step with tsx:

TEAMUP_API_KEY=your_api_key npm run dev

Claude Code integration

MCP servers are configured in ~/.claude/.mcp.json (global, all projects) or .mcp.json in your project root (project-only). Add the teamup entry inside the mcpServers object:

{
  "mcpServers": {
    "teamup": {
      "command": "node",
      "args": ["/absolute/path/to/teamup-mcp/dist/index.js"],
      "env": {
        "TEAMUP_API_KEY": "your_api_key_here",
        "TEAMUP_CALENDAR_KEY": "your_calendar_key_here"
      }
    }
  }
}

Setting TEAMUP_CALENDAR_KEY as an env var means you never need to pass calendar_key in individual tool calls. Restart Claude Code after saving the file.

Usage examples

List sub-calendars

get_subcalendars(calendar_key="ks123abc456def")

Get events for a week

get_events(
  calendar_key="ks123abc456def",
  start_date="2024-06-01",
  end_date="2024-06-07"
)

Create an event

create_event(
  calendar_key="ks123abc456def",
  title="Team standup",
  start_dt="2024-06-03T09:00:00+02:00",
  end_dt="2024-06-03T09:30:00+02:00",
  subcalendar_id=12345678
)

Update an event

version_id comes from the version field returned by get_events or create_event. It is required by Teamup to prevent lost-update conflicts.

update_event(
  calendar_key="ks123abc456def",
  event_id="987654321",
  version_id="abc123...",
  title="Team standup (moved)",
  start_dt="2024-06-03T10:00:00+02:00",
  end_dt="2024-06-03T10:30:00+02:00"
)

Delete an event

delete_event(
  calendar_key="ks123abc456def",
  event_id="987654321",
  version_id="abc123..."
)

Filter events by title

get_events(
  start_date="2026-01-01",
  end_date="2026-12-31",
  title_starts_with="U10"
)

Available title filters (applied client-side after API fetch):

Parameter Example Matches
title_contains "U10" Any title containing "U10"
title_starts_with "U10" Titles that begin with "U10"
title_regex "^U1[02]" Titles matching the regex (case-insensitive)

Search events (full-text)

search_events(
  query="Burgthann",
  start_date="2026-01-01",
  end_date="2026-12-31"
)

Searches across title, notes, location and who fields via the Teamup /search API endpoint.

Find available court slots

find_available_slots(
  date="2026-07-05",
  game_type="singles",
  earliest_time="09:00",
  latest_time="21:00"
)
Parameter Type Description
date YYYY-MM-DD Day to search
game_type singles | doubles Determines required duration: singles = 90 min, doubles = 120 min
earliest_time HH:MM Earliest acceptable start time
latest_time HH:MM Latest end of window (default: 22:00)

Returns all free time windows per court (Belegung > Platz 1–4) that are long enough for the requested game type:

[
  {
    "subcalendar_id": 8137510,
    "subcalendar_name": "Belegung > Platz 1",
    "free_windows": [
      { "from": "09:00", "to": "11:30" },
      { "from": "14:00", "to": "21:00" }
    ]
  }
]

Testing — Funktionstest mit echten Kalender-Daten

Die folgenden Prompts decken alle Tools ab und basieren auf dem realen Kalender ks2zsf595tyfr4313t. Da TEAMUP_CALENDAR_KEY als Umgebungsvariable gesetzt ist, wird calendar_key in keinem Aufruf benötigt.

get_subcalendars — alle 8 Sub-Kalender auflisten

Prompt:

Zeige mir alle Sub-Kalender im Teamup-Kalender.

Erwartetes Ergebnis: 8 Einträge:| ID | Name ||---|---|| 7774417 | Medenspielplan || 8137510 | Belegung > Platz 1 || 8137714 | Belegung > Platz 2 || 8137813 | Belegung > Platz 3 || 8137814 | Belegung > Platz 4 || 8285738 | ASV-Halle Herren || 12586059 | ASV-Halle Damen || 13375969 | Belegung > Information |

get_events — Einträge in einem Datumsbereich

Prompt:

Hole alle Einträge vom 01.07.2026 bis 31.07.2026.

Erwartetes Ergebnis: Mehrere Einträge, darunter:

  • U10 : TC Greding II (05.07.2026, Platz 1 + Platz 2)
  • U10 : TeG Altmühlgrund II (12.07.2026, Platz 1 + Platz 2)

get_events mit title_starts_with — Titelfilter

Prompt:

Zeige alle Einträge in 2026, deren Titel mit "U10" beginnt.

Erwartetes Ergebnis: Genau 9 Einträge (einige doppelt wegen Mehrfach-Platz-Belegung):

Datum Titel Kalender
03.05.2026 U10 : 15:00 Uhr TSV Pyrbaum Medenspielplan
17.05.2026 U10 : TV Hilpoltstein II Belegung > Platz 3
17.05.2026 U10 : TV Hilpoltstein II Belegung > Platz 4
14.06.2026 U10 : 14:00 Uhr TSV Freystadt Medenspielplan
28.06.2026 U10 : 15:00 Uhr TSV Burgthann Medenspielplan
05.07.2026 U10 : TC Greding II Belegung > Platz 1
05.07.2026 U10 : TC Greding II Belegung > Platz 2
12.07.2026 U10 : TeG Altmühlgrund II Belegung > Platz 1
12.07.2026 U10 : TeG Altmühlgrund II Belegung > Platz 2

Hinweis: Die doppelten Einträge sind kein Fehler — das Heimspiel belegt jeweils zwei Plätze gleichzeitig.

search_events — Volltextsuche

Prompt:

Suche nach "Burgthann" in 2026.

Erwartetes Ergebnis: 1 Eintrag:

  • U10 : 15:00 Uhr TSV Burgthann am 28.06.2026 (Medenspielplan)

find_available_slots — freie Plätze finden

Prompt:

Wann ist am 05.07.2026 ein Platz frei für ein Einzel? Ab 09:00 Uhr.

Erwartetes Ergebnis: Platz 3 und Platz 4 ganztägig frei (Platz 1 + 2 sind durch das U10-Spiel belegt):

Belegung > Platz 3:
  09:00 – 22:00

Belegung > Platz 4:
  09:00 – 22:00

create_event — neuen Eintrag anlegen

Prompt:

Lege ein Einzel-Training auf Platz 2 am 20.08.2026 von 10:00 bis 11:30 Uhr an. Titel: "Training Lars".

Erwartetes Ergebnis: Neues Event mit id und version-Feld in der Antwort — diese werden für Update und Delete benötigt.

update_event — Eintrag bearbeiten

Prompt:

Verschiebe das Training vom 20.08.2026 auf 11:00–12:30 Uhr. (event_id und version_id aus dem vorherigen Schritt verwenden)

Erwartetes Ergebnis: Geändertes Event mit neuer version-ID zurück.

delete_event — Eintrag löschen

Prompt:

Lösche das Training vom 20.08.2026 wieder. (event_id und version_id aus dem Update-Schritt verwenden)

Erwartetes Ergebnis: Bestätigung Event … deleted successfully.

Project structure

src/
  index.ts          # MCP server entrypoint & tool handlers
  teamup-client.ts  # Typed Teamup REST API client
dist/               # Compiled output (after npm run build)

MCP Server · Populars

MCP Server · New