// Command server is the Einherjar MCP server: a streamable-HTTP service // exposing framework knowledge tools to AI assistants. // // The framework index is embedded into the binary at build time by // cmd/indexer. The server itself only reads it. package main import ( "flag" "fmt" "log/slog" "net/http" "os" mcpmod "code.nochebuena.dev/einherjar/mcp" "code.nochebuena.dev/einherjar/mcp/internal/index" "code.nochebuena.dev/einherjar/mcp/internal/tools" "github.com/modelcontextprotocol/go-sdk/mcp" ) const ( serverName = "einherjar-mcp" serverVersion = "v0.1.0" ) func main() { addr := flag.String("addr", envOr("EINHERJAR_MCP_ADDR", ":8080"), "listen address") path := flag.String("path", envOr("EINHERJAR_MCP_PATH", "/mcp"), "HTTP path for the MCP streamable endpoint") flag.Parse() log := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelInfo})) idx, err := index.Load(mcpmod.IndexJSON) if err != nil { log.Error("load index", "err", err) os.Exit(1) } log.Info("index loaded", "modules", len(idx.Modules), "builtAt", idx.BuiltAt) server := mcp.NewServer(&mcp.Implementation{ Name: serverName, Version: serverVersion, }, nil) tools.Register(server, idx) handler := mcp.NewStreamableHTTPHandler(func(*http.Request) *mcp.Server { return server }, nil) mux := http.NewServeMux() mux.Handle(*path, handler) mux.HandleFunc("/healthz", func(w http.ResponseWriter, _ *http.Request) { fmt.Fprintln(w, "ok") }) log.Info("listening", "addr", *addr, "path", *path) if err := http.ListenAndServe(*addr, mux); err != nil { log.Error("server", "err", err) os.Exit(1) } } func envOr(key, def string) string { if v := os.Getenv(key); v != "" { return v } return def }