mcp

package
v0.10.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 12, 2026 License: Apache-2.0 Imports: 20 Imported by: 0

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

View Source
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

type DominantFile struct {
	FilePath      string
	EdgeCount     int
	NextEdgeCount int
}

DominantFile is getDominantFile's result.

type FileInfo

type FileInfo struct {
	Path      string
	Language  model.Language
	NodeCount int
}

FileInfo describes one indexed file.

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 (m *MultiBackend) FindEdgesBetweenNodes(nodeIDs []string, kinds []model.EdgeKind) ([]model.Edge, error)

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) GetCode

func (m *MultiBackend) GetCode(nodeID string) (string, 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 (m *MultiBackend) GetIncomingEdges(nodeID string, kinds []model.EdgeKind) ([]model.Edge, error)

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 (m *MultiBackend) GetOutgoingEdges(nodeID string, kinds []model.EdgeKind) ([]model.Edge, error)

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

type NodeEdge struct {
	Node model.Node
	Edge model.Edge
}

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.

func (*Server) Serve

func (s *Server) Serve(ctx context.Context, r io.Reader, w io.Writer) error

Serve reads JSON-RPC messages from r and writes responses to w until r is exhausted or ctx is cancelled.

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 (b *StoreBackend) FindEdgesBetweenNodes(nodeIDs []string, kinds []model.EdgeKind) ([]model.Edge, error)

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 (b *StoreBackend) GetIncomingEdges(nodeID string, kinds []model.EdgeKind) ([]model.Edge, error)

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 (b *StoreBackend) GetOutgoingEdges(nodeID string, kinds []model.EdgeKind) ([]model.Edge, error)

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.

func NewSubgraph

func NewSubgraph() *Subgraph

NewSubgraph returns an empty subgraph.

func (*Subgraph) Delete

func (g *Subgraph) Delete(id string)

Delete removes a node (its order slot is skipped on iteration).

func (*Subgraph) Get

func (g *Subgraph) Get(id string) (model.Node, bool)

Get returns the node with id, if present.

func (*Subgraph) Has

func (g *Subgraph) Has(id string) bool

Has reports whether id is in the subgraph.

func (*Subgraph) IDs

func (g *Subgraph) IDs() []string

IDs returns node IDs in insertion order.

func (*Subgraph) Len

func (g *Subgraph) Len() int

Len returns the number of nodes.

func (*Subgraph) Set

func (g *Subgraph) Set(n model.Node)

Set inserts or updates a node, preserving first-insertion order.

func (*Subgraph) Values

func (g *Subgraph) Values() []model.Node

Values returns nodes in insertion order.

type TraversalOptions

type TraversalOptions struct {
	MaxDepth  int // <=0 means unlimited
	EdgeKinds []model.EdgeKind
	NodeKinds []model.NodeKind
	Direction string // "outgoing" | "incoming" | "both"
	Limit     int
}

TraversalOptions mirrors upstream TraversalOptions for traverseBFS.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL