Skip to content
Conduit

mcp server

go-llm-lens

An MCP server that enables LLMs to navigate and understand Go codebases through full type-checked AST analysis. It exposes structured tools — find symbols, inspect types, list packages, discover inter

tender-barbarian/go-llm-lenscommunitylistedunreviewed

Set up

Runs on your computer. Pick your agent and operating system.

This project does not publish an install method we can turn into a config. Follow the README instead.

README

synced Oct 26, 2026

Go LLM Lens

CI Release OpenSSF Scorecard OpenSSF Baseline Go Report Card

An MCP (Model Context Protocol) server that enables LLMs like Claude to navigate and understand Go codebases through full type-checked AST analysis.

Instead of reading raw source files line by line, an LLM can call structured tools to explore packages, find symbols, inspect function signatures and type definitions, and discover interface implementations.

The main goal is to save tokens on constant re-learning of the codebase.

How it works

The indexer uses golang.org/x/tools/go/packages to perform full type-checked loading of the entire codebase at startup, then builds an in-memory index of all packages, functions, types, variables, and constants. The index is queried by MCP tools without re-parsing source files.

Where it saves tokens:

  • Instead of reading entire files to find a function, get_function returns just that function's source
  • Instead of grepping + reading multiple files to understand a type, get_type returns the definition directly
  • find_implementations replaces multi-step grep → read → parse workflows
  • Structured results are more compact than raw file content with line numbers

Where it doesn't help much:

  • Simple lookups in small files — Read on a known file is comparable
  • Tasks that require understanding surrounding context (comments, neighboring functions)
  • The tool call itself + its response still consume tokens, so very tiny queries have overhead

The bigger win is probably fewer round trips — less searching in the dark, fewer "read this file, now read that file" chains. That means less context accumulation overall, which is where token costs really compound.

Benchmarks

go-llm-lens vs Glob/Grep — Token Usage Benchmark

  • Task: Describe the sample codebase (github.com/tender-barbarian/gniot)
  • Model: claude-opus-4-6
  • Runs: 3
  • Date: 2026-02-23

Results

MetricGlob/Grepgo-llm-lens
Effective tokens (mean ± sd) *42,900 ± 3,97633,356 ± 965
Cost USD (mean ± sd)$0.2545 ± $0.0208$0.1967 ± $0.0028

* input + output + cache_read × 0.1 + cache_creation × 1.25 (reflects Opus 4.6 billing weights)

Verdict

go-llm-lens used ~22% fewer effective tokens and cost ~23% less (~$0.06/run saved) in a cold session.

The consistency gap is equally striking: lens has a coefficient of variation of ~3% vs ~9% for Glob/Grep. The structured tool approach takes a predictable path — a handful of targeted calls, compact structured results, done. Glob/Grep lets the model improvise a search strategy each time, so costs swing with how many files it decides to read.

Notes

  • Results may vary by task type; simple symbol lookups on small codebases are where Grep is most competitive and can match go-llm-lens
  • The advantage of go-llm-lens compounds on larger codebases and multi-step exploration tasks where Glob/Grep requires reading many files to build context

Running your own benchmark

tests/benchmark/compare-tokens.sh runs two back-to-back claude -p sessions — one constrained to Glob/Grep and one to go-llm-lens — on the same task, then prints a side-by-side token and cost comparison.

# Single comparison, keep raw JSON output:
./tests/benchmark/compare-tokens.sh --target ~/projects/mylib --keep "describe the codebase structure"

# Run 3 times each, report mean ± stddev:
./tests/benchmark/compare-tokens.sh --target ~/projects/mylib --runs 3 "describe the codebase structure"
FlagDefaultDescription
--modelclaude-opus-4-6Model to use for both sessions
--runs/-n1Number of runs per method; reports mean ± stddev when > 1
--target/-t.Go project directory to benchmark against
--keep/-koffKeep raw JSON output files instead of deleting them

Requirements: claude CLI in PATH, jq, and go-llm-lens configured as an MCP server in the current project.

Security

Seems like since the introduction of AI-assisted coding security became an afterthought. A lot of people are rightfully afraid of introducing AI slop into their workflows. As such I took special care to use proper security measures in this project.

go-llm-lens is designed to be safe to run alongside an AI assistant:

  • Read-only. The server never writes files, executes shell commands, or makes network calls. Every operation is a read against the in-memory index.

  • No network surface. Transport is stdio only. There is no HTTP server and no open port.

  • Scoped to --root. The indexer only processes source files that physically reside under the directory you specify. Files outside that tree are never read.

  • Minimal token footprint. Tools return structured JSON containing only the fields the LLM needs — signatures, types, locations, doc comments — rather than raw source files. Unexported symbols and function bodies are omitted by default (include_unexported / include_bodies opt in). This keeps context window usage predictable and small regardless of codebase size.

  • Input length limits. String arguments to codebase-query tools are capped at 2 048 bytes before any handler logic runs, preventing resource exhaustion from oversized inputs.

  • Dependency vulnerability scanning. CI runs govulncheck on every push to catch known CVEs in dependencies.

  • Security linting. gosec is enabled in the golangci-lint configuration.

  • Pinned CI actions. Every GitHub Actions step is pinned to an immutable commit SHA to prevent supply-chain attacks via mutable tags.

  • Signed and attested releases. All release artifacts are signed with Sigstore keyless signing and include SLSA provenance attestations. Verify a download:

    # Verify signature
    cosign verify-blob \
      --certificate-identity-regexp='github.com/tender-barbarian/go-llm-lens' \
      --certificate-oidc-issuer='https://token.actions.githubusercontent.com' \
      --bundle checksums.txt.bundle \
      checksums.txt
    
    # Verify SLSA provenance
    gh attestation verify checksums.txt \
      --repo tender-barbarian/go-llm-lens
    

