elastic / elastic/semantic-code-search-mcp-server

Enhancement: Use indexed `symbols` field for more precise symbol analysis

Open
#32 0 comments 0 reactions 0 assignees View on GitHub
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.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.