npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

mcp-trustcard

v2.2.1

Published

Cryptographic trust infrastructure for MCP servers — content-addressed tool identity, signed manifests, TOFU pinning, capability descriptors, a two-gate invocation policy, signed+chained receipts, and publisher key rotation. Also the "npm audit" health-ch

Readme

trustcard

Cryptographic trust infrastructure for executable capabilities.

Content-addressed capability identity, signed provenance, trust continuity, and call-time enforcement — with an empirical health scanner for MCP servers.

tests manifest

Agents increasingly execute capabilities they did not build, inspect, or previously encounter:

  • MCP tools
  • APIs
  • plugins
  • packages
  • workflows
  • remote services
  • other agents

The fundamental problem is simple:

Before an agent calls a capability, how does it know what it is, who authorized it, whether it has changed, and whether this specific call is allowed?

Today, the usual model is:

discover → connect → call

trustcard adds the missing trust layer:

discover
    ↓
identify
    ↓
verify provenance
    ↓
compare against trusted state
    ↓
evaluate policy
    ↓
allow / warn / block
    ↓
record evidence

The core primitive

trustcard turns an executable capability into a content-addressed, verifiable object.

┌──────────────────────────────────────────────────────────────┐
│                     EXECUTABLE CAPABILITY                   │
│                                                              │
│   What does it expose?       →  Capability identity          │
│   Who authorized it?          →  Signed provenance            │
│   Has it changed?             →  Change classification         │
│   Is this the thing I trust? →  Trust continuity              │
│   May this call happen?       →  Policy enforcement            │
│   What happened?              →  Tamper-evident receipt        │
└──────────────────────────────────────────────────────────────┘

For MCP, a tool's identity is derived from a canonical semantic projection:

toolDigest   = SHA-256(JCS(semantic tool projection))
toolsetDigest = SHA-256(JCS(sorted tool digests))
serverDigest  = SHA-256(JCS(server identity + protocol + toolset))

The result is a stable identity for what the capability actually is.

Not:

"the server responded successfully once"

But:

"this exact capability contract is the one I approved"

The trust model

trustcard combines five layers:

1. Capability identity

Every tool, toolset, and server receives a deterministic cryptographic identity.

The identity is based on the fields that affect what an agent can do or believe. Cosmetic or volatile metadata does not create a false trust event.

2. Provenance

Publishers can sign complete capability manifests with Ed25519.

A server can claim:

"I serve this toolset."

A publisher can attest:

"I authorized this exact toolset."

A client can verify:

"The capability I received is the capability that was signed."

3. Trust continuity

Clients can pin observed or signed state:

UNKNOWN
   ↓
OBSERVED
   ↓
PINNED
   ↓
      ┌───────────────┐
      │               │
      ▼               │
  MISMATCH        SUSPECT
      │               │
      └───────┬───────┘
              ▼
           REVOKED

For human-facing UIs and high-level APIs, these six internal states project onto four trust levels:

Internal state    Trust level    Meaning
──────────────    ───────────    ──────────────────
PINNED            TRUSTED        Green — verified, calls allowed
OBSERVED          OBSERVED       Yellow — seen but not pinned
SUSPECT           OBSERVED       Yellow — something looks off
UNKNOWN           OBSERVED       Yellow — never seen
MISMATCH          UNTRUSTED      Red — contract changed
REVOKED           REVOKED        Red — terminal, human re-pin required

A later connection is not merely:

"the server is reachable"

It becomes:

"the server is still the capability I previously trusted"

4. Change classification

A digest mismatch is not enough.

trustcard classifies the semantic meaning of change:

NONE
  ↓
SYNTACTIC
  ↓
NON_BREAKING
  ↓
ANNOTATION_DOWNGRADE
  ↓
PERMISSION_CHANGE
  ↓
BREAKING

This lets policy distinguish between:

description changed

and:

a new destructive capability appeared

and:

a previously safe parameter became unrestricted

The client learns not merely that something changed, but what the change means.

5. Call-time enforcement

Trustcard applies a two-gate model to invocation:

GATE 1
Is this the capability we approved?
        │
        ▼
Capability identity + trust state
        │
        ▼
GATE 2
May this agent make this call?
        │
        ▼
Policy + pinned schema + arguments
        │
        ▼
      ALLOW

A trusted server is not automatically authorized to perform every call.

Trust is not permission.

Quickstart

