webverb-mcp
by cs0317
README.md
# webverb-mcp
[](LICENSE)  
**Your agent, working in the sites you're already logged into.**
81 typed verbs across 13 sites. Typed fields, not HTML soup.
> **New here?** [**What webverb is, in pictures →**](https://claude.ai/code/artifact/6133e479-bd24-40ae-9379-03abc3a3e602)
> A two-minute visual explainer: the problem it solves, how you use it, and where it runs.
## Quick start
```bash
claude plugin marketplace add jiancui-research/webverb-mcp-python-public-beta
claude plugin install webverb@webverb-marketplace
```
The first call launches a **second, separate Chrome** and asks you to sign in there once.
Not the Chrome you use every day — a dedicated one, with its own profile.
## How it gets access
```mermaid
flowchart LR
A["everyday Chrome · untouched<br/>~/Library/Application Support/Google/Chrome"]
you(("you")) -->|"sign in once"| B["debug Chrome · :9222<br/>~/chrome-debug-profile"]
wv["webverb"] --> B
B --> S(["gmail · reddit · maps …"])
```
Two Chromes, two profiles, nothing shared. webverb never sees a password; it attaches to
the browser you signed into. (`C:\chrome-debug-profile` on Windows.)
What that costs:
- **`:9222` has no auth.** Any local process that reaches it drives that browser.
- **The profile is a real cookie jar** — reading that directory gets your sessions.
- **The agent acts as you.** 33 of the 81 verbs change account state.
- **Results leave the machine**, forwarded to your model.
Chrome 136+ refuses `--remote-debugging-port` on your default profile, which is why this
needs its own. Full threat model: [SECURITY.md](SECURITY.md).
<details>
<summary>Codex · Copilot CLI · any MCP host</summary>
```bash
git clone https://github.com/jiancui-research/webverb-mcp-python-public-beta
cd webverb-mcp-python-public-beta && uv sync
```
```jsonc
{ "mcpServers": { "web-verbs": {
"command": "uv",
"args": ["--directory", "/abs/path/to/repo", "run", "python", "-m", "webverb_mcp"] } } }
```
Use an **absolute** path, and raise the tool-call timeout to ~300s — a verb that scrolls a
lazy-loading feed can legitimately take minutes.
</details>
## Then just ask
- *"Summarise the top comments on my Reddit feed."*
- *"Search my Gmail for the Acme invoice and start a reply draft."*
- *"What's in my Amazon cart, and what did I order last month?"*
- *"List my Overleaf projects and show me the intro of the ICLR one."*
Under *"summarise the top comments on my Reddit feed"*, that's three calls:
```console
› search_verb(query="reddit home feed")
reddit_com/feed score 3.0
1point3acres_com/feed score 2.0
› run_verb("reddit_com/feed", {"max_posts": 3})
715 up 505 comments r/LocalLLaMA "The All Spark" Cluster: Upgrading from 16 -
— up 0 comments r/u_Amazon_Official Healthcare can be a real pain for a medical
35 up 45 comments r/PiCodingAgent Subagent extensions
› run_verb("reddit_com/post_comments", {"post_url": "…/r/LocalLLaMA/comments/1…"})
1 ▲ WithoutReason1729 Your post is getting popular and we just featured it
241 ▲ johnfkngzoidberg That's like $150k worth of hardware. Wtf.
192 ▲ Kurcide About $200k worth at today's prices after the switch
```
Verbatim from a real run. Two things it shows: the feed hands you the `post_url` the
comments verb takes, so a follow-up is one more call — and the promoted post reports
`—` rather than a score, because it's flagged `is_promoted` instead of being silently
dropped.
## What's covered
| Site | Verbs | | Site | Verbs |
| --- | :-: | --- | --- | :-: |
| amazon.com | 11 | | overleaf.com | 6 |
| docs.google.com | 10 | | reddit.com | 4 |
| drive.google.com | 10 | | x.com | 4 |
| mail.google.com | 10 | | linkedin.com | 4 |
| google.com Maps | 8 | | rednote.com | 4 |
| google.com Flights + auth | 2 | | 1point3acres.com | 4 |
| hotcrp.com | 4 | | | |
```bash
uv run python -m webverb_mcp.registry # list everything
uv run inspect_verb.py <verb> # one verb's exact arguments
```
## Missing a site? Build the verb
A verb is one file in one folder under `verbs/<site>/<action>/` — the registry finds it at
boot, no server change, at whatever depth you file it. You don't write it from scratch;
four commands hand your agent the process:
| Command | Use it to |
| --- | --- |
| `/webverb:write-verb <site or action>` | Add a verb for something nothing covers yet |
| `/webverb:fix-verb <verb or symptom>` | Repair one that broke when a site redesigned |
| `/webverb:verify-verbs [verb or site]` | Prove verbs work against real values, not "non-empty" |
| `/webverb:verb-contract [topic]` | Look up the exact rule instead of guessing |
Keep your verbs outside the install so updates can't remove them:
```bash
export WEBVERB_VERBS_DIR=~/my-verbs
```
### After you build one
```bash
uv run python -m webverb_mcp.lint # contract check — exit 0 = clean
uv run python -m webverb_mcp.registry # your verb should appear, 0 skipped
```
Then, in order:
1. **Reconnect with `/mcp`.** The running server built its registry at boot, so it cannot
see a verb you just added. This is the single most common "why isn't my verb showing
up" — the file is fine, the server is stale.
2. **Verify it lives:** `/webverb:verify-verbs <your verb>`. Registering is not working;
a verb can register cleanly and still return wrong fields.
3. **Share it, if it's a public site:** a verb is one file, so a pull request is small.
See [CONTRIBUTING](CONTRIBUTING.md).
If the verb doesn't appear at all, the usual cause is a second `.py` in its folder — the
registry silently drops those, which is what `lint` catches.
## How it works
```mermaid
flowchart LR
A[Your agent] -->|"search_verb('reddit feed')"| B[webverb MCP]
A -->|"run_verb(id, args)"| B
B --> C[(81 verbs)]
B -->|CDP :9222| D[Your signed-in Chrome]
D --> E([reddit · gmail · drive<br/>amazon · linkedin …])
E -->|typed dataclass| A
```
Two tools, not one per verb, so context cost stays flat whether you have 4 verbs or 400.
`search_verb` finds the right one and returns its schema; `run_verb` executes it.
Two properties you'll notice in practice:
- **Cheap.** A verb returns a few hundred bytes where an accessibility snapshot of the same
page runs 40,000+ characters.
- **Fails loudly.** When a site redesigns, verbs raise instead of returning an
empty-but-successful result — so you get an error, not a confidently wrong summary.
Eleven `raw_browser_*` primitives are there for whatever no verb covers yet, and for
diagnosing a verb that broke. They're named and described as a fallback so your agent
reaches for `search_verb` first. If you'd rather they not exist at all:
```bash
export WEBVERB_RAW_TOOLS=0 # leaves only search_verb and run_verb
```
Naming and descriptions are steering, and a model can ignore steering. That variable is
the only setting that makes raw page-driving impossible.
## Before you rely on it
> [!IMPORTANT]
> **Public beta.** Verbs act in your real accounts, and some sites prohibit automated
> access. Keep volumes modest and stop if a site starts refusing requests.
- **Most verbs read; 33 of 81 write.** Reading is the default, but the library includes actions
that change state — Gmail drafts, Drive moves and trashing, Amazon cart edits, Overleaf
project creation and trashing, Maps list edits, HotCRP review bids. Check a verb's name and
`inspect_verb.py` before running it on an account you care about.
- **A running server caches the registry at boot.** After adding a verb or pulling, run
`/mcp` to reconnect, or you'll keep seeing the old set.
- Chrome 136+ ignores `--remote-debugging-port` on the default profile, which is why a
dedicated one is required.
[HotCRP quick start](docs/hotcrp-quickstart.md) · [Roadmap](ROADMAP.md) · [Troubleshooting](docs/troubleshooting.md) · [Contributing](CONTRIBUTING.md) · [Security](SECURITY.md) · MIT
This server cannot be deployed
Maintenance
ActivityActive
ResponsivenessNo issues