// Package mcp 实现 MCP 协议网关,把工具注册到 NATS 并响应调用。 package mcp import ( "context" "fmt" "log" sharedbus "github.com/sundynix/sundynix-shared/bus" "github.com/sundynix/sundynix-shared/contract" "github.com/sundynix/sundynix-mcp-go/internal/search" ) // Gateway 暴露 MCP 协议端点,经共享 bus 订阅 sundynix.tools.go.* 响应调用。 type Gateway struct { bus *sharedbus.Bus search *search.Hybrid } func NewGateway(b *sharedbus.Bus, s *search.Hybrid) *Gateway { return &Gateway{bus: b, search: s} } // Serve 以队列组通配订阅 sundynix.tools.go.>,按工具名分发并阻塞。 func (g *Gateway) Serve(ctx context.Context) error { unsub, err := g.bus.ServeTool(contract.SubjectToolsGoAll, contract.QueueToolsGo, g.dispatch) if err != nil { return err } defer func() { _ = unsub() }() log.Printf("[mcp_go] tools ready on %s (queue=%s): wiki_search, echo", contract.SubjectToolsGoAll, contract.QueueToolsGo) <-ctx.Done() return ctx.Err() } // dispatch 按 ToolCall.Tool 路由到具体工具实现。 func (g *Gateway) dispatch(ctx context.Context, call *contract.ToolCall) *contract.ToolResult { log.Printf("[mcp_go] tool=%s task=%s args=%v", call.Tool, call.TaskID, call.Args) switch call.Tool { case "wiki_search": return g.wikiSearch(ctx, call) case "echo": return &contract.ToolResult{OK: true, Content: fmt.Sprint(call.Args["text"])} default: return &contract.ToolResult{OK: false, Error: "unknown tool: " + call.Tool} } } // wikiSearch 调 Hybrid 混合检索引擎。引擎目前为桩(返回空), // 这里仍把调用链路做真:真实接入 Bleve/Milvus/Neo4j 后无需改动协议。 func (g *Gateway) wikiSearch(ctx context.Context, call *contract.ToolCall) *contract.ToolResult { q, _ := call.Args["q"].(string) results, err := g.search.Query(ctx, q, 5) if err != nil { return &contract.ToolResult{OK: false, Error: "wiki_search: " + err.Error()} } return &contract.ToolResult{ OK: true, Content: fmt.Sprintf("[wiki_search] 命中 %d 条(Bleve+Milvus+Neo4j 混合检索桩)查询=%q", len(results), preview(q)), } } func preview(s string) string { r := []rune(s) if len(r) > 40 { return string(r[:40]) + "…" } return s }