Skip to main content
Glama

🔄 Synced from a monorepo — but with a live history. warden mirrors the canonical AI-Factory monorepo. History here is append-only (no force-push). Pull requests are welcome — merged PRs are imported back into the monorepo and re-synced here, so your contribution becomes canonical. 💬 Issues · Pull requests both welcome.

WARDEN — MCP server

🌐 English · Русский · Español · Français · 中文 · Glossary

One MCP server. Security firewall for advertised tool definitions. Library included.

Transport: stdio (npx -y @aimarket/warden / node dist/mcp-server.js). Compatible hosts: Claude Desktop, Cursor, Glama, and any MCP client that speaks stdio. No API keys.

Item

Location

MCP entrypoint (stdio)

warden-mcpsrc/mcp-server.ts

Tools

vet_mcp_server, static_scan_tools, classify_sensitive_tools, check_egress_url, canonicalize_json, list_scan_rules

Library

import { Warden } from "@aimarket/warden"

Glama / Docker (stdio)

Dockerfile, glama.json

Official MCP Registry

server.jsonio.github.alexar76/warden

Smithery

smithery.yaml

An MCP server tells your agent what its tools do. The agent believes it — that sentence is the attack surface. A tool description is prompt text delivered by a third party straight into your model's context, and a schema field named api_key is a request for your secrets phrased as an API.

WARDEN vets a server before any of its tools reach the model, and returns a verdict you can record: allow/block, a 0..1 score, the findings that produced it, a per-tool partition, and the exact rule table that was in force.

Zero npm runtime dependencies. The library's only import is node:crypto. The stdio MCP server adds other node: builtins (fs, path, process) and still pulls in no packages. It is the firewall out of ARGUS, extracted so you can put it in front of your own MCP host without adopting an agent.

Run as MCP server (stdio)

npx -y @aimarket/warden            # bin: warden-mcp
# from this repo:
npm run build && node dist/mcp-server.js

Claude Desktop / Cursor (mcpServers entry):

{
  "mcpServers": {
    "warden": {
      "command": "npx",
      "args": ["-y", "@aimarket/warden"]
    }
  }
}

The process never starts, proxies, or sandboxes another MCP server — you pass a tools/list dump in, you get a verdict out.

Tool

When to use

vet_mcp_server

Full gate chain on a server identity + advertised tools

static_scan_tools

Injection / exfil scan only (no origin / pinning / threat feed)

classify_sensitive_tools

Operator glob split — not an injection scan

check_egress_url

Hostname allowlist (empty list denies every host)

canonicalize_json

RFC 8785 bytes for feeds and pins

list_scan_rules

Published rule table + digest

Glama TDQS: MCP annotations (readOnly / destructive / idempotent / openWorld), when-to-use / when-not naming siblings, every inputSchema property described, outputSchema on every tool.

Publish on Glama

Listing: glama.ai/mcp/servers/alexar76/warden · quality score: glama.ai/mcp/servers/alexar76/warden/score

Same pattern as ARGUS and aimarket-mcp: repo-root glama.json + Dockerfile + node dist/mcp-server.js. Admin form values: docs/GLAMA.md.

Related MCP server: truecopy

Library (embed in your host)

npm install @aimarket/warden
import { Warden, ThreatFeed, silentLogger } from "@aimarket/warden";

const threatFeed = new ThreatFeed({ feedPublicKey: process.env.FEED_PUBKEY });
await threatFeed.load(process.env.FEED_URL); // omit → built-in deny-list only, no network

const pins = new Map();
const warden = Warden.create({
  policy: {
    blockAtSeverity: "high",
    sensitiveToolPatterns: ["*delete*", "*transfer*", "*key*"],
    allowUnknownServers: false, // fail-closed: only servers you declared
    pinToolDefs: true,
  },
  threatFeed,
  store: {
    getPin: async (id) => pins.get(id),
    putPin: async (p) => void pins.set(p.serverId, p),
  },
  log: silentLogger(), // or your own logger
});

