docs: MCP beschreiben, Fahrplan abschliessen
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
bdc4260d59
commit
0ccb21303d
@@ -6,6 +6,29 @@ die Versionierung [Semantic Versioning](https://semver.org/lang/de/).
|
|||||||
|
|
||||||
## [Unveröffentlicht]
|
## [Unveröffentlicht]
|
||||||
|
|
||||||
|
### Hinzugefügt
|
||||||
|
|
||||||
|
- **MCP-Server** unter `/api/mcp` mit sechs Werkzeugen: Aufgaben suchen,
|
||||||
|
Woche ansehen, Kalender auflisten, Aufgabe anlegen, abhaken und einplanen.
|
||||||
|
Beschreibung in [docs/MCP.md](docs/MCP.md).
|
||||||
|
- Die Werkzeugliste richtet sich nach den Rechten des Tokens — was ein Token
|
||||||
|
nicht darf, sieht das Modell gar nicht erst.
|
||||||
|
|
||||||
|
### Geändert
|
||||||
|
|
||||||
|
- Das Einplanen liegt jetzt an einer Stelle, die sowohl die Oberfläche als
|
||||||
|
auch der MCP-Server benutzen. Ein über MCP angelegter Zeitblock verhält
|
||||||
|
sich damit genau wie ein von Hand gezogener.
|
||||||
|
|
||||||
|
### Sicherheit
|
||||||
|
|
||||||
|
- MCP benutzt dieselben Tokens und dieselben Rechte wie die Schnittstelle.
|
||||||
|
Ein Sprachmodell bekommt keinen eigenen Zugang.
|
||||||
|
- Jede schreibende Nutzung steht im Protokoll, mit dem Vermerk, dass sie
|
||||||
|
über MCP kam.
|
||||||
|
- Der Server kann weder löschen noch Bereiche, Projekte, Kalenderkonten,
|
||||||
|
Einstellungen oder Tokens anfassen.
|
||||||
|
|
||||||
## [0.7.0] – 2026-09-13
|
## [0.7.0] – 2026-09-13
|
||||||
|
|
||||||
### Hinzugefügt
|
### Hinzugefügt
|
||||||
|
|||||||
@@ -43,6 +43,8 @@ wird.
|
|||||||
Planer lässt sich als App auf dem Startbildschirm ablegen
|
Planer lässt sich als App auf dem Startbildschirm ablegen
|
||||||
- **Öffentliche Schnittstelle** mit Tokens je Anwendung, Rechten je Token und
|
- **Öffentliche Schnittstelle** mit Tokens je Anwendung, Rechten je Token und
|
||||||
jeder schreibenden Nutzung im Protokoll ([Beschreibung](docs/API.md))
|
jeder schreibenden Nutzung im Protokoll ([Beschreibung](docs/API.md))
|
||||||
|
- **MCP-Server** für Sprachmodelle — dieselben Tokens, dieselben Rechte
|
||||||
|
([Beschreibung](docs/MCP.md))
|
||||||
- Anmeldung über einen OIDC-Anbieter, über Passkeys oder mit E-Mail und
|
- Anmeldung über einen OIDC-Anbieter, über Passkeys oder mit E-Mail und
|
||||||
Passwort — je Instanz einzeln zuschaltbar
|
Passwort — je Instanz einzeln zuschaltbar
|
||||||
- Rollen `Benutzer` und `Verwaltung`; jede schreibende Aktion wird
|
- Rollen `Benutzer` und `Verwaltung`; jede schreibende Aktion wird
|
||||||
@@ -51,9 +53,10 @@ wird.
|
|||||||
- Hell und Dunkel, Oberfläche durchgehend auf Deutsch
|
- Hell und Dunkel, Oberfläche durchgehend auf Deutsch
|
||||||
- Betrieb über Docker Compose, mit Sicherung, Aktualisierung und Healthcheck
|
- Betrieb über Docker Compose, mit Sicherung, Aktualisierung und Healthcheck
|
||||||
|
|
||||||
### Geplant
|
### Was noch kommen könnte
|
||||||
|
|
||||||
Ein MCP-Server. Siehe [ROADMAP.md](ROADMAP.md).
|
Der [Fahrplan](ROADMAP.md) ist abgearbeitet. Was danach denkbar wäre, steht
|
||||||
|
dort unter „Ideen für später" — und was bewusst nicht kommt, gleich darunter.
|
||||||
|
|
||||||
## Bildergalerie
|
## Bildergalerie
|
||||||
|
|
||||||
|
|||||||
+14
-4
@@ -12,7 +12,7 @@ grünen Prüfungen, aktueller Dokumentation und einem Eintrag im DEVLOG.
|
|||||||
| [M5](#m5--benachrichtigungen) | Benachrichtigungen | erledigt |
|
| [M5](#m5--benachrichtigungen) | Benachrichtigungen | erledigt |
|
||||||
| [M6](#m6--integrationen) | Integrationen | erledigt |
|
| [M6](#m6--integrationen) | Integrationen | erledigt |
|
||||||
| [M7](#m7--schnellerfassung-und-api) | Schnellerfassung und API | erledigt |
|
| [M7](#m7--schnellerfassung-und-api) | Schnellerfassung und API | erledigt |
|
||||||
| [M8](#m8--mcp) | MCP | geplant |
|
| [M8](#m8--mcp) | MCP | erledigt |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -156,9 +156,19 @@ Zeremonie als Schutz.
|
|||||||
|
|
||||||
## M8 – MCP
|
## M8 – MCP
|
||||||
|
|
||||||
- [ ] MCP-Server über `@modelcontextprotocol/sdk`
|
**Erledigt am 13.09.2026 mit Version 0.8.0.**
|
||||||
- [ ] Lesen und Anlegen von Aufgaben und Zeitblöcken
|
|
||||||
- [ ] Rechte wie bei der API, jede Nutzung im Protokoll
|
**Ziel:** Ein Sprachmodell soll den Alltag erleichtern können — ohne einen
|
||||||
|
eigenen, weicheren Zugang zu bekommen als jede andere fremde Anwendung.
|
||||||
|
|
||||||
|
- [x] MCP-Server über `@modelcontextprotocol/sdk`
|
||||||
|
- [x] Lesen und Anlegen von Aufgaben und Zeitblöcken
|
||||||
|
- [x] Rechte wie bei der API, jede schreibende Nutzung im Protokoll
|
||||||
|
- [x] Werkzeugliste richtet sich nach den Rechten des Tokens
|
||||||
|
|
||||||
|
**Bewusst offen gelassen:** Der Server kann nichts löschen, keine Bereiche
|
||||||
|
oder Projekte anlegen und keine Einstellungen anfassen. Ein Modell soll den
|
||||||
|
Alltag erleichtern, nicht die Ordnung umbauen.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
+83
@@ -0,0 +1,83 @@
|
|||||||
|
# MCP-Server
|
||||||
|
|
||||||
|
Der Planer spricht das Model Context Protocol. Damit kann ein Sprachmodell
|
||||||
|
Aufgaben suchen, anlegen, abhaken und einplanen — mit denselben Tokens und
|
||||||
|
denselben Rechten wie die [Schnittstelle](API.md).
|
||||||
|
|
||||||
|
Adresse: `<APP_URL>/api/mcp`
|
||||||
|
|
||||||
|
## Einrichten
|
||||||
|
|
||||||
|
1. In der Anwendung unter **API** einen Token anlegen. Gib ihm nur, was das
|
||||||
|
Modell wirklich braucht.
|
||||||
|
2. Den Client auf die Adresse zeigen lassen, mit dem Token als Bearer.
|
||||||
|
|
||||||
|
Für Claude Code:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
claude mcp add planer --transport http https://planer.example.de/api/mcp \
|
||||||
|
--header "Authorization: Bearer planer_…"
|
||||||
|
```
|
||||||
|
|
||||||
|
Für Clients, die nur stdio können, dazwischen `mcp-remote` setzen:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"planer": {
|
||||||
|
"command": "npx",
|
||||||
|
"args": [
|
||||||
|
"-y",
|
||||||
|
"mcp-remote",
|
||||||
|
"https://planer.example.de/api/mcp",
|
||||||
|
"--header",
|
||||||
|
"Authorization: Bearer planer_…"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Werkzeuge
|
||||||
|
|
||||||
|
Welche ein Modell zu sehen bekommt, hängt am Token. Was nicht erlaubt ist,
|
||||||
|
taucht gar nicht erst in der Liste auf — ein Modell soll nicht gegen eine Tür
|
||||||
|
laufen, die für es verschlossen ist.
|
||||||
|
|
||||||
|
| Werkzeug | Recht | Was es tut |
|
||||||
|
| -------------------- | ----------- | ----------------------------------------------- |
|
||||||
|
| `aufgaben_suchen` | `lesen` | Aufgaben auflisten, optional gefiltert |
|
||||||
|
| `woche_ansehen` | `lesen` | Zeitblöcke einer Woche mit Summe |
|
||||||
|
| `kalender_auflisten` | `lesen` | Verbundene Kalender samt Kennung |
|
||||||
|
| `aufgabe_anlegen` | `erfassen` | Neue Aufgabe in der Inbox |
|
||||||
|
| `aufgabe_abhaken` | `schreiben` | Aufgabe auf erledigt setzen |
|
||||||
|
| `zeitblock_anlegen` | `schreiben` | Aufgabe einplanen und in den Kalender schreiben |
|
||||||
|
|
||||||
|
Zum Einplanen braucht es die Kennung eines Kalenderkontos — daher erst
|
||||||
|
`kalender_auflisten`, dann `zeitblock_anlegen`.
|
||||||
|
|
||||||
|
`zeitblock_anlegen` geht durch dieselbe Stelle wie das Ziehen in der
|
||||||
|
Wochenansicht: Rasterprüfung, Kalenderschreibweg, Schleifenschutz, Protokoll.
|
||||||
|
Ein über MCP angelegter Zeitblock verhält sich also genau wie ein von Hand
|
||||||
|
gezogener.
|
||||||
|
|
||||||
|
## Was der Server bewusst **nicht** kann
|
||||||
|
|
||||||
|
- **Löschen.** Weder Aufgaben noch Zeitblöcke. Abhaken ja, wegräumen nein.
|
||||||
|
- **Bereich oder Projekt setzen.** Was hier entsteht, landet in der Inbox.
|
||||||
|
- **Bereiche, Projekte oder Kalenderkonten anlegen und ändern.**
|
||||||
|
- **Einstellungen oder Tokens anfassen.**
|
||||||
|
|
||||||
|
Ein Modell soll den Alltag erleichtern, nicht die Ordnung umbauen.
|
||||||
|
|
||||||
|
## Protokoll
|
||||||
|
|
||||||
|
Jede schreibende Nutzung landet im Protokoll — mit dem Vermerk, dass sie über
|
||||||
|
MCP kam, und mit dem Token. Ein Modell, das Aufgaben anlegt, muss genauso
|
||||||
|
nachvollziehbar sein wie ein Mensch. Eher noch mehr.
|
||||||
|
|
||||||
|
## Ohne Sitzungen
|
||||||
|
|
||||||
|
Der Server ist zustandslos: Jede Anfrage steht für sich. Der Planer hat keine
|
||||||
|
langlaufenden Vorgänge, und eine Sitzungsverwaltung wäre Zustand, den mehrere
|
||||||
|
Container nicht teilen könnten.
|
||||||
+1
-10
@@ -31,18 +31,9 @@ Anleitung für den Alltag mit dem Planer. Eine Seite je Thema.
|
|||||||
|
|
||||||
11. **[Protokoll](protokoll.md)** – nachsehen, wer wann was geändert hat
|
11. **[Protokoll](protokoll.md)** – nachsehen, wer wann was geändert hat
|
||||||
|
|
||||||
## Was noch kommt
|
|
||||||
|
|
||||||
Diese Seiten entstehen mit den nächsten Meilensteinen:
|
|
||||||
|
|
||||||
| Thema | Meilenstein |
|
|
||||||
| ----- | ----------- |
|
|
||||||
| MCP | M8 |
|
|
||||||
|
|
||||||
Der [Fahrplan](../../ROADMAP.md) sagt, was in welchem Meilenstein steckt.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
Für fremde Anwendungen und Skripte: [Schnittstelle](../API.md).
|
Für fremde Anwendungen und Skripte: [Schnittstelle](../API.md).
|
||||||
|
Für Sprachmodelle: [MCP-Server](../MCP.md).
|
||||||
Zur Einrichtung einer neuen Instanz: [Schnellstart](../SCHNELLSTART.md).
|
Zur Einrichtung einer neuen Instanz: [Schnellstart](../SCHNELLSTART.md).
|
||||||
Für Betrieb, Sicherung und alle Umgebungsvariablen: [README](../../README.md).
|
Für Betrieb, Sicherung und alle Umgebungsvariablen: [README](../../README.md).
|
||||||
|
|||||||
@@ -70,10 +70,10 @@ export async function zeitblockAnlegen(daten: FormData): Promise<Rueckmeldung> {
|
|||||||
const ergebnis = await zeitblockAnlegenFuer(
|
const ergebnis = await zeitblockAnlegenFuer(
|
||||||
{ id: akteur.id, email: akteur.email },
|
{ id: akteur.id, email: akteur.email },
|
||||||
{
|
{
|
||||||
aufgabeId: String(daten.get('aufgabeId') ?? ''),
|
aufgabeId: feld(daten, 'aufgabeId'),
|
||||||
kalenderkontoId: String(daten.get('kalenderkontoId') ?? ''),
|
kalenderkontoId: feld(daten, 'kalenderkontoId'),
|
||||||
beginn: new Date(String(daten.get('beginn') ?? '')),
|
beginn: new Date(feld(daten, 'beginn')),
|
||||||
ende: new Date(String(daten.get('ende') ?? '')),
|
ende: new Date(feld(daten, 'ende')),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -91,6 +91,17 @@ export async function zeitblockAnlegen(daten: FormData): Promise<Rueckmeldung> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ein Textfeld aus dem Formular.
|
||||||
|
*
|
||||||
|
* FormData kann auch Dateien liefern; die haetten hier nichts zu suchen und
|
||||||
|
* wuerden beim Stringify zu "[object Object]".
|
||||||
|
*/
|
||||||
|
function feld(daten: FormData, name: string): string {
|
||||||
|
const wert = daten.get(name)
|
||||||
|
return typeof wert === 'string' ? wert : ''
|
||||||
|
}
|
||||||
|
|
||||||
// --- Verschieben -----------------------------------------------------------
|
// --- Verschieben -----------------------------------------------------------
|
||||||
|
|
||||||
const verschieben = z.object({
|
const verschieben = z.object({
|
||||||
|
|||||||
Reference in New Issue
Block a user