agent-lsp Tool Reference¶
All 50 tools exposed by the agent-lsp MCP server. Coordinates are 1-based for
both line and column in every tool call; the server converts internally to
the 0-based values the LSP spec requires.
Table of Contents¶
- Session tools —
start_lsp,restart_lsp_server,open_document,close_document,add_workspace_folder,remove_workspace_folder,list_workspace_folders - Analysis tools —
get_diagnostics,get_info_on_location,get_completions,get_signature_help,get_code_actions,get_document_symbols,get_workspace_symbols,get_change_impact,get_cross_repo_references - Navigation tools —
get_references,go_to_definition,go_to_type_definition,go_to_implementation,go_to_declaration - Refactoring tools —
rename_symbol,prepare_rename,format_document,format_range,apply_edit,execute_command - Utilities —
did_change_watched_files,set_log_level - Code Intelligence tools —
call_hierarchy,type_hierarchy,get_inlay_hints,get_semantic_tokens,get_document_highlights - Build & Test tools —
run_build,run_tests,get_tests_for_file - Server Introspection tools —
get_server_capabilities,detect_lsp_servers - Simulation tools —
create_simulation_session,simulate_edit,evaluate_session,simulate_chain,commit_session,discard_session,destroy_session,simulate_edit_atomic - Startup and warm-up notes
- Symbol lookup tools —
go_to_symbol,get_symbol_source,get_symbol_documentation - Skills
Session tools¶
start_lsp¶
Initialize or reinitialize the LSP server with a specific project root. Call
this before any analysis when switching to a different project than the one the
server was started with. The server starts automatically on MCP launch with the
directory configured in mcp.json; this tool lets you point it at a different
workspace root at runtime.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
root_dir |
string | yes | Absolute path to the workspace root (directory containing package.json, go.mod, go.work, etc.) |
language_id |
string | no | In multi-server mode, selects a specific configured server (e.g. "go" targets gopls, "typescript" targets typescript-language-server). Without this, all configured servers are started. Use get_server_capabilities to diagnose which server is active. |
Example call
Actual output
Notes
- Shuts down the existing LSP process before starting the new one — no resource leak.
- After
start_lspreturns, the underlying language server is initialized but may not have finished indexing the workspace. Forget_referenceson large projects, the server waits for all$/progressend events before returning. - Call
open_documentafter this before running any per-file analysis.
restart_lsp_server¶
Restart the current LSP server process without changing the workspace root. Useful when the server becomes unresponsive or after major project-structure changes (adding a new module, moving files).
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
root_dir |
string | no | If provided, restarts with a new workspace root. Omit to restart with the same root. |
Example call
Actual output
Notes
- Requires the LSP client to already be initialized. Returns an error if
start_lsphas never been called. - All open documents are lost after restart; call
open_documentagain for any files you need.
open_document¶
Register a file with the language server for analysis. Most analysis tools
(get_info_on_location, get_completions, get_references, etc.) call this
internally via the withDocument helper, so you typically only need to call
it explicitly when you want to pre-warm a file or keep it open across multiple
operations.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
file_path |
string | yes | Absolute path to the file |
language_id |
string | no | Language identifier (typescript, javascript, go, python, rust, etc.). Defaults to "plaintext" when omitted; auto-detected from extension by most analysis tools. |
Example call
{
"file_path": "/home/user/projects/agent-lsp/test/ts-project/src/example.ts",
"language_id": "typescript"
}
Actual output
Notes
- Idempotent: opening an already-open file is safe; it re-sends
didOpenso the server refreshes its view of the file content. - The file must exist on disk; the tool reads its content before sending it to the language server.
- The server tracks
file_pathandlanguage_idinternally so it canreopenDocumentwhenget_diagnosticsis called.
close_document¶
Remove a file from the language server's open-document set. Sends
textDocument/didClose and frees the server's in-memory state for that file.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
file_path |
string | yes | Absolute path to the file to close |
Example call
Actual output
Notes
- Good practice in long sessions or large codebases to close files you are done analyzing.
get_diagnostics(nofile_path) only returns diagnostics for currently open files, so closing a file removes it from those results.
add_workspace_folder¶
Add a directory to the LSP workspace, enabling cross-repo references, definitions, and diagnostics. After adding a folder the language server re-indexes it — call sites and symbol definitions in both repos become visible to each other.
Useful pattern: start_lsp on a library repo, then add_workspace_folder for a
consumer repo. get_references on a library function then returns call sites in
both projects.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
path |
string | yes | Absolute path to the directory to add |
Example call
Actual output
{
"added": "/home/user/projects/my-app",
"workspace_folders": [
{ "uri": "file:///home/user/projects/my-library", "name": "/home/user/projects/my-library" },
{ "uri": "file:///home/user/projects/my-app", "name": "/home/user/projects/my-app" }
]
}
Notes
- Requires
start_lspto have been called first. - Supported by gopls, rust-analyzer, typescript-language-server. Servers that do not support multi-root workspaces silently ignore the notification.
- Idempotent — adding a folder that is already present is a no-op.
remove_workspace_folder¶
Remove a directory from the LSP workspace. The server stops indexing that folder.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
path |
string | yes | Absolute path to the directory to remove |
list_workspace_folders¶
Return the current list of workspace folders the server is indexing.
Parameters — none
Actual output
{
"workspace_folders": [
{ "uri": "file:///home/user/projects/my-library", "name": "/home/user/projects/my-library" }
]
}
Analysis tools¶
get_diagnostics¶
Fetch diagnostic messages (errors, warnings, hints) for one or all open files. The tool re-opens the file(s) from disk to ensure fresh content, waits for the language server to publish diagnostics, then returns them.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
file_path |
string | no | Absolute path to a specific file. Omit to get diagnostics for all open files. |
Example call — single file
Actual output — clean file
Actual output — all open files
{
"file:///home/user/projects/agent-lsp/test/ts-project/src/example.ts": [],
"file:///home/user/projects/agent-lsp/test/ts-project/src/consumer.ts": []
}
Output shape — file with errors
{
"file:///path/to/file.ts": [
{
"range": {
"start": { "line": 43, "character": 6 },
"end": { "line": 43, "character": 21 }
},
"severity": 1,
"code": 2304,
"source": "ts",
"message": "Cannot find name 'undefinedVariable'."
}
]
}
Severity codes: 1 = error, 2 = warning, 3 = information, 4 = hint.
Notes
- Output keys are
file://URIs, not file paths. - The tool waits for
textDocument/publishDiagnosticsnotifications before returning, so it may take a moment on first call. - Files must have been opened with
open_document(or any analysis tool) for their URIs to appear in the all-files result.
get_info_on_location¶
Retrieve hover information for a symbol at a specific position via
textDocument/hover. Returns type signatures, JSDoc/godoc comments, and other
contextual detail that the language server provides on hover.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
file_path |
string | yes | Absolute path to the file |
language_id |
string | yes | Language identifier |
line |
number | yes | Line number (1-based) |
column |
number | yes | Column position (1-based) |
Example call
{
"file_path": "/home/user/projects/agent-lsp/test/ts-project/src/example.ts",
"language_id": "typescript",
"line": 4,
"column": 17
}
Expected output — TypeScript function
Expected output — TypeScript class
Notes
- Returns an empty string when the server returns
null(e.g. whitespace, punctuation, or a position with no symbol). - The server must declare
hoverProvidercapability; if it does not, the tool returns an empty string immediately without sending a request. - For markdown-formatted hover content, the server returns
MarkupContent { kind: "markdown", value: "..." }and the tool returns thevaluefield. - The tool opens the file internally before requesting hover, so
open_documentis not required as a prerequisite.
get_completions¶
Request completion items at a cursor position via textDocument/completion.
Useful for discovering available properties on an object, functions exported
from a module, or valid identifiers in scope.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
file_path |
string | yes | Absolute path to the file |
language_id |
string | yes | Language identifier |
line |
number | yes | Line number (1-based) |
column |
number | yes | Column position (1-based), typically just after a . or at the start of a partial identifier |
Example call — after greeter.
{
"file_path": "/home/user/projects/agent-lsp/test/ts-project/src/consumer.ts",
"language_id": "typescript",
"line": 11,
"column": 9
}
Expected output (truncated)
[
{
"label": "greet",
"kind": 2,
"detail": "(method) Greeter.greet(person: Person): string",
"sortText": "0",
"insertText": "greet"
},
{
"label": "greeting",
"kind": 5,
"detail": "(property) Greeter.greeting: string",
"sortText": "1",
"insertText": "greeting"
}
]
Completion item kind values follow LSP §3.18: 1=Text, 2=Method,
3=Function, 4=Constructor, 5=Field, 6=Variable, 7=Class,
9=Module, etc.
Notes
- Returns
[]if the server does not declarecompletionProvidercapability. - The server may return a
CompletionListwithisIncomplete: truefor large result sets; the tool extracts theitemsarray in that case. - Place the column immediately after the trigger character (
.,:, space) for best results.
get_signature_help¶
Return function signature information when the cursor is inside an argument
list, via textDocument/signatureHelp. Shows available overloads and
highlights the active parameter.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
file_path |
string | yes | Absolute path to the file |
language_id |
string | yes | Language identifier |
line |
number | yes | Line of the call site (1-based) |
column |
number | yes | Column inside the argument list (1-based) |
Example call — cursor inside add(1, on line 4 of consumer.ts
{
"file_path": "/home/user/projects/agent-lsp/test/ts-project/src/consumer.ts",
"language_id": "typescript",
"line": 4,
"column": 16
}
Expected output
{
"signatures": [
{
"label": "add(a: number, b: number): number",
"documentation": {
"kind": "markdown",
"value": "A simple function that adds two numbers"
},
"parameters": [
{ "label": [4, 13] },
{ "label": [15, 23] }
]
}
],
"activeSignature": 0,
"activeParameter": 1
}
Notes
- Returns
"No signature help available at this location"as a string when the server returnsnull. - Returns
[]if the server does not declaresignatureHelpProvider. activeParameteris 0-based and indicates which parameter the cursor is on.
get_code_actions¶
Retrieve code actions (quick fixes, refactorings) available for a text range,
via textDocument/codeAction. The server receives the range and any
diagnostics that overlap it, then returns a list of applicable actions.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
file_path |
string | yes | Absolute path to the file |
language_id |
string | yes | Language identifier |
start_line |
number | yes | Start line of the selection (1-based) |
start_column |
number | yes | Start column (1-based) |
end_line |
number | yes | End line (1-based) |
end_column |
number | yes | End column (1-based) |
The range start must not be after the range end (validated by the schema).
Example call — selection over undefinedVariable on line 44
{
"file_path": "/home/user/projects/agent-lsp/test/ts-project/src/example.ts",
"language_id": "typescript",
"start_line": 44,
"start_column": 15,
"end_line": 44,
"end_column": 30
}
Expected output
[
{
"title": "Add missing import",
"kind": "quickfix",
"diagnostics": [ { "message": "Cannot find name 'undefinedVariable'.", "..." : "..." } ],
"edit": {
"changes": {
"file:///path/to/example.ts": [
{ "range": { "...": "..." }, "newText": "import { undefinedVariable } from './somewhere';\n" }
]
}
}
},
{
"title": "Declare 'undefinedVariable'",
"kind": "quickfix",
"command": {
"title": "Declare variable",
"command": "_typescript.applyRefactoring",
"arguments": [ "..." ]
}
}
]
Notes
- Returns
[]if the server does not declarecodeActionProvider. - The tool passes overlapping diagnostics automatically via
getOverlappingDiagnostics; you do not need to supply them manually. - Actions with an
editfield can be applied withapply_edit. Actions with acommandfield must be triggered withexecute_command.
get_document_symbols¶
List all symbols defined in a file (functions, classes, interfaces, variables,
methods, etc.) via textDocument/documentSymbol. Returns a hierarchical
DocumentSymbol tree when the server supports it, or a flat
SymbolInformation[] list otherwise.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
file_path |
string | yes | Absolute path to the file |
language_id |
string | yes | Language identifier |
format |
string | no | "json" (default) returns the full DocumentSymbol tree. "outline" returns a compact Markdown representation (name [Kind] :line, indented for children) — ~5x fewer tokens; useful for structural surveys before targeted navigation. |
Example call
{
"file_path": "/home/user/projects/agent-lsp/test/ts-project/src/example.ts",
"language_id": "typescript"
}
Expected output (hierarchical form)
[
{
"name": "add",
"kind": 12,
"range": {
"start": { "line": 3, "character": 0 },
"end": { "line": 5, "character": 1 }
},
"selectionRange": {
"start": { "line": 3, "character": 16 },
"end": { "line": 3, "character": 19 }
}
},
{
"name": "Person",
"kind": 11,
"range": { "start": { "line": 10, "character": 0 }, "end": { "line": 15, "character": 1 } },
"selectionRange": { "start": { "line": 10, "character": 17 }, "end": { "line": 10, "character": 23 } },
"children": [
{ "name": "name", "kind": 7, "...": "..." },
{ "name": "age", "kind": 7, "...": "..." },
{ "name": "email","kind": 7, "...": "..." }
]
},
{
"name": "Greeter",
"kind": 5,
"children": [
{ "name": "constructor", "kind": 9, "...": "..." },
{ "name": "greet", "kind": 6, "...": "..." }
]
}
]
Symbol kind values: 4=Constructor, 5=Class, 6=Method, 7=Property,
9=Enum, 11=Interface, 12=Function, 13=Variable, etc. (LSP §3.16.1).
Notes
- Returns
[]if the server does not declaredocumentSymbolProvider. - Coordinates in the output are 1-based — the tool shifts all
rangeandselectionRangevalues by +1 before returning, including in nestedchildren. Pass them directly to other tools without adjustment.
get_workspace_symbols¶
Search for symbols across the entire workspace via workspace/symbol. Provide
an empty query to enumerate all indexed symbols, or a substring to filter by
name. Optionally enrich results with hover documentation for a paginated window.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
query |
string | no | Search string. Use "" or omit to list all symbols. |
detail_level |
string | no | "basic" (default) returns name/kind/location only. "hover" returns the full structured response with hover-enriched enriched[] for the current pagination window. |
limit |
number | no | Number of symbols to enrich when detail_level=hover. Default 3. |
offset |
number | no | Pagination offset into results for enrichment. Default 0. |
Example call — basic
Expected output — basic
[
{
"name": "Greeter",
"kind": 5,
"location": {
"uri": "file:///home/user/projects/agent-lsp/test/ts-project/src/example.ts",
"range": {
"start": { "line": 19, "character": 0 },
"end": { "line": 32, "character": 1 }
}
}
}
]
Example call — hover enriched
Expected output — hover enriched
{
"total": 1,
"symbols": [
{
"name": "Greeter",
"kind": 5,
"location": {
"uri": "file:///path/to/example.ts",
"range": { "start": { "line": 19, "character": 0 }, "end": { "line": 32, "character": 1 } }
}
}
],
"enriched": [
{
"name": "Greeter",
"kind": 5,
"location": { "...": "..." },
"hover": "class Greeter"
}
],
"pagination": { "offset": 0, "limit": 2, "more": false }
}
Notes
- Returns
[]if the server does not declareworkspaceSymbolProvider. Some servers (e.g., tsserver) require at least one file to be open before workspace symbol search is available. - Unlike
get_document_symbols, this tool does not take afile_path— it queries the whole workspace index. - Result coordinates are 0-based (LSP native).
- With
detail_level=hover,symbols[]always contains the full result set. Useoffsetto page through theenriched[]window without re-running the workspace search.
get_change_impact¶
Enumerate all exported symbols in one or more files, resolve their references across the workspace, and partition callers into test vs non-test. Returns enclosing test function names for test references. Use before editing a file to understand blast radius.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
changed_files |
string[] | yes | Absolute paths to the files whose exported symbols should be analyzed |
include_transitive |
boolean | no | Set to true to also resolve references for each caller (second-order callers). Default: false |
Example call
Returns
{
"changed_symbols": [
{ "name": "LSPClient", "file": "internal/lsp/client.go", "line": 14 }
],
"test_files": [
"internal/lsp/client_test.go"
],
"test_functions": [
{ "name": "TestGetReferences", "file": "internal/lsp/client_test.go", "line": 42 }
],
"non_test_callers": [
{ "name": "LSPClient", "file": "internal/tools/analysis.go", "line": 67 }
],
"summary": "Found 1 changed symbols with 1 test references across 1 test files.",
"warnings": []
}
Notes
- Only exported symbols are analyzed (uppercase identifiers in Go; all public symbols in other languages).
changed_symbolslists each analyzed symbol with its file and 1-based line number.test_functionscontains the enclosing test function name for each test file reference.test_filesis the deduplicated set of test files that reference any changed symbol.non_test_callersis the blast radius for production code.warningscontains messages for anyGetReferencescalls that failed (non-fatal).
get_cross_repo_references¶
Find all references to a library symbol across one or more consumer
repositories. Adds each consumer root as a workspace folder, waits for
indexing, then calls get_references and partitions results by repo root.
Use before changing a shared library API to find all downstream callers.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
symbol_file |
string | yes | Absolute path to the file containing the symbol definition |
line |
integer | yes | 1-based line number of the symbol |
column |
integer | yes | 1-based column number of the symbol |
consumer_roots |
string[] | yes | Absolute paths to consumer repo roots to search |
language_id |
string | no | Language ID (e.g. "go"); default "plaintext" |
Example call
{
"symbol_file": "/repos/config-lib/pkg/config/parser.go",
"line": 42,
"column": 6,
"consumer_roots": ["/repos/api-service", "/repos/worker-service"]
}
Returns
{
"library_references": [
{ "file": "pkg/config/parser_test.go", "line": 18, "column": 3 }
],
"consumer_references": {
"/repos/api-service": [
{ "file": "/repos/api-service/main.go", "line": 14, "column": 9 }
],
"/repos/worker-service": [
{ "file": "/repos/worker-service/runner.go", "line": 8, "column": 5 }
]
},
"warnings": []
}
Notes
library_referencescovers references within the primary (library) workspace.consumer_referencesmaps each consumer root to its reference list.warningslists roots that could not be indexed; re-add manually if non-empty.- Requires
start_lspon the library root first.
Navigation tools¶
get_references¶
Find all locations where a symbol is referenced across the workspace, via
textDocument/references.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
file_path |
string | yes | File containing the symbol |
language_id |
string | yes | Language identifier |
line |
number | yes | Line of the symbol (1-based) |
column |
number | yes | Column of the symbol (1-based) |
include_declaration |
boolean | no | Include the symbol's own declaration. Default false. |
Example call
{
"file_path": "/home/user/projects/agent-lsp/test/ts-project/src/example.ts",
"language_id": "typescript",
"line": 4,
"column": 17,
"include_declaration": true
}
Actual output (empty — tsserver not fully indexed in this session)
Expected output — when workspace is indexed
[
{
"file": "/home/user/projects/agent-lsp/test/ts-project/src/example.ts",
"line": 4,
"column": 17,
"end_line": 4,
"end_column": 20
},
{
"file": "/home/user/projects/agent-lsp/test/ts-project/src/consumer.ts",
"line": 1,
"column": 10,
"end_line": 1,
"end_column": 13
},
{
"file": "/home/user/projects/agent-lsp/test/ts-project/src/consumer.ts",
"line": 4,
"column": 13,
"end_line": 4,
"end_column": 16
}
]
Output coordinates are 1-based (converted from LSP 0-based by the tool).
Notes
- Returns
[]if the workspace is still indexing. The tool waits for$/progressend events from gopls; tsserver does not emit these, so on first call you may need to retry after a short delay. include_declaration: trueadds the definition site to the results.- Each result includes
file(absolute path, not a URI), plusline,column,end_line,end_column(all 1-based).
go_to_definition¶
Jump to where a symbol is defined, via textDocument/definition.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
file_path |
string | yes | File containing the usage |
language_id |
string | yes | Language identifier |
line |
number | yes | Line of the symbol (1-based) |
column |
number | yes | Column (1-based) |
Example call — add usage in consumer.ts line 4
{
"file_path": "/home/user/projects/agent-lsp/test/ts-project/src/consumer.ts",
"language_id": "typescript",
"line": 4,
"column": 13
}
Expected output
[
{
"file": "/home/user/projects/agent-lsp/test/ts-project/src/example.ts",
"line": 4,
"column": 17,
"end_line": 4,
"end_column": 20
}
]
Notes
- Returns
[]if the server does not declaredefinitionProvider. - The tool normalizes
LocationLink[](targetUri/targetRange) to the same{ file, line, column, end_line, end_column }shape asLocation[]. - For built-in types (e.g.,
string,number), the server may return a location inside a bundled.d.tsdeclaration file.
go_to_type_definition¶
Navigate to the declaration of the type of a symbol, rather than the symbol
itself, via textDocument/typeDefinition.
Parameters — identical to go_to_definition
Example call — alice variable in consumer.ts (type is Person)
{
"file_path": "/home/user/projects/agent-lsp/test/ts-project/src/consumer.ts",
"language_id": "typescript",
"line": 7,
"column": 9
}
Expected output
[
{
"file": "/home/user/projects/agent-lsp/test/ts-project/src/example.ts",
"line": 11,
"column": 18,
"end_line": 15,
"end_column": 2
}
]
Notes
- Returns
[]if the server does not declaretypeDefinitionProvider. - Particularly useful with variables, parameters, and return values where
go_to_definitionwould land on the variable declaration rather than the type interface.
go_to_implementation¶
Find all concrete implementations of an interface or abstract method, via
textDocument/implementation.
Parameters — identical to go_to_definition
Example call — on an interface method
{
"file_path": "/path/to/project/src/interfaces.ts",
"language_id": "typescript",
"line": 5,
"column": 3
}
Expected output
[
{
"file": "/path/to/project/src/implementations/FooImpl.ts",
"line": 12,
"column": 3,
"end_line": 16,
"end_column": 4
}
]
Notes
- Returns
[]if the server does not declareimplementationProvider. - For a concrete class with no implementations below it, the server typically returns the class definition itself.
go_to_declaration¶
Navigate to the declaration of a symbol, as distinct from its definition, via
textDocument/declaration. In most languages the declaration and definition are
the same location. This tool is most useful for C/C++ where a function can be
declared in a header and defined in a source file.
Parameters — identical to go_to_definition
Example call — C++ function declared in header
Expected output (C++ clangd example)
[
{
"file": "/path/to/project/include/utils.h",
"line": 8,
"column": 5,
"end_line": 8,
"end_column": 15
}
]
Notes
- Returns
[]if the server does not declaredeclarationProvider. - For TypeScript and Go,
go_to_declarationandgo_to_definitiontypically return the same location. The tool exists to complete the full LSP navigation family and is most valuable with C/C++ servers (clangd) and similar languages with header/source splits.
Refactoring tools¶
rename_symbol¶
Compute a WorkspaceEdit for renaming a symbol everywhere it is used in the
workspace, via textDocument/rename. The edit is returned for inspection and
is not applied automatically. Pass it to apply_edit to commit the changes.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
file_path |
string | yes | File containing the symbol to rename |
language_id |
string | yes | Language identifier |
line |
number | yes | Line of the symbol (1-based) |
column |
number | yes | Column (1-based) |
new_name |
string | yes | The replacement name |
exclude_globs |
array of strings | no | Glob patterns for files to skip (e.g. ["vendor/", "/*_gen.go"]). Matching files are excluded from the returned WorkspaceEdit. Uses filepath.Match syntax; also matched against the file's basename. |
Example call — rename add to sum
{
"file_path": "/home/user/projects/agent-lsp/test/ts-project/src/example.ts",
"language_id": "typescript",
"line": 4,
"column": 17,
"new_name": "sum"
}
Expected output
{
"changes": {
"file:///home/user/projects/agent-lsp/test/ts-project/src/example.ts": [
{
"range": {
"start": { "line": 3, "character": 16 },
"end": { "line": 3, "character": 19 }
},
"newText": "sum"
}
],
"file:///home/user/projects/agent-lsp/test/ts-project/src/consumer.ts": [
{
"range": {
"start": { "line": 0, "character": 9 },
"end": { "line": 0, "character": 12 }
},
"newText": "sum"
},
{
"range": {
"start": { "line": 3, "character": 12 },
"end": { "line": 3, "character": 15 }
},
"newText": "sum"
}
]
}
}
The output is a raw WorkspaceEdit object. Coordinates are 0-based (LSP
native).
Notes
- Returns
"Rename not supported or symbol cannot be renamed at this location"as a string when the server returnsnull. - Returns
nullif the server does not declarerenameProvider. - Use
prepare_renamefirst to validate the rename before calling this. - Pass the returned object directly to
apply_editto write the changes to disk. exclude_globspatterns match against both the full file path and the basename. Common patterns: "vendor/" (Go vendor tree), "/_generated.go" (codegen), "testdata/*" (test fixtures).
prepare_rename¶
Validate that a rename operation is possible at the given position before
committing to it, via textDocument/prepareRename. Returns the range that
would be renamed and a suggested placeholder name.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
file_path |
string | yes | File containing the symbol |
language_id |
string | yes | Language identifier |
line |
number | yes | Line (1-based) |
column |
number | yes | Column (1-based) |
Example call
{
"file_path": "/home/user/projects/agent-lsp/test/ts-project/src/example.ts",
"language_id": "typescript",
"line": 4,
"column": 17
}
Expected output
{
"range": {
"start": { "line": 3, "character": 16 },
"end": { "line": 3, "character": 19 }
},
"placeholder": "add"
}
Notes
- Returns
"Rename not supported at this position"as a string when the server returnsnull. - Returns
nullif the server does not declarerenameProviderwithprepareProvider: true. The tool checks this flag explicitly and skips the request if it is absent. - Coordinates in the result are 0-based.
format_document¶
Compute formatting edits for an entire file via textDocument/formatting.
Returns TextEdit[] describing what the formatter would change. Edits are
not applied automatically — pass the result to apply_edit if you want to
write the formatted output to disk.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
file_path |
string | yes | Absolute path to the file |
language_id |
string | yes | Language identifier |
tab_size |
number | no | Spaces per tab. Default 2. |
insert_spaces |
boolean | no | Use spaces instead of tabs. Default true. |
Example call
{
"file_path": "/home/user/projects/agent-lsp/test/ts-project/src/example.ts",
"language_id": "typescript",
"tab_size": 2,
"insert_spaces": true
}
Expected output (already-formatted file returns empty array)
Expected output — file needing formatting
[
{
"range": {
"start": { "line": 5, "character": 0 },
"end": { "line": 5, "character": 4 }
},
"newText": " "
}
]
Each TextEdit has a 0-based range and a newText replacement string.
Notes
- Returns
[]if the server does not declaredocumentFormattingProvider. - The returned
TextEdit[]can be wrapped in aWorkspaceEditforapply_edit:{ "changes": { "file:///path/to/file.ts": [ ...edits ] } }.
format_range¶
Compute formatting edits for a selected range within a file via
textDocument/rangeFormatting. Otherwise identical to format_document but
scoped to specific lines.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
file_path |
string | yes | Absolute path to the file |
language_id |
string | yes | Language identifier |
start_line |
number | yes | Start line (1-based) |
start_column |
number | yes | Start column (1-based) |
end_line |
number | yes | End line (1-based) |
end_column |
number | yes | End column (1-based) |
tab_size |
number | no | Default 2 |
insert_spaces |
boolean | no | Default true |
Range start must not be after range end (schema-validated).
Example call — format only the Greeter class
{
"file_path": "/home/user/projects/agent-lsp/test/ts-project/src/example.ts",
"language_id": "typescript",
"start_line": 20,
"start_column": 1,
"end_line": 33,
"end_column": 2
}
Expected output
(No changes needed for already-formatted source.)
Notes
- Returns
[]if the server does not declaredocumentRangeFormattingProvider. - Not all language servers support range formatting even if they support document
formatting. Check the server's capabilities if this returns
[]unexpectedly.
apply_edit¶
Write a WorkspaceEdit to disk and notify the language server of the changes.
Pass the object returned by rename_symbol, format_document, or
format_range directly.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
workspace_edit |
object | — | A WorkspaceEdit with either changes (Record<uri, TextEdit[]>) or documentChanges (TextDocumentEdit[]). Required when using positional mode. |
file_path |
string | — | Text-match mode: absolute path to the file to edit. Use with old_text+new_text instead of workspace_edit. |
old_text |
string | — | Text-match mode: exact text to find and replace. First tries exact byte match; falls back to whitespace-normalised line match (tolerates indentation differences). |
new_text |
string | — | Text-match mode: replacement text. |
Use either workspace_edit (positional mode, for edits returned by rename_symbol/format_document) or the file_path+old_text+new_text triple (text-match mode, for AI-generated edits where exact line/column are unknown).
Example call — applying a rename edit
{
"workspace_edit": {
"changes": {
"file:///home/user/projects/agent-lsp/test/ts-project/src/example.ts": [
{
"range": {
"start": { "line": 3, "character": 16 },
"end": { "line": 3, "character": 19 }
},
"newText": "sum"
}
]
}
}
}
Actual output
Notes
- Edits within each file are applied in reverse order (bottom-to-top) so that earlier offsets remain valid as later text is replaced.
- After writing files to disk, the tool sends
textDocument/didChangefor each modified file to keep the language server in sync. documentChanges(array ofTextDocumentEdit) andchanges(object) forms are both supported.- This tool writes to disk immediately — make sure the edit looks correct before calling it.
execute_command¶
Execute a server-defined command via workspace/executeCommand. Commands are
returned in the command field of code actions (from get_code_actions) and
may also be listed in the server's executeCommandProvider.commands capability.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
command |
string | yes | Command identifier (e.g., _typescript.applyRefactoring) |
arguments |
array | no | Arguments to pass to the command |
Example call — triggering a TypeScript refactoring command
{
"command": "_typescript.applyRefactoring",
"arguments": [
"/path/to/file.ts",
"refactorRewrite",
"Add return type",
{ "startLine": 35, "startOffset": 1, "endLine": 37, "endOffset": 2 }
]
}
Expected output — command with a result
Expected output — command with no result
Notes
- Returns
nullif the server does not declareexecuteCommandProvider. - The available commands and their argument shapes are server-specific. Use
get_code_actionsto discover commands rather than constructing them manually. - Some commands apply changes server-side and push
workspace/applyEditrequests; others return an edit that you must apply withapply_edit.
Utilities¶
did_change_watched_files¶
Notify the language server that files have changed on disk outside the editor
context, via workspace/didChangeWatchedFiles. Use this after writing files
directly to disk (e.g., after code generation or template expansion) so the
server refreshes its caches.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
changes |
array | yes | Array of { uri, type } objects. uri must use the file:/// scheme. type: 1=created, 2=changed, 3=deleted. |
Example call
{
"changes": [
{
"uri": "file:///home/user/projects/agent-lsp/test/ts-project/src/newfile.ts",
"type": 1
},
{
"uri": "file:///home/user/projects/agent-lsp/test/ts-project/src/example.ts",
"type": 2
}
]
}
Actual output
Notes
- Sends a
workspace/didChangeWatchedFilesnotification (fire-and-forget); the server does not send a response. - This is a notification, not a request, so there is no success/failure from the server side.
- Follow up with
get_diagnosticsafter calling this if you want to verify the server picked up the changes. - Auto-watch: The server automatically watches the workspace root for file
changes using fsnotify and forwards them to the LSP server via
workspace/didChangeWatchedFileswith a 150ms debounce. For normal editing workflows, calling this tool manually is not required. Use it only for explicit control — e.g., to notify the server of changes made by external processes before the auto-watcher's debounce window has closed, or for files outside the workspace root.
set_log_level¶
Control the verbosity of logs written by the agent-lsp server process.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
level |
string | yes | One of: debug, info, notice, warning, error, critical, alert, emergency |
Levels from least to most verbose: emergency → alert → critical →
error → warning → notice → info → debug.
Example call
Actual output
Notes
- The default level is
info. - Set to
debugwhen troubleshooting: the server logs every LSP message sent and received in full JSON, including$/progress,workspace/configuration, andclient/registerCapabilityserver-initiated requests. - At
warningand above, only error conditions and lifecycle events are logged. Useful in production to reduce noise. - This affects the MCP server's own logging only, not the underlying language server's verbosity.
- Log messages are delivered as MCP
notifications/messageevents to the connected client (not just stderr) — you will see LSP lifecycle events, tool dispatch errors, and indexing state directly in the session. Before session init, messages fall back to stderr.
Code Intelligence tools¶
call_hierarchy¶
Resolve the call hierarchy for a symbol at a specific position. Returns the
symbol's CallHierarchyItem plus callers (incoming) and/or callees (outgoing),
via textDocument/prepareCallHierarchy, callHierarchy/incomingCalls, and
callHierarchy/outgoingCalls.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
file_path |
string | yes | Absolute path to the file |
language_id |
string | yes | Language identifier |
line |
number | yes | Line of the symbol (1-based) |
column |
number | yes | Column of the symbol (1-based) |
direction |
string | no | "incoming" (callers), "outgoing" (callees), or "both" (default) |
Example call
{
"file_path": "/path/to/project/pkg/handler.go",
"language_id": "go",
"line": 42,
"column": 6,
"direction": "incoming"
}
Expected output
{
"items": [
{
"name": "HandleRequest",
"kind": 12,
"uri": "file:///path/to/project/pkg/handler.go",
"range": { "start": { "line": 41, "character": 0 }, "end": { "line": 55, "character": 1 } },
"selectionRange": { "start": { "line": 41, "character": 5 }, "end": { "line": 41, "character": 20 } }
}
],
"incoming": [
{
"from": {
"name": "ServeHTTP",
"kind": 6,
"uri": "file:///path/to/project/pkg/server.go",
"range": { "...": "..." },
"selectionRange": { "...": "..." }
},
"fromRanges": [
{ "start": { "line": 22, "character": 2 }, "end": { "line": 22, "character": 17 } }
]
}
]
}
Notes
- Returns
"No call hierarchy item found at ..."as a string when no symbol is found at the given position. - Returns an error if the server does not declare
callHierarchyProvider. direction: "both"fetches both incoming and outgoing in a single call.
type_hierarchy¶
Resolve the type hierarchy for a symbol at a specific position. Returns the
symbol's TypeHierarchyItem plus supertypes (parent classes/interfaces) and/or
subtypes (implementations/subclasses), via textDocument/prepareTypeHierarchy,
typeHierarchy/supertypes, and typeHierarchy/subtypes. Requires LSP 3.17.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
file_path |
string | yes | Absolute path to the file |
language_id |
string | yes | Language identifier |
line |
number | yes | Line of the symbol (1-based) |
column |
number | yes | Column of the symbol (1-based) |
direction |
string | no | "supertypes" (parents), "subtypes" (implementations), or "both" (default) |
Example call
{
"file_path": "/path/to/project/pkg/animal.go",
"language_id": "go",
"line": 10,
"column": 6,
"direction": "both"
}
Expected output
{
"items": [
{
"name": "Animal",
"kind": 11,
"uri": "file:///path/to/project/pkg/animal.go",
"range": { "start": { "line": 9, "character": 0 }, "end": { "line": 15, "character": 1 } },
"selectionRange": { "start": { "line": 9, "character": 5 }, "end": { "line": 9, "character": 11 } }
}
],
"supertypes": [],
"subtypes": [
{
"name": "Dog",
"kind": 5,
"uri": "file:///path/to/project/pkg/dog.go",
"range": { "...": "..." },
"selectionRange": { "...": "..." }
}
]
}
Notes
- Returns
"No type hierarchy item found at ..."as a string when no symbol is found at the given position. - Requires the server to declare
typeHierarchyProvider(LSP 3.17). - Omitted fields (
supertypes,subtypes) are absent rather than empty arrays whendirectionlimits which are fetched.
get_inlay_hints¶
Return inlay hints for a range within a document via textDocument/inlayHint.
Inlay hints show inferred type annotations and parameter name labels inline with
source code — the same annotations IDEs display in TypeScript, Rust, Go, and
other languages with type inference.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
file_path |
string | yes | Absolute path to the file |
language_id |
string | no | Language identifier |
start_line |
number | yes | Start line of the range (1-based) |
start_column |
number | yes | Start column (1-based) |
end_line |
number | yes | End line of the range (1-based) |
end_column |
number | yes | End column (1-based) |
Example call
{
"file_path": "/path/to/project/src/example.ts",
"language_id": "typescript",
"start_line": 1,
"start_column": 1,
"end_line": 20,
"end_column": 1
}
Expected output
[
{
"position": { "line": 3, "character": 7 },
"label": ": number",
"kind": 1,
"paddingLeft": true
},
{
"position": { "line": 7, "character": 12 },
"label": "name: ",
"kind": 2
}
]
kind values: 1=Type annotation, 2=Parameter name. label may be either a
plain string or an array of InlayHintLabelPart objects with value, tooltip,
and optional location.
Notes
- Returns
[]when the server does not declareinlayHintProvideror has no hints for the given range. - Position coordinates in the output are 0-based (LSP native).
get_semantic_tokens¶
Return semantic token classifications for a range within a document via
textDocument/semanticTokens/range (falls back to full-file if range is not
supported). Semantic tokens classify each token as a function, parameter,
variable, type, keyword, etc., using the type and modifier legend declared by
the server during initialization.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
file_path |
string | yes | Absolute path to the file |
language_id |
string | no | Language identifier |
start_line |
number | yes | Start line of the range (1-based) |
start_column |
number | yes | Start column (1-based) |
end_line |
number | yes | End line of the range (1-based) |
end_column |
number | yes | End column (1-based) |
Example call
{
"file_path": "/path/to/project/main.go",
"language_id": "go",
"start_line": 1,
"start_column": 1,
"end_line": 30,
"end_column": 1
}
Expected output
[
{
"line": 5,
"character": 5,
"length": 11,
"token_type": "function",
"token_modifiers": ["definition", "exported"]
},
{
"line": 5,
"character": 17,
"length": 1,
"token_type": "parameter",
"token_modifiers": []
}
]
Output positions are 1-based. The token_type and token_modifiers fields are
decoded from the server's legend into human-readable strings.
Notes
- Returns
[]when the server does not declaresemanticTokensProvider. - The LSP wire format uses delta-encoded 5-integer tuples; this tool decodes
them into absolute positions with named type/modifier strings from the
server's legend captured during
initialize. - TypeScript, Go, Python, Rust, C, C++, C#, Kotlin, Ruby, and PHP all support semantic tokens.
get_document_highlights¶
Return all occurrences of the symbol at a position within the same file via
textDocument/documentHighlight. Highlights are file-scoped and instant — they
do not trigger a workspace-wide reference search.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
file_path |
string | yes | Absolute path to the file |
language_id |
string | no | Language identifier |
line |
number | yes | Line of the symbol (1-based) |
column |
number | yes | Column of the symbol (1-based) |
Example call
{
"file_path": "/path/to/project/src/example.ts",
"language_id": "typescript",
"line": 4,
"column": 17
}
Expected output
[
{
"range": {
"start": { "line": 3, "character": 16 },
"end": { "line": 3, "character": 19 }
},
"kind": 1
},
{
"range": {
"start": { "line": 7, "character": 12 },
"end": { "line": 7, "character": 15 }
},
"kind": 2
}
]
kind values: 1=Text, 2=Read, 3=Write.
Notes
- Returns
[]if the server does not declaredocumentHighlightProvider. - Use this instead of
get_referenceswhen you only need occurrences within the current file — it is faster and requires no workspace indexing. - Coordinates in the output are 0-based (LSP native).
Server Introspection tools¶
get_server_capabilities¶
Return the language server's capability map and classify every agent-lsp tool as supported or unsupported based on what the server advertised during initialization. Useful for discovering which tools will return meaningful results before making analysis calls.
Parameters
None. The tool takes no arguments.
Example call
Expected output
{
"server_name": "gopls",
"server_version": "v0.16.2",
"supported_tools": [
"apply_edit",
"call_hierarchy",
"did_change_watched_files",
"format_document",
"get_code_actions",
"get_completions",
"get_diagnostics",
"get_document_symbols",
"get_info_on_location",
"get_references",
"get_semantic_tokens",
"get_signature_help",
"get_workspace_symbols",
"go_to_definition",
"go_to_implementation",
"go_to_type_definition",
"rename_symbol",
"prepare_rename",
"start_lsp",
"..."
],
"unsupported_tools": [
"get_inlay_hints",
"type_hierarchy"
],
"capabilities": {
"hoverProvider": true,
"completionProvider": { "triggerCharacters": [".", ":"], "resolveProvider": true },
"..."
}
}
Notes
- Requires
start_lspto have been called first. - Always-available tools (e.g.,
start_lsp,open_document,set_log_level,detect_lsp_servers) appear insupported_toolsregardless of server capabilities. server_nameandserver_versionare omitted if the server did not provide them in itsinitializeresponse.
detect_lsp_servers¶
Scan a workspace directory for source languages and check PATH for the
corresponding LSP server binaries. Returns the detected languages, installed
servers with their executable paths, and a suggested_config array ready to
paste into the agent-lsp MCP server args.
Does not require start_lsp to have been called — it works standalone.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
workspace_dir |
string | yes | Absolute path to the workspace root to scan |
Example call
Expected output
{
"workspace_dir": "/home/user/projects/myproject",
"workspace_languages": ["go", "typescript"],
"installed_servers": [
{
"language": "go",
"server": "gopls",
"path": "/usr/local/bin/gopls",
"config_entry": "go:gopls"
},
{
"language": "typescript",
"server": "typescript-language-server",
"path": "/usr/local/bin/typescript-language-server",
"config_entry": "typescript:typescript-language-server,--stdio"
}
],
"suggested_config": [
"go:gopls",
"typescript:typescript-language-server,--stdio"
],
"not_installed": []
}
Notes
- Language detection is score-based: project root markers (e.g.,
go.mod,package.json,Cargo.toml) score +50; individual source files score +1 per file. Languages are returned ranked by score. - Skips
node_modules,vendor,target,build,dist,.git, and other standard build/cache directories. not_installedlists languages detected in the workspace whose server binary was not found on PATH.suggested_configentries use the formatlanguage:binaryorlanguage:binary,arg1,arg2and can be passed directly as agent-lsp MCP server args.
Build & Test tools¶
run_build¶
Compile the project using the detected workspace language. Language-specific
dispatch — go build ./... (Go), cargo build (Rust), tsc --noEmit
(TypeScript), mypy . (Python typecheck proxy), npm run build (JavaScript),
dotnet build (C#), swift build (Swift), zig build (Zig),
gradle build --quiet (Kotlin). Does not require start_lsp.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
workspace_dir |
string | yes | Absolute path to the workspace root |
path |
string | no | Narrows the build scope (e.g., a subdirectory or file) |
language |
string | no | Override auto-detected language |
Returns
{
"success": true,
"errors": [
{ "file": "/path/to/file.go", "line": 12, "column": 5, "message": "undefined: Foo" }
],
"raw": "go build ./...\n..."
}
Notes
- Language is auto-detected from workspace root markers (
go.mod,Cargo.toml,package.json,pyproject.toml, etc.) whenlanguageis omitted. errorsis always an array; it is empty on a clean build.- Does not start or require an LSP session.
run_tests¶
Run the test suite for the detected workspace language. Language-specific
dispatch — go test -json ./... (Go), cargo test --message-format=json
(Rust), pytest --tb=json (Python), npm test (JavaScript/TypeScript),
dotnet test (C#), swift test (Swift), zig build test (Zig),
gradle test --quiet (Kotlin). Test failure location fields are
LSP-normalized (file URI + zero-based range) — paste directly into
go_to_definition. Does not require start_lsp.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
workspace_dir |
string | yes | Absolute path to the workspace root |
path |
string | no | Narrows the test scope (e.g., a package path or file) |
language |
string | no | Override auto-detected language |
Returns
{
"passed": false,
"failures": [
{
"file": "/path/to/file_test.go",
"line": 42,
"test_name": "TestFoo",
"message": "assertion failed: expected 1, got 2",
"location": {
"uri": "file:///path/to/file_test.go",
"range": { "start": { "line": 41, "character": 0 }, "end": { "line": 41, "character": 0 } }
}
}
],
"raw": "..."
}
Notes
passedistrueonly when all tests pass and the test runner exits 0.failuresis empty whenpassedistrue.locationis LSP-normalized for direct use withgo_to_definition.- Does not start or require an LSP session.
get_tests_for_file¶
Return test files that exercise a given source file. Static lookup — no test
execution. Go: *_test.go in the same directory. Python: test_*.py /
*_test.py in the same directory and a tests/ sibling. TypeScript/JS:
*.test.ts, *.spec.ts, *.test.js, *.spec.js, etc. Rust: returns the
source file itself (tests are inline). Swift: returns the source file itself
(tests are inline via XCTest). Zig: returns the source file itself (inline
test blocks). C#: globs *Test*.cs / *Tests.cs in the project tree.
Kotlin: globs *Test.kt / *Tests.kt in the project tree.
Does not require start_lsp.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
file_path |
string | yes | Absolute path to the source file |
Returns
Notes
test_filesis an empty array when no test files are found.- For Rust, Swift, and Zig, the source file itself is returned in
test_filesbecause tests live in the same file as the source code (Rust#[cfg(test)]modules, Swift XCTest methods, Zig inlinetestblocks). - For C#, test files are discovered by globbing
*Test*.cs/*Tests.cs. - For Kotlin, test files are discovered by globbing
*Test.kt/*Tests.kt. - Does not start or require an LSP session.
Simulation tools¶
Speculative code sessions let you apply hypothetical edits, evaluate their diagnostic impact, then commit or discard — without touching files on disk. See docs/speculative-execution.md for the full design.
Call start_lsp before using any simulation tool. All simulation tools operate against the currently-running language server.
Position convention: all start_line, start_column, end_line, end_column parameters are 1-indexed (same as editor line numbers). The server converts to 0-indexed internally.
create_simulation_session¶
Create an isolated speculative session rooted at the current workspace state. The session accumulates in-memory edits without modifying files on disk.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
workspace_root |
string | yes | Absolute path to the workspace root |
language |
string | yes | Language identifier (go, typescript, etc.) |
Example call
Actual output
Notes
- Call
start_lspfirst; the session is attached to the running language server. - The session must be destroyed when done — call
destroy_sessionto release resources. - Multiple sessions may exist simultaneously with independent state.
simulate_edit¶
Apply an in-memory edit to an existing session. Does not modify files on disk. Multiple edits accumulate within the session.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
session_id |
string | yes | Session ID from create_simulation_session |
file_path |
string | yes | Absolute path to the file to edit |
start_line |
int | yes | Start line of the edit range (1-indexed) |
start_column |
int | yes | Start column (1-indexed) |
end_line |
int | yes | End line of the edit range (1-indexed) |
end_column |
int | yes | End column (1-indexed) |
new_text |
string | yes | Replacement text for the specified range |
Example call
{
"session_id": "a3f2-4b91-...",
"file_path": "/home/user/projects/myproject/pkg/handler.go",
"start_line": 42,
"start_column": 1,
"end_line": 42,
"end_column": 20,
"new_text": "replacement text"
}
Actual output
Notes
- Multiple
simulate_editcalls may be made before callingevaluate_session; evaluation reflects the cumulative state. - Does not evaluate diagnostics — call
evaluate_sessionseparately to observe impact.
evaluate_session¶
Compare the session's current diagnostic state against the baseline. Returns which errors were introduced and which were resolved by the accumulated edits.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
session_id |
string | yes | Session ID |
scope |
string | no | "file" (default) or "workspace". File scope is faster and returns confidence: "high". |
timeout_ms |
int | no | Milliseconds to wait for diagnostics to settle. Default: 3000ms (file), 8000ms (workspace). |
Example call
Actual output
{
"session_id": "a3f2-4b91-...",
"errors_introduced": null,
"errors_resolved": null,
"net_delta": 0,
"scope": "file",
"confidence": "high",
"timeout": false,
"duration_ms": 412
}
Notes
net_delta: 0means no new errors were introduced — safe to apply.confidencevalues:"high"(file scope, settled within timeout),"partial"(timed out or snapshot incomplete),"eventual"(workspace scope, cross-file propagation may be incomplete).- Does not mutate session state.
simulate_chain¶
Apply a sequence of edits within a session and evaluate diagnostics after each step. Returns per-step results and identifies the last step that is safe to apply.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
session_id |
string | yes | Session ID |
edits |
array | yes | Ordered list of edit objects, each with file_path, start_line, start_column, end_line, end_column, new_text |
timeout_ms |
int | no | Timeout per evaluation step |
Example call
{
"session_id": "a3f2-4b91-...",
"edits": [
{
"file_path": "/home/user/projects/myproject/pkg/handler.go",
"start_line": 10, "start_column": 1,
"end_line": 10, "end_column": 30,
"new_text": "first change"
},
{
"file_path": "/home/user/projects/myproject/pkg/handler.go",
"start_line": 20, "start_column": 1,
"end_line": 20, "end_column": 30,
"new_text": "second change"
}
]
}
Actual output
{
"steps": [
{ "step": 1, "net_delta": 0, "errors_introduced": [] },
{ "step": 2, "net_delta": 3, "errors_introduced": ["..."] }
],
"safe_to_apply_through_step": 1,
"cumulative_delta": 3
}
Notes
- Each step builds on the previous in-memory state within the session.
safe_to_apply_through_stepis the last step index withnet_delta: 0.
commit_session¶
Materialize the session's accumulated speculative state. By default returns a patch without writing to disk (functional mode). Pass apply: true to write files to disk.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
session_id |
string | yes | Session ID |
target |
string | no | Target path override for writing files |
apply |
boolean | no | If true, write changes to disk. Default false. |
Example call — patch only (default)
Example call — write to disk
Actual output
{
"session_id": "a3f2-4b91-...",
"files_written": [],
"patch": { "changes": { "file:///path/to/file.go": [ { "...": "..." } ] } }
}
Notes
- Default is functional (patch only, no disk writes). Callers opt into disk writes explicitly with
apply: true. - Commit is only allowed from a session in
evaluatedormutatedstate; prohibited ondirtyorcreatedsessions. - Call
destroy_sessionafter committing to release resources.
discard_session¶
Revert all in-memory edits accumulated in the session. The session is reset to baseline state. Nothing is written to disk.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
session_id |
string | yes | Session ID |
Example call
Actual output
Notes
- Equivalent to rolling back a transaction — no side effects.
- Call
destroy_sessionafter discarding to release resources.
destroy_session¶
Clean up all resources associated with a session. Must be called after committing or discarding to prevent resource leaks.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
session_id |
string | yes | Session ID |
Example call
Actual output
Notes
- Must be called even on dirty sessions — this is the only valid cleanup path for a session in
dirtystate. - Sessions are in-memory only; session IDs become invalid on MCP server restart.
simulate_edit_atomic¶
One-shot convenience wrapper: applies a single edit, evaluates diagnostics, and discards in one call. The file on disk is never modified.
Two modes:
- Standalone (session_id omitted): creates a temporary session, applies the edit, evaluates, then destroys the session automatically. Requires workspace_root and language.
- Existing session (session_id provided): applies the edit into an existing session and evaluates without destroying it. workspace_root and language are ignored.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
session_id |
string | no | Existing session ID — if provided, uses that session instead of creating a temporary one |
workspace_root |
string | no* | Absolute path to the workspace root (*required when session_id is omitted) |
language |
string | no* | Language identifier (*required when session_id is omitted) |
file_path |
string | yes | Absolute path to the file to edit |
start_line |
int | yes | Start line (1-indexed) |
start_column |
int | yes | Start column (1-indexed) |
end_line |
int | yes | End line (1-indexed) |
end_column |
int | yes | End column (1-indexed) |
new_text |
string | yes | Replacement text |
scope |
string | no | "file" (default) or "workspace" |
timeout_ms |
int | no | Timeout for diagnostic evaluation |
Example call
{
"workspace_root": "/home/user/projects/myproject",
"language": "go",
"file_path": "/home/user/projects/myproject/pkg/handler.go",
"start_line": 42,
"start_column": 1,
"end_line": 42,
"end_column": 20,
"new_text": "replacement text",
"scope": "file",
"timeout_ms": 5000
}
Actual output
Notes
- Easiest way to test a single edit — no session lifecycle management required.
- Call
start_lspfirst. net_delta: 0means the edit is safe to apply (no new errors introduced).- Automatically discards and destroys the session; the file on disk is never modified.
- Backed by the same session infrastructure as the full lifecycle tools — not a separate code path.
Startup and warm-up notes¶
The tsserver (and some other language servers) perform asynchronous workspace
indexing after initialize. During this period:
get_info_on_locationmay return empty string.get_referencesmay return[].get_diagnosticsmay return empty diagnostic arrays.
The server handles three server-initiated requests that must be responded to before workspace loading completes:
window/workDoneProgress/create— pre-registers a progress token.workspace/configuration— the server returnsnullfor each requested config item.client/registerCapability— acknowledged withnull.
agent-lsp handles all three automatically. For get_references, the client
additionally waits for all $/progress end events before returning. tsserver
does not emit $/progress, so references may require a brief wait and retry
on first use. Set set_log_level to debug and look for Progress end: log
lines to confirm when the server is ready.
Symbol lookup tools¶
go_to_symbol¶
Navigate to a symbol's definition by dot-notation path — no file path or line/column required. Useful when you know a symbol name but not its location.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
symbol_path |
string | yes | Dot-notation symbol path, e.g. "MyClass.method" or "pkg.Function" |
workspace_root |
string | no | Restrict search to a specific workspace root |
language |
string | no | Filter candidates by language ID |
Algorithm
- Splits
symbol_pathon.to extract the leaf name (last component). - Calls
GetWorkspaceSymbolswith the leaf name to get candidates. - If the path is dotted, prefers candidates where
ContainerNamematches the parent component; otherwise uses the first result. - Opens the candidate file via
WithDocumentand callsGetDefinitionat the candidate position; if empty, uses the candidate location directly. - Returns a 1-indexed
FormattedLocation.
Example call
Actual output
[
{
"file": "/Users/you/code/agent-lsp/internal/lsp/client.go",
"line": 142,
"column": 1,
"end_line": 142,
"end_column": 13
}
]
get_symbol_source¶
Return the source code of the innermost symbol (function, method, struct, class,
etc.) whose range contains a given cursor position. Composes
textDocument/documentSymbol + file read — no new LSP methods required.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
file_path |
string | yes | Absolute path to the file |
language_id |
string | no | Language identifier (used for document open) |
line |
number | no | 1-based line number of the cursor position |
character |
number | no | 1-based character offset of the cursor (aliased from column) |
position_pattern |
string | no | @@-syntax pattern for cursor placement (see Position-pattern section) |
Example call
{
"file_path": "/home/user/projects/myproject/main.go",
"language_id": "go",
"line": 12,
"character": 5
}
Actual output
{
"symbol_name": "handleRequest",
"symbol_kind": "Function",
"start_line": 10,
"end_line": 18,
"source": "func handleRequest(w http.ResponseWriter, r *http.Request) {\n\t// ...\n}"
}
Notes
findInnermostSymbolwalks the DocumentSymbol tree recursively and returns the deepest symbol whose range contains the cursor — so clicking inside a method body returns the method, not the enclosing class.start_lineandend_lineare 1-based.- Provide
line+character, orposition_patternwith@@— at least one position input is required. - CI-verified across all 30 languages via
testGetSymbolSource.
get_symbol_documentation¶
Fetch authoritative documentation for a named symbol from local toolchain sources (go doc, pydoc, cargo doc) without requiring an LSP hover response. Works on transitive dependencies not indexed by the language server.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
symbol |
string | yes | Fully-qualified symbol name (e.g. fmt.Println, std::vec::Vec::new) |
language_id |
string | yes | Language identifier: go, rust, python |
file_path |
string | no | Absolute path to any file in the module/project — used to infer package context for Go |
format |
string | no | "text" (default) or "markdown" — wraps signature in a fenced code block |
Algorithm
Dispatches to a per-language toolchain command based on language_id:
| Language | Command |
|---|---|
go |
go doc <symbol> (run from file_path directory if provided) |
python |
pydoc <symbol> |
rust |
cargo doc --open (offline cache lookup) |
Example call
Actual output
{
"symbol": "fmt.Println",
"language": "go",
"source": "toolchain",
"doc": "func Println(a ...any) (n int, err error)\n\nPrintln formats using the default formats...",
"signature": "func Println(a ...any) (n int, err error)",
"error": ""
}
Notes
- All dispatchers use a 10-second timeout. Cold module cache (first
go doccall) may approach this limit; subsequent calls are fast. - Output is ANSI-stripped — safe for MCP transport.
- When the toolchain command fails,
sourceis"error"anderrorcontains the stderr. This is a structured result, not an MCP error — callers can detect it and fall back toget_info_on_location. - TypeScript and JavaScript are not supported; returns
source: "error"with an appropriate message. get_symbol_documentationis used as Tier 2 in thelsp-docsskill — call it after hover returns empty, before falling back to source navigation.
Position-pattern parameter (position_pattern)¶
Five tools accept an optional position_pattern field:
get_info_on_location, get_references, go_to_definition,
rename_symbol, and get_symbol_source. When provided, it replaces the line/column pair.
How it works
The value is a text snippet that appears in the file, with @@ marking the
cursor position. ResolvePositionPattern searches the file for the text
surrounding @@, strips the marker, and returns the 1-indexed line and column
of the character immediately after @@.
Example
This positions the cursor at the D in GetDefinition — equivalent to
passing the line/column manually, but resistant to line number drift.
Error cases
- Pattern missing
@@: returns an error. - Search text not found in file: returns an error.
Dry-run preview for rename_symbol¶
rename_symbol now accepts an optional dry_run boolean parameter.
| Name | Type | Required | Description |
|---|---|---|---|
dry_run |
boolean | no | If true, return the workspace edit preview without writing to disk (default: false) |
Glob exclusions for rename_symbol¶
rename_symbol accepts an optional exclude_globs array. Files matching
any pattern are excluded from the returned WorkspaceEdit — the rename
still executes on all other files.
| Name | Type | Required | Description |
|---|---|---|---|
exclude_globs |
array | no | Array of glob patterns (filepath.Match syntax). Matched against full path and basename. |
Example — exclude generated files and vendor tree:
{
"file_path": "/project/pkg/types.go",
"line": 12,
"column": 6,
"new_name": "SessionToken",
"exclude_globs": ["vendor/**", "**/*_gen.go", "**/*_generated.go"]
}
Dry-run output
{
"workspace_edit": { "...": "full WorkspaceEdit as usual" },
"preview": {
"note": "Dry run — no files were modified. Call apply_edit with workspace_edit to commit."
}
}
Normal mode (dry_run omitted or false): behavior unchanged — returns the
WorkspaceEdit directly, ready for apply_edit.
Skills¶
Twenty agent-native skills compose agent-lsp tools into single-command
workflows. Install with cd skills && ./install.sh.
| Skill | Tools used | Purpose |
|---|---|---|
/lsp-safe-edit |
simulate_edit_atomic, get_diagnostics, get_code_actions, apply_edit |
Speculative preview before disk write (simulate_edit_atomic); before/after diagnostic diff; surfaces code actions on introduced errors; handles multi-file edits |
/lsp-edit-export |
get_references, get_info_on_location, simulate_edit_atomic |
Safe editing of exported symbols — finds all callers first, then validates the edit |
/lsp-edit-symbol |
get_workspace_symbols, get_document_symbols, apply_edit |
Edit a named symbol without knowing its file or position — resolves name to definition, retrieves full range, applies edit |
/lsp-rename |
prepare_rename, rename_symbol (dry_run), apply_edit, get_diagnostics |
Two-phase rename: prepare_rename validates position first, then preview all sites, confirm, apply atomically |
/lsp-verify |
get_diagnostics, run_build, run_tests |
Full three-layer check: LSP diagnostics + build + tests — summarizes pass/fail |
/lsp-simulate |
create_simulation_session, simulate_edit_atomic, simulate_chain, evaluate_session |
Speculative editing — test changes without touching the file; supports single edits, sessions, and chained multi-edit sequences |
/lsp-impact |
get_references, call_hierarchy, type_hierarchy |
Blast-radius analysis before renaming or deleting — maps all callers, implementors, and subtypes |
/lsp-dead-code |
get_document_symbols, get_references |
Detect zero-reference exports and unreachable symbols across a file or workspace |
/lsp-implement |
go_to_implementation, type_hierarchy |
Find all concrete implementations of an interface or abstract type — capability pre-check, risk assessment (0 = likely unused, >10 = breaking API change) |
/lsp-docs |
get_info_on_location, get_symbol_documentation, go_to_definition, get_symbol_source |
Three-tier documentation lookup: hover → offline toolchain doc → source definition |
/lsp-cross-repo |
add_workspace_folder, list_workspace_folders, get_references, go_to_implementation, call_hierarchy |
Multi-root cross-repo analysis — add a consumer repo and find all callers, references, and implementations of a library symbol across both repos |
/lsp-local-symbols |
get_document_symbols, get_document_highlights, get_info_on_location |
File-scoped analysis — list all symbols in a file, find all usages of a symbol within the file (faster than workspace search), get type info |
/lsp-test-correlation |
get_tests_for_file, get_workspace_symbols, run_tests |
Find and run only the tests covering an edited file; multi-file deduplication; fallback to workspace symbol search when mapping is absent |
/lsp-format-code |
format_document, format_range, apply_edit, get_diagnostics |
Format a file or selection via the language server formatter; full-file or range; verifies no diagnostics introduced after applying |
/lsp-explore |
go_to_symbol, get_info_on_location, go_to_implementation, call_hierarchy, get_references |
Symbol exploration: hover + implementations + call hierarchy + references in one pass — for navigating unfamiliar code |
/lsp-understand |
get_info_on_location, go_to_implementation, call_hierarchy, get_references, get_symbol_source, get_document_symbols, go_to_symbol |
Deep-dive exploration — builds a Code Map showing type info, implementations, call hierarchy, references, and source |
/lsp-refactor |
get_change_impact, simulate_edit_atomic, simulate_chain, get_diagnostics, run_build, run_tests, get_tests_for_file, apply_edit, format_document |
End-to-end safe refactor: blast-radius analysis, speculative preview, apply, verify build, run affected tests |
/lsp-extract-function |
get_document_symbols, get_code_actions, execute_command, apply_edit, get_diagnostics, format_document |
Extract a code block into a named function; primary path uses LSP code action, falls back to manual extraction |
/lsp-fix-all |
get_diagnostics, get_code_actions, apply_edit, format_document |
Bulk-apply quick-fix code actions for all diagnostics in a file |
/lsp-generate |
get_code_actions, execute_command, apply_edit, format_document, get_diagnostics |
Trigger LSP code generation — implement interface stubs, generate test skeletons, add missing methods |
Skills work with any MCP client that supports tool use, not just Claude Code.
See also¶
- docs/skills.md — skill reference with workflows, use cases, and composition patterns
- docs/language-support.md — language coverage matrix and per-language tool support