Files
LehrerApp/LehrerApp.McpBridge/Program.cs
T
adminandClaude Sonnet 5 42c650518c MCP: TMPDIR-Auseinanderdriften zwischen Desktop und Bridge auf Mac/Linux behoben
LehrerApp.Desktop und LehrerApp.McpBridge emulieren die Named Pipe unter
macOS/Linux über eine Socket-Datei unter TMPDIR. Von Finder/Dock
gestartet bekommt Desktop das reguläre Session-TMPDIR unter
/var/folders/.../T, während die Bridge als Kindprozess von Claude
Desktop oft eine reduzierte Umgebung mit TMPDIR=/tmp erbt - beide
suchten die Pipe-Datei dann an unterschiedlichen Orten und fanden sich
nie ("MCP nicht erreichbar", obwohl beide Prozesse liefen). TMPDIR wird
jetzt in beiden Prozessen vor der ersten Pipe-Instanz hart auf denselben,
von ApplicationData abgeleiteten Ordner gesetzt.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-13 01:46:04 +02:00

52 lines
2.4 KiB
C#

using LehrerApp.Core.Mcp;
using LehrerApp.McpBridge;
using ModelContextProtocol.Protocol;
using ModelContextProtocol.Server;
// Resilienter Bridge-Prozess (Nutzer-Feedback): meldet sich gegenüber dem KI-Client (z.B. Claude
// Desktop) IMMER erfolgreich als MCP-Server, unabhängig davon, ob LehrerApp.Desktop beim Start
// dieses Prozesses bereits läuft - Claude Desktop startet oft per Windows-Autostart, bevor der
// Nutzer LehrerApp geöffnet hat. Die eigentliche Weiterleitung an den echten Server sowie das
// Nachladen der echten Werkzeugliste, sobald LehrerApp erreichbar ist, übernimmt
// RealServerBridge - Details und Begründung siehe dort.
// Muss vor der ersten NamedPipeClientStream-Instanz laufen (siehe RealServerBridge), sonst löst
// TMPDIR-Auseinanderdriften zwischen diesem als Claude-Desktop-Kindprozess gestarteten Prozess und
// LehrerApp.Desktop auf macOS/Linux "MCP nicht erreichbar" aus, obwohl LehrerApp läuft.
McpPipeConstants.EnsureStableUnixSocketDirectory();
var bridge = new RealServerBridge();
await bridge.TryReconnectAsync(CancellationToken.None);
bridge.EnsureFallbackTool();
using var cts = new CancellationTokenSource();
var reconnectLoop = bridge.RunBackgroundReconnectLoopAsync(TimeSpan.FromSeconds(5), cts.Token);
var serverOptions = new McpServerOptions
{
ServerInfo = new Implementation { Name = "LehrerApp", Version = "1.0.0" },
// ListChanged = true: Voraussetzung dafür, dass Claude Desktop reagiert, wenn RealServerBridge
// das Status-Werkzeug nachträglich durch die echte Werkzeugliste ersetzt (oder umgekehrt, falls
// LehrerApp während der Sitzung beendet wird).
Capabilities = new ServerCapabilities { Tools = new ToolsCapability { ListChanged = true } },
ToolCollection = bridge.Tools,
};
await using var stdin = Console.OpenStandardInput();
await using var stdout = Console.OpenStandardOutput();
await using var transport = new StreamServerTransport(stdin, stdout, "LehrerApp.McpBridge");
await using var server = McpServer.Create(transport, serverOptions, loggerFactory: null, serviceProvider: null);
try
{
// Läuft, bis der KI-Client stdin schließt (Sitzungsende) - danach ist nichts mehr zu tun.
await server.RunAsync(cts.Token);
}
finally
{
await cts.CancelAsync();
try { await reconnectLoop; }
catch { /* Beenden über Cancellation ist der Normalfall hier */ }
await bridge.DisposeAsync();
}