---
name: delphi-code-navigation
description: Use when the user wants to read, understand, navigate, or refactor Delphi/Pascal source — anything involving "find this method", "where is X declared", "what does this do", "find all callers", "show me the symbols in this unit", "is there an error in this file", or any code-comprehension task on .pas / .dpr / .dpk / .dproj files. Covers when to reach for the lsp_* tools (semantic, fast, accurate) vs grep/Read (when LSP is unavailable or for whole-file content), and the project-resolution model that decides which DelphiLSP child answers the call.
---

# Delphi code navigation with the lsp_* tools

The plugin embeds Embarcadero's DelphiLSP and exposes its standard
LSP methods as MCP tools. **Prefer these over grep for any
semantic question** about Delphi source — they understand
inheritance, generics, interface vs implementation sections, unit
namespaces, and `uses` clauses; grep does not.

## When to use which tool

| Question | Tool |
|---|---|
| "Where is `TFoo.Bar` defined / what does it do?" | `lsp_definition` (jumps to body in Delphi); `lsp_declaration` (jumps to interface-section signature); `lsp_implementation` (jumps from interface decl → body). |
| "What is this — type, signature, doc?" | `lsp_hover`. Returns markdown with type info, XMLDoc when present. |
| "Find all callers / users of `X`." | `lsp_references` when available (D13.1+). On D12 the tool isn't exposed; fall back to: `lsp_workspace_symbol` + grep on the matched files. |
| "What's in this file — classes, methods, fields?" | `lsp_document_symbols`. Hierarchical outline with line/column ranges. |
| "Find any class/method/symbol named `X` across the project." | `lsp_workspace_symbol`. Returns either exact (`precision: "exact"`) or aggregated-from-documentSymbol (`precision: "approximate"`) results. |
| "Are there any errors in this file?" | `lsp_diagnostics` with `file=<path>` and `wait_ms=2000`. Returns cached `publishDiagnostics` events. |
| "Complete this expression" or "what methods does this object have?" | `lsp_completion`. Pass a position right after a `.`/`(`/`<`/`[`. |
| "What parameters does this call take?" | `lsp_signature_help`. Pass a position inside the parentheses of a call. |

**Don't use grep** for those. grep gives you false positives on
identifiers in comments, strings, related-but-different methods,
and unrelated unit aliases. Use grep only when LSP can't answer
(license error, file not in any project, or a string-literal /
comment search where you actually want raw text matching).

## Coordinate convention

All `lsp_*` tools take **1-based** `line` and `column`. They
convert to LSP's 0-based on the wire. If you copy a position from
a stack trace or compiler error (which are also 1-based), pass
straight through without subtraction.

## Project resolution

Each `lsp_*` call resolves its target project in priority order:

1. **Explicit `project` arg** — pass a `.delphilsp.json` or
   `.dproj` path when you know which project the file belongs to.
2. **File walk-up** — when you pass `file=...`, the bridge walks
   up the file's directory tree looking for a sibling
   `.delphilsp.json` or `.dproj`. Most calls don't need an
   explicit project because of this.
3. **Current default** — set by `lsp_open_project` once per
   session, or by `lsp_default_project` in plugin config.

If none of these resolves, you'll get a structured error telling
you to call `lsp_open_project` first.

`lsp_open_project` returns `{project, capabilities, project_files,
active}` — useful as a sanity check that the bridge spawned a
DelphiLSP child and parsed its capabilities correctly.

## Project config — autogen vs IDE-generated

DelphiLSP needs a `.delphilsp.json` to do anything useful. There
are two ways to get one:

- **Autogen (default).** Point the bridge at any `.dproj`. The
  first time a project is touched, the bridge auto-generates the
  JSON next to the dproj. No IDE step required.
- **IDE-generated.** In RAD Studio, tick *Tools > Options > Code
  Insight > Generate LSP Config*, close + reopen the project. The
  resulting `.delphilsp.json` lands next to the dproj. The bridge
  prefers a fresh existing sibling JSON over autogen.

If autogen produces wrong answers (rare; the dccOptions assembly
covers ~80% of the IDE's MSBuild expansion), have the user run
the IDE step once and the bridge will pick up the IDE's
authoritative output.

## When LSP isn't available

- **License error** — DelphiLSP's license check requires an
  interactive desktop session. If the user runs rdbg-mcp from
  SSH or a service, every LSP call returns
  *"DelphiLSP license check failed..."* with an actionable
  message. Suggest they run from RDP/local desktop. Fall back to
  grep + `Read` for navigation in this case.
- **No DelphiLSP installed** — the bridge couldn't find
  DelphiLSP.exe. Suggest installing RAD Studio Community Edition
  (free) or pointing `delphilsp_path` at an existing install.
  Fall back to grep + `Read`.
- **No `.delphilsp.json` and no `.dproj`** — the user's pointing
  at loose `.pas` files outside any project. Suggest creating a
  minimal dproj or using grep for this file.

## Pairing with runtime debugging

The LSP and runtime-debug surfaces share one bridge process and
one Claude tool catalogue. Combine them:

- **Stack trace → source** — when you walk frames via
  `inspect_locals` or get `paused.source:line` from `events`,
  jump straight to the body with `lsp_definition` or get the
  signature with `lsp_hover`.
- **Trace through types** — when `inspect_object` shows a
  property of class `TFoo`, `lsp_definition` on `TFoo` jumps to
  its declaration and `lsp_document_symbols` on its unit lists
  every member.
- **Confirm a hypothesis** — *"is this AV in handler X or its
  caller Y?"* — use `lsp_references` (or workspace_symbol +
  grep) to enumerate callers, then break in each and confirm.

For Delphi-specific quirks (class helpers, generics, interface
sections), the LSP tools answer correctly where text-matching
gives wrong results. Lead with LSP, fall back only when needed.
