MCP Security API
Scan an MCP server's tools.json manifest, a published npm / PyPI package, a GitHub repository, or a live remote MCP endpoint (OAuth-protected servers included) over a single HTTPS request — and get back an auditable A–F Trust Score with every finding and its evidence as JSON. Completely free — grab a key and start scanning in seconds.
The API runs the same deterministic engine as the open-source MCP Trust Checker CLI: no LLM in the loop, no telemetry, and the same input always produces the same score. Use it to gate CI, power a marketplace listing, or check a server before you connect it to your data.
The API is completely free
Access is free — there is nothing to buy and no card to add. Calls are authenticated with an API key, and you get one instantly: fill in the short form and your key works right away. No waiting for approval.
- No cost
- No credit card
- Commercial use allowed
- Instant — no waiting
Quick start
Every scan carries your API key — only /health, /config and /access/request are open. Get one free with the button above — it works immediately.
curl https://mcptrustchecker.com/api/v1/scan/npm/@modelcontextprotocol/server-filesystem \\
-H 'Authorization: Bearer YOUR_API_KEY'Or scan a manifest you already have:
curl -X POST https://mcptrustchecker.com/api/v1/scan/manifest \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
--data-binary @tools.jsonEndpoints
Base URL https://mcptrustchecker.com/api/v1. Every response is application/json. Every endpoint lives under that base: there are no unversioned aliases.
Scans a JSON body: a tools.json manifest or a raw tools/list result. Fully offline — nothing is fetched. Best for private or self-hosted servers.
| Field | Type | Notes |
|---|---|---|
| body | JSON object | Required. Max 512 KB. Arrays and scalars are rejected. |
curl -X POST https://mcptrustchecker.com/api/v1/scan/manifest \
-H 'Content-Type: application/json' \
-d '{"tools":[{"name":"read_file","description":"Read a file from disk."}]}'Fetches the published npm artifact, verifies it against the registry-declared hash, and analyses the exact source you would install — in memory, without installing or executing anything. Scoped names and pinned versions are supported.
| Path | Examples |
|---|---|
| {package} | left-pad · @upstash/context7-mcp · [email protected] |
curl https://mcptrustchecker.com/api/v1/scan/npm/@upstash/context7-mcpThe same deep scan for PyPI: resolves the sdist (or wheel), verifies its SHA-256, and reads the shipped Python source.
curl https://mcptrustchecker.com/api/v1/scan/pypi/mcp-server-fetchScans a GitHub repository directly — for MCP servers not published to npm or PyPI, or when you want to grade the source on the default branch. The engine downloads the repository archive, reads its real source in memory (never executed), and returns the same A–F Trust Score. The download is size-capped and the working copy is deleted after every scan.
curl https://mcptrustchecker.com/api/v1/scan/github/upstash/context7Scans a live remote MCP server by URL — the growing class of servers that ship as a hosted endpoint rather than a package, so there is nothing to download. The scanner connects over Streamable-HTTP (with SSE fallback), enumerates the real tool surface and grades it. Pass accessToken for a server behind a bearer or OAuth token; it is used for that request only and never stored.
Coverage is live, not source. A remote scan reads only what the wire exposes: tool poisoning, capability blast radius and cross-tool toxic flows are all detected, but the implementation is never fetched. The grade is not directly comparable to a package scan — the report states this in coverage.
Guarded. https only, no embedded credentials, and the host must still be public after DNS resolution — a hostname that resolves to a loopback, private, link-local or cloud-metadata address is refused, and every redirect hop is re-checked.
curl -X POST https://mcptrustchecker.com/api/v1/scan/remote \\
-H 'Authorization: Bearer YOUR_KEY' \\
-H 'Content-Type: application/json' \\
-d '{"url":"https://mcp.deepwiki.com/mcp"}'Returns a shields.io endpoint payload — the grade, the score and the colour — for the package's current Trust Score. Like every other /api/v1 call it is authenticated, so shields.io cannot fetch it directly; for a README badge use the keyless badge at /scan/{registry}/{package}/badge.svg instead (site root, not /api/v1), which the online scanner hands out with every result.
Issues an API key. This is what the button at the top of this page calls — use it directly if you would rather script it. The key is returned once and never stored in plaintext, so save it on the spot. No approval step: it is active immediately.
| Field | Type | Notes |
|---|---|---|
| string | Required. Where we would reach you about the key. | |
| useCase | string | Required, up to 2000 chars. What you are building. |
| expectedVolume | string | Optional, up to 120 chars. |
| turnstileToken | string | Required only while the captcha is enabled — see /config below. |
curl -X POST https://mcptrustchecker.com/api/v1/access/request \
-H 'Content-Type: application/json' \
-d '{"email":"[email protected]","useCase":"Gating MCP servers in CI"}'{ "status": "active", "apiKey": "…", "message": "Save this key now — it is shown only once and works immediately." }Answers 201. This endpoint is limited per IP address rather than per key, for obvious reasons: 10 requests per 10 minutes. An address that already has three requests on file gets 409 — contact support instead of minting more.
Public runtime configuration, needed only if you build your own key-request form: whether the captcha is currently on and, if so, its site key. The secret key never leaves the server.
{ "turnstile": { "enabled": true, "siteKey": "0x4AAA…" } }No API key required.
Liveness, engine version and current scanner load. No API key, not rate limited — safe to poll from a monitor.
{
"status": "ok",
"engine": "1.17.0",
"methodology": "mcptrustchecker-1.17",
"concurrency": { "active": 0, "queued": 0, "max": 12 }
}The response
Every scan returns the same shape. Three independent axes answer three different questions.
{
"tool": { "name": "mcptrustchecker", "version": "1.17.0", "methodologyVersion": "mcptrustchecker-1.17" },
"target": { "id": "@modelcontextprotocol/server-filesystem", "source": { "kind": "package" } },
"scannedAt": "2026-07-23T16:41:52.108Z",
"score": { "score": 94, "grade": "A", "vector": [ … ], "categorySubtotals": { … } },
"capabilityProfile": { "level": "high", "tags": [ "sensitive-source", "file-write", "external-sink" ], "reasons": { … } },
"coverage": { "level": "source", "caveats": [ "Tools were statically extracted from the published source (14 recovered)…" ] },
"findings": [
{
"ruleId": "MTC-FLOW-004",
"title": "Sensitive-source and external-sink co-exist",
"severity": "high",
"confidence": "strong",
"evidence": "sources [read_file, read_text_file, …] → sinks [write_file, move_file]",
"location": { "kind": "flow", "name": "read_file → move_file" }
}
],
"toxicFlows": [ … ],
"surfaceDigest": "a3f81c40e7b2…"
}Every point of the score is reconstructable. score.vector itemises each penalty — rule, severity, confidence multiplier and diminishing factor — so you can verify the grade rather than trust it.
Pricing, rate limits & fair use
The API is free and keys are issued instantly. A key exists so abuse can be stopped without punishing everyone else — not to upsell you.
| Control | Value |
|---|---|
| Price | Free — all endpoints, including commercial use |
| API key | Required — get one free, issued instantly |
| Rate limit | 120 requests/min per key (burst 120) |
| Request body | 512 KB maximum |
| Package scan cache | 15 minutes (repeat scans served instantly) |
| Timeout | 30s package scan · 10s manifest scan |
Exceeding the rate limit returns 429 with a Retry-After header. When the scanner is saturated you may get 503 — retry shortly.
Not exposed by design. The hosted API will not spawn a process, so there is no remote-code-execution vector. The one caller-supplied URL it will fetch is a remote MCP endpoint passed to /scan/remote, and that fetch is constrained by an SSRF guard which re-checks the address the hostname actually resolves to. To scan a private endpoint the guard blocks, or a live stdio server, run the open-source CLI locally: it does everything the API does, plus live stdio/HTTP scanning and OAuth sign-in, entirely on your machine.
Errors
| Status | Meaning |
|---|---|
| 400 | Invalid input — malformed JSON, not a valid registry package name. |
| 401 | Missing or unrecognised API key. |
| 403 | Key is not active. |
| 404 | Unknown endpoint. |
| 413 | Body larger than 512 KB. |
| 429 | Rate limited. See Retry-After. |
| 503 | Scanner saturated — retry shortly. |
| 504 | Scan exceeded its time budget. |
{ "error": { "status": 400, "message": "package must be a registry package name, not a URL" } }Prefer to run it yourself?
The scanner is MIT-licensed and runs fully offline. Everything the API does — and more — works locally.
npx mcptrustchecker # scan every MCP server you already have installed
npx mcptrustchecker scan ./tools.json # a manifest, offline
npx mcptrustchecker scan <package> --online # read the real published source
npx mcptrustchecker scan ./tools.json --sarif # SARIF for GitHub code scanningChangelog
What changed on the hosted API, most recent first. The scanning engine is versioned separately — GET /health always reports the exact engine and methodology a scan ran under.
| When | What changed |
|---|---|
| 2026-10-19 engine 1.17 |
Scanning engine upgraded to methodology mcptrustchecker-1.17. Python tools are read the way FastMCP serves them. A Python tool’s input schema is built from its function signature, its docstring is the description when the registration gives none, and description constants imported from sibling modules are resolved. Placeholder tool names such as fn, my_tool or tool no longer appear: a registration whose name cannot be read is reported in the coverage caveat instead. Capability heuristics read the new surface in context: a credential the caller passes in is not a sensitive source, a validator handed a script does not run it, and a URL the handler builds on a fixed host is not a destination the model chooses. report.surface now carries descriptions and parameters for Python servers. Grades move for some Python servers; re-scan before comparing with 1.16.1 results. |
| 2026-10-14 engine 1.16.1 |
Scanning engine upgraded to methodology mcptrustchecker-1.16.1. Grades no longer drop for text the detectors misread. Honesty rules (“do not tell the user it can be sent”), defensive caveats, quoted examples and negations in tool descriptions are no longer taken for attacks; on a marketplace’s 165 post-1.16 grade drops, 96 return to their 1.15 grade and F grades go from 21 to 2. New rule MTC-INJ-ESCALATE-1 reports metadata that has the model grant itself destructive permission. MTC-CAP-003 grades its evidence: an additive write no longer contradicts destructiveHint: false. Client score: ingesting outside content alone is listed in capabilityProfile.observations instead of costing 3 points, unless the model chooses the URL; PyPI PEP 740 attestations are now read (verification: source), and a repository mismatch is the new info rule MTC-SUP-016. A registry outage now fails the scan as retryable instead of being recorded as a missing version. New: add ?surface=1 to a scan request (or "surface": true in the remote-scan body) to receive report.surface — the tools, prompts and resources the score was computed on. Grades move, mostly up; re-scan before comparing with 1.16 results. |
| 2026-10-14 engine 1.16 |
Scanning engine upgraded to methodology mcptrustchecker-1.16. Tools registered through a helper, a loop or a decorator wrapper are recovered, and every tool’s annotations are read. A tool that declares readOnlyHint: false, destructiveHint: true or openWorldHint: true — or whose handler visibly sends an HTTP or database write — raises the capability level; a declared hint never lowers it (new capability tag state-write). Tools registered behind a condition are listed in coverage.conditionalTools; each tool reports its hints and hintSource. MTC-SRC-001/010 inside a bundled Ajv, depd or get-intrinsic is info “in bundled dependency” and no longer raises the capability level when a verified signature matches; other bundled packages are named (data.vendored) but count in full. Grades move for some packages; re-scan before comparing with 1.15 results. |
| 2026-10-13 engine 1.15 |
Scanning engine upgraded to methodology mcptrustchecker-1.15. Process execution is graded per call, and by what the MCP server can actually reach. MTC-SRC-002 used to fire on a file’s child_process import and call it “command injection”; it now reads each call. A runtime-built shell command or a runtime-chosen program is still code execution (high); a fixed program spawned without a shell is a process-spawn capability (low, or info with fixed arguments). Code that only a package’s CLI or daemon loads — not its MCP server — no longer raises the capability level. Findings now carry data.callShape, data.reachable and a per-location data.fingerprint. Also: PyPI licenses declared the PEP 639 way are read, a pinned npm version is no longer credited with a repository a later release added, and install hooks are read rather than judged by their command line. Grades move for some packages; re-scan before comparing with 1.14 results. |
| 2026-09-20 engine 1.14 |
Scanning engine upgraded to methodology mcptrustchecker-1.14. A package name is no longer counted as a registry record. The coverage axis treated packageMeta.name — the string you send, echoed back onto the surface before any lookup — as evidence that the registry had answered. A target whose lookup returned nothing therefore reported "coverage": "metadata" and scored 92, grade A, while nothing had in fact been inspected. Coverage now requires a fact the registry actually supplied: a resolved version, a declared dependency, or the artifact’s tarball digest. Such a target reports "coverage": "empty" and 75, grade C, with a caveat naming the remedy. Scans that did reach the registry are unchanged, and this API already rejects an unknown package with 422 before scanning, so the effect shows up mainly in pasted-manifest results. GET /health now reports engine 1.14.0. |
| 2026-08-25 engine 1.13 |
Scanning engine upgraded to methodology mcptrustchecker-1.13. Verification is stricter about what it claims. A vendor tier now rests solely on ownership of the npm scope, which npm enforces at publish time — it is no longer inferred from the repository field a package declares about itself, which anyone could point at a well-known organisation. A package carrying build provenance keeps source: an attestation proves those bytes were built by a workflow, not whose. Provenance is also read for the version actually scanned rather than whatever npm tags latest, so a pinned scan no longer inherits a newer release’s attestation. No score or grade moves — the two tiers carry the same weight. Affects the verification field in every report. |
| 2026-07-27 engine 1.12 |
Scanning engine upgraded to methodology mcptrustchecker-1.12 (reported by /health) — a detection and correctness release. Injection detection gained a decode ladder (a payload hidden behind base64, URL- or entity-encoding is now decoded and read), semantic shapes (MTC-INJ-SEM-1) that catch a paraphrased override no phrase pattern would match, and description ↔ schema coherence (MTC-INJ-SCHEMA-1). The scanned surface was widened to everything the model is actually handed: a payload in inputSchema.description is no longer invisible. Two scoring invariants were repaired — adding a finding can no longer raise a score, and a scan that inspected nothing no longer grades A. Grades move only where these detections fire; on a 40-package sample across every band, existing grades were unchanged. |
| 2026-07-24 remote endpoints |
Added POST /scan/remote — scan a live remote MCP server by URL, including servers behind OAuth (the online scanner runs the full discovery + dynamic client registration + PKCE flow and holds the token in memory for a single scan). Fetching a caller-supplied URL is the one SSRF surface in the API, so it is tightly guarded: https only, no embedded credentials, and the host must remain public after DNS resolution, re-checked on every redirect and OAuth-discovery hop. A remote scan reports coverage: live — the tool surface is read over the wire, the implementation is not. |
| 2026-07-24 github + scanner |
Added GET /scan/github/{owner}/{repo} — scan a GitHub repository directly, for MCP servers not published to npm or PyPI. The repository archive is downloaded (size-capped), read in memory and deleted after every scan; same deterministic A–F Trust Score as a package scan. Alongside it, a free online scanner now runs the same engine in the browser with no key — every result is a shareable link with a live Trust Score badge. |
| 2026-07-24 engine 1.9 |
Scanning engine upgraded to methodology mcptrustchecker-1.9 (reported by /health) — the largest accuracy improvement since the model was introduced, driven by a full-population audit of every grade across 30,000+ scanned servers. The headline: evaluating a runtime value is capability, not malice. MTC-SRC-010 (eval/new Function on a variable) moved to the capability axis, matching MTC-SRC-001 — it is what an honest code-runner, interpreter or template engine does, and scoring it charged one capability twice. Nothing was lost on the threat side: the assembled-command + eval dropper still scores, decode-then-execute droppers still score, and no weight, category cap, grade band or hard gate changed. Eight precision guards shipped alongside it — security scanners no longer flag their own detection patterns, bilingual descriptions are no longer read as homoglyphs, documented example keys and test fixtures are no longer "leaked secrets", and a server's own src/tools handlers are no longer excused as dev tooling. |
| 2026-07-23 engine 1.8 |
Scanning engine upgraded to methodology mcptrustchecker-1.8 (reported by /health). Package scans now statically extract the tool surface from the published source, so the MCP-specific detectors — tool-poisoning, hidden-Unicode smuggling and cross-tool toxic flows — run on npm/PyPI packages, not only on a live server. Publisher verification gained a repo tier: a public, inspectable repository is the ecosystem norm and is discounted only lightly, distinct from a package whose source cannot be located. Injection precision was tightened after a per-rule false-positive audit — plain emphasis, ALL-CAPS acronyms, self-ordering prerequisites and detector/guard tools that merely quote an attack no longer raise a finding on their own. |
| 2026-07-23 limits |
Per-key rate limit raised to 120 requests/min, request body cap raised to 512 KB, and the package-scan timeout tightened to 30s. |
| 2026-07-22 launch |
Deterministic scanning over one HTTPS request: /scan/npm, /scan/pypi and /scan/manifest, plus /badge and /health. Same engine as the open-source CLI — no LLM, and the same input always yields the same score. |
Breaking changes, if any ever land, will be announced here before they ship. The endpoints above are stable; responses may gain new fields, so parse them leniently.
Frequently asked questions
Is there an API to check if an MCP server is safe?
Yes. The MCP Trust Checker API scans a Model Context Protocol server, a tools.json manifest, or an npm/PyPI package and returns an auditable A–F Trust Score as JSON, including every finding with its evidence. It is free to use; a free API key is issued on request.
How do I scan an MCP server with an API request?
POST your tools.json manifest to /api/v1/scan/manifest, or GET /api/v1/scan/npm/{package} to scan a published npm package. Both return the full JSON scan report with a Trust Score, Capability level and Coverage.
Is the MCP security API free?
Yes — the API is completely free. There is no cost and no credit card, including for commercial use. Access is authenticated with an API key, which is issued instantly from the API page: fill in a short form and it works right away. The key exists so abuse can be stopped without rate-limiting everyone else, not to charge you.
Does the MCP security API require an API key?
Yes. Requests are authenticated with a free API key. Get one from the API page — provide an email and a short description of your use case — and it works immediately, no approval wait. Send the key as "Authorization: Bearer
What does the MCP Trust Score measure?
The Trust Score is a 0–100 number with an A–F grade that answers one question: how safe is this MCP server for the user who wants to adopt it. It is computed in two deterministic, itemised stages — first a threat score from a penalty vector over threat findings (prompt injection, tool poisoning, hidden Unicode payloads, cross-tool toxic flows, supply-chain risk and rug-pull drift), then three small, subtract-only client-adoption-risk terms: the capability blast radius if the server were manipulated, how strongly the publisher is verified, and how much of the package the scan could inspect. Capability (blast radius) and Coverage are reported as their own axes.
Can the API scan a private or self-hosted MCP server?
The hosted API will not spawn a process, and the only caller-supplied URL it fetches is a remote MCP endpoint passed to /scan/remote, which is constrained by an SSRF guard that re-checks the resolved address. To scan a private or self-hosted server, POST its tools.json manifest to the manifest endpoint, or run the open-source CLI locally with npx mcptrustchecker — it runs on your own machine and reaches nothing but the server you point it at.