wardcat-mcp
wardcat-mcp is a local, privacy-preserving server that detects and anonymizes PII in text, acting as an on-premise guardrail for AI agents and pipelines.
scan(text, entities?): Detect PII in text and receive a sanitized version along with a PII-free summary of violations (entity types, actions taken, confidence scores). Optionally narrow detection to specific entity types (e.g.,EMAIL,IBAN).redact(text, action, entities?): Detect and anonymize PII using one of four actions:redact— removes the value entirely (e.g.,[EMAIL])mask— keeps a partial hint (e.g.,b***@acme.com)hash— replaces with a stable salted pseudonym (e.g.,[EMAIL:3245e00b…])warn— leaves text untouched but reports what was found
is_sensitive(text): Use an on-premise LLM to holistically determine whether text contains sensitive information — useful as a gate before forwarding text to external services.server_info(): Query the server to discover enabled entity types, the default anonymization action, valid actions, and whether the NER and LLM layers are active — allowing agents to self-configure without trial and error.
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., "@wardcat-mcpscan this: 'My SSN is 123-45-6789'"
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.
wardcat-mcp
An MCP server that exposes wardcat's on-prem PII detection and anonymization as tools any agent can call — Claude Desktop, Cursor, a self-hosted bot, a RAG pipeline. Use it as a guardrail: sanitize inputs before they reach an LLM, or gate them with a semantic "is this sensitive?" check.
Runs locally, stays local. The server runs on your machine over stdio; the text, the models, and all detection stay on-prem — nothing is sent anywhere. Publishing this package ships code you run yourself, not a hosted service.
Tools
Tool | Description |
| Detect PII and return the sanitized text plus a PII-free summary — entity types, actions, confidence. The summary never carries raw values; |
| Like |
| Holistic LLM yes/no on whether the text contains sensitive information. Requires the LLM layer ( |
| Report the enabled entity types, the default action, and whether the NER / LLM layers are active — so an agent can discover capabilities without trial and error. |
All tools return structured output (a typed schema, not a JSON string) and are annotated read-only.
Threat model — what this protects. wardcat-mcp guards what leaves the agent: it sanitizes text before it is logged, stored, or forwarded to a downstream API. It does not hide anything from the host LLM that is orchestrating the tool call — by the time a model invokes
scan, it has already read the raw text (and it may be retained in that provider's context or logs). To filter text before it reaches any LLM, call the wardcat library in-process instead.
Related MCP server: MCP Presidio
Install & run
Not published to PyPI — run it straight from the repository (its wardcat dependency does come from PyPI, so this needs no other source):
# Run directly from GitHub, no install:
uvx --from git+https://github.com/oguzhantopcu0/wardcat-mcp.git wardcat-mcp
# from a local clone:
uv run wardcat-mcp
# with the SpaCy NER layer (PERSON/ORG/ADDRESS), from a clone:
uv run --extra ner wardcat-mcpDocker
The server talks over stdio, so run the container interactively (-i):
docker build -t wardcat-mcp .
docker run -i --rm -e WARDCAT_SALT=your-secret wardcat-mcp
# with the SpaCy NER layer:
docker build --build-arg EXTRAS='[ner]' -t wardcat-mcp:ner .In an MCP client, point command at docker with args ["run", "-i", "--rm", "-e", "WARDCAT_SALT=your-secret", "wardcat-mcp"].
Add it to an MCP client
Claude Desktop (claude_desktop_config.json), Cursor, Cline, Zed, etc.:
{
"mcpServers": {
"wardcat": {
"command": "uvx",
"args": ["--from", "git+https://github.com/oguzhantopcu0/wardcat-mcp.git", "wardcat-mcp"],
"env": {
"WARDCAT_SALT": "your-secret-salt",
"WARDCAT_ACTION": "redact",
"WARDCAT_LLM_MODEL": "llama3.2:3b"
}
}
}
}Configuration (environment variables)
Var | Default | Meaning |
|
| Hashing salt (required for the |
| broad structural + name set | Comma-separated entity types to enable. |
|
|
|
| — | Enable SpaCy NER with this model (needs the |
| — | Enable the on-prem LLM layer via Ollama (e.g. |
|
| Ollama endpoint. |
Development
uv sync --dev
uv run pytest # deterministic, regex-only — no models or network needed
uv run ruff check .
uv run mypy srcDisclaimer
wardcat is a best-effort PII detector — it does not catch everything and is not legal advice or a substitute for compliance review (e.g. GDPR/KVKK). Validate it against your own data. Provided "as is" (MIT).
License
MIT — see LICENSE.
Available Tools
4 toolsis_sensitiveARead-only
Return True if text contains sensitive information (holistic LLM gate).
Requires the on-prem LLM layer: set WARDCAT_LLM_MODEL (e.g. llama3.2:3b).
Use it as a guardrail before forwarding text to an external service.
| Name | Required | Description | Default |
|---|---|---|---|
| text | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already indicate readOnlyHint and openWorldHint. The description adds valuable behavioral context: the tool uses an LLM (requires WARDCAT_LLM_MODEL), returns a boolean, and serves as a holistic gate. 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.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three concise sentences with front-loaded core function. No wasted words. Every sentence earns its place: purpose, prerequisite, usage advice.
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 tool is simple with one parameter and an output schema (implied boolean). The description covers the core purpose, prerequisite, and usage context. It could be improved by contrasting with sibling tools like 'scan' to avoid confusion, but overall sufficient.
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 only parameter 'text' is a string with 0% schema coverage. The description adds purpose (checks for sensitive info) but no additional constraints or format details. Score baseline 3 for a simple parameter.
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 returns True if text contains sensitive information, acting as a holistic LLM gate. However, it does not explicitly differentiate from siblings like 'scan' or 'redact', which could serve similar 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 provides explicit when-to-use: as a guardrail before forwarding to an external service. It also mentions a prerequisite (requires on-prem LLM layer). However, it lacks guidance on when not to use or alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
redactARead-only
Detect PII in text and anonymize every match with action.
Unlike scan, you pick the action per call: redact drops the value
([EMAIL]), mask keeps a hint (b***@acme.com, last-4 of a card), hash
yields a stable salted pseudonym ([EMAIL:3245e00b…]), and warn leaves the
text untouched but still reports what was found. action defaults to the
server's WARDCAT_ACTION.
The violations summary never contains raw values; sanitized_text still
holds the original text under action="warn" (which reports only).
Pass entities to anonymize only a subset of the server's enabled types
(e.g. ["EMAIL", "IBAN"]), leaving other detected PII untouched; omit it to
anonymize everything. Requesting a type the server didn't enable is an error.
| Name | Required | Description | Default |
|---|---|---|---|
| text | Yes | ||
| action | No | ||
| entities | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| action | Yes | |
| is_clean | Yes | |
| warnings | Yes | |
| violations | Yes | |
| sanitized_text | Yes | |
| violation_count | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnlyHint annotation, the description discloses behavior of each action (redact, mask, hash, warn), states that violations summary never contains raw values, and notes that under 'warn' the sanitized_text holds original text. This adds significant context.
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 and well-structured: opening sentence states purpose, then a paragraph clarifying differences from 'scan' and action details, followed by entities usage. Every sentence adds value without redundancy.
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 tool has three parameters (one required), an output schema exists, and the description covers key behavioral aspects and parameter usage, it is fairly complete. Minor gaps: no mention of output fields or error handling for disabled entity types, but overall sufficient.
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?
With 0% schema description coverage, the description fully compensates by detailing the 'action' parameter (including four options and default), the 'entities' parameter (subset of types), and implying the 'text' parameter's role. This adds comprehensive meaning beyond the schema.
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 detects PII in text and anonymizes matches. It distinguishes itself from sibling 'scan' by noting that with 'redact' you pick the action per call, and it lists specific actions. This provides a specific verb-resource pair with clear differentiation.
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 contrasts with 'scan' to guide usage, and explains when to use the 'entities' parameter for subset selection. However, it does not provide explicit when-not-to-use conditions beyond the scan comparison.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
scanARead-only
Detect PII in text and return the sanitized text plus a PII-free summary.
The violations summary never contains raw sensitive values — only entity
types, the action applied, and confidence — so it is always safe to log.
sanitized_text echoes the original text only when the server's action is
warn (which reports without altering); for redact/mask/hash the
sensitive values are removed.
Pass entities to narrow this call to a subset of the server's enabled
types (e.g. ["EMAIL", "IBAN"]); omit it to apply every enabled filter.
Requesting a type the server didn't enable is an error.
| Name | Required | Description | Default |
|---|---|---|---|
| text | Yes | ||
| entities | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| is_clean | Yes | |
| warnings | Yes | |
| violations | Yes | |
| sanitized_text | Yes | |
| violation_count | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Describes the output structure in detail: 'violations' summary never contains raw values, 'sanitized_text' behavior varies by action (warn vs redact/mask/hash). No contradiction with readOnlyHint annotation since the tool appears to be a pure computation returning results without side effects.
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 three paragraphs and somewhat verbose. Some sentences (e.g., about server actions) could be condensed. It contains necessary detail but would benefit from tighter phrasing.
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 presence of an output schema and annotations, the description covers all essential aspects: purpose, parameters, output details, and safe-to-log summary. It is sufficiently complete for the agent to use the tool correctly.
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 description coverage is 0%, but the description fully explains both parameters: 'text' is the input, and 'entities' is an optional array to specify PII types, with clear behavior when omitted vs when a disabled type is requested. This adds essential meaning beyond the schema.
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?
Description clearly states it detects PII in 'text' and returns sanitized text plus a PII-free summary. Verb and resource are specific, and it distinguishes from sibling tools like 'redact' (which likely just redacts without summary) and 'is_sensitive' (which probably returns a boolean).
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?
Provides clear guidance on when to use the 'entities' parameter and that omitting it applies all enabled filters. Also warns that requesting an unenabled type is an error. However, it does not explicitly contrast with sibling tools to help decide between scan, redact, or is_sensitive.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
server_infoARead-only
Report what this server detects and how it anonymizes by default.
Lets an agent discover the enabled entity types, the default action, and whether the NER / LLM layers are active — without probing by trial and error.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| llm_enabled | Yes | |
| ner_enabled | Yes | |
| valid_actions | Yes | |
| default_action | Yes | |
| enabled_entities | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, and the description adds detail on what is reported (entity types, default action, NER/LLM layers). No contradiction; description enhances transparency.
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?
Two sentences with no wasted words. First sentence states purpose, second adds benefit. Highly concise and front-loaded.
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?
With no parameters and an output schema, the description sufficiently explains the tool's purpose and output. No missing context for a simple info tool.
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?
No parameters exist, so baseline 4 applies. Schema coverage is 100%, so the description does not need to compensate for missing param info.
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?
Description clearly states it reports server detection capabilities and anonymization defaults, listing specific items like entity types and NER/LLM status. The verb 'report' and resource 'server info' are specific, and the tool distinguishes itself from siblings (is_sensitive, redact, scan) which are data processing tools.
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?
States the tool lets an agent discover capabilities without trial and error, implying it should be used before other tools. While not explicitly naming alternatives, the context with sibling tools makes the usage clear.
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.
4 tool updates
v0.1.0- First observed
is_sensitive - First observed
redact - First observed
scan - First observed
server_info
TDQS
Scored across 4 tools
Each tool has a clearly distinct purpose: is_sensitive is a boolean guard, redact applies a specific action, scan returns sanitized text, and server_info reports configuration. No overlap in functionality.
All tool names are in snake_case and descriptive, but the pattern varies: is_sensitive uses 'is_', redact and scan are single verbs, and server_info is a noun pair. While readable and consistent in style, it's not a uniform verb_noun pattern.
Four tools is well-scoped for a PII detection and redaction server. Each tool serves a core function without unnecessary bloat or gaps, fitting the server's purpose perfectly.
The tool set covers essential operations: boolean check (is_sensitive), configurable redaction (redact), full scan with summary (scan), and configuration discovery (server_info). Minor gaps like batch processing could exist, but the core workflow is complete.
Maintenance
Related MCP Connectors
MCP server for detecting and redacting PII (Personally Identifiable Information) in PDF documents.
Security & DLP proxy for MCP: tool-poisoning scans, PII redaction on tool args/results. Beta.
AI governance MCP server for EU AI Act compliance and jurisdiction verification
Zero-secret MCP gateway for AI agents: risk-scored, audited calls with human-in-the-loop approval.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceAn MCP proxy that pseudo-anonymizes PII before data reaches external AI providers like Claude, ChatGPT, or Gemini.18MIT
- AlicenseAqualityDmaintenanceAn MCP server that enables LLMs to detect and anonymize over 25 types of Personally Identifiable Information (PII) using Microsoft Presidio. It supports various redaction strategies and can process both plain text and structured data to help ensure data privacy.10MIT
- FlicenseNot gradedqualityDmaintenanceMCP server for automatic detection and redaction of PII in text, with anonymization and deanonymization capabilities, all local processing.1-
- AlicenseNot gradedqualityDmaintenanceA local, containerized MCP server that uses a local LLM to sanitize documents by removing or transforming PII before content is sent to public LLM services.MIT