mcp

package
v0.5.0 Latest Latest
Warning

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

Go to latest
Published: Aug 8, 2026 License: MIT Imports: 17 Imported by: 0

Documentation

Overview

Package mcp implements the codegraph stdio MCP server (D-08): a startup-time conditional tool registration surface. It imports only internal/query (the read-only engine + formatters) — never internal/graphstore's Pebble implementation directly — so the internal/graphstore/archtest boundary holds (D-08b). Every tool handler in tools.go delegates to the same internal/query.Engine methods and formatters the CLI uses, taking a fresh query.OpenAt snapshot per call (D-02/D-08b, RESEARCH Pitfall 2) — one engine, two front-ends, so MCP output shapes stay byte-identical to the CLI's without a second rendering path.

Phase 2 (SDK-01) migrated this package's backend from github.com/mark3labs/mcp-go to github.com/modelcontextprotocol/go-sdk — the official MCP org's SDK — behind the Server seam SDK-02 built.

Index

Constants

View Source
const ProtocolVersion = "2025-11-25"

ProtocolVersion is the MCP protocol revision this server declares.

This is the revision today's server actually negotiates. It is owned by this repository rather than read from an SDK, so a dependency bump can never move it silently (VRFY-02).

Mechanism honesty (Phase 2, corrected from Phase 1's prediction): this literal is an asserted compatibility pin, not the source of the negotiated value, and that remains true under github.com/modelcontextprotocol/go-sdk v1.7.0 too. The negotiated revision is decided by the unexported package-level negotiatedVersion function in the SDK's own mcp package (mcp/shared.go), whose version- value constants (latestProtocolVersion, protocolVersion20260728, etc.) are all unexported and therefore structurally unreferenceable from internal/mcp — Go's own visibility rules make it impossible, not merely discouraged. ServerOptions exposes no ProtocolVersion field among its 17 fields (it does expose Instructions and Capabilities); the sole reachable mechanism, AddReceivingMiddleware, only ever READS the SDK's own already- computed *InitializeResult after negotiation has happened (see server.go's session-line middleware) — it is not a setter. What this constant buys is the same alarm Phase 1 built: it currently equals the value go-sdk negotiates for this literal, so the moment a dependency bump moves that value, the wire oracle's spec anchor (test/wireoracle) turns red — the "a dependency bump must never move wire behavior silently" property REQUIREMENTS.md VRFY-02 asks for ("asserted against a repo-owned literal"). VRFY-02's stricter "reads from" phrasing is confirmed undeliverable against this SDK too (D-04, D-06) — not deferred again, but proven false by exhaustive source enumeration (02-RESEARCH.md Q1) rather than assumed. Do not mistake this pin for an injection point.

This file deliberately references no SDK identifier.

Variables

This section is empty.

Functions

func BuildServer

func BuildServer(hasIndex bool, allowlist map[string]bool, repoPath, startPath string, opts ...Option) *mcp.Server

BuildServer constructs the stdio MCP server with startup-time conditional tool registration (D-08a, Pattern 3): hasIndex gates whether ANY tool is registered at all (MCP-03 — zero tools when no .codegraph/ resolves, though MCP init still completes successfully), allowlist gates which of the 7 companion tools register beyond the always-visible codegraph_explore (MCP-01/02).

repoPath and startPath are DELIBERATELY DISTINCT (CR-01, the Phase-1 CR-02 recurrence this parameter split fixes): repoPath is the confinement root — the RESOLVED index root every handler's confineToRepoRoot check anchors against, rejecting any client-supplied "path" argument that resolves outside it (CR-02/tools.go's trust boundary) — while startPath is the CALLER'S actual starting directory (serve.go's `start`, before ResolveCodegraphDir's upward walk), the value every handler falls back to when the caller omits "path" and the value that must reach query.OpenAt for WorktreeMismatch to have anything to compare. Because repoPath is always startPath itself or an ANCESTOR of it (it is ResolveCodegraphDir(startPath)'s own return value), confining the default startPath to repoPath always succeeds structurally — only an explicit, client-supplied "path" redirecting elsewhere can ever be rejected.

opts is variadic (SDK-02/VRFY-03) specifically so every pre-existing positional call site (17 of them, all in tests, as of this change) keeps compiling unchanged — only NewStdioServer, this file's one production caller, passes WithSessionLog.

func ParseAllowlist

func ParseAllowlist(env string) (allowed map[string]bool, unknown []string)

ParseAllowlist splits the CODEGRAPH_MCP_TOOLS env value on commas, trims whitespace around each entry, and classifies each non-empty name against companionNames (D-08a/MCP-02). Recognized names are returned in allowed (allowed[name] == true); unrecognized names are returned in unknown, in the order they were seen, for the caller to warn about via WarnUnknownToolsTo — ParseAllowlist itself never writes output or aborts, so an unknown name can never fail startup (MCP-02: "unknown names ignored with a stderr warning").

func WarnUnknownToolsTo

func WarnUnknownToolsTo(w io.Writer, unknown []string)

WarnUnknownToolsTo writes one stderr-style warning line per unknown allowlist name to w. Diagnostics never go to stdout — stdout is reserved for the MCP JSON-RPC transport (T-03-07-Leak) — so callers must pass os.Stderr, never os.Stdout, in production.

Types

type CalleesArgs

type CalleesArgs struct {
	Limit  int    `json:"limit,omitempty" jsonschema:"Cap on results returned"`
	Path   string `json:"path,omitempty" jsonschema:"Repo path (default: server cwd)"`
	Symbol string `json:"symbol" jsonschema:"Symbol name"`
}

