Teamup Calendar MCP by usefulapi

Read and search Teamup Calendar events and sub-calendars; create, update, delete and undo events.

Should I use this

Quality & Safety

A
Description quality
100%
Schema completeness
91%
Naming quality
80%
Poisoning risk
100%
Permission match
100%
Protocol compliance
100%

Based on automated analysis of tool definitions and protocol compliance.

Context Cost

~4,102Tokens (tool definitions)
~1.9 KBTypical response size
Significant attention impact (3.20% of 128k context)

This is the approximate number of tokens consumed each time the server's tools are loaded into a model's context. Higher counts reduce the attention available for other tasks.

Install

One-Click Install

Add this to your `claude_desktop_config.json` file:

{
  "mcpServers": {
    "teamup-calendar": {
      "url": "https://teamup-calendar.usefulapi.io/mcp"
    }
  }
}

Remote endpoints

https://teamup-calendar.usefulapi.io/mcpstreamable-http

What it can do

Tool inventory

Tools (15)

🟢 Read-only🟡 Write🔴 Delete⚪ Unknown
🟢teamup_get_calendar

The calendar this connection points at: title, timezone and date settings, custom event fields, sub-calendars, the permission of the calendar key in use and the plan's features. Call this first to learn the sub-calendar ids and the timezone. The calendar key itself is never returned. GET /{calendarKey}/configuration.

Input Schema

