| 25 | } |
| 26 | |
| 27 | func (m *MCPServerCMD) Run(_ *cliContext.Context) error { |
| 28 | if m.Target == "" { |
| 29 | return fmt.Errorf("--target / LOCALAI_MCP_TARGET is required") |
| 30 | } |
| 31 | |
| 32 | client := httpapi.New(m.Target, m.APIKey) |
| 33 | srv := localaitools.NewServer(client, localaitools.Options{ |
| 34 | DisableMutating: m.ReadOnly, |
| 35 | }) |
| 36 | |
| 37 | // Stdio: the host (e.g. Claude Desktop, Cursor, mcphost) talks JSON-RPC |
| 38 | // over our stdin/stdout. There's nothing else this process should print — |
| 39 | // every other goroutine logging to stderr is fine, but stdout is sacred. |
| 40 | // |
| 41 | // Honour SIGINT/SIGTERM so a Ctrl-C from the host or `kill -TERM` from |
| 42 | // process supervision gives srv.Run a chance to drain in-flight calls |
| 43 | // before exiting. |
| 44 | ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) |
| 45 | defer stop() |
| 46 | return srv.Run(ctx, &mcp.StdioTransport{}) |
| 47 | } |