Skip to main content
Glama
vulnify

Vulnify MCP

Official

@vulnify/mcp is the MCP server for Vulnify, a runtime authorization layer for AI agents. The agent asks first. This process proxies https://api.vulnify.io. It does not store events or API keys.

Sign in with Vulnify (OAuth 2.1) at https://mcp.vulnify.io/mcp. That hosted server speaks stateless Streamable HTTP. The local path is npx -y @vulnify/mcp with VULNIFY_API_KEY.

check_action is a dry run. It skips the PII scan and records nothing. decide_action records a real decision. A REVIEW waits for a person. This server cannot approve or deny one.

Application code that should decide inside your own process uses the Node SDK (@vulnify/sdk). This package does not depend on the SDK. The SDK turns some transport failures into a fail-closed decision. This server returns those failures as MCP tool errors, so a model does not read them as ALLOW.

Quickstart

The source of truth is docs.vulnify.io/mcp. The same steps are in docs/clients.md.

Sign in with Vulnify

Connect to https://mcp.vulnify.io/mcp. Leave API-key and OAuth client fields empty. The client receives HTTP 401 and:

WWW-Authenticate: Bearer realm="https://mcp.vulnify.io/mcp", resource_metadata="https://mcp.vulnify.io/.well-known/oauth-protected-resource/mcp", scope="decisions:read decisions:write policies:read policies:test"

The body is {"error":"unauthorized","message":"Sign in with Vulnify, or send an API key as Authorization: Bearer or X-Vulnify-Key:."}. Protected-resource metadata lists the authorization server https://api.vulnify.io.

You choose an organization and allow the scopes the client requests:

Scope

Tools

decisions:read

get_decision

decisions:write

decide_action

policies:read

list_policies

policies:test

check_action, test_policies

After you allow access, the hosted server offers those five tools. plan_policy_changes and check_mcp_tool_call are not in that list. They need an API key. A missing scope comes back as a tool error that names the scope. That error is not an ALLOW. Revoke the connection under Settings > Connected apps: app.vulnify.io/settings/connected-apps.

Claude

In Claude, open Settings > Connectors > Add custom connector. Set the URL to https://mcp.vulnify.io/mcp. Do not paste an API key. Add Vulnify in Claude opens that dialog with the name and URL filled in. Claude then starts Sign in with Vulnify.

Cursor

Install in Cursor adds the hosted server and starts sign-in.

The same server in .cursor/mcp.json, or in ~/.cursor/mcp.json, is the URL with no header:

{
  "mcpServers": {
    "vulnify": {
      "url": "https://mcp.vulnify.io/mcp"
    }
  }
}

Grok

Open grok.com/connectors, then New Connector > Custom. Name it Vulnify. Set the URL to https://mcp.vulnify.io/mcp. Leave the OAuth fields empty. Grok starts Sign in with Vulnify.

Claude Code

claude mcp add --transport http vulnify https://mcp.vulnify.io/mcp

Claude Code then signs in. Do not pass an API key on this command.

API key or local npx

Use an API key when you need plan_policy_changes or check_mcp_tool_call, when the client cannot open a browser, or when the key has an IP allowlist. The local process needs Node.js 20 or newer and reads VULNIFY_API_KEY. It does not open the OAuth consent page.

npx -y @vulnify/mcp
VULNIFY_API_KEY=vln_live_... npx -y @vulnify/mcp

The key is vln_live_... or vln_test_.... A TEST key stores sandbox events. Those stay out of the main dashboards.

On the hosted server, both headers still work. Send the key on every request:

Authorization: Bearer <key>
X-Vulnify-Key: <key>

An API-key session lists all seven tools.

Cursor, hosted:

{
  "mcpServers": {
    "vulnify": {
      "url": "https://mcp.vulnify.io/mcp",
      "headers": {
        "Authorization": "Bearer vln_live_..."
      }
    }
  }
}

Cursor, local:

{
  "mcpServers": {
    "vulnify": {
      "command": "npx",
      "args": ["-y", "@vulnify/mcp"],
      "env": {
        "VULNIFY_API_KEY": "vln_live_..."
      }
    }
  }
}

X-Vulnify-Key works in place of Authorization on the hosted server.

Claude Code with an API key:

