Skip to main content
Glama

qrp-mcp

Every signature in your wallet, contract and validator rests on elliptic-curve cryptography. A large quantum computer breaks it. This tells your AI agent exactly where yours is.

An MCP server that scans a local directory for cryptography that Shor's algorithm defeats — secp256k1, Ed25519, BLS, Schnorr, RSA — plus weak primitives and CI signing commands, and classifies each one: broken by a quantum computer, post-quantum, or neither.

Everything runs on your machine. No network calls, no account, no API key, nothing uploaded. A tool that reads your keys' surroundings has no business phoning home, so this one makes zero outbound connections — enforced by a test, not promised in a paragraph. The only process it starts is a local git, to pin what it read, with the scanned repository's own hooks and filters disarmed.

Why this matters for chains and wallets

Bitcoin and Ethereum authenticate with ECDSA over secp256k1. Solana, Cardano and Polkadot use Ed25519. Ethereum's consensus layer aggregates with BLS12-381. Taproot adds Schnorr.

All four are public-key schemes whose security rests on discrete-log hardness — and all four fall to the same quantum algorithm. The practical consequence is specific: once a public key is exposed, the private key becomes derivable. Reused addresses, on-chain public keys, and long-lived validator keys are where that exposure already exists today.

None of this is a prediction about dates. It is an inventory question: which of my code paths sign with what? That question has an answer right now, and this tool gives it.

Related MCP server: Secure Code Review MCP Server

Quick start

Add it to your MCP client — no installation step, uvx fetches and runs it:

{
  "mcpServers": {
    "qrp": {
      "command": "uvx",
      "args": ["qrp-mcp"]
    }
  }
}

Then ask your agent:

Scan ~/code/my-protocol for quantum-vulnerable cryptography.

As a Claude Code plugin

The same server, packaged with a skill, so there is no config file to edit:

/plugin marketplace add StanimirTenev/qrp-mcp
/plugin install qrp@quantumreadiness

Then /qrp:pqc-scan in any project. Both routes need uv on your PATH, since uvx is what fetches and runs the server.

Without an agent: write the result to a file

uvx qrp-mcp scan ~/code/my-protocol --out result.json

This produces the same result as the scan_repo tool, written to a file you can read before it goes anywhere. Nothing is sent. --level trimmed removes the quoted lines of code but keeps each file and line number. The SHA-256 of the written bytes is printed, so anyone you send the file to can quote back exactly what they received.

Tools

Tool

What it does

scan_repo(path)

Scans a directory's source, CI/CD configs and infrastructure-as-code; returns findings, a summary, and the coverage block below

export_cbom(path)

The same reading as a CycloneDX 1.6 CBOM, with the coverage block inside it

compare_coverage(a, b)

Whether two scans produced numbers that can be compared at all

list_algorithms()

The algorithm families the server recognises and how each is classified

What it looks at

Chain and wallet codesecp256k1, ecrecover, ethers, web3, bitcoinjs, ECPair, btcec, tweetnacl, @solana/web3.js, solana_program, bls12-381, blst, @chainsafe/bls, BIP340/Taproot Schnorr. Solidity (.sol), Rust (.rs), Move and Cairo are scanned alongside Python, Go, Java, JS/TS, Ruby, PHP, C/C++/C# — headers included — PowerShell, Perl and shell.

Classical crypto anywhere else — RSA, DSA, DH, ECDSA and elliptic-curve usage, plus MD5, SHA-1, RC4 and DES/3DES. Not only through library calls: the names the protocols themselves use (ssh-rsa, rsa-sha2-512, ssh-dss, key types such as rsa-2048 and RSA_4096), the modern OpenSSL 3 form where the algorithm is a string argument (EVP_PKEY_Q_keygen(libctx, propq, "RSA", bits), the EVP_*_fetch calls), and the hash idioms people actually write (hashes.MD5(), hashlib.new('md5'), MD5Init, <sha1.h>, Go sha1.Sum).

Cipher suites, decomposedECDHE-RSA-AES128-GCM-SHA256 is ECDH and RSA, and DHE-DSS-… and DES-CBC3-SHA name families that reading the suite as one word never sees. IANA TLS_* names are read the same way. A banned component is not a use: !MD5 and !3DES in a cipher list are exclusions, and they are treated as such.

Protocols and dependencies, counted without inventing an algorithm — a pinned TLS version (MinVersion: tls.VersionTLS12, ssl_protocols, SslProtocols.Tls12, SSL3_VERSION), an SSH transport line, and a cryptographic library declared in package.json, go.mod, requirements.txt, Cargo.toml, pom.xml or a Gemfile. These are real facts about a repository and they are reported — in their own buckets, never in detected_algorithms. Each carries a basis: configured_protocol or declared_dependency, never observed_call, because an installed library is not a line of code that calls it. A version is not a verdict either: TLSv1.0 is marked deprecated, and quantum vulnerability is not claimed from a version number, since TLS 1.3 is vulnerable over X25519 and is not over X25519MLKEM768. -SSLv3 in an SSLProtocol line is a ban, and is recorded as one. Manifests are parsed structurally, so a library named in a comment is not a dependency.

Key sizes — a size named on the line (key_size=1024, rsa:1024, genrsa 1024, GenerateKey(..., 1024)) travels with the family, so a weak RSA key is reported as weak rather than as one more RSA. The smallest size seen per family is in algorithm_key_sizes.

Hybrids and composites — the RFC 10024 TLS groups X25519MLKEM768, SecP256r1MLKEM768 and SecP384r1MLKEM1024, OpenSSH 10's default mlkem768x25519-sha256, and the composite certificate algorithms of draft-ietf-lamps-pq-composite-sigs such as id-MLDSA44-RSA2048-PSS-SHA256. A hybrid holds if either half holds, so the post-quantum scheme leads — and the classical half is carried in also_present rather than dropped, since it is the component Shor breaks.

Post-quantum schemes, by family — ML-KEM, ML-DSA, SLH-DSA, Falcon (FN-DSA), NTRU, Classic McEliece, BIKE, HQC, FrodoKEM, XMSS, and the stateful LMS/HSS of SP 800-208 that CNSA 2.0 requires for firmware signing. The nine schemes NIST advanced to its third additional-signatures round in May 2026 — FAEST, HAWK, MAYO, MQOM, QR-UOV, SDitH, SNOVA, SQIsign, UOV — are recognised as candidates, and CROSS as dropped from that process.

Each carries the mathematical family it rests on (structured or unstructured lattice, code-based, hash-based, isogeny-based, multivariate, symmetric-based) and where it stands: standardised, selected, candidate, withdrawn, eliminated or broken. SIKE is reported as broken and HAWK as withdrawn rather than counted as quantum-resistant — "post-quantum" is a category, not an assessment.

Certificates and keys.pem, .der, .crt, .cer, .cert, .csr, .key, .pub, .p12, .pfx. Algorithms are resolved from the object identifiers inside the DER and from PEM labels and OpenSSH key types, and private key material is reported separately. This does not parse X.509: it keeps only the identifiers already in the classifier, so a malformed certificate yields nothing rather than nonsense.

Configurationnginx.conf, sshd_config, openssl.cnf, swanctl.conf, .ini, .toml, .properties, .hcl, .json, and any YAML that is not a manifest. This is where a TLS or SSH hybrid group is chosen: X25519MLKEM768 and mlkem768x25519-sha256 are almost never strings in code. IKE proposal syntax is read here too — ecp384 is NIST P-384, modp2048 is group 14.

Quantum-resistant mechanisms, not only algorithms — RFC 8784 mixes a postquantum preshared key into IKEv2 key derivation, so a tunnel resists a quantum adversary with no post-quantum algorithm present. A scanner matching algorithm names cannot see that by construction, and would report a protected deployment as classical_only. PPK is matched by the directives that switch it on and classified as quantum_resistant_mechanism — deliberately not pqc_ready, because a preshared key is not ML-KEM. Whether it holds depends on the entropy of the key and on out-of-band distribution, neither of which is visible in a file, and the finding says so.

CI/CD pipelines — signing commands such as gpg --sign, cosign sign, signtool, jarsigner, codesign.

Infrastructure as code — Terraform and Kubernetes key algorithms, and private key material committed by mistake.

Build files, includes, test recipes and key inventoriesMakefile, CMakeLists.txt, .in, .cmake (a build file enumerates which algorithms a tree implements at all), .inc (the assembly and C fragments of implementations — OpenSSL keeps its ML-DSA there), .t (Perl test recipes: tests are code, and skipping them quietly is exactly what this tool argues against), and known_hosts / authorized_keys, where the key type is named on every line.

