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>
This commit is contained in:
2026-09-13 01:46:04 +02:00
co-authored by Claude Sonnet 5
parent 2c791258a1
commit 42c650518c
3 changed files with 36 additions and 0 deletions
+25
View File
@@ -9,4 +9,29 @@ namespace LehrerApp.Core.Mcp;
public static class McpPipeConstants public static class McpPipeConstants
{ {
public const string PipeName = "LehrerApp.Mcp"; public const string PipeName = "LehrerApp.Mcp";
/// <summary>
/// Unter macOS/Linux emuliert .NET Named Pipes über eine Socket-Datei unter
/// <see cref="Path.GetTempPath"/> (intern "CoreFxPipe_" + Name), und die liest dafür die
/// TMPDIR-Umgebungsvariable des jeweiligen Prozesses. LehrerApp.Desktop (von Finder/Dock
/// gestartet) bekommt das reguläre per-Login-Session-TMPDIR unter /var/folders/.../T,
/// während LehrerApp.McpBridge als Kindprozess von Claude Desktop oft eine reduzierte
/// Umgebung mit TMPDIR=/tmp erbt - beide Prozesse suchen die Pipe-Datei dann an
/// unterschiedlichen Orten und finden sich nie ("MCP nicht erreichbar, obwohl LehrerApp
/// läuft", auch wenn beide Prozesse laufen und die Pipe grundsätzlich offen ist). Fix: TMPDIR
/// für beide Prozesse hart auf denselben Ordner setzen, bevor die erste
/// NamedPipeServerStream/-ClientStream-Instanz entsteht - dieselbe ApplicationData-Basis wie
/// AppBootstrapper (siehe dort) wird anders als TMPDIR zuverlässig an Kindprozesse
/// weitergereicht. Muss als eine der ersten Anweisungen in Main aufgerufen werden (Desktop wie
/// Bridge), auf Windows ein No-op (dort nutzen Named Pipes den Kernel-Namespace, keine
/// Socket-Datei).
/// </summary>
public static void EnsureStableUnixSocketDirectory()
{
if (OperatingSystem.IsWindows()) return;
var dir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
"LehrerApp", "ipc");
Directory.CreateDirectory(dir);
Environment.SetEnvironmentVariable("TMPDIR", dir);
}
} }
+5
View File
@@ -1,4 +1,5 @@
using Avalonia; using Avalonia;
using LehrerApp.Core.Mcp;
using LehrerApp.Desktop.Services; using LehrerApp.Desktop.Services;
namespace LehrerApp.Desktop; namespace LehrerApp.Desktop;
@@ -8,6 +9,10 @@ class Program
[STAThread] [STAThread]
public static void Main(string[] args) public static void Main(string[] args)
{ {
// Muss vor der ersten NamedPipeServerStream-Instanz laufen (siehe
// McpServerHostedService), sonst löst TMPDIR-Auseinanderdriften zwischen diesem Prozess
// und LehrerApp.McpBridge auf macOS/Linux "MCP nicht erreichbar" aus - siehe Doku dort.
McpPipeConstants.EnsureStableUnixSocketDirectory();
var logger = AppBootstrapper.EnsureLogger(); var logger = AppBootstrapper.EnsureLogger();
GlobalExceptionHandler.Install(logger); GlobalExceptionHandler.Install(logger);
+6
View File
@@ -1,3 +1,4 @@
using LehrerApp.Core.Mcp;
using LehrerApp.McpBridge; using LehrerApp.McpBridge;
using ModelContextProtocol.Protocol; using ModelContextProtocol.Protocol;
using ModelContextProtocol.Server; using ModelContextProtocol.Server;
@@ -9,6 +10,11 @@ using ModelContextProtocol.Server;
// Nachladen der echten Werkzeugliste, sobald LehrerApp erreichbar ist, übernimmt // Nachladen der echten Werkzeugliste, sobald LehrerApp erreichbar ist, übernimmt
// RealServerBridge - Details und Begründung siehe dort. // 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(); var bridge = new RealServerBridge();
await bridge.TryReconnectAsync(CancellationToken.None); await bridge.TryReconnectAsync(CancellationToken.None);
bridge.EnsureFallbackTool(); bridge.EnsureFallbackTool();