claude mcp add --transport http vulnify https://mcp.vulnify.io/mcp --header "Authorization: Bearer vln_test_your_key"

Prefer an environment variable over a key written into the shell history. For sign-in, use the Claude Code command with no header.

Claude Desktop can run the local process. On macOS the file is ~/Library/Application Support/Claude/claude_desktop_config.json. On Windows it is %APPDATA%\Claude\claude_desktop_config.json. Restart the app after saving.

{
  "mcpServers": {
    "vulnify": {
      "command": "npx",
      "args": ["-y", "@vulnify/mcp"],
      "env": {
        "VULNIFY_API_KEY": "vln_live_..."
      }
    }
  }
}

VS Code, .vscode/mcp.json, hosted:

{
  "servers": {
    "vulnify": {
      "type": "http",
      "url": "https://mcp.vulnify.io/mcp",
      "headers": {
        "Authorization": "Bearer ${input:vulnify-api-key}"
      }
    }
  }
}

VS Code, local:

{
  "servers": {
    "vulnify": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@vulnify/mcp"],
      "env": {
        "VULNIFY_API_KEY": "${input:vulnify-api-key}"
      }
    }
  }
}

Related MCP server: hejdar-mcp

How it works

The finalDecision field is the authoritative result. A tool error is not an ALLOW.

Tools

Every tool has a title and readOnlyHint, destructiveHint, idempotentHint, and openWorldHint. Hints tell the client how to present the tool. They do not change what the tool does.

Tool

API

Records?

readOnlyHint

Notes

check_action

POST /v1/policies/test (one case)

No

true

Skips the PII scan and records nothing. No event id.

decide_action

POST /v1/events

Yes

false

Writes a security event and an audit entry. finalDecision is the authoritative result.

get_decision

GET /v1/events/{id}

No

true

Reads a decision. Optional wait polls a REVIEW until ALLOW or BLOCK (30 seconds max).

list_policies

GET /v1/policies

No

true

Policies as code, sorted by name.

test_policies

POST /v1/policies/test

No

true

Up to 200 cases. Skips the PII scan. Proposed policies are not saved.

plan_policy_changes

POST /v1/policies/apply

No

true

dryRun is forced to true. Needs an org-wide LIVE key.

check_mcp_tool_call

POST /v1/gateway/mcp

Yes

false

Maps a tool name to an action and records the decision. Does not run the tool.

destructiveHint is false on every tool. openWorldHint is false on every tool, because each call stays inside the caller's own Vulnify organization. idempotentHint is true for the read-only tools and false for decide_action and check_mcp_tool_call. An idempotencyKey makes a retry of a recorded decision return the same event.

Policy list, test, and plan calls are limited to 60 requests per minute per key. Batch dry runs with test_policies. POST /v1/events has its own limit. The OpenAPI text says only that the limit was exceeded.

Safety

This server cannot change a review and cannot save a policy.

  • There is no approve tool and no deny tool. A human resolves a REVIEW in Vulnify.

  • There is no apply tool. plan_policy_changes calls POST /v1/policies/apply with dryRun: true on every request. The tool input has no dryRun field. The server sets dryRun last, so a caller cannot turn the dry run off. The tool returns the diff.

  • POST /v1/gateway/http is not a tool. On ALLOW, that API endpoint forwards the HTTP call. This server does not.

plan_policy_changes needs an org-wide LIVE key. A TEST key or an agent-bound key gets 403. An OAuth session does not list plan_policy_changes or check_mcp_tool_call.

OAuth scopes

User login is the hosted HTTP server. The local stdio process still uses an API key. The hosted server maps tools to scopes:

Tool

Scope

OAuth route

check_action

policies:test

POST /v1/mcp/policies/test

test_policies

policies:test

POST /v1/mcp/policies/test

decide_action

decisions:write

POST /v1/mcp/events

get_decision

decisions:read

GET /v1/mcp/events/{id}

list_policies

policies:read

GET /v1/mcp/policies

plan_policy_changes

API key and stdio only

Omitted from OAuth tools/list

check_mcp_tool_call

API key and stdio only

Omitted from OAuth tools/list

A token that is missing the scope gets a tool error that names the scope. That error is not an ALLOW. Active introspection results are reused for at most 60 seconds, and never past exp.

