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>
52 lines
1.3 KiB
Go
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)
|
|
}
|
|
}
|