Skip to content

Commit cf45aa3

Browse files
mcp-scan docs (#7)
* MCP scan scaffolding * add mcp guardrails content * add example commands in proxying --------- Co-authored-by: knielsen404 <[email protected]>
1 parent 2132c67 commit cf45aa3

File tree

10 files changed

+1005
-0
lines changed

10 files changed

+1005
-0
lines changed

docs/mcp-scan/assets/proxy.svg

Lines changed: 233 additions & 0 deletions
Loading

docs/mcp-scan/assets/scan.svg

Lines changed: 212 additions & 0 deletions
Loading

docs/mcp-scan/guardrails.md

Lines changed: 269 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,269 @@
1+
---
2+
title: Guardrails in MCP-Scan
3+
description: Use MCP-scan to ensure your MCP servers are safe to use.
4+
icon: bootstrap/lock
5+
---
6+
7+
# Guardrails in `mcp-scan`
8+
9+
<div class='subtitle'>
10+
Safeguard and restrict your MCP tool calls and responses.
11+
</div>
12+
13+
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.
14+
15+
This guide covers how to structure guardrail configs, write custom rules, and apply enforcement at the client, server, and tool levels.
16+
17+
<img src="../assets/proxy.svg" alt="proxying-overview-diagram" class="textwidth" style="max-width: 420pt; margin: 40pt auto; display: block;" />
18+
19+
!!! note
20+
By default, the configuration file is located at `~/.mcp-scan/guardrails-config.yml`.
21+
22+
## File structure
23+
24+
The configuration file defines guardrailing behavior hierarchically, scoped by **client**, **server**, and **tool**. Below is a structured overview of the YAML format:
25+
26+
```yaml
27+
<client-name>:
28+
<server-name>:
29+
guardrails:
30+
<default-guardrail-name>: <guardrail-action>
31+
...
32+
33+
custom_guardrails:
34+
- name: <guardrail-name>
35+
id: <guardrail-id>
36+
action: <guardrail-action>
37+
content: |
38+
<guardrail-content>
39+
...
40+
41+
tools:
42+
<tool-name>:
43+
<default-guardrail-name>: <guardrail-action>
44+
...
45+
enabled: <boolean>
46+
...
47+
...
48+
```
49+
50+
Each configuration block defines a set of **default**, **custom**, and **tool-level** guardrails for a specific `<client> / <server>` combination (e.g., a client like Cursor and a server like a Git MCP instance).
51+
52+
The ellipses (`...`) in the schema indicate that multiple entries can be added at each level:
53+
54+
- Multiple servers under a single client.
55+
56+
- Multiple guardrails under each guardrails section.
57+
58+
- Multiple tools under a server.
59+
60+
This structure supports flexible, fine-grained control across different environments and toolchains. The sections of the file are described below.
61+
62+
63+
## Default guardrails
64+
65+
Default guardrails are pre-configured and run by default with the `log` action. Alternatively, their behavior can be overridden by specifying `<default-guardrail-name>: <guardrail-action>` as shown above. The following default guardrails exist and can be configured:
66+
67+
| Name | Requirements | Description |
68+
|-------------|--------|----------------------------------------|
69+
| `links` | `None` | Detects links. |
70+
| `secrets` | `None` | Detects secrets, such as tokens or api keys. |
71+
| `pii` | `presidio`, `transformers` | Detects personally identifiable information, such as names, emails, or credit card numbers. |
72+
| `moderated` | `ENV: OPENAI_API_KEY` | Detects content that should be moderated, such as hate speech or explicit content. |
73+
74+
75+
!!! note
76+
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.
77+
78+
79+
**Example:** Overriding a default guardrail.
80+
```yaml
81+
cursor:
82+
email-mcp-server:
83+
guardrails:
84+
pii: block
85+
secrets: paused
86+
```
87+
88+
## Custom guardrails
89+
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.
90+
91+
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).
92+
93+
### Schema
94+
A custom guardrail is defined using the following fields:
95+
96+
| Name | Type | Description |
97+
|-------------|-------------|----------------------------------------|
98+
| `name` | `string` | A name for the guardrail. |
99+
| `id` | `string` | A unique identifier for the guardrail. |
100+
| `action` | `Guardrail Action` | The `action` to take when this guardrail is triggered. See below. |
101+
| `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. |
102+
103+
**Example:** Defining a custom guardrail.
104+
105+
Below is a `yaml` fragment that shows how a custom guardrail can be defined to ensure emails are only sent to trusted recipients.
106+
```yaml
107+
...
108+
custom_guardrails:
109+
- name: "Trusted Recipient Email"
110+
id: "trusted_email_check"
111+
action: block
112+
content: |
113+
raise "Untrusted email recipient" if:
114+
(call: ToolCall)
115+
call is tool:send_email
116+
not match(".*@company.com", call.function.arguments.recipient)
117+
...
118+
```
119+
120+
## Tool-specific guardrails
121+
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.
122+
123+
124+
### Schema
125+
The following fields are available for each `tool`:
126+
127+
| Name | Type | Description |
128+
|-------------|-------------|----------------------------------------|
129+
| `<default-guardrail>` | `Guardrail Action` | Overrides the behavior of `<default-guardrail>` for this tool specifically. |
130+
| `enabled` | `boolean` | Disables tool when set to <span class='boolean-value-false'>False</span>. If this field is not provided, it defaults to <span class='boolean-value-true'>True</span>. |
131+
132+
133+
!!! note
134+
While the tools section does not allow for defining custom guardrails, you can always use the `call is tool:<tool_name>` syntax to select a specific tool, as shown in the example from the previous section.
135+
136+
**Example:** Disabling and overriding behavior for tools.
137+
138+
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.
139+
```yaml
140+
...
141+
tools:
142+
send_message:
143+
enabled: false
144+
145+
read_messages:
146+
secrets: block
147+
...
148+
```
149+
150+
## Guardrail actions
151+
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.
152+
153+
The following actions are available:
154+
155+
| Name | Description |
156+
|-------------|----------------------------------------|
157+
| `block` | This will block the client outright, preventing it from executing what triggered the guardrail. |
158+
| `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. |
159+
| `paused` | This pauses the enforcement of the guardrail. |
160+
161+
These actions are available for both default and custom guardrails.
162+
163+
164+
## Priority of rules
165+
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.
166+
167+
This ensures predictable behavior and allows for precise control, especially when configuring environments with overlapping scopes.
168+
169+
170+
!!! note
171+
**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.
172+
173+
### Rule Priority (from highest to lowest)
174+
1. **Tool-specific guardrails**
175+
Guardrails defined for a specific tool override all other configurations.
176+
2. **Client/server-specific guardrails**
177+
Guardrails set at the server level for a particular client are used unless overridden by a tool-specific rule.
178+
3. **Implicit default guardrails**
179+
If no explicit rule is defined, the default guardrails apply automatically with the `log` action.
180+
181+
**Example:** A simple config file with overrides.
182+
183+
To see how this hierarchy of precedence works, consider the following example configuration:
184+
185+
```yaml
186+
client:
187+
server:
188+
guardrails:
189+
pii: block
190+
secrets: paused
191+
192+
tools:
193+
tool:
194+
secrets: block
195+
```
196+
197+
The resulting behavior of this configuration is:
198+
199+
- `secrets` is set to block for the `tool`, because tool-specific guardrails have the highest priority.
200+
201+
- For all other tools on `server`, secrets is set to `paused`, as defined at the client/server level.
202+
203+
- For any other client/server combinations not defined in the config, `secrets` will use the implicit default and be set to `log`.
204+
205+
- `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`).
206+
207+
This precedence ensures that you can enforce strict guardrails where needed, while still benefiting from broad default coverage elsewhere.
208+
209+
210+
## Example file
211+
Below is a complete example of a guardrail configuration file.
212+
It demonstrates how to define default and custom guardrails for specific clients and servers, apply tool-level overrides, and selectively enable or disable tools
213+
214+
```yaml
215+
cursor:
216+
email-mcp-server:
217+
218+
# Customize the guardrailing for this specific server
219+
guardrails:
220+
pii: block
221+
moderated: paused
222+
223+
# Define multiple custom guardrails
224+
custom_guardrails:
225+
- name: "Trusted Recipient Email"
226+
id: "untrustsed_email_gr_1"
227+
action: block
228+
229+
# Guardrail to ensure that we know all recipients
230+
content: |
231+
raise "Untrusted email recipient" if:
232+
(call: ToolCall)
233+
call is tool:send_email
234+
not match(".*@company.com", call.function.arguments.recipient)
235+
236+
237+
# Guardrail to ensure an email is not sent after
238+
# a prompt injection is detected in the inbox
239+
- name: "PII Email"
240+
id: "untrustsed_email_gr_2"
241+
action: log
242+
content: |
243+
from invariant.detectors import prompt_injection
244+
245+
raise "Suspicious email before send" if:
246+
(inbox: ToolOutput) -> (call: ToolCall)
247+
inbox is tool:get_inbox
248+
call is tool:send_email
249+
prompt_injection(inbox.content)
250+
251+
# Specify the behavior of individual tools
252+
tools:
253+
send_message:
254+
enabled: false
255+
256+
read_messages:
257+
secrets: block
258+
259+
weather:
260+
guardrails:
261+
moderated: paused
262+
263+
# Separate configurations on a per client/server basis
264+
claude:
265+
git-mcp-server:
266+
tools:
267+
commit-tool:
268+
links: paused
269+
```