npm install -g mcp-trustcard

Or use it without installation:

npx mcp-trustcard <command>

Inspect a capability

mcp-trustcard fingerprint @modelcontextprotocol/server-memory
Trustcard: memory-server
────────────────────────────────────────────────────────
Server       [email protected]
Protocol     2025-06-18
Tools        9
Toolset      sha256:077EddEANnTm…
Server       sha256:FiELfkb8KDtT…
Manifest     VERIFIED
Pin          MATCH
────────────────────────────────────────────────────────

Pin trust on first use

mcp-trustcard pin @modelcontextprotocol/server-memory
mcp-trustcard pins

Later connections can detect and classify drift.

Compare two capability states

mcp-trustcard diff old.json new.json --verbose

Sign a capability manifest

mcp-trustcard keygen --out publisher.key.json

mcp-trustcard manifest \
  your-server \
  --key publisher.key.json \
  --out manifest.json

mcp-trustcard sign \
  manifest.json \
  --key publisher.key.json \
  --out signed.json

Use it as middleware

Trustcard can sit between an MCP client and server.

import { TrustSession } from "mcp-trustcard/lib/session.js";
import { TrustStore } from "mcp-trustcard/lib/trust.js";
import { Guard } from "mcp-trustcard/lib/guard.js";
import { wrapClient } from "mcp-trustcard/lib/middleware.js";

const trust = new TrustStore({
  policy: { requireSignature: true }
});

const guard = new Guard({
  mode: "enforce",
  policy: { allowDestructive: false }
});

const session = new TrustSession({
  cmd,
  args,
  env,
  trust,
  guard,
  protocolVersions
});

await session.connect();

trust.pin(
  session.serverId,
  session.observation
);

const secure = wrapClient(rawMcpClient, {
  guard,
  session,
  strictArgs: true
});

await secure.request("tools/call", {
  name: "search",
  arguments: { query: "x" }
});

The call can be denied when:

  • the server is revoked
  • the server no longer matches its trusted identity
  • the tool is unknown
  • the tool is not in the approved manifest
  • the tool is destructive under policy
  • the arguments violate the approved schema

The MCP scanner

Trustcard also includes the original reason the project exists:

mcp-trustcard scan <server>

The scanner is the empirical layer.

It answers:

What does this server actually do when a client connects to it?

The protocol answers:

Is this the capability I intended to trust?

Both questions matter.

Scan a server

mcp-trustcard scan @modelcontextprotocol/server-github
mcp-trustcard scan @modelcontextprotocol/server-github --json
mcp-trustcard scan --strict <server>
mcp-trustcard scan --threshold 70 <server>

The eight checks

| Check | Points | Question | |---|---:|---| | Installability | 15 | Can the package be resolved? | | Protocol handshake | 25 | Does it speak MCP correctly? | | Tool schema validity | 15 | Are its schemas valid? | | Destructive capabilities | 10 | Does it expose dangerous capabilities? | | Authentication | 10 | Does it clearly handle authentication? | | Secret exposure | 10 | Does it expose secret-shaped material? | | Protocol version | 10 | Does it negotiate a supported protocol? | | Latency / failure rate | 5 | Does it respond reliably? |

The score is useful for:

  • CI
  • discovery
  • regression detection
  • ecosystem visibility

But a score is not a trust decision.

A server scoring 95 can still be the wrong capability for a particular agent.

A server scoring 60 can still be acceptable under a constrained policy.

Trustcard separates empirical health from cryptographic identity.

Danger detection — three engines

The destructive-capabilities check uses a three-engine fusion:

  1. Heuristic engine — word-boundary regex for destructive verbs (delete, destroy, drop, kill, …) and write/exec verbs, plus inputSchema parameter analysis for dangerous inputs (command, sql, path, url, webhook, script). Context-aware scoring: verbs like clear and reset are only destructive when paired with destructive nouns (files, data, cache, database) — not when used in cognitive tools ("clear thoughts").
  2. Semantic engine — TF-IDF vectors over tool names + descriptions, compared against a curated corpus of dangerous-action patterns using cosine similarity. Catches novel attacks that avoid known verbs (e.g. "invalidate stored data").
  3. Injection engine (v2.2) — scans tool descriptions for prompt-injection markers: <IMPORTANT> tags, [SYSTEM OVERRIDE] brackets, "ignore previous instructions", "do not tell the user", sensitive file paths (~/.ssh/id_rsa), secrecy instructions, base64 blobs, and exfiltration language. This is a separate threat class from destructive actions — a tool can have a benign schema ("add two numbers") with a weaponized description.