Distinct from the MCP gateway

https://mcp.vulnify.io/mcp (and the local stdio process) is the server an MCP client connects to. The client then calls the tools above.

check_mcp_tool_call is different. It sends one tool call to POST /v1/gateway/mcp on api.vulnify.io, records the decision, and stops. It does not execute the tool, and connecting a client to this server does not call that gateway.

IP allowlists

An API key can list allowed source IPs. Calls through https://mcp.vulnify.io/mcp with that key come from the hosted server's egress address, not from the machine where Cursor or VS Code is running. An allowlist that only contains an office or laptop address rejects the hosted server. Use npx -y @vulnify/mcp on a host whose address is on the list. Sign in with Vulnify does not send that API key.

Product

The screenshot is from a demo workspace. The agent is SupportBot.

Audit exports in the Vulnify app are a JSON or CSV download that includes a SHA-256 checksum. SIEM export is JSON or CEF lines.

Configuration

Variable

Where

Required

Purpose

VULNIFY_API_KEY

stdio process

yes

API key (vln_live_... or vln_test_...). HTTP does not fall back to this variable.

VULNIFY_BASE_URL

both

no

API base URL. Default https://api.vulnify.io.

OAUTH_INTROSPECTION_SECRET

HTTP

for user login

Bearer secret for POST /oauth/introspect. Stays on the server. API keys work without it.

OPENAI_APPS_CHALLENGE

HTTP

no

When set, GET /.well-known/openai-apps-challenge returns this value as text/plain. Unset, that path is 404.

PORT

HTTP

no

Listen port. Default 8080.

HOST

HTTP

no

Bind address. Default 0.0.0.0.

Use an agent-bound LIVE key when a recorded decision should count for one agent. plan_policy_changes needs an org-wide LIVE key.

VULNIFY_TEST_API_KEY is only for npm run test:live. The server does not read it.

HTTP server

npx -y @vulnify/mcp --http

The container runs the HTTP server as a non-root user:

docker build -t vulnify-mcp .
docker run --rm -p 8080:8080 -e PORT=8080 vulnify-mcp

No API key is required to start the container. Send the key on each request.

curl -sS localhost:8080/health
curl -sS -o /dev/null -w '%{http_code}\n' -X POST localhost:8080/mcp \
  -H 'content-type: application/json' -d '{}'

The health check prints JSON. The POST without a key prints 401.

GET /.well-known/mcp/server-card.json does not require a key. It lists the tools the server registers (names, descriptions, and input schemas), states that you can sign in with OAuth or send a Vulnify API key in a header, and links to the docs and this repository.

curl -sS https://mcp.vulnify.io/.well-known/mcp/server-card.json

Errors

Tool failures are MCP tool errors (isError). The API key is not included.

Status

Meaning

401

The API key or access token is missing, invalid, revoked, or expired.

403

The key is bound to another agent, the caller IP is not allowlisted, the access token lacks a scope, or plan_policy_changes was called without an org-wide LIVE key.

413

The JSON body is over the API's 200 KB limit.

429

The key is rate limited. Policy calls are 60 per minute. Retry a recorded decision with the same idempotencyKey.

Security

Report a vulnerability to security@vulnify.io. The disclosure policy is at vulnify.io/disclosure. See SECURITY.md.

Keys are not logged. Request logs are method, path, and status. content sent for a sensitive-data scan is forwarded to the API and is not written to this server's logs. The API scans that text in memory and does not store it.

This package does not run a shell and does not register hooks. Do not put a key in a tool argument or in a committed config file.

Network endpoints this process uses:

  • https://api.vulnify.io (or VULNIFY_BASE_URL) for every tool call, and for GET /v1/policies when an API key is checked. An API key is sent as Authorization: Bearer to /v1/*. A user access token is sent as Authorization: Bearer to /v1/mcp/*.

  • POST /oauth/introspect on that same origin, with Authorization: Bearer set to OAUTH_INTROSPECTION_SECRET, to validate vln_oat_... tokens. The secret is not sent to clients and is not logged.

  • https://mcp.vulnify.io/mcp is the hosted HTTP transport. The server process does not call that URL.

Development

npm install
npm test
npm run lint
npm run build

