go-ai/cmd/daemon/cmd.go
Snider 0202bec84a
Some checks failed
Security Scan / security (push) Successful in 9s
Test / test (push) Failing after 1m47s
refactor: extract MCP server to core/mcp
Move mcp/, cmd/mcpcmd/, cmd/brain-seed/ to the new core/mcp repo.
Update daemon import to use forge.lthn.ai/core/mcp/pkg/mcp.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 18:40:50 +00:00

119 lines
3.2 KiB
Go

// Package daemon provides the `core daemon` command for running as a background service.
package daemon
import (
"context"
"fmt"
"os"
"path/filepath"
"forge.lthn.ai/core/cli/pkg/cli"
"forge.lthn.ai/core/mcp/pkg/mcp"
"forge.lthn.ai/core/go-log"
"forge.lthn.ai/core/go-process"
)
// Transport types for MCP server.
const (
TransportStdio = "stdio"
TransportTCP = "tcp"
TransportSocket = "socket"
)
// Config holds daemon configuration.
type Config struct {
// MCPTransport is the MCP server transport type (stdio, tcp, socket).
MCPTransport string
// MCPAddr is the address/path for tcp or socket transports.
MCPAddr string
// HealthAddr is the address for health check endpoints.
HealthAddr string
// PIDFile is the path for the PID file.
PIDFile string
}
// DefaultConfig returns the default daemon configuration.
func DefaultConfig() Config {
home, _ := os.UserHomeDir()
return Config{
MCPTransport: TransportTCP,
MCPAddr: mcp.DefaultTCPAddr,
HealthAddr: "127.0.0.1:9101",
PIDFile: filepath.Join(home, ".core", "daemon.pid"),
}
}
// ConfigFromEnv loads configuration from environment variables.
func ConfigFromEnv() Config {
cfg := DefaultConfig()
if v := os.Getenv("CORE_MCP_TRANSPORT"); v != "" {
cfg.MCPTransport = v
}
if v := os.Getenv("CORE_MCP_ADDR"); v != "" {
cfg.MCPAddr = v
}
if v := os.Getenv("CORE_HEALTH_ADDR"); v != "" {
cfg.HealthAddr = v
}
if v := os.Getenv("CORE_PID_FILE"); v != "" {
cfg.PIDFile = v
}
return cfg
}
// AddDaemonCommand adds the 'daemon' command group to the root.
func AddDaemonCommand(root *cli.Command) {
cfg := ConfigFromEnv()
cli.AddDaemonCommand(root, cli.DaemonCommandConfig{
Name: "daemon",
Description: "Manage the core daemon",
PIDFile: cfg.PIDFile,
HealthAddr: cfg.HealthAddr,
RunForeground: func(ctx context.Context, _ *process.Daemon) error {
log.Info("Starting MCP service",
"transport", cfg.MCPTransport,
"addr", cfg.MCPAddr,
)
mcpSvc, err := mcp.New()
if err != nil {
return fmt.Errorf("failed to create MCP service: %w", err)
}
return startMCP(ctx, mcpSvc, cfg)
},
ExtraStartArgs: func() []string {
return []string{
"--mcp-transport", cfg.MCPTransport,
"--mcp-addr", cfg.MCPAddr,
}
},
Flags: func(cmd *cli.Command) {
cli.PersistentStringFlag(cmd, &cfg.MCPTransport, "mcp-transport", "t", cfg.MCPTransport,
"MCP transport type (stdio, tcp, socket)")
cli.PersistentStringFlag(cmd, &cfg.MCPAddr, "mcp-addr", "a", cfg.MCPAddr,
"MCP listen address (e.g., :9100 or /tmp/mcp.sock)")
},
})
}
// startMCP starts the MCP server with the configured transport.
func startMCP(ctx context.Context, svc *mcp.Service, cfg Config) error {
switch cfg.MCPTransport {
case TransportStdio:
log.Info("Starting MCP server", "transport", "stdio")
return svc.ServeStdio(ctx)
case TransportTCP:
log.Info("Starting MCP server", "transport", "tcp", "addr", cfg.MCPAddr)
return svc.ServeTCP(ctx, cfg.MCPAddr)
case TransportSocket:
log.Info("Starting MCP server", "transport", "unix", "path", cfg.MCPAddr)
return svc.ServeUnix(ctx, cfg.MCPAddr)
default:
return fmt.Errorf("unknown MCP transport: %s (valid: stdio, tcp, socket)", cfg.MCPTransport)
}
}