API und Webhooks
Alles, was dein Sprachmodell über MCP kann, geht auch per HTTP. Ein Trainingsplaner, ein Vereinsportal oder eine eigene Automation ruft dieselben Werkzeuge auf und hält sich dabei an dieselben Regeln. Webhooks melden, wenn sich etwas geändert hat, die Daten holt sich das andere System dann über die API.
Überblick
Die Schnittstelle hat drei Teile. Die Tool-API und die Webhooks gehören zusammen, die Ingest-API ist ein eigener Eingang für Messwerte.
| Teil | Pfad | Recht des Tokens | Wofür |
|---|---|---|---|
| Tool-API | /api/v1/tools | api:read · api:write | Jedes Werkzeug des MCP-Servers, lesend und schreibend. |
| Webhooks | /api/v1/webhooks | api:read · api:write | Abos anlegen, Zustellungen einsehen, Test-Ping schicken. |
| Ingest-API | /api/ingest/v1 | ingest | Körperwerte von Waagen und Automationen einliefern. Zur Doku der Ingest-API |
Token anlegen
Für die Tool-API und die Webhooks brauchst du ein API-Token. Es erreicht nur /api/v1, kein MCP und keine Seiten des Webs. Ein MCP-Token oder ein Ingest-Token funktioniert hier nicht.
- Öffne im Kontobereich „Verbindungen“.
- Lege unter „API und Webhooks“ ein Token an und gib ihm den Namen des Systems, das es nutzt. Der Name steht später im Protokoll jedes Aufrufs.
- Entscheide, ob es nur lesen oder auch schreiben darf. Lesen reicht für alle lesenden Werkzeuge und zum Einsehen der Webhooks. Schreibende Werkzeuge und das Anlegen von Webhooks brauchen das Schreibrecht.
- Kopier das Token. Es steht nur einmal im Klartext da.
Werkzeuge aufrufen
Ein Werkzeug ruft man mit POST auf seine Adresse auf. Der Körper ist das Objekt der Argumente, genau wie im MCP. Ohne Körper gelten die Vorgaben des Werkzeugs, bei Zeiträumen etwa die letzten sieben Tage. Die Antwort enthält unter result dasselbe, was ein Sprachmodell bekommt.
curl -X POST https://api.training-mcp.app/api/v1/tools/activities \
-H "Authorization: Bearer DEIN_API_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{"from": "2026-10-01", "to": "2026-10-07", "sport": "run"}'{
"tool": "activities",
"result": {
"items": [
{ "id": 18231, "sport": "run", "start": { "utc": "2026-10-06T05:31:00Z", "local": "6. Oktober 2026 07:31" },
"duration_min": 52.4, "distance_km": 10.02, "hr_avg_bpm": 141, "source": "garmin" }
],
"attribution": "Enthält Daten von Garmin-Geräten. Nenne Garmin als Quelle, wenn du diese Werte wiedergibst."
}
}HTTP-Status
- 200
- Erfolg. Das Ergebnis steht in result.
- 401
- Kein oder ein widerrufenes Token.
- 403
- Das Token hat das nötige Recht nicht, etwa ein Lese-Token an einem schreibenden Werkzeug, oder die Einwilligung zur Weitergabe ist widerrufen.
- 404
- Ein Werkzeug dieses Namens gibt es nicht.
- 409
- Schreibkonflikt: Unter dem Schlüssel steht schon etwas anderes. Beide Fassungen stehen in result, siehe „Schreiben“.
- 422
- Die Argumente passen nicht, etwa ein falsches Datumsformat oder eine unbekannte Kennung. Der Grund steht in message.
- 429
- Mehr als 120 Aufrufe in der Minute je Token.
Für jeden Aufruf gilt, was im MCP gilt: Du siehst nur die Daten deines Kontos, Jugendkonten bekommen dieselben Einschränkungen, und wo Garmin-Daten drinstecken, steht der Hinweis auf Garmin in attribution. Jeder Aufruf steht im Protokoll deines Kontos, mit dem Namen des Tokens.
Alle Werkzeuge
Die Liste kommt direkt vom Server, aus derselben Beschreibung, die ein MCP-Client bekommt. Was hier steht, geht auch.
Die Liste wird geladen …
Schreiben
Schreiben geht nur über die schreibenden Werkzeuge. Einen zweiten Weg an ihnen vorbei gibt es nicht, auch nicht für die API. Damit gelten dieselben Regeln wie im Gespräch mit dem Sprachmodell.
- Versioniert: Regeln, Profil und Status bekommen bei jeder Änderung eine neue Fassung, die alte bleibt lesbar.
- Kein stilles Überschreiben: Steht unter demselben Schlüssel (Tag, Einheit, Titel) schon etwas anderes, kommt 409 mit beiden Fassungen zurück. Mit mode replace überschreibst du, mit mode append ergänzt du.
- Dasselbe zweimal geschrieben bleibt ein Eintrag. Ein Aufruf lässt sich also gefahrlos wiederholen.
- Quelle: Jeder Eintrag nennt, woher er kommt. Ohne Angabe steht „api“ da, mit dem Argument source ein eigener Name, etwa der deines Systems.
- Nichts wird gelöscht. Mit discard wird ein Eintrag als verworfen markiert.
- Messwerte schreibst du hier nicht. Strecke, Puls oder Gewicht kommen aus den Quellen, für eigene Messwerte gibt es die Ingest-API.
curl -X POST https://api.training-mcp.app/api/v1/tools/note-day \
-H "Authorization: Bearer DEIN_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"date": "2026-10-07", "kind": "illness", "note": "Erkältet, Training fällt aus.", "source": "vereinsportal"}'HTTP/1.1 409 Conflict
{
"tool": "note-day",
"result": {
"status": "conflict",
"message": "Unter diesem Schlüssel steht schon etwas anderes. … Zum Überschreiben erneut mit mode replace aufrufen, zum Ergänzen mit mode append.",
"stored": { "id": 1, "date": "2026-10-07", "kind": "illness", "note": "Erkältet, Training fällt aus.", "source": "vereinsportal" },
"differences": {
"note": { "stored": "Erkältet, Training fällt aus.", "new": "Nur leicht erkältet, locker laufen." }
}
}
}Webhooks
Ein Webhook ist ein Ping. training mcp meldet an eine Adresse deiner Wahl, dass sich etwas geändert hat, und nennt Kennungen und das Werkzeug, das die Daten liefert. Inhalte stehen nicht darin. Dein System holt sie sich mit seinem Token über die API.
- activity.created
- Neue Einheiten sind da, aus jeder Quelle. data.activity_ids
- activity.updated
- Eine Einheit hat eine Datei oder eine zweite Quelle bekommen. data.activity_ids
- daily.updated
- Tageswerte wie Schlaf, HRV oder Ruhepuls sind neu oder geändert. data.dates
- body.updated
- Körperwerte sind neu oder geändert. data.measured_at
- record.written
- Ein schreibendes Werkzeug hat etwas gespeichert, aus MCP, API oder Web. data.records mit Typ, Kennung, Aktion, Werkzeug und Client
- ping
- Test, ausgelöst im Web oder per API.
curl -X POST https://api.training-mcp.app/api/v1/webhooks \
-H "Authorization: Bearer DEIN_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.org/hooks/training", "events": ["activity.created", "record.written"]}'POST https://example.org/hooks/training
Content-Type: application/json
X-Training-MCP-Event: activity.created
X-Training-MCP-Delivery: 9f1c2b7e-…
X-Training-MCP-Signature: t=1791370000,v1=5d2f…
{
"id": "9f1c2b7e-…",
"event": "activity.created",
"created_at": "2026-10-07T06:12:00Z",
"data": { "activity_ids": [18231, 18232], "more": false },
"fetch": { "tool": "activity-detail", "url": "https://api.training-mcp.app/api/v1/tools/activity-detail" }
}- Das Secret steht nur in der Antwort auf das Anlegen. Mit POST /api/v1/webhooks/{id}/secret erzeugst du ein neues, das alte gilt dann nicht mehr.
- Gesammelt: Was innerhalb von 30 Sekunden anfällt, kommt als eine Zustellung mit bis zu 100 Kennungen, darüber steht more: true. Ein großer Import erzeugt so einige Pings statt Tausender.
- Eigene Änderungen erkennen: record.written nennt den Client. Was dein System selbst über die API geschrieben hat, steht dort als api: mit dem Namen deines Tokens.
- Zustellung: Erfolg ist jeder Status 2xx binnen zehn Sekunden. Sonst folgen Versuche nach 1, 5 und 30 Minuten, 2 und 6 Stunden. Weiterleitungen werden nicht verfolgt.
- Nach zehn fehlgeschlagenen Zustellungen in Folge wird das Abo pausiert, und du bekommst eine Mail. Fortsetzen geht unter „Verbindungen“ oder mit PATCH und paused: false.
- Nur öffentliche HTTPS-Adressen. Ziele im privaten oder internen Netz lehnt der Server ab, beim Anlegen und vor jeder Zustellung.
- Höchstens zehn Abos je Konto. Die letzten Zustellungen mit Status und Antwortcode stehen unter GET /api/v1/webhooks/{id}/deliveries, 30 Tage lang.
Signatur prüfen
Jede Zustellung trägt im Header X-Training-MCP-Signature einen Zeitstempel t und die Signatur v1. Die Signatur ist HMAC-SHA256 mit deinem Secret über den Zeitstempel, einen Punkt und den rohen Körper. Prüf sie, bevor du etwas tust, vergleich in konstanter Zeit und verwirf Zustellungen, die älter als fünf Minuten sind. Gezählt wird der rohe Körper, wie er ankommt, nicht ein neu serialisiertes JSON.
import hashlib, hmac, time
def verify(secret: str, header: str, body: bytes) -> bool:
parts = dict(p.split("=", 1) for p in header.split(","))
t, sig = parts["t"], parts["v1"]
if abs(time.time() - int(t)) > 300:
return False
expected = hmac.new(secret.encode(), f"{t}.".encode() + body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, sig)import { createHmac, timingSafeEqual } from 'node:crypto'
export function verify(secret, header, rawBody) {
const parts = Object.fromEntries(header.split(',').map(p => p.split('=')))
if (Math.abs(Date.now() / 1000 - Number(parts.t)) > 300) return false
const expected = createHmac('sha256', secret).update(`${parts.t}.${rawBody}`).digest('hex')
return timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1))
}Maschinenlesbar
Tool-API und Webhooks beschreiben sich selbst als OpenAPI 3.1, erzeugt aus den Schemas der Werkzeuge. Wer eine Anbindung bauen lässt, auch von einem Sprachmodell, gibt am besten diese Datei mit.
https://api.training-mcp.app/api/v1/openapi.jsonDatenschutz
Über die API gehen deine Trainings- und Gesundheitsdaten an das System, dem du ein Token gibst. Das entscheidest du, und du nimmst es mit dem Widerruf des Tokens zurück. Es gilt dieselbe Einwilligung wie für dein Sprachmodell. Widerrufst du sie, antworten die Werkzeuge nicht mehr, nur account-status sagt noch, warum. Webhooks enthalten keine Inhalte, nur Kennungen.
Datenschutzerklärung