npm run test:live calls list_policies on https://api.vulnify.io when VULNIFY_TEST_API_KEY is set, and skips when it is not. It does not record an event.

Publishing is described in RELEASING.md.

License

MIT. Copyright 2026 Vulnify.

Available Tools

7 tools
check_actionCheck actionA
Read-onlyIdempotent
Inspect

Use for what-if questions when you are not about to act. Dry-run a proposed action against the organization policies (POST /v1/policies/test, one case, stored policies). This skips the PII scan and records nothing: no security event and no audit entry. There is no content field and no DLP scan. The result has no event id and no finalDecision. decide_action is the call that records a decision. Dry runs are limited to 60 requests per minute per key. test_policies covers up to 200 cases in one call.

ParametersJSON Schema
NameRequiredDescriptionDefault
agentYesAgent name. The dry run does not accept agentId.
actionYesEvent action. Allowed values: READ_DATA, WRITE_DATA, DELETE_DATA, EXPORT_DATA, SEND_EMAIL.
resourceYesResource name. The dry run does not accept resourceId.
destinationNoWhere the data goes. Allowed values: INTERNAL, EXTERNAL_EMAIL, EXTERNAL_API.
recordsAffectedNoHow many records the action would touch. Optional. 0 to 100000000.
containsSensitiveDataNoHint for policy conditions. This call does not scan content.

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultsYesOne result per case.

TDQS

A4.7/5.0
Behavior5/5

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

Annotations already establish readOnly/idempotent/non-destructive, and the description goes well beyond them: it discloses that this skips the PII scan, records no security event and no audit entry, performs no DLP scan, has no content field, and returns no event id or finalDecision, plus a concrete rate limit of 60 requests/minute/key. That is exactly the side-effect and constraint context an agent needs.

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?

Every sentence is front-loaded with actionable information and none is filler: usage condition, endpoint, side-effect profile, sibling routing, rate limit. Dense but each clause earns its place.

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 dry-run tool with an output schema present, the description covers everything the agent needs: trigger condition, scope of the check, side effects, rate limit, and sibling alternatives. Return-value shape is intentionally signaled ('no event id and no finalDecision') rather than fully specified, which is appropriate given the output schema.

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%, so all six parameters (including both enums) are already fully documented in the schema, which sets the baseline at 3. The description adds only marginal parameter meaning by noting the absence of a content field and clarifying that no DLP scan occurs, which largely restates the schema's own note on containsSensitiveData.

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+resource ('Dry-run a proposed action against the organization policies') with the exact endpoint, and explicitly differentiates itself from siblings decide_action (records a decision) and test_policies (batch up to 200 cases). An agent can select this tool without opening any schema.

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?

It opens with the triggering condition ('Use for what-if questions when you are not about to act') and names the alternative that does record ('decide_action is the call that records a decision'), plus routes batch needs to test_policies. When-to-use, when-not-to-use, and alternatives are all present.

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

check_mcp_tool_callCheck MCP tool callAInspect

Records a decision for a downstream MCP tool call (POST /v1/gateway/mcp). Vulnify maps the tool name to an action by substring and returns the same recorded decision as decide_action, including an id. This writes a security event and an audit entry. The tool arguments are not executed. The finalDecision field is the authoritative result. A REVIEW or BLOCK finalDecision means the downstream tool was not allowed. This server cannot approve the review. An idempotencyKey makes a retry return the same event.

ParametersJSON Schema
NameRequiredDescriptionDefault
toolYesDownstream MCP tool name. Vulnify maps it to an action by substring. The tool is not executed.
agentNoAgent name. Use this or agentId. A registered MCP route can supply a default agent.
agentIdNoAgent id (UUID). Use this or agent.
contentNoOptional text scanned for sensitive data. Scanned in memory and not stored. This server does not log it.
routeIdNoRegistered MCP route. Supplies a default agent.
resourceNoResource name registered in Vulnify. Use this or resourceId.
argumentsNoTool arguments. Not executed by Vulnify.
resourceIdNoResource id (UUID). Use this or resource.
destinationNoWhere the data goes. Allowed values: INTERNAL, EXTERNAL_EMAIL, EXTERNAL_API.
idempotencyKeyNoRetries with the same key return the stored decision for 24 hours instead of recording another event.
recordsAffectedNoHow many records the tool call would touch. Optional. 0 to 100000000.