const verdict = await warden.vet(server, await client.listTools());

if (!verdict.allow) throw new Error(`blocked by ${verdict.decidedBy}`);
const usable = verdict.allowedTools; // a poisoned tool can be quarantined alone
await warden.approve(server, tools); // pin what the user accepted

vet() performs no network I/O. The only request WARDEN ever makes is the threat-feed fetch you asked for by passing a URL to load().

The gate chain

flowchart LR
  T["tool defs<br/>from the server"] --> S["static scan<br/>25 rules"]
  S --> F["threat feed<br/>11 built-ins + signed"]
  F --> O["origin<br/>declared vs catalog"]
  O --> P["pinning<br/>drift vs approval"]
  P --> V["verdict<br/>allow · score · findings<br/>allowedTools / blockedTools"]

Gate

What it decides

Network

Fatal?

static-scan

Injection, exfiltration, credential requests and hidden-Unicode/base64 tells in the tool name, its description and its inputSchema — 25 rules, v4, of which 15 can block and 10 are advisory-only, 17 also cover the name, and 12 carry a context guard

none

no

threat-feed

Known-bad server identity or tool, from 11 built-in records plus an optional signed feed

only the feed fetch

yes, for a server-scoped critical

origin

Whether the operator declared this server or it arrived from a remote catalog

none

yes, under allowUnknownServers: false

pinning

Whether the tool defs still match what the user approved

none

yes, under pinToolDefs: true

The composite score is the product of gate contributions, so one bad gate drags the whole server down rather than being averaged away. Severity and blocking are separate axes: an advisory finding is reported and never blocks and never costs a tool, at any blockAtSeverity — because "how much attention does this deserve" and "is this a defect at all" are different questions, and encoding the second as a low severity made it blocking again for anyone who tightened the threshold.

The verdict is meant to be recorded

{
  allow: false,
  score: 0,
  decidedBy: "threat-feed",
  findings: [{ gate, severity, code: "THREAT_TOOL_MATCH", message, tool, advisory? }],
  allowedTools: ["add"],
  blockedTools: ["sweeper"],
  rulesets: { staticScan: { version: "4", digest: "sha256-klRyTiD3…" } }
}

rulesets is not decoration. The same server scores differently under a later rule table, and without the version and a digest over the rules there is no way to tell that apart from the server having changed. A stored scan without them is not reproducible.

Signed threat feed

WARDEN will not read an unsigned remote feed. The contract is deliberately boring:

GET <your feed url>
{ "records": [ {pattern, severity, code, reason, source, scope}, … ],
  "timestamp": 1786205907380,   // epoch ms, integer — required
  "signature": "f588d5a4…"      // Ed25519 (hex) over the RFC 8785 canonical
}                               // form of {records, timestamp}

Three properties are checked, and any failure keeps the built-in floor rather than degrading to no protection:

  1. authenticity — Ed25519 against the key you pinned in advance (feedPublicKey);

  2. freshness — the signed timestamp must be inside maxAgeMs (24 h by default), so whoever serves the URL cannot replay a months-old snapshot and silently erase every record added since. A signature says who wrote a document, never when you were handed it;

  3. determinism — RFC 8785 canonical bytes, so publisher and verifier agree regardless of JSON key order.

MOMUS is a reference publisher of this contract (/warden/threat-feed) if you want something to point load() at.

Also in the box

  • EgressGuard — an outbound allowlist to wrap any request a tool makes. A tool reaching a host you never listed is the classic phone-home tell. *.example.com matches subdomains; an empty allowlist blocks everything rather than allowing everything.

  • isSensitiveTool / classifyTools — glob classification of tools that must require per-call approval. Sensitive tools stay advertised; they just cannot run unattended.

  • canonicalize / parseJsonStrict — a strict RFC 8785 (JCS) implementation, also exported as @aimarket/warden/jcs so another implementation can be byte-checked against it. Integers only beyond MAX_SAFE_JSON_INTEGER, refusal (not escaping) on lone surrogates, and a reason code on every refusal.