Not read, on purpose — documentation: .txt, .md, .pod, .rst. Measured across five real repositories, reading them would have added more than 11,000 "findings" from help texts and changelogs. An algorithm mentioned in prose is not a deployment. The boundary is pinned by a test, so it is a declared scope rather than a silent skip — the same standard this tool asks of others. Binaries and images are not read either.

Accidents of the alphabet are not findings — a match inside a long hexadecimal or base64 run does not count. A NIST test vector in OpenSSH spells ed448 inside its message bytes.

Real run against OpenZeppelin's contracts (711 files, about five seconds):

{
  "detected_algorithms": ["ECDSA", "RSA"],
  "summary": {
    "quantum_vulnerable_count": 2,
    "pqc_ready_count": 0,
    "highest_severity": "high",
    "pqc_readiness": "classical_only"
  }
}

What the coverage block says

Every scan carries one, because a coverage figure without its conditions is not comparable to another coverage figure. Four things, each answering something the percentage cannot:

  • instrument — the version and the emitter's own commit. Two runs of this package once reported the same version from code that differed by a commit, so the version alone does not identify what did the reading. Where the tool runs from an installed wheel there is no commit, and the field says which absence rather than going quiet.

  • corpus — the commit that was read, whether the tree was dirty, and whether the clone was shallow. A commit identifies a tracked tree; a scanner walks a filesystem, and the two are not the same thing.

  • window — when it was read.

  • scope — the denominator, the numerator, and every file that was in the first and not the second, with a reason. The reasons are a closed set: type_not_claimed is a boundary this tool declares, unreadable is a failure it hit, and they are never collapsed. A reason with no instances is reported at zero rather than omitted.

Measured across five real repositories (certbot, OpenSSH, Vault, Bitcoin, OpenSSL) at this release, the scan reads 67% of the files present — 74% of OpenSSL, 85% of OpenSSH, 66% of certbot, 77% of Bitcoin, 58% of Vault. The rest is counted and named with a reason. A directory that cannot be entered or listed is reported in unreadable_directories; its files cannot be counted, so the scan then says it cannot account for every file instead of claiming it read them all.

It also states which kind of claim the numbers are. Coverage is a claim about reading, not about finding: a file can be opened, counted, and still be one this tool was blind in. Reaching a file is something a scanner can measure about itself; whether it found what was there is not, because a silent rule and an absent algorithm produce the same output. So the block reports claims.axis: reached, and declares that it holds no control — the corpus with independently established contents that would license the second claim — naming the absence rather than implying the stronger reading.

What the number is, and what it is not

A coverage figure here is the overlap between the file types this tool claims and what the corpus is made of. It is not a discovery rate. A scanner claiming 32 extensions cannot reach 100 % against a tree holding 79 kinds, so a lower number means more file types left unclaimed rather than more cryptography left unfound — and the two read identically unless the page says which it is.

The denominator stays conservative anyway: you cannot know a .txt holds no PEM block without opening it, and key files often carry no extension at all.

Concentration, and the partition it is measured over

The block reports where the mass sits, not only how large a total is — because an aggregate over a lopsided population describes its largest members and reads as describing all of them. Measured across five open-source repositories: three file kinds account for 52 % to 89 % of everything not read, and the two largest kinds present are 43 % to 55 % of everything counted.

Three values travel with every share, and the third is the one most tools omit:

  • share — how much the largest members are.

  • cardinality — how many kinds that share is out of. Three of 24 kinds at 69 % is five and a half times a flat split; three of 63 at 68 % is fourteen times one. Without it the same share means different things and cannot be read as high or low at all.

  • partition — what a kind is. A concentration is not a property of an aggregate but of the aggregate crossed with the partition it was measured over: the same tree split by extension, by directory, or by language gives different shares with nothing changing on disk. This block partitions by file extension and says so beside every figure.

The signer's sentence carries the same three inside the bracket holding the count, because a figure lifted out of a document without them is the failure the block exists to prevent:

This scan read 822 of 1250 files (65.76%); the remaining 428 (3 of 24, by extension —
files with no extension, .rst and .txt — being 68.93% of them) are listed with a reason each.

The published measurement, with the raw artefacts: quantumreadiness.eu/evidence/scan-coverage

The CBOM it emits

