elastic / elastic/semantic-code-search-mcp-server
Enhancement: Use indexed `symbols` field for more precise symbol analysis
- Dominant language
- TypeScript
- Stars
- 12
- Forks
- 7
- PR merge metrics
- No merged PRs in 30d
Description
## Summary
The `symbol_analysis` tool currently searches the `content` field as text and aggregates by the chunk's `kind`. It could instead query the indexed `symbols` nested field to provide more precise results—distinguishing between symbol definitions (`function.name`), call sites (`function.call`), and usages (`variable.usage`).
## Background
The `symbol_analysis` tool predates the `aggregateBySymbolsAndImports` function (added in commit `67585cd` for `map_symbols_by_query`). When the more precise nested symbols approach was developed, `symbol_analysis` was not retrofitted to use it.
## Current Behavior
```typescript
// src/mcp_server/tools/symbol_analysis.ts:104
const kql = `content: "${symbolName}"`;
```
The tool:
1. Searches chunks where `content` text contains the symbol name (full-text search)
2. Aggregates by `filePath`, then by chunk's `kind` field (lines 121-122)
3. Uses chunk's `startLine` for location (line 128)
```
┌─────────────────────────────────────────────────────────────────────┐
│ symbol_analysis({ symbolName: "MyFunction" }) │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ Query: content: "MyFunction" (full-text search) │
│ │
│ Aggregation: chunk.kind → function_declaration, call_expression │
│ │
│ Limitation: A chunk with kind=function_declaration that CALLS │
│ MyFunction will be categorized as "primaryDefinition" │
│ │
└─────────────────────────────────────────────────────────────────────┘
```
## Indexed Data Available
The indexer extracts symbols into a nested field with precise kinds:
```typescript
// ES mapping (from src/utils/elasticsearch.ts)
symbols: {
type: 'nested',
properties: {
name: { type: 'keyword' }, // exact symbol name
kind: { type: 'keyword' }, // how symbol is used
line: { type: 'integer' }, // exact line number
},
}
```
Symbol kinds extracted by the indexer:
- `function.name` → function definition
- `function.call` → function invocation
- `class.name` → class definition
- `class.instantiation` → `new` expression
- `method.name` → method definition
- `variable.name` → variable declaration
- `variable.usage` → variable reference
The MCP server already has `aggregateBySymbolsAndImports` (lines 182-294 in `src/utils/elasticsearch.ts`) which queries these nested fields — but `symbol_analysis` doesn't use it.
## Proposed Enhancement
Query the `symbols` nested field directly:
```
┌─────────────────────────────────────────────────────────────────────┐
│ symbol_analysis({ symbolName: "MyFunction" }) │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ Query: symbols.name: "MyFunction" (nested, exact match) │
│ │
│ Aggregation: symbols.kind → function.name, function.call │
│ │
│ Result: Precise categorization by HOW the symbol is used │
│ │
└─────────────────────────────────────────────────────────────────────┘
```
## Impact on Agents
| Aspect | Current (`content` + `chunk.kind`) | Proposed (`symbols.name` + `symbols.kind`) |
|--------|-------------------------------------|---------------------------------------------|
| Matching | Full-text (may match comments, strings) | Exact keyword match on parsed symbols |
| Classification | Chunk type (indirect) | Symbol usage type (direct) |
| Line numbers | Chunk's startLine/endLine | Symbol's exact line |
| False positives | Higher (text matching) | Lower (AST-extracted symbols) |
Agents currently receive imprecise categorization — a function that *calls* `MyFunction` inside a `function_declaration` chunk gets categorized as a "primaryDefinition" because the chunk type is `function_declaration`. With the proposed change, the agent would correctly see it categorized as an "executionCallSite" based on the `function.call` symbol kind.
## Implementation Sketch
Option 1: Refactor to use existing `aggregateBySymbolsAndImports` with a nested query filter.
Option 2: Add nested query directly:
```typescript
// Replace content query with nested symbols query
const query = {
nested: {
path: 'symbols',
query: {
term: { 'symbols.name': symbolName }
}
}
};
// Aggregate by symbols.kind instead of chunk.kind
aggs: {
files: {
terms: { field: 'filePath', size: 1000 },
aggs: {
symbol_kinds: {
nested: { path: 'symbols' },
aggs: {
filtered: {
filter: { term: { 'symbols.name': symbolName } },
aggs: {
by_kind: {
terms: { field: 'symbols.kind' },
aggs: {
lines: { terms: { field: 'symbols.line', size: 100 } }
}
}
}
}
}
}
}
}
}
```
### Report Category Mapping
Update categorization to use `symbols.kind` values:
| symbols.kind | Report Category |
|--------------|-----------------|
| `function.name`, `class.name`, `method.name` | primaryDefinitions |
| `type.name`, `interface.name` | typeDefinitions |
| `function.call`, `class.instantiation` | executionCallSites |
| `variable.usage` | usageReferences |
## Acceptance Criteria
- [ ] Query uses `symbols.name` nested field for exact symbol matching
- [ ] Results grouped by `symbols.kind` values
- [ ] Line numbers reflect exact symbol location from `symbols.line`
- [ ] Report categories updated to match symbol kind taxonomy
- [ ] Existing tests updated to reflect new aggregation structure
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.