webagent-protocol 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- webagent_protocol-0.2.0/.gitignore +14 -0
- webagent_protocol-0.2.0/LICENSE +21 -0
- webagent_protocol-0.2.0/PKG-INFO +401 -0
- webagent_protocol-0.2.0/README.md +333 -0
- webagent_protocol-0.2.0/docs/assets/shopper_demo.svg +153 -0
- webagent_protocol-0.2.0/docs/configuration.md +240 -0
- webagent_protocol-0.2.0/docs/deployment.md +154 -0
- webagent_protocol-0.2.0/docs/evidence/README.md +53 -0
- webagent_protocol-0.2.0/docs/evidence/agent-eval/results.json +141 -0
- webagent_protocol-0.2.0/docs/evidence/agent-eval/summary.md +40 -0
- webagent_protocol-0.2.0/docs/evidence/agent-eval/transcripts.jsonl +55 -0
- webagent_protocol-0.2.0/docs/evidence/benchmark.md +32 -0
- webagent_protocol-0.2.0/docs/evidence/environment.txt +17 -0
- webagent_protocol-0.2.0/docs/evidence/load-test.md +5 -0
- webagent_protocol-0.2.0/docs/mcp_extension.md +243 -0
- webagent_protocol-0.2.0/docs/spec_rfc.md +1013 -0
- webagent_protocol-0.2.0/docs/test-vectors.json +257 -0
- webagent_protocol-0.2.0/docs/whitepaper.md +592 -0
- webagent_protocol-0.2.0/examples/bakery_server.py +476 -0
- webagent_protocol-0.2.0/examples/benchmark.py +257 -0
- webagent_protocol-0.2.0/examples/generate_test_vectors.py +162 -0
- webagent_protocol-0.2.0/examples/llm_agent.py +105 -0
- webagent_protocol-0.2.0/examples/load_test.py +298 -0
- webagent_protocol-0.2.0/examples/shopper_agent.py +114 -0
- webagent_protocol-0.2.0/pyproject.toml +129 -0
- webagent_protocol-0.2.0/tests/__init__.py +0 -0
- webagent_protocol-0.2.0/tests/conftest.py +62 -0
- webagent_protocol-0.2.0/tests/interop/verify_vectors.mjs +71 -0
- webagent_protocol-0.2.0/tests/test_client_resolution.py +324 -0
- webagent_protocol-0.2.0/tests/test_configuration.py +211 -0
- webagent_protocol-0.2.0/tests/test_conversation_guard.py +238 -0
- webagent_protocol-0.2.0/tests/test_crypto_and_pow.py +347 -0
- webagent_protocol-0.2.0/tests/test_e2e_negotiation.py +358 -0
- webagent_protocol-0.2.0/tests/test_fuzz.py +212 -0
- webagent_protocol-0.2.0/tests/test_mcp_extension.py +372 -0
- webagent_protocol-0.2.0/tests/test_safety.py +415 -0
- webagent_protocol-0.2.0/tests/test_server_mount.py +480 -0
- webagent_protocol-0.2.0/tests/test_spec_validation.py +212 -0
- webagent_protocol-0.2.0/tests/test_storage.py +252 -0
- webagent_protocol-0.2.0/tests/test_trust.py +235 -0
- webagent_protocol-0.2.0/wap/__init__.py +75 -0
- webagent_protocol-0.2.0/wap/cli/__init__.py +5 -0
- webagent_protocol-0.2.0/wap/cli/main.py +369 -0
- webagent_protocol-0.2.0/wap/client/__init__.py +47 -0
- webagent_protocol-0.2.0/wap/client/dnskey.py +82 -0
- webagent_protocol-0.2.0/wap/client/exceptions.py +137 -0
- webagent_protocol-0.2.0/wap/client/resolver.py +361 -0
- webagent_protocol-0.2.0/wap/client/session.py +621 -0
- webagent_protocol-0.2.0/wap/mcp/__init__.py +5 -0
- webagent_protocol-0.2.0/wap/mcp/bridge.py +793 -0
- webagent_protocol-0.2.0/wap/mcp/safety.py +120 -0
- webagent_protocol-0.2.0/wap/py.typed +0 -0
- webagent_protocol-0.2.0/wap/server/__init__.py +29 -0
- webagent_protocol-0.2.0/wap/server/admission.py +117 -0
- webagent_protocol-0.2.0/wap/server/app.py +1071 -0
- webagent_protocol-0.2.0/wap/server/mcp_endpoint.py +305 -0
- webagent_protocol-0.2.0/wap/server/mcp_import.py +122 -0
- webagent_protocol-0.2.0/wap/server/middleware.py +111 -0
- webagent_protocol-0.2.0/wap/server/observability.py +102 -0
- webagent_protocol-0.2.0/wap/server/rate_limiter.py +90 -0
- webagent_protocol-0.2.0/wap/server/router.py +358 -0
- webagent_protocol-0.2.0/wap/server/state.py +117 -0
- webagent_protocol-0.2.0/wap/spec/__init__.py +75 -0
- webagent_protocol-0.2.0/wap/spec/conversation.py +231 -0
- webagent_protocol-0.2.0/wap/spec/crypto.py +216 -0
- webagent_protocol-0.2.0/wap/spec/jcs.py +132 -0
- webagent_protocol-0.2.0/wap/spec/models.py +453 -0
- webagent_protocol-0.2.0/wap/spec/pow.py +230 -0
- webagent_protocol-0.2.0/wap/storage/__init__.py +30 -0
- webagent_protocol-0.2.0/wap/storage/base.py +70 -0
- webagent_protocol-0.2.0/wap/storage/memory.py +115 -0
- webagent_protocol-0.2.0/wap/storage/meters.py +204 -0
- webagent_protocol-0.2.0/wap/storage/redis.py +202 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Varad Ganjoo and WebAgent Protocol contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: webagent-protocol
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: WebAgent Protocol: an MCP extension that lets AI agents discover, verify and safely use tools published by any website.
|
|
5
|
+
Project-URL: Homepage, https://github.com/varadganjoo/WebAgent-Protocol
|
|
6
|
+
Project-URL: Documentation, https://github.com/varadganjoo/WebAgent-Protocol#readme
|
|
7
|
+
Project-URL: Specification, https://github.com/varadganjoo/WebAgent-Protocol/blob/main/docs/spec_rfc.md
|
|
8
|
+
Project-URL: MCP extension proposal, https://github.com/varadganjoo/WebAgent-Protocol/blob/main/docs/mcp_extension.md
|
|
9
|
+
Project-URL: Changelog, https://github.com/varadganjoo/WebAgent-Protocol/blob/main/CHANGELOG.md
|
|
10
|
+
Project-URL: Issues, https://github.com/varadganjoo/WebAgent-Protocol/issues
|
|
11
|
+
Author: Varad Ganjoo
|
|
12
|
+
License-Expression: MIT
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Keywords: agentic-web,ai-agents,ed25519,fastapi,mcp,model-context-protocol,proof-of-work,well-known
|
|
15
|
+
Classifier: Development Status :: 4 - Beta
|
|
16
|
+
Classifier: Framework :: AsyncIO
|
|
17
|
+
Classifier: Framework :: FastAPI
|
|
18
|
+
Classifier: Intended Audience :: Developers
|
|
19
|
+
Classifier: Operating System :: OS Independent
|
|
20
|
+
Classifier: Programming Language :: Python :: 3
|
|
21
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
26
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
27
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
28
|
+
Classifier: Topic :: Security :: Cryptography
|
|
29
|
+
Classifier: Typing :: Typed
|
|
30
|
+
Requires-Python: >=3.11
|
|
31
|
+
Requires-Dist: cryptography>=42
|
|
32
|
+
Requires-Dist: httpx-sse>=0.4
|
|
33
|
+
Requires-Dist: httpx[http2]>=0.27
|
|
34
|
+
Requires-Dist: jsonschema>=4.21
|
|
35
|
+
Requires-Dist: pydantic>=2.12
|
|
36
|
+
Requires-Dist: rich>=13.7
|
|
37
|
+
Requires-Dist: typer>=0.15
|
|
38
|
+
Provides-Extra: all
|
|
39
|
+
Requires-Dist: dnspython>=2.6; extra == 'all'
|
|
40
|
+
Requires-Dist: fastapi>=0.110; extra == 'all'
|
|
41
|
+
Requires-Dist: mcp<3,>=2; extra == 'all'
|
|
42
|
+
Requires-Dist: redis>=5; extra == 'all'
|
|
43
|
+
Requires-Dist: sse-starlette>=3.0; extra == 'all'
|
|
44
|
+
Requires-Dist: uvicorn[standard]>=0.29; extra == 'all'
|
|
45
|
+
Provides-Extra: dev
|
|
46
|
+
Requires-Dist: build>=1.3; extra == 'dev'
|
|
47
|
+
Requires-Dist: fastapi>=0.110; extra == 'dev'
|
|
48
|
+
Requires-Dist: hypothesis>=6.140; extra == 'dev'
|
|
49
|
+
Requires-Dist: mcp<3,>=2; extra == 'dev'
|
|
50
|
+
Requires-Dist: pytest-asyncio>=1.2; extra == 'dev'
|
|
51
|
+
Requires-Dist: pytest>=9; extra == 'dev'
|
|
52
|
+
Requires-Dist: redis>=5; extra == 'dev'
|
|
53
|
+
Requires-Dist: ruff>=0.15; extra == 'dev'
|
|
54
|
+
Requires-Dist: sse-starlette>=3.0; extra == 'dev'
|
|
55
|
+
Requires-Dist: uvicorn[standard]>=0.29; extra == 'dev'
|
|
56
|
+
Provides-Extra: dns
|
|
57
|
+
Requires-Dist: dnspython>=2.6; extra == 'dns'
|
|
58
|
+
Provides-Extra: mcp
|
|
59
|
+
Requires-Dist: mcp<3,>=2; extra == 'mcp'
|
|
60
|
+
Provides-Extra: redis
|
|
61
|
+
Requires-Dist: redis>=5; extra == 'redis'
|
|
62
|
+
Provides-Extra: server
|
|
63
|
+
Requires-Dist: fastapi>=0.110; extra == 'server'
|
|
64
|
+
Requires-Dist: mcp<3,>=2; extra == 'server'
|
|
65
|
+
Requires-Dist: sse-starlette>=3.0; extra == 'server'
|
|
66
|
+
Requires-Dist: uvicorn[standard]>=0.29; extra == 'server'
|
|
67
|
+
Description-Content-Type: text/markdown
|
|
68
|
+
|
|
69
|
+
# WebAgent Protocol
|
|
70
|
+
|
|
71
|
+
[](https://github.com/varadganjoo/WebAgent-Protocol/actions/workflows/ci.yml)
|
|
72
|
+
[](https://pypi.org/project/webagent-protocol/)
|
|
73
|
+
[](https://github.com/varadganjoo/WebAgent-Protocol/blob/main/pyproject.toml)
|
|
74
|
+
[](https://github.com/varadganjoo/WebAgent-Protocol/blob/main/LICENSE)
|
|
75
|
+
[](https://github.com/varadganjoo/WebAgent-Protocol/blob/main/docs/mcp_extension.md)
|
|
76
|
+
|
|
77
|
+
**An open MCP extension for the open web. AI agents can discover, verify, and safely use the tools
|
|
78
|
+
that any website publishes, starting from nothing but its domain name.**
|
|
79
|
+
|
|
80
|
+
MCP connects a model to tools you have installed. WebAgent Protocol (WAP) lets the model find tools on sites
|
|
81
|
+
it has never seen:
|
|
82
|
+
|
|
83
|
+
- **Discovery.** A website publishes a signed manifest at `/.well-known/wap.json`.
|
|
84
|
+
- **Native tools.** Claude, Cursor, Codex, or any other MCP host gets the site's capabilities as native tools.
|
|
85
|
+
- **Signed results.** Every answer is signed by the business, so a quoted price is provably the business's
|
|
86
|
+
price.
|
|
87
|
+
- **Protection for the business.** Proof-of-work and rate limits stop bots from draining the business's AI
|
|
88
|
+
budget.
|
|
89
|
+
- **Protection for the user.** Actions that change something or spend money are confirmed with the user,
|
|
90
|
+
and built-in loop protection stops two AIs from talking in circles forever.
|
|
91
|
+
|
|
92
|
+
Free and open source (MIT). Python 3.11+. It's a library: you install it and build on it, and you choose how
|
|
93
|
+
strict every protection is and where the state lives.
|
|
94
|
+
|
|
95
|
+
<p align="center">
|
|
96
|
+
<img src="https://raw.githubusercontent.com/varadganjoo/WebAgent-Protocol/main/docs/assets/shopper_demo.svg" alt="A shopper agent discovers a bakery's agent, verifies its signature, solves a proof-of-work challenge, negotiates a bulk price over three rounds and receives a signed reservation token" width="760">
|
|
97
|
+
</p>
|
|
98
|
+
|
|
99
|
+
## One function, three ways in
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
from wap.server import WAPServer
|
|
103
|
+
|
|
104
|
+
wap = WAPServer(name="Golden Crust Bakery", domain="bakery.example", private_key=KEY, require_pow=True)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
@wap.action(description="Units of a pastry available right now.", effects="read")
|
|
108
|
+
async def check_pastry_stock(item: str) -> StockLevel: ...
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
wap.mount(app) # your FastAPI app
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
That single decorator publishes:
|
|
115
|
+
|
|
116
|
+
| Endpoint | Who uses it | What they get |
|
|
117
|
+
|---|---|---|
|
|
118
|
+
| `/.well-known/wap.json` | any agent, crawler, or registry | a signed manifest: tools, JSON Schemas, public key, policies |
|
|
119
|
+
| `/mcp` | **any MCP client**, unchanged | standard MCP tools, with signed results and WAP metadata in `_meta` |
|
|
120
|
+
| `/wap/v1/interact` | WAP clients and the `wap-mcp` bridge | signed envelopes, proof-of-work, SSE streaming, multi-turn sessions |
|
|
121
|
+
|
|
122
|
+
## How it relates to MCP and A2A
|
|
123
|
+
|
|
124
|
+
| | MCP | A2A | **WebAgent Protocol** |
|
|
125
|
+
|---|---|---|---|
|
|
126
|
+
| Main job | connect a model host to tools it has been configured with | structured tasks between autonomous agents | let hosts **find and safely use tools that websites publish** |
|
|
127
|
+
| How a server is found | configured by the user | agent card at a well-known URL | signed manifest at `/.well-known/wap.json` that links to the site's MCP endpoint |
|
|
128
|
+
| Relationship to WAP | WAP **extends** it: WAP tools *are* MCP tools, and extra guarantees ride in `_meta` and a declared extension | complementary | — |
|
|
129
|
+
|
|
130
|
+
WAP adds what an open-web setting needs and an installed-server setting can assume:
|
|
131
|
+
|
|
132
|
+
- **Replies you can prove.** Every reply is Ed25519-signed and bound to the domain.
|
|
133
|
+
- **Admission control.** Anyone can call without registering, but abuse costs the caller more than it costs
|
|
134
|
+
the business.
|
|
135
|
+
- **Bounded dialogues.** Conversations between agents are guaranteed to end.
|
|
136
|
+
|
|
137
|
+
The full proposal, written as an MCP Specification Enhancement Proposal, is in
|
|
138
|
+
[`docs/mcp_extension.md`](https://github.com/varadganjoo/WebAgent-Protocol/blob/main/docs/mcp_extension.md).
|
|
139
|
+
|
|
140
|
+
## Built for real deployments
|
|
141
|
+
|
|
142
|
+
Everything is configurable, and you bring your own infrastructure:
|
|
143
|
+
|
|
144
|
+
| Concern | What the library gives you |
|
|
145
|
+
|---|---|
|
|
146
|
+
| **Several workers or machines** | Pluggable state store: in-memory by default, or `RedisStore` for shared rate limits, replay protection, sessions and idempotency. It's tested with two server instances sharing one Redis. |
|
|
147
|
+
| **Your own rate limits** | Per-IP and per-agent-key limits, each tunable or disabled, plus an **admission hook** for tiers (for example, partners with high limits and no puzzles, logged-in customers, blocked keys). |
|
|
148
|
+
| **Abuse under load** | Proof-of-work whose difficulty can rise automatically with load (`AdaptivePow`). |
|
|
149
|
+
| **Retries without double-booking** | Idempotency keys, which the client adds automatically for anything that isn't read-only. A lost response is retried safely. |
|
|
150
|
+
| **Humans stay in control** | Each action declares `effects` (`read`, `write`, `financial`). Your agent asks the user before side effects (a `confirm` hook, or MCP elicitation in the bridge), and free-text requests can't trigger actions without that confirmation. |
|
|
151
|
+
| **Tool-poisoning defences** | Site-written descriptions are sanitised and labelled before a model sees them. Domain allow and block lists; private networks blocked by default in the bridge. |
|
|
152
|
+
| **Interoperable signatures** | RFC 8785 canonical JSON, with [test vectors](https://github.com/varadganjoo/WebAgent-Protocol/blob/main/docs/test-vectors.json) that an independent Node.js verifier checks in CI. |
|
|
153
|
+
| **Key management** | Key rotation that pinned clients follow automatically, optional trust-on-first-use, optional DNS TXT anchoring. |
|
|
154
|
+
| **Operations** | Observer hooks with logging and metrics helpers, a [deployment guide](https://github.com/varadganjoo/WebAgent-Protocol/blob/main/docs/deployment.md), and a real multi-worker [load test](https://github.com/varadganjoo/WebAgent-Protocol/blob/main/examples/load_test.py). |
|
|
155
|
+
|
|
156
|
+
See [`docs/configuration.md`](https://github.com/varadganjoo/WebAgent-Protocol/blob/main/docs/configuration.md) for every setting.
|
|
157
|
+
|
|
158
|
+
## Quickstart
|
|
159
|
+
|
|
160
|
+
### Install
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
pip install webagent-protocol # client + CLI
|
|
164
|
+
pip install "webagent-protocol[server]" # business side: FastAPI + /mcp endpoint
|
|
165
|
+
pip install "webagent-protocol[mcp]" # wap-mcp bridge for Claude, Cursor, Codex
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
To work from source: `git clone https://github.com/varadganjoo/WebAgent-Protocol && pip install -e ".[dev]"`.
|
|
169
|
+
The import name is `wap`.
|
|
170
|
+
|
|
171
|
+
### Run the demo
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
python examples/bakery_server.py # a bakery agent on http://localhost:8000
|
|
175
|
+
python examples/shopper_agent.py # discovers it, negotiates, reserves (screenshot above)
|
|
176
|
+
wap inspect localhost:8000 # the verified manifest and tool schemas
|
|
177
|
+
wap ask localhost:8000 "hold 2 almond croissants for Ada"
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
To watch a language model do the shopping instead, run [`examples/llm_agent.py`](https://github.com/varadganjoo/WebAgent-Protocol/blob/main/examples/llm_agent.py). It
|
|
181
|
+
needs `pip install "webagent-protocol[mcp]" openai python-dotenv` and `OPENAI_API_KEY` (optionally `OPENAI_LLM`)
|
|
182
|
+
in a `.env` file. The model discovers the bakery, gets its capabilities as tools, negotiates, and asks you
|
|
183
|
+
before it reserves anything:
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
python examples/llm_agent.py "Buy 12 sourdough croissants for Ada at the best price you can get"
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### Use it from Claude, Cursor, or Codex
|
|
190
|
+
|
|
191
|
+
**Option A: the bridge (any WAP site, discovered on demand).** Add `wap-mcp` as an MCP server. When the model
|
|
192
|
+
calls `wap_discover("bakery.example")`, the site's tools appear in its tool list as
|
|
193
|
+
`bakery_example__check_pastry_stock`, `bakery_example__reserve_item`, and so on. Before a tool that changes
|
|
194
|
+
something runs (`bakery_example__reserve_item`), the host shows the user a confirmation prompt.
|
|
195
|
+
|
|
196
|
+
```json
|
|
197
|
+
{
|
|
198
|
+
"mcpServers": {
|
|
199
|
+
"webagent": { "command": "wap-mcp", "env": { "WAP_CONFIRM": "write" } }
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
That is the config for Claude Desktop (`claude_desktop_config.json`) and Cursor (`.cursor/mcp.json`).
|
|
205
|
+
For the other hosts:
|
|
206
|
+
|
|
207
|
+
- **Claude Code:** `claude mcp add webagent -- wap-mcp`
|
|
208
|
+
- **Codex** (`~/.codex/config.toml`): `[mcp_servers.webagent]` with `command = "wap-mcp"`
|
|
209
|
+
- **Pre-loading sites:** use `wap-mcp bakery.example other.example` or `WAP_DOMAINS=...`, which is useful for
|
|
210
|
+
hosts that don't refresh tool lists.
|
|
211
|
+
|
|
212
|
+
**Option B: connect straight to one site's `/mcp`.** This is plain remote MCP, for example
|
|
213
|
+
`claude mcp add --transport http bakery https://bakery.example/mcp`.
|
|
214
|
+
|
|
215
|
+
The bridge's safety settings all have safe defaults and can be changed through environment variables:
|
|
216
|
+
|
|
217
|
+
- which actions need the user's approval (`WAP_CONFIRM`), and whether new sites need approval
|
|
218
|
+
(`WAP_APPROVE_SITES`);
|
|
219
|
+
- domain allow and block lists (`WAP_ALLOWED_DOMAINS`, `WAP_BLOCKED_DOMAINS`);
|
|
220
|
+
- private-network blocking;
|
|
221
|
+
- how instruction-like site text is handled;
|
|
222
|
+
- key pinning and auth tokens.
|
|
223
|
+
|
|
224
|
+
The full list is in [`docs/configuration.md`](https://github.com/varadganjoo/WebAgent-Protocol/blob/main/docs/configuration.md#mcp-bridge-wap-mcp).
|
|
225
|
+
|
|
226
|
+
### Use it from Python
|
|
227
|
+
|
|
228
|
+
```python
|
|
229
|
+
from wap import WAPClient
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
async def ask_user(request) -> bool: # your UI: called before any write/financial action
|
|
233
|
+
return input(f"Allow {request.summary()}? [y/N] ").lower() == "y"
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
async with WAPClient(confirm=ask_user, trust_on_first_use=True) as client:
|
|
237
|
+
manifest = await client.discover("bakery.example") # verified signature, domain, expiry
|
|
238
|
+
|
|
239
|
+
stock = await client.invoke("bakery.example", "check_pastry_stock", {"item": "Sourdough Croissant"})
|
|
240
|
+
print(stock.structured_data, stock.verified) # {'available': 24, ...} True
|
|
241
|
+
|
|
242
|
+
session = client.session("bakery.example") # multi-turn, state kept server-side
|
|
243
|
+
offer = await session.send(
|
|
244
|
+
capability_id="negotiate_bulk_price",
|
|
245
|
+
payload={"item": "Sourdough Croissant", "quantity": 12, "offered_unit_price": 3.6},
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
async for event in client.query("bakery.example", "Any croissants left?"): # SSE streaming
|
|
249
|
+
print(event.text or "", end="")
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### Already have an MCP server? Put it on the open web
|
|
253
|
+
|
|
254
|
+
```python
|
|
255
|
+
from mcp.server.mcpserver import MCPServer
|
|
256
|
+
from wap.server import WAPServer
|
|
257
|
+
|
|
258
|
+
tools = MCPServer("inventory") # your existing MCP server
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
@tools.tool()
|
|
262
|
+
def check_stock(sku: str) -> dict: ...
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
wap = WAPServer(name="Acme", domain="acme.example", private_key=KEY)
|
|
266
|
+
wap.include_mcp(tools) # its tools become signed, discoverable, abuse-protected
|
|
267
|
+
app = wap.create_app() # serves wap.json, /wap/v1/interact and /mcp
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
## Loop protection: no infinite loops between agents
|
|
271
|
+
|
|
272
|
+
When your assistant negotiates with a business's assistant, both are language models and neither is sure
|
|
273
|
+
when to stop. WAP bounds every conversation on **both** sides:
|
|
274
|
+
|
|
275
|
+
| Pattern | Example | Default limit |
|
|
276
|
+
|---|---|---|
|
|
277
|
+
| Same question, same answer | "Any croissants?" → "24 left" → "Any croissants?" … | 3 in a row |
|
|
278
|
+
| Ping-pong cycles | offer A → counter B → offer A → counter B … | cycles up to 3 turns, repeated 3 times |
|
|
279
|
+
| Stalls | the same offer again and again while only a round counter changes | 5 identical requests |
|
|
280
|
+
| Runaway sessions | endless turns | 100 per session (50 on the client, 40 in the bridge) |
|
|
281
|
+
|
|
282
|
+
How each side enforces it:
|
|
283
|
+
|
|
284
|
+
- **Fingerprints ignore cosmetic changes**, so "Any croissants??" and "any croissants" count as the same
|
|
285
|
+
request. A repeated question that gets a *changing* answer, such as polling stock, counts as progress.
|
|
286
|
+
- **The business** refuses to continue a loop *before* running any tool, returning `loop_detected` (409) or
|
|
287
|
+
`conversation_limit` (429).
|
|
288
|
+
- **The user's side** stops itself before sending, and counts error replies as replies.
|
|
289
|
+
- **In Claude or Cursor**, the model receives a tool error telling it to *stop, summarize, and report back to
|
|
290
|
+
the user*. In our [evaluation](https://github.com/varadganjoo/WebAgent-Protocol/blob/main/docs/evidence/agent-eval/summary.md), a model told to keep repeating a
|
|
291
|
+
lowball offer was stopped on its 6th call in 5 of 5 runs, and the business never received more than five
|
|
292
|
+
of its requests, even when the model ignored the stop instruction and kept trying.
|
|
293
|
+
|
|
294
|
+
All limits can be tuned with `ConversationPolicy`. The algorithm is in [spec §12.2](https://github.com/varadganjoo/WebAgent-Protocol/blob/main/docs/spec_rfc.md).
|
|
295
|
+
|
|
296
|
+
## Architecture
|
|
297
|
+
|
|
298
|
+
```mermaid
|
|
299
|
+
sequenceDiagram
|
|
300
|
+
autonumber
|
|
301
|
+
participant H as MCP host<br/>(Claude / Cursor / Codex)
|
|
302
|
+
participant Br as wap-mcp bridge
|
|
303
|
+
participant B as Business agent<br/>(WAPServer)
|
|
304
|
+
participant T as Business tools / LLM
|
|
305
|
+
|
|
306
|
+
H->>Br: wap_discover("bakery.example")
|
|
307
|
+
Br->>B: GET /.well-known/wap.json
|
|
308
|
+
B-->>Br: signed manifest
|
|
309
|
+
Note over Br: verify signature, domain & origin binding, expiry, pins
|
|
310
|
+
Br-->>H: tools/list_changed → bakery_example__reserve_item, …
|
|
311
|
+
H->>Br: bakery_example__reserve_item({...})
|
|
312
|
+
Note over Br: loop guard · JSON Schema validation
|
|
313
|
+
opt proof-of-work required
|
|
314
|
+
Br->>B: GET /wap/v1/challenge
|
|
315
|
+
Note over Br: solve SHA-256 puzzle
|
|
316
|
+
end
|
|
317
|
+
Br->>B: POST /wap/v1/interact (signed request)
|
|
318
|
+
Note over B: rate limit → signature → replay → PoW → auth → loop guard
|
|
319
|
+
B->>T: validated call (only now)
|
|
320
|
+
B-->>Br: SSE tokens + signed reply
|
|
321
|
+
Note over Br: verify reply against manifest key
|
|
322
|
+
Br-->>H: structured result + verification metadata
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
```text
|
|
326
|
+
wap/
|
|
327
|
+
├── spec/ models · crypto (Ed25519, canonical JSON) · pow (Hashcash) · conversation (loop guard)
|
|
328
|
+
├── server/ WAPServer + @action · router (WAP endpoints, SSE) · mcp_endpoint (/mcp) · mcp_import · rate_limiter
|
|
329
|
+
├── client/ resolver (discovery + verification) · session (WAPClient, WAPSession) · exceptions
|
|
330
|
+
├── mcp/ bridge (wap-mcp: built-in tools + dynamic per-site tools)
|
|
331
|
+
└── cli/ wap ask · inspect · verify · keygen · serve
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
## Security at a glance
|
|
335
|
+
|
|
336
|
+
- **Domain authenticity.** Manifests are signed and bound to the exact domain they were fetched from.
|
|
337
|
+
Endpoints must stay on that origin, discovery never follows redirects, and keys can be pinned.
|
|
338
|
+
- **Reply integrity.** Replies are verified against the *manifest* key and bound to the request. The test
|
|
339
|
+
suite includes a man-in-the-middle that rewrites prices; the client catches it.
|
|
340
|
+
- **Replay and session hijacking.** Requests are signed and time-bound, with a replay cache. Sessions belong to
|
|
341
|
+
the key that opened them, and negotiated quotes can only be redeemed in their own session.
|
|
342
|
+
- **Economic defence.** Challenges are stateless and single-use, and their difficulty can't be downgraded.
|
|
343
|
+
Requests are limited per IP and per agent key. Rejected traffic never reaches your code.
|
|
344
|
+
- **Side effects need consent.** Write and financial actions are confirmed with the user and carry
|
|
345
|
+
idempotency keys. Free-text requests are read-only unless confirmed.
|
|
346
|
+
- **Tool poisoning.** Site-written text is sanitised, truncated and labelled before any model sees it.
|
|
347
|
+
- **The `/mcp` endpoint** enables the MCP SDK's DNS-rebinding protection for the manifest's domain.
|
|
348
|
+
- **Signed means attributable, not safe.** Treat reply text as data, never as instructions.
|
|
349
|
+
|
|
350
|
+
## Documentation
|
|
351
|
+
|
|
352
|
+
| | |
|
|
353
|
+
|---|---|
|
|
354
|
+
| [`docs/configuration.md`](https://github.com/varadganjoo/WebAgent-Protocol/blob/main/docs/configuration.md) | Every setting for servers, clients and the bridge |
|
|
355
|
+
| [`docs/deployment.md`](https://github.com/varadganjoo/WebAgent-Protocol/blob/main/docs/deployment.md) | Keys, Redis and workers, proxies, capacity, monitoring |
|
|
356
|
+
| [`docs/spec_rfc.md`](https://github.com/varadganjoo/WebAgent-Protocol/blob/main/docs/spec_rfc.md) | WAP/1.0 specification: headers, errors, state machines, security |
|
|
357
|
+
| [`docs/test-vectors.json`](https://github.com/varadganjoo/WebAgent-Protocol/blob/main/docs/test-vectors.json) | Fixed keys, documents, canonical bytes and signatures for other implementations |
|
|
358
|
+
| [`docs/mcp_extension.md`](https://github.com/varadganjoo/WebAgent-Protocol/blob/main/docs/mcp_extension.md) | The MCP extension proposal (`io.webagent/wap`) |
|
|
359
|
+
| [`docs/whitepaper.md`](https://github.com/varadganjoo/WebAgent-Protocol/blob/main/docs/whitepaper.md) | *Beyond Scraping*: motivation, design, and an evaluation with a real model |
|
|
360
|
+
| [`docs/evidence/`](https://github.com/varadganjoo/WebAgent-Protocol/blob/main/docs/evidence/README.md) | Every measurement behind the whitepaper, with agent transcripts and how to reproduce them |
|
|
361
|
+
| [`CHANGELOG.md`](https://github.com/varadganjoo/WebAgent-Protocol/blob/main/CHANGELOG.md) · [`CONTRIBUTING.md`](https://github.com/varadganjoo/WebAgent-Protocol/blob/main/CONTRIBUTING.md) · [`SECURITY.md`](https://github.com/varadganjoo/WebAgent-Protocol/blob/main/SECURITY.md) | Project docs |
|
|
362
|
+
|
|
363
|
+
## What we measured
|
|
364
|
+
|
|
365
|
+
We ran a real model (`gpt-6-luna`) against a live bakery server in Docker, with nothing mocked
|
|
366
|
+
([results](https://github.com/varadganjoo/WebAgent-Protocol/blob/main/docs/evidence/agent-eval/summary.md), [method](https://github.com/varadganjoo/WebAgent-Protocol/blob/main/docs/evidence/README.md)):
|
|
367
|
+
|
|
368
|
+
| | Result |
|
|
369
|
+
|---|---|
|
|
370
|
+
| Stock-and-price question | all strategies 10/10 correct; WAP used **4.8× fewer** billed input tokens than raw HTML, but **1.7× more** than tag-stripped text |
|
|
371
|
+
| Negotiate and reserve | **5/5** reserved at the negotiated price, every reply signature-verified |
|
|
372
|
+
| User declines | **0 holds** in 10/10 runs (client `confirm` hook and `wap-mcp` elicitation) |
|
|
373
|
+
| Agent told to keep repeating an offer | stopped on the **6th call** in 5/5 runs; the business executed at most 5 |
|
|
374
|
+
| Throughput, 4 workers + Redis | about **600 signed, proof-of-work-gated requests/s** on a laptop, replays accepted exactly once |
|
|
375
|
+
|
|
376
|
+
Tokens are not WAP's main argument: on a small page a text scraper is cheaper for a read-only question.
|
|
377
|
+
The difference is that the WAP agent can act, safely. The [whitepaper](https://github.com/varadganjoo/WebAgent-Protocol/blob/main/docs/whitepaper.md#6-evaluation) has
|
|
378
|
+
the details and limitations; `docker build -f evals/Dockerfile -t wap-eval .` reproduces everything.
|
|
379
|
+
|
|
380
|
+
## Development
|
|
381
|
+
|
|
382
|
+
```bash
|
|
383
|
+
pip install -e ".[dev]"
|
|
384
|
+
pytest -q # full suite; Redis and Node.js tests run when installed
|
|
385
|
+
ruff check . && ruff format --check .
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
The suite covers:
|
|
389
|
+
|
|
390
|
+
- the official MCP client talking to `/mcp` over streamable HTTP;
|
|
391
|
+
- two server instances sharing a real Redis;
|
|
392
|
+
- property-based fuzzing, and canonical JSON cross-checked against Node.js;
|
|
393
|
+
- adversarial cases: forged or re-keyed manifests, tampered replies, replays, session hijacking, poisoned tool
|
|
394
|
+
descriptions, lost responses and double-booking, and looping agents.
|
|
395
|
+
|
|
396
|
+
`python examples/load_test.py --workers 4 --redis-url redis://...` runs a real multi-process load test. Contributions are welcome; see
|
|
397
|
+
[CONTRIBUTING.md](https://github.com/varadganjoo/WebAgent-Protocol/blob/main/CONTRIBUTING.md).
|
|
398
|
+
|
|
399
|
+
## License
|
|
400
|
+
|
|
401
|
+
MIT © Varad Ganjoo. Free to use, modify, and ship.
|