export_cbom produces a CycloneDX 1.6 document, validated against the published schema. Three things travel in it that a component list alone cannot say:

  • compositions.aggregateincomplete where files were not examined, and unknown where the tool cannot account for its own reading. Reading every file is not enough for complete: that word claims every asset present was found, which is the second axis, and only a held control licenses it. The document used to say complete on the strength of the denominator alone; comparing against other scanners showed findings missed inside files that had been read.

  • properties — the whole coverage block. It travels there because the root object is additionalProperties: false and the format has no field for it; the awkwardness is the point rather than something to hide.

  • evidence.occurrences — file, line and matched text for every asset.

Output is deterministic where it matters. The serial number is derived from the target, the two pins and a digest of what was found, so the same code over the same corpus that finds the same things gets the same serial, and a different result gets a different one. The timestamp and the coverage window record when the run happened, so those fields differ between runs.

Measured against the other scanners

In September 2026 three free tools that do the same job — CryptoScan, CBOMkit-hyperion (sonar-cryptography) and CBOMkit-theia — were run over the same repositories and the findings compared line by line. What they found and this tool did not became the 0.8.0, 0.8.1 and 0.9.0 releases. Of what this tool does that they did not, one claim needed narrowing when a wider survey was done, and it is corrected here:

  • Coverage inside the document. Several tools do report what they skipped: QuantaKrypto's qscan counts scanned and unread files, IBM Quantum Safe Explorer logs each excluded file with a reason, SandboxAQ shows missed locations. What we have not found elsewhere is the coverage travelling inside the CycloneDX CBOM — a reason per group of unread files, the paths that could not be read, the directories that could not be entered, and accounts_for_every_file. qscan computes the counts and drops them on export, so it is one flag away from the same thing.

  • This scanner separates reading from finding in the document itself, and refuses to say complete without a control that licenses the stronger claim. Reading is self-measurable; finding is not.

  • sntrup761, the default hybrid in OpenSSH from 9.0 to 9.9 — OpenSSH 10 defaults to mlkem768x25519-sha256 — has no rule in CryptoScan; this tool reports 145 lines of it in the OpenSSH tree.

  • Private keys are recognised by content, not by file name: the 45 key files CBOMkit-theia found in OpenSSH and this tool did not are read from 0.9.0, and a PEM header with the body elided — documentation — is not one.

  • An excluded cipher (!MD5) is counted as a use by CryptoScan; here it is an exclusion.

  • On certbot, this scanner finds algorithms in 26 files against hyperion's 7, and hyperion's one extra finding is wrong (RSA-96 where certbot defaults to 2048).

Measured on a corpus this project did not write

The nearest tool of the same kind is QuantaKrypto's qscan — lexical like this one by its own changelog, and the only other tool in this class that publishes a detection figure. In September 2026 both were run against Cryben (Näther & Hirsch, arXiv 2608.04857): an independent corpus with its own reference CBOM and its own scorer, written by neither of us. The scripts and the raw output are reproducible; the method matters more than the number.

qscan 0.12.0

this tool 0.8.1

this tool 0.11.0

Cryben, in the scope this tool declares

30/37

22/37

36/37

qscan's own corpus, qscan's own metric

0.847

0.511

0.909

the same, no wildcard credit for either tool

0.790

0.881

qscan's corpus without its structural labels

0.802

0.714

0.944

Cryben, full 197 findings, precision

0.93

0.667

Cryben, full 197 findings, F1

0.34

0.346

a negative corpus, 200 files with no such cryptography

200 clean

Vault, wall clock

7.9 s

173 s

219 s

Four things those numbers do not mean, said here rather than left to be assumed:

  • Cryben is 37 cases in this tool's scope. A figure from 37 cases has a wide interval. It is a floor worth publishing, not a precision claim.

  • The scorer is theirs. qscan's metric matches per file, not per line, and credits a finding that names no algorithm. An earlier version of this section claimed the figure was unchanged with that credit withdrawn. It was wrong: the switch that withdrew it dropped only one bucket, while elliptic-curve findings kept the credit unconditionally. Withdrawn properly, and applied to both tools, the numbers are 0.818 for this tool and 0.790 for qscan. The conclusion survived the correction; the sentence did not.

  • A per-scan control is still not held. claims.control.held stays false in your scan unless you run one, and it should: a figure measured here says nothing about your repository.

  • Recall is not the axis this tool is weakest on — precision is. On Cryben's full 197 findings, scored by its authors' own tool, this scanner's precision is 0.667 against qscan's 0.93. It was 0.542 one release ago. Reaching a rival's recall while reporting more that the reference does not is not the same as being the better inventory, and it would be dishonest to publish the first number without the second.

