versions-le-mcp
v1.1.0
Published
Find where one dependency is constrained differently across a repository's manifests.
Maintainers
Readme
versions-le-mcp
An MCP server that compares the version
constraints in a set of manifests — package.json, Cargo.toml,
pyproject.toml, go.mod and GitHub workflows — and reports where one
dependency is constrained differently, and where two constraints cannot both
be satisfied by any version. It is the engine behind the
Versions-LE editor extension, exposed
as a tool an agent can call.
Comparison never crosses an ecosystem. An npm semver and a Cargo
semver are unrelated packages that share a word, and a bare "1.0.200" means
exactly that version in npm and anything below 2 in Cargo.
A constraint in a grammar it does not model is refused by name, never
approximated — a git or path specifier, a workspace inheritance, a PEP 440
compatible-release clause. It is reported in refusals and left out of every
comparison.
No dependencies, no network calls, no filesystem access. Content goes in, structured results come out.
Use it
Point any MCP host at npx versions-le-mcp.
Claude Code
claude mcp add versions-le -- npx -y versions-le-mcpAnything with a JSON config — Cursor, Windsurf, Claude Desktop:
{
"mcpServers": {
"versions-le": {
"command": "npx",
"args": ["-y", "versions-le-mcp"]
}
}
}VS Code needs nothing here. Install the extension instead — it carries this server and registers it for you: VS Code Marketplace · Open VSX
No Node? The same compare_versions tool ships in a static Rust binary:
cargo install versions-le, then versions-le mcp
(crates.io). The two servers answer
identically — one corpus runs against both, and a differential test feeds both
thousands of generated manifest sets, broken JSON and TOML included, and
compares every answer. The binary additionally offers versions_le_check,
which walks a tree; this server reads no files.
Prefer a global install to npx on every launch:
npm install -g versions-le-mcpNo environment variables, no API key, no configuration of its own. To check it before wiring it into anything:
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | npx -y versions-le-mcpIf that prints the tool name, the server works.
The tool
compare_versions
| argument | type | |
|---|---|---|
| files | { path, content }[] | required. The manifests. The path decides the grammar and labels every finding: package.json, Cargo.toml, pyproject.toml, go.mod, or a .yml/.yaml under .github/workflows/. |
| maxResults | number | Default 500, ceiling 5000. |
Findings are disjoint-constraint, malformed-constraint (errors),
constraint-conflict, msrv-mismatch, prerelease-in-production (warnings)
and floating-pin (info), each with every site that produced it. Refusals are
unknown_grammar, ambiguous_version_string, cross_ecosystem and
per_job_tool_version. A manifest that does not parse is a diagnostic, and
ok is false while one is present:
{
"ok": true,
"data": {
"schema": 1,
"manifests": [
{
"path": "api/Cargo.toml",
"ecosystem": "cargo",
"entries": 1
},
{
"path": "web/Cargo.toml",
"ecosystem": "cargo",
"entries": 1
}
],
"findings": [
{
"code": "disjoint-constraint",
"severity": "error",
"ecosystem": "cargo",
"name": "regex",
"message": "\"1\" (api/Cargo.toml) and \"2\" (web/Cargo.toml) cannot both be satisfied by one version",
"sites": [
{
"file": "api/Cargo.toml",
"key": "dependencies.regex",
"constraint": "1"
},
{
"file": "web/Cargo.toml",
"key": "dependencies.regex",
"constraint": "2"
}
]
}
],
"refusals": [],
"summary": {
"manifests": 2,
"entries": 2,
"findings": 1,
"refusals": 0,
"errors": 1,
"warnings": 0,
"infos": 0
}
},
"diagnostics": [],
"meta": {
"tool": "compare_versions",
"count": 1,
"truncated": false
}
}Also in the MCP registry
io.github.nolindnaidoo/versions-le —
registry.modelcontextprotocol.io
Fourteen more like it
One tool each, same shape: content in, structured data out, no network and no
filesystem. Every one is on npm as <name>-mcp and in the MCP registry as
io.github.nolindnaidoo/<name>.
| Package | Tool | Does |
|---|---|---|
| urls-le-mcp | extract_urls | URLs, with protocol and position |
| colors-le-mcp | extract_colors | colors from stylesheets and code |
| dates-le-mcp | extract_dates | dates and timestamps |
| numbers-le-mcp | extract_numbers | numeric values |
| paths-le-mcp | extract_paths | file and directory paths |
| string-le-mcp | extract_strings | string values |
| regex-le-mcp | extract_patterns | regexes, with a ReDoS verdict |
| secrets-le-mcp | detect_secrets | credentials, masked — never the value |
| envsync-le-mcp | compare_env_files | dotenv key drift, names only |
| scrape-le-mcp | analyze_robots_txt | whether a path may be crawled |
| unicode-le-mcp | detect_unicode_risks | Unicode that hides meaning, as codepoints |
| i18n-le-mcp | check_catalogues | translation catalogues, keys only |
| ids-le-mcp | extract_ids | UUIDs, ULIDs and Snowflakes, with the time inside |
| ips-le-mcp | extract_ips | IP addresses, CIDR blocks and MACs, normalized |
Every tool in the family, one page: letools.dev
Built by
Nolin Naidoo — Chief Engineer, AI/ML & Platform Architecture. nolindnaidoo.com · GitHub · LinkedIn
Also from the same workshop
Twelve Rust tools built the same way: small, single-purpose, and driven by a machine rather than a person. pixelcoords and pixelactions make up one loop — pixelcoords answers where, pixelactions acts there. The ten LE crates are the terminal half of the extensions they sit in: the same detection, held to the extension's own corpus, and an exit code instead of a results editor.
| | | | |---|---|---| | pixelcoords | Freeze your screen, mark regions, get pixel-exact coordinates and crops | site · crates.io · docs.rs | | pixelactions | Consume human-verified coordinates, perform the interaction, confirm it landed | site · crates.io · docs.rs | | paths-le | Find every path in a codebase and report whether it still points at anything | crates.io | | secrets-le | Find hardcoded credentials, and never print one | crates.io | | urls-le | Extract every URL from a codebase, with its protocol and exact position | crates.io | | regex-le | Find every regex in a codebase and report which can be driven into catastrophic backtracking | crates.io | | string-le | Get every string in a codebase out where a person can read them | crates.io | | numbers-le | Find every hardcoded number in a codebase so a person can check them | crates.io | | envsync-le | Compare the dotenv files in a tree and say which keys are missing from which | crates.io | | colors-le | Find every colour in a codebase, and say which are not in your palette | crates.io | | dates-le | Extract every date and timestamp, and the exact instant each one resolves to | crates.io | | scrape-le | Check whether a page is scrapeable before the scraper is written | crates.io |
Licence
MIT © Nolin Naidoo
