jsonloupe

Official registry AI and agents

Open huge JSON locally and give agents its shape, queries and exact values, never the whole blob.

What can you do with jsonloupe?

  • Tree / Code / Split views — virtualized tree, editable CodeMirror code
  • Command palette — ⌘K / Ctrl K from anywhere: type a few letters of a
  • Colour schemes — Tokyo Night, Catppuccin Mocha, Dracula, Gruvbox and
  • Search & filter — / to search (literal or /regex/i), filter mode
  • Path & identity — breadcrumb with one-click copy as JSONPath, JSON
  • Value lenses — epoch → your local date and "3 days ago", the same
  • Tables & CSV — any array gets a sortable table view; export exact-digit
  • Playbook — your checks and functions on one sheet — a check is a query

Install

Add this to your client's MCP configuration (Claude Desktop: claude_desktop_config.json; Cursor: .cursor/mcp.json; VS Code and others use the same "mcpServers" shape).

NPM package jsonloupe
Claude Code
claude mcp add jsonloupe -- npx -y jsonloupe@1.9.2 mcp
JSON configuration (Claude Desktop, Cursor, VS Code)
{
    "mcpServers": {
        "jsonloupe": {
            "command": "npx",
            "args": [
                "-y",
                "jsonloupe@1.9.2",
                "mcp"
            ]
        }
    }
}

Documentation

From the project's README on GitHub, refreshed weekly. Links open on GitHub.

Contents
  1. Run it
  2. Why another JSON viewer?
  3. Quick start
  4. Feature tour
  5. Nested JSON to linked tables
  6. Playbooks: your functions and checks as a file
  7. Use with AI agents
  8. Privacy & security
  9. Deploying
  10. Development
  11. License

jsonloupe is a browser-based workbench for inspecting, diffing, editing, and querying JSON documents that are too big or too precise for ordinary viewers — and for turning them into spreadsheets: nested JSON goes in, linked tables come out, as one .xlsx or a zip of CSVs. The questions you ask of every file can be kept as checks in a playbook: one press judges them all over the open document, and the same file gates CI through jsonloupe check. Nothing leaves your machine: in the browser, documents are parsed in a web worker, stored in IndexedDB, and never uploaded anywhere. No backend, no account, no telemetry.

Run it

Use the hosted app at jsonloupe.dev, rebuilt from main on every merge — or run the latest npm release from your own machine, fully offline:

npx jsonloupe

That starts a loopback-only static server (127.0.0.1:5199, or the next free port) serving the prebuilt app from the package — no runtime dependencies, no network calls, one auditable file of about 200 lines with its comments: bin/jsonloupe.mjs. --port <n> and --no-open do what they say; --key-file <path> serves a model key from that file to the page, over loopback only. The same command carries the converter's verbs (inspect, draft, convert, below) and the CI gate (check, below); npx jsonloupe --help lists them.

Why another JSON viewer?

  • Lossless numbers. Int64 IDs beyond 2^53 (snowflake/order/entity IDs) and precise decimals survive paste → view → edit → copy → download with their exact digits. Nothing is ever coerced to a float.
  • Built for huge documents. The tree is virtualized and expansion is chunked ([0 … 9999] range rows), so opening a five-million-element array is instant. Parsing, diffing, search, and compression all run off the UI thread.
  • Compressed payloads are first-class. Paste or drop raw .zst, Base64-Zstd (standard or URL-safe), or PostgreSQL \x… bytea — it's detected, decoded in the worker, and opened as a document with a transformation trace. An encoder and a transport-size inspector (exact UTF-8 / Zstd / Base64 / envelope bytes against editable budgets) round-trip the other way.
  • Nested JSON becomes a spreadsheet, on your machine. Repeating arrays and object maps become their own linked tables — orders and order_items joined by order_id, never items/0/sku columns. You see real rows before anything is written, and the mapping saves as a small file that produces the same columns from next month's file, with no model involved.
  • Semantic diff. Side-by-side compare with identity-based array alignment (match by id, composite keys, or auto-detected), so reordered arrays don't drown you in false changes. Ignore noisy fields by key or path prefix.
  • A real query language. A JSONPath subset with predicates and aggregation pipes ($.tasks[?(@.status == 'FAILED')] | group(@.failureReason)), executed locally with live preview as you type. Numeric literals, predicates, sums, averages, minima, and maxima remain exact for int64 and precise decimals.
  • Checks you can gate on. Keep the questions you ask of every file as checks — a query and the count it should come to — and one press judges them all, naming the first paths behind each failure. A count it could not finish is inconclusive, never a pass it has not earned. The same playbook file gates CI through jsonloupe check and an agent through MCP's run_checks.

