Skip to content

Releases: Ducarv/mcpmoat

v0.1.0

Choose a tag to compare

@github-actions github-actions released this 26 Oct 13:55
Immutable release. Only release title and notes can be modified.
503d5ba

First public release of mcpmoat, an offline scanner for malicious or tampered MCP servers.

This is an early release. Expect rough edges. Read "Not done yet" before you rely on it.

What works

  • Discovery. mcpmoat scan finds the MCP servers in your Claude Code, Cursor and Codex configs. It shows the origin, type and command of each server. It masks secret-like arguments.
  • Config checks. mcpmoat scan --no-connect checks the configs only. It starts no server and opens no connection. It flags a plaintext secret, a remote server over plain http://, an unpinned package and a typosquatted package name (threats T4 and T5).
  • Inspection. mcpmoat scan connects to each stdio and HTTP server and lists its tools, prompts and resources. A stdio server runs with exactly the configured command and a scrubbed environment. Each server has a time limit (--timeout). A server that fails does not stop the scan.
  • Rug pull detection. The first scan pins the tools of each server in pins.json. A later scan reports a changed, new, removed or unverifiable tool (MOAT-T2-001 to MOAT-T2-004) with a diff. Accept a change with mcpmoat pin --accept <server> --expect <digest>.
  • Output and exit codes. Terminal report, or one JSON document with --json (schema in docs/schema/). Exit code 0 means no findings, 1 means findings at or above --fail-on (default high), 2 means an execution error.
  • Ignore lists. --ignore <rule-id> and a .mcpmoat-ignore file.
  • Signed builds. Archives for macOS and Linux (amd64 and arm64), with checksums.txt and build provenance attestations.