CalleesArgs is codegraph_callees' input schema (D-07). Fields declared alphabetically by JSON name (limit, path, symbol). Symbol carries no omitempty — it is the only required field.

type CallersArgs

type CallersArgs struct {
	Limit  int    `json:"limit,omitempty" jsonschema:"Cap on results returned"`
	Path   string `json:"path,omitempty" jsonschema:"Repo path (default: server cwd)"`
	Symbol string `json:"symbol" jsonschema:"Symbol name"`
}

CallersArgs is codegraph_callers' input schema (D-07). Fields declared alphabetically by JSON name (limit, path, symbol). Symbol carries no omitempty — it is the only required field.

type ExploreArgs

type ExploreArgs struct {
	MaxFiles int    `json:"max_files,omitempty" jsonschema:"Cap on distinct files returned (default 5)"`
	Path     string `json:"path,omitempty" jsonschema:"Repo path (default: server cwd)"`
	Query    string `json:"query" jsonschema:"Natural-language or symbol/file query"`
}

ExploreArgs is codegraph_explore's input schema (D-07), inferred by mcp.AddTool from these struct tags. Fields are declared in alphabetical order of their JSON name (max_files, path, query) so jsonschema-go's Go-struct-field-declaration-order property emission matches mark3labs' alphabetical order, minimizing plan 02-05's diff review surface. Query carries no omitempty — it is the only required field.

type FilesArgs

type FilesArgs struct {
	Depth   int    `json:"depth,omitempty" jsonschema:"Directory-nesting cap (0 = unlimited)"`
	Filter  string `json:"filter,omitempty" jsonschema:"Restrict to one language"`
	Format  string `json:"format,omitempty" jsonschema:"\"flat\" (default) or \"tree\""`
	Path    string `json:"path,omitempty" jsonschema:"Repo path (default: server cwd)"`
	Pattern string `json:"pattern,omitempty" jsonschema:"Shell glob narrowing the result set"`
}

FilesArgs is codegraph_files' input schema (D-07). Fields declared alphabetically by JSON name (depth, filter, format, path, pattern). No field is required.

type ImpactArgs

type ImpactArgs struct {
	Depth  int    `json:"depth,omitempty" jsonschema:"BFS depth (default 2, max 50)"`
	Path   string `json:"path,omitempty" jsonschema:"Repo path (default: server cwd)"`
	Symbol string `json:"symbol" jsonschema:"Symbol name"`
}

ImpactArgs is codegraph_impact's input schema (D-07). Fields declared alphabetically by JSON name (depth, path, symbol). Symbol carries no omitempty — it is the only required field.

type NodeArgs

type NodeArgs struct {
	File   string `json:"file,omitempty" jsonschema:"File path — disambiguates symbol, or selects file-mode when symbol is omitted"`
	Line   int    `` /* 141-byte string literal not displayed */
	Path   string `json:"path,omitempty" jsonschema:"Repo path (default: server cwd)"`
	Symbol string `json:"symbol,omitempty" jsonschema:"Symbol name to look up (omit for a file-mode read)"`
}

NodeArgs is codegraph_node's input schema (D-07). Fields declared alphabetically by JSON name (file, line, path, symbol). Symbol carries omitempty — node's file-mode read means symbol is optional, matching today's schema (never marked required).

type Option

type Option func(*buildConfig)

Option configures BuildServer via the functional-options pattern.

func WithSessionLog

func WithSessionLog(w io.Writer) Option

WithSessionLog sets the writer VRFY-03's always-on session line is written to. Passing a nil writer here is equivalent to omitting the option (no session line is emitted) — NewStdioServer is the seam that makes "always on" a construction guarantee rather than a convention; see its doc comment.

type SearchArgs

type SearchArgs struct {
	Kind  string `json:"kind,omitempty" jsonschema:"Restrict to one node kind"`
	Limit int    `json:"limit,omitempty" jsonschema:"Cap on results returned"`
	Path  string `json:"path,omitempty" jsonschema:"Repo path (default: server cwd)"`
	Query string `json:"query" jsonschema:"Search term"`
}

SearchArgs is codegraph_search's input schema (D-07). Fields declared alphabetically by JSON name (kind, limit, path, query). Query carries no omitempty — it is the only required field.

type Server

type Server interface {
	ServeStdio() error
}

Server is SDK-02's narrow seam: the entire surface internal/cli needs to bootstrap and run the stdio MCP server, with no SDK type anywhere in its signature. internal/cli/serve.go depends only on this interface (and NewStdioServer, below) — it never imports modelcontextprotocol/go-sdk/mcp.

func NewStdioServer

func NewStdioServer(hasIndex bool, allowlist map[string]bool, repoPath, startPath string, sessionLog io.Writer) Server

NewStdioServer is internal/cli/serve.go's sole entrypoint into this package (SDK-02): it builds the server via BuildServer and returns it as the SDK-agnostic Server interface.

sessionLog must not be nil, and NewStdioServer panics if it is. VRFY-03's always-on negotiated-version stderr line is the milestone's only mitigation for a spec-sanctioned silent version mismatch (Legacy mark3labs servers silently coerce an unrecognized protocolVersion rather than rejecting it) — so silently disabling that line by passing a nil writer through some future call site must be structurally impossible, not merely unlikely. Callers that genuinely want the line suppressed (there is no such production caller today) must pass io.Discard explicitly — a deliberate, greppable opt-out, never a nil default.

type StatusArgs

type StatusArgs struct {
	Path string `json:"path,omitempty" jsonschema:"Repo path (default: server cwd)"`
}

StatusArgs is codegraph_status's input schema (D-07). No field is required.

Jump to

Keyboard shortcuts

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