Fusion logic: when multiple engines flag a tool, confidence is high. When only one flags it, medium/low. A tool is marked dangerous when the fused score exceeds 0.3.

Safe tool patterns: idempotent non-destructive operations (create_directory, mkdir, sequentialthinking) are whitelisted — the override applies unless the injection detector flags the description (a poisoned create_directory is still dangerous).

Call-time protection

A scan is a snapshot.

Capabilities can change after the scan.

The proxy enforces an approved manifest at runtime:

# Generate a manifest (includes danger analysis + 90-day expiry by default)
mcp-trustcard gen-manifest \
  @modelcontextprotocol/server-memory \
  --save-manifest memory.json

# For local commands (e.g. a Python server):
mcp-trustcard gen-manifest \
  --save-manifest my-server.json \
  --allow-tool dangerous_but_reviewed_tool \
  --expires-in 30 \
  -- uv run my-server mcp serve

# Inspect a manifest or pin store
mcp-trustcard inspect memory.json

# Enforce at call time (stdio)
mcp-proxy \
  --manifest memory.json \
  -- npx -y @modelcontextprotocol/server-memory

For remote HTTP/SSE servers:

mcp-http-proxy \
  --manifest notion.json \
  --upstream https://example.com/mcp \
  --port 9876 \
  --strict

The proxy can detect:

  • new tools
  • removed tools
  • changed schemas
  • unapproved calls
  • manifest drift
  • manifest expiration

It can then:

ALLOW
WARN
BLOCK

according to policy.

Manifest expiration

Manifests carry an expiresAt timestamp (default: 90 days). An expired manifest blocks all calls until regenerated, ensuring the danger analysis stays fresh. Override with --expires-in <days> or --no-expiry.

Tool overrides

Tools flagged as dangerous by the danger detector can be explicitly allowed with --allow-tool <name> (repeatable). The override is recorded in the manifest as manualOverride: true so it's visible in audit. Use this only for tools you've reviewed and that have their own safety constraints.

Why blocked?

Every denial includes a structured explanation — not just "DENIED" but the tool name, the reason code (MANIFEST_EXPIRED, TOOL_NOT_APPROVED, DANGEROUS_TOOL), the danger score, and the action to take.

Signed, chained receipts

Trustcard can bind a call to the capability that authorized it:

{
  capability: toolsetDigest,
  tool: toolDigest,
  arguments: argsDigest,
  result: resultDigest
}

Receipts are signed and hash-chained:

receipt[n]
    ↓
hash
    ↓
receipt[n+1]

This makes the history tamper-evident.

A receipt is evidence of a decision and an observed interaction.

It is not proof that a server behaved honestly internally.

Capability descriptors

The trust model is not fundamentally MCP-specific.

MCP is the first supported protocol.

The deeper abstraction is:

                ┌─────────────┐
MCP ───────────▶│             │
OpenAPI ───────▶│ Capability  │
Function calls ─▶│ Descriptor │
Plugins ────────▶│             │
Agents ─────────▶│             │
                └──────┬──────┘
                       │
                       ▼
              Canonical identity
              Provenance
              Change
              Policy
              Receipts

A capability descriptor projects different execution surfaces into one canonical trust model.

The goal is simple:

Trust should attach to what a capability can do, not to the protocol that happens to transport it.

What trustcard does not claim

For the full guarantees table, see docs/SECURITY-MODEL.md.

Trustcard is not a sandbox.

A signed capability can still be malicious.

A publisher can sign bad software.

A trusted server can have a vulnerability.

A receipt can prove what was authorized and observed, not that the server's internal execution was honest.

Trustcard addresses:

identity
provenance
continuity
change
authorization
evidence

It does not replace:

sandboxing
least privilege
runtime isolation
code auditing
secret management

Those are complementary controls.

Documentation

Development

npm test
npm run test:fast

Trustcard is implemented with Node.js standard-library primitives, including:

node:crypto
node:child_process

The short version

A scanner tells you what a server looked like.

A signature tells you who authorized a capability.

A digest tells you what the capability is.

A pin tells you whether it changed.

A policy tells you whether the call is allowed.

A receipt tells you what was authorized and observed.

trustcard combines all of them.

License

MIT