Output Schema

ParametersJSON Schema
NameRequiredDescription
idYesDecision id.
finalDecisionYesAuthoritative result. Allowed values: ALLOW, REVIEW, BLOCK.

TDQS

A3.9/5.0
Behavior5/5

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

Annotations only carry the readOnly/destructive/idempotent/openWorld hints, and the description adds substantial context beyond them: it writes a security event and an audit entry, the tool arguments are never executed, finalDecision is the authoritative output, REVIEW/BLOCK means the downstream tool was denied, the review cannot be approved here, and idempotencyKey governs retry behavior. This is exactly the side-effect and outcome disclosure a security-gate tool needs.

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?

Front-loaded with the core action and delivered in short, information-dense sentences with no filler. It reads as a flat list of facts rather than organized prose, but each sentence carries distinct, useful information.

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

Completeness4/5

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

An output schema exists, so return values need not be enumerated, and the description still flags the critical output field (finalDecision is authoritative) plus the meaning of REVIEW/BLOCK. For a write-bearing security gate with 11 parameters it covers the important behaviors, though it could be clearer about how a caller should act on an ALLOW versus a REVIEW outcome.

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 already documents all 11 parameters (substring mapping, agent/agentId alternatives, content not stored, idempotencyKey 24h window, etc.). The description largely restates that material ('The tool arguments are not executed', the idempotencyKey behavior) rather than adding new parameter meaning, so the baseline 3 applies.

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

Purpose4/5

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

States a specific verb and resource ('Records a decision for a downstream MCP tool call') and pins it to an endpoint, so the agent knows exactly what operation it is. It names the sibling decide_action and explains the relationship ('returns the same recorded decision as decide_action'), which helps differentiate, though it never states plainly why one would pick this over decide_action.

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

Usage Guidelines3/5

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

Usage is implied rather than stated: the tool is scoped to downstream MCP tool calls that Vulnify maps by substring, which hints at the MCP-specific case versus the generic check_action/decide_action. There is one useful when-not signal ('This server cannot approve the review'), but no explicit 'use this instead of X when Y' routing guidance.

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

decide_actionDecide actionAInspect

Call this before a consequential action with any tool or connector: sending an email or message, exporting or sharing data, deleting data, writing to production or financial records, payments, or external API writes. ALLOW: proceed. REVIEW: hold the action, tell the user it waits for approval in Vulnify, and check again with get_decision. BLOCK: skip the action and explain the reasons. Records a decision for a proposed action (POST /v1/events). This writes a security event and an audit entry, counts toward the organization quota, and may open a human review. The finalDecision field is the authoritative result. decision is what was stored and does not change when a review is resolved. finalDecision stays REVIEW until a human approves, denies, or the review expires. This tool does not approve the review. A REVIEW or BLOCK finalDecision means the action was not allowed. Optional content is scanned in memory and is not stored. An idempotencyKey makes a retry return the same event.

ParametersJSON Schema
NameRequiredDescriptionDefault
agentNoAgent name. Omit only when the API key is bound to an agent. Use this or agentId.
actionYesEvent action. Allowed values: READ_DATA, WRITE_DATA, DELETE_DATA, EXPORT_DATA, SEND_EMAIL.
agentIdNoAgent id. Use this or agent.
contentNoOptional text scanned for sensitive data. Scanned in memory by Vulnify and not stored. This server does not log it.
resourceNoResource name. Use this or resourceId.
resourceIdNoResource id. Use this or resource.
destinationNoWhere the data goes. Allowed values: INTERNAL, EXTERNAL_EMAIL, EXTERNAL_API.
idempotencyKeyNoRetries with the same key return the stored decision for 24 hours instead of recording another event.
recordsAffectedNoHow many records the action would touch. Optional. 0 to 100000000.

Output Schema

ParametersJSON Schema
NameRequiredDescription
idYesDecision id.
finalDecisionYesAuthoritative result. Allowed values: ALLOW, REVIEW, BLOCK.

TDQS

A4.6/5.0
Behavior5/5

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