Quick start

git clone https://github.com/priyanshuN/jsonloupe && cd jsonloupe
npm ci
npm run dev        # http://localhost:5199

Paste JSON on the landing page — it parses instantly and is saved to local memory (Recents sidebar: reopen, pin, delete). Malformed input (trailing commas, single quotes, Python literals, truncated log extracts) is auto-repaired and flagged, with the original bytes preserved.

Feature tour

  • Tree / Code / Split views — virtualized tree, editable CodeMirror code view (fold, search, apply-with-⌘S), or both side by side with click-to-line sync. Inline-edit primitives in the tree; full undo/redo across edits. A small document opens unfolded to fill the screen, and scrolling deep keeps the parent keys you are inside pinned at the top of the tree.
  • Command palette — ⌘K / Ctrl K from anywhere: type a few letters of a view, an action, a theme or a recent document's name, and press Enter.
  • Colour schemes — Tokyo Night, Catppuccin Mocha, Dracula, Gruvbox and GitHub Dark for dark; Solarized Light, Catppuccin Latte, Rosé Pine Dawn and GitHub Light for light; plus jsonloupe's own pair. Hover one in the sidebar picker (or arrow through them in ⌘K) to try it on the whole app. Each mode keeps its own scheme, so "follow the system" swaps between your two at sunset. Every scheme meets WCAG AA contrast, checked in CI.
  • Search & filter — / to search (literal or /regex/i), filter mode prunes the tree to matching branches and restores your expansion state after.
  • Path & identity — breadcrumb with one-click copy as JSONPath, JSON Pointer, or JS accessor; "same value" jumps to every node holding a value (schema-free correlation-ID tracing).
  • Value lenses — epoch → your local date and "3 days ago", the same relative time on ISO timestamps, a colour chip on colour strings, latitude/longitude, uuid/url/base64 flags, and byte weight on collapsed containers so the heavy node is findable at a glance.
  • Tables & CSV — any array gets a sortable table view; export exact-digit CSV (RFC 4180) of tables or query results.
  • Playbook — your checks and functions on one sheet — a check is a query and the count it should come to (none, at most 3 groups, between 1 and 10); run all judges every one over the open document and points at the first nodes behind each failure. A function is JavaScript for the questions no query language should have to answer, run in a sandbox with the network removed; tick several and one press answers all of them as a single report. The same checks gate CI through jsonloupe check. (below.)
  • JSON → Excel / CSV converter — rename and reorder columns, choose source fields, add constants, set date and coordinate handling, take the column names from a target CSV header, and save or share the mapping for the next file. (below.)
  • File handles — drop .json/.jsonl/.zst files; reload re-reads from disk and shows what changed since the version you were looking at.
  • Query — run JSON queries locally, save useful ones, or turn a result into a reusable check. Optional English → query mode translates a question using only the document's shape (field names/types — never values), then stops so you can review the generated query before running it locally. Bring your own connection: authorize with OpenRouter without pasting a key, or use the advanced manual-key option — paste a key, or load it from a local file (a raw key or a .env line, read in the page and never uploaded). Until you explicitly connect, the feature is inert. A disclosure panel records exactly what was sent. See SECURITY.md.
Browser query cookbook

Open a document, press query, leave JSON query selected, and paste a query. It runs directly in this tab: no API key and nothing sent to a model.

Given this small document:

{"tasks":[
  {"id":9007199254740992,"status":"FAILED"},
  {"id":9007199254740993,"status":"READY"}
]}
  • Filter to the failed rows:

    $.tasks[?(@.status == 'FAILED')]

    Result: one match, $.tasks[0].

  • Count rows by status:

    $.tasks[*] | group(@.status)

    Result: FAILED 1, READY 1.

  • Compare an integer beyond JavaScript's safe range without rounding it:

    $.tasks[?(@.id > 9007199254740992)] | count

    Result: 1 — only the exact 9007199254740993 id is greater.

Nested JSON to linked tables

If a spreadsheet is the only thing you came for, jsonloupe.dev/json-to-excel.html is that job on a page of its own: paste, convert, done.

