1+ // @index MCP context handlers that summarize graph state for downstream tool selection.
12package mcp
23
34import (
@@ -14,6 +15,42 @@ import (
1415 "github.com/tae2089/code-context-graph/internal/model"
1516)
1617
18+ // fileCount carries a single COUNT(DISTINCT file_path) scan result.
19+ // @intent capture the distinct-file count returned by the minimal-context summary query.
20+ type fileCount struct {
21+ Count int64
22+ }
23+
24+ // commCount holds aggregated membership counts per community.
25+ // @intent transport GROUP BY community_id results into MCP response shaping.
26+ type commCount struct {
27+ CommunityID uint
28+ Count int
29+ }
30+
31+ // commInfo is the summarized community payload shared by MCP responses.
32+ // @intent serialize minimal-context community summaries without introducing extra response fields.
33+ type minimalContextCommInfo struct {
34+ Label string `json:"label"`
35+ NodeCount int `json:"node_count"`
36+ }
37+
38+ // flowCount holds aggregated membership counts per flow.
39+ // @intent transport GROUP BY flow_id results into MCP response shaping.
40+ type flowCount struct {
41+ FlowID uint
42+ Count int
43+ }
44+
45+ // flowInfo is the summarized flow payload shared by MCP responses.
46+ // @intent serialize minimal-context flow summaries without introducing extra response fields.
47+ type minimalContextFlowInfo struct {
48+ Name string `json:"name"`
49+ NodeCount int `json:"node_count"`
50+ }
51+
52+ // getMinimalContext returns a compact project snapshot with risk hints and suggested tools.
53+ // @intent give agents a cheap first read of namespace state before they spend tokens on deeper graph queries.
1754func (h * handlers ) getMinimalContext (ctx context.Context , request mcp.CallToolRequest ) (* mcp.CallToolResult , error ) {
1855 ctx = h .applyWorkspace (ctx , request )
1956 log := h .logger ()
@@ -49,7 +86,6 @@ func (h *handlers) getMinimalContext(ctx context.Context, request mcp.CallToolRe
4986 return "" , trace .Wrap (err , "count edges" )
5087 }
5188
52- type fileCount struct { Count int64 }
5389 var fc fileCount
5490 fileQ := h .deps .DB .WithContext (ctx ).Model (& model.Node {}).Select ("COUNT(DISTINCT file_path) as count" ).Where ("namespace = ?" , ns )
5591 if err := fileQ .Scan (& fc ).Error ; err != nil {
@@ -110,11 +146,6 @@ func (h *handlers) getMinimalContext(ctx context.Context, request mcp.CallToolRe
110146 if keyEntities == nil {
111147 keyEntities = []string {}
112148 }
113-
114- type commCount struct {
115- CommunityID uint
116- Count int
117- }
118149 var ccRows []commCount
119150 commCountQ := h .deps .DB .WithContext (ctx ).
120151 Model (& model.CommunityMembership {}).
@@ -136,26 +167,16 @@ func (h *handlers) getMinimalContext(ctx context.Context, request mcp.CallToolRe
136167 if err := communityQ .Find (& communities ).Error ; err != nil {
137168 return "" , trace .Wrap (err , "find communities" )
138169 }
139-
140- type commInfo struct {
141- Label string `json:"label"`
142- NodeCount int `json:"node_count"`
143- }
144- commInfos := make ([]commInfo , len (communities ))
170+ commInfos := make ([]minimalContextCommInfo , len (communities ))
145171 for i , c := range communities {
146- commInfos [i ] = commInfo {Label : c .Label , NodeCount : ccMap [c .ID ]}
172+ commInfos [i ] = minimalContextCommInfo {Label : c .Label , NodeCount : ccMap [c .ID ]}
147173 }
148174 sort .Slice (commInfos , func (i , j int ) bool {
149175 return commInfos [i ].NodeCount > commInfos [j ].NodeCount
150176 })
151177 if len (commInfos ) > 3 {
152178 commInfos = commInfos [:3 ]
153179 }
154-
155- type flowCount struct {
156- FlowID uint
157- Count int
158- }
159180 var fcRows []flowCount
160181 flowCountQ := h .deps .DB .WithContext (ctx ).
161182 Model (& model.FlowMembership {}).
@@ -176,14 +197,9 @@ func (h *handlers) getMinimalContext(ctx context.Context, request mcp.CallToolRe
176197 if err := flowQ .Find (& flowList ).Error ; err != nil {
177198 return "" , trace .Wrap (err , "find flows" )
178199 }
179-
180- type flowInfo struct {
181- Name string `json:"name"`
182- NodeCount int `json:"node_count"`
183- }
184- flowInfos := make ([]flowInfo , len (flowList ))
200+ flowInfos := make ([]minimalContextFlowInfo , len (flowList ))
185201 for i , f := range flowList {
186- flowInfos [i ] = flowInfo {Name : f .Name , NodeCount : fcMap [f .ID ]}
202+ flowInfos [i ] = minimalContextFlowInfo {Name : f .Name , NodeCount : fcMap [f .ID ]}
187203 }
188204 sort .Slice (flowInfos , func (i , j int ) bool {
189205 return flowInfos [i ].NodeCount > flowInfos [j ].NodeCount
@@ -214,6 +230,8 @@ func (h *handlers) getMinimalContext(ctx context.Context, request mcp.CallToolRe
214230 }))
215231}
216232
233+ // suggestTools maps common task wording to the MCP tools most likely to help.
234+ // @intent steer callers toward high-signal graph operations without requiring them to know the full tool catalog.
217235func suggestTools (task string ) []string {
218236 lower := strings .ToLower (task )
219237
0 commit comments