pqc-triage
Fetches arXiv preprints as a live data feed to supply published quantum resource estimates and research updates for PQC Triage, with provenance marked as live or fallback.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@pqc-triagescan my package-lock.json and tell me which crypto surfaces must migrate first"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
PQC Triage
Find the cryptography a quantum computer breaks first — and the exact year you must migrate by.
Live app · GitHub · API · Agent · Issues
Post-quantum migration is a calendar problem wearing a technical costume. Nobody argues about whether RSA-2048 falls to Shor's algorithm; everybody argues about when, and the honest answer is "whatever year a cryptographically relevant quantum computer arrives". Most inventories never get that far, because the first hard question is where the cryptography is.
PQC Triage imports a real dependency manifest and a real source excerpt, resolves every cryptographic surface to an algorithm, scores each one against published quantum resource estimates and the NIST transition dates, and commits a sealed migration plan with a start-by year for every surface.
Zero API keys. Runs offline on an embedded Postgres. Every number carries its citation.

✨ Features
Real inventory. Parses
package-lock.json,package.json,requirements.txt,go.mod,Gemfile.lock,composer.lock,Cargo.lockandpom.xml, then scans a source excerpt line by line for cryptographic call sites. Every surface carries the line it matched on.A deadline, not a score. Mosca's rule: work must start by H − (X + Y) — the quantum horizon, minus the years the data must stay secret, minus the migration lead time. You get a year, not a percentage.
Explainable by construction. Six weighted factors per surface, each with its weight, its severity, its point contribution and the sentence that produced it.
Published quantum costs. Logical qubits and Toffoli counts for a Shor attack from the Gidney–Ekerå closed form for RSA, and the Häner et al. anchor scaled linearly for elliptic-curve discrete logs. Labelled as literature estimates, not predictions.
Honest live data. deps.dev release metadata, OSV advisories, arXiv preprints and the NIST news feed, each reporting
liveorfallbackwith a sealed dated sample that is never presented as current.An agent interface that cannot cheat. MCP JSON-RPC 2.0 with eleven typed tools. The mutating tools call the same service functions the buttons do, scoped to one owner, with idempotency keys.
An audit chain you can replay. Every create, decision and retire appends a SHA-384 seal:
seal_n = SHA-384(UTF-8(prevSeal) || canonicalJson(event_n)). Deletes leave tombstones so the chain never breaks.An in-repo model, no API key. A multinomial Naive Bayes classifier trains from a seed corpus of realistic call sites plus every correction you teach it, and shows you the tokens that moved its answer.
A takeaway artifact. Markdown, JSON or CSV migration plan with every factor, every citation, the provenance table and the seals. Plus a revocable public report link.
Related MCP server: quantakrypto pqc-tools
🚀 Quickstart
git clone https://github.com/aniruddhaadak80/pqc-triage
cd pqc-triage
npm ci
npm run devOpen http://localhost:3000. No environment variables are required. Local development,
npm test and the browser suite all use an embedded PGlite Postgres at .pgdata/, which is
a real Postgres compiled to WebAssembly — the same schema, the same SQL, the same indexes.
A first-time visitor is seeded with one survey imported from the sample manifest that ships in the repository, so the workbench has something real in it immediately.
Quality commands
npm run typecheck # tsc --noEmit, strict
npm run lint # eslint, zero warnings tolerated
npm run test # vitest, 125 deterministic unit tests
npm run build # next build
npm run test:browser # Playwright: the full journey on desktop and mobile (needs a build first)
npm run verify:live # end-to-end proof against a deploymentProduction environment variables
Documented in .env.example; all of them optional.
Variable | Required | What it does |
| in production | Pooled Postgres connection string. Injected automatically by the Neon integration on Vercel. |
| no | Overrides the public base URL used for canonical URLs, the sitemap, OpenGraph metadata and |
| no | Where the embedded database lives during local development. Defaults to |
On a Vercel runtime without DATABASE_URL the app refuses to open a connection rather
than quietly falling back to an ephemeral store. See assertStoreUsable in
src/lib/db/client.ts.
🔌 API
Everything is owned by an anonymous HttpOnly session cookie, so there is no account to
create. The first response from the edge proxy sets pqc_sid.
BASE=https://pqc-triage.vercel.app
# Health: proves the store with a real insert, read-back and delete
curl -s $BASE/api/health | jq '.store, .writeProbe, .engineVersion'
# Create a survey from a manifest and a source excerpt
SURVEY=$(curl -s -c jar -X POST $BASE/api/surveys \
-H 'content-type: application/json' \
-d '{"name":"billing-gateway","repoHint":"acme/gateway",
"manifest":"{\"dependencies\":{\"jsonwebtoken\":\"^9.0.2\",\"node-forge\":\"^1.3.1\"}}",
"source":"jwt.sign(p, s, { algorithm: \"HS256\" });\nconst legacy = crypto.createCipheriv(\"des-ede3\", key, iv);"}' \
| jq -r '.survey.id')
# Read it back, with the analysis the UI renders
curl -s -b jar $BASE/api/surveys/$SURVEY | jq '.analysis.score, .analysis.band, .analysis.engineVersion'
# Decide on the worst surface
SURFACE=$(curl -s -b jar $BASE/api/surveys/$SURVEY | jq -r '.analysis.surfaces[0].surfaceId')
curl -s -b jar -X PATCH $BASE/api/surfaces/$SURFACE \
-H 'content-type: application/json' \
-d '{"decision":"migrate-now","decisionNote":"Hybrid KEM in the next release.","shelfLifeYears":27}'
# Read the persisted state back
curl -s -b jar $BASE/api/surveys/$SURVEY \
| jq --arg s "$SURFACE" '.surfaces[] | select(.id==$s) | {decision, shelfLifeYears}'
# Run the engine over any primitive, with nothing stored
curl -s -X POST $BASE/api/mcp -H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call",
"params":{"name":"assess_primitive","arguments":{"primitive":"rsa-2048","shelfLifeYears":25}}}'
# Replay the seal chain
curl -s -b jar "$BASE/api/integrity?survey=$SURVEY" | jq '.valid, .eventsChecked, .algorithm'
# Download the plan
curl -s -b jar -D- -o plan.md "$BASE/api/export?survey=$SURVEY&format=md"
# Retire it; the rows stay as tombstones and replay still verifies
curl -s -b jar -X DELETE $BASE/api/surveys/$SURVEY | jq '.tombstone, .seal'Errors
One envelope for every endpoint and every tool call.
{ "error": { "code": "validation_error", "message": "The request body did not match the schema.", "details": [{ "path": "name", "message": "Too small: expected string to have >=1 characters" }] } }Code | Status | When |
| 422 | Schema or bounds failure |
| 404 | Missing, or owned by another session |
| 409 | State conflict |
| 429 | Best-effort write limiter tripped |
| 415 | Wrong content type |
| 500 | Anything unexpected, with no stack trace and no environment values |
🤖 Agent console
Eleven typed tools over MCP-style JSON-RPC 2.0 at /api/mcp. The mutating tools call the
same service functions the buttons on the site call.
{
"mcpServers": {
"pqc-triage": {
"type": "http",
"url": "https://pqc-triage.vercel.app/api/mcp"
}
}
}The same configuration is served from
public/mcp.json.
flowchart LR
classDef data fill:#22d3ee,stroke:#0e7490,color:#083344
classDef engine fill:#a78bfa,stroke:#6d28d9,color:#2e1065
classDef agent fill:#34d399,stroke:#047857,color:#022c22
classDef infra fill:#94a3b8,stroke:#475569,color:#0f172a
classDef risk fill:#fb7185,stroke:#be123c,color:#4c0519
Client["Any MCP client"]:::infra -->|POST jsonrpc| Endpoint["/api/mcp"]:::infra
Endpoint --> Init["initialize + ownerToken"]:::agent
Endpoint --> List["tools/list with schemas"]:::agent
Endpoint --> Call["tools/call"]:::agent
Call --> Read["list_signals / list_surveys / get_survey"]:::data
Call --> Engine["assess_primitive / classify_primitive"]:::engine
Call --> Mutate["import_survey / record_decision / delete_survey"]:::risk
Mutate --> Service["service layer, same as the UI"]:::infra
Service --> Store[("hosted Postgres")]:::infra
Service --> Seal["SHA-384 chain append"]:::agent
Read --> Feed["deps.dev / OSV / arXiv / NIST"]:::dataAn agent that does not keep cookies takes the ownerToken from the initialize result
and sends it back as params.ownerToken; it is an unguessable 128-bit capability scoped to
that owner. Mutating tools accept an idempotencyKey; replaying the same key returns the
first result instead of writing twice.
Architecture
flowchart TB
classDef data fill:#22d3ee,stroke:#0e7490,color:#083344
classDef engine fill:#a78bfa,stroke:#6d28d9,color:#2e1065
classDef agent fill:#34d399,stroke:#047857,color:#022c22
classDef infra fill:#94a3b8,stroke:#475569,color:#0f172a
classDef risk fill:#fb7185,stroke:#be123c,color:#4c0519
Browser["Browser"]:::infra --> Proxy["proxy.ts assigns the owner cookie"]:::infra
Proxy --> Pages["App Router pages, server by default"]:::infra
Browser --> Rest["REST routes"]:::infra
Browser --> Rpc["JSON-RPC 2.0"]:::agent
Pages --> Service["service.ts, the only writer"]:::infra
Rest --> Service
Rpc --> Service
Service --> Engine["engine hndl@1.0.0"]:::engine
Service --> Extract["extract.ts"]:::engine
Service --> Registry["crypto-registry.ts"]:::engine
Service --> Adapter["SqlExecutor adapter"]:::infra
Adapter --> Neon["Neon Postgres, production"]:::data
Adapter --> Pglite["PGlite, local and CI"]:::data
Service --> Seal["seal.ts"]:::agent
Service --> Live["live sources"]:::data
Engine --> PagesServer components are the default; client components exist only where there is interaction. The engine, the registry, the resource model and the classifier are pure TypeScript with no Node dependencies, which is why the browser can run the identical function the server does — the sweep on the workbench is not an approximation of the score, it is the score.
flowchart LR
classDef data fill:#22d3ee,stroke:#0e7490,color:#083344
classDef engine fill:#a78bfa,stroke:#6d28d9,color:#2e1065
classDef agent fill:#34d399,stroke:#047857,color:#022c22
classDef infra fill:#94a3b8,stroke:#475569,color:#0f172a
classDef risk fill:#fb7185,stroke:#be123c,color:#4c0519
Manifest["manifest paste"]:::data --> Detect["detectEcosystem"]:::engine
Source["source excerpt"]:::data --> Scan["scanSource, line by line"]:::engine
Detect --> Parse["parseManifest per ecosystem"]:::engine
Parse --> Pkg["match the curated crypto package list"]:::engine
Scan --> Hits["one hit per primitive, with line numbers"]:::engine
Pkg --> Row["ExtractedSurface"]:::engine
Hits --> Row
Row --> Resolve["resolvePrimitive into the scoring table"]:::engine
Resolve --> Enrich["enrich up to six dependencies"]:::data
Enrich --> Persist["surfaces and surveys rows"]:::infra
Persist --> Score["analyzeSurvey"]:::engine
Score --> Bands["band and deadline per surface"]:::engine
Bands --> Band["no live signal scores neutral, never zero"]:::riskflowchart TB
classDef data fill:#22d3ee,stroke:#0e7490,color:#083344
classDef engine fill:#a78bfa,stroke:#6d28d9,color:#2e1065
classDef agent fill:#34d399,stroke:#047857,color:#022c22
classDef infra fill:#94a3b8,stroke:#475569,color:#0f172a
classDef risk fill:#fb7185,stroke:#be123c,color:#4c0519
In["primitive, role, X, H, decision"]:::engine --> Deadline["mustStartBy = H - (X + Y)"]:::engine
In --> Bits["quantum bits from SP 800-57"]:::engine
In --> QCost["Shor resource estimate"]:::data
Deadline --> Harvest["F1 harvest 0.26"]:::engine
Bits --> QB["F2 quantum bits 0.22"]:::engine
Deadline --> Sched["F3 headroom 0.18"]:::engine
In --> Class["F4 classical 0.14"]:::engine
In --> Supply["F5 supply 0.12"]:::engine
In --> Use["F6 usage 0.08"]:::engine
Harvest --> Sum["score = 100 x sum(w x s)"]:::engine
QB --> Sum
Sched --> Sum
Class --> Sum
Supply --> Sum
Use --> Sum
Sum --> Band["bands at 75 / 55 / 35 / 15"]:::risk
Sum --> Repl["replacement and its lead time Y"]:::engine
Band --> Out["score, factors, mustStartBy, decryptableFrom, seal"]:::engine
Repl --> OutData provenance
flowchart LR
classDef data fill:#22d3ee,stroke:#0e7490,color:#083344
classDef engine fill:#a78bfa,stroke:#6d28d9,color:#2e1065
classDef agent fill:#34d399,stroke:#047857,color:#022c22
classDef infra fill:#94a3b8,stroke:#475569,color:#0f172a
classDef risk fill:#fb7185,stroke:#be123c,color:#4c0519
Deps["deps.dev release metadata"]:::data --> Live["live"]:::infra
Osv["OSV advisories"]:::data --> Live
Arxiv["arXiv quant-ph / cs.CR"]:::data --> Live
Nist["NIST news feed"]:::data --> Live
Live --> Norm["NormalizedSignal: source, status, fetchedAt, href"]:::infra
Live -.->|timeout or unreachable| Fallback["sealed dated sample"]:::risk
Fallback --> Norm
Norm --> Score["supply factor"]:::engine
Norm --> Board["live signal board"]:::infra
Fallback -->|never| User["user-created surfaces"]:::infra
User --> Store[("hosted store")]:::dataSource | Used for | Endpoint |
Latest release, publish date, license per dependency |
| |
Published advisory records per dependency |
| |
Current quant-ph / cs.CR work on post-quantum migration |
| |
Standards announcements, filtered for cryptography |
| |
Transition dates: deprecate after 2030, disallow after 2035 | cited, not fetched | |
Comparable strengths; Grover halves symmetric strength | cited, not fetched | |
RSA Shor cost: 6,189 logical qubits at n=2048 | cited, not fetched | |
ECDLP anchor: 2,124 logical qubits at 256 bits | cited, not fetched | |
ML-KEM, ML-DSA and SLH-DSA parameter sets | cited, not fetched |
Each live response reports live or fallback per source, with the fetch time. When a
feed is unreachable the app serves a sealed dated sample and says so, including the
sample's own date. Fallback data never replaces user-created data, and a dependency with no
live signal is scored neutral, never as if it were clean.
Deployment
flowchart TB
classDef data fill:#22d3ee,stroke:#0e7490,color:#083344
classDef engine fill:#a78bfa,stroke:#6d28d9,color:#2e1065
classDef agent fill:#34d399,stroke:#047857,color:#022c22
classDef infra fill:#94a3b8,stroke:#475569,color:#0f172a
classDef risk fill:#fb7185,stroke:#be123c,color:#4c0519
Push["push to main"]:::infra --> Ci["GitHub Actions on Node 22"]:::agent
Ci --> Type["typecheck + lint + test + build"]:::agent
Type --> Ok{"all green?"}:::risk
Ok -->|no| Stop["blocked, nothing deploys"]:::risk
Ok -->|yes| Ver["vercel --prod"]:::infra
Ver --> Neon["Neon integration injects DATABASE_URL"]:::data
Ver --> Alias["public production alias"]:::infra
Neon --> Guard["no DATABASE_URL means refuse, never fall back"]:::risk
Alias --> Live["scripts/verify-live.mjs proves 100+ checks"]:::agent
Live --> Badge["README badge, mcp.json, sitemap, OG metadata"]:::infraDATABASE_URL is injected by the Neon integration on Vercel. Both Postgres drivers are
declared in serverExternalPackages, because PGlite's WASM binary and seed data must stay
outside the server bundle. scripts/verify-live.mjs runs the whole loop against the public
alias with real HTTP and fails loudly if the store is not the hosted one.
📁 Project map
User routes
Route | What it is for | Persistence |
| Product entry: live posture plate, the import form, current research | Reads the owner's newest survey |
| Workspace. Filter by band and sort in the URL | Reads the owner's surveys |
| The primary action: manifest plus source excerpt |
|
| The workbench: fringe plate, horizon sweep, per-surface triage |
|
| Seal replay with the full event list | Reads the audit chain |
| Cross-survey what-if across five horizons, with bulk commit |
|
| Scoring table, resource model, engine factors, the classifier |
|
| Live JSON-RPC 2.0 console with preloaded calls and a full-loop button | Whatever the called tool writes |
| Export centre with a rendered preview | Reads, and |
| Replay every chain in the session |
|
| Public read-only report, only when the owner published it | None. Revocable |
API routes
Route | Methods | Responsibility |
|
| Proves the store with a real write probe |
|
| Normalized signals with per-source status |
|
| List and import |
|
| Read, rename / publish / horizon, retire |
|
| List and add a surface by hand |
|
| Decide, retune the shelf life, retire |
|
| Classify, teach, and export the learned table |
|
| Markdown, JSON or CSV download |
|
| Seal replay, optionally with the event log |
|
| Horizon and thresholds for the session |
|
| JSON-RPC 2.0 and the tool manifest |
Domain
Path | Responsibility |
| The scoring table: strength, quantum bits, NIST dates, replacement |
|
|
| Shor resource estimates from the published models |
| Manifest parsing per ecosystem, source scanning, package hints |
|
|
| Seed training set of realistic call sites |
| Canonical JSON and SHA-256 |
| Genesis, seal computation, chain replay |
| The only place state changes |
|
|
| The four public sources, timeouts, normalization, sealed fallback |
| Markdown, JSON and CSV builders |
Security model and ownership
Anonymous ownership. An edge proxy assigns a 128-bit random
HttpOnlycookie before anything else runs and forwards the id on an internal header, so the very first page load already knows the owner. Every query filters onsession_id. Another session reading your survey gets404, not403.Destructive operations. Retirement is a soft delete plus a sealed event. Rows stay as tombstones so replay never breaks; the public report link is revoked.
Abuse control. A 60-writes-per-minute in-process limiter per session, payload caps on every text field, a 60-surface import cap, and an allowlisted egress set. The limiter is documented as best-effort: a serverless runtime can recycle the process at any moment, so a durable limiter belongs in a hosted rate limiter or an edge rule, not in this application. There is deliberately no control here that pretends otherwise.
Input. Every body is validated with a Zod schema, every id is checked against a UUID pattern, every string is length-bounded, every SQL statement is parameterised, and no upstream payload reaches the UI unnormalized.
Secrets. There are none to leak. No API keys, no tokens, no client-side environment reads.
.env.exampledocuments shape only.Publishing is explicit and revocable.
/share/[id]returns404for anything the owner has not published.Errors. No stack traces and no environment values reach a client.
Integrity and seal replay
flowchart TB
classDef agent fill:#34d399,stroke:#047857,color:#022c22
classDef infra fill:#94a3b8,stroke:#475569,color:#0f172a
classDef risk fill:#fb7185,stroke:#be123c,color:#4c0519
Write["create, decide, retire"]:::agent --> Canon["canonicalJson: keys sorted, arrays ordered"]:::agent
Canon --> Seal["SHA-384(prevSeal + canonicalJson(event))"]:::agent
Seal --> Head["surveys.last_seal and event_count"]:::infra
Replay["GET /api/integrity"]:::infra --> Genesis["genesis derived from the survey id"]:::agent
Genesis --> Recompute["recompute every seal in seq order"]:::agent
Recompute --> Verdict["valid, or the first broken seq with a reason"]:::risk
Delete["delete"]:::risk --> Tomb["soft delete, row retained"]:::risk
Tomb --> ReplayTimestamps are stored as application-generated ISO-8601 text rather than database types,
which keeps the chain byte-identical across the hosted and embedded adapters. The unit
tests recompute every digest with Node's crypto directly, so the implementation and the
oracle would both have to change for the suite to pass.
User journey
flowchart LR
classDef data fill:#22d3ee,stroke:#0e7490,color:#083344
classDef engine fill:#a78bfa,stroke:#6d28d9,color:#2e1065
classDef agent fill:#34d399,stroke:#047857,color:#022c22
classDef infra fill:#94a3b8,stroke:#475569,color:#0f172a
classDef risk fill:#fb7185,stroke:#be123c,color:#4c0519
Visit["Land on /"]:::infra --> Import["Paste a manifest and a source excerpt"]:::data
Import --> Read["Read the fringe plate and the factor table"]:::engine
Read --> Sweep["Move the quantum horizon"]:::engine
Sweep --> Decide["Record a decision with a rationale"]:::risk
Decide --> Residual["Watch the residual score fall"]:::engine
Residual --> Export["Download the migration plan"]:::data
Export --> Share["Publish or revoke a report link"]:::agent
Share --> Verify["Replay the seal chain"]:::agent
Verify --> Retire["Retire the survey, tombstones retained"]:::risk🗺️ Roadmap
Now — shipped and verified
flowchart LR
classDef ok fill:#34d399,stroke:#047857,color:#022c22
A["Extract manifests and source"]:::ok --> B["Score with hndl@1.0.0"]:::ok
B --> C["Agent tools over JSON-RPC"]:::ok --> D["Sealed export"]:::okImport a manifest and a source excerpt, and see every cryptographic surface with the line it matched.
Move the quantum horizon and watch every must-migrate-by year recompute, then commit it.
Record a decision and a rationale, and watch the residual score fall.
Hand the plan to a reviewer as Markdown, JSON or CSV, and prove it with a seal replay.
Next
flowchart LR
classDef next fill:#22d3ee,stroke:#0e7490,color:#083344
A["Package graph reachability"]:::next --> B["Hybrid KEM rollout checklist"]:::next
B --> C["Saved plan versions"]:::next --> D["Signed share links"]:::nextReachability: score a surface by whether anything actually calls it, so a dormant RSA helper does not outrank the TLS terminator. Outcome: the worklist matches reality, not just the manifest.
Hybrid rollout checklist: per surface, the concrete steps for a classical-plus-PQ handshake, including certificate size and MTU implications. Outcome: an engineer can start on Monday.
Saved plan versions: snapshot a survey's analysis so a migration can be reviewed as a diff. Outcome: you can prove what changed between two reviews.
Signed share links: HMAC the public report path so a link cannot be guessed or replayed after revocation.
Later
flowchart LR
classDef later fill:#a78bfa,stroke:#6d28d9,color:#2e1065
A["SBOM ingest"]:::later --> B["Hardware inventory"]:::later
B --> C["Policy-as-code export"]:::laterSBOM ingest: read CycloneDX and SPDX directly, so you do not have to paste a manifest.
Hardware inventory: model HSM and KMS boundaries, which is where real key custody lives.
Policy-as-code export: emit the plan in the format your compliance tooling already reads.
🤝 Contributing
Issues and pull requests are welcome. Please read CONTRIBUTING.md first, and SECURITY.md before reporting anything security-related.
npm ci && npm run typecheck && npm run lint && npm run test && npm run buildLicense
MIT © PQC Triage contributors. See LICENSE.
Not security advice. PQC Triage is an engineering aid. It does not certify a system as quantum-safe, it models a calendar rather than your threat model, and its resource figures are published literature values under stated assumptions, not forecasts. Do not paste production secrets: what you import is stored so it can be scored.
This server cannot be deployed
Maintenance
Related MCP Connectors
Scan code for quantum-vulnerable cryptography and get NIST post-quantum migration guidance.
Trust-check any dependency for agents: OpenSSF Scorecard, licenses, CVEs, deps. 7 ecosystems.
Generate SBOMs, scan vulnerabilities, and analyze dependencies from local projects or Git repos.
PQC scanner for GitHub repos and smart contracts. Detects quantum-vulnerable ECDSA/RSA.
Related MCP Servers
- AlicenseAqualityCmaintenanceEnables AI agents to sign decisions with post-quantum cryptographic proofs and maintain secure audit trails for compliance. It provides tools for stamping events, verifying chain integrity, and exporting audit data across industries like finance and healthcare.452 npmMIT
- AlicenseAqualityBmaintenancePost-quantum readiness for AI coding agents: scans code for quantum-vulnerable cryptography (RSA/ECDH/ECDSA/DH) and returns NIST ML-KEM/ML-DSA/SLH-DSA (and hybrid) migration guidance, with fix verification and dependency checks. Content-based, advisory tools only; runs local (npx @quantakrypto/mcp) or as a hosted OAuth endpoint.1612Apache 2.0
- AlicenseAqualityAmaintenanceAn MCP server that scans local codebases for quantum-vulnerable cryptography (secp256k1, Ed25519, RSA, etc.) and CI signing commands, classifying each finding as quantum-broken, post-quantum, or neither. It runs entirely locally with no network calls, providing a deterministic inventory for AI agents.51,493 PyPIApache 2.0

Celmis MCP Serverofficial
AlicenseNot gradedqualityAmaintenanceEnables querying indexed code across multiple repositories with file-level citations, reviewing pull requests, auditing dependencies, and exporting SBOMs and evidence packs through MCP tools.3AGPL 3.0