You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When Probe is used as an MCP server for Claude Code, Cursor, Windsurf, or other AI editors, it cannot answer:
"Who calls this function?" (call graph)
"What does this function depend on?" (dependencies)
"What implements this trait/interface?" (implementations)
"What's the structure of this repo?" (map)
"What would break if I change this?" (impact analysis)
PR #103 adds the LSP daemon with call hierarchy, references, and implementations persisted in SQLite. This investment should be exposed through MCP.
Current State
File:npm/src/mcp/index.ts
ProbeServer wraps @modelcontextprotocol/sdkServer
Transport: StdioServerTransport
Each tool calls the probe Rust binary via child process
Current tools (3):
Tool
Description
search_code
Semantic code search with ElasticSearch queries
extract_code
Extract code blocks using tree-sitter AST
grep
Standard grep-style search
Proposed New Tools (6)
Tool 1: map_code -- Repository Structure Overview
Depends on:#501 (probe map command) LSP required: No
{name: "map_code",description: "Get a structural overview of a codebase showing directory tree and symbol signatures. Use this FIRST when exploring an unfamiliar project to understand its architecture before searching for specific code.",inputSchema: {type: "object",properties: {path: {type: "string",description: "Root directory to map (absolute or relative path)"},depth: {type: "number",description: "Maximum directory depth to traverse. Default: unlimited. Use 1-2 for large repos."},detail: {type: "string",enum: ["files","signatures","full"],description: "Level of detail. 'files': filenames + line counts. 'signatures': + function/class/struct signatures (default). 'full': + first doc comment line.",default: "signatures"},language: {type: "string",description: "Filter to specific language: rust, typescript, python, go, java, etc."},maxTokens: {type: "number",description: "Maximum output tokens. Output truncated gracefully within budget.",default: 4000}},required: ["path"]}}
Depends on: PR #103 (LSP daemon) LSP required: Yes (graceful fallback to text search)
{name: "find_callers",description: "Find all functions that call a given function/method. Requires the LSP daemon to be running. Returns caller function signatures with file locations.",inputSchema: {type: "object",properties: {file: {type: "string",description: "File containing the target function (absolute or relative path)"},line: {type: "number",description: "Line number of the function definition"},symbol: {type: "string",description: "Symbol name (alternative to file+line). Will be searched in the codebase."},depth: {type: "number",description: "How many levels of callers to traverse. 1 = direct callers only (default). 2+ = callers of callers.",default: 1},maxResults: {type: "number",description: "Maximum number of callers to return.",default: 20}},required: []}}
{name: "find_callees",description: "Find all functions/methods called by a given function. Requires the LSP daemon. Returns callee signatures with file locations.",inputSchema: {type: "object",properties: {file: {type: "string",description: "File containing the source function"},line: {type: "number",description: "Line number of the function definition"},symbol: {type: "string",description: "Symbol name (alternative to file+line)"},depth: {type: "number",description: "Levels of callees to traverse. 1 = direct (default).",default: 1},maxResults: {type: "number",description: "Maximum callees to return.",default: 30}},required: []}}
{name: "find_references",description: "Find all references (usages) of a symbol across the codebase. Requires the LSP daemon. More precise than text search -- only finds actual code references, not string matches in comments or docs.",inputSchema: {type: "object",properties: {file: {type: "string",description: "File containing the symbol definition"},line: {type: "number",description: "Line number of the symbol"},symbol: {type: "string",description: "Symbol name (alternative to file+line)"},includeDeclaration: {type: "boolean",description: "Include the declaration itself.",default: false},maxResults: {type: "number",default: 30}},required: []}}
Example response:
References to `SearchResult` (src/models.rs:35):
1. src/search/search_runner.rs:225 -- return type of perform_probe()
2. src/search/search_runner.rs:1621 -- return type of search_with_structured_patterns()
3. src/search/result_ranking.rs:12 -- parameter of rank_search_results()
4. src/search/block_merging.rs:8 -- parameter/return of merge_ranked_blocks()
5. src/search/search_output.rs:54 -- parameter of format_and_print_search_results()
6. src/extract/processor.rs:27 -- return type of process_file_for_extraction()
7. src/search/file_processing.rs:42 -- return type of process_file_with_results()
8. tests/cli_tests.rs:120 -- test assertion
[8 of 23 references shown]
Tool 5: find_implementations -- What Implements This Trait/Interface?
{name: "find_implementations",description: "Find all implementations of a trait, interface, or abstract class. Requires the LSP daemon. Works with Rust traits, TypeScript/Java interfaces, Go interfaces, Python abstract classes.",inputSchema: {type: "object",properties: {file: {type: "string",description: "File containing the trait/interface definition"},line: {type: "number",description: "Line number of the trait/interface"},symbol: {type: "string",description: "Symbol name (alternative to file+line)"},maxResults: {type: "number",default: 20}},required: []}}
Tool 6: impact_analysis -- What Would Break If I Change This?
Depends on: Tools 2-5 above LSP required: Yes
This is the highest-value compound tool.
{name: "impact_analysis",description: "Analyze the impact of changing a function, type, or method. Shows all code that directly depends on this symbol: callers, type references, trait implementations, and test coverage. Use this before refactoring to understand the blast radius.",inputSchema: {type: "object",properties: {file: {type: "string",description: "File containing the symbol"},line: {type: "number",description: "Line number of the symbol"},symbol: {type: "string",description: "Symbol name (alternative to file+line)"},depth: {type: "number",description: "Depth of transitive analysis. 1 = direct dependents (default).",default: 1},maxTokens: {type: "number",description: "Token budget for the response.",default: 4000}},required: []}}
Implementation: Compound tool that internally:
Calls find_callers (depth N) for call hierarchy
Calls find_references for all usages
Calls find_implementations if the symbol is a trait/interface
Categorizes results: Direct callers, Type references, Test coverage, Downstream dependents
Formats as a structured report within token budget
Example response:
Impact Analysis: struct `SearchResult` (src/models.rs:35)
## Direct Usage (18 locations in 12 files)
### Core Pipeline (would break search):
src/search/search_runner.rs:225 -- perform_probe() return type
src/search/search_runner.rs:1621 -- search_with_structured_patterns() return type
src/search/result_ranking.rs:12 -- rank_search_results() parameter
src/search/block_merging.rs:8 -- merge_ranked_blocks() parameter + return
src/search/search_output.rs:54 -- format_and_print_search_results() parameter
### Extract Pipeline (would break extract):
src/extract/processor.rs:27 -- process_file_for_extraction() return type
src/extract/processor.rs:884 -- extract_all_symbols_from_file() return type
### Serialization (would break JSON/XML output):
src/search/search_output.rs:120 -- JSON serialization
src/search/search_output.rs:180 -- XML serialization
## Test Coverage
tests/cli_tests.rs:120 -- test_basic_search
tests/cli_tests.rs:245 -- test_search_ranking
tests/integration_test.rs:55 -- test_end_to_end
## Summary
Files affected: 12
Functions affected: 18
Tests covering this symbol: 3
Risk: HIGH (core data structure used across search + extract pipelines)
Update ProbeAgent system prompt in npm/src/agent/ProbeAgent.js (~line 2420):
## Available Tools
### Exploration
- map_code: Get repo structure overview. Use FIRST on unfamiliar codebases.
- search_code: Keyword search with ElasticSearch syntax.
- extract_code: Read specific files or symbols.
### Code Intelligence (requires LSP daemon)
- find_callers: Who calls this function?
- find_callees: What does this function call?
- find_references: Where is this symbol used?
- find_implementations: What implements this trait/interface?
- impact_analysis: What would break if I change this?
### Workflow
When exploring a codebase:
1. map_code to understand structure
2. search_code to find relevant code
3. extract_code to read specific symbols
4. find_callers/find_callees to understand relationships
5. impact_analysis before making changes
Phase 4: Graceful Degradation
All LSP-backed tools must handle the daemon not running:
try{constresult=awaitexecuteProbe(['lsp','query',type,file,line]);return{content: [{type: 'text',text: result}]};}catch(error){if(error.message.includes('daemon not running')){return{content: [{type: 'text',text: `LSP daemon is not running. To enable code intelligence:\n`+` probe lsp start\n\n`+`Falling back to text-based search...\n\n`+awaitfallbackToSearch(symbol)}]};}throwerror;}
The fallback uses probe search with the symbol name as a best-effort alternative.
Tool Priority Ranking
Priority
Tool
Value
Effort
LSP Required
1
map_code
Very High -- every agent session starts with orientation
Medium
No
2
find_callers
High -- most common structural question
Low
Yes
3
find_references
High -- essential for refactoring
Low
Yes
4
find_callees
Medium -- useful for understanding code flow
Low
Yes
5
find_implementations
Medium -- essential for polymorphic code
Low
Yes
6
impact_analysis
Very High -- but depends on 2-5
Medium
Yes
Success Criteria
MCP server exposes 9 tools (3 existing + 6 new) instead of 3
map_code works instantly without LSP daemon (same zero-setup as probe search)
LSP tools gracefully degrade to text search when daemon is not running
All tools respect token budgets
Agent prompt guides LLM to use tools in the right order (map → search → extract → analyze)
Problem Statement
Probe's MCP server currently exposes only 3 tools (
search_code,extract_code,grep), while competitors expose significantly more:get_edges,shortest_path,explore,get_maptrace_callers,trace_callees,trace_graph,rpg_searchget_repo_structure,get_package_structure,get_file_structure,get_ast_nodewith dependency/reference dataWhen Probe is used as an MCP server for Claude Code, Cursor, Windsurf, or other AI editors, it cannot answer:
PR #103 adds the LSP daemon with call hierarchy, references, and implementations persisted in SQLite. This investment should be exposed through MCP.
Current State
File:
npm/src/mcp/index.tsProbeServerwraps@modelcontextprotocol/sdkServerStdioServerTransportprobeRust binary via child processCurrent tools (3):
search_codeextract_codegrepProposed New Tools (6)
Tool 1:
map_code-- Repository Structure OverviewExample call:
{ "path": "./src", "depth": 2, "detail": "signatures", "maxTokens": 3000 }Example response:
Tool 2:
find_callers-- Who Calls This Function?Example call:
{ "file": "src/search/search_runner.rs", "line": 225, "depth": 1 }Example response:
Tool 3:
find_callees-- What Does This Function Call?Example call:
{ "symbol": "perform_probe", "depth": 1 }Example response:
Tool 4:
find_references-- Where Is This Symbol Used?Example response:
Tool 5:
find_implementations-- What Implements This Trait/Interface?Example response:
Tool 6:
impact_analysis-- What Would Break If I Change This?Implementation: Compound tool that internally:
find_callers(depth N) for call hierarchyfind_referencesfor all usagesfind_implementationsif the symbol is a trait/interfaceExample response:
Implementation Plan
Phase 1:
map_code(No LSP dependency)probe mapcommand in Rust (see Feature:probe map-- Repository Structure Overview Command #501)map_codetool to MCP server innpm/src/mcp/index.tsprobe mapvia child processFiles to modify:
npm/src/mcp/index.ts-- addmap_codetool registration + handlerEstimated scope: ~60 lines TypeScript (after #501 is done)
Phase 2: LSP-Backed Tools (Depends on PR #103)
After PR #103 lands and the LSP daemon + IPC client are available:
Add a new Rust CLI subcommand:
probe lsp query <type> <file> <line>that:DaemonRequestcallers,callees,references,implementationsAdd 4 MCP tools that call
probe lsp query ...Add
impact_analysisas a compound MCP toolFiles to modify:
src/cli.rs-- addLspcommand withQuerysubcommandsrc/lsp_integration/query.rs-- new: CLI query handlersrc/lsp_integration/output.rs-- new: format LSP resultsnpm/src/mcp/index.ts-- add 5 new tool registrations + handlersEstimated scope: ~500 lines Rust, ~200 lines TypeScript
Phase 3: Agent Prompt Updates
Update ProbeAgent system prompt in
npm/src/agent/ProbeAgent.js(~line 2420):Phase 4: Graceful Degradation
All LSP-backed tools must handle the daemon not running:
The fallback uses
probe searchwith the symbol name as a best-effort alternative.Tool Priority Ranking
map_codefind_callersfind_referencesfind_calleesfind_implementationsimpact_analysisSuccess Criteria
map_codeworks instantly without LSP daemon (same zero-setup asprobe search)map_code<1s, LSP tools <2s,impact_analysis<5sCompetitive Context
This feature set was identified by comparing probe's MCP surface with:
get_edges,shortest_path,exploretrace_callers,trace_callees,trace_graphProbe's advantage: tools 2-6 leverage the LSP daemon investment from PR #103 with minimal additional code, and
map_coderequires zero setup.