qscan is faster by a factor of about 24. It is not deeper: it is lexical, by its own changelog, as this section already says. Measured per language on its own corpus it leads in none by more than three labels and trails this tool by five in Go; its real edge is in TLS, SSH and dependency lines rather than in any language. This tool reads more kinds of file, says what it did not read, and does not invent a family for an asset that names none.

The corpus that measures the other direction

A corpus of labelled findings can only ever say what a tool misses. It says nothing about the twenty lines in the same file that are not cryptography. So this release is measured against one written for the opposite question:

  • 200 files with no quantum-vulnerable cryptography at all — ordinary code in fifteen languages, configuration, CI, infrastructure, manifests, lockfiles, data and documentation. Any finding on one of them is a false positive.

  • 100 near misses — cryptography named, banned, discussed, tested against or imitated, but not used: an SSLProtocol line removing SSLv3, a policy listing forbidden algorithms, a lint rule quoting the pattern it forbids, a test asserting an algorithm is rejected, a docstring explaining why RSA was dropped, base64 that is a JWT payload rather than a key.

Every file was written and labelled before the scanner was run over it, and the corpus was written by someone who had not read the scanner's rules. A corpus assembled by looking at what a tool reported measures the tool against itself, which is the circularity this document criticises elsewhere.

Result: 200 of the 200 negative files are clean — no finding of any kind. On the 100 near misses, this release reports 83 findings the labels say should not read as a use, down from 136. What remains is one shape: a file whose whole purpose is to forbid. A lint rule quoting hashlib.md5(...) as the thing it bans is, line by line, indistinguishable from code calling it; telling them apart needs file-level context this release does not attempt.

The corpus is a floor, not a measurement. It was written by the same hands that wrote the tool, so a construct nobody here thought of is in neither. Its honest use is as a difference between two releases.

What is still missing here

Stated rather than hidden, and each of these is a known gap rather than a suspicion:

  • A finding carries no confidence level. A bare word in a comment and a real call site look alike. In a hand-checked sample of 20 new findings on Vault, one was in a comment.

  • SSH and TLS assets are read at 8/14 and 7/11 on qscan's corpus; X448 at 4/8.

  • Speed. Reading key material by content costs about 26% over 0.8.1 on a large tree.

  • A symlink is never read. Where a tree reaches content only through a link whose target sits in a directory this tool excludes, that content is not scanned. It is named as a link rather than silently skipped, but it is not read.

  • Symmetric cryptography, hashes for integrity, KDFs and random number generation are out of scope by design. This tool reports what a cryptographically relevant quantum computer would break. On Cryben's full 197 findings — most of which are AES, SHA-256 and KDF — it scores 0.13, and that is the scope working, not failing.

What an outside review found

0.9.0 was reviewed by someone who did not write it, from the published ZIP, and reported nine defects. All nine reproduced here before anything was changed, and all nine are fixed in 0.10.0. Two of them were about the claims this tool makes for itself, which is the worst place to be wrong:

  • A symlink carried the scan outside the directory it was given. A link inside the tree pointing at a file beside it was read, and reported under the link's name. This tool is pointed at code its user did not write, and the excerpt travels into an agent's context and into any exported CBOM, so that was the declared boundary failing. Links are no longer followed. Each is named in symlinks_not_followed, with a relative path when the target is inside the root and the words "outside the scanned directory" otherwise -- printing an outside path would leak what reading it did. A linked directory sets accounts_for_every_file to false. On certbot, which uses 48 of them, coverage falls from 68.9% to 65.8%: the links are now counted as present and not read. No algorithm is lost, because each target is still read at its own path.

  • compare_coverage keyed on a commit, and a commit is not what was read. A dirty emitter still compared; an unverified corpus compared because None read as False; two different subdirectories of one commit compared at 100% and 0% coverage; a git-ignored file that the scan reads changed the corpus while both pins stayed clean. Comparability now keys on corpus.content_digest -- a hash over the files read and the text read from them, the files skipped with their sizes, and every entry not read with its reason. The git pin stays as provenance a reader can follow; it no longer carries the conclusion. dirty is three answers, and None means nobody checked.

