Go中生产级MCP&A2A的实施
一个全面的、以教程为重点的实施,展示了以下产品的生产质量集成 模型上下文协议(MCP) 和 代理人对代理人(A2A) 具有完全可观察性、安全性和成本控制功能的协议。
内置于 Go服务器 以及互动 流线型UI 用于实践探索所有功能。
🎯 概述
此存储库展示了两个生产就绪用例:
- 多租户RAG管道(MCP):使用混合搜索(BM25+矢量)、JWT身份验证、速率限制和租户隔离进行安全文档搜索
- 成本控制研究助理(A2A):具有预算意识的研究代理,具有任务管理、实时流媒体和多层成本跟踪功能
✨ 主要特点
🔐 安全和多租户
- JWT认证:带有租户和用户声明的RS256令牌
- 多租户隔离:PostgreSQL中的行级安全性(RLS)
- 速率限制:Redis支持每租户请求限制
- 基于范围的授权:细粒度访问控制
🔍 搜索与检索
- 混合搜索:BM25(关键字)+向量(语义),具有互惠排名融合
- pg载体:使用HNSW索引进行高效的相似性搜索
- 文档管理:具有租户隔离的完整CRUD操作
- 分页:对大型结果集进行高效的基于光标的分页
💰 成本控制和预算
- 令牌跟踪:GPT-4、GPT-3.5、Claude的准确每次请求令牌计数
- 预算执行:飞行前检查防止超限
- 多层计划:基本(10美元)、专业(50美元)、企业(200美元)每月预算
- 成本归属:每个用户和每个任务的成本跟踪
📊 可观测性和监测
- 分布式跟踪:OpenTetry+Jaeger实现端到端请求可见性
- 指标:所有操作的Prometheus兼容指标
- 健康检查:所有服务的就绪性和活性探针
- 结构化日志记录:带有跟踪上下文传播的JSON日志
🚀 实时流媒体
- 服务器发送事件(SSE):实时任务更新
- 任务生命周期:待定→ 跑步→ 已完成/失败/取消
- 事件广播:任务状态更改的发布/子模式
🧪 测试覆盖率
- MCP服务器:95%的平均覆盖率,125+个单元测试
- A2A服务器:平均覆盖率92.6%,75+个单元测试
- 集成测试:Redis、数据库和中间件测试
- 总计:200+通过测试
🏗️ 建筑
┌─────────────────────────────────────────────────────────┐
│ Streamlit UI │
│ - Authentication & JWT token management │
│ - MCP RAG testing (hybrid search, documents) │
│ - A2A task creation & monitoring │
│ - Cost tracking & budget visualization │
│ - Metrics dashboards (Prometheus) │
│ - Distributed tracing (Jaeger) │
└─────────────────┬───────────────────────────────────────┘
│
┌───────────┴───────────┐
│ │
┌─────▼────────┐ ┌──────────▼──────────┐
│ MCP Server │ │ A2A Server │
│ Port 8080 │ │ Port 8081 │
│ │ │ │
│ - JSON-RPC │ │ - REST API │
│ - JWT Auth │ │ - Agent Cards │
│ - Hybrid │ │ - Task Management │
│ Search │ │ - SSE Streaming │
│ - Rate Limit │ │ - Cost Tracking │
└─────┬────────┘ └─────────┬───────────┘
│ │
┌───┴───┬────────┬─────────┴─────┬──────────┐
│ │ │ │ │
┌─▼──┐ ┌─▼───┐ ┌──▼──────┐ ┌─────▼────┐ ┌──▼──────┐
│PG │ │Redis│ │ Jaeger │ │Prometheus│ │ Grafana │
│+pgv│ │ │ │ Tracing │ │ Metrics │ │Dashboard│
└────┘ └─────┘ └─────────┘ └──────────┘ └─────────┘📁 项目结构
.
├── mcp-server/ # Go MCP server (95% coverage)
│ ├── cmd/server/main.go # Entry point
│ ├── internal/
│ │ ├── auth/ # JWT validation (93.1% coverage)
│ │ ├── database/ # PostgreSQL + pgvector
│ │ ├── protocol/ # JSON-RPC 2.0 (100% coverage)
│ │ ├── tools/ # MCP tools (97.4% coverage)
│ │ ├── middleware/ # Logging, rate limiting (92.9%)
│ │ └── server/ # HTTP server (94.8% coverage)
│ ├── Dockerfile # Multi-stage build
│ └── go.mod
│
├── a2a-server/ # Go A2A server (92.6% coverage)
│ ├── cmd/server/main.go # Entry point with 3 capabilities
│ ├── internal/
│ │ ├── protocol/ # A2A types (100% coverage)
│ │ ├── agentcard/ # Agent Card store (100% coverage)
│ │ ├── tasks/ # Task lifecycle (98.3% coverage)
│ │ ├── cost/ # Cost tracking (91.5% coverage)
│ │ └── server/ # HTTP + SSE server (81.8%)
│ ├── Dockerfile
│ └── go.mod
│
├── streamlit-ui/ # Interactive testing UI
│ ├── app.py # Main dashboard
│ ├── pages/
│ │ ├── 1_🔐_Authentication.py # JWT generation & testing
│ │ ├── 2_📄_MCP_RAG.py # Hybrid search, documents
│ │ ├── 3_🤖_A2A_Tasks.py # Task creation & monitoring
│ │ ├── 4_💰_Cost_Tracking.py # Budget analytics
│ │ ├── 5_📊_Metrics.py # Prometheus dashboards
│ │ └── 6_🔍_Tracing.py # Jaeger integration guide
│ ├── utils/
│ │ ├── mcp_client.py # JSON-RPC 2.0 client
│ │ ├── a2a_client.py # REST + SSE client
│ │ └── auth.py # JWT token generation
│ ├── Dockerfile
│ └── requirements.txt
│
├── docker compose.yml # Complete local stack
├── README.md # This file
├── DESIGN.md # Detailed architecture
└── go.work # Go workspace🚀 快速开始
先决条件
- 码头工人 & Docker Compose (必填)
- 转到1.23+ (用于地方发展)
- Python 3.11+ (用于Streamlit UI开发)
用Docker Compose开始一切
# Clone the repository
git clone
cd mcp-a2a-go
# Start all services (PostgreSQL, Redis, Jaeger, Prometheus, MCP, A2A, Streamlit)
docker compose up --build
# Wait for services to be healthy (check logs)
# When you see "Streamlit UI available at http://localhost:8501"访问服务:
- 流线型UI: http://localhost:8501(交互式测试仪表板)
- MCP服务器: http://localhost:8080(JSON-RPC端点:/mcp)
- A2A服务器: http://localhost:8081(REST API)
- 猎手: http://localhost:16686(分布式跟踪)
- 普罗米修斯: http://localhost:9090(指标)
- 格拉法纳: http://localhost:3000(仪表板-管理员/管理员)
使用Streamlit UI
Streamlit UI为测试所有功能提供了一个完整的交互环境:
1. 🔐 认证页面
- 为3个演示租户(acme corp、globex、initech)生成JWT代币
- 配置作用域(读、写、管理)
- 测试令牌验证
- 查看已解码的令牌声明
2. 📄 MCP RAG页面
- 初始化MCP会话
- 列出可用工具
- 使用可调BM25/向量权重测试混合搜索
- 列出带页码的文档
- 检索特定文档
- 验证多租户隔离
3. 🤖 A2A任务页面
- 查看具有功能的代理卡
- 为3个功能创建任务:
- search_papers:搜索学术论文 - analyze_code:分析代码存储库 - summarize_research:总结研究主题
- 选择预算级别(基本10美元,专业50美元,企业200美元)
- 通过SSE监控实时任务进度
- 查看任务生命周期和状态
4. 💰 成本跟踪页面
- 按层级查看预算概览
- 按型号监控成本(GPT-4、GPT-3.5、Claude)
- 分析使用时间线
- 跟踪代币消费
- 比较模型定价
5. 📊 指标页面
- 查看系统健康指标
- 请求率和错误分析
- 响应时间分布
- 速率限制状态
- 数据库和缓存指标
6. 🔍 追踪页面
- 了解分布式跟踪
- 查看样本痕迹
- 了解跨度层次结构
- 性能调试指南
- 链接到Jaeger UI
手动测试(无UI)
测试MCP服务器
# Generate a JWT token (you'll need to create a test token)
# See streamlit-ui/utils/auth.py for token generation
# 1. Initialize MCP session
curl -X POST http://localhost:8080/mcp \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-d '{
"jsonrpc": "2.0",
"id": "1",
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"clientInfo": {"name": "test-client", "version": "1.0.0"}
}
}'
# 2. List tools
curl -X POST http://localhost:8080/mcp \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-d '{
"jsonrpc": "2.0",
"id": "2",
"method": "tools/list"
}'
# 3. Hybrid search
curl -X POST http://localhost:8080/mcp \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-d '{
"jsonrpc": "2.0",
"id": "3",
"method": "tools/call",
"params": {
"name": "hybrid_search",
"arguments": {
"query": "machine learning",
"limit": 10,
"bm25_weight": 0.5,
"vector_weight": 0.5
}
}
}'测试A2A服务器
# 1. Get agent card
curl http://localhost:8081/agent
# 2. Create a task
curl -X POST http://localhost:8081/tasks \
-H "Content-Type: application/json" \
-d '{
"user_id": "demo-user-pro",
"agent_id": "research-assistant",
"capability": "search_papers",
"input": {
"query": "transformer architecture",
"limit": 5
}
}'
# 3. Get task status
curl http://localhost:8081/tasks/{task_id}
# 4. Stream task events (SSE)
curl -N http://localhost:8081/tasks/{task_id}/events🧪 运行测试
所有测试
# From project root
./scripts/run-tests.shMCP服务器测试
cd mcp-server
# All tests with coverage
go test ./... -coverprofile=coverage.out
# View coverage report
go tool cover -html=coverage.out
# Specific package
go test ./internal/auth/...
go test ./internal/tools/...
go test ./internal/middleware/...A2A服务器测试
cd a2a-server
# All tests with coverage
go test ./... -coverprofile=coverage.out
# View coverage report
go tool cover -html=coverage.out
# Specific package
go test ./internal/protocol/...
go test ./internal/tasks/...
go test ./internal/cost/...测试覆盖率总结
| 套餐 | 覆盖范围 | 测试 |
|---|---|---|
| mcp服务器/内部/协议 | 100% | 25+ |
| mcp服务器/内部/身份验证 | 93.1% | 20+ |
| mcp服务器/内部/工具 | 97.4% | 30+ |
| mcp服务器/内部/中间件 | 92.9% | 25+ |
| mcp服务器/内部/服务器 | 94.8% | 25+ |
| MCP服务器平均值 | 95% | 125+ |
| a2a服务器/内部/协议 | 100% | 12 |
| a2a服务器/内部/代理卡 | 100% | 10 |
| a2a服务器/内部/任务 | 98.3% | 13 |
| a2a服务器/内部/成本 | 91.5% | 13 |
| a2a服务器/内部/服务器 | 81.8% | 27 |
| A2A服务器平均值 | 92.6% | 75+ |
| 总计 | 94% | 200+ |
📚 用例演练
用例1:多租户RAG管道
场景:您有多个团队(acme corp、globex、initech)需要单独的文档搜索。
步骤:
- 首选 认证 Streamlit中的页面
- 为生成令牌
acme-corp租户与read和write范围 - 首选 MCP抹布 页
- 使用令牌初始化会话
- 使用查询测试混合搜索:“安全策略”
- 调整BM25/矢量权重以查看不同的结果
- 列出文档以查看租户隔离数据
- 为不同租户生成令牌并验证隔离
关键收获:
- JWT声称在数据库级别强制实施租户隔离
- 混合搜索结合了关键字和语义匹配
- 限速防止滥用
- 所有请求都在Jaeger中跟踪
用例3:成本控制研究助理
场景:研究团队在预算限制下需要人工智能的帮助。
步骤:
- 首选 A2A任务 Streamlit中的页面
- 查看显示3种功能的代理卡
- 选择预算级别:基本(每月10美元)、专业(每月50美元)或企业(每月200美元)
- 创建任务:“搜索变压器架构论文”
- 在任务执行时监视实时SSE事件
- 首选 成本跟踪 查看预算使用情况的页面
- 尝试创建任务,直到超出预算
- 查看预算执行情况
关键收获:
- 飞行前预算检查可防止超支
- 不同型号的成本不同(GPT-4与GPT-3.5)
- SSE提供实时任务更新
- 成本归因跟踪用户和任务的支出
🔧 本地开发(无Docker)
先决条件
- PostgreSQL 16,带pgvector扩展
- Redis 7+
- 转到1.23+
设置PostgreSQL
# Install pgvector extension
psql -U postgres -c "CREATE EXTENSION IF NOT EXISTS vector;"
# Create database
psql -U postgres -c "CREATE DATABASE mcp_dev;"
# Set environment variables
export DB_HOST=localhost
export DB_PORT=5432
export DB_USER=postgres
export DB_PASSWORD=postgres
export DB_NAME=mcp_dev
export DB_SSLMODE=disable设置Redis
# Start Redis
redis-server
# Set environment variable
export REDIS_ADDR=localhost:6379运行MCP服务器
cd mcp-server
# Install dependencies
go mod download
# Run server
go run cmd/server/main.go
# Server starts on http://localhost:8080运行A2A服务器
cd a2a-server
# Install dependencies
go mod download
# Run server
go run cmd/server/main.go
# Server starts on http://localhost:8081运行Streamlit UI
cd streamlit-ui
# Install dependencies
pip install -r requirements.txt
# Set environment variables
export MCP_SERVER_URL=http://localhost:8080
export A2A_SERVER_URL=http://localhost:8081
export JAEGER_URL=http://localhost:16686
export PROMETHEUS_URL=http://localhost:9090
# Run Streamlit
streamlit run app.py
# UI starts on http://localhost:8501🔐 安全功能
身份验证和授权
- JWT代币:具有公钥/私钥对的RS256算法
- 代币声明:
tenant_id,user_id,scopes,exp,iat,nbf - 范围验证:端点需要特定的作用域(读、写、管理)
- 令牌到期:可配置的自动验证过期时间
多租户
- 行级安全(RLS):PostgreSQL策略强制租户隔离
- 上下文传播:JWT的租户ID流经所有操作
- 隔离速率限制:每个租户都有单独的费率限制计数器
- 数据隔离:按tenant_id自动筛选的查询
速率限制
- 算法:Redis后端的令牌桶
- 配置:每个租户和每个端点的限制
- 回应:HTTP 429
Retry-After头球 - 监控:Prometheus速率限制命中率指标
📊 可观测性
该实施提供 生产级可观测性 配备双仪器:
- 开放遥测:服务到服务跟踪、基础设施指标
- 浪伏:LLM特定的可观察性(提示、令牌、成本)
分布式追踪(OpenTetry+Jaeger)
全栈仪器:
- ✅ Go服务器:HTTP中间件、工具执行、数据库查询
- ✅ Python工作流:LangGraph节点、MCP调用、LLM调用
- ✅ 端到端痕迹:流线型UI→ python→ Go → 数据库→ LLM
特征:
- 跟踪传播:通过HTTP标头的W3C跟踪上下文
- 跨度属性:tenant_id、user_id(仅跟踪)、工具名称、查询参数
- 采样:可配置(默认情况下,开发人员为100%)
- 汽车仪表:Python中的HTTP客户端(请求,httpx)
示例跟踪:
[Streamlit] user.query (1200ms)
├─ [Python] rag_workflow.execute (1150ms)
│ ├─ [Python] mcp.hybrid_search (300ms)
│ │ └─ [Go MCP] mcp.request → mcp.tool.call → mcp.db.hybrid_search (280ms)
│ ├─ [Python] llm.generate (800ms) + [Langfuse] tracks tokens/cost
│ └─ [Python] format.response (50ms)查看痕迹: http://localhost:16686
度量(开放遥测+普罗米修斯)
MCP服务器指标 (/metrics):
mcp.request.count,mcp.request.duration-HTTP请求指标mcp.tool.execution.duration-按工具名称列出的工具执行时间mcp.db.query.duration-数据库查询性能mcp.search.results-搜索结果计数分布
A2A服务器指标 (/metrics):
a2a.task.count,a2a.task.duration-任务生命周期指标a2a.cost.total,a2a.tokens.total-按型号进行成本跟踪a2a.budget.remaining-按层级划分的预算利用率a2a.sse.connections-活动SSE连接
配置:
# Enable/disable observability
OTEL_ENABLE_TRACING=true
OTEL_ENABLE_METRICS=true
# OTLP endpoint (Jaeger)
OTEL_EXPORTER_OTLP_ENDPOINT=jaeger:4318
# Sampling rate (0.0 to 1.0)
OTEL_TRACES_SAMPLER_ARG=1.0 # 100% sampling
# Environment
ENVIRONMENT=development # or production查看指标: http://localhost:9090
LLM可观察性(Langfuse)
OpenTelemetry的补充:
- 快速跟踪:完整的提示/响应历史记录
- 令牌使用:每次通话令牌计数和成本
- 模型性能:按型号分类的延迟
- 质量指标:用户反馈和评级
整合:Python工作流使用两者 @observe (廊坊)和OTel跨度
测试可观察性
快速自动化测试:
./scripts/test-observability.sh手动验证:
# 1. Check metrics endpoints
curl http://localhost:8080/metrics # MCP server
curl http://localhost:8081/metrics # A2A server
# 2. Query Prometheus
curl -G http://localhost:9090/api/v1/query \
--data-urlencode 'query=mcp_request_count'
# 3. Make test requests to generate traces
curl -X POST http://localhost:8080/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
# 4. View traces in Jaeger UI
open http://localhost:16686
# Select service: mcp-server, a2a-server, or rag-workflow
# Click "Find Traces" to see distributed traces常见的Prometheus查询:
# Request rate by service
sum by (service) (rate(mcp_request_count[5m]))
# Error rate
rate(mcp_request_count{status="error"}[5m])
# Tool execution time (95th percentile)
histogram_quantile(0.95, rate(mcp_tool_execution_duration_bucket[5m]))
# Total cost by model
sum by (model) (a2a_cost_total)故障排除:
- 没有指标? 检查普罗米修斯目标:http://localhost:9090/targets(均应为“UP”)
- 没有痕迹? 验证
OTEL_ENABLE_TRACING=true在docker-compose.yml中 - 上下文不传播? 检查HTTP标头是否包括
traceparent
💡 配置
环境变量
MCP服务器
# Database
DB_HOST=postgres
DB_PORT=5432
DB_USER=postgres
DB_PASSWORD=postgres
DB_NAME=mcp_dev
DB_SSLMODE=disable
# Redis
REDIS_ADDR=redis:6379
# Server
MCP_PORT=8080
MCP_LOG_LEVEL=info
# JWT
JWT_PUBLIC_KEY_PATH=/path/to/public.pem
JWT_ISSUER=mcp-server-demo
JWT_AUDIENCE=mcp-server
# Rate Limiting
RATE_LIMIT_REQUESTS=100
RATE_LIMIT_WINDOW=60s
# Observability
OTEL_EXPORTER_JAEGER_ENDPOINT=http://jaeger:14268/api/tracesA2A服务器
# Redis
REDIS_ADDR=redis:6379
# Server
A2A_PORT=8081
A2A_LOG_LEVEL=info
# Cost Limits (monthly budgets in USD)
BUDGET_BASIC=10.0
BUDGET_PRO=50.0
BUDGET_ENTERPRISE=200.0
# Observability
OTEL_EXPORTER_JAEGER_ENDPOINT=http://jaeger:14268/api/traces🐛 故障排除
MCP服务器无法启动
# Check database connection
psql -h localhost -U postgres -d mcp_dev -c "SELECT 1;"
# Check pgvector extension
psql -h localhost -U postgres -d mcp_dev -c "SELECT * FROM pg_extension WHERE extname='vector';"
# Check Redis connection
redis-cli pingJWT令牌被拒绝
- 验证令牌未过期(检查
exp索赔) - 确保
issuer匹配服务器配置 - 确保
audience匹配服务器配置 - 检查令牌签名(必须是RS256)
利率限制过于严格
- 调整
RATE_LIMIT_REQUESTS和RATE_LIMIT_WINDOW - 检查Redis是否有卡住的计数器:
redis-cli KEYS "rate_limit:*"
SSE流媒体不工作
- 验证任务ID是否正确
- 如果从浏览器访问,请检查CORS标头
- 确保连接超时足够长
- 检查服务器日志中的订阅错误
📖 进一步阅读
- 设计文档:详细的架构和实施指南
- MCP规范: https://spec.modelcontextprotocol.io/
- OpenTetry Go: https://opentelemetry.io/docs/languages/go/
- pg载体: https://github.com/pgvector/pgvector
📝 许可证
MIT许可证-有关详细信息,请参阅许可证文件
