VCR代理商
🚀 现在可用 PyPI 和 ! 安装时使用pip install agent-vcr或npm install @agent-vcr/core.
记录、回放和区分MCP交互——就像AI代理的VCR。
在没有不稳定的实时服务器的情况下测试MCP服务器和客户端。 用于测试的模拟MCP:录制一次,永远重播。CI中不再有“MCP服务器宕机”或“速率限制”——确定性、快速、离线。
 ](https://pypi.org/project/agent-vcr/) ](https://www.npmjs.com/package/@agent-vcr/core)   ](https://nodejs.org/)
Agent VCR是一个测试框架 模型上下文协议(MCP)它透明地记录MCP客户端和服务器之间的所有JSON-RPC 2.0交互,然后确定性地重放它们——不需要真正的服务器。 比自己开玩笑更容易: 一个安装,一个录制命令,一个回放命令。几秒钟内的金色卡带。
Python和TypeScript是一流的。 Python实现有250多个测试和一个完整的CLI;TypeScript实现有72个单元测试、完整的CLI,并作为 @agent-vcr/core 在npm上——非常适合大多数MCP服务器和客户端所在的TypeScript优先的MCP生态系统。录音是跨语言的:用Python录音,用TypeScript重放(或者反过来)。看 typescript/README.md.
问题
如果你正在构建MCP服务器或客户端,你遇到了这些问题:
“我的测试很不稳定,因为它们依赖于实时服务器。” 外部MCP服务器停机、速率限制或每次运行返回不同的结果。CI管道失败的原因与代码无关。
“如果不破坏服务器,我就无法测试错误处理。” 您如何验证您的客户端处理超时、格式错误的响应或服务器崩溃?您需要修改服务器本身,或者只是希望最好。
“我寄了一张破钞,但没收到。” 您更新了MCP服务器,下游客户端发生故障。无法检测到这一点 tools/call 开始返回不同的模式,直到用户提交了错误。
“针对真实API的测试既缓慢又昂贵。” 每次测试运行都会到达真实的服务器,等待真实的响应,并消耗掉API配额。一个需要几秒钟的测试套件需要几分钟的时间。
VCR代理商如何解决这个问题
在真实服务器上记录一次MCP交互,并将其另存为 .vcr 卡带,并永远重放它们:
Record (once) Replay (every test run)
───────────── ─────────────────────────
Client ←→ Agent VCR ←→ Real Server Client ←→ Agent VCR (mock)
│ │
└──→ session.vcr ────────────────────┘- 确定性的:每次输入相同,输出相同
- 快速:无网络呼叫,即时响应
- 离线:测试在没有服务器访问权限的情况下运行
- 安全:在不修改真实服务器的情况下注入错误
- 可见的:在发货前区分两个记录以捕捉回归
结果: 曾经缓慢而不稳定的CI(实时MCP服务器、超时、速率限制)变得快速而确定——在几秒钟内运行,在部署前捕获破坏性的更改。
真实世界用例
开源MCP服务器作者: 船a .vcr 使用服务器的盒式磁带,这样用户就可以在不安装或运行服务器的情况下运行他们的客户端测试——这是其他人无法实现的分发故事。 拥有多代理系统的企业: 许多AI代理与许多MCP服务器通信?当服务器团队A推送一个新版本时,diff功能会在生产之前捕捉到破坏性的更改。平台团队使用Agent VCR来控制部署。 CI/CD: 不再因为MCP服务器宕机、速率受限或运行缓慢而进行不稳定的测试。录制金色录音带;测试以毫秒为单位运行,每次都是确定性的。 成本控制: 调用付费API的MCP服务器?记录一次——永远不要在测试中再次消耗配额。
真实世界的例子
1.金盒测试
记录“已知良好”会话,提交 .vcr 将文件保存到您的仓库中,并在CI中重放。如果您的代码更改破坏了交互模式,测试将立即失败。
# Record the golden cassette (once, using the included demo server)
agent-vcr record --transport stdio --server-command "python demo/servers/calculator_v1.py" -o cassettes/golden.vcr
# Every CI run replays it
pytest tests/ --vcr-dir=cassettes2.MCP服务器兼容性门
在部署新的服务器版本之前,记录新旧版本,然后记录差异:
agent-vcr record --transport stdio --server-command "python demo/servers/calculator_v1.py" -o v1.vcr
agent-vcr record --transport stdio --server-command "python demo/servers/calculator_v2.py" -o v2.vcr
agent-vcr diff v1.vcr v2.vcr --fail-on-breaking如果 tools/call 更改了响应模式,或者删除了一个方法,diff会捕获它并以代码1退出——阻止部署。
3.弹性测试的错误注入
使用响应覆盖来模拟故障,而无需修改服务器:
replayer = MCPReplayer(recording)
# Inject a server error for request id=3
replayer.set_response_override(3, {
"jsonrpc": "2.0",
"id": 3,
"error": {"code": -32603, "message": "Internal server error"}
})
# Your client code should handle this gracefully
response = replayer.handle_request(request)
assert handle_error(response) == expected_fallback4.线下开发
在飞机上工作?在WiFi不好的咖啡店?事先记录您的MCP服务器交互,并根据回放进行开发:
# Before going offline
agent-vcr record --transport sse --server-url http://localhost:3000/sse -o dev-session.vcr
# While offline — full mock server on port 3100
agent-vcr replay --file dev-session.vcr --transport sse --port 31005.多智能体回归测试
当多个AI代理共享MCP基础设施时,一个代理的服务器更改可能会破坏另一个代理。Agent VCR允许每个团队维护自己的磁带并独立运行兼容性检查。
6.协议演进跟踪
随着MCP规范的发展,使用差异来跟踪服务器在协议版本之间的行为变化:
result = MCPDiff.compare("mcp-2024-11.vcr", "mcp-2025-03.vcr")
print(f"Added methods: {len(result.added_interactions)}")
print(f"Breaking changes: {len(result.breaking_changes)}")快速开始
初次接触VCR探员? 跟随 实践教程 --8个动手实验室,涵盖每个用例和真实命令。
安装
python
# Recommended
uv pip install agent-vcr
# Or with pip
pip install agent-vcrTypes/Node.js:
npm install @agent-vcr/core
# or
pnpm add @agent-vcr/core录制会话
# Record stdio-based MCP server (try it now with the included demo server)
agent-vcr record --transport stdio --server-command "python demo/servers/calculator_v1.py" -o session.vcr
# Record SSE-based MCP server (replace URL with your server)
agent-vcr record --transport sse --server-url http://localhost:3000/sse -o session.vcr作为模拟服务器重播
# Replay via stdio (pipe to your client)
agent-vcr replay --file session.vcr --transport stdio
# Replay via HTTP+SSE
agent-vcr replay --file session.vcr --transport sse --port 3100Replay a recording as mock server
区分两个录音
agent-vcr diff baseline.vcr current.vcr
agent-vcr diff baseline.vcr current.vcr --format json --fail-on-breaking索引和搜索许多磁带
agent-vcr index recordings/ -o index.json
agent-vcr search index.json --method tools/list
agent-vcr search index.json --endpoint-id github批次差异
# pairs.json: {"pairs": [{"baseline": "v1.vcr", "current": "v2.vcr"}, ...]}
agent-vcr diff-batch pairs.json --fail-on-breaking验证、合并和分析
# Validate a recording's schema and structure
agent-vcr validate session.vcr
# Merge multiple recordings into one
agent-vcr merge session1.vcr session2.vcr -o combined.vcr --deduplicate
# Show statistics (method distribution, latency percentiles, error rate)
agent-vcr stats session.vcr检查记录
agent-vcr inspect session.vcr
agent-vcr inspect session.vcr --format table比赛策略
重放器支持5种匹配策略来查找记录的响应:
| 策略 | 描述 | 用例 |
|---|---|---|
exact | 完全JSON匹配(不包括jsonrpc和id字段) | 最严格的测试 |
method | 仅按方法名称匹配 | 广泛匹配 |
method_and_params | 匹配方法+完整参数 *(默认)* | 标准测试 |
subset | 匹配方法+部分参数(子集) | 灵活测试 |
sequential | 按顺序返回交互 | 有序回放 |
*注: fuzzy 该策略已被弃用;使用 subset 相反。 fuzzy 为了向后兼容,保留为别名。*
重播者功能
重放器支持延迟模拟以进行真实测试:
# Simulate latency during replay
agent-vcr replay --file session.vcr --simulate-latency
# Scale recorded latencies (1.0 = original, 2.0 = double)
agent-vcr replay --file session.vcr --simulate-latency --latency-multiplier 2.0差异特征
增强的差异功能:
# Compare latency between recordings
agent-vcr diff baseline.vcr current.vcr --compare-latency立即尝试
回购随附样品 .vcr 卡带,以便您可以立即尝试CLI:
# Inspect a recording
agent-vcr inspect examples/recordings/calculator-v1.vcr
# Diff two server versions — spot the new tool and schema changes
agent-vcr diff examples/recordings/calculator-v1.vcr examples/recordings/calculator-v2.vcr
# See error handling in action
agent-vcr inspect examples/recordings/calculator-errors.vcr样本盒包括:
| 文件 | 描述 | 交互 |
|---|---|---|
calculator-v1.vcr | 计算器MCP服务器v1--加、乘 | 3 |
calculator-v2.vcr | 计算器v2--添加除法工具+响应元数据 | 4 |
calculator-errors.vcr | 错误场景--除以零,找不到方法 | 4 |
程序化使用
手动创建录制
from datetime import datetime
from agent_vcr.core.format import (
JSONRPCRequest, JSONRPCResponse, VCRInteraction,
VCRMetadata, VCRRecording, VCRSession,
)
# Build the initialize handshake
init_req = JSONRPCRequest(id=0, method="initialize", params={
"protocolVersion": "2024-11-05",
"clientInfo": {"name": "my-client", "version": "1.0.0"},
})
init_resp = JSONRPCResponse(id=0, result={
"protocolVersion": "2024-11-05",
"serverInfo": {"name": "my-server", "version": "1.0.0"},
"capabilities": {"tools": {}},
})
# Build an interaction
interaction = VCRInteraction(
sequence=0,
timestamp=datetime.now(),
direction="client_to_server",
request=JSONRPCRequest(id=1, method="tools/list", params={}),
response=JSONRPCResponse(id=1, result={
"tools": [{"name": "echo", "description": "Echo a message"}]
}),
latency_ms=12.5,
)
# Assemble and save
recording = VCRRecording(
metadata=VCRMetadata(
version="1.0.0",
recorded_at=datetime.now(),
transport="stdio",
),
session=VCRSession(
initialize_request=init_req,
initialize_response=init_resp,
interactions=[interaction],
),
)
recording.save("session.vcr")在代码中回放
from agent_vcr.core.format import VCRRecording
from agent_vcr.replayer import MCPReplayer
recording = VCRRecording.load("session.vcr")
replayer = MCPReplayer(recording, match_strategy="method_and_params")
response = replayer.handle_request({
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list",
"params": {}
})
print(response) # Returns the recorded response录音困难
from agent_vcr.diff import MCPDiff
result = MCPDiff.compare("baseline.vcr", "current.vcr")
if result.is_identical:
print("No changes!")
elif result.is_compatible:
print(f"Compatible changes: {len(result.modified_interactions)} modified")
else:
print("Breaking changes detected!")
for change in result.breaking_changes:
print(f" - {change}")Pytest集成
Agent VCR包括一个用于无缝测试集成的pytest插件。
使用夹具
import pytest
@pytest.mark.vcr("cassettes/test_tools_list.vcr")
def test_tools_list(vcr_replayer):
"""Test that tools/list returns expected tools."""
response = vcr_replayer.handle_request({
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list",
"params": {}
})
assert "result" in response
assert len(response["result"]["tools"]) > 0使用异步上下文管理器
from agent_vcr.pytest_plugin import vcr_cassette
async def test_with_cassette():
async with vcr_cassette("my_test.vcr") as cassette:
response = cassette.replayer.handle_request({
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {"name": "echo", "arguments": {"message": "hello"}}
})
assert response["result"]["content"][0]["text"] == "hello"CLI选项
pytest --vcr-record # Record new cassettes
pytest --vcr-dir=my_cassettes # Custom cassette directoryVCR文件格式
录制使用基于JSON的 .vcr 格式:
{
"format_version": "1.0.0",
"metadata": {
"version": "1.0.0",
"recorded_at": "2026-02-07T10:30:00",
"transport": "stdio",
"client_info": {"name": "claude-desktop"},
"server_info": {"name": "my-mcp-server"},
"tags": {"env": "staging"}
},
"session": {
"initialize_request": { "jsonrpc": "2.0", "id": 0, "method": "initialize", "params": {} },
"initialize_response": { "jsonrpc": "2.0", "id": 0, "result": { "capabilities": {} } },
"capabilities": {},
"interactions": [
{
"sequence": 0,
"timestamp": "2026-02-07T10:30:05",
"direction": "client_to_server",
"request": { "jsonrpc": "2.0", "id": 1, "method": "tools/list", "params": {} },
"response": { "jsonrpc": "2.0", "id": 1, "result": { "tools": [] } },
"latency_ms": 12.5
}
]
}
}Python vs TypeScript
Python实现是 完整并经过测试 (250+次测试)。Types/Node.js端口反映了相同的架构,并具有 完整的单元测试套件 (72次测试)。
| 特性 | Python | TypeScript |
|---|---|---|
| 状态 | 生产就绪 | 72个单元测试,源代码完成 |
| 测试 | 250多个测试通过 | 72个单元测试 tests/unit/ |
| CLI | 功能齐全 | 功能齐全 |
| 测试框架 | pytest插件 | Jest/Vitest(回放模式) |
| 录制格式 | .vcr (JSON) | .vcr (JSON)--格式相同 |
| 集成中的记录模式 | 已实施 | 计划用于v0.2.0 |
跨语言录音: 这 .vcr 格式是纯JSON,因此Python创建的记录可以通过TypeScript实现加载。
缩放(多MCP,代理到代理)
我们支持 多MCP 和 代理人对代理人:录制多个会话(一个 .vcr 每客户端↔服务器会话),用标签标记每个会话 --session-id, --endpoint-id,以及 --agent-id,并在测试或工具中关联它们。 索引 (agent-vcr index, agent-vcr search)以及 批量差异 (agent-vcr diff-batch)让你在许多磁带上工作。有关设计和代理到代理模式,请参见 docs/scaling.md.
示例——相关性元数据(带有端点/会话ID的记录,inspect显示它们):
建筑
看 docs/architecture.md 用于整个系统设计、数据流图和设计决策。
python
python/src/agent_vcr/
├── core/
│ ├── format.py # Pydantic models for .vcr format
│ ├── matcher.py # Request matching strategies
│ └── session.py # Session lifecycle management
├── transport/
│ ├── base.py # Abstract transport interface
│ ├── stdio.py # Subprocess stdio proxy
│ └── sse.py # HTTP+SSE proxy
├── recorder.py # Transparent recording proxy
├── replayer.py # Mock server from recordings
├── diff.py # Recording comparison engine
├── indexer.py # Index/search many .vcr files
├── cli.py # Command-line interface
└── pytest_plugin.py # Pytest integrationTypeScript:
typescript/src/
├── core/
│ ├── format.ts # Zod schemas for .vcr format
│ ├── matcher.ts # Request matching strategies
│ └── session.ts # Session lifecycle management
├── transport/
│ ├── base.ts # Abstract transport interface
│ ├── stdio.ts # Subprocess stdio proxy
│ └── sse.ts # HTTP+SSE proxy
├── recorder.ts # Transparent recording proxy
├── replayer.ts # Mock server from recordings
├── diff.ts # Recording comparison engine
├── cli.ts # Command-line interface
└── integrations/
├── jest.ts # Jest integration
└── vitest.ts # Vitest integration发展
python
# Clone and install
git clone https://github.com/jarvis2021/agent-vcr.git
cd agent-vcr/python
# Setup with uv (recommended)
uv venv
source .venv/bin/activate
uv pip install -e ".[dev]"
# Run tests
pytest tests/ -v
# Run with coverage
pytest tests/ --cov=src/agent_vcr --cov-report=html
# Lint
ruff check src/
# Type check
mypy src/TypeScript
cd agent-vcr/typescript
npm install
npm run build
npm test创建演示GIF
- 记录 (上图):
assets/lab-1-record.gif--来自实验室1(make-lab-gifs.sh 1)那么agg demo/lab-1.cast assets/lab-1-record.gif. - 回放 (上图):
assets/lab-2-replay.gif--来自实验室2(asciinema rec demo/lab-2.cast -c "bash demo/make-lab-gifs.sh 2")那么agg demo/lab-2.cast assets/lab-2-replay.gif. - 差异 (真实世界的例子):
assets/lab-3-diff.gif. 相关性:assets/correlation-demo.gif通过demo/record-correlation-demo.sh.
运行所有测试(Python+TypeScript)
从repo根目录:
cd python && uv run pytest tests/ -v贡献
欢迎投稿!请参阅 docs/architecture.md 用于系统设计上下文和 贡献.md 作为指导方针。
