cli/pkg/mcp/transport_unix.go
Vi bdbcc4acfd feat(daemon): add MCP daemon mode with multi-transport support (#334)
Implements the daemon mode feature for running core as a background service
with MCP server capabilities.

New features:
- `core daemon` command with configurable MCP transport
- Support for stdio, TCP, and Unix socket transports
- Environment variable configuration (CORE_MCP_TRANSPORT, CORE_MCP_ADDR)
- CLI flags for runtime configuration
- Integration with existing daemon infrastructure (PID file, health checks)

Files added:
- internal/cmd/daemon/cmd.go - daemon command implementation
- pkg/mcp/transport_stdio.go - stdio transport wrapper
- pkg/mcp/transport_unix.go - Unix domain socket transport

Files modified:
- pkg/mcp/mcp.go - added log import
- pkg/mcp/transport_tcp.go - added log import
- pkg/mcp/transport_tcp_test.go - fixed port binding test

Usage:
  core daemon                           # TCP on 127.0.0.1:9100
  core daemon --mcp-transport=socket --mcp-addr=/tmp/core.sock
  CORE_MCP_TRANSPORT=stdio core daemon  # for Claude Code integration

Fixes #119

Co-authored-by: Claude <developers@lethean.io>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Snider <snider@host.uk.com>
2026-02-05 17:42:35 +00:00

52 lines
1.3 KiB
Go

package mcp
import (
"context"
"net"
"os"
"github.com/host-uk/core/pkg/log"
)
// ServeUnix starts a Unix domain socket server for the MCP service.
// The socket file is created at the given path and removed on shutdown.
// It accepts connections and spawns a new MCP server session for each connection.
func (s *Service) ServeUnix(ctx context.Context, socketPath string) error {
// Clean up any stale socket file
if err := os.Remove(socketPath); err != nil && !os.IsNotExist(err) {
s.logger.Warn("Failed to remove stale socket", "path", socketPath, "err", err)
}
listener, err := net.Listen("unix", socketPath)
if err != nil {
return err
}
defer func() {
_ = listener.Close()
_ = os.Remove(socketPath)
}()
// Close listener when context is cancelled to unblock Accept
go func() {
<-ctx.Done()
_ = listener.Close()
}()
s.logger.Security("MCP Unix server listening", "path", socketPath, "user", log.Username())
for {
conn, err := listener.Accept()
if err != nil {
select {
case <-ctx.Done():
return nil
default:
s.logger.Error("MCP Unix accept error", "err", err, "user", log.Username())
continue
}
}
s.logger.Security("MCP Unix connection accepted", "user", log.Username())
go s.handleConnection(ctx, conn)
}
}