Open a document and press the table glyph in the toolbar's tools group (convert; every glyph there names itself on hover). Every repeating array becomes its own table, joined back to its parent by the id that was already in the data — so this:

{ "orders": [
    { "id": 7, "cust": "ACME",
      "items": [ { "sku": "A", "qty": 2 }, { "sku": "B", "qty": 1 } ] } ] }

comes out as two sheets rather than one row full of items/0/sku columns:

orders                    order_items
id  cust                  order_id  sku  qty
 7  ACME                         7  A      2
                                 7  B      1

jsonloupe finds those tables for you but never runs the guess blindly: the mapping and a preview of real rows stay on screen while you rename columns, choose which fields to keep, and say how dates and coordinates should be read. What you approve is saved as a small mapping file — keep it in this browser, export it, or use it from the command line:

jsonloupe inspect payload.json          # what tables are in here?
jsonloupe draft   payload.json -o payload.spec.json   # a first mapping, to read
jsonloupe convert payload.json --spec payload.spec.json -o payload.xlsx

The same mapping produces the same columns through the browser, the CLI, and the MCP server, with no model in the loop — that is the point of freezing it. What lands in the cells is what was in the document: dates arrive as real dates you can sort and subtract, numbers and coordinates as numbers, and text that only looks numeric stays text, so "1.10" keeps its trailing zero and an int64 id keeps every digit instead of being rounded. Excel's limits and values a column cannot read are reported or refused, never quietly written wrong.

Playbooks: your functions and checks as a file

The document changes daily; the handful of questions you ask of it does not. So playbook in the toolbar (the functions view before 1.8; ⌘K still finds it by that word) opens them beside the document, as one sheet: your checks — a query and the count it should come to — and your functions, each list in name order. run all (⌘⇧↵ / Ctrl ⇧↵ while the playbook is open; press it again to stop) measures every check over whatever is open and paints each row's verdict in place, then runs the ticked functions. The first row that did not pass opens by itself, showing the first nodes it matched; press a path and the tree beside the sheet selects that node, while the sheet stays where it is.

Checks

Press + check in the sheet, or turn a Query result into one with save as check. A check counts matches — groups for | group, distinct values for | distinct — and passes when the count meets its expectation:

Pass whenexpectationPlaybook version
no matches are found{"type": "no-matches"}3
at least one match is found{"type": "at-least-one"}3
exactly N are found{"type": "exact-count", "count": N}3
at most N are found{"type": "at-most", "count": N}4
at least N are found (N ≥ 1){"type": "at-least", "count": N}4
between M and N are found, both included{"type": "between", "min": M, "max": N}4

A count is a whole number within JavaScript's safe range; one past it is refused, never rounded. A query that ends in | sum, | avg, | min or | max yields one value rather than a count, so a check on it says it could not run instead of judging a number it was never meant to count.

Every check comes back as ✓ pass, ✕ fail, ? inconclusive, or ✗ could not run. Inconclusive is the honest third answer: | group and | distinct keep at most 100,000 groups or values (the cardinality cap). Past that, the count is only a lower bound: at least 100,001. A lower bound passes only when it proves the expectation by itself (at least one, or at least N already reached), fails when it is already over the limit (none, or at most 100,000), and is inconclusive otherwise — it is never reported as a pass it has not earned. Narrowing the query decides it.

A check whose query names a field the open document does not have says so on its row, and its panel adds "this reads status — this document has none of that, so a pass here may prove nothing". A no matches check passes just as well on a file whose field was renamed.

A saved check keeps one last verdict, with up to five matched paths and a short preview of each. It belongs to the document the check last ran on: run it on another document and that run replaces it. Reopen the document it ran on and the verdicts are still there; edit it and they fade, marked "document edited", until you run again. That record stays in this browser: it is never written into an exported playbook, and removing the document removes it.

Functions

A function learns what it reads. The first time one runs it is handed the document through a recording proxy, and the paths it actually touched are kept with it. That is what lets the sheet say

this reads orders, orders[].deliveredInHours — this document has none of that

before you press run, instead of leaving you to read an empty result as "none today". It is always a remark and never a gate: the reading knows only the branch that run took, so the run button still works. Tick several functions and run all answers all of them, as a single object keyed by function name. open report in the functions head shows it: today's report, which downloads and reopens as a document like any other. A function's result lasts while that document stays open. Open another document, or reload, and its row says it has not run. Which functions are ticked is remembered in this browser.