With annotations only covering broad hints, the description carries the load and does so richly: it writes a security event and audit entry, consumes organization quota, may trigger human review, does not itself approve reviews, and content is scanned in memory and not stored. The idempotencyKey explanation (same key returns stored decision for 24h) refines rather than contradicts idempotentHint=false, which describes default behavior.

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?

Front-loaded with the trigger condition and the outcome-to-action mapping, which is the highest-value content. It is dense and somewhat long, but nearly every sentence (finalDecision vs decision, REVIEW persistence, idempotency) adds decision-relevant information rather than padding.

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 consequential gating tool with an output schema present, the description still explains the return semantics (finalDecision is authoritative; decision does not change on resolution; REVIEW/BLOCK mean the action was not allowed). Combined with full schema coverage, nothing an agent needs to call it correctly 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 already documents all 9 parameters, including the enum values and idempotencyKey behavior. The description's mentions of content scanning and idempotency largely restate schema text, so this is correctly a baseline 3.

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?

Opens with a specific trigger ('Call this before a consequential action with any tool or connector') and states the resource is a recorded decision for a proposed action (POST /v1/events). An agent can distinguish it from siblings like get_decision and check_action without opening a schema.

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?

Explicitly enumerates when to call it (sending email/messages, exporting/sharing data, deleting, production/financial writes, payments, external API writes) and prescribes per-outcome behavior for ALLOW, REVIEW, and BLOCK, including the follow-up call to get_decision. Nothing is left to inference.

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

get_decisionGet decisionA
Read-onlyIdempotent
Inspect

Read a recorded decision (GET /v1/events/{id}), including a REVIEW. finalDecision is REVIEW while the review is pending, then ALLOW after approval or BLOCK after denial or expiry. decision itself does not change. The finalDecision field is the authoritative result. waitMs polls until finalDecision is ALLOW or BLOCK, or until the bounded wait elapses (30 seconds maximum). waitTimedOut is true when the wait ended and finalDecision is still REVIEW. This does not approve or deny the review.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesDecision id returned by decide_action or check_mcp_tool_call.
waitMsNoWhen finalDecision is REVIEW, the server polls until finalDecision is ALLOW or BLOCK, or until this many milliseconds pass. Maximum 30000. 0, or omitting the field, returns the current decision immediately.
pollIntervalMsNoMilliseconds between polls. Default 1000.

Output Schema

ParametersJSON Schema
NameRequiredDescription
idYesDecision id.
waitTimedOutYesTrue when the wait elapsed and finalDecision is still REVIEW.
finalDecisionYesAuthoritative result. Allowed values: ALLOW, REVIEW, BLOCK.

TDQS

A4.3/5.0
Behavior4/5

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

Annotations already cover the safe-read profile (readOnly, idempotent, non-destructive), and the description adds genuine behavioral context: the state transition from REVIEW to ALLOW/BLOCK, that decision is immutable while finalDecision is authoritative, and the 30-second bounded wait. It omits error/not-found behavior, but the added semantics are substantial.

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?

Front-loads the verb, resource, and endpoint, then spends its remaining sentences on the semantics an agent actually needs (state transitions, polling bound, timeout flag). No filler or restated name/title.

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 annotations carrying the safety profile, a 100%-covered schema, and an output schema, the description only needs to supply the non-obvious semantics, and it does: finalDecision authority, polling termination conditions, and the non-mutating boundary.

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 id, waitMs, and pollIntervalMs are already fully documented with constraints. The description paraphrases waitMs polling behavior but adds no syntax or format detail beyond the schema, so the baseline 3 applies.

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 ('Read a recorded decision (GET /v1/events/{id})') and clarifies the scope includes a REVIEW, with the explicit boundary 'This does not approve or deny the review' separating it from decide_action.

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

Usage Guidelines4/5

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

Explains clearly when to supply waitMs (while finalDecision is REVIEW, to poll until ALLOW/BLOCK or timeout) and what waitTimedOut means, plus when not to use it. It never names decide_action as the alternative for resolving a review, so the routing guidance is one step short of explicit.

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

list_policiesList policiesA
Read-onlyIdempotent
Inspect

