{
  "markdown": "# attest-mcp\n\n[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/14159/badge)](https://www.bestpractices.dev/projects/14159)\n\nListed on the [official MCP Registry](https://registry.modelcontextprotocol.io/) as\n`io.github.SPAZIO-GENESI/attest-mcp`.\n\nMCP server **and CLI** for [Spazio Genesi](https://attestazione.spaziogenesi.org)'s\nattestation service — attest, verify, and check the existence of digital works from\nany MCP-capable AI agent (Claude Code, Claude Desktop, etc.) or straight from a\nterminal / CI pipeline.\n\n**Full privacy**: file bytes never leave your device. The fingerprint (SHA-256) is\ncomputed locally, streamed from disk — only the hash and optional metadata are sent.\n\n📖 English documentation: [attestazione.spaziogenesi.org/en](https://attestazione.spaziogenesi.org/en/)\n— site, developer docs, and tiers/terms are all available in English.\n\n## What it does\n\nThe attestation service timestamps a file's SHA-256 fingerprint, signs it (HMAC), and\ncan produce a signed PDF certificate plus an OpenTimestamps proof anchored in Bitcoin.\nThis server exposes that service as MCP tools, so an agent can attest and verify works\non your behalf without a browser.\n\n## Why this, not just an OpenTimestamps wrapper\n\nSeveral MCP servers can submit a hash to an OpenTimestamps calendar. As far as\nwe know, this is the only one that hands back a **complete proof of\nexistence** — a signed PDF certificate, a recognized RFC 3161 timestamp, and\na Bitcoin anchor — for **free**, with the file's bytes never leaving the\ncaller's machine. No account, no upload, no paid notarization chain. If you\nknow of another MCP server with the same combination (full certificate +\nfree + local hashing), we'd genuinely like to hear about it — open an issue.\n\n## Built for the European legal and regulatory context\n\nSpazio Genesi is an Italian non-profit (ETS – *Ente del Terzo Settore*). The\nattestation service behind this package was designed with the EU regulatory\nenvironment in mind, not adapted to it afterwards:\n\n- **GDPR-first, privacy by design**: the file itself never reaches our servers —\n  only its SHA-256 fingerprint (and any metadata you choose to declare) is sent.\n- **EU data residency**: certificates and proofs are archived on Cloudflare R2\n  under EU jurisdiction.\n- **Recognized timestamping, no single point of trust**: every certificate carries\n  an RFC 3161 timestamp from an AATL-rooted authority (trusted by Adobe and most\n  PDF readers) *and* an independent Bitcoin anchor via OpenTimestamps.\n- **Honest about eIDAS**: this is **not** (yet) an eIDAS qualified trust service —\n  the signer identity is currently self-signed, and a qualified electronic seal is\n  a planned but unimplemented upgrade. See the\n  [technical whitepaper](https://trust.spaziogenesi.org/whitepaper.html) for the\n  full, unvarnished breakdown of what is and isn't guaranteed.\n\nFull tiers and terms: [attestazione.spaziogenesi.org/en/condizioni](https://attestazione.spaziogenesi.org/en/condizioni/).\n\n## Install\n\n**Claude Desktop** — one command, no manual JSON editing:\n\n```bash\nnpx -y @spazio-genesi/attest-mcp-setup\n```\n\nThis finds your `claude_desktop_config.json` (Windows/macOS/Linux), adds the\n`attest-mcp` entry, and backs up the original file first. It refuses to touch\nanything if the existing file isn't valid JSON — it never guesses. Restart\nClaude Desktop afterwards. To remove it again: add `--uninstall`. To preview\nwithout writing: add `--dry-run`.\n\n**Claude Code**:\n\n```bash\nclaude mcp add attest-mcp -- npx -y @spazio-genesi/attest-mcp\n```\n\n**Manual / other clients** — add this to your MCP client's config:\n\n```json\n{\n  \"mcpServers\": {\n    \"attest-mcp\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@spazio-genesi/attest-mcp\"]\n    }\n  }\n}\n```\n\n## Authentication\n\nTwo ways to authenticate, matching the underlying service:\n\n1. **API key** (for partner integrations, issued manually by Spazio Genesi):\n   set the `IMGAUTH_API_KEY` environment variable.\n2. **Device flow** (for personal/agent use): call the `authorize` tool with no\n   arguments. It returns a URL — open it, approve with the human-verification\n   widget, then call `authorize` again with the returned code. The session\n   token (24h, 20 attestations) is saved to `~/.config/attest-mcp/credentials.json`\n   (permissions `600` where supported) and used automatically after that.\n\nEither way, the credential only unlocks the anti-bot check on attestation — the\nserver-side timestamp, cryptographic signature, and rate limits are unchanged.\n\n## Tools\n\n| Tool | What it does |\n|---|---|\n| `authorize` | Start or continue the device-flow authorization. |\n| `attest_file` | Hash a local file (streamed) and attest it. |\n| `get_certificate_pdf` | Mint a fresh signed PDF, or recover an already-archived one, saved to disk. |\n| `verify_file` | Hash a local file and check it against a declared hash + signature. |\n| `verify_certificate` | Verify a certificate's signature without a local file. |\n| `check_anchor` | Check/download the OpenTimestamps (Bitcoin) proof. |\n| `service_status` | Traffic-light status of the attestation service. |\n\n## CLI (`sg-attest`)\n\nSame package, no separate install. The CLI is a `bin` alongside the MCP server,\nsharing the same hashing/API/config code — same full privacy (streamed local\nhash, file bytes never sent), same credentials.\n\n```bash\nnpx -y -p @spazio-genesi/attest-mcp sg-attest attest ./work.png\nnpx -y -p @spazio-genesi/attest-mcp sg-attest verify ./work.png --hash <sha256>\n```\n\n(`-p` is required: `sg-attest` is a secondary `bin` of the package, and plain\n`npx -y @spazio-genesi/attest-mcp` runs the MCP server instead.)\n\nOne advantage over the site: **no 1 GB cap**. The browser is limited by\nWebCrypto (which loads the whole file into memory); this CLI streams from\ndisk on Node, so it can attest files of any size.\n\n| Command | What it does | Credential |\n|---|---|---|\n| `attest <file> [--title --author --year --note] [--pdf <out>]` | Hash locally (streamed) → attest → print fingerprint, attestation, HMAC. Nothing is archived and no `/c/<hash>` page exists without `--pdf`; only `--pdf <out>` mints the signed certificate **and** prints the verification link | Yes |\n| `verify <file> [--hash <sha256>]` | Hash locally; with `--hash`, compares (exit 2 if different); also reports archive/anchor status | No |\n| `verify-cert --hash --attestazione --hmac [--titolo --autore --anno --note]` | Verifies a certificate's HMAC signature, no local file involved | No |\n| `cert <hash> [-o <file.pdf>]` | Recovers an already-archived certificate | No |\n| `anchor <hash> [-o <file.ots>]` | Checks/downloads the OpenTimestamps (Bitcoin) proof | No |\n| `status` | Traffic-light status of the service | No |\n| `authorize` | Device flow: prints a URL to approve, polls, saves the token | — |\n| `--version` / `--help` | Version (from `package.json`) and usage | — |\n\nEvery command accepts `--json` (emits one JSON object on stdout, for scripting)\nand `--quiet` (reduces non-essential human-readable output). Errors go to\nstderr; the CLI never prints a credential (API key or session token) to\nstdout, stderr, or `--json` output — same discipline as the MCP server.\n\n**Exit codes** (a stable contract, for CI/scripting):\n\n| Code | Meaning |\n|---|---|\n| `0` | Success / positive outcome |\n| `1` | Operational error (network, auth, bad input) |\n| `2` | Negative verification outcome (hash mismatch, invalid signature) |\n\nAuthentication is the same as the MCP server: `IMGAUTH_API_KEY` env var, or a\nsession token saved by `sg-attest authorize` (device flow). There is no\n`--key` flag — a credential on the command line ends up in shell history; use\nthe env var (or a CI secret) instead.\n\nA GitHub Action that uses this CLI to attest build artifacts in CI lives in a\ncompanion repo: [`attest-action`](https://github.com/SPAZIO-GENESI/attest-action).\n\n### Standalone binaries (no Node required)\n\nFor a machine or CI runner without Node.js, download a pre-compiled `sg-attest`\nexecutable from the [Releases page](https://github.com/SPAZIO-GENESI/attest-mcp/releases) —\nsame commands, same behavior, nothing to install.\n\n| OS | Architecture | File |\n|---|---|---|\n| Linux | x64 | `sg-attest-linux-x64` |\n| Linux | arm64 | `sg-attest-linux-arm64` |\n| macOS | Intel | `sg-attest-macos-x64` |\n| macOS | Apple Silicon | `sg-attest-macos-arm64` |\n| Windows | x64 | `sg-attest-windows-x64.exe` |\n| Windows | ARM64 | `sg-attest-windows-arm64.exe` |\n\nEach release also includes `SHA256SUMS.txt`. Verify the download before running it:\n\n```bash\nsha256sum -c SHA256SUMS.txt --ignore-missing   # Linux/macOS\n```\n\n```powershell\n(Get-FileHash .\\sg-attest-windows-x64.exe -Algorithm SHA256).Hash   # compare by eye to SHA256SUMS.txt\n```\n\n⚠️ The binaries are **not code-signed**: expect an \"unknown publisher\" warning\nfrom Windows SmartScreen or macOS Gatekeeper the first time you run one. The\nchecksum above is the integrity guarantee in the meantime — the binary is\nbuilt and published by [GitHub Actions](.github/workflows/release-binaries.yml)\ndirectly from this repo's source, nothing hand-uploaded.\n\nUsage is identical to the npm-installed CLI, just call the file directly:\n\n```bash\nchmod +x ./sg-attest-linux-x64          # Linux/macOS only\n./sg-attest-linux-x64 attest ./work.png --pdf cert.pdf\n./sg-attest-linux-x64 status\n```\n\n`npx`/`npm` remain the primary distribution channel (and what `attest-action`\nuses in CI) — the binaries are an additional channel, not a replacement.\n\n### Build provenance (SLSA/in-toto)\n\nThe checksum above answers \"is this file intact?\" — it says nothing about\n*where the bytes came from*. Every release since `v0.4.2` also carries a\nsigned [build provenance attestation](https://slsa.dev/provenance/v1)\n(`actions/attest-build-provenance`, job `release` in\n[`release-binaries.yml`](.github/workflows/release-binaries.yml)): cryptographic\nproof that the file was built by this repo's own workflow, from a specific\ncommit and tag, not hand-uploaded or swapped afterward.\n\nThe GitHub CLI can verify it, but `gh attestation verify` requires an\n**authenticated** `gh` session even on this public repo (confirmed: it fails\nwith \"please run gh auth login\" without one) — a real gap if the point is a\ncheck anyone can run with zero setup:\n\n```bash\ngh attestation verify sg-attest-linux-x64 --repo SPAZIO-GENESI/attest-mcp\n```\n\n[`scripts/verify-provenance.mjs`](scripts/verify-provenance.mjs) does the same\nverification **with no GitHub credentials at all** — only the public\nattestations REST endpoint (confirmed reachable unauthenticated, even on this\npublic repo) and the [`sigstore`](https://www.npmjs.com/package/sigstore)\nlibrary, which checks the signature against Sigstore's own public\ninfrastructure (Rekor, Fulcio, TUF — no account needed there either):\n\n```bash\ngit clone https://github.com/SPAZIO-GENESI/attest-mcp\ncd attest-mcp && npm install\nnode scripts/verify-provenance.mjs ./sg-attest-linux-x64 \\\n  --repo SPAZIO-GENESI/attest-mcp --tag v0.4.2\n```\n\nExits `0` on success, `1` if the file doesn't match anything the workflow\nactually built (e.g. a single altered byte makes the digest — and therefore\nthe lookup key itself — no longer match any attestation).\n\n## Configuration\n\n| Env var | Default | Purpose |\n|---|---|---|\n| `IMGAUTH_API_KEY` | — | API key credential, bypasses the device flow. |\n| `IMGAUTH_BASE_URL` | `https://imgauth.spaziogenesi.org` | Override for local development (`http://localhost:8787`). |\n| `IMGAUTH_CERT_PAGE_BASE` | `https://attestazione.spaziogenesi.org` | Override for the permanent-certificate-page base URL. |\n\n## Troubleshooting\n\nIf your client reports **\"Server disconnected\"**, check its log first: this server\nwrites diagnostics to stderr, which MCP clients capture. On Claude Desktop the log\nlives in `%APPDATA%\\Claude\\logs\\mcp-server-attest-mcp.log` (Windows) or\n`~/Library/Logs/Claude/mcp-server-attest-mcp.log` (macOS).\n\nYou should see one line per lifecycle event:\n\n```\n[attest-mcp 2026-07-21T11:14:12.948Z] v0.2.2 ready on stdio (node v22.22.2, pid 32316)\n[attest-mcp 2026-07-21T11:14:12.965Z] exiting (code 0)\n```\n\n- `exiting (code 0)` — ordinary shutdown: the client closed stdin. After a laptop\n  sleep or a client restart this is expected; just restart the client to reconnect.\n- `fatal: …` followed by `exiting (code 1)` — a real crash, with the stack trace on\n  the preceding line. Please [open an issue](https://github.com/SPAZIO-GENESI/attest-mcp/issues)\n  with it.\n- No `ready` line at all — the process never started: check that `node` is on PATH\n  and at least v18 (`node --version`).\n\nstdout carries the JSON-RPC protocol and is never used for logging.\n\n## Known limitation\n\nThe certificate PDF and its text are in **Italian** (Spazio Genesi is an Italian\nnon-profit and the certificate is a legal-facing document). The MCP tool\ndescriptions and this README are in English for an international audience.\n\n## Development\n\n```bash\nnpm install\nnpm test          # unit tests (hash vectors, CLI argument parsing)\nIMGAUTH_BASE_URL=http://localhost:8787 npm start   # MCP server against a local `wrangler dev`\nIMGAUTH_BASE_URL=http://localhost:8787 node src/cli.js status   # CLI against the same\n```\n\n`test/cli-smoke.local.mjs` is a local-only harness (not run by `npm test`) that\nexercises every `sg-attest` command end-to-end against an isolated `wrangler dev`\nimgauth instance — see the header comment in that file for the required env vars.\n\n## Security\n\nReport vulnerabilities → [`/sicurezza/`](https://attestazione.spaziogenesi.org/sicurezza/)\n(responsible disclosure policy, safe harbor for good-faith research) — this\nrepo has no `security.txt` of its own (npm package, no static assets), but\nthe policy covers the whole project.\n\n## Contributing\n\nBug reports and feature requests: [open an issue](https://github.com/SPAZIO-GENESI/attest-mcp/issues).\nPull requests are welcome — keep them focused (one change per PR), make sure\n`npm test` passes, and explain the \"why\" in the description, not just the\n\"what\". **Test policy**: any PR that adds new functionality should add a test\nfor it under `test/`; `npm run lint` and `npm test` both run in CI on every\npush and pull request. For anything that touches the attestation contract itself (hashing,\nHMAC verification, the API surface), open an issue first: this client mirrors\na contract owned by [imgauth](https://github.com/SPAZIO-GENESI/imgauth), so\nchanges need to stay compatible with it.\n\n## License\n\nMIT — see [LICENSE](LICENSE). This is a client for the attestation service; the\nservice itself ([imgauth](https://github.com/SPAZIO-GENESI/imgauth)) is AGPL-3.0.\n",
  "bytes": 14626,
  "sha": "5345abca0c6a1dc8eb277b8ecda45a087ceb7297603c06746fa8d3cfe91295b6",
  "repo_slug": "spazio-genesi/attest-mcp",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_spazio_genesi_attest_mcp_ed53e391/readme"
}