feat(mcp): auto-select unix socket transport

Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
Virgil 2026-04-02 12:56:30 +00:00
parent e09f3518e0
commit 8e77c5e58d
3 changed files with 62 additions and 3 deletions

View file

@ -10,10 +10,10 @@ import (
"os/signal"
"syscall"
"forge.lthn.ai/core/cli/pkg/cli"
"dappco.re/go/mcp/pkg/mcp"
"dappco.re/go/mcp/pkg/mcp/agentic"
"dappco.re/go/mcp/pkg/mcp/brain"
"forge.lthn.ai/core/cli/pkg/cli"
)
var workspaceFlag string
@ -27,13 +27,18 @@ var mcpCmd = &cli.Command{
var serveCmd = &cli.Command{
Use: "serve",
Short: "Start the MCP server",
Long: `Start the MCP server on stdio (default) or TCP.
Long: `Start the MCP server on stdio (default), TCP, Unix socket, or HTTP.
The server provides file operations, RAG tools, and metrics tools for AI assistants.
Environment variables:
MCP_ADDR TCP address to listen on (e.g., "localhost:9999")
If not set, uses stdio transport.
MCP_UNIX_SOCKET
Unix socket path to listen on (e.g., "/tmp/core-mcp.sock")
Selected after MCP_ADDR and before stdio.
MCP_HTTP_ADDR
HTTP address to listen on (e.g., "127.0.0.1:9101")
Selected before MCP_ADDR and stdio.
Examples:
# Start with stdio transport (for Claude Code integration)

View file

@ -716,6 +716,10 @@ func supportedLanguages() []LanguageInfo {
// os.Setenv("MCP_ADDR", "127.0.0.1:9100")
// svc.Run(ctx)
//
// // Unix socket (set MCP_UNIX_SOCKET):
// os.Setenv("MCP_UNIX_SOCKET", "/tmp/core-mcp.sock")
// svc.Run(ctx)
//
// // HTTP (set MCP_HTTP_ADDR):
// os.Setenv("MCP_HTTP_ADDR", "127.0.0.1:9101")
// svc.Run(ctx)
@ -726,6 +730,9 @@ func (s *Service) Run(ctx context.Context) error {
if addr := core.Env("MCP_ADDR"); addr != "" {
return s.ServeTCP(ctx, addr)
}
if socketPath := core.Env("MCP_UNIX_SOCKET"); socketPath != "" {
return s.ServeUnix(ctx, socketPath)
}
return s.ServeStdio(ctx)
}

View file

@ -0,0 +1,47 @@
package mcp
import (
"context"
"net"
"testing"
"time"
)
func TestRun_Good_UnixTrigger(t *testing.T) {
s, err := New(Options{})
if err != nil {
t.Fatalf("Failed to create service: %v", err)
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
socketPath := shortSocketPath(t, "run")
t.Setenv("MCP_UNIX_SOCKET", socketPath)
t.Setenv("MCP_HTTP_ADDR", "")
t.Setenv("MCP_ADDR", "")
errCh := make(chan error, 1)
go func() {
errCh <- s.Run(ctx)
}()
var conn net.Conn
deadline := time.Now().Add(2 * time.Second)
for time.Now().Before(deadline) {
conn, err = net.DialTimeout("unix", socketPath, 200*time.Millisecond)
if err == nil {
break
}
time.Sleep(50 * time.Millisecond)
}
if err != nil {
t.Fatalf("Failed to connect to Unix socket at %s: %v", socketPath, err)
}
conn.Close()
cancel()
if err := <-errCh; err != nil {
t.Fatalf("Run failed: %v", err)
}
}