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:
@@ -0,0 +1,21 @@
|
||||
using ModelContextProtocol.Protocol;
|
||||
using ModelContextProtocol.Server;
|
||||
|
||||
namespace LehrerApp.McpBridge;
|
||||
|
||||
/// <summary>
|
||||
/// Reicht einen von LehrerApp.Desktop tatsächlich angebotenen MCP-Tool-Aufruf 1:1 an den echten
|
||||
/// Server weiter - Name, Beschreibung und Eingabeschema (<see cref="ProtocolTool"/>) stammen
|
||||
/// unverändert von dort (siehe <see cref="RealServerBridge"/>). Die Bridge muss dadurch kein
|
||||
/// eigenes Wissen über einzelne LehrerApp-Werkzeuge/-Parameter pflegen; ändert sich ein Tool in
|
||||
/// LehrerApp.Desktop, übernimmt die Bridge das beim nächsten Verbindungsaufbau automatisch.
|
||||
/// </summary>
|
||||
internal sealed class ProxyMcpServerTool(Tool protocolTool, RealServerBridge bridge) : McpServerTool
|
||||
{
|
||||
public override Tool ProtocolTool { get; } = protocolTool;
|
||||
public override IReadOnlyList<object> Metadata { get; } = [];
|
||||
|
||||
public override ValueTask<CallToolResult> InvokeAsync(
|
||||
RequestContext<CallToolRequestParams> request, CancellationToken cancellationToken) =>
|
||||
new(bridge.CallRealToolAsync(request.Params, cancellationToken));
|
||||
}
|
||||
Reference in New Issue
Block a user