{
  "type": "object",
  "properties": {},
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🟢teamup_list_subcalendars(include_inactive, name_contains, limit, offset)

List the sub-calendars (the colored lanes that events belong to, such as people, rooms or resources). A key with admin permission also sees inactive ones. GET /{calendarKey}/subcalendars.

Input Schema

{
  "type": "object",
  "properties": {
    "include_inactive": {
      "description": "Include inactive sub-calendars (default false).",
      "type": "boolean"
    },
    "name_contains": {
      "description": "Only sub-calendars whose name matches this text.",
      "type": "string",
      "minLength": 1,
      "maxLength": 100
    },
    "limit": {
      "description": "Results per page, 1-200 (default 50).",
      "type": "integer",
      "exclusiveMinimum": 0,
      "maximum": 200
    },
    "offset": {
      "description": "Number of results to skip (default 0). Pass the previous reply's next_offset.",
      "type": "integer",
      "minimum": 0,
      "maximum": 1000000
    }
  },
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🟢teamup_get_subcalendar(subcalendar_id)

One sub-calendar by id: name, color, overlap rule, active state and which links may use it. GET /{calendarKey}/subcalendars/{id}.

Input Schema

{
  "type": "object",
  "properties": {
    "subcalendar_id": {
      "type": "integer",
      "exclusiveMinimum": 0,
      "maximum": 9007199254740991,
      "description": "Sub-calendar id."
    }
  },
  "required": [
    "subcalendar_id"
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🟢teamup_list_access_keys(name_contains, type, limit, offset)

List the calendar's access keys (sharing links and user accesses) with name, role, active state and per-sub-calendar permission. Needs a key with admin permission. The secret key values are never returned (they are secrets); use the id and name to tell links apart. GET /{calendarKey}/keys.

Input Schema

{
  "type": "object",
  "properties": {
    "name_contains": {
      "description": "Only keys whose link, user or group name matches this text.",
      "type": "string",
      "minLength": 1,
      "maxLength": 100
    },
    "type": {
      "description": "Only this kind of access.",
      "type": "string",
      "enum": [
        "anonymous",
        "user",
        "group"
      ]
    },
    "limit": {
      "description": "Results per page, 1-200 (default 50).",
      "type": "integer",
      "exclusiveMinimum": 0,
      "maximum": 200
    },
    "offset": {
      "description": "Number of results to skip (default 0). Pass the previous reply's next_offset.",
      "type": "integer",
      "minimum": 0,
      "maximum": 1000000
    }
  },
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🟢teamup_list_events(start_date, end_date, subcalendar_ids, tz)

List the events in a date range, optionally only on some sub-calendars. Recurring events are expanded: every occurrence in the range is returned with its own id (series id + -rid- + start). Notes come as markdown. Times use the calendar's timezone unless tz is set. GET /{calendarKey}/events.

Input Schema

{
  "type": "object",
  "properties": {
    "start_date": {
      "description": "First day, yyyy-mm-dd (default: today).",
      "type": "string",
      "pattern": "^(\\d{4})-(\\d{2})-(\\d{2})$"
    },
    "end_date": {
      "description": "Last day, inclusive, yyyy-mm-dd (default: start_date). Needs start_date; at most 366 days after it.",
      "type": "string",
      "pattern": "^(\\d{4})-(\\d{2})-(\\d{2})$"
    },
    "subcalendar_ids": {
      "description": "Only events on these sub-calendars.",
      "minItems": 1,
      "maxItems": 100,
      "type": "array",
      "items": {
        "type": "integer",
        "exclusiveMinimum": 0,
        "maximum": 9007199254740991
      }
    },
    "tz": {
      "description": "Timezone for the times in the reply, e.g. Europe/Berlin. Default: the calendar's timezone.",
      "type": "string",
      "pattern": "^[A-Za-z0-9_+\\-/]{1,64}$"
    }
  },
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🟢teamup_search_events(query, start_date, end_date, subcalendar_ids, tz, ...)

Search events by keyword (2-100 characters) within a date range (default: today only, so always pass the range you mean). Recurring events are expanded. Paged with limit and offset. GET /{calendarKey}/events?query=.

Input Schema

{
  "type": "object",
  "properties": {
    "query": {
      "type": "string",
      "minLength": 2,
      "maxLength": 100,
      "description": "Search text (Teamup's search syntax applies)."
    },
    "start_date": {
      "description": "First day, yyyy-mm-dd (default: today).",
      "type": "string",
      "pattern": "^(\\d{4})-(\\d{2})-(\\d{2})$"
    },
    "end_date": {
      "description": "Last day, inclusive, yyyy-mm-dd (default: start_date). Needs start_date; at most 366 days after it.",
      "type": "string",
      "pattern": "^(\\d{4})-(\\d{2})-(\\d{2})$"
    },
    "subcalendar_ids": {
      "description": "Only events on these sub-calendars.",
      "minItems": 1,
      "maxItems": 100,
      "type": "array",
      "items": {
        "type": "integer",
        "exclusiveMinimum": 0,
        "maximum": 9007199254740991
      }
    },
    "tz": {
      "description": "Timezone for the times in the reply, e.g. Europe/Berlin. Default: the calendar's timezone.",
      "type": "string",
      "pattern": "^[A-Za-z0-9_+\\-/]{1,64}$"
    },
    "limit": {
      "description": "Results per page, 1-200 (default 50).",
      "type": "integer",
      "exclusiveMinimum": 0,
      "maximum": 200
    },
    "offset": {
      "description": "Number of results to skip (default 0). Pass the previous reply's next_offset.",
      "type": "integer",
      "minimum": 0,
      "maximum": 1000000
    }
  },
  "required": [
    "query"
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🟢teamup_get_event(event_id)

One event by id: title, times, sub-calendars, location, who, notes (markdown), recurrence rule, custom fields, signups, comments, attachments (metadata), version, change history and reminders. Use the occurrence id (123-rid-<unix start>) for one occurrence of a recurring event. GET /{calendarKey}/events/{id}.

Input Schema

{
  "type": "object",
  "properties": {
    "event_id": {
      "type": "string",
      "pattern": "^[1-9]\\d{0,17}(-rid-[1-9]\\d{0,12})?$",
      "description": "Event id."
    }
  },
  "required": [
    "event_id"
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🟢teamup_list_changed_events(since_timestamp, mode)

Events created, changed or deleted since a Unix timestamp (at most 30 days back), for syncing. A recurring event comes back once, as its series, not as occurrences. Deleted events carry delete_dt. Pass the reply's timestamp as since_timestamp next time so nothing is missed. GET /{calendarKey}/events?modifiedSince=.

Input Schema

{
  "type": "object",
  "properties": {
    "since_timestamp": {
      "type": "integer",
      "exclusiveMinimum": 0,
      "maximum": 4102444800,
      "description": "Unix timestamp in seconds, at most 30 days in the past."
    },
    "mode": {
      "description": "synchronize (default): events created and deleted after the timestamp are left out. monitor: they are returned too.",
      "type": "string",
      "enum": [
        "synchronize",
        "monitor"
      ]
    }
  },
  "required": [
    "since_timestamp"
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🟢teamup_list_event_signups(event_id)

The people signed up for an event (name, email, id). Signups must be enabled on the event. GET /{calendarKey}/events/{id}/signups.

Input Schema

{
  "type": "object",
  "properties": {
    "event_id": {
      "type": "string",
      "pattern": "^[1-9]\\d{0,17}(-rid-[1-9]\\d{0,12})?$",
      "description": "Event id."
    }
  },
  "required": [
    "event_id"
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🟡teamup_create_event(subcalendar_ids, start, end, all_day, title, ...)

WRITE: create an event. Needs a calendar key with add or modify permission. Give at least subcalendar_ids, start and end. Not idempotent: a repeated call creates a second event. The reply holds the new event and an undo_id; teamup_undo_event_action removes the event again within one hour. POST /{calendarKey}/events.

Input Schema

{
  "type": "object",
  "properties": {
    "subcalendar_ids": {
      "minItems": 1,
      "maxItems": 100,
      "type": "array",
      "items": {
        "type": "integer",
        "exclusiveMinimum": 0,
        "maximum": 9007199254740991
      },
      "description": "Sub-calendar ids the event belongs to (from teamup_list_subcalendars)."
    },
    "start": {
      "type": "string",
      "description": "Start, e.g. 2026-10-14T09:00:00 (calendar timezone) or with an offset such as +02:00. For an all-day event: yyyy-mm-dd."
    },
    "end": {
      "type": "string",
      "description": "End, same format as start. Must not be before start."
    },
    "all_day": {
      "description": "True for an all-day event (default false).",
      "type": "boolean"
    },
    "title": {
      "description": "Event title.",
      "type": "string",
      "maxLength": 1024
    },
    "location": {
      "type": "string",
      "maxLength": 255
    },
    "who": {
      "description": "The \"who\" field.",
      "type": "string",
      "maxLength": 255
    },
    "notes": {
      "description": "Notes, in markdown.",
      "type": "string",
      "maxLength": 65535
    },
    "rrule": {
      "description": "Recurrence rule (iCalendar RRULE, e.g. FREQ=WEEKLY;COUNT=10). Omit for a single event.",
      "type": "string",
      "maxLength": 500
    },
    "custom": {
      "description": "Values of custom fields, keyed by field id (see teamup_get_calendar -> fields).",
      "type": "object",
      "propertyNames": {
        "type": "string"
      },
      "additionalProperties": {}
    },
    "signup_enabled": {
      "description": "Let people sign up (default false).",
      "type": "boolean"
    },
    "signup_limit": {
      "description": "Maximum signups; required by Teamup when signup_enabled is true.",
      "type": "integer",
      "minimum": 0,
      "maximum": 100000
    },
    "signup_visibility": {
      "description": "Who sees the signups: all_users or users_with_modify_permission.",
      "type": "string",
      "enum": [
        "all_users",
        "users_with_modify_permission"
      ]
    },
    "comments_enabled": {
      "description": "Allow comments (default false).",
      "type": "boolean"
    },
    "comments_visibility": {
      "description": "Who sees the comments: all_users or users_with_modify_permission.",
      "type": "string",
      "enum": [
        "all_users",
        "users_with_modify_permission"
      ]
    }
  },
  "required": [
    "subcalendar_ids",
    "start",
    "end"
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🔴teamup_update_event(event_id, redit, subcalendar_ids, start, end, ...)

WRITE: change fields of an event; fields you leave out keep their value (the event is read first and sent back with its version, so a concurrent edit is refused instead of overwritten; an event without a version is not changed). Needs modify permission. For a recurring event pass redit; use the occurrence id (123-rid-<unix start>) with single or future. Attachments are not touched. The reply holds the event and an undo_id for one hour (teamup_undo_event_action). PUT /{calendarKey}/events/{id}.

Input Schema

{
  "type": "object",
  "properties": {
    "event_id": {
      "type": "string",
      "pattern": "^[1-9]\\d{0,17}(-rid-[1-9]\\d{0,12})?$",
      "description": "Event id (occurrence id for one occurrence of a recurring event)."
    },
    "redit": {
      "type": "string",
      "enum": [
        "single",
        "future",
        "all"
      ],
      "description": "Which occurrences of a recurring event: single (only this one), future (this and all later ones) or all."
    },
    "subcalendar_ids": {
      "minItems": 1,
      "maxItems": 100,
      "type": "array",
      "items": {
        "type": "integer",
        "exclusiveMinimum": 0,
        "maximum": 9007199254740991
      },
      "description": "Sub-calendar ids the event belongs to (from teamup_list_subcalendars)."
    },
    "start": {
      "description": "New start (same formats as in teamup_create_event).",
      "type": "string"
    },
    "end": {
      "description": "New end.",
      "type": "string"
    },
    "all_day": {
      "type": "boolean"
    },
    "title": {
      "type": "string",
      "maxLength": 1024
    },
    "location": {
      "type": "string",
      "maxLength": 255
    },
    "who": {
      "type": "string",
      "maxLength": 255
    },
    "notes": {
      "description": "New notes, in markdown. Replaces the old notes.",
      "type": "string",
      "maxLength": 65535
    },
    "rrule": {
      "description": "New recurrence rule; with redit all or future only. An empty string removes the recurrence (the series becomes a single event).",
      "type": "string",
      "maxLength": 500
    },
    "custom": {
      "description": "Custom field values to set, keyed by field id; other custom fields keep their value.",
      "type": "object",
      "propertyNames": {
        "type": "string"
      },
      "additionalProperties": {}
    },
    "signup_enabled": {
      "type": "boolean"
    },
    "signup_limit": {
      "type": "integer",
      "minimum": 0,
      "maximum": 100000
    },
    "signup_visibility": {
      "type": "string",
      "enum": [
        "all_users",
        "users_with_modify_permission"
      ]
    },
    "comments_enabled": {
      "type": "boolean"
    },
    "comments_visibility": {
      "type": "string",
      "enum": [
        "all_users",
        "users_with_modify_permission"
      ]
    }
  },
  "required": [
    "event_id"
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🔴teamup_delete_event(event_id, redit, version)

WRITE, DESTRUCTIVE: delete an event, or for a recurring event the chosen occurrences. Needs modify permission. Not retried. The reply holds an undo_id; teamup_undo_event_action restores the event within one hour, after that the deletion is permanent. For one occurrence use the occurrence id (123-rid-<unix start>) and redit single (the default); redit all deletes the whole series. DELETE /{calendarKey}/events/{id}.

Input Schema

{
  "type": "object",
  "properties": {
    "event_id": {
      "type": "string",
      "pattern": "^[1-9]\\d{0,17}(-rid-[1-9]\\d{0,12})?$",
      "description": "Event id (occurrence id for one occurrence of a recurring event)."
    },
    "redit": {
      "description": "For a recurring event: single (default), future or all. With all the whole series is deleted.",
      "type": "string",
      "enum": [
        "single",
        "future",
        "all"
      ]
    },
    "version": {
      "description": "The event's version (from teamup_get_event). If set, the delete is refused when the event changed since.",
      "type": "string",
      "minLength": 1,
      "maxLength": 12
    }
  },
  "required": [
    "event_id"
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🔴teamup_undo_event_action(undo_id)

WRITE: undo a recent event creation, update or deletion with the undo_id from that call. Works for one hour only and is refused if someone else changed the event since. PUT /{calendarKey}/events/undo/{undo_id}.

Input Schema

{
  "type": "object",
  "properties": {
    "undo_id": {
      "type": "string",
      "pattern": "^[A-Za-z0-9_.~-]{1,200}$",
      "description": "The undo_id returned by create, update or delete."
    }
  },
  "required": [
    "undo_id"
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🟡teamup_create_subcalendar(name, color, overlap, active)

WRITE: create a sub-calendar. Needs a calendar key with admin permission, and the plan may limit how many exist. Not idempotent: a repeated call creates a second one. POST /{calendarKey}/subcalendars.

Input Schema

{
  "type": "object",
  "properties": {
    "name": {
      "type": "string",
      "minLength": 1,
      "maxLength": 255,
      "description": "Sub-calendar name."
    },
    "color": {
      "description": "Color number from Teamup's palette (default 17).",
      "type": "integer",
      "minimum": 1,
      "maximum": 48
    },
    "overlap": {
      "description": "Allow overlapping events on it (default true).",
      "type": "boolean"
    },
    "active": {
      "description": "Active (default true).",
      "type": "boolean"
    }
  },
  "required": [
    "name"
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🔴teamup_update_subcalendar(subcalendar_id, name, color, overlap, active)

WRITE: change a sub-calendar's name, color, overlap rule or active state; fields you leave out keep their value. Needs admin permission. Making a sub-calendar inactive hides it from users without admin rights. PATCH /{calendarKey}/subcalendars/{id}.

Input Schema

{
  "type": "object",
  "properties": {
    "subcalendar_id": {
      "type": "integer",
      "exclusiveMinimum": 0,
      "maximum": 9007199254740991,
      "description": "Sub-calendar id."
    },
    "name": {
      "type": "string",
      "minLength": 1,
      "maxLength": 255
    },
    "color": {
      "type": "integer",
      "minimum": 1,
      "maximum": 48
    },
    "overlap": {
      "type": "boolean"
    },
    "active": {
      "type": "boolean"
    }
  },
  "required": [
    "subcalendar_id"
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}

Community

Rate this Server

Evidence

Recent observations

verifiedversion not recorded15 tools