{"_id":"@arclat-ai/mcpie","_rev":"2-c0f5a0ce857cac722022b36c8a8b289f","name":"@arclat-ai/mcpie","dist-tags":{"latest":"0.1.1"},"versions":{"0.1.0":{"name":"@arclat-ai/mcpie","version":"0.1.0","keywords":["mcp","model-context-protocol","security","scanner","audit","prompt-injection","tool-poisoning","sarif","claude","ai-agents"],"author":{"name":"Arclat"},"license":"Apache-2.0","_id":"@arclat-ai/mcpie@0.1.0","maintainers":[{"name":"abdur-rafay-ar","email":"abdurrafay.tech@gmail.com"}],"homepage":"https://mcpie.arclat.com","bugs":{"url":"https://github.com/arclat-ai/mcpie/issues"},"bin":{"mcpie":"dist/cli.js"},"dist":{"shasum":"8800dd4b23d5974c8d025a76a35a239686855a0b","tarball":"https://registry.npmjs.org/@arclat-ai/mcpie/-/mcpie-0.1.0.tgz","fileCount":117,"integrity":"sha512-jLq4BJ0MzQx95ySNbmCj2iTx2MhyDvd41zIHwWfUFkNkqhTUeJMJJe5xZxvWrSkEJ3fBJaorBvjuF3STgfFBBQ==","signatures":[{"sig":"MEUCIQCvv69MmO3rVvd66sUFc/QLWtSxi/Xkcu+Ul1yuNJZAAQIgDtbrDMcCH5SnSzqEDxG4BCdID7kk5HFmTmQ2viNXVzk=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":315949},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","engines":{"node":">=18.17"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"scripts":{"dev":"npm run build && node dist/cli.js","test":"node --test \".tmp-test/test/*.test.js\"","build":"tsc -p tsconfig.build.json","clean":"node -e \"for (const d of ['dist','.tmp-test']) require('fs').rmSync(d,{recursive:true,force:true})\"","pretest":"tsc -p tsconfig.test.json","typecheck":"tsc -p tsconfig.json --noEmit","docs:rules":"node scripts/gen-rule-docs.mjs","prepublishOnly":"npm run clean && npm run build && npm test && npm run docs:rules"},"_npmUser":{"name":"abdur-rafay-ar","email":"abdurrafay.tech@gmail.com"},"repository":{"url":"git+https://github.com/arclat-ai/mcpie.git","type":"git"},"_npmVersion":"11.6.2","description":"Security scanner for MCP servers. Think `npm audit` for the Model Context Protocol.","directories":{},"_nodeVersion":"24.13.0","dependencies":{},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.5.3","@types/node":"^20.14.0"},"_npmOperationalInternal":{"tmp":"tmp/mcpie_0.1.0_1786048167995_0.025705800055316974","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@arclat-ai/mcpie","version":"0.1.1","description":"Security scanner for MCP servers. Think `npm audit` for the Model Context Protocol.","keywords":["mcp","model-context-protocol","security","scanner","audit","prompt-injection","tool-poisoning","sarif","claude","ai-agents"],"homepage":"https://mcpie.arclat.com","bugs":{"url":"https://github.com/arclat-ai/mcpie/issues"},"repository":{"type":"git","url":"git+https://github.com/arclat-ai/mcpie.git"},"license":"Apache-2.0","author":{"name":"Arclat"},"type":"module","bin":{"mcpie":"dist/cli.js"},"main":"dist/index.js","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"engines":{"node":">=18.17"},"publishConfig":{"access":"public"},"scripts":{"build":"tsc -p tsconfig.build.json","clean":"node -e \"for (const d of ['dist','.tmp-test']) require('fs').rmSync(d,{recursive:true,force:true})\"","prepublishOnly":"npm run clean && npm run build && npm test && npm run docs:rules","typecheck":"tsc -p tsconfig.json --noEmit","pretest":"tsc -p tsconfig.test.json","test":"node --test \".tmp-test/test/*.test.js\"","docs:rules":"node scripts/gen-rule-docs.mjs","dev":"npm run build && node dist/cli.js"},"dependencies":{},"devDependencies":{"@types/node":"^20.14.0","typescript":"^5.5.3"},"_id":"@arclat-ai/mcpie@0.1.1","_nodeVersion":"24.13.0","_npmVersion":"11.6.2","dist":{"integrity":"sha512-Rnz3wsYY6ugFuwJt5nIzOGpokqPoYHzGLysrljG5iDW+WbrtF3pKHDYV9StuWd8MmI7Tzh+tHDBaeKgMVIf8bQ==","shasum":"99d5c87af282e500b1df9b83ca3d0e14f3549865","tarball":"https://registry.npmjs.org/@arclat-ai/mcpie/-/mcpie-0.1.1.tgz","fileCount":117,"unpackedSize":317793,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDn+59XECSz6PSQZEo3lflC8xaa5iCYf/X6Gahe0I/K5QIgf+6mAh5QuaJxkvhNtpT6jCDVL/hrEFEFEETRc8l6RJk="}]},"_npmUser":{"name":"abdur-rafay-ar","email":"abdurrafay.tech@gmail.com"},"directories":{},"maintainers":[{"name":"abdur-rafay-ar","email":"abdurrafay.tech@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/mcpie_0.1.1_1786048867468_0.48693493252182773"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-06T20:29:27.876Z","modified":"2026-08-06T20:41:07.852Z","0.1.0":"2026-08-06T20:29:28.141Z","0.1.1":"2026-08-06T20:41:07.588Z"},"bugs":{"url":"https://github.com/arclat-ai/mcpie/issues"},"author":{"name":"Arclat"},"license":"Apache-2.0","homepage":"https://mcpie.arclat.com","keywords":["mcp","model-context-protocol","security","scanner","audit","prompt-injection","tool-poisoning","sarif","claude","ai-agents"],"repository":{"type":"git","url":"git+https://github.com/arclat-ai/mcpie.git"},"description":"Security scanner for MCP servers. Think `npm audit` for the Model Context Protocol.","maintainers":[{"name":"abdur-rafay-ar","email":"abdurrafay.tech@gmail.com"}],"readme":"<div align=\"center\">\n\n# mcpie\n\n**Security scanner for MCP servers.** Think `npm audit` for the Model Context Protocol.\n\n[![CI](https://github.com/arclat-ai/mcpie/actions/workflows/ci.yml/badge.svg)](https://github.com/arclat-ai/mcpie/actions/workflows/ci.yml)\n[![npm](https://img.shields.io/npm/v/%40arclat-ai%2Fmcpie?color=f97316)](https://www.npmjs.com/package/@arclat-ai/mcpie)\n[![license](https://img.shields.io/badge/license-Apache--2.0-f97316)](./LICENSE)\n[![node](https://img.shields.io/node/v/%40arclat-ai%2Fmcpie?color=f97316)](https://nodejs.org)\n[![dependencies](https://img.shields.io/badge/runtime%20deps-0-f97316)](./package.json)\n\n[Website](https://mcpie.arclat.com) · [Rules](./rules) · [Contributing](./CONTRIBUTING.md) · [Security](./SECURITY.md)\n\n</div>\n\nMCP servers are being installed the way npm packages were in 2016 — quickly, by\nname, with full trust. `mcpie` scans the MCP servers you use (and the ones you\nbuild) for tool poisoning, over-broad permissions, credential exposure, rug\npulls, and other documented attack classes.\n\n```\n$ npx @arclat-ai/mcpie scan\n\n  mcpie v0.1.0 — scanning 4 MCP servers from claude_desktop_config.json\n\n  ✔ filesystem-server        A   no findings\n  ✖ web-clipper              F   3 findings\n    ├─ CRIT  MS-004  exec is called with data that appears to come from tool input, through a shell.\n    │        \"const output = execSync(`extractors/${name} ${args}`, { shell: true })\"\n    │        → src/server.js:43\n    ├─ HIGH  MS-001  Description of tool \"clip_page\" contains 1 invisible character(s)\n    │        (ZERO WIDTH SPACE) that reach the model but not the reader.\n    │        → tools/clip_page\n    └─ MED   MS-003  Filesystem root scoped to \"~\"\n             → narrower scope recommended: project directory only\n  ✖ db-helper                C   1 finding\n    └─ HIGH  MS-005  Secret `DB_API_KEY` is read from the environment and appears\n             in a value returned to the model.\n             → src/handlers/query.ts:88\n  ✔ notes-mcp                B   no findings\n             · 1 low-confidence finding hidden — re-run with --verbose to see it\n\n  4 findings (1 critical, 2 high, 1 medium) · 4 servers · worst grade F\n```\n\n## Quickstart\n\n```bash\n# Scan the MCP servers configured on this machine\nnpx @arclat-ai/mcpie scan\n\n# Scan a specific server package or local directory\nnpx @arclat-ai/mcpie scan @scope/some-mcp-server\nnpx @arclat-ai/mcpie scan ./my-server\n\n# Machine-readable output\nnpx @arclat-ai/mcpie scan --json\nnpx @arclat-ai/mcpie scan --sarif    # drops straight into GitHub's Security tab\nnpx @arclat-ai/mcpie scan --markdown # for PR comments and job summaries\n\n# Write a lockfile of current tool definitions, then detect rug pulls later\nnpx @arclat-ai/mcpie lock\nnpx @arclat-ai/mcpie scan --check-lock\n```\n\nPrefer a short command? Install it once and the binary is just `mcpie`:\n\n```bash\nnpm install -g @arclat-ai/mcpie\nmcpie scan\n```\n\nZero config. `mcpie` auto-discovers servers from `claude_desktop_config.json`,\n`.mcp.json`, `~/.claude.json`, Cursor, VS Code, Windsurf, and Zed. Run\n`npx @arclat-ai/mcpie list` to see exactly what it found and where.\n\nZero dependencies, too — `npx @arclat-ai/mcpie` installs one package and nothing else. A\nsecurity tool that drags in a dependency tree is arguing against itself.\n\n## What it checks\n\n| ID | Check | Category |\n|----|-------|----------|\n| [MS-001](./rules/MS-001.md) | Tool poisoning — instructions embedded in tool/parameter descriptions, invisible Unicode | Prompt injection |\n| [MS-002](./rules/MS-002.md) | Cross-server shadowing — descriptions that reference or steer other servers' tools | Prompt injection |\n| [MS-003](./rules/MS-003.md) | Over-broad filesystem scope — roots at `/` or `~`, traversal patterns in schemas | Permissions |\n| [MS-004](./rules/MS-004.md) | Unscoped command execution — `exec`/`spawn` fed by tool parameters without an allowlist | Code |\n| [MS-005](./rules/MS-005.md) | Credential exposure — secrets read from env and passed into results or outbound requests | Secrets |\n| [MS-006](./rules/MS-006.md) | Suspicious egress — undeclared hardcoded endpoints, undisclosed telemetry | Exfiltration |\n| [MS-007](./rules/MS-007.md) | Rug pull — tool definitions changed since lockfile; mutable install refs | Supply chain |\n| [MS-008](./rules/MS-008.md) | Typosquatting — names within edit distance of popular servers, false official claims | Supply chain |\n\nEvery finding carries a **severity** (critical/high/medium/low) and an honest\n**confidence** label (high/medium/low). Static analysis has false positives; we\nlabel ours instead of hiding them. Low-confidence findings are hidden by default\nand shown with `--verbose`.\n\nFull rule docs, detection logic, and the scoring formula live in\n[`/rules`](./rules) — scores you can't audit are scores you can't trust.\n\n## How it reads a server\n\n`mcpie` never runs the server it is scanning. It reads:\n\n1. **Your client configs** — the launch command, arguments, environment, and\n   declared roots. Several findings live entirely at this layer: a filesystem\n   server rooted at `~` is a configuration mistake, not a server bug.\n2. **The server's source**, when it is on disk or resolvable as a package.\n   Tool names and descriptions are extracted statically from TypeScript,\n   JavaScript, and Python. Packages that aren't installed locally are fetched\n   with `--ignore-scripts` — running install scripts to check whether a package\n   is safe would be the single worst bug this tool could have.\n\nStatic extraction misses tools built dynamically and occasionally over-reads.\nThat trade is deliberate: it works without executing anybody's code, which is the\nonly way a pre-install scanner can be safe by construction. Findings from static\nparsing are marked as such in `--json` output.\n\n`--live` opts into the other path: `mcpie` speaks MCP over stdio, runs the\nhandshake, and asks the server for its real tool list. It is off by default\nbecause **executing an unaudited server in order to audit it is backwards**. Use\nit on servers you already trust, or in a sandbox.\n\n## Scoring\n\nEach server starts at 100. Every finding subtracts\n`severity_weight × confidence_factor`, and repeats of the same rule are\ndiscounted by `1/n` so one noisy rule cannot sink a server on its own.\n\n| Severity | Weight | | Confidence | Factor |\n|---|---|---|---|---|\n| critical | 40 | | high | 1.0 |\n| high | 20 | | medium | 0.6 |\n| medium | 8 | | low | 0.25 |\n| low | 2 | | | |\n\nGrades: **A** ≥ 90, **B** ≥ 75, **C** ≥ 60, **D** ≥ 40, **F** below 40. A\nhigh-confidence critical finding is an **F** regardless of the arithmetic —\naveraging away a command-injection finding would be dishonest.\n\nHiding a finding from the terminal never improves the grade: the score is always\ncomputed over everything the rules found.\n\nThe whole formula is [`src/score.ts`](./src/score.ts), and it is short on purpose.\n\n## Rug pulls and the lockfile\n\nAn MCP server is approved once and trusted forever. Nothing in the protocol\nre-prompts you when a tool description changes, so a server can ship a clean\ndefinition on day one and a poisoned one on day thirty.\n\n```bash\nnpx @arclat-ai/mcpie lock                   # writes mcpie-lock.json — commit this\nnpx @arclat-ai/mcpie scan --check-lock      # fails when a tool definition drifts\n```\n\nThe lockfile hashes each tool's *semantic* surface. Reformatting a schema is not\na rug pull and won't fire; a description that gains a zero-width payload will.\n\n## In CI\n\nUse the action:\n\n```yaml\n- uses: arclat-ai/mcpie@v0\n  with:\n    target: .\n    fail-on: B\n    check-lock: true\n\n- uses: github/codeql-action/upload-sarif@v3\n  with:\n    sarif_file: mcpie.sarif\n```\n\nOr call the CLI directly:\n\n```yaml\n- run: npx @arclat-ai/mcpie@0.1.0 scan . --sarif -o mcpie.sarif --fail-on B\n```\n\n**Exit codes:** `0` clean · `1` findings at or above the threshold · `2` usage\nerror · `3` internal error. Without `--fail-on`, only high-or-worse findings\nexit non-zero.\n\n## As a library\n\n```ts\nimport { scanPath, scanConfigured } from 'mcpie'\n\nconst report = await scanPath('./my-server')\nif (report.summary.worstGrade === 'F') process.exit(1)\n\nfor (const server of (await scanConfigured()).servers) {\n  console.log(server.name, server.grade, server.findings.length)\n}\n```\n\n## CLI reference\n\n```\nmcpie scan [target...]     Scan MCP servers. With no target, scans everything configured.\nmcpie lock [target...]     Record the current tool surface to mcpie-lock.json.\nmcpie list                 List the MCP servers mcpie can see, and where they came from.\nmcpie rules [id]           Show the rule catalogue, or one rule in full.\n\n  --json --sarif --markdown   Output formats\n  -o, --out <file>            Also write the report to a file\n  --verbose                   Remediation steps and low-confidence findings\n  --live                      Run each server and ask it for its tools (off by default)\n  --no-fetch                  Never download packages; scan only what is on disk\n  --check-lock                Compare the tool surface against the lockfile\n  --only <ids> --skip <ids>   Select rules, e.g. --only MS-001,MS-004\n  --min-severity <s>          Hide findings below critical|high|medium|low\n  --fail-on <grade>           Exit 1 when any server scores below A|B|C|D|F\n  --timeout <ms>              Per-server timeout for fetch and live enumeration\n  -C, --cwd <dir>             Run as if from this directory\n```\n\n## Why this exists\n\nDocumented, real-world MCP attack classes are stacking up: prompt-injection\nexfiltration through the official GitHub MCP server (Invariant Labs, 2025),\nunauthenticated SSE interfaces on popular servers, tool-definition rug pulls,\ncredential exfiltration via poisoned descriptions. Meanwhile there are 10,000+\npublic MCP servers and no `npm audit` equivalent. Enterprise gateways exist for\ncompanies with security teams; `mcpie` is for the developer about to paste a\nserver into their config.\n\n## What mcpie is not\n\n- **Not a runtime proxy or gateway.** It's a static/pre-install scanner. If you\n  need runtime policy enforcement, use a gateway — they solve a different problem.\n- **Not a guarantee.** A clean scan means \"no known patterns detected,\" not\n  \"safe.\" Anyone selling you certainty in this space is selling.\n- **Not a courtroom.** Findings describe patterns that enable attacks, never\n  intent.\n\n## Responsible disclosure\n\nFindings in maintained servers are disclosed privately to maintainers with a\n14-day window before publication. Found something in `mcpie` itself? See\n[SECURITY.md](./SECURITY.md) — same rules apply to us.\n\n## Roadmap\n\n- [x] Config discovery across Claude Desktop, Claude Code, Cursor, VS Code, Windsurf, Zed\n- [x] Static tool extraction (TS/JS/Python) + optional live MCP enumeration\n- [x] Rules MS-001 → MS-008\n- [x] JSON + SARIF + Markdown output\n- [x] Lockfile and rug-pull detection\n- [x] GitHub Action — fail CI when a config drops below a score threshold\n- [ ] Public registry — a scored page for every popular MCP server, rescanned weekly\n- [ ] \"Scanned with mcpie\" badge for server authors\n- [ ] Rules for unauthenticated SSE/HTTP transports and OAuth scope creep\n\n## Contributing\n\nThe highest-value contribution is a **new rule**: rules are a metadata block and\na detector function in [`/src/rules`](./src/rules), each citing the attack it\ndetects, with generated docs in [`/rules`](./rules). A rule PR with a fixture\nproving it fires — and one proving it stays quiet — is the fastest path to a\nmerge. Fixture servers (deliberately vulnerable, for testing) live in\n[`/fixtures`](./fixtures) — breaking them counts as fixing them.\n\nSee [CONTRIBUTING.md](./CONTRIBUTING.md).\n\n## License\n\nApache-2.0. The scanner is and stays fully open source.\n\n---\n\nBuilt by [Arclat](https://www.arclat.com) · [mcpie.arclat.com](https://mcpie.arclat.com)\n","readmeFilename":"README.md"}