docs/mcp-scan/index.md

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
---
2+
title: Securing MCP with Invariant
3+
description: Use MCP-scan to safeguard your MCP integrations.
4+
icon: bootstrap/shield-check
5+
---
6+
7+
# MCP-Scan: A security scanner for MCP
8+
9+
<div class='subtitle'>
10+
Use MCP-scan to safeguard your MCP integrations.
11+
</div>
12+
13+
[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.
14+
15+
<img src="./assets/proxy.svg" alt="mcp-scan-overview-diagram" class="textwidth" style="max-width: 480pt; margin: 40pt auto; display: block;" />
16+
17+
### MCP-Scan Features
18+
19+
- Scanning of Claude, Cursor, Windsurf, and other file-based MCP client configurations
20+
- 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)
21+
- Live runtime monitoring of MCP traffic using `mcp-scan proxy`
22+
- _MCP guardrailing_ of tool calls and responses, including PII detection, secrets detection, tool restrictions and [custom guardrailing policies](./guardrails)
23+
- Detection of cross-origin escalation attacks ([tool shadowing](https://invariantlabs.ai/blog/mcp-security-notification-tool-poisoning-attacks))
24+
- _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
25+
26+
## Quick Start
27+
To run a simple system-level scan with MCP-Scan, use the following command:
28+
29+
```bash
30+
uvx mcp-scan@latest
31+
```
32+
33+
or
34+
35+
```
36+
npx mcp-scan@latest
37+
```
38+
39+
To learn more about the scan, see the [chapter on scanning](./scanning.md).
40+
41+
## Why MCP-Scan?
42+
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.
43+
44+
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.
45+
46+
## Using MCP-Scan
47+
48+
MCP-scan offers two primary modes of operations, allowing you to identify security vulnerabilities in your MCP integrations and continously monitor your MCP traffic.
49+
50+
51+
<!-- * [_Server Scanning_](./scanning.md) with **`mcp-scan scan`** -->
52+
### Passive Scanning with **`mcp-scan scan`**
53+
54+
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.
55+
56+
<br/>
57+
58+
<img src="./assets/scan.svg" alt="scanning-overview-diagram" class="textwidth" style="max-width: 420pt; margin: auto; display: block;" />
59+
60+
<br/>
61+
62+
Learn more about the scanning mode in the [MCP Server Scanning](./scanning.md) chapter.
63+
64+
65+
### Active Proxying with **`mcp-scan proxy`**
66+
67+
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.
68+
69+
<br/>
70+
71+
<img src="./assets/proxy.svg" alt="proxying-overview-diagram" class="textwidth" style="max-width: 420pt; margin: auto; display: block;" />
72+
73+
<br/>
74+
75+
Learn more about the proxying mode in the [MCP Proxying with mcp-scan](./proxying.md) chapter.
76+
77+
78+
## Including MCP-scan results in your own project / registry
79+
80+
If you want to include MCP-scan results in your own project or registry, please reach out to the team via `[email protected]`, and we can help you with that.
81+
For automated scanning we recommend using the `--json` flag and parsing the output.
82+
83+
## Further Reading
84+
- [Introducing MCP-Scan](https://invariantlabs.ai/blog/introducing-mcp-scan)
85+
- [MCP Security Notification Tool Poisoning Attacks](https://invariantlabs.ai/blog/mcp-security-notification-tool-poisoning-attacks)
86+
- [WhatsApp MCP Exploited](https://invariantlabs.ai/blog/whatsapp-mcp-exploited)
87+
- [MCP Prompt Injection](https://simonwillison.net/2025/Apr/9/mcp-prompt-injection/)
88+
89+
90+
## Next Steps
91+
92+
If you are interested in learning more about securing MCP and agents more generally, consider reading one of the following chapters next.
93+
94+
<div class='tiles'>
95+
96+
<a href="./scanning" class='tile primary'>
97+
<span class='tile-title'>MCP Server Scanning →</span>
98+
<span class='tile-description'>Scans your configured MCP servers for malicious tool descriptions and behavior.</span>
99+
</a>
100+
101+
<a href="./proxying" class='tile primary'>
102+
<span class='tile-title'>MCP Proxying with mcp-scan</span>
103+
<span class='tile-description'>Monitors, logs and safeguards all MCP traffic on your machine.</span>
104+
</a>
105+
106+
<a href="../guardrails/" class='tile'>
107+
<span class='tile-title'>Guardrails →</span>
108+
<span class='tile-description'>Learn the fundamentals about guardrailing with Invariant.</span>
109+
</a>
110+
111+
<a href="../explorer/" class='tile'>
112+
<span class='tile-title'>Explorer →</span>
113+
<span class='tile-description'>Configure your guardrailing rules in Explorer, and visualize agent behavior.</span>
114+
</a>
115+
116+
</div>

0 commit comments

Comments
 (0)