Scripts run in an ephemeral worker with fetch, XMLHttpRequest, WebSockets, IndexedDB, importScripts and nested workers removed before any user code, terminated on its result or after ten seconds (a ticked batch shares those ten seconds, and one that runs past them is stopped whole) — a pasted script cannot reach the network or the documents you have opened. JavaScript number mode preserves the behavior of existing functions and says when a document contains values it will round. exact text mode instead hands those unsafe literals to the function as their original digit strings ("9007199254740993"); ordinary values such as 3 and 1.5 remain numbers, so normal counting and arithmetic still work. The mode is saved and exported with the function rather than left as a browser preference.

The file

A playbook is that reusable work as a file — the questions and expectations, never the data:

{
  "playbookVersion": 4,
  "name": "carrier dumps",
  "functions": [
    {
      "name": "slow orders",
      "script": "data.orders.filter(o => o.deliveredInHours > 48)",
      "reads": ["orders", "orders[].deliveredInHours"],
      "numberMode": "exact-text"
    }
  ],
  "checks": [
    {
      "name": "no failed orders",
      "query": "$.orders[?(@.status == 'FAILED')]",
      "expectation": { "type": "no-matches" }
    },
    {
      "name": "a full day of orders",
      "query": "$.orders[*]",
      "expectation": { "type": "at-least", "count": 1000 }
    },
    {
      "name": "a handful of carriers",
      "query": "$.orders[*] | group(@.carrier)",
      "expectation": { "type": "between", "min": 1, "max": 5 }
    }
  ]
}

export in the playbook bar writes one, as version 3 unless a check needs version 4: a library with no at-most, at-least or between check exports as version 3, which jsonloupe 1.4 to 1.7 read. import, or dropping the file on the window, adds what it holds. Import merges and never replaces — a name you already use keeps yours and the incoming one lands as slow orders 2, because a duplicate is one forget away and an overwrite is not. Unknown fields are refused by name rather than dropped, so a file from a newer jsonloupe cannot import as a subset of itself and look like it worked. The library keeps 100 functions and 100 checks: saving a 101st is refused with a message saying so, and a playbook that would not fit is refused whole, rather than pushing your oldest ones out. Version 1, 2 and 3 playbooks still import; version 1 functions keep their original JavaScript-number mode.

In CI: jsonloupe check

The same checks gate a pipeline. jsonloupe check runs a playbook's checks against one or more files with the browser's own engine, and exits non-zero when one fails:

npx -y jsonloupe@^1.8.0 check carrier-dumps.playbook.json out/orders.json
out/orders.json · 3 checks · 4 ms
  ✕ no failed orders — Fail — 2 matches; expected no matches
      first: $.orders[312]
             $.orders[877]
  ✓ a full day of orders — Pass — 1,204 matches; expected at least 1,000 matches
  ✓ a handful of carriers — Pass — 3 groups; expected between 1 and 5 groups
1 function not run — functions run only in the browser
✕ 1 failed · ✓ 2 passed

Keep the @^1.8.0. jsonloupe before 1.8 has no check verb: it starts the viewer's local server instead, which never exits, so the job hangs until the runner times it out. From 1.8 on, a word jsonloupe does not know exits 1 rather than starting anything.

The playbook comes first, then any number of files: .json, .jsonl/.ndjson, raw Zstd, or a Base64-Zstd / bytea payload, detected as they are in the browser. A file that is not valid JSON fails the gate rather than being repaired behind your back; --allow-repair checks the repaired document instead. Every query is checked before any file is read, so a typo in the last check costs no parsing. Functions are JavaScript and never run outside the browser's sandbox, so check counts them and says it did not run them. The text report prints matched paths and never values, since CI logs are often public. A path still names the keys it passes through, so on a document keyed by e-mail address or account id, pass --no-evidence. --format json writes one object, with a short preview of each matched node, for a program to read; --max-evidence N (0–100, default 3) or --no-evidence sets how many paths a check that did not pass names.

Exit statusMeaning
0every check passed on every file
1usage error, a file or playbook that could not be read, or a file that is not valid JSON — including one that would need repairing
2the playbook is not valid JSON or not a playbook, has no checks or more than 100 (what a library holds), or has a query no check can count; nothing was checked
3at least one check failed
4nothing failed, but a check was inconclusive or could not run

