diff --git a/docs/mcp-scan/assets/proxy.svg b/docs/mcp-scan/assets/proxy.svg new file mode 100644 index 0000000..c4a6e8e --- /dev/null +++ b/docs/mcp-scan/assets/proxy.svg @@ -0,0 +1,233 @@ + + + + Group 55 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/mcp-scan/assets/scan.svg b/docs/mcp-scan/assets/scan.svg new file mode 100644 index 0000000..da2080e --- /dev/null +++ b/docs/mcp-scan/assets/scan.svg @@ -0,0 +1,212 @@ + + + + Group 54 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/mcp-scan/guardrails.md b/docs/mcp-scan/guardrails.md new file mode 100644 index 0000000..f90dc41 --- /dev/null +++ b/docs/mcp-scan/guardrails.md @@ -0,0 +1,269 @@ +--- +title: Guardrails in MCP-Scan +description: Use MCP-scan to ensure your MCP servers are safe to use. +icon: bootstrap/lock +--- + +# Guardrails in `mcp-scan` + +
+Safeguard and restrict your MCP tool calls and responses. +
+ +The `mcp-scan proxy` command supports dynamic guardrailing for MCP servers, letting you enforce safety rules during tool use. It comes with a set of default guardrails and allows you to define custom behavior through a configuration file. + +This guide covers how to structure guardrail configs, write custom rules, and apply enforcement at the client, server, and tool levels. + +proxying-overview-diagram + +!!! note + By default, the configuration file is located at `~/.mcp-scan/guardrails-config.yml`. + +## File structure + +The configuration file defines guardrailing behavior hierarchically, scoped by **client**, **server**, and **tool**. Below is a structured overview of the YAML format: + +```yaml +: + : + guardrails: + : + ... + + custom_guardrails: + - name: + id: + action: + content: | + + ... + + tools: + : + : + ... + enabled: + ... +... +``` + +Each configuration block defines a set of **default**, **custom**, and **tool-level** guardrails for a specific ` / ` combination (e.g., a client like Cursor and a server like a Git MCP instance). + +The ellipses (`...`) in the schema indicate that multiple entries can be added at each level: + +- Multiple servers under a single client. + +- Multiple guardrails under each guardrails section. + +- Multiple tools under a server. + +This structure supports flexible, fine-grained control across different environments and toolchains. The sections of the file are described below. + + +## Default guardrails + +Default guardrails are pre-configured and run by default with the `log` action. Alternatively, their behavior can be overridden by specifying `: ` as shown above. The following default guardrails exist and can be configured: + +| Name | Requirements | Description | +|-------------|--------|----------------------------------------| +| `links` | `None` | Detects links. | +| `secrets` | `None` | Detects secrets, such as tokens or api keys. | +| `pii` | `presidio`, `transformers` | Detects personally identifiable information, such as names, emails, or credit card numbers. | +| `moderated` | `ENV: OPENAI_API_KEY` | Detects content that should be moderated, such as hate speech or explicit content. | + + +!!! note + Some default guardrails require optional extra packages to run and are disabled if not installed. You can install them with the argument `--install-extras [list of extras]` to install a specific set of extras or `--install-extras all` to install all extras. + + +**Example:** Overriding a default guardrail. +```yaml +cursor: + email-mcp-server: + guardrails: + pii: block + secrets: paused +``` + +## Custom guardrails +Custom guardrails allow you to define rules tailored to specific workflows, data patterns, or business logic. These guardrails offer flexible semantics and can detect complex or domain-specific behaviors that aren't covered by the built-in defaults. + +To get started writing custom rules, refer to the [rule writing reference](./rules.md) to get started quickly with writing guardrails, or explore the rest of this documentation to learn about the concepts in depth, perhaps [starting with this introduction](./index.md). + +### Schema +A custom guardrail is defined using the following fields: + +| Name | Type | Description | +|-------------|-------------|----------------------------------------| +| `name` | `string` | A name for the guardrail. | +| `id` | `string` | A unique identifier for the guardrail. | +| `action` | `Guardrail Action` | The `action` to take when this guardrail is triggered. See below. | +| `content` | `string` | A multiline string defining the semantics of this guardrailing rule. Please refer to the rest of this documentation to see how to write guardrails. | + +**Example:** Defining a custom guardrail. + +Below is a `yaml` fragment that shows how a custom guardrail can be defined to ensure emails are only sent to trusted recipients. +```yaml +... +custom_guardrails: + - name: "Trusted Recipient Email" + id: "trusted_email_check" + action: block + content: | + raise "Untrusted email recipient" if: + (call: ToolCall) + call is tool:send_email + not match(".*@company.com", call.function.arguments.recipient) +... +``` + +## Tool-specific guardrails +Tool-specific guardrails allow you to override or refine guardrailing behavior for individual tools within a given server. This is useful when certain tools require stricter enforcement, relaxed rules, or even complete disabling. + + +### Schema +The following fields are available for each `tool`: + +| Name | Type | Description | +|-------------|-------------|----------------------------------------| +| `` | `Guardrail Action` | Overrides the behavior of `` for this tool specifically. | +| `enabled` | `boolean` | Disables tool when set to False. If this field is not provided, it defaults to True. | + + +!!! note + While the tools section does not allow for defining custom guardrails, you can always use the `call is tool:` syntax to select a specific tool, as shown in the example from the previous section. + +**Example:** Disabling and overriding behavior for tools. + +The `yaml` fragment below demonstrates how to disable the `send_message` tool and override the behavior for the `secrets` default guardrail to be `block` specifically for the `read_messages` tool. +```yaml +... +tools: + send_message: + enabled: false + + read_messages: + secrets: block +... +``` + +## Guardrail actions +Guardrail actions define how the system responds when a guardrail is triggered. These actions let you tailor enforcement severity across different contexts - whether to silently monitor behavior, stop execution entirely, or pause enforcement temporarily. + +The following actions are available: + +| Name | Description | +|-------------|----------------------------------------| +| `block` | This will block the client outright, preventing it from executing what triggered the guardrail. | +| `log` | This lets the client execute what triggered the guardrail, but logs it in the console, so you can monitor the violation patterns without blocking the client's workflow. | +| `paused` | This pauses the enforcement of the guardrail. | + +These actions are available for both default and custom guardrails. + + +## Priority of rules +When multiple guardrail rules are defined for the same context (e.g., a default guardrail set at both the server and tool level), the system follows a strict priority hierarchy to determine which rule takes effect. + +This ensures predictable behavior and allows for precise control, especially when configuring environments with overlapping scopes. + + +!!! note + **Custom guardrails are not subject to this priority system**. Once defined, they are always active and enforced with their specified action, regardless of other configurations. + +### Rule Priority (from highest to lowest) +1. **Tool-specific guardrails** + Guardrails defined for a specific tool override all other configurations. +2. **Client/server-specific guardrails** + Guardrails set at the server level for a particular client are used unless overridden by a tool-specific rule. +3. **Implicit default guardrails** + If no explicit rule is defined, the default guardrails apply automatically with the `log` action. + +**Example:** A simple config file with overrides. + +To see how this hierarchy of precedence works, consider the following example configuration: + +```yaml +client: + server: + guardrails: + pii: block + secrets: paused + + tools: + tool: + secrets: block +``` + +The resulting behavior of this configuration is: + +- `secrets` is set to block for the `tool`, because tool-specific guardrails have the highest priority. + +- For all other tools on `server`, secrets is set to `paused`, as defined at the client/server level. + +- For any other client/server combinations not defined in the config, `secrets` will use the implicit default and be set to `log`. + +- `pii` is set to block across all tools under `server` due to the client/server setting. For all other combinations, it falls back to the implicit default (`log`). + +This precedence ensures that you can enforce strict guardrails where needed, while still benefiting from broad default coverage elsewhere. + + +## Example file +Below is a complete example of a guardrail configuration file. +It demonstrates how to define default and custom guardrails for specific clients and servers, apply tool-level overrides, and selectively enable or disable tools + +```yaml +cursor: + email-mcp-server: + + # Customize the guardrailing for this specific server + guardrails: + pii: block + moderated: paused + + # Define multiple custom guardrails + custom_guardrails: + - name: "Trusted Recipient Email" + id: "untrustsed_email_gr_1" + action: block + + # Guardrail to ensure that we know all recipients + content: | + raise "Untrusted email recipient" if: + (call: ToolCall) + call is tool:send_email + not match(".*@company.com", call.function.arguments.recipient) + + + # Guardrail to ensure an email is not sent after + # a prompt injection is detected in the inbox + - name: "PII Email" + id: "untrustsed_email_gr_2" + action: log + content: | + from invariant.detectors import prompt_injection + + raise "Suspicious email before send" if: + (inbox: ToolOutput) -> (call: ToolCall) + inbox is tool:get_inbox + call is tool:send_email + prompt_injection(inbox.content) + + # Specify the behavior of individual tools + tools: + send_message: + enabled: false + + read_messages: + secrets: block + + weather: + guardrails: + moderated: paused + +# Separate configurations on a per client/server basis +claude: + git-mcp-server: + tools: + commit-tool: + links: paused +``` diff --git a/docs/mcp-scan/index.md b/docs/mcp-scan/index.md new file mode 100644 index 0000000..9fb287c --- /dev/null +++ b/docs/mcp-scan/index.md @@ -0,0 +1,116 @@ +--- +title: Securing MCP with Invariant +description: Use MCP-scan to safeguard your MCP integrations. +icon: bootstrap/shield-check +--- + +# MCP-Scan: A security scanner for MCP + +
+Use MCP-scan to safeguard your MCP integrations. +
+ +[MCP-scan](https://github.com/invariantlabs-ai/mcp-scan) is a security scanning tool that uses Invariant's security stack to ensure the MCP integrations you are using in MCP clients, such as Cursor, Claude, and Windsurf are safe. + +mcp-scan-overview-diagram + +### MCP-Scan Features + +- Scanning of Claude, Cursor, Windsurf, and other file-based MCP client configurations +- Scanning for prompt injection attacks in tool descriptions and [tool poisoning attacks](https://invariantlabs.ai/blog/mcp-security-notification-tool-poisoning-attacks) using [Guardrails](https://github.com/invariantlabs-ai/invariant?tab=readme-ov-file#analyzer) +- Live runtime monitoring of MCP traffic using `mcp-scan proxy` +- _MCP guardrailing_ of tool calls and responses, including PII detection, secrets detection, tool restrictions, and [custom guardrailing policies](./guardrails) +- Detection of cross-origin escalation attacks ([tool shadowing](https://invariantlabs.ai/blog/mcp-security-notification-tool-poisoning-attacks)) +- _Tool Pinning_ to detect and prevent [MCP rug pull attacks](https://invariantlabs.ai/blog/mcp-security-notification-tool-poisoning-attacks), i.e. detects changes to MCP tools via hashing + +## Quick Start +To run a simple system-level scan with MCP-Scan, use the following command: + +```bash +uvx mcp-scan@latest +``` + +or + +``` +npx mcp-scan@latest +``` + +To learn more about the scan, see the [chapter on scanning](./scanning.md). + +## Why MCP-Scan? +As Invariant's [security research on MCP](https://invariantlabs.ai/blog/mcp-security-notification-tool-poisoning-attacks) uncovered ([Tool Poisoning Attacks](https://invariantlabs.ai/blog/mcp-security-notification-tool-poisoning-attacks), [WhatsApp MCP Exploits](https://invariantlabs.ai/blog/whatsapp-mcp-exploited)), MCP implementations across various platforms—such as Cursor, Claude Desktop, Zapier, and others—are susceptible to dangerous attacks. These vulnerabilities include prompt injections, hidden malicious tool instructions (tool poisoning), and cross-origin escalations through tool shadowing. + +Recognizing these serious security threats, we developed **MCP-Scan** to help users quickly identify vulnerabilities within their MCP installations, ensuring safer and more secure agent interactions. + +## Using MCP-Scan + +MCP-scan offers two primary modes of operations, allowing you to identify security vulnerabilities in your MCP integrations and continuously monitor your MCP traffic. + + + +### Passive Scanning with **`mcp-scan scan`** + +Using `mcp-scan scan`, you can scan your configured MCP servers for malicious tool descriptions and behavior, in order to prevent attacks from untrusted MCP servers. `mcp-scan scan` is a static check that only runs when you invoke it, and does not run in the background. + +
+ +scanning-overview-diagram + +
+ +Learn more about the scanning mode in the [MCP Server Scanning](./scanning.md) chapter. + + +### Active Proxying with **`mcp-scan proxy`** + +Using `mcp-scan proxy`, you can monitor, log, and safeguard all MCP traffic on your machine. This allows you to inspect the runtime behavior of agents and tools, and prevent attacks from e.g., untrusted sources (like websites or emails) that may try to exploit your agents. `mcp-scan proxy` is a dynamic security layer that runs in the background, and continuously monitors your MCP traffic. + +
+ +proxying-overview-diagram + +
+ +Learn more about the proxying mode in the [MCP Proxying with mcp-scan](./proxying.md) chapter. + + +## Including MCP-scan results in your own project / registry + +If you want to include MCP-scan results in your own project or registry, please reach out to the team via `mcpscan@invariantlabs.ai`, and we can help you with that. +For automated scanning, we recommend using the `--json` flag and parsing the output. + +## Further Reading +- [Introducing MCP-Scan](https://invariantlabs.ai/blog/introducing-mcp-scan) +- [MCP Security Notification Tool Poisoning Attacks](https://invariantlabs.ai/blog/mcp-security-notification-tool-poisoning-attacks) +- [WhatsApp MCP Exploited](https://invariantlabs.ai/blog/whatsapp-mcp-exploited) +- [MCP Prompt Injection](https://simonwillison.net/2025/Apr/9/mcp-prompt-injection/) + + +## Next Steps + +If you are interested in learning more about securing MCP and agents more generally, consider reading one of the following chapters next. + + diff --git a/docs/mcp-scan/proxying.md b/docs/mcp-scan/proxying.md new file mode 100644 index 0000000..c0da128 --- /dev/null +++ b/docs/mcp-scan/proxying.md @@ -0,0 +1,87 @@ +--- +title: Scanning Your MCP Servers with MCP-Scan +description: Use MCP-scan to ensure your MCP servers are safe to use. +icon: bootstrap/hdd-network +--- + +# Proxying with `mcp-scan proxy` + +
+Monitors, logs, and safeguards all MCP traffic on your machine. +
+ +The `mcp-scan proxy` command temporarily intercepts the MCP traffic on your machine, using [Gateway](../guardrails/gateway.md), to safeguard and audit MCP calls on your machine. This allows you to inspect the runtime behavior of agents and tools, and to prevent attacks from e.g., untrusted sources (like websites or emails) that may try to exploit or hijack your agents. + +`mcp-scan proxy` is a dynamic security layer that runs as long as the CLI process is running, and continuously monitors all MCP traffic on your machine. + +proxying-overview-diagram + +## Usage + +To get started, run the following command in your terminal: + +``` +uvx mcp-scan@latest proxy +``` + +As visible from the output, this temporarily rewrites all MCP server configurations across your machine, to route calls via [Gateway](../guardrails/gateway.md), allowing you to inspect and guardrail MCP calls. + +This transparently proxies all MCP calls on your machine, and logs them to the console, in which `mcp-scan proxy` is running: + +!!! note + + Some MCP clients require a restart or a re-initialization of the proxied MCP server for proxying to take effect. + +**Output** (compact mode): +``` +-- → vscode (user@UserHostMachine) used arxiv-server to tools/list (call_2) -- +Arguments: +{} + +-- ← (call_2) vscode (user@UserHostMachine) used arxiv-server to tools/list -- +[{'name': 'search_papers', 'description': 'Search for papers on arXiv with advanced filtering', 'inputSchema': {'type': 'object', 'properties': {'query': {'type': +'string'}, 'max_results': {'type': 'integer'}, 'date_from': {'type': 'string'}, 'date_to': {'type': 'string'}, 'categories': {'type': 'array', 'items': {'type': +'string'}}}, 'required': ['query']}}, {'name': 'download_paper', 'descriptio... + +-- → vscode (user@UserHostMachine) used arxiv-server to search_papers (call_3) -- +Arguments: +{'query': 'LMQL language model query language', 'max_results': 10} + +-- ← (call_3) vscode (user@UserHostMachine) used arxiv-server to search_papers -- +{'total_results': 10, 'papers': [{'id': '2505.14687v1', 'title': 'Grouping First, Attending Smartly: Training-Free Acceleration for Diffusion Transformers', +'authors': ['Sucheng Ren', 'Qihang Yu', 'Ju He', 'Alan Yuille', 'Liang-Chieh Chen'], 'abstract': 'Diffusion-based Transformers have demonstrated impressive +generative\ncapabilities, but their high computational costs hinder practical deploymen... + +--------------------------------------------------------------- +GUARDRAIL LOG Found PII in tool output. (124 ranges) +--------------------------------------------------------------- +``` + +As shown here, both MCP calls and responses are logged, together with relevant metadata like the server and client name, username, as well as the call ID. + +### Command Line Options + +``` +> mcp-scan proxy [CONFIGURATION_FILE] + +[CONFIGURATION_FILE] Optional path of the configuration file to rewrite + for proxying. If not provided, all system-wide MCP + configurations are rewritten. + +--pretty [oneline|compact|full] Pretty print the output. (default: "oneline") +``` + +`--pretty` controls the output format of the logs. The default is `compact`, which is a human-readable format that is easy to read. The `oneline` format is a single line per log entry, and the `full` format is a more verbose format that includes fully formatted tool calls and outputs. + +### Examples + +``` +# proxies all MCP client system-wide (supported clients only) +mcp-scan proxy + +# proxies a specific client configuration file (customary MCP configuration format assumed) +mcp-scan proxy path/to/client/json + +# use single-line trace logging format +mcp-scan proxy --pretty oneline +``` \ No newline at end of file diff --git a/docs/mcp-scan/scanning.md b/docs/mcp-scan/scanning.md new file mode 100644 index 0000000..288a43c --- /dev/null +++ b/docs/mcp-scan/scanning.md @@ -0,0 +1,73 @@ +--- +title: Scanning Your MCP Servers with MCP-Scan +description: Use MCP-scan to ensure your MCP servers are safe to use. +icon: bootstrap/file-break +--- + +# Scanning with `mcp-scan scan` + +
+Scans your configured MCP servers for malicious tool descriptions and behavior. +
+ +Using `mcp-scan scan`, you can statically scan your configured MCP servers for malicious tool descriptions and behavior, in order to prevent attacks from untrusted MCP servers. + +`mcp-scan scan` is a static check that only runs when you invoke it, and does not run in the background. + +
+ +scanning-overview-diagram + +
+ +If you also want to enable runtime monitoring, see the [Proxying chapter](./proxying.md) for more information. + +## Quick Start +To run MCP-Scan, use the following command: + +```bash +uvx mcp-scan@latest +``` + +or + +``` +npx mcp-scan@latest +``` + +**Example Output**: + +![mcp-scan-output](https://invariantlabs.ai/images/mcp-scan-output.png) + +## How It Works +MCP-Scan searches through your configuration files to find MCP server configurations. It connects to these servers and retrieves tool descriptions. + +It then scans tool descriptions, both with local checks and by invoking Invariant Guardrailing via an API. For this, tool names and descriptions are shared with invariantlabs.ai. By using MCP-Scan, you agree to the invariantlabs.ai [terms of use](https://explorer.invariantlabs.ai/terms) and [privacy policy](https://invariantlabs.ai/privacy-policy). + +Invariant Labs is collecting data for security research purposes (only about tool descriptions and how they change over time, not your user data). Don't use MCP-scan if you don't want to share your tools. +You can run MCP-scan locally by using the `--local-only` flag. This will only run local checks and will not invoke the Invariant Guardrailing API, however, it will not provide as accurate results as it just runs a local LLM-based policy check. This option requires an `OPENAI_API_KEY` environment variable to be set. + +MCP-scan does not store or log any usage data, i.e., the contents and results of your MCP tool calls. + +### Command Line Options + +Next to the main `mcp-scan scan` command, MCP-scan supports a number of command line options. For more information, use the `--help` flag, or see the [project README](http://github.com/invariantlabs-ai/mcp-scan). + +### Examples + +```bash +# Scan all known MCP configs +mcp-scan + +# Scan a specific config file +mcp-scan ~/custom/config.json + +# Just inspect tools without verification +mcp-scan inspect + +# View whitelisted tools +mcp-scan whitelist + +# Whitelist a tool +mcp-scan whitelist tool "add" "a1b2c3..." +``` \ No newline at end of file diff --git a/docs/overrides/.icons/bootstrap/file-break.svg b/docs/overrides/.icons/bootstrap/file-break.svg new file mode 100644 index 0000000..e94b3a3 --- /dev/null +++ b/docs/overrides/.icons/bootstrap/file-break.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/docs/overrides/.icons/bootstrap/lock.svg b/docs/overrides/.icons/bootstrap/lock.svg new file mode 100644 index 0000000..c38aa42 --- /dev/null +++ b/docs/overrides/.icons/bootstrap/lock.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/docs/overrides/.icons/bootstrap/shield-check.svg b/docs/overrides/.icons/bootstrap/shield-check.svg new file mode 100644 index 0000000..3908fca --- /dev/null +++ b/docs/overrides/.icons/bootstrap/shield-check.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index 388be00..999e480 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -127,6 +127,11 @@ nav: # - Syntax: guardrails/examples/syntax.md # - Copyright: guardrails/examples/copyright.md # - Loop Detection: guardrails/examples/loop.md + - MCP-Scan: + - Overview: mcp-scan/index.md + - Scanning: mcp-scan/scanning.md + - Proxying: mcp-scan/proxying.md + - Guardrails: mcp-scan/guardrails.md - Integrations: - Explorer: - Overview: explorer/index.md