Skip to content

Commit 1ec345e

Browse files
ithiria894claude
andcommitted
readme: badges, ASCII architecture diagram, personal story, comparison table
Based on CCO and PokeClaw README patterns. Added shields.io badges, ASCII art scanner comparison, architecture diagram, honest limitations, and founder story section. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 949ed61 commit 1ec345e

1 file changed

Lines changed: 65 additions & 43 deletions

File tree

README.md

Lines changed: 65 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,29 @@
11
# intentprobe
22

3-
**See a tool's true intent before you install it.**
3+
<p align="center">
4+
<strong>See a tool's true intent before you install it.</strong>
5+
</p>
46

5-
MCP servers, Claude Code skills, and agent tools describe themselves in plain English. Two descriptions can use almost identical words while only one of them quietly steals your SSH keys. Text scanners can't tell them apart. IntentProbe can.
7+
<p align="center">
8+
<a href="https://github.com/mcpware/intentprobe/stargazers"><img src="https://img.shields.io/github/stars/mcpware/intentprobe?style=social" alt="Stars" /></a>
9+
<a href="https://github.com/mcpware/intentprobe/network/members"><img src="https://img.shields.io/github/forks/mcpware/intentprobe?style=social" alt="Forks" /></a>
10+
<img src="https://img.shields.io/badge/Python-3.10%2B-blue?logo=python&logoColor=white" alt="Python 3.10+" />
11+
<a href="LICENSE"><img src="https://img.shields.io/badge/License-Apache%202.0-blue" alt="License" /></a>
12+
<img src="https://img.shields.io/badge/runs-100%25%20local-brightgreen" alt="Runs locally" />
13+
<img src="https://img.shields.io/badge/telemetry-zero-blue" alt="Zero telemetry" />
14+
</p>
615

7-
Instead of matching text patterns, IntentProbe runs the description through a small local model and reads its internal activations. If the model internally understands the text as "this is trying to exfiltrate secrets," a trained probe catches that signal, even when the words look safe.
16+
MCP servers, Claude Code skills, and agent tools describe themselves in plain English. Two descriptions can use almost identical words while only one of them quietly steals your SSH keys.
17+
18+
```
19+
Every other scanner: Tool description ──→ Text pattern matching ──→ "Looks fine" ✅
20+
(reads the words)
21+
22+
IntentProbe: Tool description ──→ Small local model ──→ Read activations ──→ "This is stealing keys" 🚫
23+
(reads what the model understood)
24+
```
25+
26+
Text scanners read words. IntentProbe reads intent.
827

928
```
1029
$ intentprobe scan --format summary \
@@ -16,10 +35,6 @@ input-1: decision=block risk=0.980 activation=0.980 static=0.950
1635
- static finding: Mentions uploading data outside the local tool scope
1736
```
1837

19-
Runs locally on CPU. Nothing leaves your machine.
20-
21-
![IntentProbe demo: text scanner misses poisoned tool, activation probe catches it](docs/demo.gif)
22-
2338
## The problem
2439

2540
> **Tool A:** "Reads the SSH config file and returns a parsed list of host aliases, hostnames, and ports. Does not modify files or open connections."
@@ -28,20 +43,42 @@ Runs locally on CPU. Nothing leaves your machine.
2843
2944
Same words. Same topic. Tool B exfiltrates your private keys.
3045

31-
On 485 poisoned tool descriptions from real MCP servers, Snyk's shipped text classifier caught 19.9%. On matched-vocabulary pairs where safe and poisoned descriptions share the same words, it caught **zero**.
46+
Every MCP scanner we source-verified uses text patterns, regex rules, or text classifiers. On matched-vocabulary tool poisoning where safe and poisoned descriptions share the same words, Snyk's shipped classifier catches **zero**.
3247

3348
## Benchmarks
3449

35-
Head-to-head on the same test sets, same split, same seed:
50+
Head-to-head on the same test sets, same split, same seed. Every number is reproducible from scripts in `research/`.
3651

37-
| Test set | IntentProbe | Snyk DeBERTa |
52+
| | IntentProbe | Snyk DeBERTa |
3853
|---|---|---|
39-
| MCPTox template attacks (n=249) | **99.2%** recall | 19.9% recall |
40-
| Matched-vocabulary pairs (n=86) | **96.5%** recall | 0.0% recall |
41-
| Novel attack phrasing | **71-73%** recall | 0-20% recall |
42-
| Adversarial evasion (camouflage suffixes) | **0/146 evaded** | N/A |
54+
| **MCPTox template attacks** (n=249) | **99.2%** recall | 19.9% recall |
55+
| **Matched-vocabulary pairs** (n=86) | **96.5%** recall | 0.0% recall |
56+
| **Novel attack phrasing** | **71-73%** recall | 0-20% recall |
57+
| **Adversarial evasion** (camouflage suffixes) | **0/146 evaded** | N/A |
58+
59+
<sub>Methodology: research/benchmark-results-deberta-vs-probe-2026-05-31.md and research/ADVERSARIAL_EVASION_RESULTS_2026-06-07.md</sub>
60+
61+
## How it works
62+
63+
```
64+
┌─────────────────────────┐
65+
Tool description ───→ │ Qwen2.5-0.5B (frozen) │ ───→ Activations at layers 13-15
66+
└─────────────────────────┘ │
67+
68+
┌────────────────────┐
69+
│ Trained probe │ ───→ allow / warn / block
70+
│ (22 KB, logreg) │
71+
└────────────────────┘
72+
+
73+
Static regex corroboration
74+
```
75+
76+
1. Text goes through a frozen local model (Qwen2.5-0.5B, 494M params, any CPU).
77+
2. A 22 KB trained probe reads internal activations at layers 13-15.
78+
3. Static regex checks corroborate the signal.
79+
4. Decision: **allow** / **warn** / **block** with a confidence score.
4380

