npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

units-le-mcp

v1.1.0

Published

Extract durations, sizes, percentages and frequencies in one base unit, refusing ambiguous ones.

Readme

units-le-mcp

An MCP server that finds every quantity in a document — a number welded to a unit — and returns it twice: as the document wrote it, and in one base unit so two of them can be compared. Durations come back in milliseconds, sizes in bytes, percentages as a ratio, frequencies in hertz, each with its line, column and key path. It is the engine behind the Units-LE editor extension, exposed as a tool an agent can call.

A quantity it cannot read unambiguously comes back with a named reason, never a guess. A bare 500m is minutes in one config format, milliseconds in another and millicores in Kubernetes, so it is returned as ambiguous_unit rather than as any of them. 1.5KB, 1,5s and 1h + 30m are refused the same way. 1MB is returned as 10^6 bytes, with a flag saying the writer may have meant 2^20. A bare number with no unit is not a finding.

No dependencies, no network calls, no filesystem access. Content goes in, structured results come out.

Use it

Point any MCP host at npx units-le-mcp.

Claude Code

claude mcp add units-le -- npx -y units-le-mcp

Anything with a JSON config — Cursor, Windsurf, Claude Desktop:

{
  "mcpServers": {
    "units-le": {
      "command": "npx",
      "args": ["-y", "units-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 extract_units tool ships in a static Rust binary: cargo install units-le, then units-le mcp (crates.io). The two servers answer identically — one corpus runs against both, and a differential test feeds both thousands of generated documents in every format, broken ones included, and compares every answer, parser errors and all. The binary additionally offers units_le_scan, which walks a tree; this server reads no files.

Prefer a global install to npx on every launch:

npm install -g units-le-mcp

No 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 units-le-mcp

If that prints the tool name, the server works.

The tool

extract_units

| argument | type | | |---|---|---| | content | string | required. The document text. | | format | json jsonc yaml csv tsv toml ini env | Optional. Anything else, or nothing, scans the text directly. | | filename | string | Used to infer the format when format is absent, e.g. config.toml. | | dimension | duration bytes percent frequency | Report only one. A refusal that names no dimension is always kept. | | maxResults | number | Default 500, from 1 to 5000. |

Refusals are ambiguous_unit, fractional_bytes, locale_separator, compound_arithmetic and out_of_range, each with a sentence a person can act on; si_iec_hazard accompanies a value rather than replacing it. A structured document that does not parse is a diagnostic in its parser's own words, and ok is false while one is present:

{
  "ok": true,
  "data": {
    "quantities": [
      {
        "value": "1h30m",
        "dimension": "duration",
        "baseUnit": "milliseconds",
        "base": "5400000",
        "key": "cache.ttl",
        "line": 2,
        "column": 8
      },
      {
        "value": "500m",
        "dimension": null,
        "baseUnit": null,
        "base": null,
        "reason": "ambiguous_unit",
        "detail": "`m` is minutes in one config format, milliseconds in another and millicores in Kubernetes. Write `min`, `ms`, or spell out the core count.",
        "key": "cpu",
        "line": 3,
        "column": 6
      }
    ],
    "fileType": "yaml",
    "refused": 1
  },
  "diagnostics": [],
  "meta": {
    "tool": "extract_units",
    "count": 2,
    "truncated": false
  }
}

Also in the MCP registry

io.github.nolindnaidoo/units-le — registry.modelcontextprotocol.io

Fifteen 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 | | versions-le-mcp | compare_versions | dependency constraints that disagree across manifests |

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