Semantic JS MCP
Provides structured semantic context for JavaScript/TypeScript codebases, enabling coding agents to navigate, review, and change code with explicit uncertainty.
README
Semantic JS MCP
Your coding agent is only as good as its understanding of your codebase.
Coding agents can generate code quickly, but reliable engineering requires more than reading files and matching text. They need to understand which declaration a reference belongs to, how symbols cross workspace boundaries, whether the collected evidence is complete, and whether that evidence is still accurate.
Semantic JS MCP gives coding agents structured, read-only semantic context so they can navigate, review, and change code with explicit uncertainty.
Better agents begin with better evidence.
It supports the JavaScript ecosystem, including TypeScript, JavaScript, TSX, JSX, Node module variants, and Vue projects. Language servers provide the underlying semantic data, which the server turns into structured results designed for coding agents.
For each file, it identifies the owning workspace and uses the corresponding TypeScript or Vue language server. Across the repository, it can distinguish verified references from unrelated or unresolved text matches. These results complement text search, source inspection, and focused tests.
Project Status
Version 0.8.1 is the current release. APIs and result contracts may evolve while the project remains on the 0.x release line. See the roadmap for areas under consideration.
Installation
Codex plugin
Add the public marketplace, then install the plugin:
codex plugin marketplace add elnonathan/semantic-js-mcp
codex plugin add semantic-js-mcp@elnonathan
Codex CLI 0.144.4 or newer is required for npm-backed marketplace installation. Start a new Codex session after installation. The plugin bundles both the MCP server configuration and the semantic-navigation skill.
MCP executable
Install the package globally when using an MCP host that accepts a command-based stdio configuration:
npm install --global semantic-js-mcp
semantic-js-mcp doctor
Configure the host to run semantic-js-mcp serve.
Runtime
- Node.js 22 or newer is supported.
- Node.js 24 LTS is recommended for new installations. See the Node.js release schedule.
rg(ripgrep) must be available onPATHfor repository-wide discovery.- The nearest workspace TypeScript SDK is used when available; the bundled TypeScript SDK is the fallback.
- TypeScript,
typescript-language-server, and the Vue language server are pinned dependencies. Published packages bundle every production dependency so Codex installations do not require a separate dependency installation step. Source checkouts usenpm ci; startup verifies provider entry points before accepting MCP requests. - Source discovery and language selection include
.ts,.tsx,.mts,.cts,.js,.jsx,.mjs,.cjs, and.vuefiles. - Run
npm run check:runtimeto report every required component and its resolved file path.
The package exposes a semantic-js-mcp executable. semantic-js-mcp serve starts the stdio MCP server, and semantic-js-mcp doctor verifies the installed Node runtime, ripgrep, resolved provider paths, MCP startup, tool discovery, TypeScript reference accounting, diagnostic freshness, and Vue navigation.
Development Setup
From a source checkout:
npm ci
npm run check
npm run check:runtime
npm run doctor
npm run smoke:ci
npm run smoke
npm run smoke:vue
Run npm run benchmark after changes to scanning, references, caching, lifecycle, or memory. Normal analysis is local and read-only; it does not require network access after dependencies are installed.
For an MCP host that accepts a direct stdio configuration, point it at the checked-out server using an absolute path:
{
"mcpServers": {
"semantic-js-mcp": {
"command": "node",
"args": ["/absolute/path/to/semantic-js-mcp/server.mjs"]
}
}
}
The bundled .mcp.json provides the relative-path configuration used when the repository is installed as a Codex plugin.
When the package executable is available on the host's PATH, the equivalent stdio configuration is:
{
"mcpServers": {
"semantic-js-mcp": {
"command": "semantic-js-mcp",
"args": ["serve"]
}
}
}
Tool Graph
Tools are ordered from smaller responses to deeper evidence:
| Tool | Provides | Typical continuation |
|---|---|---|
lsp_document_symbols |
Structure for one file | lsp_definition, lsp_audit_symbol |
lsp_workspace_symbols |
Symbol-name discovery | lsp_count_named_symbol, lsp_audit_named_symbol |
lsp_definition |
Definition resolution at a position | lsp_hover, lsp_count_references |
lsp_hover |
Inferred type and documentation | lsp_definition, lsp_audit_symbol |
lsp_diagnostics |
Focused diagnostics for one file | lsp_definition, lsp_hover |
lsp_count_text_matches |
Exact identifier text count without semantic verification | lsp_count_named_symbol, lsp_audit_named_symbol |
lsp_count_named_symbol |
Definition and reference counts by name | lsp_audit_named_symbol, lsp_references |
lsp_count_references |
Reference counts at a position | lsp_audit_symbol, lsp_references |
lsp_audit_named_symbol |
Composed summary by symbol name | lsp_references |
lsp_audit_symbol |
Composed summary at a position | lsp_references |
lsp_references |
First page of verified locations | lsp_reference_page |
lsp_reference_page |
A later page from the same collection | lsp_definition |
lsp_unresolved_reference_page |
Unresolved candidates with locations and literal reasons | lsp_definition |
Composite audits reuse the same internal definition, hover, and reference primitives as the narrow tools. Compatible count, audit, and reference calls reuse a short-lived reference set.
Result Contract
Every successful result contains:
server: the literal semantic-js-mcp server name and version that produced the response.resultSchema: the literal canonical result schema name and version.request: normalized inputs and explicit limit interpretation.result: evidence produced by the tool.collection: how evidence collection completed.presentation: how much collected evidence appears in this response.continueWith: exact MCP tool names that can add the next kind of evidence.
structuredContent is the canonical JSON object. The text content is YAML generated from that same object and parses back to the same data.
Collection status
complete: the requested collection scope completed and every discovered item was classified.limited: a suppliedmaxCandidatesormaxDefinitionsvalue stopped collection.partial: collection completed with explicitly reported items whose definition or owning file could not be resolved.failed: the tool call failed and the error object explains why.
Collection and presentation are independent. A complete collection may use presentation.mode: page, count-only, summary-by-file, or subset without weakening its counts.
For reference results, includeDeclaration: false excludes locations that resolve to the requested declaration. It never excludes the source position merely because that position initiated the query. The reported invariant is verifiedTotal = foundByOwningWorkspaceLanguageServer + verifiedFromOtherWorkspaces after declaration filtering and deduplication.
Vue template definitions
Definition lookup uses the Vue language server and TypeScript server first. If both leave a Vue template tag unresolved, the server parses the SFC and follows only a matching local import from <script> or <script setup>. A successful fallback reports resolutionMethod: vue-template-import-binding-definition. This proves an imported component binding; it does not infer global component registration or filename-based identity.
The Vue parser and TypeScript AST dependencies are loaded lazily only when this fallback is needed.
Signature source
Position audits first request hover information at the query position. If that position has a resolved definition but no hover information, the audit requests hover at the resolved declaration. signatureSource reports query-position-hover, resolved-definition-hover, or not-reported; signatureDefinition identifies the declaration used by the fallback.
Limits
Collection limits accept positive integers only:
- omitted:
{mode: unlimited} - supplied:
{mode: maximum, maximum: N}
Omitting maxCandidates or maxDefinitions requests unlimited collection. pageSize and maxResults only control returned items for tools that expose them as presentation parameters.
Text-match accounting
Repository verification reports:
matchesFoundmatchesCheckedmatchesToRequestedSymbolmatchesToDifferentSymbolsmatchesWhoseDefinitionCouldNotBeResolvedaccountingStatus: complete | incomplete
accountingStatus: complete means every discovered text match appears in exactly one classification. Unresolved matches remain explicit and make semantic collection partial.
Count and audit responses expose the referenceSetId and unresolved-candidate count. Use lsp_unresolved_reference_page to inspect those candidates without inflating every summary. The server also queries tsserver projectInfo for unresolved candidates and reports whether the file belongs to a configured or inferred TypeScript project. Reasons describe only observed behavior; they do not speculate that an alias caused a failure.
Freshness
Reusable reference sets store SHA-256 fingerprints for the source file, native reference files, every cross-workspace candidate file, and the relevant package.json, tsconfig.json, or jsconfig.json files. They also store a repository source-inventory fingerprint built from every relevant path, file size, and high-resolution modification time. Reuse and pagination verify both layers, so new, deleted, renamed, or normally modified source files invalidate repository-wide completeness. Changed evidence produces REFERENCE_SET_CONTENT_CHANGED and requires a new lsp_references collection. Expired or evicted sets produce REFERENCE_SET_NOT_FOUND_OR_EXPIRED.
The inventory is sampled before and after collection. If repository sources change during collection, the server retries once and then returns REPOSITORY_CHANGED_DURING_COLLECTION instead of publishing an unstable result.
Diagnostics clear their cache on didChange and report the analyzed document version and SHA-256 content fingerprint. Only a language-server report for that exact document version appears under diagnosticsForCurrentDocument. Otherwise that field is null, evidence.status is untrusted, and any unconfirmed report is isolated under unconfirmedDiagnosticReport. Untrusted diagnostics always produce a partial collection.
Diagnostic severities are preserved literally. If a language server omits severity, the result reports not-reported; it is not silently treated as information, warning, or error.
CI policy adapter
MCP tools report evidence; they do not decide whether a code change passes. npm run ci:evaluate -- <result.json> applies a deterministic CI policy to one canonical structured result:
pass, exit0: complete evidence and no verified error diagnostic.fail, exit1: verified diagnostics contain an error.untrusted, exit2: collection is partial or limited.blocked, exit3: the tool failed or the input is not a semantic-js-mcp result.
Pass --yaml after the input path for a YAML representation. The adapter accepts canonical JSON or YAML, validates the server and result-schema identity plus public tool and presentation literals, and never converts incomplete evidence into a pass.
Installation doctor
semantic-js-mcp doctor returns a structured installation report with the same deterministic status vocabulary and exit codes as the CI adapter:
pass, exit0: every installation and semantic fixture check passed;fail, exit1: the server ran, but a functional check returned the wrong result;untrusted, exit2: runtime checks passed, but a provider did not confirm current diagnostic evidence;blocked, exit3: a runtime requirement, provider component, or MCP startup step was unavailable.
Use semantic-js-mcp doctor --yaml for a YAML representation. An untrusted result is not converted to a package failure by the distribution smoke test, but the reason remains explicit in the report.
Cost visibility
lsp_count_text_matches scans repository text without issuing per-match semantic requests. Use it to measure common identifiers before requesting verified counts or audits. Semantic collections preserve omitted limits as unlimited and report text-search time, semantic-verification time, semantic request count, and maximum concurrency. There is no hidden candidate cap.
The bundled Codex MCP configuration allows up to 300 seconds for one tool call. Reaching a client or language-server timeout returns a failed call; it never changes collection scope or reports a timed-out collection as complete.
Memory Management
Language-server clients and reusable reference sets are released automatically using idle timeout, TTL, and LRU policies. These policies affect reuse only; they do not cap a collection being computed.
Environment variables:
SEMANTIC_JS_MCP_CLIENT_IDLE_TIMEOUT_MSdefault60000SEMANTIC_JS_MCP_CLIENT_MINIMUM_EVICTION_AGE_MSdefault15000SEMANTIC_JS_MCP_MAXIMUM_ACTIVE_CLIENTSdefault4SEMANTIC_JS_MCP_REFERENCE_SET_TTL_MSdefault300000SEMANTIC_JS_MCP_MAXIMUM_REFERENCE_SETSdefault12SEMANTIC_JS_MCP_MAXIMUM_CHANGED_REFERENCE_SET_MARKERSdefault24SEMANTIC_JS_MCP_MAXIMUM_CACHED_REFERENCE_LOCATIONSdefault50000SEMANTIC_JS_MCP_DEFAULT_REFERENCE_PAGE_SIZEdefault100SEMANTIC_JS_MCP_CROSS_WORKSPACE_CONCURRENCYdefault6
A single reference collection may exceed the cache-location budget so it can still be paged. Older collections are evicted first.
Verification
npm run check
npm run check:runtime
npm run doctor
npm run smoke
npm run smoke:ci
npm run smoke:vue
npm run smoke:distribution
npm run benchmark measures text counting, verified reference collection, memory, and freshness-validation latency at configurable match counts. Set SEMANTIC_JS_MCP_BENCHMARK_COUNTS=10,100,1000,10000 to include the 10,000-match scale.
npm run smoke:distribution packs the explicit npm file allowlist, installs the tarball into a temporary consumer project, runs the installed executable, and verifies that runtime components resolve from the consumer dependency tree rather than the source checkout.
The smoke tests create temporary generic TypeScript and Vue projects. They do not depend on a specific application repository.
Current Limitations
- The server provides static semantic evidence, not runtime call tracing or behavioral proof.
- Empty references and clean diagnostics do not establish absence or correctness.
- Vue named-component discovery remains ambiguous when filenames, component names, import aliases, global registration, and test doubles differ. Prefer a position-based audit when an exact use is available.
- Diagnostics remain
untrustedwhen the owning language server does not correlate a report with the current document version. - Dynamic imports, computed property access, generated code, runtime dependency injection, and dynamically constructed class names may require text search and direct source inspection.
- CSS graph analysis, Tailwind semantics, and other language domains are intentionally outside this project. Provider-native diagnostics embedded in Vue documents may still be preserved.
Roadmap
See ROADMAP.md for planned areas of development. Roadmap items describe direction, not release commitments.
Project Documents
Maintainer
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。
mcp-server-qdrant
这个仓库展示了如何为向量搜索引擎 Qdrant 创建一个 MCP (Managed Control Plane) 服务器的示例。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。