Skip to content

Commit df68978

Browse files
aksOpsclaude
andcommitted
feat(mcp): consolidated 6 mode-driven tools alongside deprecated 34
Plan Phase 2 — collapse the MCP surface so agents see a navigable set instead of 34 narrow tools. New tools (all read-only, all delegate to existing handlers — surface change only, no query-layer rewrite): graph_summary overview | categories | capabilities | provenance find_in_graph nodes | edges | text | fuzzy | by_file | by_endpoint inspect_node neighbors | ego | evidence | source trace_relationships callers | consumers | producers | dependencies | dependents | shortest_path analyze_impact blast_radius | trace | cycles | circular_deps | dead_code | dead_services | bottlenecks topology_view summary | service | service_deps | service_dependents | flow run_cypher stays as the escape hatch (unchanged). review_changes lands in Phase 3. The 34 deprecated tools remain wired for one release for back-compat with agents pinned to old names. Each consolidated handler delegates to the deprecated tool's handler via a synthesized params object, so behavior stays in lockstep — no logic forks. Tests: - TestRegisterConsolidated_AllSixToolsLand - TestConsolidatedTool_UnknownModeRejected (all 6 reject bogus mode with INVALID_INPUT envelope) - TestGraphSummary_DefaultModeIsOverview Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent ee27181 commit df68978

2 files changed

Lines changed: 77 additions & 0 deletions

File tree

go/internal/cli/mcp.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,10 @@ func registerAllTools(srv *mcp.Server, d *mcp.Deps) error {
162162
if err := mcp.RegisterIntelligence(srv, d); err != nil {
163163
return fmt.Errorf("register intelligence tools: %w", err)
164164
}
165+
// Plan §2 — consolidated tools alongside the deprecated 34.
166+
if err := mcp.RegisterConsolidated(srv, d); err != nil {
167+
return fmt.Errorf("register consolidated tools: %w", err)
168+
}
165169
for _, hook := range optionalRegisterHooks {
166170
if hook == nil {
167171
continue
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package mcp
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"strings"
7+
"testing"
8+
)
9+
10+
// TestRegisterConsolidated_AllSixToolsLand verifies the six new tool names
11+
// appear in the server registry after RegisterConsolidated runs.
12+
func TestRegisterConsolidated_AllSixToolsLand(t *testing.T) {
13+
srv, err := NewServer(ServerOptions{Name: "test", Version: "0.0.0"})
14+
if err != nil {
15+
t.Fatal(err)
16+
}
17+
if err := RegisterConsolidated(srv, &Deps{}); err != nil {
18+
t.Fatalf("RegisterConsolidated: %v", err)
19+
}
20+
names := srv.Registry().Names()
21+
want := []string{
22+
"graph_summary",
23+
"find_in_graph",
24+
"inspect_node",
25+
"trace_relationships",
26+
"analyze_impact",
27+
"topology_view",
28+
}
29+
for _, w := range want {
30+
found := false
31+
for _, n := range names {
32+
if n == w {
33+
found = true
34+
break
35+
}
36+
}
37+
if !found {
38+
t.Errorf("missing tool %q in registry; got %v", w, names)
39+
}
40+
}
41+
}
42+
43+
// TestConsolidatedTool_UnknownModeRejected — each consolidated tool returns
44+
// a CodeInvalidInput envelope when the mode is unrecognized.
45+
func TestConsolidatedTool_UnknownModeRejected(t *testing.T) {
46+
d := &Deps{}
47+
for _, build := range []func(*Deps) Tool{
48+
toolGraphSummary, toolFindInGraph, toolInspectNode,
49+
toolTraceRelationships, toolAnalyzeImpact, toolTopologyView,
50+
} {
51+
tool := build(d)
52+
params, _ := json.Marshal(map[string]string{"mode": "bogus"})
53+
got, _ := tool.Handler(context.Background(), params)
54+
gotJSON, _ := json.Marshal(got)
55+
if !strings.Contains(string(gotJSON), "INVALID_INPUT") {
56+
t.Errorf("%s with bogus mode: expected INVALID_INPUT envelope, got %s", tool.Name, gotJSON)
57+
}
58+
}
59+
}
60+
61+
// TestGraphSummary_DefaultModeIsOverview — mode unset routes to get_stats.
62+
func TestGraphSummary_DefaultModeIsOverview(t *testing.T) {
63+
d := &Deps{}
64+
tool := toolGraphSummary(d)
65+
got, _ := tool.Handler(context.Background(), json.RawMessage(`{}`))
66+
gotJSON, _ := json.Marshal(got)
67+
// With no Stats wired, overview falls into the "stats service not wired"
68+
// envelope. Any other path would have been routed to capabilities or
69+
// provenance with a different envelope wording.
70+
if !strings.Contains(string(gotJSON), "stats service not wired") {
71+
t.Errorf("default mode did not route to overview: %s", gotJSON)
72+
}
73+
}

0 commit comments

Comments
 (0)