Changelog
What changed in each version of Faintprint, newest first. Every version is installed by its exact number, so you always know which one produced a report: faintprint --version prints it, and every report carries it.
0.5.0 — 2026-11-09
The report a client expects.
- Every server now gets one line that answers "may we use it?" — Do not use, Do not use until checked, Check before use, Not finished, or No signs of an attack followed by what the server can do ("nothing powerful found", or what it can do and "give it only to people who need that"). It is at the top of each server's page, on the run's page and in the terminal's results table, with one sentence of what to do. It is worked out from the two ratings and whether the check finished; the build check and the exit codes are exactly as before.
- Advice is labelled for whom it is. The advice under each finding now reads "What the publisher should change:", because you cannot edit someone else's server; what you can do is in the line at the top.
- The whole attack is shown where the attack is. Under every sign of an attack, the page shows the tool's whole description (or the 1,000 characters around the match, for a longer one), with the matched words marked. No finding moved from one rating to the other.
- A "Not finished" page starts with what nobody has read yet: the borderline passages, then the same tool's wording that tells the AI how to use other tools, under "Worth reading before you decide".
- A local server's ready command. For a local server in a config file, the terminal now prints the MCP Inspector line with that server's own command and arguments filled in. Any argument that looks like a key is replaced by
<hidden>, the config's environment settings are not copied, and the line is never written to a report or file. - Your Anthropic key is checked before the price question. With
--review, one free token count — it sends your key and one fixed word, never a server's text — tells you straight away if the key is refused ("nothing was spent"). Without a key, the command also says that a Claude subscription is not an API key, and where to create one. The pipeline step does the same check at the start of the job. - The run's page shows each server's own name with the file or config entry it came from beside it. An address that ends in ".", "," or ")" and gets no answer is followed by a hint to try it without that character; nothing is fetched on the guess.
- Reports are now format 5 and
summary.jsonformat 4: fields were added (decision,what_to_do, the descriptions on attack items, and per serverserver_nameandlisted_as), none removed. The SARIF file is unchanged.
0.4.0 — 2026-11-07
A shorter path on a laptop.
- Install once with pipx, then type
faintprintin any folder. The install line is now onepipx install, with your token handed to that one command inPIP_INDEX_URL; nothing on your machine keeps the secret. To update, run the same line with the new version number:--forcemoves pipx to exactly that version. The lines for a Python environment of your own are still in the README, under "Without pipx". faintprint scanwith nothing named looks for servers. It reads the config files of Claude Desktop, Claude Code, Cursor, Windsurf and VS Code on this machine (read only) and scans the servers they list, exactly as--discoverdoes, and its first line says so. If it finds none, it still ends with exit code 2. Naming what to scan works as before.- The report opens in your browser when the scan ends, when you typed the command in a terminal;
--no-openskips that. In a pipeline, a script, piped output, the container image or a session without a screen it never opens, and opening never changes the exit code. The report pages load nothing from the network. - A web address typed without
https://no longer ends in a bare "no such file". When the name is not a file here and looks like an address, the command says so and shows the full form to type (http://for a server on your own machine). Nothing is fetched on a guess, a file that exists is always read as a file, and the exit code stays 2. - The AI review's input is fenced more tightly. Text a server writes can no longer imitate the markers that keep the server's words apart from the reviewer's instructions anywhere in what the reviewer reads — the tool's name, title and description, its parameters, the other tools' names — where before only the passage under review was protected. The one exception is the name of a resource or prompt, which is shown as written. On the attacks of this kind we measured, the reviewer answered as before every time it answered, and declined to answer a little more often; a declined check counts as no confirmation, never as a clearance.
- Nothing about what is scanned, how it is rated or when the build check fails has changed. The report format stays 4 and the summary format 3.
- In a pipeline (step version 1.2.0) the step installs 0.4.0 by default. It works as before: it scans exactly what you name and never opens a browser.
0.3.0 — 2026-10-29
Findings in GitHub's Security tab.
faintprint scan --sarif FILEalso writes the findings in SARIF 2.1.0, the standard format code scanners hand their findings over in. Uploaded to GitHub, each sign of an attack becomes an alert in the repository's Security tab: Likely attack as critical, Suspicious as high, Minor as medium. A passage the AI reviewer confirmed is an alert of its own, with the reviewer's reason. A borderline passage the review did not read, or read and could not decide on, is a note. Passages the reviewer cleared and "What it can do" stay on the report page.- Each alert points at the line that holds the passage when the tool list is a saved file in the folder you scan from, at the server's entry when a config file there names a remote server, and otherwise at the copy of the tool list the run saves in the report folder. The same finding stays the same alert from run to run, even when lines move or the version changes.
- A saved tool list read from outside the folder you scan from is now copied into the report folder, so the place each finding points at always exists. Nothing else about what is scanned, how it is rated or when the build check fails has changed.
- Every report now says where each finding is: a
place(file, line, column) on every item and passage, and asourcefor the server. Items found by the fixed rules also carry the sentence around the match, and confirmed passages the fix line. The report format is now 4 and the summary format 3 (summary.jsonnames the SARIF file); fields were added, none removed or renamed. - In a pipeline (step version 1.1.0) the reports include
faintprint.sarif, and on GitHubupload-sarif: trueuploads it to code scanning. That needs the workflow permissionsecurity-events: write, and on a private repository GitHub Code Security.
0.2.0 — 2026-10-20
The product has its name.
- The command is
faintprint. After installing, runfaintprint scan …instead ofpython -m mcp_scanner scan …. The package is installed asfaintprint(with remote servers:faintprint[connect]). Nothing about what is scanned, how it is rated or when the build check fails has changed. faintprint --versionprints the version, the number of static rules, the AI reviewer's prompt version and model, and the MCP library version. It reads nothing and writes nothing.- Every report says what made it. Each server's JSON report and
summary.jsoncarry a newproductblock with the name and version, and both pages show them at the bottom. The report format is now 3 and the summary format 2; fields were added, none removed or renamed, so anything that read version 0.1.0's files still finds what it read. - A tool list the command saves now says
"_saved_by": "faintprint scan". Tool lists saved by 0.1.0 are read exactly as before. - Installed from a private package index with your own access token, or run as a container image with the same token (built for Intel/AMD Linux; Apple-silicon Macs run it under Docker's emulation). The package file is built so that the same source always gives the same file, byte for byte, and the checksum on the release page is the one you download.
0.1.0 — 2026-10-17
The first installable release, for pilots.
- One command scans MCP servers — by web address, from the config files of Claude Desktop, Claude Code, Cursor, Windsurf and VS Code (or every one found on the machine with
--discover, read only), or from a saved tool list. Local servers are never started and no tool is ever called; a local server is scanned from a tool list you save with the MCP Inspector, and the guide gives the one command. - Two ratings per server: Signs of an attack (No signs found · Minor · Suspicious · Likely attack) and What it can do (Limited · Moderate · High), with the exact sentence from the server's own text beside every finding.
- An optional AI review of borderline passages, on your own Anthropic API key, only after the passages, the number of calls, the price and exactly what is sent have been shown and you say yes (
--yeswithin--max-costin a pipeline). An unfinished review is never shown as a clean result. - A build check with exit codes 0 (pass), 1 (fail), 2 (could not run) and 3 (not finished), at a level you choose with
--fail-on. - Fewer false alarms than the version tested with the first customer: wording about sending credentials is now matched only within one sentence and towards a real destination, and "accepts any web address" no longer fires on fields a tool returns, or on a parameter merely described as fetching something.
- Reports as HTML and JSON per server,
index.htmlandsummary.jsonper run, and each fetched tool list saved beside its report so the same report can be rebuilt later with no network.