The rest: a malformed coverage block returned an exception instead of unestablished; certificate evidence came off a set, so its order moved between interpreters; --out ~/file passed its check and failed its write; and three tests read the tool's own git pins from the environment, so they passed from a clone and failed from the published tarball -- which anyone who downloaded 0.9.0 and ran its tests saw, and we had not, because we always ran in the checkout. Extracting the release and running its tests in a fresh environment is now part of shipping one.

Why deterministic

There is no LLM inside this tool. The same input always produces the same output, and every finding points at a file and a line you can open yourself.

That is the point of handing it to an agent: the agent brings the language, the tool brings the truth. An agent guessing about your signing code is worse than nothing; an agent reading a deterministic inventory can actually reason about it.

What it is not

It reads source, configuration, CI pipelines, infrastructure-as-code, Kubernetes manifests, build files, certificates and key inventories. It does not read documentation, binaries or images.

Every file under the path is accounted for in one of three ways: scanned, unreadable, or skipped because the tool does not claim that type — the last counted by extension, so the coverage figure has a base. files_scanned + unreadable_files + files_skipped_by_type always equals files_present. A directory the scan cannot enter or list is named in unreadable_directories; its files cannot be counted, so the scan then says it cannot account for every file instead of claiming it read them all. A scan that read seven files out of nine is a different report from one that read seven out of four hundred, and only one of them is worth trusting.

A free inventory tool, not a readiness assessment. It deliberately does not do:

  • risk scoring or prioritisation,

  • migration planning,

  • network or host scanning, or reading a system certificate store,

  • tracking change over time.

Those live in the Quantum Readiness Platform, the product this tool is extracted from. Nothing here is crippled to push you there — what it does, it does completely.

It also does not tell you that you are about to be hacked. It tells you what you are using.

License

Apache-2.0.

Available Tools

4 tools
compare_coverageA
Read-onlyIdempotent

Say whether two scans produced numbers that can be compared at all.

Two coverage percentages can differ because the estate moved, because the instrument moved, or because the corpus was collected differently, and the percentages show none of the three. This reads the pins and conditions in both blocks and answers with one of three verdicts.

comparable means nothing that moves the number differs. not_comparable lists which conditions differ, each with what it means, so the reader knows whether to re-run, re-clone or ignore it. unestablished means the blocks do not carry enough to decide -- an unpinned corpus, or an emitter that names no commit -- which is a different situation from a known difference and has a different repair.

Use it before putting two coverage figures in one table. Do not use it to compare findings; it reads conditions, not results.

ParametersJSON Schema
NameRequiredDescriptionDefault
firstYesThe `coverage` block from one scan result.
secondYesThe `coverage` block from another scan result.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly/idempotent/non-destructive, so safety is covered. Beyond that, the description discloses the full behavioral model: it reads pins and conditions rather than results, returns one of three named verdicts, explains what each verdict means, and flags that 'unestablished' implies a different repair than a known difference. That is genuine context not available from annotations or the schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core purpose, then a rationale paragraph, then a verdict taxonomy, then a use/don't-use instruction. Every sentence earns its place, though the multi-line prose format is slightly longer than strictly necessary for a two-parameter tool.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read-only comparison tool with an output schema, the description supplies everything an agent needs: purpose, preconditions (pinned corpus, named commit), the meaning of each verdict, and the decision each verdict implies. Nothing material is left ambiguous.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the two parameters (`first`, `second`) are already documented as coverage blocks. The description reinforces that it reads 'the pins and conditions in both blocks' but adds no syntax or field-level detail beyond the schema. Baseline 3 is appropriate when the schema carries the parameter burden.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a clear verb (compare/say whether) and resource (two scans' coverage blocks), and draws a hard boundary between comparing conditions vs comparing findings. The explicit distinction 'Do not use it to compare findings; it reads conditions, not results' separates it from any result-diffing sibling.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives an explicit when-to-use ('before putting two coverage figures in one table') and an explicit when-not-to-use ('do not use it to compare findings'). It even decomposes the three verdicts into decision-relevant repair actions (re-run, re-clone, ignore), which is unusually actionable guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

export_cbomA
Read-onlyIdempotent

Scan one directory and return a CycloneDX 1.6 CBOM that carries its own coverage.