Documentation

The gate chain

Every rule tier, every finding code, how the composite score is built, and how to add a gate

The signed threat feed

The wire contract, the three checks, and how to publish a feed WARDEN will accept

Integration guide

Wiring WARDEN into your own MCP host, policy choices, and what to record

Field survey: 1 108 public MCP servers

What WARDEN decided on real third-party tool definitions — 50 servers blocked, 4 substantiated, and the six ways the rest were wrong

Glama / Docker

stdio MCP server, health check, admin Build steps / CMD

MCP registries

Official Registry, Smithery, mcp.so / Pulse

Security

How to report a firewall bypass

Contributing

Zero-dep rule, ruleset PRs

What this is not

  • Not a sandbox. These are in-process JS decisions. OS-level confinement of the MCP child process (seccomp/Landlock, sandbox-exec) is not here.

  • Not a model. No LLM is called anywhere in the chain. That is why vet() is fast, offline and deterministic — and why the static scan is regex-shaped and will miss a paraphrase no rule covers.

  • Not a reputation service. An earlier version had a gate that asked a trust oracle for a score it had no data to compute, then reported the oracle as unreachable without having sent a request. It was removed, and test/no-phantom-gate.test.ts fails if any gate ever claims unreachability again.

  • Not a substitute for reading the tool defs. 11 built-in threat records is a floor, not a catalog.

  • Not a proxy. The stdio MCP entry inspects advertised definitions you pass it. It does not connect to, fetch, or execute the server under scan.

Development

npm install && npm run build && npm test   # 166 tests

test/packaging.test.ts is what keeps the headline honest: it fails if an npm runtime dependency appears, if any source file imports outside the package (except node: builtins), or if the entry point stops exporting the enforcement surface. test/mcp-server.test.ts is the Glama health check: initialize + tools/list + a tools/call.

Used by ARGUS (the reference host), MOMUS (the publisher side), and the AICOM MCP-security course.

MIT © AICOM (alexar76)

Available Tools

6 tools
canonicalize_jsonCanonicalize JSON with RFC 8785 (JCS) bytesA
Read-onlyIdempotent

Return the RFC 8785 JSON Canonicalization Scheme serialization WARDEN uses for threat-feed signatures and tool-def pins, so another implementation can byte-check against it. Integers only inside ±(2^53−1); lone surrogates and non-integers are refused with a reason code, not escaped.

When to use: you are publishing or verifying a signed threat feed, hashing tool defs, or comparing two JSON documents that must agree regardless of key order. Subpath @aimarket/warden/jcs is the same function.

When NOT to use: scanning tool defs (static_scan_tools); pretty-printing for humans (this output is for bytes, not display).

Behaviour: local, no network. Pass either a parsed JSON value or a JSON string (string is parsed with parseJsonStrict first). Failure returns isError with CanonicalizationCode — it does not emit partial bytes.

Returns { canonical } or an error. Example: canonicalize_json({ value: { b: 1, a: 2 } }) → {"a":2,"b":1}.

ParametersJSON Schema
NameRequiredDescriptionDefault
valueYesJSON value to canonicalize, or a JSON string to parse first. Objects have keys sorted by UTF-16 code units. Numbers must be integers in ±(2^53−1). Do not pass undefined, functions, or cyclic structures.

Output Schema

