见证
⚠️ 阿尔法 --积极发展。可能会发生重大变化。
Witness是一个MCP服务器,它使AI代理能够记录、回放和比较HTTP API交互。
将其视为REST API的飞行记录器——由您的AI代理控制,而不是由您控制。每个请求和响应都被捕获为一个结构化的、可重放的工件,可以与任何其他记录进行区分。
记录生产中的请求,包括每个出站HTTP调用及其响应。在本地重播,并从录制中删除所有外部依赖项。这个bug在第一次尝试时就会复制。迁移差异是自动的。无需编写测试脚本,也无需维护模拟。
______________________________________________________________________
为什么它存在
立即、确定性地再现生产错误
当一个bug出现在生产环境中时,在本地复制它是最困难的部分。请求取决于特定的数据、时间和来自开发环境中不存在的外部服务的响应。
有了见证,你 在生产中记录失败的请求 -包括API发出的每个出站HTTP调用及其收到的响应。那你呢 在本地重播 从记录中删除所有外部依赖项。相同的请求,相同的数据,相同的第三方响应。每次第一次尝试时,虫子都会繁殖。
Production (record) Dev (replay)
┌──────────────┐ ┌──────────────┐
│ POST /orders│ │ POST /orders│
│ + payment API response: 402 │ + payment API → 402 (from recording)
│ + inventory API response: 200 │ + inventory API → 200 (from recording)
│ = 500 Internal Server Error │ = 500 Internal Server Error ← reproduced
└──────────────┘ └──────────────┘没有嘲讽框架。无测试夹具。不知道外部服务返回了什么。录音 是 repro案。
用证据验证API迁移
手动测试API迁移、版本升级和后端替换是单调乏味且容易出错的。证人自动化了证据收集:
- 记录的行为 老的 系统。
- 对以下对象重播相同的请求 新 系统。
- 逐个字段比较响应。
没有要编写的测试脚本。没有要维护的断言。AI代理通过四个工具调用来驱动整个工作流程。
______________________________________________________________________
运作原理
Witness作为您的AI代理(Claude、Copilot等)连接到的MCP服务器运行。代理调用Witness工具的方式与调用任何其他工具的方式相同——通过用自然语言描述它想要做什么。Witness处理HTTP执行、存储和差异。
┌──────────────┐ MCP tools ┌─────────────────────────┐
│ AI Agent │ ──────────────────────► │ Witness MCP Server │
│ (Claude, etc)│ │ │
└──────────────┘ │ witness/record ──────►│──► Legacy API
│ witness/replay ──────►│──► Modern API
│ witness/compare ───────│
│ witness/list ───────│
│ witness/inspect ───────│
│ │
│ Interaction Store │
│ witness-store/ │
│ sessions/ │
│ {session}/ │
│ interactions/ │
└─────────────────────────┘每个记录的交互都保存为JSON文件,并分配一个人类可读的 WitnessId:
legacy-create-order_POST_api-orders_ff3f6f9b_20260320T1125
└──── tag ────┘ └─method─┘ └──path──┘ └body hash┘ └timestamp┘同一个请求总是产生相同的ID,这使得记录可以引用并消除重复。
______________________________________________________________________
出站捕获和回放
Witness还包括一个ASP。NET核心库(Witness.AspNetCore)这使得 记录和重放出站HTTP调用 由您的API在请求处理过程中生成。
┌─── RECORD ──────────────────────────────────────────────┐
│ │
│ Inbound request → API processes it │
│ ├─ Outbound call #1 → real HTTP → response captured │
│ └─ Outbound call #2 → real HTTP → response captured │
│ All captured as Interaction.OutboundCalls │
│ │
└──────────────────────────────────────────────────────────┘
┌─── REPLAY ──────────────────────────────────────────────┐
│ │
│ Inbound request → API processes it │
│ ├─ Outbound call #1 → intercepted → recorded response │
│ └─ Outbound call #2 → intercepted → recorded response │
│ No real HTTP calls — fully deterministic │
│ │
└──────────────────────────────────────────────────────────┘这是由请求头驱动的:
X-Witness-Mode: record--正常执行出站呼叫并捕获响应X-Witness-Mode: replay+X-Witness-Id: {id}--带有记录响应的存根出站呼叫
整合
// Register outbound capture on an HttpClient
builder.Services.AddHttpClient("external-api")
.AddWitnessCapture(opt => opt.SessionId = "my-session");
// Enable the record/replay middleware
app.UseWitnessMiddleware(opt => opt.StorePath = "./witness-store");______________________________________________________________________
示例:验证API迁移
假设您正在将订单API从传统系统迁移到现代系统。模式已更改-- order_id 成为 orderId, status: "pending" 成为 state: "created" --但两个端点都接受相同的请求并返回HTTP 201。
在切换流量之前,您需要新的API正确处理请求的证据。
1.问你的人工智能代理
“在以下位置记录对传统服务的POST到/api/订单http://legacy:3001,然后在以下位置针对新服务重播http://modern:3002,并比较响应。"
2.代理人调用Witness工具
记录与传统:
witness/record
{
"target": "http://legacy:3001",
"method": "POST",
"path": "/api/orders",
"body": { "product_id": 1, "qty": 2 },
"options": { "tag": "create-order", "sessionId": "migration-validation" }
}{
"WitnessId": "create-order_POST_api-orders_ff3f6f9b_20260320T1125",
"StatusCode": 201,
"ResponseBody": { "order_id": 1001, "qty": 2, "total_price": 19.98, "status": "pending" }
}针对新服务重播:
witness/replay
{
"witnessId": "create-order_POST_api-orders_ff3f6f9b_20260320T1125",
"target": "http://modern:3002",
"options": { "sessionId": "migration-validation" }
}{
"ReplayWitnessId": "replay-create-order_POST_api-orders_ff3f6f9b_20260320T1125",
"StatusCode": 201,
"ResponseBody": { "orderId": 1001, "quantity": 2, "amount": 19.98, "currency": "USD", "state": "created" }
}比较:
witness/compare
{
"witnessId1": "create-order_POST_api-orders_ff3f6f9b_20260320T1125",
"witnessId2": "replay-create-order_POST_api-orders_ff3f6f9b_20260320T1125"
}{
"isMatch": false,
"summary": {
"statusCode": { "match": true, "original": 201, "replay": 201 },
"body": {
"match": false,
"diffCount": 5,
"diffs": [
{ "path": "order_id", "original": 1001, "replay": null },
{ "path": "orderId", "original": null, "replay": 1001 },
{ "path": "status", "original": "pending", "replay": null },
{ "path": "state", "original": null, "replay": "created" },
{ "path": "currency", "original": null, "replay": "USD" }
]
}
}
}代理人报告: *“这两项服务都返回201。架构按预期更改-- order_id → orderId, status → state,新服务增加了 currency 现场。没有数据丢失。"*
现在,你有了一个结构化的、可复制的记录,准确地记录了发生了什么变化。没有人工比较,没有猜测。
3.列出会议中记录的所有互动
witness/list
{ "sessionId": "migration-validation" }{
"SessionId": "migration-validation",
"Count": 2,
"Interactions": [
{ "WitnessId": "create-order_POST_...", "Method": "POST", "StatusCode": 201 },
{ "WitnessId": "replay-create-order_POST_...", "Method": "POST", "StatusCode": 201 }
]
}______________________________________________________________________
在Copilot聊天会话中使用Witness
一旦在VS Code中将Witness配置为MCP服务器,您就可以从Copilot Chat面板驱动整个工作流程,而无需编写一行测试代码。
下面是一个真实的会话,验证上面示例中相同顺序的API迁移。
______________________________________________________________________
你:
我需要验证API的新订单http://modern:3002与传统的相比,它的行为是正确的http://legacy:3001.首先,记录对旧服务的产品查找和订单创建,然后对新服务进行回放,并告诉我发生了什么变化。
______________________________________________________________________
副驾驶: 当然。我将记录两次与旧服务的交互,将其与新服务进行回放,并比较结果。
*召唤* witness/record *--GET/api/products/1关于传统*
✅ 200 OK--{ "id": 1, "name": "Widget", "unit_price": 9.99, "stock": 100 }证人ID:legacy-get-product_GET_api-products-1_00000000_20260320T1125
*召唤* witness/record *--POST/api/遗留订单*
✅ 201已创建--{ "order_id": 1001, "qty": 2, "total_price": 19.98, "status": "pending" }证人ID:legacy-create-order_POST_api-orders_ff3f6f9b_20260320T1125
*召唤* witness/replay *--在现代计算机上重放GET/api/products/1*
✅ 200 OK-- { "id": 1, "name": "Widget", "price": 9.99, "currency": "USD" }*召唤* witness/replay *--在现代计算机上重放POST/api/命令*
✅ 201已创建-- { "orderId": 1001, "quantity": 2, "amount": 19.98, "currency": "USD", "state": "created" }*召唤* witness/compare *--产品查询*
❌ 车身不匹配(4个差异):unit_price→price,stock远离的,currency添加
*召唤* witness/compare *--订单创建*
❌ 车身不匹配(5个差异):order_id→orderId,qty→quantity,total_price→amount,status远离的,state+currency添加
两个端点都返回正确的HTTP状态代码。 模式在传统和现代之间有意更改:
| 字段(传统) | 字段(现代) | 更改 |
|---|---|---|
unit_price | price | 重命名 |
stock | *(已删除)* | 不再暴露 |
| *(无)* | currency | 新领域 |
order_id | orderId | 重命名(camelCase) |
qty | quantity | 重命名 |
total_price | amount | 重命名 |
status: "pending" | state: "created" | 重命名+新增词汇 |
没有数据丢失,只是在不同的字段名称下保留了值。现代API还增加了 currency 作为一个新的必填字段。如果任何消费者依赖于旧字段名,则需要在您切换之前对其进行更新。
______________________________________________________________________
你:
很好。将此保存为会话“order-api-migration-v2”,并列出记录的所有内容。
______________________________________________________________________
副驾驶: *召唤* witness/list *--会话“order-api-migration-v2”*
Session: order-api-migration-v2 (6 interactions)
GET /api/products/1 200 legacy-get-product_GET_...
GET /api/products/1 200 replay-legacy-get-product_GET_...
POST /api/orders 201 legacy-create-order_POST_...
POST /api/orders 201 replay-legacy-create-order_POST_...所有交互都存储在 ./witness-store/sessions/order-api-migration-v2/。您可以通过以下方式检查任何单独的记录 witness/inspect 或随时重新运行比较。
______________________________________________________________________
这是一个完整的循环——从自然语言到结构化迁移证据——在一个聊天会话中,无需编写代码。
______________________________________________________________________
入门
1.建造
git clone https://github.com/pmilet/witness.git
cd witness
dotnet build src/Witness.slnx2.配置您的MCP客户端
克劳德桌面/克劳德代码 --添加到 claude_desktop_config.json 或 .claude/settings.json:
{
"mcpServers": {
"witness": {
"command": "dotnet",
"args": ["run", "--project", "/absolute/path/to/witness/src/Witness.McpServer/Witness.McpServer.csproj", "--no-build"]
}
}
}VS代码(GitHub副本) --添加到 .vscode/mcp.json:
{
"servers": {
"witness": {
"command": "dotnet",
"args": ["run", "--project", "/absolute/path/to/witness/src/Witness.McpServer/Witness.McpServer.csproj", "--no-build"]
}
}
}3.尝试演示API
cd demo
docker compose up demo-api -d
# The API is now running at http://localhost:5080
# Record an order (with outbound call to JSONPlaceholder):
curl -X POST http://localhost:5080/api/orders \
-H "Content-Type: application/json" \
-H "X-Witness-Mode: record" \
-d '{"productId": 1, "quantity": 2}'4.使用它
录音存储在 ./witness-store/ 相对于服务器运行的位置。会话组相关交互。将代理指向任何HTTP API并开始录制。
______________________________________________________________________
可用工具
| 工具 | 它做什么 |
|---|---|
witness/record | 执行HTTP请求并保存完整交互 |
witness/replay | 将录制的请求重新发送到其他目标 |
witness/compare | 逐场区分两个记录的相互作用 |
witness/list | 浏览会话及其交互 |
witness/inspect | 查看单个交互的完整细节 |
______________________________________________________________________
常见用例
生产缺陷再现 --记录生产中失败的请求(捕获所有出站呼叫响应)。在您的开发环境中重播它——同样的请求,同样的外部响应,第一次尝试时就会重现错误。没有嘲笑,没有猜测。
API迁移 --记录遗留行为,与新服务进行回放,进行比较。在切换流量之前,每个差异都是可见的。
版本升级验证 --对v1进行记录,对v2进行回放。证明兼容性或表面破坏性变化。
回归测试 --今天记录一个基线。在下次部署后重播。任何行为变化都会立即出现。
线下开发 -将与第三方API的交互记录一次,然后从记录中回放。没有网络,没有费率限制,没有成本。
出站依赖关系清除 -记录API的行为,包括所有出站HTTP调用。用从录音中删除的出站呼叫重播相同的请求。完全确定的离线测试。
______________________________________________________________________
存储库布局
src/ .NET 9.0 solution
Witness.Domain/ Core domain (Interaction, WitnessId, HttpRequest/Response)
Witness.Application/ CQRS commands and queries (Record, Replay, Inspect, List)
Witness.Infrastructure/ Storage, HTTP execution
Witness.AspNetCore/ ASP.NET Core library (outbound capture + record/replay middleware)
Witness.McpServer/ MCP server host
demo/
Witness.DemoApi/ Sample API demonstrating inbound + outbound capture
docker-compose.yml Docker setup for demo APIs
docs/ Documentation, spec, quickstart看 docs/QUICKSTART.md 获取详细的设置指南和 docs/witness-mcp-server-spec.md 为了获得完整的规格。
______________________________________________________________________
许可证
______________________________________________________________________
Every HTTP interaction is evidence. Witness captures it.