With several files the most actionable status wins: 3, then 1, then 4. Undecided has its own status so a pipeline can tolerate it on purpose (… || test $? -eq 4).

In GitHub Actions, --format github adds annotations after the text report: one on the playbook for each check that did not pass — a warning when it was inconclusive, an error otherwise — and an error on each file it could not check, or on the playbook when it is invalid:

jobs:
  checks:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - uses: actions/setup-node@v7
        with:
          node-version: 24
      # … the steps that write out/orders.json
      - run: npx -y jsonloupe@^1.8.0 check carrier-dumps.playbook.json out/orders.json --format github

An agent gets the same gate from the MCP server's run_checks (below), with a playbook's path or the checks inline. It refuses a document that is not valid JSON in the same way; allowRepair: true checks the repaired document and says so.

Use with AI agents

The same engine runs as an MCP server, so an agent can work on a document that would never fit in its context:

claude mcp add jsonloupe -- npx -y -p jsonloupe jsonloupe-mcp

If you have jq and plain JSON, use jq. This is for the cases jq is awkward about: compressed payloads (.zst, Base64-Zstd, PostgreSQL \x… bytea) that have to be decoded first, int64 and decimal digits that must survive the whole pipeline exactly, identity-keyed semantic diff between two documents, and MCP hosts that have no shell to run jq in.

Twelve tools (run_checks from 1.8): load_doc, get_schema, run_query, profile, sample, diff_docs, export_csv, export_result, plus inspect, draft_spec, and convert for the spreadsheet path above, and run_checks, which gates a document on a playbook's checks and never runs its functions. For one question, pass filePath straight to get_schema, run_query, profile, sample, export_csv, export_result or run_checks; it opens the document and returns a reusable docId in the same call. For a sequence of questions, and for diff_docs and the converter tools, which take a docId, call load_doc once and reuse that docId. Up to eight documents stay open; past that the least recently used is closed, and the next response says so. Query details default to 10 rows (use limit=0 for summary only, or offset + limit to page), and text and structured MCP results are both bounded. A typical run over a 37 MB routing payload:

run_query filePath=payload.json "$.tasks[?(@.status == 'FAILED')] | count"
                                  → docId: d1 · count: 17500
profile d1 "$.tasks[*]"          → auto-discovered field coverage, null/missing/types,
                                    exact sums/stats, lengths, distincts and top values
run_query d1 "$.tasks[?(@.status == 'FAILED')] | group(@.region, @.failureReason)"
                                  → composite breakdown, exact complete counts
run_query d1 "$.tasks[*] | top(@.delayMinutes, @.id, @.status)" limit=5
                                  → only the five highest rows; the full array never enters context
sample d1 "$.tasks[0]"           → the whole element, id 9007199254740993 intact
export_result d1 "…| pluck(@.id, @.failureReason)" format=csv outPath=failed.csv
                                  → complete, atomic, rows + UTF-8 bytes only
inspect d1                       → candidate tables, fields, types, deterministic suggestions
draft_spec d1 outPath=tasks.spec.json
                                  → reviewable mapping on disk
convert d1 specPath=tasks.spec.json outPath=tasks.xlsx
                                  → workbook path + row/skipped/warning counts, never its rows
run_checks d1 playbookPath=tasks.playbook.json
                                  → pass, fail or inconclusive per check (or could not run);
                                    a failed or inconclusive check names its first paths
                                    ($.tasks[3]); functions counted, never run

The common schema → profile → query loop is deliberately cheaper than loading JSON or writing a one-off Python script: counts and aggregates stream over every match without materializing the result list; present, missing, and isNull keep false/null/absent distinct; composite grouping and bounded top/bottom replace local sort scripts; and profiles inspect multiple or automatically discovered fields in one scan. Complete CSV/JSONL exports stream to a temporary file and publish atomically. Existing paths are refused unless the agent passes overwrite=true explicitly.

The server makes no network calls and accesses only explicitly supplied input/output paths. A bad query returns the grammar and a suggestion rather than an empty result. The reproducible agent-choice evaluation measures whether an agent selects these operations when Python is also available.

If an agent knows the MCP is installed but still writes one-off scripts, put this routing rule in its project instructions (for example AGENTS.md or CLAUDE.md):

For small plain JSON, use jq when it is already the shortest safe option. Otherwise prefer the JsonLoupe MCP over ad-hoc Python whenever it supports the operation; use custom shell code only when JsonLoupe cannot answer it.