List the organization policies as code (GET /v1/policies). Returns apiVersion vulnify.io/v1 and policies sorted by name. Read-only. Any non-revoked API key of the organization may call it. Limited to 60 requests per minute per key.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
policiesYesStored policies sorted by name.
apiVersionYesAlways vulnify.io/v1.

TDQS

A4/5.0
Behavior4/5

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

Annotations already cover the safety profile (readOnlyHint, idempotentHint, destructiveHint=false), yet the description adds genuinely new context: a 60 requests/minute/key rate limit, the auth requirement (any non-revoked API key), and the sort order of results. It does not describe error or pagination behavior, so it falls short of a 5.

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?

Three short sentences, front-loaded with purpose and endpoint, then behavior and constraints. Every sentence carries distinct information (endpoint, return shape, auth, rate limit) with no redundancy.

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 parameterless read tool with an output schema and full annotation coverage, the definition supplies everything an agent needs: endpoint, authenticated-access rule, rate limit, and result ordering. Nothing material 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?

The tool takes zero parameters, so there is nothing for the description to disambiguate; the schema is empty and fully covered. Baseline 4 applies for a no-parameter tool.

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

Purpose4/5

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

States a specific verb and resource ('List the organization policies as code') and pins the underlying endpoint (GET /v1/policies), which clearly separates it from mutating siblings like plan_policy_changes. It stops short of naming an alternative sibling or stating when this read is preferred over test_policies.

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

Usage Guidelines3/5

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

Usage is implied by the read-only list semantics and the note that any non-revoked API key may call it, which tells the agent it needs no special scope. There is no explicit when-to-use/when-not-to-use statement or routing to a sibling such as test_policies or plan_policy_changes.

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

plan_policy_changesPlan policy changesA
Read-onlyIdempotent
Inspect

Diff policy creates, updates, and deletes without writing them (POST /v1/policies/apply). dryRun is forced to true and cannot be turned off. Nothing is stored and no audit entry is written. prune only marks missing policies for deletion in the plan. Requires an org-wide LIVE API key; a TEST key or an agent-bound key is refused with 403. This tool does not apply the plan.

ParametersJSON Schema
NameRequiredDescriptionDefault
pruneNoWhen true, the plan marks stored policies whose names are missing from policies for deletion. Nothing is deleted.
policiesYesPolicies to diff against the stored set. Each item needs name, action, and decision. Nothing is written.

Output Schema

ParametersJSON Schema
NameRequiredDescription
dryRunYesAlways true. The plan is not applied.
changesYesCreates, updates, deletes, and unchanged names.

TDQS

A4.7/5.0
Behavior5/5

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

Goes well beyond the annotations: dryRun is forced true and non-negotiable, nothing is stored, no audit entry is written, prune only marks deletions in the plan, and an org-wide LIVE key is required (TEST or agent-bound keys get a 403). This is exactly the operational context an agent needs before calling a policy tool.

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?

Six short sentences, all front-loaded with the highest-value fact first (no writes) and none wasted. The endpoint, side-effect, parameter note, and auth constraint each earn their place.

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 preview tool with an output schema present, the description covers everything left unspecified: safety profile, side effects, parameter caveats, and authentication requirements. An agent has no unanswered question that would cause a wrong call.

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, but the description adds real value by clarifying prune's narrow effect and by stating that dryRun is forced and not a user-controllable input. It does not, however, add anything about the nested policy object beyond what the schema already documents.

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 (diff) and precise resource (policy creates, updates, and deletes), and even names the underlying endpoint POST /v1/policies/apply. The phrase 'without writing them' instantly separates it from a mutation tool and from siblings like test_policies or list_policies.

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

Usage Guidelines4/5

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

Clearly frames the tool as a preview step ('This tool does not apply the plan'), which tells the agent when it is appropriate. It does not name the sibling that performs the actual apply, so the routing is implied rather than explicit; the auth conditions also function as usage preconditions.

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

test_policiesTest policiesA
Read-onlyIdempotent
Inspect

Evaluate up to 200 policy cases without recording an event (POST /v1/policies/test). When policies is omitted, the enabled stored policies are used. When policies is set, those proposed policies are evaluated instead and nothing is written. This skips the PII scan: cases have no content field. pass is null when a case omits expect. One call covers up to 200 cases. Limited to 60 requests per minute per key.