Not done yet

  • The tool rules for tool poisoning (T1) and shadowing (T3) do not run yet. So exit code 0 does not mean that the tools are safe.
  • scan --rules <dir> loads and checks extra rule files, but does not apply them yet.
  • There is no lock for pins.json yet (#150).
  • The macOS binaries are not notarized yet. The Homebrew cask removes the quarantine flag on install.
  • The env scrub is not a sandbox. A stdio server runs as you.
  • mcpmoat does not analyse server source code. It does not stop prompt injection in content that your agent reads.

Install

brew install --cask Ducarv/tap/mcpmoat

Or download an archive below, or run go install github.com/Ducarv/mcpmoat/cmd/mcpmoat@v0.1.0. Check a download with the steps in Verify a download. Then run mcpmoat version.

Changelog

  • 503d5ba Merge pull request #183 from Ducarv/chore/166-167-e2e-test-helpers
  • e8207f9 test(cli): share the exec runner and tidy helper comments
  • f660759 test(cli): apply review fixes to the shared helpers and the exit-code test
  • 9c2f76c test(cli): share pins helpers and cover the rugpull fixture exit codes
  • cae8832 Merge pull request #176 from Ducarv/chore/66-release-pipeline
  • 5b4d0d6 docs(release): cover a failed post-publish check and bind verify to the commit
  • 43702e4 fix(release): name a missing dist file and fix the 12-character commit note
  • 1c5d652 Merge origin/main into chore/66-release-pipeline
  • 0eec53f Merge pull request #165 from Ducarv/feat/62-rugpull-fixture
  • 9902694 docs(release): close the cask checklist against Ruby interpolation
  • 37e9454 ci: read both tool pins from env lines with one anchored parser
  • 3e6f7a4 fix(release): fail when the published release is not immutable
  • 75917f3 Merge origin/main into feat/62-rugpull-fixture
  • fc56e63 Merge pull request #179 from Ducarv/feat/63-terminal-report
  • 9de4b40 Merge origin/main into feat/63-terminal-report
  • 3de2012 docs(release): match the cask checklist to a real cask
  • d1ea553 docs(release): check the whole cask, not only its sha256 values
  • 470b31f ci: check the govulncheck pin too, and loop the static check over targets
  • f36cf8a fix(release): accept only first-parent main commits and recheck the tag after publish
  • 55cd693 Merge pull request #177 from Ducarv/feat/65-exit-codes-fail-on
  • ccae74b fix(cli): give the size-limit MOAT-T2-004 row of a pinned server its own risk
  • c65da69 Merge origin/main into feat/65-exit-codes-fail-on
  • ee8267a Merge pull request #173 from Ducarv/feat/64-json-output
  • d9e3174 fix(report): print the failure reason after the counts in the scan summary
  • c76e273 docs(release): state the secret and ordering limits, reword NFR-02
  • 2ce0bae ci: match every GoReleaser pin form and send script errors to stderr
  • d7104d9 fix(release): verify the exact signing workflow and recheck the tag
  • ada13ac docs: say that the signal check before the pin save applies only to new pins
  • 5d9d2cd fix(cli): fail a pinned server whose tools no longer fit the pins size limit
  • 5d5309a docs: pin advice for go install, symlink-safe hook install, one exit 2 list
  • e9f10f7 refactor(cli): say "not ignored" in the exit code help and link the README contract
  • a01b3f5 docs(release): drop the manual publish, order the setup, fix install notes
  • c3f2e16 ci: move the snapshot check to a script and check the GoReleaser pins
  • c6cc3af fix(release): stop on a missing environment and recheck assets after publish
  • 2eedd09 fix(release): pin archive tar headers and skip rc tags for stable changelogs
  • 86c94f0 test(cli): drop a blank line left by the TestScanJSONDiffKinds move
  • 3d694fa fix(cli): give every pin row of a server with unpinnable tools a fix that works
  • cc2f4ab docs: describe the --fail-on critical note and a pins.json read error on a signal
  • a037d96 feat(cli): note on stderr for --fail-on critical and add severityFlag
  • d92e4da test(report): check the E2E JSON against the schema and tidy round 3
  • 7abdc94 docs(report): state the scan --json contract edges and tidy the JSON code
  • ff228b1 fix(report): print the reason of a server-level pin finding as Reason, not Tool
  • 41eb880 docs: make README the one exit code contract and harden the CI guide
  • 825bbce test(cli): use perLevel tables and copy the CI fixture with os.CopyFS
  • af2a507 refactor(cli): shorten the exit code usage text and point to README
  • 126e30c fix(report): flag incomplete reports and diff notes in scan --json
  • 904be83 fix(release): reproducible archives, full asset check, brew verify docs
  • b24ef50 fix(report): give scan-made MOAT-T2-004 rows a fix that works, match outcomes by index
  • 56d955d feat(report): add the terminal report with summary, severity groups and colour
  • 1f7e7b2 fix(release): pin the current tag, replace stale drafts, dedupe verify docs
  • 2498e69 docs: pin the CI install, guard .mcpmoat-ignore and fix hook edge cases
  • 6d9d834 refactor(cli): narrow the exit 2 usage text and trim --fail-on tests
  • 696d4b7 refactor(report): type the JSON mode and inspection status, clarify docs
  • 5cb0f76 docs(release): document install, verification and the release process
  • c34c0a3 ci: check the GoReleaser config and build a snapshot on every PR
  • 81d0eb5 chore(release): add GoReleaser config and attested release workflow
  • d132be0 feat(report): add scan --json with a versioned JSON Schema
  • 0fc02f2 docs: document exit codes and add the CI and git hook guide
  • 29e8d07 test(cli): add a CI fixture repo and TestE2EScanFailOn
  • 0012293 feat(cli): add scan --fail-on to set the exit code 1 threshold
  • 7c436eb test(pins): tidy TestE2ERugPull after the round 1 review
  • f51b670 Merge pull request #164 from Ducarv/feat/153-hash-meta-icons
  • 57257e9 docs(pins): document inline icon size and the new-tool diff cut, drop copied limits
  • af9b9a3 test(pins): finish the marshalJSON and canonicalJSON renames in test names
  • fdfeb8a docs(pins): note server URLs in pins.json and match the render field order
  • feb14f2 test(cli): check that a pinned server keeps pins.json after a bad _meta
  • baf69b2 refactor(inspect): rename marshalSchema to marshalJSON
  • a08...
Read more

v0.1.0-rc.1

v0.1.0-rc.1 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 26 Oct 13:47
Immutable release. Only release title and notes can be modified.
503d5ba

Changelog

  • 503d5ba Merge pull request #183 from Ducarv/chore/166-167-e2e-test-helpers
  • e8207f9 test(cli): share the exec runner and tidy helper comments
  • f660759 test(cli): apply review fixes to the shared helpers and the exit-code test
  • 9c2f76c test(cli): share pins helpers and cover the rugpull fixture exit codes
  • cae8832 Merge pull request #176 from Ducarv/chore/66-release-pipeline
  • 5b4d0d6 docs(release): cover a failed post-publish check and bind verify to the commit
  • 43702e4 fix(release): name a missing dist file and fix the 12-character commit note
  • 1c5d652 Merge origin/main into chore/66-release-pipeline
  • 0eec53f Merge pull request #165 from Ducarv/feat/62-rugpull-fixture
  • 9902694 docs(release): close the cask checklist against Ruby interpolation
  • 37e9454 ci: read both tool pins from env lines with one anchored parser
  • 3e6f7a4 fix(release): fail when the published release is not immutable
  • 75917f3 Merge origin/main into feat/62-rugpull-fixture
  • fc56e63 Merge pull request #179 from Ducarv/feat/63-terminal-report
  • 9de4b40 Merge origin/main into feat/63-terminal-report
  • 3de2012 docs(release): match the cask checklist to a real cask
  • d1ea553 docs(release): check the whole cask, not only its sha256 values
  • 470b31f ci: check the govulncheck pin too, and loop the static check over targets
  • f36cf8a fix(release): accept only first-parent main commits and recheck the tag after publish
  • 55cd693 Merge pull request #177 from Ducarv/feat/65-exit-codes-fail-on
  • ccae74b fix(cli): give the size-limit MOAT-T2-004 row of a pinned server its own risk
  • c65da69 Merge origin/main into feat/65-exit-codes-fail-on
  • ee8267a Merge pull request #173 from Ducarv/feat/64-json-output
  • d9e3174 fix(report): print the failure reason after the counts in the scan summary
  • c76e273 docs(release): state the secret and ordering limits, reword NFR-02
  • 2ce0bae ci: match every GoReleaser pin form and send script errors to stderr
  • d7104d9 fix(release): verify the exact signing workflow and recheck the tag
  • ada13ac docs: say that the signal check before the pin save applies only to new pins
  • 5d9d2cd fix(cli): fail a pinned server whose tools no longer fit the pins size limit
  • 5d5309a docs: pin advice for go install, symlink-safe hook install, one exit 2 list
  • e9f10f7 refactor(cli): say "not ignored" in the exit code help and link the README contract
  • a01b3f5 docs(release): drop the manual publish, order the setup, fix install notes
  • c3f2e16 ci: move the snapshot check to a script and check the GoReleaser pins
  • c6cc3af fix(release): stop on a missing environment and recheck assets after publish
  • 2eedd09 fix(release): pin archive tar headers and skip rc tags for stable changelogs
  • 86c94f0 test(cli): drop a blank line left by the TestScanJSONDiffKinds move
  • 3d694fa fix(cli): give every pin row of a server with unpinnable tools a fix that works
  • cc2f4ab docs: describe the --fail-on critical note and a pins.json read error on a signal
  • a037d96 feat(cli): note on stderr for --fail-on critical and add severityFlag
  • d92e4da test(report): check the E2E JSON against the schema and tidy round 3
  • 7abdc94 docs(report): state the scan --json contract edges and tidy the JSON code
  • ff228b1 fix(report): print the reason of a server-level pin finding as Reason, not Tool
  • 41eb880 docs: make README the one exit code contract and harden the CI guide
  • 825bbce test(cli): use perLevel tables and copy the CI fixture with os.CopyFS
  • af2a507 refactor(cli): shorten the exit code usage text and point to README
  • 126e30c fix(report): flag incomplete reports and diff notes in scan --json
  • 904be83 fix(release): reproducible archives, full asset check, brew verify docs
  • b24ef50 fix(report): give scan-made MOAT-T2-004 rows a fix that works, match outcomes by index
  • 56d955d feat(report): add the terminal report with summary, severity groups and colour
  • 1f7e7b2 fix(release): pin the current tag, replace stale drafts, dedupe verify docs
  • 2498e69 docs: pin the CI install, guard .mcpmoat-ignore and fix hook edge cases
  • 6d9d834 refactor(cli): narrow the exit 2 usage text and trim --fail-on tests
  • 696d4b7 refactor(report): type the JSON mode and inspection status, clarify docs
  • 5cb0f76 docs(release): document install, verification and the release process
  • c34c0a3 ci: check the GoReleaser config and build a snapshot on every PR
  • 81d0eb5 chore(release): add GoReleaser config and attested release workflow
  • d132be0 feat(report): add scan --json with a versioned JSON Schema
  • 0fc02f2 docs: document exit codes and add the CI and git hook guide
  • 29e8d07 test(cli): add a CI fixture repo and TestE2EScanFailOn
  • 0012293 feat(cli): add scan --fail-on to set the exit code 1 threshold
  • 7c436eb test(pins): tidy TestE2ERugPull after the round 1 review
  • f51b670 Merge pull request #164 from Ducarv/feat/153-hash-meta-icons
  • 57257e9 docs(pins): document inline icon size and the new-tool diff cut, drop copied limits
  • af9b9a3 test(pins): finish the marshalJSON and canonicalJSON renames in test names
  • fdfeb8a docs(pins): note server URLs in pins.json and match the render field order
  • feb14f2 test(cli): check that a pinned server keeps pins.json after a bad _meta
  • baf69b2 refactor(inspect): rename marshalSchema to marshalJSON
  • a08f01f test(pins): remove test duplication around _meta and icons
  • 7baa36e docs(pins): correct the render order note and the indented field count
  • f38f69a fix(inspect): name the _meta field by its wire name in the encode error
  • 2df6bdc fix(pins): reject a _meta that is not an object and icons that are not an array
  • 79f38b2 test(pins): apply review fixes to the rug-pull fixture
  • a0403c4 refactor(pins): tidy the _meta and icons code after review
  • b73f36f test(pins): add the rug-pull fixture and an E2E journey
  • 1c360b6 feat(pins): hash tool _meta and icons in the pin hash
  • f660389 Merge pull request #159 from Ducarv/feat/60-61-pin-diff-accept
  • 0bfaaf1 fix(ci): run the E2E pin tests below a private TMPDIR
  • 9ee80a3 Merge remote-tracking branch 'origin/main' into feat/60-61-pin-diff-accept
  • bae9265 test(inspect): check ctx, not a wall-clock bound, in the flood stop test
  • 5c2e052 fix(pins): treat an unverifiable new name as a rename, and tidy the hint code
  • 7fc8f3d feat(pins): add pin --project, show inspection warnings, and flag renames
  • 4b1eeed fix(pins): fail on a server that cannot be pinned, and stop the save on a late signal
  • 99ade3b fix(pins): give no accept command for a cut diff, and cap render indentation
  • 87cb40f fix(pins): bind the accept hint to what scan shows, and keep the full digest
  • b6804fa fix(pins): fail on a pinned server that was not inspected
  • 751840d fix(pins): show new tools, warn on cut diffs, and split the pin code
  • 8a7753b feat(pins): detect tool changes with a diff and add pin --accept
  • c2bc39c Merge pull request #155 from Ducarv/feat/58-canonical-hash
  • 5e887d3 chore(ci): re-run the GitGuardian check after the false positive triage
  • 24ed921 Merge origin/main int...
Read more