MCP server

The official Model Context Protocol server for Attestd. Once connected, Claude Code and Cursor gain native access to CVE risk and supply-chain integrity checks for every dependency decision. No plugin, no wrapper code, no custom tool definition.

Two transports, four tools. Hosted HTTP at mcp.attestd.io is the recommended path. No Node.js required. Works in Claude Code, Cursor, or any HTTP-based MCP client. The stdio npm package @attestd/mcp is available for local use and runs as a child process.

Hosted MCP is listed on Smithery for agent marketplace discovery and one-click connect flows.

hosted mcp

Connect to mcp.attestd.io

Point your MCP client at https://mcp.attestd.io/mcp with your API key in the Authorization header. No local install required. Works in Claude Code, Cursor, and any other HTTP-based MCP client.

  1. Get an API key from the portal.
  2. Add the block below to ~/.claude/mcp.json or project .mcp.json.
  3. Restart your MCP client. All four Attestd tools appear automatically.
~/.claude/mcp.json
{
  "mcpServers": {
    "attestd": {
      "url": "https://mcp.attestd.io/mcp",
      "headers": {
        "Authorization": "Bearer your-api-key-here"
      }
    }
  }
}

All requests to /mcp require an Authorization: Bearer atst_... header. The /health endpoint is unauthenticated.

stdio (local)

Local stdio via npx

Spawns @attestd/mcp as a local child process. Requires Node.js 18+. npx downloads the package on first run; subsequent starts use the npx cache.

~/.claude/mcp.json
{
  "mcpServers": {
    "attestd": {
      "command": "npx",
      "args": ["-y", "@attestd/mcp"],
      "env": {
        "ATTESTD_API_KEY": "your-api-key-here"
      }
    }
  }
}
tools

Available tools

check_package_vulnerability

Calls /v1/check and returns structured CVE and supply-chain data. Requires an API key (hosted: Authorization header; stdio: ATTESTD_API_KEY env).

ArgumentDescription
productInfrastructure slug or monitored package name. Use list_covered_products if unsure. Examples: nginx, postgresql, litellm, log4j.
versionExact version string: 1.20.0, 2.14.1, 1.82.7.

check_batch_vulnerabilities

Checks up to 100 packages in a single request. Use this instead of looping check_package_vulnerability when auditing a lockfile or dependency manifest. Each item costs one API call. Quota is checked upfront; if the batch would exceed your monthly limit, a 429 is returned before any calls are billed. Requires an API key.

ArgumentDescription
itemsArray of { product, version } objects. Minimum 1, maximum 100.

list_covered_products

Returns Attestd-covered products. With an API key, calls GET /v1/products and returns live CVE infrastructure slugs plus monitored supply chain packages. Without a key, returns the static bundled infrastructure list. Use this when the product slug is uncertain before calling check_package_vulnerability.

get_cve_details

Calls GET /v1/cve/{cve_id} and returns CVSS, EPSS, KEV status, and affected products. Requires an API key. Returns { found: false } when the CVE is not in Attestd's database (not an error).

ArgumentDescription
cve_idCVE identifier, e.g. CVE-2021-44228.
response examples

What Claude sees

Each tool call returns a single JSON text item. Claude branches on these fields to make deployment decisions.

Critical CVE with active exploitation (log4j 2.14.1)

json
// Claude calls: check_package_vulnerability({ product: "log4j", version: "2.14.1" })
{
  "outsideCoverage": false,
  "riskState": "critical",
  "activelyExploited": true,
  "patchAvailable": true,
  "fixedVersion": "2.16.0",
  "supplyChainCompromised": false,
  "supplyChainDescription": null
}

Supply chain compromise (litellm 1.82.7)

json
// Claude calls: check_package_vulnerability({ product: "litellm", version: "1.82.7" })
{
  "outsideCoverage": false,
  "riskState": "none",
  "activelyExploited": false,
  "patchAvailable": false,
  "fixedVersion": null,
  "supplyChainCompromised": true,
  "supplyChainDescription": "Malicious publish detected on PyPI: version 1.82.7 contains..."
}

Batch check (lockfile audit)

json
// Claude calls: check_batch_vulnerabilities({ items: [
//   { product: "litellm", version: "1.82.7" },
//   { product: "nginx",   version: "1.20.0" }
// ]})
{
  "count": 2,
  "results": [
    {
      "product": "litellm",
      "version": "1.82.7",
      "outsideCoverage": false,
      "riskState": "none",
      "activelyExploited": false,
      "supplyChainCompromised": true,
      "supplyChainDescription": "Malicious publish detected on PyPI: version 1.82.7 contains..."
    },
    {
      "product": "nginx",
      "version": "1.20.0",
      "outsideCoverage": false,
      "riskState": "high",
      "activelyExploited": false,
      "patchAvailable": true,
      "fixedVersion": "1.27.4"
    }
  ]
}

Product outside coverage

This is not a safety signal. Attestd has no data for this product. Treat the risk as unknown.

json
// Claude calls: check_package_vulnerability({ product: "wordpress", version: "6.4.2" })
{
  "outsideCoverage": true,
  "riskState": null,
  "typosquat": null,
  "message": "No Attestd coverage for 'wordpress'. Treat as unknown risk, not safe."
}

// Claude calls: check_package_vulnerability({ product: "react-codeshift", version: "1.0.0" })
{
  "outsideCoverage": true,
  "riskState": null,
  "typosquat": {
    "detected": true,
    "kind": "hallucination",
    "resembles": "jscodeshift",
    "likelyIntended": ["jscodeshift"],
    "confidence": 0.9,
    "ecosystem": "npm"
  },
  "message": "'react-codeshift' fails package name integrity. Prefer jscodeshift."
}