ParametersJSON Schema
NameRequiredDescriptionDefault
casesYesOne to 200 cases. Each case has a name, an input, and an optional expected decision.
policiesNoWhen set, these policies are evaluated instead of the stored ones. Nothing is written.

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultsYesOne result per case.

TDQS

A4.1/5.0
Behavior5/5

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

Annotations already declare readOnly/idempotent/non-destructive, yet the description adds substantive behavior: nothing is written when 'policies' is set, the PII scan is skipped, 'pass' is null when 'expect' is omitted, and a concrete rate limit of 60 requests/minute/key. These are exactly the traits an agent cannot infer from structured fields.

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?

Short sentences with the purpose and endpoint front-loaded and the rate limit sensibly at the end. Mild redundancy: 'up to 200 policy cases' in sentence one is repeated as 'One call covers up to 200 cases' later, and that limit is also in the schema (maxItems 200).

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 rich annotations and an output schema present, the description still covers the pieces an agent needs: two operating modes, the no-write guarantee, the skipped scan, nullable results, and throughput/rate limits. Nothing required to call it correctly 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 coverage is 100%, so the baseline is 3. The description restates the omitted-vs-set semantics of 'policies' that the schema already documents, adding little new meaning beyond what the structured field provides.

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

Purpose4/5

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

States a specific verb+resource ('Evaluate ... policy cases') plus the endpoint and scope ('up to 200'), and the dry-run character ('without recording an event') sets it apart behaviorally from write-oriented siblings. It never names an alternative (check_action, decide_action) to anchor the distinction, so it stops short of a 5.

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

Usage Guidelines4/5

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

Gives clear conditional context: omitting 'policies' uses stored policies, setting it evaluates proposed ones. It also discloses a usable limitation ('skips the PII scan: cases have no content field'). No explicit when-not or sibling routing, so 4 rather than 5.

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.

  1. 7 tool updatesv0.1.5
    • First observedcheck_action
    • First observedcheck_mcp_tool_call
    • First observeddecide_action
    • First observedget_decision
    • First observedlist_policies
    • First observedplan_policy_changes
    • First observedtest_policies

TDQS

A4/5.0

Scored across 7 tools

Disambiguation3/5

Several tools share the same underlying endpoint and near-identical semantics: check_action and test_policies both hit POST /v1/policies/test as dry-runs, and check_mcp_tool_call vs decide_action both record decisions (one keyed to MCP tool names, one to general actions). The descriptions do a good job cross-referencing each other to steer selection, but the boundaries are genuinely blurry in places.

Naming Consistency4/5

Names follow a mostly predictable verb_noun pattern (list_policies, test_policies, check_action, decide_action, get_decision). Minor deviations exist—plan_policy_changes uses a longer noun phrase and plural/singular usage is inconsistent (list_policies vs check_action)—but the convention is readable and consistent overall.

Tool Count5/5

Seven tools is well-scoped for a policy governance and decision-recording server. Each tool maps to a distinct capability (list, test, plan, check, decide, get) without redundancy that would bloat the surface.

Completeness3/5

The read/test/decide/get lifecycle is covered, but there are notable gaps: plan_policy_changes only produces a plan with no corresponding apply tool, and no tool can approve or deny a review (explicitly noted as out of scope). Agents hitting a REVIEW have no resolution path within this server.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    B
    maintenance
    Security co-pilot for AI agents. Scans for vulnerabilities like prompt injection, infinite loops, and token bombing in AI Agents, audits MCP servers, verifies AGENTS.md governance, and generates EU AI Act compliance reports.
    10
    57 npm
    3
    Apache 2.0
  • A
    license
    A
    quality
    C
    maintenance
    Runtime policy enforcement for AI agents. Evaluate every agent action against your organization's policies before execution, with observe and enforce modes.
    1
    1
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enforces deterministic policies on AI agent tool calls, evaluating actions against compliance modules (SOC 2, HIPAA, GDPR, etc.) and returning ALLOW, BLOCK, or CONSTRAIN decisions with an audit trail.
    MIT
  • A
    license
    A
    quality
    F
    maintenance
    Enables agentic coding clients to enforce portable policy guardrails by evaluating proposed shell, file write, git, and network actions and returning allow, deny, or ask decisions.
    2
    MIT