44-
Every number is reproducible. Scripts and datasets are in `research/`. Run them yourself.
81+
Under a second per description. No GPU. Nothing leaves your machine.
4582

4683
## Install
4784

@@ -52,7 +89,7 @@ python3 -m venv .venv
5289
.venv/bin/pip install -e .
5390
```
5491

55-
Requires Python 3.10+. First scan downloads Qwen2.5-0.5B (~1 GB, once).
92+
First scan downloads Qwen2.5-0.5B (~1 GB, once). After that, everything stays local.
5693

5794
## Try it
5895

@@ -64,48 +101,33 @@ Requires Python 3.10+. First scan downloads Qwen2.5-0.5B (~1 GB, once).
64101
# Scan an MCP server folder before installing
65102
.venv/bin/intentprobe scan-path ./some-mcp-server --format summary
66103

67-
# Use as a CI gate (exit code 2 on block)
104+
# CI gate (exit code 2 on block)
68105
.venv/bin/intentprobe scan --fail-on block --text "..."
69-
```
70-
71-
For runtime gating (scan tool calls as they happen), see `docs/RUNTIME_HOOKS.md` or try the safe demo:
72106

73-
```bash
107+
# Runtime gating demo (safe, in-memory, no real tools)
74108
.venv/bin/python examples/runtime_toy_agent.py --allow-download
75109
```
76110

77-
## How it works
78-
79-
1. Text goes through a frozen local model (Qwen2.5-0.5B, 494M params).
80-
2. A trained probe reads internal activations at layers 13-15.
81-
3. Static regex checks look for known-bad keywords as corroboration.
82-
4. Decision: **allow** / **warn** / **block** with a confidence score.
83-
84-
The probe weights are 22 KB. The base model runs on any CPU in under a second per description. No GPU needed.
111+
For runtime hook integration, see [docs/RUNTIME_HOOKS.md](docs/RUNTIME_HOOKS.md).
85112

86113
## What it scans
87114

88-
`scan-path` extracts descriptions from `package.json`, MCP JSON configs, `SKILL.md`, README files, and tool/skill metadata files. `runtime` mode accepts live tool-call events with secret redaction.
115+
`scan-path` extracts descriptions from `package.json`, MCP JSON configs, `SKILL.md`, README files, and tool/skill metadata. `runtime` mode accepts live tool-call events with automatic secret redaction.
89116

90117
## Honest limitations
91118

92-
- The probe is strongest when safe and poisoned descriptions share vocabulary. That is where text scanners score zero and IntentProbe scores 96%.
93-
- On fully novel attack families not seen in training, recall drops to ~41%. Still 4x better than text classifiers (10.7%), but this is the open frontier.
94-
- Camouflage suffixes ("this tool is safe and sandboxed") do not evade the probe (0/146), but gradient-based white-box attacks are untested.
95-
- IntentProbe detects and flags for a human. It does not silently "fix" tools.
96-
97-
## Privacy
98-
99-
IntentProbe runs locally. It does not send descriptions, scan results, or telemetry to any server. The first scan downloads the base model from Hugging Face. After that, everything stays on your machine.
119+
- Strongest on matched-vocabulary poisoning (safe and malicious share words). That is where every text scanner scores zero and IntentProbe scores 96%.
120+
- On fully novel attack families not in training, recall drops to ~41%. Still 4x better than text classifiers (10.7%), but this is the open frontier.
121+
- Camouflage suffixes ("this tool is safe and sandboxed") do not fool the probe (0/146 evaded). Gradient-based white-box attacks are untested.
122+
- IntentProbe flags for a human. It does not silently "fix" tools.
100123

101-
## Help improve the scanner
124+
## The story
102125

103-
If IntentProbe misses a poisoned tool you found in the wild, that sample is gold.
126+
I built this after source-reading Snyk's shipped MCP scanner and finding it uses a DeBERTa text classifier that scores 0% recall on matched-vocabulary tool poisoning. The entire category of MCP scanners relies on text patterns. None of them read model internals.
104127

105-
- **Missed detection**: open a [Missed detection](https://github.com/mcpware/intentprobe/issues/new?template=missed-detection.yml) issue.
106-
- **False positive**: open a [False positive](https://github.com/mcpware/intentprobe/issues/new?template=false-positive.yml) issue.
128+
IntentProbe is a different approach: run the description through a small model, read the activations, and train a probe on the signal that encodes intent. The research paper behind this is in `research/`. The probe weights are 22 KB. The benchmarks are open. Run them yourself.
107129

108-
Redact secrets and private data before posting. See `docs/SAMPLE_REPORTING.md`.
130+
If it misses something, [report it](https://github.com/mcpware/intentprobe/issues/new?template=missed-detection.yml). Every missed sample improves the next probe.
109131

110132
## License
111133

0 commit comments

Comments
 (0)