get_cve_details (Log4Shell)

json
// Claude calls: get_cve_details({ cve_id: "CVE-2021-44228" })
{
  "found": true,
  "cveId": "CVE-2021-44228",
  "description": "Apache Log4j2 JNDI injection allows remote code execution.",
  "cvssScore": 10.0,
  "activelyExploited": true,
  "remoteExploitable": true,
  "affectedProducts": ["log4j"],
  "epssScore": 0.97568,
  "epssPercentile": 0.99976
}

// CVE not in database
{
  "found": false,
  "cveId": "CVE-9999-99999"
}

list_covered_products

json
// Claude calls: list_covered_products()
// With API key: live data from GET /v1/products
{
  "source": "live",
  "total": 214,
  "cveProducts": [
    { "slug": "nginx", "displayName": "NGINX" }
  ],
  "supplyChainPackages": [
    { "package": "litellm", "ecosystem": "pypi", "displayName": null }
  ]
}

// Without API key: static bundled infrastructure list
{
  "source": "static",
  "count": 356,
  "products": [
    { "slug": "nginx", "display": "NGINX" }
  ]
}
return fields

Field reference

FieldSemantics
outsideCoveragetrue when Attestd has no CVE data for this product. Unknown risk. Do not treat as safe.
riskState"critical" | "high" | "elevated" | "low" | "none" | null when outside coverage. Block on critical or high.
activelyExploitedtrue if the version is in the CISA KEV catalog. Hard block regardless of riskState.
remoteExploitabletrue if any matching CVE is remotely exploitable.
authenticationRequiredtrue only when all matching CVEs require authentication to exploit.
patchAvailabletrue if a clean version is known. Pair with fixedVersion to tell Claude what to recommend.
fixedVersionEarliest version with no known critical/high CVEs. null when no patch exists yet.
confidenceSynthesis confidence from 0.0 to 1.0.
cveIdsArray of CVE IDs contributing to the risk assessment.
typosquatPackage name integrity. Present when the name is a typosquat or AI-hallucinated package. Contains detected, kind, resembles, likely_intended, confidence, and ecosystem. Single-check only. Block or warn when detected is true.
supplyChainCompromisedtrue if a malicious publish or integrity event was detected on PyPI or npm. Hard block.
supplyChainDescriptionHuman-readable description of the supply-chain event when present.
errorPresent when the tool returns isError: true, for example a bad key, rate limit, or missing arguments.
system prompt

Recommended system prompt

Include this in the Claude Code project or global system prompt to make the deployment-gate policy explicit. Without it, Claude may treat outsideCoverage: true as if there were no known vulnerabilities, which is incorrect.

text
You are a security-aware deployment assistant with access to the Attestd MCP server.

Before approving any software dependency, infrastructure component, or package version:
1. When reviewing multiple packages at once, use check_batch_vulnerabilities (up to 100 per call) instead of looping check_package_vulnerability.
2. For a single package, call check_package_vulnerability with the product slug and exact version.
3. Block deployment if riskState is "critical" or "high".
4. Block immediately if activelyExploited is true, regardless of riskState.
5. Block immediately if supplyChainCompromised is true.
6. Block or warn immediately if typosquat.detected is true. Treat kind "hallucination" as an AI-invented or conflated package name; prefer the resembles / likely_intended names instead of installing the requested name.
7. If outsideCoverage is true and typosquat is null, state explicitly that the risk is UNKNOWN. Do not treat it as safe.
8. If patchAvailable is true, include fixedVersion in your recommendation.

Use list_covered_products if you are unsure whether an infrastructure slug is supported (live catalog when the MCP server has an API key).
Use get_cve_details when you need CVSS, EPSS, or KEV context for a specific CVE after a check flags it.
workflow

Example: dependency review

A developer asks Claude to review a requirements.txt or Dockerfile before deploying. Claude reads the file, calls check_package_vulnerability for each dependency, and synthesises a go/no-go decision.

bash
# Example: Claude Code reviewing a requirements.txt before deploy

User: "Review my dependencies before I deploy"

# Claude reads the file, then calls check_batch_vulnerabilities in one shot:
check_batch_vulnerabilities(items=[
  { product: "litellm", version: "1.82.7" },
  { product: "nginx",   version: "1.20.0" }
])

# Results:
# litellm 1.82.7 → supplyChainCompromised: true  ← BLOCKED
# nginx   1.20.0 → riskState: "high"             ← FLAGGED

# Claude output:
# "I cannot approve this deployment. litellm 1.82.7 has a confirmed supply-chain
#  compromise. nginx 1.20.0 has a high risk state. Upgrade to 1.27.4 (riskState: none).
#  Remove litellm 1.82.7 entirely; no safe version is available at this time."

# For large lockfiles Claude will split into batches of up to 100 items per call.

The same pattern applies to CI pipelines, pull request reviews, and infrastructure audits. Claude will call the tool proactively whenever a dependency or version appears in context.

verify

Verify the server works

Hosted MCP health check:

bash
# Health check (no auth required)
curl https://mcp.attestd.io/health
# → {"status":"ok","attestd":{...}} when upstream API is reachable

# Quick tool list (replace with your key)
curl -X POST https://mcp.attestd.io/mcp \
  -H "Authorization: Bearer atst_..." \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'

For local stdio, send a raw JSON-RPC tools/list request over stdin:

bash
# Build and verify locally (requires Node 18+)
npm install -g @attestd/mcp   # optional: pin a version globally
# or just use npx (no install needed):
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' \
  | ATTESTD_API_KEY=your-key npx -y @attestd/mcp

All four tools, check_package_vulnerability, check_batch_vulnerabilities, and list_covered_products, should appear in the response.

see also