Same reading as scan_repo; a different document. Use this when the result has to leave the machine -- an auditor, a customer, a pipeline artefact -- and scan_repo when a person or an agent is going to read it here.

What the document carries beyond the components: compositions.aggregate states how complete the list is in the schema's own vocabulary, complete only when every file present was examined; properties carries the whole coverage block flattened, including every file not examined with its reason; and each asset carries evidence.occurrences with file, line and matched text.

The coverage block travels as properties because the CycloneDX root object is additionalProperties: false and the format has no field for it. That is the point of emitting it this way rather than a limitation to work around.

The serial number is derived from the target, the two pins and a digest of the findings, so two runs of the same code over the same corpus that find the same things share it and a different result does not. The timestamp and coverage window record when each run happened.

ParametersJSON Schema
NameRequiredDescriptionDefault
pathYesDirectory to scan and export, same argument as `scan_repo`.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the read-only and idempotent annotations, the description discloses how coverage is represented via compositions.aggregate, properties, and evidence.occurrences. It also explains why properties is used, and how serial number and timestamp are derived. This goes well beyond what annotations alone convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well organized: purpose, usage rule, output semantics, rationale, and serial/time details. Every section earns its place, and the most important routing information appears early.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a one-parameter export tool with an output schema and read-only annotations, the description covers invocation, when to choose it, what the returned document contains, and design rationale. No significant gap remains.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The only parameter, path, has 100% schema description coverage, so the schema already says it is a directory to scan and export using the same argument as scan_repo. The description adds no meaningful new parameter-level detail beyond that, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

First sentence names a specific action and deliverable: scan a directory and return a CycloneDX 1.6 CBOM. It also contrasts with scan_repo by calling it a different document, which separates the tool from its sibling.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly says to use export_cbom when the result has to leave the machine for an auditor, customer, or pipeline artifact, and scan_repo when a person or agent will read it locally. This is a clear, decision-ready routing rule.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_algorithmsA
Read-onlyIdempotent

List every algorithm family this server can recognise, and how each is classified.

Returns the whole table: family name, classification (classical and quantum-vulnerable, post-quantum, symmetric, hash, or deprecated) and the kind of use it stands for. Reads no files and takes no arguments.

Use this to check coverage before trusting a scan -- whether a scheme the project depends on is one this server knows at all -- or to explain a classification without scanning. To find what a particular directory uses, use scan_repo instead; this tool never looks at a codebase.

An algorithm absent from this table is reported as unknown by a scan, which is not the same as absent from the code.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations (readOnly, idempotent, non-destructive), the description adds meaningful behavioral detail: it reads no files, takes no arguments, and returns the whole table. It also discloses the important semantics that an algorithm absent from the table is reported as 'unknown' by a scan, which is not the same as absent from the code.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured, front-loaded with the purpose, followed by return value, usage context, and a caveat. Every sentence contributes meaningful information without redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-parameter, read-only listing tool with a rich description and an output schema present, everything an agent needs is covered: what it returns, when to use it, when to use the alternative, and the key unknown-classification caveat.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With zero parameters and 100% schema description coverage, the baseline is 4. The description reinforces that the tool takes no arguments and reads no files, which adds a small amount of clarity beyond the empty schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states exactly what the tool does: 'List every algorithm family this server can recognise, and how each is classified.' It clearly identifies the resource (algorithm families) and the action (listing with classification), and it distinguishes itself from the sibling scan_repo by noting it never looks at a codebase.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit when-to-use guidance: check coverage before trusting a scan and explain classifications without scanning. It also names the alternative, scan_repo, and states the condition for choosing it instead ('to find what a particular directory uses'), with a clear exclusion: 'this tool never looks at a codebase.'

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

scan_repoA
Read-onlyIdempotent

Inventory the cryptography inside one local directory tree, file by file.

Reads source, configuration (nginx.conf, sshd_config, .ini, .toml), CI pipelines, Terraform and Kubernetes manifests under path. Returns each algorithm found with its file and line, the mathematical family and standing of every post-quantum scheme, and a coverage count.

Use this to answer what a specific project on this machine actually uses. Do not use it to ask whether this server knows a given algorithm, or to explain how one is classified without scanning anything -- list_algorithms answers that from the same table and reads no files. It is also the wrong tool for a network endpoint, a running host or a certificate store: it opens files on disk and nothing else.