ParametersJSON Schema
NameRequiredDescription
canonicalYesRFC 8785 canonical JSON text (UTF-8-ready string). Hash or sign these bytes, not JSON.stringify output.

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations, the description reveals local/no-network operation, the exact failure mode (isError with CanonicalizationCode, no partial bytes), accepted input forms (parsed value or JSON string parsed with parseJsonStrict), and strict acceptance rules (integers within ±(2^53−1), lone surrogates refused). No annotation contradiction is present.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-organized with clear sections: purpose, when to use, when not to use, behavior, return shape, and example. Every sentence carries useful information, and the core purpose is front-loaded before the usage guidance.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a single-parameter tool with an output schema, the description fully covers usage context, input constraints, failure behavior, and expected output. Nothing an agent needs to call or interpret the result correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3. The description adds meaning by specifying that a string input is parsed with parseJsonStrict first, and it provides a concrete example (canonicalize_json({ value: { b: 1, a: 2 } }) → {"a":2,"b":1}) that clarifies input and output shape beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('Return'), a specific resource (RFC 8785 JSON Canonicalization Scheme serialization), and the purpose (WARDEN threat-feed signatures, tool-def pins, byte-checking). It also distinguishes the tool from static_scan_tools in the 'When NOT to use' section, so it is not just a restatement of the name.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description contains dedicated 'When to use' and 'When NOT to use' sections. It lists concrete use cases (publishing/verifying signed threat feeds, hashing tool defs, comparing JSON documents independent of key order) and names an existing alternative (static_scan_tools) plus an exclusion (pretty-printing for humans).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

check_egress_urlCheck a URL against a WARDEN egress allowlistA
Read-onlyIdempotent

Ask EgressGuard whether a URL's hostname is on an operator allowlist. A tool reaching a host you never listed is the classic phone-home tell. Empty allowlist blocks everything (fail-closed), not everything-allowed.

When to use: a tool is about to fetch/post and you want the same check a host should wrap around that request. Hostnames match case-insensitively; "*.example.com" matches subdomains, not the apex.

When NOT to use: vetting tool definitions (vet_mcp_server / static_scan_tools); canonicalizing JSON (canonicalize_json). This does not fetch the URL and does not inspect tool text.

Behaviour: local URL parse + hostname match. Unparseable URLs are refused. No DNS, no HTTP. Idempotent.

Returns { allowed, host?, reason? }. Example: check_egress_url({ url: "https://api.github.com/repos", allowlist: ["api.github.com", "*.internal.example.com"] }).