In the browser: WebMCP

Where the browser exposes WebMCP (document.modelContext — a Chrome origin trial from Chrome 149, and the ChatGPT desktop app's built-in browser), jsonloupe.dev registers the same bounded verbs pointed at the document already on screen, so a browser agent and the person watching share one document instead of mailing copies back and forth. Eight tools: run_query, get_schema, profile and sample work as they do over stdio, and four act on the viewer itself, which no headless server can do: load_doc opens a document in it, reveal_path scrolls the tree to a row and flashes it, and highlight_matches/clear_highlights drive the toolbar's own filter state — visible, counted, and reversible by the human's own button. Every tool that returns document content is annotated untrustedContentHint: values are data, never instructions. Browsers without the API fetch nothing and run the same app they always did. Details, testing instructions, and provenance in WEBMCP.md.

Privacy & security

Documents never leave your machine. The complete network-call inventory (four fetch calls, all in opt-in model connection or English query translation), the shape-only LLM contract, and the XSS posture are documented in SECURITY.md. The corresponding threat model, trust boundaries, and assurance argument are in SECURITY-ASSURANCE.md.

Deploying

jsonloupe builds to a fully static site:

npm run build      # dist/

Serve dist/ from any static host (GitHub Pages, Cloudflare Pages, Netlify…). The app needs nothing server-side to work. To match jsonloupe.dev's protection, set the response headers in SECURITY-HEADERS.md at the host — above all the Run sandbox's own CSP on /assets/run-sandbox-*.js, without which a pasted script's import() can reach any host. The local /__api-key convenience endpoint (dev mode, or npx jsonloupe --key-file) simply doesn't exist in a static deploy, and English translation activates only when a visitor connects their own model account or key.

Development

npm run dev        # Vite on :5199, with the loopback-only /__api-key endpoint
npm test           # vitest — engine, worker, converter, playbook, CLI, MCP, WebMCP, NL and DOM suites
npm run lint:security  # FLOSS security analysis + checked TypeScript style
npm run lint:contract  # the UI contract in src/style.css: tokens, contrast, motion, type ramp
npm run lint:headers   # every source file carries the MIT SPDX and copyright notice
npm run coverage   # same suite with enforced 90% statement / 80% branch floors
npm run build      # type checks + vite build + the MCP and CLI bundles
npm run build:mcp  # or build:cli — one target's type check and bundle only
npm run test:a11y  # real Chromium: axe, keyboard/focus, playbook and WebMCP journeys (run after build)
npm run check:site-headers # verify the live OpenSSF hardening headers
npm run check:reproducible-build  # clean locked installs must produce identical bytes
npm run smoke:mcp  # drives the built MCP server over real stdio against a 37 MB fixture (run after build)
npm run eval:agent -- --help  # black-box MCP-vs-Python agent-choice benchmark
npm run eval:ask -- --dry-run  # Ask correctness/injection suite; --dry-run costs nothing

Start with CONTRIBUTING.md. Architecture and internals are documented in ARCHITECTURE.md and SPEC.md; the converter has its own SPEC-converter.md, including what it deliberately refuses to do. Project decisions and the next twelve months are in GOVERNANCE.md and ROADMAP.md. Official publishing and consumer verification are documented in RELEASING.md. What changed in each release is in CHANGELOG.md.

License

MIT. Bundled third-party packages are listed in THIRD_PARTY_LICENSES.md.

Software is provided "as is", without warranty of any kind — see the license text. If you connect a model for English queries, your use of the configured LLM provider is governed by that provider's terms.

Frequently asked questions

What is jsonloupe?

Open huge JSON locally and give agents its shape, queries and exact values, never the whole blob.

How do I install jsonloupe?

It runs on your machine. In Claude Code: claude mcp add jsonloupe -- npx -y jsonloupe@1.9.2 mcp. For other clients, paste the JSON configuration from this page into their MCP settings.

Does jsonloupe need an API key?

Its registry entry lists no required key or secret. Some features may still need an account with the service it connects to.

Is jsonloupe open source?

Yes. Its code is on GitHub under the MIT license.

Who maintains jsonloupe?

It is published by priyanshuN. AI.tn lists it but does not maintain or endorse it.

From the official MCP Registry. Listing is not an endorsement: review a server's code and permissions before giving it access to your data.