feat: LehrerApp.McpBridge zu resilientem MCP-Proxy umgebaut
Claude Desktop deaktivierte den ganzen MCP-Server, sobald der Initialize-Handshake beim Bridge-Start fehlschlug - der Regelfall, wenn LehrerApp.Desktop (z.B. nach Windows-Autostart von Claude Desktop) noch nicht läuft. Die Bridge ist jetzt selbst ein MCP-Server gegenüber Claude Desktop und gleichzeitig ein MCP-Client gegenüber dem echten Server in LehrerApp.Desktop: der Handshake gelingt dadurch immer. Verbunden spiegelt sie die echte Werkzeugliste 1:1; ohne Verbindung bietet sie nur ein lehrerapp_status-Werkzeug an, das den Grund erklärt und erneut verbindet. Ein Hintergrund-Loop versucht unabhängig davon alle 5s zu reconnecten und schaltet per notifications/tools/list_changed automatisch auf die echten Werkzeuge um, sobald LehrerApp erreichbar ist. Bricht die Verbindung während eines laufenden Aufrufs ab, kommt ein normales Tool-Fehlerergebnis statt eines Prozessabsturzes zurück. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -2756,6 +2756,62 @@ folgenden Punkte gehören direkt in `LehrerApp.Desktop`:
|
||||
schrieb und ein reiner No-Op genügte.
|
||||
- 16 neue Tests in [McpToolsTests.cs](LehrerApp.Desktop.Tests/McpToolsTests.cs) (jetzt 57).
|
||||
|
||||
- [x] **4.5.34** `LehrerApp.McpBridge` zu einem resilienten MCP-Proxy umgebaut, statt bei
|
||||
fehlendem Kontakt zu LehrerApp den ganzen Prozess fehlschlagen zu lassen (2026-09-12,
|
||||
Nutzer-Feedback): Claude Desktop startet per Windows-Autostart oft, bevor LehrerApp.Desktop
|
||||
läuft. Die Bridge führte den MCP-Initialize-Handshake bisher selbst nur einmal beim
|
||||
Prozessstart durch und ließ ihn fehlschlagen, wenn die Pipe zu diesem Zeitpunkt nicht
|
||||
erreichbar war — Claude Desktop markiert einen MCP-Server nach einem fehlgeschlagenen
|
||||
Handshake als tot und deaktiviert ihn für die Sitzung, ohne erneut zu versuchen. Ein erster
|
||||
Zwischenschritt (nur die Fehlermeldung nach Ursache unterscheiden, `TimeoutException` vs.
|
||||
echter Fehler) hätte daran nichts geändert — auf Nachfrage entschieden, stattdessen das
|
||||
eigentliche Problem zu lösen.
|
||||
- **Neue Architektur:** die Bridge ist jetzt selbst ein vollwertiger MCP-Server (über
|
||||
`ModelContextProtocol.Server`, dieselbe SDK-Bausteine wie `McpServerHostedService` in
|
||||
LehrerApp.Desktop) UND gleichzeitig ein MCP-**Client** gegenüber dem echten Server in
|
||||
LehrerApp.Desktop (`ModelContextProtocol.Client.McpClient` über
|
||||
`ModelContextProtocol.Protocol.StreamClientTransport` auf derselben Named Pipe). Der
|
||||
Initialize-Handshake gegenüber Claude Desktop gelingt dadurch **immer**, unabhängig davon,
|
||||
ob LehrerApp erreichbar ist.
|
||||
- Neues [RealServerBridge.cs](LehrerApp.McpBridge/RealServerBridge.cs): hält die Client-
|
||||
Verbindung zu LehrerApp und spiegelt deren aktuelle Werkzeugliste 1:1 (Name, Beschreibung,
|
||||
Eingabeschema unverändert übernommen) in die Werkzeugsammlung, die die Bridge Claude
|
||||
Desktop anbietet — kein eigenes Wissen über einzelne LehrerApp-Werkzeuge nötig, ändert sich
|
||||
eins in LehrerApp.Desktop, übernimmt die Bridge das automatisch beim nächsten
|
||||
Verbindungsaufbau. Ist LehrerApp nicht erreichbar, bietet die Bridge statt der echten
|
||||
Werkzeuge genau ein Werkzeug an,
|
||||
[StatusMcpServerTool.cs](LehrerApp.McpBridge/StatusMcpServerTool.cs)
|
||||
(`lehrerapp_status`) — es erklärt der KI, dass LehrerApp gestartet werden muss, und
|
||||
versucht bei jedem Aufruf aktiv erneut zu verbinden. Ein Hintergrund-Loop
|
||||
(`RunBackgroundReconnectLoopAsync`, alle 5s) versucht das unabhängig davon ebenfalls
|
||||
laufend, damit die echten Werkzeuge auch ohne aktives Nachfragen zurückkommen, sobald der
|
||||
Nutzer LehrerApp startet. Jeder Wechsel zwischen Status-Werkzeug und echter Werkzeugliste
|
||||
löst automatisch `notifications/tools/list_changed` aus
|
||||
(`McpServerPrimitiveCollection<T>.DeferChangedEvents`), worauf ein MCP-konformer Client
|
||||
seine Werkzeugliste neu abruft.
|
||||
- [ProxyMcpServerTool.cs](LehrerApp.McpBridge/ProxyMcpServerTool.cs) reicht einen Tool-Aufruf
|
||||
unverändert an den echten Client weiter; bricht die Verbindung während eines Aufrufs ab
|
||||
(LehrerApp wurde beendet), liefert `RealServerBridge.CallRealToolAsync` ein reguläres
|
||||
`CallToolResult` mit `IsError = true` und einer erklärenden Nachricht zurück — kein
|
||||
Transport-/Prozessabbruch, die Sitzung mit Claude Desktop bleibt bestehen, nur dieser eine
|
||||
Aufruf schlägt sichtbar (für den Assistenten erklärbar) fehl.
|
||||
- [ConnectionDiagnostics.cs](LehrerApp.McpBridge/ConnectionDiagnostics.cs): dieselbe
|
||||
Unterscheidung wie im verworfenen Zwischenschritt (`TimeoutException` = LehrerApp läuft
|
||||
nicht/MCP-Server nicht aktiviert, alles andere = echtes Konfigurations-/Rechteproblem, z.B.
|
||||
ein ACL-Mismatch zwischen den Prozessen) — jetzt als gemeinsam genutzter Baustein an allen
|
||||
drei Verbindungsversuchsstellen (initialer Connect, Hintergrund-Loop, Status-Werkzeug)
|
||||
statt nur im alten Einzel-Connect-Pfad.
|
||||
- End-to-End mit einer echten, laufenden LehrerApp.Desktop-Instanz verifiziert (manuelles
|
||||
JSON-RPC über die Bridge): erfolgreicher Connect übernimmt alle 35 registrierten Werkzeuge
|
||||
mit vollem Schema; `get_students` liefert echte Daten; LehrerApp.Desktop während einer
|
||||
laufenden Sitzung beendet lässt einen in Arbeit befindlichen Aufruf mit lesbarer
|
||||
Fehlermeldung statt Absturz fehlschlagen und schaltet auf das Status-Werkzeug um;
|
||||
LehrerApp.Desktop neu gestartet stellt die volle Werkzeugliste innerhalb des
|
||||
Hintergrund-Loop-Intervalls automatisch wieder her.
|
||||
- Kein zusätzliches Feature wie Windows-Autostart für LehrerApp.Desktop selbst oder ein
|
||||
Tray-Icon (auf Nachfrage bewusst nicht Teil dieser Änderung) — die Bridge löst das Problem
|
||||
rein auf Protokollebene, unabhängig davon, wann der Nutzer LehrerApp tatsächlich startet.
|
||||
|
||||
**Wichtige Abweichung von der ursprünglichen Planung (5.2):** Vor der Umsetzung zeigte sich,
|
||||
dass 5.2 wie ursprünglich beschrieben eine zweite, parallele Fehlzeiten-Erfassung neben dem
|
||||
bereits bestehenden Anwesenheits-Tracking aus Kapitel 3 (`ParticipationEntry.Attendance`,
|
||||
|
||||
Reference in New Issue
Block a user