ParametersJSON Schema
NameRequiredDescriptionDefault
urlYesAbsolute URL the tool wants to open (https://host/path). Only the hostname is compared; path, query, and credentials are not allowlisted separately. Must be parseable by the WHATWG URL parser.
allowlistYesPermitted hostnames. Exact match, or leading "*." for subdomains ("*.example.com" matches api.example.com, not example.com). Empty array blocks every host. Entries are trimmed and compared case-insensitively.

Output Schema

ParametersJSON Schema
NameRequiredDescription
hostNoParsed hostname when the URL was valid.
reasonNoWhy the request is blocked; omitted when allowed is true.
allowedYestrue only when the hostname matches an allowlist entry.

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Even with annotations declaring readOnlyHint, idempotentHint, and destructiveHint, the description adds substantial behavioral context: local URL parse, no DNS/HTTP, fail-closed empty allowlist, case-insensitive matching, wildcard semantics, and refusal of unparseable URLs. This fully discloses the tool's operational behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-organized into short labeled sections, front-loads the core purpose, and contains no filler. Each sentence adds meaningful guidance, from scope and exclusions to behavior and return shape.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read-only, idempotent two-parameter tool, the description is complete: it explains purpose, when to use it, when not to use it, behavior, return value, and an example. The existing output schema covers the detailed return structure, so no necessary information is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema already documents both parameters thoroughly. The description adds value beyond this with a concrete example call, wildcard behavior restated in practical terms, and the fail-closed empty allowlist note, which helps the agent form correct invocations.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: 'Ask EgressGuard whether a URL's hostname is on an operator allowlist.' It clearly distinguishes itself from siblings by naming vet_mcp_server, static_scan_tools, and canonicalize_json as tools not to use for this purpose.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit 'When to use' and 'When NOT to use' sections, naming concrete alternatives and explaining the intended context: checking a host before a tool fetches or posts. It also specifies what the tool does NOT do, such as fetching the URL or inspecting tool text.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

classify_sensitive_toolsClassify MCP tools as sensitive vs safe by glob policyA
Read-onlyIdempotent

Split advertised tool names into sensitive vs safe using the operator's case-insensitive * globs (the same policy.sensitiveToolPatterns a host would use). Sensitive tools stay advertised; they require per-call approval — this tool does not run them.

When to use: show the user which names will need confirmation before they approve a server, or to preview a glob set. This is policy over identifiers, not an injection scan.

When NOT to use: scanning descriptions for poisoning (static_scan_tools or vet_mcp_server); checking whether a URL is allowed out (check_egress_url).

Behaviour: local glob match, no network. An empty patterns array marks every tool safe. Patterns match the whole name; "delete" hits create_delete_repo. Does not call Warden.vet and does not persist anything.

Returns { sensitive, safe }. Example: classify_sensitive_tools({ tools: [{ name: "delete_repo", description: "Delete a repository.", inputSchema: { type: "object" } }], patterns: ["delete"] }).

ParametersJSON Schema
NameRequiredDescriptionDefault
toolsYestools/list items whose names will be classified. Descriptions and schemas are ignored; only name is matched.
patternsYesOperator globs, case-insensitive, matched against the whole tool name. "*" is the only wildcard. Empty array → every tool is safe. Same semantics as WardenPolicy.sensitiveToolPatterns, not threat-feed matching.

Output Schema

ParametersJSON Schema
NameRequiredDescription
safeYesNames matching no pattern.
sensitiveYesNames matching at least one pattern. Still advertised; require per-call approval.

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the readOnlyHint/idempotentHint/destructiveHint annotations by disclosing: local glob match with no network access, no persistence, no Warden.vet call, empty patterns array → every tool safe, whole-name matching with '*delete*' hitting create_delete_repo, and that sensitive tools are classified but not run. These are exactly the behavioral traits an agent needs to predict side effects and edge cases.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Organized into labeled sections (When to use / When NOT to use / Behaviour / Returns) that make it scannable, with the core purpose front-loaded in the first sentence. Slightly verbose, but every sentence carries distinct information — no filler, and the section labels justify the length.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Complete for a 2-param tool with full schema coverage, rich annotations, and an output schema. The description covers purpose, when-to-use versus three named siblings, edge cases (empty patterns), safety profile (no network, no persistence), matching semantics, and return shape. Nothing an agent needs to invoke it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so baseline is 3. The description adds genuine value with a concrete worked example showing the call shape and return value ({ sensitive, safe }), and it reinforces the crucial nuance that descriptions/schemas are ignored in classification and only name is matched. The example clarifies the wildcard semantics beyond what the schema states.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: 'Split advertised tool names into sensitive vs safe using the operator's case-insensitive * globs'. It names the policy source (policy.sensitiveToolPatterns), explicitly declares what it is not ('This is policy over identifiers, not an injection scan'), and the title itself is an accurate summary. Distinguishes clearly from siblings static_scan_tools, vet_mcp_server, and check_egress_url.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides explicit selection criteria: 'When to use: show the user which names will need confirmation before they approve a server, or to preview a glob set.' Then gives explicit exclusions with named alternatives: 'When NOT to use: scanning descriptions for poisoning (static_scan_tools or vet_mcp_server); checking whether a URL is allowed out (check_egress_url).' An agent can route to the correct sibling without inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_scan_rulesList the published WARDEN static-scan rule tableA
Read-onlyIdempotent

Return the in-force static-scan ruleset: version, digest, and every rule's code, severity, tier (block vs advise), surfaces (name / description / inputSchema), optional regex source, and named guards. A recorded verdict is only reproducible together with this identity.

When to use: explain a finding code, confirm you are on ruleset v4, or re-run a scan with the same table. include_source=true adds the regex source and flags for an independent re-implementation.

When NOT to use: evaluating a live tools/list (static_scan_tools or vet_mcp_server — those apply the table). This tool does not scan anything.

Behaviour: local snapshot of the compiled rule table, no network, no mutation. Digest is sha256 over the RFC 8785 form of {version, rules}.

Returns the ruleset object. Example: list_scan_rules({ include_source: false }).

ParametersJSON Schema
NameRequiredDescriptionDefault
include_sourceNoWhen true, each rule includes source (regex body) and flags so a third party can re-run the exact pattern. Default false — identity, tier, surfaces, and guards only, smaller payload.

Output Schema

ParametersJSON Schema
NameRequiredDescription
rulesYes
digestYessha256-<base64> of the canonical rule table.
versionYesMonotonic ruleset version.

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations (readOnly, idempotent, non-destructive), the description adds genuinely new behavioral context: 'local snapshot of the compiled rule table, no network, no mutation,' the digest computation detail ('sha256 over the RFC 8785 form of {version, rules}'), and the reproducibility caveat that 'a recorded verdict is only reproducible together with this identity.' None of this is derivable from the annotations, and it does not contradict them.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core purpose, then organized into clearly labeled sections (When to use / When NOT to use / Behaviour / Returns) that make it scannable. Every sentence earns its place — the output content is enumerated once in detail rather than repeated, and the non-use case doubles as sibling differentiation. The minimal redundancy of the example call is negligible.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple 1-optional-parameter tool with an output schema present, nothing is missing: return contents, use cases, exclusion cases against siblings, network/side-effect behavior, digest identity, and an invocation example are all covered. An agent has everything needed to decide whether to call it and what to expect.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% — the input schema fully documents include_source, its default, and its effect. The description adds only marginal enrichment by framing include_source=true as enabling 'an independent re-implementation,' which gives the parameter a purpose beyond its mechanics. Baseline 3 is appropriate since the schema carries the heavy lifting.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Return the in-force static-scan ruleset' followed by an exact enumeration of contents (version, digest, rule code, severity, tier, surfaces, regex source, guards). It explicitly distinguishes itself from siblings with 'This tool does not scan anything' and names static_scan_tools and vet_mcp_server as the tools that apply the table, so an agent cannot confuse it with them.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides labeled 'When to use' guidance (explain a finding code, confirm ruleset v4, re-run a scan with the same table) and an explicit 'When NOT to use' section naming the sibling alternatives (static_scan_tools, vet_mcp_server) and the condition that routes to them. This is exactly the when/when-not/alternatives structure the rubric asks for.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

static_scan_toolsStatic-scan MCP tool definitions for injection and exfilA
Read-onlyIdempotent

Run only the static-scan gate (ruleset v4, 25 signatures with context guards) over advertised tool names, descriptions, and input schemas. Returns findings, a 0..1 gate score, and the published ruleset digest.

When to use: you have a tools/list dump and want injection / credential / hidden-Unicode hits without origin, pinning, or the threat feed. Cheaper and narrower than vet_mcp_server.

When NOT to use: you need the full host decision (vet_mcp_server); you want operator glob classification (classify_sensitive_tools); you want the published rule table itself (list_scan_rules).

Behaviour: local regex+guard evaluation, no network, no mutation. Advisory-tier hits are reported with advisory=true and do not reduce the score. Does not launch servers or send tool output to a model.

Returns structured JSON matching outputSchema. Example: static_scan_tools({ tools: [{ name: "add", description: "Add two integers.", inputSchema: { type: "object" } }] }).

ParametersJSON Schema
NameRequiredDescriptionDefault
toolsYestools/list items to scan (1..256). Same shape as vet_mcp_server.tools.

Output Schema

ParametersJSON Schema
NameRequiredDescription
scoreYesstatic-scan gate contribution: 1 minus the penalty for the worst non-advisory severity. Advisory hits do not change this number.
rulesetYes
findingsYesHits from the 25-rule table, including advisory-only codes.

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description adds significant behavioral detail beyond the read-only, idempotent, non-destructive annotations: local regex+guard evaluation, no network access, no mutation, no server launching, and advisory-tier hits flagged with advisory=true that do not reduce the score. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is longer than average, but each section earns its place: purpose, routing conditions, behavioral caveats, and a concrete example. The When to use / When NOT to use structure is scannable and front-loads the key decisions.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the rich annotations, full input schema, output schema, and sibling context, the description covers everything an agent needs to call correctly: scope, score range, advisory behavior, side-effect guarantees, and alternative routing. Nothing important is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema already documents the tools parameter and its nested properties. The description adds value by instructing the agent to pass descriptions and input schemas through unmodified, warning that rewriting hides injection surfaces, and noting the shape matches vet_mcp_server.tools.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific action ('Run only the static-scan gate') over a specific resource ('advertised tool names, descriptions, and input schemas'), then identifies the outputs. It clearly distinguishes itself from vet_mcp_server, classify_sensitive_tools, and list_scan_rules via the When NOT to use section.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Contains explicit 'When to use' and 'When NOT to use' sections. It names the triggering condition (having a tools/list dump and wanting injection/credential/hidden-Unicode hits) and lists sibling tools that should be used instead for broader analysis or rule retrieval.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

vet_mcp_serverVet an MCP server through the full WARDEN gate chainA
Read-onlyIdempotent

Run WARDEN's ordered gate chain (static-scan → threat-feed → origin → pinning) over a server identity plus its advertised tools/list payload and return a recordable verdict (allow/block, 0..1 product score, findings, allowedTools/blockedTools, ruleset digest).

When to use: you have a complete server record and want the same decision a host should make before any of those tool definitions reach the model. Prefer this over calling the four gates yourself.

When NOT to use: inspecting descriptions only (call static_scan_tools — no origin/pinning); splitting tools by operator glob (classify_sensitive_tools); checking one outbound URL (check_egress_url); producing RFC 8785 bytes (canonicalize_json).

Behaviour: local, deterministic, no network. This stdio process uses the built-in 11-record threat floor (it does not fetch a signed feed) and an empty in-memory pin store, so every server is first-contact: TOOL_DEF_UNPINNED is advisory and does not block. Origin defaults to allowUnknownServers=true so catalog-discovered servers are not fail-closed. Override policy when you need the host's real knobs. Does not connect to, start, or approve the target server.

Returns structured JSON matching outputSchema. Example: vet_mcp_server({ server: { id: "demo@0", name: "demo", transport: "stdio", command: "npx" }, tools: [{ name: "add", description: "Add two integers.", inputSchema: { type: "object" } }] }).

ParametersJSON Schema
NameRequiredDescriptionDefault
toolsYesExact tools/list payload (1..256 tools). Each item is name + description + inputSchema from the server. Do not filter before vetting — blockedTools is the partition.
policyNoOptional WardenPolicy overlay. Omitted keys keep the stdio defaults: blockAtSeverity=high, empty sensitiveToolPatterns, allowUnknownServers=true, pinToolDefs=true. Use classify_sensitive_tools when you only want the glob split.
serverYesIdentity of the MCP server being vetted — the host's McpServerRef, not a live connection. WARDEN never launches this command or fetches this URL.

Output Schema

ParametersJSON Schema
NameRequiredDescription
allowYesfalse when a gate was fatal or a non-advisory finding reached blockAtSeverity.
scoreYesProduct of per-gate scores in [0, 1]. One bad gate drags the whole server down; it is not an average.
findingsYesAccumulated findings across all gates, including advisory.
rulesetsYesRule-table identity in force for this verdict. Store this with the scan.
decidedByNoGate that produced the blocking decision, present only when allow is false.
allowedToolsYesTool names the host may expose to the model.
blockedToolsYesTool names quarantined; the rest of the server may still be usable.

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the readOnly/idempotent/destructive annotations, the description reveals local deterministic no-network behavior, built-in threat floor, empty pin store advisory outcomes, origin default, and that it never connects/starts/approves the server. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is organized into labeled sections, front-loads purpose, and uses each sentence for a distinct piece of information (use, exclusions, behavior, example). Despite length, it is dense and scannable.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With a rich input schema, output schema, and annotations present, the description still adds the operational context needed to call correctly: gate order, policy defaults, first-contact behavior, and exclusions. Nothing essential for selection or invocation is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema carries the parameter burden. The description adds a concrete invocation example and notes policy override semantics, but it doesn't need to compensate for missing param docs.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description opens with a specific verb+resource: run WARDEN's ordered gate chain over a server identity plus tools/list payload and return a verdict. It also distinguishes itself from siblings by naming what it is not in the 'When NOT to use' section.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Contains explicit 'When to use' and 'When NOT to use' guidance with named alternatives: static_scan_tools, classify_sensitive_tools, check_egress_url, canonicalize_json. It even says to prefer this over calling the four gates manually.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.

  1. 6 tool updatesv1.0.0
    • First observedcanonicalize_json
    • First observedcheck_egress_url
    • First observedclassify_sensitive_tools
    • First observedlist_scan_rules
    • First observedstatic_scan_tools
    • First observedvet_mcp_server

TDQS

A4.7/5.0
Disambiguation4/5

Most tools have sharply distinct purposes, and the one overlapping pair—vet_mcp_server vs static_scan_tools—is clearly differentiated by scope (full gate chain vs static-only) and by explicit when-to-use guidance. The remaining tools (classification, egress, canonicalization, rule listing) are cleanly separated and unlikely to be confused.

Naming Consistency4/5

Five of six tools follow a predictable verb-oriented snake_case pattern (classify_sensitive_tools, check_egress_url, canonicalize_json, list_scan_rules, and roughly vet_mcp_server). static_scan_tools is a noun-phrase outlier, but the overall naming style is consistent and readable.

Tool Count5/5

Six tools is well-scoped for the stated purpose: one comprehensive vetting entry point plus focused utilities for static scanning, policy preview, egress checks, canonicalization, and rules introspection. Each tool fills a distinct role without redundancy or bloat.

Completeness5/5

The toolset covers the full vetting decision, the static scan gate, sensitive-tool classification, outbound URL policy checks, canonicalization for signature/pin verification, and ruleset introspection. No obvious dead ends or missing operations prevent an agent from completing the typical vetting workflow.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    D
    maintenance
    MCP security trust layer. Continuously monitors 800+ MCP packages on npm for install scripts, command injection, hardcoded secrets, capability drift, and publisher posture. Ships a GitHub Action policy gate for PR-level allow/warn/block decisions. 5 MCP tools, no API key required.
    8
    121
    1
    MIT
  • A
    license
    A
    quality
    A
    maintenance
    Supply-chain gate for AI agent skills and MCP servers: poison-scan tool definitions, hash-pin the vetted set into a lock file and verify drift in CI. truecopy-mcp is a drop-in stdio proxy that filters a live server's tools/list down to its pinned, unmodified, unpoisoned tools.
    2
    29
    1
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Self-hosted MCP gateway that applies deterministic, compiled policy to tool discovery, invocation, and outbound data flow, with no model in the enforcement path. Every decision emits a hash-chained receipt sealed with Ed25519 and verifiable using public keys only.
    Apache 2.0
  • A
    license
    Not graded
    quality
    B
    maintenance
    A task-scoped MCP stdio proxy that learns candidate least-privilege policies from labeled successful runs, requires human review, enforces exact decisions, detects tool-definition drift, and emits privacy-minimized JSONL events for Wazuh.
    1
    Apache 2.0

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/alexar76/warden'

If you have feedback or need assistance with the MCP directory API, please join our Discord server