This is an MCP server that runs and exposes a language server to LLMs. Not a language server for MCP, whatever that would be.
mcp-language-server helps MCP enabled clients navigate codebases more easily by giving them access semantic tools like get definition, references, rename, and diagnostics.
- Install Go: Follow instructions at https://golang.org/doc/install
- Install or update this server:
go install github.com/isaacphi/mcp-language-server@latest - Install a language server: follow one of the guides below
- Configure your MCP client: follow one of the guides below
Go (gopls)
Install gopls: go install golang.org/x/tools/gopls@latest
Configure your MCP client: This will be different but similar for each client. For Claude Desktop, add the following to ~/Library/Application\ Support/Claude/claude_desktop_config.json
{
"mcpServers": {
"language-server": {
"command": "mcp-language-server",
"args": ["--workspace", "/Users/you/dev/yourproject/", "--lsp", "gopls"],
"env": {
"PATH": "/opt/homebrew/bin:/Users/you/go/bin",
"GOPATH": "/users/you/go",
"GOCACHE": "/users/you/Library/Caches/go-build",
"GOMODCACHE": "/Users/you/go/pkg/mod"
}
}
}
}
Note: Not all clients will need these environment variables. For Claude Desktop you will need to update the environment variables above based on your machine and username:
PATHneeds to contain the path togoand togopls. Get this withecho $(which go):$(which gopls)GOPATH,GOCACHE, andGOMODCACHEmay be different on your machine. These are the defaults.
Rust (rust-analyzer)
Install rust-analyzer: rustup component add rust-analyzer
Configure your MCP client: This will be different but similar for each client. For Claude Desktop, add the following to ~/Library/Application\ Support/Claude/claude_desktop_config.json
{
"mcpServers": {
"language-server": {
"command": "mcp-language-server",
"args": [
"--workspace",
"/Users/you/dev/yourproject/",
"--lsp",
"rust-analyzer"
]
}
}
}
Python (pyright)
Install pyright: npm install -g pyright
Configure your MCP client: This will be different but similar for each client. For Claude Desktop, add the following to ~/Library/Application\ Support/Claude/claude_desktop_config.json
{
"mcpServers": {
"language-server": {
"command": "mcp-language-server",
"args": [
"--workspace",
"/Users/you/dev/yourproject/",
"--lsp",
"pyright-langserver",
"--",
"--stdio"
]
}
}
}
Typescript (typescript-language-server)
Install typescript-language-server: npm install -g typescript typescript-language-server
Configure your MCP client: This will be different but similar for each client. For Claude Desktop, add the following to ~/Library/Application\ Support/Claude/claude_desktop_config.json
{
"mcpServers": {
"language-server": {
"command": "mcp-language-server",
"args": [
"--workspace",
"/Users/you/dev/yourproject/",
"--lsp",
"typescript-language-server",
"--",
"--stdio"
]
}
}
}
C/C++ (clangd)
Install clangd: Download prebuilt binaries from the official LLVM releases page or install via your system's package manager (e.g., apt install clangd, brew install clangd).
Configure your MCP client: This will be different but similar for each client. For Claude Desktop, add the following to ~/Library/Application\\ Support/Claude/claude_desktop_config.json
{
"mcpServers": {
"language-server": {
"command": "mcp-language-server",
"args": [
"--workspace",
"/Users/you/dev/yourproject/",
"--lsp",
"/path/to/your/clangd_binary",
"--",
"--compile-commands-dir=/path/to/yourproject/build_or_compile_commands_dir"
]
}
}
}
<p><strong>Note</strong>:</p>
<ul>
<li>Replace <code>/path/to/your/clangd_binary</code> with the actual path to your clangd executable.</li>
<li><code>--compile-commands-dir</code> should point to the directory containing your <code>compile_commands.json</code> file (e.g., <code>./build</code>, <code>./cmake-build-debug</code>).</li>
<li>Ensure <code>compile_commands.json</code> is generated for your project for clangd to work effectively.</li>
</ul>
C# (csharp-ls)
Install the .NET SDK: csharp-ls requires a recent .NET SDK. See dotnet.microsoft.com/download.
Install csharp-ls: dotnet tool install --global csharp-ls. Make sure ~/.dotnet/tools is on your PATH.
Configure your MCP client: This will be different but similar for each client. For Claude Desktop, add the following to ~/Library/Application\ Support/Claude/claude_desktop_config.json
{
"mcpServers": {
"language-server": {
"command": "mcp-language-server",
"args": [
"--workspace",
"/Users/you/dev/yourproject/",
"--lsp",
"csharp-ls"
]
}
}
}
<p><strong>Note</strong>: csharp-ls discovers your <code>.sln</code>/<code>.csproj</code> from the workspace root automatically; passing <code>-s /path/to/your.sln</code> as an extra argument is only needed for more complex, multi-solution repos.</p>
Other
I have only tested this repo with the servers above but it should be compatible with many more. Note:
- The language server must communicate over stdio.
- Any aruments after
--are sent as arguments to the language server. - Any env variables are passed on to the language server.
definition: Retrieves the complete source code definition of any symbol (function, type, constant, etc.) from your codebase.references: Locates all usages and references of a symbol throughout the codebase.diagnostics: Provides diagnostic information for a specific file, including warnings and errors.hover: Display documentation, type hints, or other hover information for a given location.rename_symbol: Rename a symbol across a project.edit_file: Allows making multiple text edits to a file based on line numbers. Provides a more reliable and context-economical way to edit files compared to search and replace based edit tools.workspace_symbol: Search the entire workspace for symbols matching a query, without needing to know which file they live in.implementation: Find every type or method that implements an interface (or interface method) — the only reliable way to enumerate an interface's satisfaction set in structurally-typed languages like Go and TypeScript.call_hierarchy: List direct callers and callees of a function or method, for refactor impact analysis and data-flow tracing.
This codebase makes use of edited code from gopls to handle LSP communication. See ATTRIBUTION for details. Everything here is covered by a permissive BSD style license.
mcp-go is used for MCP communication. Thank you for your service.
This is beta software. Please let me know by creating an issue if you run into any problems or have suggestions of any kind.
Please keep PRs small and open Issues first for anything substantial. AI slop O.K. as long as it is tested, passes checks, and doesn't smell too bad.
Clone the repo:
git clone https://github.com/isaacphi/mcp-language-server.git
cd mcp-language-serverA justfile is included for convenience:
just -l
Available recipes:
build # Build
check # Run code audit checks
fmt # Format code
generate # Generate LSP types and methods
help # Help
install # Install locally
snapshot # Update snapshot tests
test # Run testsConfigure your Claude Desktop (or similar) to use the local binary:
{
"mcpServers": {
"language-server": {
"command": "/full/path/to/your/clone/mcp-language-server/mcp-language-server",
"args": [
"--workspace",
"/path/to/workspace",
"--lsp",
"language-server-executable"
],
"env": {
"LOG_LEVEL": "DEBUG"
}
}
}
}Rebuild after making changes.
Setting the LOG_LEVEL environment variable to DEBUG enables verbose logging to stderr for all components including messages to and from the language server and the language server's logs.
Every MCP tool call is observed centrally and summarized to stderr at INFO level, e.g.:
[INFO][tools] tool call: name=definition ok=true duration_ms=2 args_bytes=22 result_bytes=150
These summaries never include file contents — only the tool name, success, duration and payload sizes.
For full structured telemetry, set MCP_TRAJECTORY_FILE to a path and the server writes an ATIF (Agent Trajectory Interchange Format) document, with one step per tool call (tool_calls + observation, including per-call duration_ms). LLM-side fields (model, tokens, cost) are not visible to this server and are omitted.
| Variable | Default | Description |
|---|---|---|
MCP_TRAJECTORY_FILE |
(unset) | Path to write the ATIF trajectory. When unset, only the summary logs above are emitted. |
MCP_TRAJECTORY_MAX_CONTENT |
4096 |
Max characters kept per argument/result value in the trajectory file (longer values are truncated). |
MCP_TRAJECTORY_MAX_STEPS |
10000 |
Cap on steps retained in memory / written, to bound memory on long-running servers. |
When the server registers file watchers, it can eagerly open every workspace file. This is required by some language servers (typescript-language-server, rust-analyzer) to resolve cross-file features, but is unnecessary and slow for servers that index from disk (gopls, pyright). The behavior is auto-detected per language server and can be forced with MCP_PREOPEN_FILES:
| Variable | Default | Description |
|---|---|---|
MCP_PREOPEN_FILES |
(auto) | true/false to force or disable eagerly opening all workspace files. Auto disables it for gopls/pyright and enables it otherwise. |
The server can shut itself down automatically after a period with no MCP requests (useful if you run several persistent language-server instances and want unused ones to free their resources). Disabled by default.
{
"mcpServers": {
"language-server": {
"command": "/full/path/to/your/clone/mcp-language-server/mcp-language-server",
"args": [
"--workspace",
"/path/to/workspace",
"--lsp",
"language-server-executable",
"--idle-timeout",
"15m"
]
}
}
}| Flag / Env var | Default | Description |
|---|---|---|
--idle-timeout / MCP_IDLE_TIMEOUT |
0 (disabled) |
Shut down after this long with no MCP requests (e.g. 15m, 1h). The flag takes precedence if both are set. |
internal/lsp/methods.gocontains generated code to make calls to the connected language server.internal/protocol/tsprotocol.gocontains generated code for LSP types. I borrowed this fromgopls's source code. Thank you for your service.- LSP allows language servers to return different types for the same methods. Go doesn't like this so there are some ugly workarounds in
internal/protocol/interfaces.go.
There is a snapshot test suite that makes it a lot easier to try out changes to tools. These run actual language servers on mock workspaces and capture output and logs.
You will need the language servers installed locally to run them. There are tests for go, rust, python, typescript, clangd (C/C++), and csharp-ls (C#).
integrationtests/
├── tests/ # Tests are in this folder
├── snapshots/ # Snapshots of tool outputs
├── test-output/ # Gitignored folder showing the final state of each workspace and logs after each test run
└── workspaces/ # Mock workspaces that the tools run on
To update snapshots, run UPDATE_SNAPSHOTS=true go test ./integrationtests/...
