Extract every UUID, ULID, NanoID, ObjectId and Snowflake, and decode the time inside
- ✓Open-source license (MIT)
- ✓Actively maintained (<30d)
- ✓Clear description
- ✓Topics declared
- ✓Documented (README)
claude mcp add ids-le -- npx -y ids-le-mcp{
"mcpServers": {
"ids-le": {
"command": "npx",
"args": ["-y", "ids-le-mcp"]
}
}
}MCP Servers overview
<p align="center">
<img src="src/assets/images/icon.png" alt="IDs-LE Logo" width="96" height="96"/>
</p>
<h1 align="center">IDs-LE: The ID That Only Looks Like One</h1>
<p align="center">
<b>Find every identifier in a document, decode the time inside it, and refuse the ones that cannot be named</b><br/>
<i>UUID · ULID · NanoID · MongoDB ObjectId · Snowflake</i>
</p>
<p align="center">
<a href="https://marketplace.visualstudio.com/items?itemName=nolindnaidoo.ids-le">
<img src="https://img.shields.io/badge/Install%20from-VS%20Code-blue?style=for-the-badge&logo=visualstudiocode" alt="Install from VS Code Marketplace" />
</a>
<a href="https://open-vsx.org/extension/OffensiveEdge/ids-le">
<img src="https://img.shields.io/open-vsx/dt/OffensiveEdge/ids-le?style=for-the-badge&label=Open%20VSX&color=blue" alt="Open VSX downloads" />
</a>
<a href="https://www.npmjs.com/package/ids-le-mcp">
<img src="https://img.shields.io/npm/v/ids-le-mcp?style=for-the-badge&label=MCP%20server&color=blue&logo=npm" alt="ids-le-mcp on npm" />
</a>
<a href="https://crates.io/crates/ids-le">
<img src="https://img.shields.io/crates/v/ids-le?style=for-the-badge&label=Rust%20CLI&color=blue&logo=rust" alt="ids-le on crates.io" />
</a>
<a href="https://letools.dev/tools/ids-le">
<img src="https://img.shields.io/badge/LE%20Tools-letools.dev-blue?style=for-the-badge" alt="LE Tools" />
</a>
</p>
---
> **Useful?** A star or rating is how other developers find it —
> [★ GitHub](https://github.com/nolindnaidoo/ids-le) ·
> [★ Open VSX](https://open-vsx.org/extension/OffensiveEdge/ids-le/reviews) ·
> [★ Marketplace](https://marketplace.visualstudio.com/items?itemName=nolindnaidoo.ids-le&ssr=false#review-details)
## What it does
A support ticket quotes `6a7bb780a1b2c3d4e5f60718` and asks when the record was made. A regex says ObjectId, minted 2026-08-12. It is the front of a git commit hash, and the date is noise that happens to land in a plausible year.
Open a document, press `Ctrl+Alt+I` (`Cmd+Alt+I` on Mac), and every identifier in it is listed by kind with its line and column, the document's own key path for it, whether it is valid, and — for the six schemes that carry a clock — the instant it was minted, as ISO-8601 UTC. The report opens beside the editor. Works in VS Code and in VS Code–based editors like Cursor and VSCodium (installable from Open VSX).
- **Reading a log or a dump** — which of these are UUID v7s, and when was each minted?
- **Reviewing a config** — the placeholder nil UUID that escaped into production
- **Before trusting a hex string** — whether the document actually says it is an identifier
**A run it cannot name honestly is reported with the reason, never dropped.** **It rewrites nothing.**
## Install
| Where | What you get | Install |
|---|---|---|
| **VS Code** | The extraction, in your editor, on a keystroke | [Marketplace](https://marketplace.visualstudio.com/items?itemName=nolindnaidoo.ids-le) |
| **Cursor, VSCodium, Windsurf** | The same extension | [Open VSX](https://open-vsx.org/extension/OffensiveEdge/ids-le) |
| **A terminal or a CI step** | A whole tree, with an exit code | `cargo install ids-le` · [crates.io](https://crates.io/crates/ids-le) |
| **Any MCP agent, via Node** | `extract_ids` over stdio | `npx ids-le-mcp` · [npm](https://www.npmjs.com/package/ids-le-mcp) |
| **Zed** | The MCP server as a context server | [add it by hand](https://zed.dev/docs/ai/mcp) *(no listing yet)* |
## It refuses rather than guesses
A tool that answers confidently and wrongly is worse than one that stops and
names what it needs. So every run this crate will not name is **a row in the
report with a reason** — never a dropped row, never a silent guess.
| Reason | What it means |
|---|---|
| `ambiguous_kind` | Two or more schemes fit and nothing in the document chooses between them. |
| `malformed` | The right shape, and validation failed. |
| `nil_or_max` | The nil or max UUID: structurally perfect, and RFC 9562 says it names nothing. |
| `version_claim_mismatch` | A UUID claims v4 — 122 random bits — and the bytes are plainly not random. Both are reported; neither is resolved. |
| `timestamp_implausible` | A decode landed before 1990 or more than a year out. The decode comes with the flag. |
Some are worth spelling out, because they are the cases a regex gets
confidently wrong:
- `5d41402abc4b2a76b9719d911017c592` is an unhyphenated UUID **and** an MD5
digest. Nothing in a document separates them, so nothing here picks.
- `6a7bb780a1b2c3d4e5f60718` is 24 hex characters. Under `_id` it is an
ObjectId minted on 2026-08-12. Under `checksum`, or in prose, it is
refused — an ObjectId's whole specification is *24 hex characters*, so
a truncated SHA-1 fits it exactly and only the document can tell them
apart.
- `1536886938009600000` under `channel_id` is a Discord Snowflake at
2026-08-12. Under a bare `user_id` it is refused, because the Twitter epoch
fits too and the document does not say which. Under `population` it is not
a finding at all.
The full table, and the boundaries the tool holds itself to, are in
[`crate/SPEC.md`](crate/SPEC.md).
## The kinds
| Kind | Shape | Decoded time | Extra fields |
|---|---|---|---|
| `uuid` | 36 characters, `8-4-4-4-12`, hex | v1, v6, v7 | `version`, `variant` |
| `ulid` | 26 characters, Crockford base32 | always (48-bit Unix ms) | — |
| `nanoid` | 21 characters, `A-Za-z0-9_-` | never — a NanoID has no clock | — |
| `objectid` | 24 hex characters, under a key naming an id | always (32-bit Unix seconds) | — |
| `snowflake` | 17–19 digits, under a key naming an id | always (top 42 bits + an epoch) | — |
**Two of those kinds need the document's permission.** An ObjectId is 24
hex characters and a Snowflake is a large integer; neither carries a
version, a variant, a checksum or a restricted alphabet, so neither run
can say on its own what it is — a truncated git hash is a structurally
perfect ObjectId, and a byte count is a structurally perfect Snowflake.
Both are named only where the field's own name ends in `id` (`_id`,
`userId`, `USER-ID`, `$oid`), and refused as `ambiguous_kind` otherwise.
In a plain-text file, which has no keys at all, neither is ever named.
All eight UUID versions RFC 9562 defines are recognised, and all four
variants — `ncs`, `rfc4122`, `microsoft`, `future` — are reported. A version
is only reported under the RFC variant, because in any other layout those
four bits are not a version field.
## The timestamps
This is the part nobody wants to write twice. Six of these carry a clock, in
six unrelated bit layouts, over four different epochs — one of which starts
in 1582:
| Scheme | Where the time is | Epoch |
|---|---|---|
| UUID v1 | 60 bits of 100-nanosecond intervals, low field first | 1582-10-15 |
| UUID v6 | the same ticks, reordered so they sort | 1582-10-15 |
| UUID v7 | 48 bits of milliseconds, at the front | Unix |
| ULID | the first ten Crockford characters, 48 bits | Unix |
| ObjectId | the leading four bytes, in seconds | Unix |
| Snowflake | the top 42 bits | Twitter (2010-11-04) or Discord (2015-01-01) |
Every one comes back as the same ISO-8601 UTC string, milliseconds always
present. UUID v2 is named and **not** decoded: its clock has its low 32 bits
overwritten by a POSIX uid, so it resolves to roughly seven minutes and is
not the same claim.
A decode that lands before 1990 or more than a year from now is refused as
`timestamp_implausible` — and the decode is on the row next to the flag,
because a refusal that hides its evidence is a verdict a reader cannot check.
## Formats
JSON (and JSONC), YAML, TOML, INI (`.properties`), dotenv, CSV and TSV
give each finding a key path — `service.requestId`,
`documents.[0]._id`, `discord.channel_id`. Everything else is read as text:
**the same runs, in the same places, without the key**.
The key path is evidence, not decoration. ObjectId and Snowflake are named
only under a field the document calls an id, so a run that is named in the
`.json` comes back `ambiguous_kind` in the `.md` beside it — same row, same
position, same decode, and a reason instead of a name.
## Use it from an AI agent
The same engine runs as an [MCP](https://modelcontextprotocol.io) server, so an agent can call it directly instead of guessing which hex string is which.
| Editor | How |
|---|---|
| **VS Code** 1.101+ | Nothing to install — the extension registers `extract_ids` with agent mode |
| **Zed** | No listing yet — [add the MCP server by hand](https://zed.dev/docs/ai/mcp) |
| **Claude Code** | `claude mcp add ids-le -- npx -y ids-le-mcp` |
| **Cursor, Windsurf, anything else** | point it at `npx ids-le-mcp` |
```
extract_ids(content, format?, filename?, kind?, maxResults?)
```
It returns the rows the editor renders, refusals included, as data — capped at 500 by default with `meta.truncated`. It reads no files and makes no network requests. Published as [`ids-le-mcp`](https://www.npmjs.com/package/ids-le-mcp) on npm and as `io.github.nolindnaidoo/ids-le` in the [MCP registry](https://registry.modelcontextprotocol.io). It answers exactly as the Rust CLI's server does: one corpus runs against both, and a differential test feeds both thousands of generated documents in every format and compares every answer.
<details>
<summary><b>Configuring it by hand</b> — any host with an MCP config file</summary>
```json
{
"mcpServers": {
"ids-le": {
"command": "npx",
"args": ["-y", "ids-le-mcp"]
}
}
}
```
Or install it once with `npm install -g ids-le-mcp` and point at `ids-le-mcp`. It needs no environment variables, no API key and no configuration of its own. To check it:
```bash
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | npx -y ids-le-mcp
```
</details>
## The CLI
The same extraction runs over a whole tree from a terminal or a CI step: a Rust CLI in [`crate/`](crate/README.md), sharing one corpus with the extension — [`crate/fixturesWhat people ask about ids-le
What is nolindnaidoo/ids-le?
+
nolindnaidoo/ids-le is mcp servers for the Claude AI ecosystem. Extract every UUID, ULID, NanoID, ObjectId and Snowflake, and decode the time inside It has 1 GitHub stars and its last recorded update is dated 2026-10-04.
How do I install ids-le?
+
You can install ids-le by cloning the repository (https://github.com/nolindnaidoo/ids-le) or following the README instructions on GitHub. ClaudeWave also provides quick install blocks on this page.
Is nolindnaidoo/ids-le safe to use?
+
Our security agent has analyzed nolindnaidoo/ids-le and assigned a Trust Score of 95/100 (tier: Verified). See the full breakdown of passed checks and flags on this page.
Who maintains nolindnaidoo/ids-le?
+
nolindnaidoo/ids-le is maintained by nolindnaidoo. The last recorded GitHub activity is dated 2026-10-04, with 2 open issues.
Are there alternatives to ids-le?
+
Yes. On ClaudeWave you can browse similar mcp servers at /categories/mcp, sorted by popularity or recent activity.
Deploy ids-le to your cloud
Ship this repo to production in minutes. Each platform spins up its own environment with editable env vars.
Maintain this repo? Add a badge to your README
Drop the badge into your GitHub README to show it's tracked on ClaudeWave. Each badge links back to this page and reflects the live Trust Score.
[](https://claudewave.com/repo/nolindnaidoo-ids-le)<a href="https://claudewave.com/repo/nolindnaidoo-ids-le"><img src="https://claudewave.com/api/badge/nolindnaidoo-ids-le" alt="Featured on ClaudeWave: nolindnaidoo/ids-le" width="320" height="64" /></a>More MCP Servers
Fair-code workflow automation platform with native AI capabilities. Combine visual building with custom code, self-host or cloud, 400+ integrations.
User-friendly AI Interface (Supports Ollama, OpenAI API, ...)
An open-source AI agent that brings the power of Gemini directly into your terminal.
Real-time global intelligence dashboard. AI-powered news aggregation, geopolitical monitoring, and infrastructure tracking in a unified situational awareness interface
🕷️ An adaptive Web Scraping framework that handles everything from a single request to a full-scale crawl! Don't be shy, join here: https://discord.gg/EMgGbDceNQ and follow here for daily tips and tricks: https://x.com/Scrapling_dev
The fastest path to AI-powered full stack observability, even for lean teams.