Documentation
¶
Overview ¶
Package mcp implements the MCP (Model Context Protocol) server for codegrapher — a behavior-parity port of upstream codegraph's MCP surface (src/mcp/tools.ts + src/context/index.ts), served over stdio.
Index ¶
- Constants
- type DominantFile
- type FileInfo
- type FindOptions
- type GraphBackend
- type GraphStats
- type MultiBackend
- func (m *MultiBackend) FindEdgesBetweenNodes(nodeIDs []string, kinds []model.EdgeKind) ([]model.Edge, error)
- func (m *MultiBackend) FindNodesByExactName(names []string, kinds []model.NodeKind, limit int) ([]model.SearchResult, error)
- func (m *MultiBackend) FindNodesByNameSubstring(substring string, kinds []model.NodeKind, limit int, excludePrefix bool) ([]model.SearchResult, error)
- func (m *MultiBackend) GetCallees(nodeID string) ([]NodeEdge, error)
- func (m *MultiBackend) GetCallers(nodeID string) ([]NodeEdge, error)
- func (m *MultiBackend) GetChildren(nodeID string) ([]model.Node, error)
- func (m *MultiBackend) GetCode(nodeID string) (string, error)
- func (m *MultiBackend) GetDominantFile() (*DominantFile, error)
- func (m *MultiBackend) GetFileDependents(filePath string) ([]string, error)
- func (m *MultiBackend) GetFiles() ([]FileInfo, error)
- func (m *MultiBackend) GetImpactRadius(nodeID string, depth int) (*Subgraph, error)
- func (m *MultiBackend) GetIncomingEdges(nodeID string, kinds []model.EdgeKind) ([]model.Edge, error)
- func (m *MultiBackend) GetNodeByID(id string) (*model.Node, error)
- func (m *MultiBackend) GetNodesByName(name string) ([]model.Node, error)
- func (m *MultiBackend) GetNodesInFile(filePath string) ([]model.Node, error)
- func (m *MultiBackend) GetOutgoingEdges(nodeID string, kinds []model.EdgeKind) ([]model.Edge, error)
- func (m *MultiBackend) GetProjectNameTokens() map[string]struct{}
- func (m *MultiBackend) GetProjectRoot() string
- func (m *MultiBackend) GetStats() (GraphStats, error)
- func (m *MultiBackend) GetTypeHierarchy(nodeID string) (*Subgraph, error)
- func (m *MultiBackend) SearchNodes(query string, kinds []model.NodeKind, limit int) ([]model.SearchResult, error)
- func (m *MultiBackend) TraverseBFS(startID string, opts TraversalOptions) (*Subgraph, error)
- type NodeEdge
- type Server
- type StoreBackend
- func (b *StoreBackend) FindEdgesBetweenNodes(nodeIDs []string, kinds []model.EdgeKind) ([]model.Edge, error)
- func (b *StoreBackend) FindNodesByExactName(names []string, kinds []model.NodeKind, limit int) ([]model.SearchResult, error)
- func (b *StoreBackend) FindNodesByNameSubstring(substring string, kinds []model.NodeKind, limit int, excludePrefix bool) ([]model.SearchResult, error)
- func (b *StoreBackend) GetCallees(nodeID string) ([]NodeEdge, error)
- func (b *StoreBackend) GetCallers(nodeID string) ([]NodeEdge, error)
- func (b *StoreBackend) GetChildren(nodeID string) ([]model.Node, error)
- func (b *StoreBackend) GetCode(nodeID string) (string, error)
- func (b *StoreBackend) GetDominantFile() (*DominantFile, error)
- func (b *StoreBackend) GetFileDependents(filePath string) ([]string, error)
- func (b *StoreBackend) GetFiles() ([]FileInfo, error)
- func (b *StoreBackend) GetImpactRadius(nodeID string, depth int) (*Subgraph, error)
- func (b *StoreBackend) GetIncomingEdges(nodeID string, kinds []model.EdgeKind) ([]model.Edge, error)
- func (b *StoreBackend) GetNodeByID(id string) (*model.Node, error)
- func (b *StoreBackend) GetNodesByName(name string) ([]model.Node, error)
- func (b *StoreBackend) GetNodesInFile(filePath string) ([]model.Node, error)
- func (b *StoreBackend) GetOutgoingEdges(nodeID string, kinds []model.EdgeKind) ([]model.Edge, error)
- func (b *StoreBackend) GetProjectNameTokens() map[string]struct{}
- func (b *StoreBackend) GetProjectRoot() string
- func (b *StoreBackend) GetStats() (GraphStats, error)
- func (b *StoreBackend) GetTypeHierarchy(nodeID string) (*Subgraph, error)
- func (b *StoreBackend) SearchNodes(rawQuery string, kinds []model.NodeKind, limit int) ([]model.SearchResult, error)
- func (b *StoreBackend) TraverseBFS(startID string, opts TraversalOptions) (*Subgraph, error)
- type Subgraph
- type TraversalOptions
Constants ¶
const ServerInstructions = "" /* 6508-byte string literal not displayed */
ServerInstructions is the MCP server instructions block sent in the initialize response. Byte-for-byte the upstream text (captured in testdata/golden/*/mcp/initialize.json).
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type DominantFile ¶
DominantFile is getDominantFile's result.
type FindOptions ¶
type FindOptions struct {
SearchLimit int
TraversalDepth int
MaxNodes int
MinScore float64
EdgeKinds []model.EdgeKind
NodeKinds []model.NodeKind
}
FindOptions mirrors FindRelevantContextOptions in upstream types.
type GraphBackend ¶
type GraphBackend interface {
GetProjectRoot() string
GetStats() (GraphStats, error)
GetFiles() ([]FileInfo, error)
// SearchNodes runs the full multi-strategy search pipeline
// (QueryBuilder.searchNodes upstream → query.SearchNodes here).
SearchNodes(query string, kinds []model.NodeKind, limit int) ([]model.SearchResult, error)
GetNodesByName(name string) ([]model.Node, error)
GetNodeByID(id string) (*model.Node, error)
GetNodesInFile(filePath string) ([]model.Node, error)
GetFileDependents(filePath string) ([]string, error)
// GetCallers / GetCallees are depth-1 traversals over
// calls/references/imports edges, with the reaching edge attached.
GetCallers(nodeID string) ([]NodeEdge, error)
GetCallees(nodeID string) ([]NodeEdge, error)
// GetImpactRadius mirrors GraphTraverser.getImpactRadius: insertion-
// ordered blast radius including the start node.
GetImpactRadius(nodeID string, depth int) (*Subgraph, error)
// GetChildren returns contains-children of a container node.
GetChildren(nodeID string) ([]model.Node, error)
GetOutgoingEdges(nodeID string, kinds []model.EdgeKind) ([]model.Edge, error)
GetIncomingEdges(nodeID string, kinds []model.EdgeKind) ([]model.Edge, error)
// GetTypeHierarchy walks extends/implements ancestors + descendants.
GetTypeHierarchy(nodeID string) (*Subgraph, error)
// TraverseBFS mirrors GraphTraverser.traverseBFS.
TraverseBFS(startID string, opts TraversalOptions) (*Subgraph, error)
// FindNodesByExactName mirrors QueryBuilder.findNodesByExactName
// (case-insensitive exact name with co-location boosting).
FindNodesByExactName(names []string, kinds []model.NodeKind, limit int) ([]model.SearchResult, error)
// FindNodesByNameSubstring mirrors QueryBuilder.findNodesByNameSubstring
// (LIKE %sub%, ordered by name length).
FindNodesByNameSubstring(substring string, kinds []model.NodeKind, limit int, excludePrefix bool) ([]model.SearchResult, error)
// GetDominantFile mirrors QueryBuilder.getDominantFile.
GetDominantFile() (*DominantFile, error)
// FindEdgesBetweenNodes mirrors QueryBuilder.findEdgesBetweenNodes.
FindEdgesBetweenNodes(nodeIDs []string, kinds []model.EdgeKind) ([]model.Edge, error)
// GetProjectNameTokens mirrors CodeGraph.getProjectNameTokens.
GetProjectNameTokens() map[string]struct{}
// GetCode reads a node's source slice from disk (ContextBuilder.getCode).
// Returns "" (no error) when the node or file is unavailable.
GetCode(nodeID string) (string, error)
}
GraphBackend is the engine seam the tool handlers use — the subset of upstream's CodeGraph facade the MCP tools call. Implemented by StoreBackend.
type GraphStats ¶
type GraphStats struct {
FileCount int
NodeCount int
EdgeCount int
NodesByKind map[model.NodeKind]int
FilesByLanguage map[model.Language]int
DBSizeBytes int64
JournalMode string
}
GraphStats summarizes the index. Mirrors GraphStats in upstream types.
type MultiBackend ¶
type MultiBackend struct {
// contains filtered or unexported fields
}
MultiBackend implements GraphBackend by fanning out each operation across a slice of per-scope StoreBackends and merging the results. The data model is one SQLite DB per (language, version) scope; every live read is single-scope (no cross-DB JOINs), so whole-repo answers come from running each query per scope and merging in Go.
Merge strategy by method category:
- Search/list (SearchNodes, FindNodesByExactName, FindNodesByNameSubstring, GetNodesByName, GetFiles): run on each backend, concatenate, de-duplicate by stable node identity (node ID; file path for files), then re-apply the single-store sort/limit so the merged output matches single-store shape.
- Lookup-by-id (GetNodeByID, GetCode): return the first backend that resolves the id (node IDs are file-path-derived, so unique to one scope).
- Traversal rooted at an id (GetCallers, GetCallees, GetChildren, GetImpactRadius, GetTypeHierarchy, TraverseBFS, GetOutgoingEdges, GetIncomingEdges, GetNodesInFile, GetFileDependents, FindEdgesBetweenNodes): each scope is self-contained for its own nodes/edges, so non-owning scopes return empty and the owning scope's result is what surfaces. Subgraph methods return the owning scope's subgraph directly to preserve the insertion order the explore formatter depends on.
- status/stats (GetStats): sum counts and union the language/kind maps.
- GetDominantFile: the densest file across all scopes.
- GetProjectNameTokens / GetProjectRoot: scope-independent (derived from the shared project root); taken from the first backend.
For a single backend, every method delegates to behavior identical to today.
func NewMultiBackend ¶
func NewMultiBackend(stores []*store.Store, projectRoot string) *MultiBackend
func (*MultiBackend) FindEdgesBetweenNodes ¶
func (*MultiBackend) FindNodesByExactName ¶
func (m *MultiBackend) FindNodesByExactName(names []string, kinds []model.NodeKind, limit int) ([]model.SearchResult, error)
func (*MultiBackend) FindNodesByNameSubstring ¶
func (m *MultiBackend) FindNodesByNameSubstring(substring string, kinds []model.NodeKind, limit int, excludePrefix bool) ([]model.SearchResult, error)
func (*MultiBackend) GetCallees ¶
func (m *MultiBackend) GetCallees(nodeID string) ([]NodeEdge, error)
func (*MultiBackend) GetCallers ¶
func (m *MultiBackend) GetCallers(nodeID string) ([]NodeEdge, error)
func (*MultiBackend) GetChildren ¶
func (m *MultiBackend) GetChildren(nodeID string) ([]model.Node, error)
func (*MultiBackend) GetDominantFile ¶
func (m *MultiBackend) GetDominantFile() (*DominantFile, error)
func (*MultiBackend) GetFileDependents ¶
func (m *MultiBackend) GetFileDependents(filePath string) ([]string, error)
func (*MultiBackend) GetFiles ¶
func (m *MultiBackend) GetFiles() ([]FileInfo, error)
func (*MultiBackend) GetImpactRadius ¶
func (m *MultiBackend) GetImpactRadius(nodeID string, depth int) (*Subgraph, error)
func (*MultiBackend) GetIncomingEdges ¶
func (*MultiBackend) GetNodeByID ¶
func (m *MultiBackend) GetNodeByID(id string) (*model.Node, error)
func (*MultiBackend) GetNodesByName ¶
func (m *MultiBackend) GetNodesByName(name string) ([]model.Node, error)
func (*MultiBackend) GetNodesInFile ¶
func (m *MultiBackend) GetNodesInFile(filePath string) ([]model.Node, error)
func (*MultiBackend) GetOutgoingEdges ¶
func (*MultiBackend) GetProjectNameTokens ¶
func (m *MultiBackend) GetProjectNameTokens() map[string]struct{}
func (*MultiBackend) GetProjectRoot ¶
func (m *MultiBackend) GetProjectRoot() string
func (*MultiBackend) GetStats ¶
func (m *MultiBackend) GetStats() (GraphStats, error)
func (*MultiBackend) GetTypeHierarchy ¶
func (m *MultiBackend) GetTypeHierarchy(nodeID string) (*Subgraph, error)
func (*MultiBackend) SearchNodes ¶
func (m *MultiBackend) SearchNodes(query string, kinds []model.NodeKind, limit int) ([]model.SearchResult, error)
func (*MultiBackend) TraverseBFS ¶
func (m *MultiBackend) TraverseBFS(startID string, opts TraversalOptions) (*Subgraph, error)
type NodeEdge ¶
NodeEdge pairs a neighbor node with the edge that reached it — the shape upstream GraphTraverser.getCallers/getCallees return.
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
Server is the codegrapher MCP server: a minimal JSON-RPC 2.0 loop over newline-delimited JSON (the MCP stdio transport), implementing initialize, tools/list and tools/call. Hand-rolled rather than an SDK so the wire responses match the captured goldens field-for-field (SDKs add fields like `annotations` that the original server never emitted).
func NewServer ¶
func NewServer(backend GraphBackend) *Server
NewServer creates a new MCP server backed by backend.
type StoreBackend ¶
type StoreBackend struct {
// contains filtered or unexported fields
}
StoreBackend implements GraphBackend over a *store.Store, delegating the search pipeline to the query package (the same thin-adapter pattern as internal/cli/store_querier.go) and porting the upstream GraphTraverser methods the MCP tools need with their exact iteration order.
func NewStoreBackend ¶
func NewStoreBackend(st *store.Store, projectRoot string) *StoreBackend
NewStoreBackend creates a StoreBackend. projectRoot is the absolute path to the project root (the directory containing .codegraph/).
func (*StoreBackend) FindEdgesBetweenNodes ¶
func (*StoreBackend) FindNodesByExactName ¶
func (b *StoreBackend) FindNodesByExactName(names []string, kinds []model.NodeKind, limit int) ([]model.SearchResult, error)
FindNodesByExactName mirrors QueryBuilder.findNodesByExactName: a two-pass case-insensitive exact-name lookup with co-location boosting.
func (*StoreBackend) FindNodesByNameSubstring ¶
func (b *StoreBackend) FindNodesByNameSubstring(substring string, kinds []model.NodeKind, limit int, excludePrefix bool) ([]model.SearchResult, error)
FindNodesByNameSubstring mirrors QueryBuilder.findNodesByNameSubstring: plain `name LIKE %sub%` ordered by name length. Implemented with a raw read-only query through Store.Transaction (the store's public API exposes no equivalent; SearchLike scores and matches qualified names too).
func (*StoreBackend) GetCallees ¶
func (b *StoreBackend) GetCallees(nodeID string) ([]NodeEdge, error)
GetCallees mirrors GraphTraverser.getCallees (depth 1, with edges).
func (*StoreBackend) GetCallers ¶
func (b *StoreBackend) GetCallers(nodeID string) ([]NodeEdge, error)
GetCallers mirrors GraphTraverser.getCallers (depth 1, with edges).
func (*StoreBackend) GetChildren ¶
func (b *StoreBackend) GetChildren(nodeID string) ([]model.Node, error)
GetChildren mirrors GraphTraverser.getChildren: contains-children of nodeID.
func (*StoreBackend) GetCode ¶
func (b *StoreBackend) GetCode(nodeID string) (string, error)
GetCode mirrors ContextBuilder.getCode/extractNodeCode: the node's source lines [startLine, endLine] read from disk. Config-leaf nodes return their key only (#383). Returns "" when the node or file is unavailable.
func (*StoreBackend) GetDominantFile ¶
func (b *StoreBackend) GetDominantFile() (*DominantFile, error)
GetDominantFile mirrors QueryBuilder.getDominantFile: the file holding the densest concentration of in-file edges, excluding test/generated files.
func (*StoreBackend) GetFileDependents ¶
func (b *StoreBackend) GetFileDependents(filePath string) ([]string, error)
func (*StoreBackend) GetFiles ¶
func (b *StoreBackend) GetFiles() ([]FileInfo, error)
func (*StoreBackend) GetImpactRadius ¶
func (b *StoreBackend) GetImpactRadius(nodeID string, depth int) (*Subgraph, error)
GetImpactRadius is a faithful, insertion-ordered port of GraphTraverser.getImpactRadius: container nodes expand their children at the same depth; incoming edges of all kinds except `contains` are followed upward; no provenance filtering. The same semantics as query.Impact's traversal, kept here because the MCP formatter depends on JS Map insertion order, which the query package's sorted output discards.
func (*StoreBackend) GetIncomingEdges ¶
func (*StoreBackend) GetNodeByID ¶
func (b *StoreBackend) GetNodeByID(id string) (*model.Node, error)
func (*StoreBackend) GetNodesByName ¶
func (b *StoreBackend) GetNodesByName(name string) ([]model.Node, error)
func (*StoreBackend) GetNodesInFile ¶
func (b *StoreBackend) GetNodesInFile(filePath string) ([]model.Node, error)
func (*StoreBackend) GetOutgoingEdges ¶
func (*StoreBackend) GetProjectNameTokens ¶
func (b *StoreBackend) GetProjectNameTokens() map[string]struct{}
GetProjectNameTokens mirrors CodeGraph.getProjectNameTokens (memoized).
func (*StoreBackend) GetProjectRoot ¶
func (b *StoreBackend) GetProjectRoot() string
func (*StoreBackend) GetStats ¶
func (b *StoreBackend) GetStats() (GraphStats, error)
func (*StoreBackend) GetTypeHierarchy ¶
func (b *StoreBackend) GetTypeHierarchy(nodeID string) (*Subgraph, error)
GetTypeHierarchy mirrors GraphTraverser.getTypeHierarchy.
func (*StoreBackend) SearchNodes ¶
func (b *StoreBackend) SearchNodes(rawQuery string, kinds []model.NodeKind, limit int) ([]model.SearchResult, error)
SearchNodes delegates to the query package's full search pipeline (FTS5 → LIKE → fuzzy with exact-name supplement and multi-signal rescoring).
func (*StoreBackend) TraverseBFS ¶
func (b *StoreBackend) TraverseBFS(startID string, opts TraversalOptions) (*Subgraph, error)
TraverseBFS mirrors GraphTraverser.traverseBFS, including the structural- edge prioritisation (contains, then calls, then everything else).
type Subgraph ¶
type Subgraph struct {
Edges []model.Edge
Roots []string
// Confidence is "high" or "low" (findRelevantContext's honest-handoff
// signal). Unused by explore formatting but kept for fidelity.
Confidence string
// contains filtered or unexported fields
}
Subgraph is an insertion-ordered node set plus edges and roots, mirroring upstream's Subgraph { nodes: Map, edges, roots }. JS Map iteration order is insertion order, and the explore formatter depends on it, so the Go port tracks order explicitly.