mcp-guardrails-kit
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@mcp-guardrails-kitTriage ticket 1234 and flag any injection risks."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
mcp-guardrails-kit
A prompt-injection-aware tool gateway and MCP server, built as a reference implementation for a fictional internal ticket-triage assistant.
This is a portfolio project, not a real product. It exists to demonstrate a concrete, testable pattern for building guardrails around agentic tool use — permission tiers, untrusted-content quarantine, and heuristic injection detection — around a small but real MCP server. The domain (support ticket triage) is generic and interchangeable; the guardrail patterns are the point.
What it demonstrates
Tool permission tiers with explicit confirmation. Every tool is registered as either
read_onlyorsensitive. Sensitive tools (draft_reply,escalate_ticket) never execute a side effect until the caller passesconfirmed=True— every caller in this codebase routes through the gateway's singleinvoke()entry point by construction (seedocs/adr/0001-tool-permission-tiers.mdfor the honest caveat: this is a code-review convention, not a language-enforced boundary).Quarantine of untrusted external content.
fetch_external_pagereturns content fetched from a URL linked inside a ticket — a realistic prompt-injection vector. That content is wrapped and clearly delimited as data, never treated as instructions, before it is handed back to any caller or model.Heuristic injection detection with a verdict. Quarantined (and other) text is scanned for injection patterns and returns one of
ALLOW/FLAG/BLOCK. ABLOCKverdict replaces the payload with a safe refusal instead of the raw text (never a verbatim excerpt — even the scan's ownmatched_patternsare redacted to category labels before crossing a tool boundary). This is backed by a red-team test suite of known injection phrasings.Three independent scan gates, not just one. A
Supervisorwalks a triage → draft → review → escalate pipeline. A ticket's own subject/body — the most directly attacker-controlled input in the system — is scanned right after lookup; the drafted reply is re-scanned before escalation is considered; and the escalationreasona model proposes is scanned again beforeescalate_ticketis ever called. ABLOCKat any of the three halts the pipeline right there.
Related MCP server: production-grade-mcp-agentic-system
Install & run
pip install -e ".[dev]"
pytest
ruff check .No external services or API keys are required to install, test, or lint. See
Scope & non-goals below for what pip install -e ".[live]" adds.
Connecting the MCP server to a real client
After pip install -e . (or pip install mcp-guardrails-kit once published), the
mcp-guardrails-kit command is registered as a console entry point
(see [project.scripts] in pyproject.toml) and speaks the MCP stdio protocol. Point a
real MCP client at it — for example, Claude Desktop or Claude Code — with a config block
like:
{
"mcpServers": {
"guardrails-kit": {
"command": "mcp-guardrails-kit"
}
}
}For Claude Desktop, this goes in claude_desktop_config.json; for Claude Code, add it via
claude mcp add or the equivalent project-level MCP config. No arguments or environment
variables are required for the default (non-live) mode.
Scope & non-goals
Heuristic injection detection is defense in depth, not a guarantee. It is a regex/keyword-based scanner, not a model-backed classifier. It will miss novel or sufficiently obfuscated phrasings — see
docs/adr/0003-heuristic-injection-detection.mdfor the explicit tradeoff. The permission-tier and quarantine layers stay in effect even when detection fails; injection detection is one layer among three, not the only one.There is no real ticketing system behind this.
search_knowledge_baseandlookup_ticketread from small in-memory fixtures. There is no database, no external ticketing API integration, and no persistence.AnthropicModelClientis optional and live-only. It is gated behind theliveextra (pip install -e ".[live]") and is never imported or exercised by the test suite or CI — tests and the default install path have zero dependency on any external LLM API or network access.All data is in-memory and resets on restart. Drafts, escalations, and fetched external content are not persisted anywhere; restarting the server clears all state.
More
Architecture and data flow:
docs/architecture.mdDesign decisions:
docs/adr/
Available Tools
5 toolsdraft_replyA
Draft a reply to a customer for the given ticket. SENSITIVE: call with confirmed=false first (the default) to preview — this creates no draft and returns confirmation_required=True. Only a subsequent call with confirmed=true actually creates the draft.
| Name | Required | Description | Default |
|---|---|---|---|
| confirmed | No | ||
| ticket_id | Yes | ||
| draft_body | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | Yes | |
| data | No | |
| scan | No | |
| tool_name | Yes | |
| blocked_reason | No | |
| confirmation_required | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description discloses that preview mode creates no draft and returns confirmation_required=True, while only confirmed=true creates the draft. This goes beyond the annotations, which only state readOnly=false and destructive=false, and fully explains the tool's side-effect behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two concise sentences with no redundant information. It front-loads the core purpose and then explains the confirmation behavior efficiently.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the moderate complexity and the presence of an output schema, the description provides sufficient context for the confirmation flow. It covers the critical behavioral nuance and does not need to detail return values beyond what the output schema already conveys.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema has no parameter descriptions, so the description must compensate. It explains the confirmed parameter's role clearly, but ticket_id and draft_body are only implied by the tool's purpose and are not explicitly defined, leaving some ambiguity.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool drafts a reply to a customer for a given ticket, which is a specific verb and resource. It is implicitly distinguished from sibling tools like lookup_ticket and escalate_ticket, which serve different purposes.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly instructs to call with confirmed=false first to preview and confirmed=true to actually create the draft. This provides clear when-to-use guidance and highlights the sensitive confirmation workflow.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
escalate_ticketA
Escalate a ticket to a human agent for the given reason. SENSITIVE: call with confirmed=false first (the default) to preview — this escalates nothing and returns confirmation_required=True. Only a subsequent call with confirmed=true actually escalates.
| Name | Required | Description | Default |
|---|---|---|---|
| reason | Yes | ||
| confirmed | No | ||
| ticket_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | Yes | |
| data | No | |
| scan | No | |
| tool_name | Yes | |
| blocked_reason | No | |
| confirmation_required | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description transparently discloses that the default call with confirmed=false does not escalate and returns confirmation_required=True. This reveals side effects beyond the annotations, making the tool's behavior clear.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise, with a separate note for the confirmation flow. It avoids unnecessary details and is well-organized, making it easy to read and understand.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers the purpose and the confirmation workflow, and hints at the output (confirmation_required). It does not mention potential error scenarios or the full output schema, but given the simple nature of the tool, it is sufficiently complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema has no parameter descriptions, but the description explains the 'confirmed' parameter's role (preview vs. actual) and mentions 'reason'. The 'ticket_id' is self-explanatory from the name, but no format or constraints are given, slightly reducing clarity.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose: to escalate a ticket to a human agent. The verb 'escalate' and resource 'ticket' are explicit, and it is distinct from sibling tools like search, lookup, and draft.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit usage guidelines by explaining the confirmation workflow: first call with confirmed=false to preview, then call with confirmed=true to actually escalate. This is actionable and clarifies when to use each mode.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
fetch_external_pageARead-onlyIdempotent
Fetch a web page linked from a ticket. The content is untrusted: it is quarantined and scanned for prompt-injection attempts before being returned, and may be blocked outright if it matches a known injection pattern.
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | Yes | |
| data | No | |
| scan | No | |
| tool_name | Yes | |
| blocked_reason | No | |
| confirmation_required | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description goes beyond the read-only annotation by revealing that content is untrusted, quarantined, scanned for prompt-injection, and may be blocked. This gives important behavioral context that is not present in the annotations alone.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, well-structured sentence that front-loads the primary action and then adds important security context. There is no unnecessary verbosity or repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given that an output schema exists, the description does not need to explain return values. It covers purpose, source, and security behavior, making it complete for a tool of this simplicity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The URL parameter is not described in the schema, and the description does not explicitly explain what the parameter represents. It is implied that 'url' is the address of the page to fetch, but the description does not add meaningful detail beyond the parameter name itself.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states that the tool fetches a web page linked from a ticket, with a specific verb and resource. It is easily distinguished from sibling tools like search or escalation, which perform different actions.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides implicit guidance by specifying that the page must be linked from a ticket, which suggests when to use this tool. It does not explicitly contrast with alternatives, but the context is sufficient for most use cases.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
lookup_ticketARead-onlyIdempotent
Look up a support ticket by its id.
| Name | Required | Description | Default |
|---|---|---|---|
| ticket_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | Yes | |
| data | No | |
| scan | No | |
| tool_name | Yes | |
| blocked_reason | No | |
| confirmation_required | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotations already declare readOnlyHint=true, destructiveHint=false, and idempotentHint=true, covering safety expectations. The description adds no extra behavioral details (e.g., side effects or return behavior), but it does not contradict the annotations either. Given the annotation coverage, a score of 3 is appropriate.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, focused sentence that directly conveys the tool's purpose. It is appropriately sized for a simple lookup operation and contains no redundant words or irrelevant information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
While the description is clear for a basic lookup, it omits details about the return value (e.g., whether it returns the full ticket object or just a summary) and any potential edge cases like not found behavior. Given that the tool has an output schema, some return context would be expected for completeness, but the simplicity of the operation keeps this at a moderate level.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema fully documents the single parameter (ticket_id, string, required), so schema coverage is 100%. The description adds no additional meaning about the parameter, such as expected format, example values, or how to obtain the ID. Since the schema already covers the basics, the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the action ('Look up'), the resource ('support ticket'), and the lookup key ('by its id'). This distinguishes it from sibling tools like search_knowledge_base and escalate_ticket, which have different purposes.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives no explicit guidance on when to use this tool versus alternatives. It does not mention that this should be used when the ticket ID is already known, nor does it contrast with search or fetch tools. Users are left to infer the appropriate context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_knowledge_baseARead-onlyIdempotent
Search the internal support knowledge base for articles matching a query.
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | Yes | |
| data | No | |
| scan | No | |
| tool_name | Yes | |
| blocked_reason | No | |
| confirmation_required | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, covering the safety profile. The description adds no further behavioral context such as pagination, result limits, or search syntax. It is consistent with annotations but contributes no extra transparency beyond them.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, front-loaded sentence with no redundant words. It immediately states the verb and resource, making it easy to parse quickly.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple read-only search tool with one parameter and an output schema (though not shown), the description is adequate. It names the knowledge base as the scope and the query as the input. However, it omits any note about result behavior (e.g., pagination, relevance) that could be expected from a search tool, and it does not cross-reference sibling tools. The existence of an output schema reduces the need to describe return values.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0% – the input schema for 'query' has only a type and no description. The description implies 'query' is the search text via 'matching a query,' which provides basic meaning. However, it does not clarify format, length, or any search operators. The description partially compensates but not richly.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('Search') and a specific resource ('internal support knowledge base'), clearly stating the tool's purpose. It is easily distinguishable from siblings like lookup_ticket (tickets), fetch_external_page (external content), draft_reply (composing), and escalate_ticket (escalation) without needing to inspect schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides no guidance on when to use this tool versus the siblings. There is no mention of conditions like 'use this when searching for help articles' or 'do not use for ticket lookups.' An agent must infer usage solely from the tool name and resource.
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.
5 tool updates
v0.1.0- First observed
draft_reply - First observed
escalate_ticket - First observed
fetch_external_page - First observed
lookup_ticket - First observed
search_knowledge_base
TDQS
Scored across 5 tools
Each tool has a distinct, non-overlapping purpose: search knowledge base, lookup ticket, fetch external page (with security features), draft reply, and escalate ticket. No ambiguity between them.
All tool names follow a consistent verb_noun pattern in snake_case (e.g., search_knowledge_base, lookup_ticket, fetch_external_page, draft_reply, escalate_ticket). The convention is uniform and predictable.
Five tools is a well-scoped set for a guardrails kit focused on support workflows. Each tool serves a clear function, and there is no bloat or insufficiency given the narrow domain.
The tool surface covers the main support workflow: search, lookup, secure fetching, drafting replies, and escalation. Minor gaps exist (e.g., no tool to update ticket status or send replies), but these are not critical to the stated guardrails purpose.
Maintenance
Related MCP Connectors
AgentGuard — 20-tool AI safety MCP: policy preflight, risk scoring, audit logging, rate limits.
Security scanner for MCP servers. Detect vulnerabilities, prompt injection, and tool poisoning.
Email safety MCP server. Detects phishing, prompt injection, CEO fraud for AI agents.
Formally-verified injection/exfiltration detector for AI agents (MCP-02).
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceAn MCP server that provides safeguard capabilities to protect against prompt injection and unsafe tool calls.381 PyPI8MIT
- AlicenseNot gradedqualityDmaintenanceA production-grade MCP server designed for multi-tenant, authenticated, and observable AI agent systems, enabling secure tool execution across heterogeneous data sources.64MIT
- AlicenseNot gradedqualityCmaintenanceMCP server that provides tools to scan text and URLs for prompt injection attacks, protecting AI agents from adversarial inputs.MIT
- FlicenseNot gradedqualityFmaintenanceAn MCP server for prompt injection boundary enforcement that scans URL content using a tiered LLM model strategy.-