Content
<p align="center">
<img width="420" alt="semctx - Semantic code context for AI agents" src="https://github.com/user-attachments/assets/aafca8a1-ca9f-4569-973e-d9eeddc44231" />
<p align="center"><b>Semantic code context</b> for AI agents, via LSP and LSIF.</p>
</p>
Imagine you're working on an AI agent that has to make sense of tangled codebases. Every time it needs to figure out a symbol or follow a reference, it burns through tokens on endless searches and wild guesses. That's where **semctx** comes in - a way to hook AI agents straight into the semantic side of code via LSP servers and LSIF dumps. Instead of telling your agent to rummage through repos, guess relationships, or fake editor behavior, it just asks the language server or LSIF index for the right answer, turning hover, definition, references, diagnostics, symbols, and code actions into clean tool calls and ditching the heavy prompts for raw repo digging.
The idea is simple: expose official LSP through MCP, no made-up stuff. You pick your LSP servers, tie languages to the current workspace, and **semctx** handles sessions, transports, capability talks, document syncing, and routing. Result? A better workflow for AI, with clearer context, less junk, and fewer errors, all from the same protocols editors use.
##### Table of contents:
- [What It Does](#what-it-does)
- [Why (AI Agents Care)](#why-ai-agents-care)
- [For Agent Builders](#for-agent-builders)
- [AGENTS.md Template](#agentsmd-template)
- [Requirements](#requirements)
- [Usage](#usage)
- [MCP Client configuration](#mcp-client-configuration)
- [Configuration](#configuration)
- [MCP Tool Surface](#mcp-tool-surface)
- [Request Conventions](#request-conventions)
- [Behavior Notes](#behavior-notes)
- [License](#license)
> [!WARNING]
> **semctx** is still pre-v1. Expect breaking changes while the tool surface, config schema, and payload shapes settle.
> If you're wiring it into an MCP host or agent workflow, pin a specific version and review changes before upgrading.
## What It Does
**semctx** links MCP to LSP servers over stdio, tcp, or unix. It supports multiple languages in one workspace, letting agents tap into semantic editor features without endless text searches. It pulls key LSP language and workspace features into MCP tools that focus on reading and planning edits (like rename and format) which give you the changes but don't run them.
For offline stuff, it works with LSIF dumps, grabbing hover info, navigation, documents, diagnostics, semantic tokens, and project views from local JSONL files. If you add related dumps, it handles cross-dump links and references. Results are structured and to the point, with excerpts for ranges, paging for big queries, context for position requests, and previews for code actions, hence you can spot-check code without pulling in whole files.
It checks server capabilities and fails cleanly if something's not supported. It's read-only on purpose: plans renames and formats but doesn't apply edits, run commands, or mess with files. It also has helpers for binding resolution alongside the LSP and LSIF tools.
## Why (AI Agents Care)
It's annoying to make an agent scrape a repo for info the language server already has. **semctx** helps you get precise context for definitions, references, symbols, diagnostics, and fixes, without stuffing prompts with full files. It saves tokens by giving focused protocol answers instead of messy search noise, cuts hallucination risk with spec-backed LSP or LSIF replies, and lets you flip between live LSP for active editing and LSIF for offline, pre-built indexes.
## For Agent Builders
No more "search the repo to crack this symbol". With **semctx**, you run a tight semantic loop:
1. Call `resolve_language_binding` to set the session for your language.
2. Use `go_to_definition` for the symbol you want. Add `source: "lsif"` or `indexPath` when you want the offline LSIF path.
3. Grab the next bit of detail with `hover`, `find_all_references`, `document_symbols`, or `diagnostics`.
4. Read files only when you need the deep implementation.
5. Use `code_actions`, `rename_symbol`, `format_document`, and `format_range` to inspect suggested changes without giving the agent edit rights.
**semctx** wraps LSP and LSIF results in a small metadata layer, with excerpts for range outputs when it can. Agents see the raw protocol under `result`, but the `context` usually lets you skip extra reads. Big queries add paging and groups; code actions have previews; hover calls give request context.
This keeps prompts short, saves compute for actual thinking (token-efficient), and relies on protocol facts over guesses.
### AGENTS.md Template
If you're adding **semctx** instructions to other repos for agents, start with [AGENTS.template.md](AGENTS.template.md). It's the source template: put it in the repo root as `AGENTS.md`, add your project's commands and notes, and stick to the semctx-first flow so agents check semantic facts before searching files.
## Requirements
You need:
1. Go 1.26.1 or later (optional; only if installing/building from source)
2. An LSP server reachable via stdio, tcp, or unix
3. An MCP host for stdio servers
## Usage
**semctx** is an MCP stdio server, launched by an MCP host. Add the following config to your MCP client:
```json
{
"mcpServers": {
"semctx": {
"command": "go",
"args": ["run", "go.dw1.io/semctx/cmd/semctx@v0.1.0"],
"env": {
"SEMCTX_CONFIG": "./.semctx.yaml"
}
}
}
}
```
If you self-host **semctx** from a release or local build, point your MCP client at the binary instead:
```json
{
"mcpServers": {
"semctx": {
"command": "/path/to/semctx",
"env": {
"SEMCTX_CONFIG": "./.semctx.yaml"
}
}
}
}
```
### MCP Client configuration
Use the standard config above in any MCP host that supports local stdio MCP servers.
<details>
<summary>Amp</summary>
Follow the [Amp MCP docs](https://ampcode.com/manual#mcp) and use the standard config above.
If you prefer the CLI, add `semctx` first and then adjust the saved server config if you want an explicit `SEMCTX_CONFIG` path instead of the default `./.semctx.yaml`.
</details>
<details>
<summary>Antigravity</summary>
Follow the [Antigravity MCP docs](https://antigravity.google/docs/mcp) to add a custom MCP server, then paste in the standard config above.
</details>
<details>
<summary>Claude Code</summary>
Follow the [Claude Code MCP guide](https://code.claude.com/docs/en/mcp) and use the standard config above.
You can also add it from the CLI when `./.semctx.yaml` is present in the current workspace:
```bash
claude mcp add semctx --scope user go run go.dw1.io/semctx/cmd/semctx@v0.1.0
```
If you prefer a local build, change `command` to `/path/to/semctx` and keep `SEMCTX_CONFIG` pointed at your config file.
</details>
<details>
<summary>Cline</summary>
Follow the [Cline MCP docs](https://docs.cline.bot/mcp/configuring-mcp-servers) and use the standard config above.
</details>
<details>
<summary>Codex</summary>
Follow the [Codex MCP guide](https://developers.openai.com/codex/mcp/#configure-with-the-cli) and use the standard config above.
You can also add it from the CLI when you are using the default workspace config path:
```bash
codex mcp add semctx -- go run go.dw1.io/semctx/cmd/semctx@v0.1.0
```
If you keep Codex config in `.codex/config.toml`, translate the same `command`, `args`, and `env` values into that file.
</details>
<details>
<summary>Command Code</summary>
Follow the [Command Code MCP docs](https://commandcode.ai/docs/mcp) or add it from the CLI:
```bash
cmd mcp add semctx --scope user go run go.dw1.io/semctx/cmd/semctx@v0.1.0
```
</details>
<details>
<summary>Copilot CLI</summary>
Start Copilot CLI, run `/mcp add`, choose a local MCP server, and use the standard config above.
If the prompt only accepts a command string, use `go run go.dw1.io/semctx/cmd/semctx@v0.1.0` and rely on `./.semctx.yaml` in the current workspace.
</details>
<details>
<summary>Copilot / VS Code</summary>
Follow the [VS Code MCP configuration guide](https://code.visualstudio.com/docs/copilot/chat/mcp-servers#_add-an-mcp-server) and use the standard config above.
For macOS and Linux, you can also add it from the CLI:
```bash
code --add-mcp '{"name":"semctx","command":"go","args":["run","go.dw1.io/semctx/cmd/semctx@v0.1.0"],"env":{"SEMCTX_CONFIG":"./.semctx.yaml"}}'
```
</details>
<details>
<summary>Cursor</summary>
Go to `Cursor Settings` -> `MCP` -> `New MCP Server` and use the standard config above.
If you self-host `semctx`, replace the `go run ...` command with `/path/to/semctx`.
</details>
<details>
<summary>Factory CLI</summary>
Follow the [Factory CLI MCP docs](https://docs.factory.ai/cli/configuration/mcp) or add it directly:
```bash
droid mcp add semctx "go run go.dw1.io/semctx/cmd/semctx@v0.1.0"
```
</details>
<details>
<summary>Gemini CLI</summary>
Follow the [Gemini CLI MCP guide](https://github.com/google-gemini/gemini-cli/blob/main/docs/tools/mcp-server.md#how-to-set-up-your-mcp-server) and use the standard config above.
Project-scoped and user-scoped installs work well when you keep `.semctx.yaml` in the current workspace:
```bash
gemini mcp add semctx go run go.dw1.io/semctx/cmd/semctx@v0.1.0
gemini mcp add -s user semctx go run go.dw1.io/semctx/cmd/semctx@v0.1.0
```
</details>
<details>
<summary>Gemini Code Assist</summary>
Follow the [Gemini Code Assist MCP guide](https://cloud.google.com/gemini/docs/codeassist/use-agentic-chat-pair-programmer#configure-mcp-servers) and use the standard config above.
</details>
<details>
<summary>JetBrains AI Assistant & Junie</summary>
Go to `Settings | Tools | AI Assistant | Model Context Protocol (MCP)` -> `Add` and use the standard config above.
The same setup works for Junie in `Settings | Tools | Junie | MCP Settings` -> `Add`.
</details>
<details>
<summary>Kiro</summary>
In `Kiro Settings`, go to `Configure MCP` and open the workspace or user MCP config, then paste in the standard config above.
You can also open MCP config from the Kiro activity bar and use the same server definition there.
</details>
<details>
<summary>Katalon Studio</summary>
Katalon StudioAssist expects an MCP proxy for stdio servers. Start a proxy in front of `semctx`:
```bash
mcp-proxy --transport streamablehttp --port 8080 -- go run go.dw1.io/semctx/cmd/semctx@v0.1.0
```
Then add `http://127.0.0.1:8080/mcp` in StudioAssist as an HTTP MCP server.
</details>
<details>
<summary>Mistral Vibe</summary>
Add this to `~/.vibe/config.toml`:
```toml
[[mcp_servers]]
name = "semctx"
transport = "stdio"
command = "go"
args = ["run", "go.dw1.io/semctx/cmd/semctx@v0.1.0"]
```
</details>
<details>
<summary>OpenCode</summary>
Add this to `~/.config/opencode/opencode.json` or your existing OpenCode config:
```json
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"semctx": {
"type": "local",
"command": ["go", "run", "go.dw1.io/semctx/cmd/semctx@v0.1.0"]
}
}
}
```
</details>
<details>
<summary>Qoder</summary>
In `Qoder Settings`, go to `MCP Server` -> `+ Add` and use the standard config above.
You can also follow the [Qoder MCP guide](https://docs.qoder.com/user-guide/chat/model-context-protocol).
</details>
<details>
<summary>Qoder CLI</summary>
Add `semctx` with the Qoder CLI:
```bash
qodercli mcp add semctx -- go run go.dw1.io/semctx/cmd/semctx@v0.1.0
qodercli mcp add -s user semctx -- go run go.dw1.io/semctx/cmd/semctx@v0.1.0
```
</details>
<details>
<summary>Visual Studio</summary>
Use Visual Studio MCP server settings and paste in the standard config above.
If you prefer a proxy or wrapper executable, point Visual Studio at that command instead.
</details>
<details>
<summary>Warp</summary>
Go to `Settings | AI | Manage MCP Servers` -> `+ Add` and use the standard config above.
</details>
<details>
<summary>Windsurf</summary>
Follow the [Windsurf MCP guide](https://docs.windsurf.com/windsurf/cascade/mcp#mcp-config-json) and use the standard config above.
</details>
By default, **semctx** looks for `./.semctx.yaml` in the current workspace. You can also point it at a custom config path with `-config` or `SEMCTX_CONFIG`.
Internal logging is off by default so MCP stdio sessions stay quiet unless you're debugging. Enable it with `-log-level` or `SEMCTX_LOG_LEVEL` using one of `debug`, `info`, `warn`, `error`, or `off`. When logging is enabled, **semctx** always writes to stderr and will also append to `-log-file` or `SEMCTX_LOG_FILE` when you want a persistent log.
Example:
```json
{
"mcpServers": {
"semctx": {
"command": "/path/to/semctx",
"env": {
"SEMCTX_CONFIG": "./.semctx.yaml",
"SEMCTX_LOG_LEVEL": "debug",
"SEMCTX_LOG_FILE": "./.semctx/semctx.log"
}
}
}
}
```
> [!NOTE]
> If no **semctx** config is provided, it looks for `./.semctx.yaml` in the current workspace. If that file is not present, **semctx** still starts, but LSP tools need configured sessions before they can do useful work.
## Configuration
Config is YAML. Basics:
- `servers` for LSP server connections.
- `defaults` for shared rules across bindings.
- `languages` to map languages to servers.
- `transport.kind` as stdio, tcp, or unix.
- Relative config paths resolve from the current workspace root.
- LSP server launch directories default to the current workspace root.
- Bindings active unless `disabled` is true.
- Files in .yaml or .yml.
- Auto-finds `./.semctx.yaml` in the current workspace when no path is provided.
- LSP client info from **semctx** name and version, not customizable.
Example:
```yaml
defaults:
diagnosticsMode: auto
connectionTimeout: 10s
servers:
gopls:
transport:
kind: stdio
stdio:
command: gopls
args:
- serve
env:
GOFLAGS: -tags=integration
languages:
go:
server: gopls
initializationOptions:
gofumpt: true
```
Transport needs:
- stdio: `stdio.command`; args optional.
- tcp: `tcp.address`.
- unix: `unix.path`.
Startup validates: rejects bad keys, missing refs, incomplete transports, invalid modes.
## MCP Tool Surface
These tools are the key: agents use them directly instead of rebuilding language logic from searches.
<details>
<summary>1. Configuration and Binding Resolution</summary>
- `resolve_language_binding`: gets the session for your language.
</details>
<details>
<summary>2. Navigation and Hierarchies</summary>
- `hover`
- `go_to_declaration`
- `go_to_definition`
- `go_to_type_definition`
- `find_all_implementations`
- `find_all_references`
- `show_call_hierarchy`
- `show_call_hierarchy_incoming_calls`
- `show_call_hierarchy_outgoing_calls`
- `show_type_hierarchy`
- `show_type_hierarchy_supertypes`
- `show_type_hierarchy_subtypes`
- `document_highlights`
- `monikers`
</details>
<details>
<summary>3. Symbols, Links, Completion, and Structure</summary>
- `document_symbols`
- `folding_ranges`
- `document_links`
- `resolve_document_link`
- `code_lenses`
- `resolve_code_lens`
- `selection_ranges`
- `semantic_tokens`
- `semantic_tokens_delta`
- `semantic_tokens_range`
- `inline_values`
- `inlay_hints`
- `resolve_inlay_hint`
- `completions`
- `resolve_completion_item`
- `signature_help`
- `workspace_symbols`
- `resolve_workspace_symbol`
</details>
<details>
<summary>4. Diagnostics and Suggested Fixes</summary>
- `diagnostics`
- `workspace_diagnostics`
- `code_actions`
- `resolve_code_action`
- `document_colors`
- `color_presentations`
</details>
<details>
<summary>5. Edit Planning</summary>
- `prepare_rename`
- `rename_symbol`
- `format_document`
- `format_range`
</details>
<details>
<summary>6. LSIF Offline Queries</summary>
- `find_containing_projects`
</details>
## Request Conventions
For document tools:
- `source` may be `lsp` or `online` for live workspace queries, `lsif` or `offline` for local-dump queries, or omitted to auto-select LSIF when `indexPath` is present and LSP otherwise.
- `language` is your configured language id for live LSP requests.
- `path` can be absolute or relative to the current workspace root; `uri` works too.
- `indexPath` points at the primary LSIF JSONL dump for offline requests, and `relatedIndexPaths` adds extra dumps for cross-dump links.
- Positions stay zero-based.
- Big tools like references and implementations take `limit` and `offset` for paging.
For LSP-only planning and workspace tools:
- Rename sends `newName`, returns LSP WorkspaceEdit.
- Formatting sends FormattingOptions, returns TextEdit array.
- Workspace diagnostics take `identifier` and `previousResultIds`, return report.
For the LSIF-only project tool:
- `indexPath` points at the primary LSIF JSONL dump.
- `relatedIndexPaths` adds extra dumps for cross-dump links.
- `uri` is preferred for docs; `path` resolves from the current workspace root.
One live binding? Skip `language` where allowed. Multiple? Send it.
## Behavior Notes
**semctx** checks LSP capabilities at init, runs tools only if supported. Handles server requests for config and folders. Acknowledges refreshes for `codeLens`, `semanticTokens`, etc. Rejects `applyEdit` (it's read-only). No vendor extensions.
## License
**semctx** is released with ♡ by [**@dwisiswant0**](https://github.com/dwisiswant0) under the Apache License 2.0. See the [LICENSE](LICENSE) file for details.
MCP Config
Below is the configuration for this MCP Server. You can copy it directly to Cursor or other MCP clients.
mcp.json
Connection Info
You Might Also Like
everything-claude-code
Complete Claude Code configuration collection - agents, skills, hooks,...
markitdown
MarkItDown-MCP is a lightweight server for converting URIs to Markdown.
cc-switch
All-in-One Assistant for Claude Code, Codex & Gemini CLI across platforms.
servers
Model Context Protocol Servers
servers
Model Context Protocol Servers
Time
A Model Context Protocol server for time and timezone conversions.