Limitations

  • Codebase must build. Full type checking requires the code to compile. Broken packages are skipped with a warning.
  • Dependencies must be available. Run go mod download in the target codebase before starting the server.
  • Index is built at startup. Changes to the codebase require restarting the server.
  • One codebase per server instance. Use multiple server instances for multiple codebases.
  • Standard library not indexed. Only packages under the module root (./...) are indexed.

Prerequisites

  • Go 1.25+
  • The target codebase must compile cleanly (go build ./... passes)
  • Dependencies must be downloaded (go mod download has been run)

Installation

Download a pre-built binary from the latest release for your platform (Linux, macOS, Windows — amd64 and arm64).

Or install with Go:

go install github.com/tender-barbarian/go-llm-lens/cmd/server@latest

Or build from source:

git clone https://github.com/tender-barbarian/go-llm-lens
cd go-llm-lens
go build -o go-llm-lens ./cmd/server

Usage

go-llm-lens --root /path/to/your/go/repo

The server communicates over stdio using the MCP protocol.

Flags

FlagDefaultDescription
--root.Root directory of the Go codebase to index

LLM Integration

go-llm-lens is an MCP server so it can work with any AI coding tool, but it was developed and tested with Claude Code, so here's how to set it up.

Add to Claude Code

claude mcp add --scope user --transport stdio go-llm-lens -- /path/to/go-llm-lens

Encourage Claude to use it

Claude won't prefer these tools over Glob/Grep/Read by default. Add the following to your CLAUDE.md (global ~/.claude/CLAUDE.md or project-level):

## Codebase exploration
**ALWAYS use `go-llm-lens` MCP tools for Go symbol lookup. NEVER use Glob/Grep/Read to explore Go code structure.**

- `list_packages` — list all indexed packages
- `get_package_symbols` — browse all symbols in a package
- `get_file_symbols` — list symbols defined in a specific file
- `find_symbol` — locate any function/type/var/const by name (supports prefix/contains match)
- `get_function` — read full function/method definition including body
- `get_type` — read full struct or interface definition
- `find_implementations` — find all concrete types implementing an interface

Only fall back to Glob/Grep/Read for non-Go files or when the MCP server is unavailable.

MCP Tools

All tools return JSON-encoded results.

list_packages

Lists all indexed packages with summary statistics.

FieldTypeRequiredDescription
filterstringnoOptional prefix filter on import path

Output: Array of { import_path, name, dir, file_count, func_count, type_count }

get_package_symbols

Returns all symbols in a package: functions, types, variables, and constants.

FieldTypeRequiredDescription
packagestringyesPackage import path
include_unexportedboolnoInclude unexported symbols (default: false)
include_bodiesboolnoInclude function bodies (default: false)

Output: { funcs: [...], types: [...], vars: [...] } each with signature and doc comment.

find_symbol

Searches for a symbol by name across the entire indexed codebase.

FieldTypeRequiredDescription
namestringyesSymbol name to search for
kindstringnoFilter by kind: func, method, type, var, const (empty = all)
matchstringnoMatch mode: exact (default), prefix, or contains

Output: Array of matches with package, kind, signature, receiver (for methods), and location.

get_function

Returns full details for a specific function or method.

FieldTypeRequiredDescription
packagestringyesPackage import path
namestringyesFunction name, or TypeName.MethodName for methods

Output: Full signature, parameter names and types, return types, doc comment, implementation body, is_promoted (true for methods promoted from embedded types), file and line.

get_type

Returns full definition of a type (struct or interface).

FieldTypeRequiredDescription
packagestringyesPackage import path
namestringyesType name

Output:

  • For structs: fields with types, struct tags, and comments; all methods (with is_promoted flag for methods from embedded types); embedded types
  • For interfaces: method signatures with parameter and return types; embedded interfaces
  • Doc comment, file and line

get_file_symbols

Returns all symbols defined in a specific file.

FieldTypeRequiredDescription
filestringyesFile path (absolute or relative)
include_unexportedboolnoInclude unexported symbols (default: false)
include_bodiesboolnoInclude function bodies (default: false)

Output: { funcs: [...], types: [...], vars: [...] } scoped to the given file.

find_implementations

Finds all concrete types in the indexed codebase that implement a given interface.

FieldTypeRequiredDescription
packagestringyesPackage import path of the interface
interfacestringyesInterface type name

Output: Array of { name, package, location, implements_via } where implements_via is "value" or "pointer".

Uses types.Implements from go/types for precise, type-system-accurate results.

License

See LICENSE.

↑↓ navigate openesc close