Skip to content

Install LSP servers

apm install handles three dependency kinds: APM packages (see Install Packages), MCP servers (see Install MCP servers), and LSP servers. This page covers LSP servers: how you declare them, what gets written, and how the install pipeline manages their lifecycle.

LSP integration targets supported agent runtimes. Today APM writes configuration for Claude Code and GitHub Copilot CLI, while keeping the manifest dependency model runtime-agnostic. See Claude Code’s Plugins reference and GitHub’s Copilot CLI LSP servers documentation for runtime-specific config details.

Declare an LSP server in apm.yml and run apm install:

dependencies:
lsp:
- name: gopls
command: gopls
args: ["serve"]
extensionToLanguage:
".go": go
Terminal window
apm install

APM writes runtime-specific config for each detected target. Claude Code uses .lsp.json or ~/.claude.json; Copilot CLI uses .github/lsp.json or ~/.copilot/lsp-config.json. The runtime starts the configured language servers automatically.

LSP servers live under dependencies.lsp: (or devDependencies.lsp:). Two forms are valid:

dependencies:
lsp:
# 1. String reference (server name only -- resolved from
# transitive packages or plugin .lsp.json)
- gopls
# 2. Full object (self-contained server definition)
- name: pyright
command: pyright-langserver
args: ["--stdio"]
extensionToLanguage:
".py": python
".pyi": python
transport: stdio
env:
PYTHONPATH: "./src"
startupTimeout: 10000

The full field reference is in the Manifest schema.

RuntimeProject fileUser file (-g)Language map key
Claude Code.lsp.json~/.claude.json lspServersextensionToLanguage
GitHub Copilot CLI.github/lsp.json lspServers~/.copilot/lsp-config.json lspServersfileExtensions

Claude Code project-scope .lsp.json example:

{
"gopls": {
"command": "gopls",
"args": ["serve"],
"extensionToLanguage": {
".go": "go"
}
}
}

Copilot CLI project-scope .github/lsp.json example:

{
"lspServers": {
"gopls": {
"command": "gopls",
"args": ["serve"],
"fileExtensions": {
".go": "go"
}
}
}
}

User-scope files keep the same runtime-specific server shape under their lspServers section.

Two fields are required for every LSP server definition (object form):

FieldTypeDescription
commandstringBinary to execute. Must be on $PATH or a relative path.
extensionToLanguagemap<string, string>Maps file extensions to LSP language identifiers (e.g. ".go": "go").

Optional fields give you finer control:

FieldTypeDefaultDescription
argslist<string>[]Command-line arguments.
transportstringstdiostdio or socket.
envmap<string, string>{}Environment variables set when starting the server.
initializationOptionsanyOptions passed during LSP initialization.
settingsanySettings passed via workspace/didChangeConfiguration.
workspaceFolderstringWorkspace folder path.
startupTimeoutintMax time (ms) to wait for server startup.
shutdownTimeoutintMax time (ms) for graceful shutdown.
restartOnCrashboolRestart the server automatically on crash.
maxRestartsintMaximum restart attempts before giving up.

When an APM package you depend on declares its own dependencies.lsp entries, APM collects them transitively after installation. Direct (root) dependencies take precedence: if the root manifest and a transitive package both declare a server with the same name, the root definition wins.

Unlike MCP, LSP has no registry vs self-defined distinction. All LSP servers from installed packages are treated as trusted.

When a previously installed LSP server is no longer declared by any dependency, APM removes it from the target runtime configs it manages. The lockfile tracks which servers APM manages, so hand-added servers are never touched.

apm install persists two fields in apm.lock.yaml:

  • lsp_servers — sorted list of APM-managed server names.
  • lsp_configs — server-name-to-config baseline for drift detection.

See the Lockfile specification.

When APM installs a plugin that contains lspServers in plugin.json or a .lsp.json file, the LSP servers are automatically extracted and wired into the install pipeline. The ${CLAUDE_PLUGIN_ROOT} placeholder in server configs is replaced with the absolute plugin path for legacy Claude Code plugin compatibility.

LSP integration writes configuration for supported runtimes and leaves the manifest schema runtime-neutral. Target selection follows the same runtime detection and --target/targets: mechanics as MCP installs.

RuntimeLSP support
Claude Code.lsp.json / ~/.claude.json
GitHub Copilot CLI.github/lsp.json / ~/.copilot/lsp-config.json
OthersNot yet supported