Coverage is reported as a fraction with a base. files_scanned + unreadable_files + files_skipped_by_type == files_present. A file that could not be opened is listed, never counted as scanned, because no findings in a file nobody read is not the same as a file that is clean. Files skipped because this tool does not claim their type are counted by extension, so the reader can judge the boundary rather than assume past it.

Cost scales with the size of the tree, so a large monorepo takes proportionally longer; there is no cache and no partial mode.

ParametersJSON Schema
NameRequiredDescriptionDefault
pathYesDirectory to scan, absolute or relative to the working directory: a checked-out repository, a service directory, a config tree. Vendored and build directories (.git, node_modules, vendor, dist, build, target) are excluded and do not count toward files_present.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the readOnly/idempotent/destructive annotations, the description discloses coverage arithmetic, unreadable files listed but not counted, skipped-by-type behavior, exclusions, no cache, no partial mode, and that cost scales with tree size. Nothing material about side effects or limits is hidden.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Purpose is front-loaded and the description is organized into clear blocks: scope, outputs, usage boundaries, coverage semantics, cost. It is slightly longer than strictly necessary, but every block contributes decision-relevant information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a one-parameter read-only tool, the description covers input semantics, output coverage, exclusions, failure handling, cost, and alternative tools. The presence of an output schema means return-value details do not need to be duplicated, so nothing material is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The single path parameter is already fully described in the schema (absolute/relative, repo/service/config tree, excluded vendored/build directories), so schema coverage is 100%. The description reinforces what `path` points at and adds file types read, but parameter semantics are adequately carried by the schema; no compensation needed.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opening sentence names a specific verb and resource: 'Inventory the cryptography inside one local directory tree, file by file.' It states what is read and returned (algorithms with file/line, families, coverage count), and the sibling list_algorithms is explicitly positioned as the read-no-files alternative, so the tool is not confused with it.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit when-to-use ('answer what a specific project ... actually uses'), explicit when-not-to-use (server algorithm knowledge, explanation without scanning, network endpoints, running hosts, certificate stores), and names the alternative list_algorithms that 'reads no files.' This is exactly the level of routing guidance an agent needs.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 2 tool updatesv0.7.0
    • Addedcompare_coverage
    • Addedexport_cbom
  2. 1 tool updatev0.6.0
    • Changedscan_repo1 field changed
      • addedInput schema / properties / path / description
        Added value: +"Directory to scan, absolute or relative to the working directory: a checked-out repository, a service directory, a config tree. Vendored and build directories (.git, node_modules, vendor, dist, build, target) are excluded and do not count toward files_present."
  3. 2 tool updatesv0.1.0
    • First observedlist_algorithms
    • First observedscan_repo

TDQS

A4.6/5.0

Scored across 4 tools

Disambiguation4/5

Each tool has a distinct job: list_algorithms is a read-only reference, scan_repo returns a human-readable inventory, export_cbom produces a portable document, and compare_coverage assesses comparability of coverage numbers. The only near-overlap is scan_repo vs export_cbom, but their output formats and use cases are explicitly separated.

Naming Consistency5/5

All tool names follow the same snake_case verb_noun pattern: list_algorithms, scan_repo, export_cbom, compare_coverage. The verbs are clear, distinct, and consistently positioned.

Tool Count5/5

Four tools is well-scoped for the narrow domain of cryptographic repository scanning and coverage reporting. Each tool earns its place and none feels redundant.

Completeness4/5

The core workflow is covered: understanding detection coverage, scanning a directory, producing a CBOM, and judging whether coverage numbers are comparable. Minor gaps exist, such as no direct way to diff two scans' findings or scan a single file, but these do not block the server's stated purpose.

Maintenance

ActivityMaintained
ResponsivenessUnresponsive

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    Local MCP server that scans code for security issues (secrets, dependencies, configurations, risky patterns) and integrates with GitHub Copilot in VS Code for automated pre-commit reviews.
    -
  • A
    license
    C
    quality
    B
    maintenance
    Security scanner and MCP server that catches dangerous patterns in MCP servers and AI agent projects, such as leaked secrets, shell execution, and prompt-injection text. Runs as both a CLI and MCP server with CI-friendly severity gates.
    2
    1
    MIT
  • A
    license
    A
    quality
    A
    maintenance
    Post-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.
    16
    11
    Apache 2.0