关于 OTC Pricing MCP
OTC Pricing MCP 是用于查询 Open Telekom Cloud 价格和文档的开源 MCP 服务,支持 STDIO 与 SSE。它提供价格查询、成本估算、计费比较和索引文档检索工具。
主要功能
- 01按服务和区域查询价格
- 02按 CPU 和内存查找计算规格
- 03估算资源月度成本
- 04比较按需与预留价格
- 05搜索 OTC 文档并获取章节
- 06提供健康检查和 Prometheus 指标
适用场景
- 01查找符合资源需求的 ECS 规格
- 02估算云资源月度成本
- 03比较按需与预留方案
- 04检索 OTC 服务及 API 文档
MCP 相关
该服务通过 MCP 工具提供 OTC 价格数据和已索引的用户手册、API 参考内容。MCP 客户端可通过 STDIO 或 SSE 连接。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
OTC 定价 MCP 服务
一个开源的 Model Context Protocol (MCP) 服务,用于访问 Open Telekom Cloud (OTC) 价格计算器 API。
通过完善的可观测性(结构化日志、Prometheus 指标和健康检查),向 Claude 和其他大模型客户端提供 OTC 定价数据。
状态:v0.1.3 — STDIO + SSE 传输方式、Kubernetes 部署、完善的可观测性
什么是 MCP?
Model Context Protocol 是一项标准,可让大模型应用(例如 Claude)与外部工具和数据源交互。本服务支持两种传输方式:
| 传输方式 | 工作原理 | 适用场景 |
|---|---|---|
| STDIO | Claude 将服务作为子进程启动;通过 stdin/stdout 通信 | 本地 Claude Desktop、命令行工具 |
| SSE | 基于 HTTP 的服务器发送事件 — Claude 连接到一个 URL | 远程/托管部署、Web 客户端 |
本服务通过 9 个专用工具,让 Claude 能够访问 OTC 定价数据以及用户手册和 API 参考文档,支持你选择的任一种传输方式。
可以用它做什么?
示例用例:
- 询问 Claude:“在 eu-de 中寻找最便宜的、具有 4 个 CPU 和 8GB RAM 的 ECS 实例”
- Claude 调用
find_compute_flavor工具 → 获取定价数据 → 给出答案 - 询问:“比较 S3 存储的按需付费与 12 个月预留定价”
- Claude 调用
compare_billing_models工具 → 进行分析 → 展示节省金额
快速开始
1. 安装
要求:Python 3.12+
# Clone the repository
git clone https://github.com/seaser0/otc-pricing-mcp.git
cd otc-pricing-mcp
# Install dependencies
uv sync
# Run the server
python -m otc_pricing_mcp
你将看到:
{"event": "mcp_server_starting", "transports": ["stdio", "sse"], "port": 8080, ...}
{"event": "mcp_server_ready", "status": "accepting_connections", ...}
现在,服务会同时在 stdin/stdout 和 http://localhost:8080/sse 上监听 MCP 连接。
2. 连接 MCP 客户端
选项 A — STDIO(本地,Claude Desktop)
{
"mcpServers": {
"otc-pricing": {
"command": "python",
"args": ["-m", "otc_pricing_mcp"],
"env": {
"LOG_LEVEL": "INFO",
"METRICS_PORT": "8080"
}
}
}
}
选项 B — SSE(远程,Kubernetes)
将支持 SSE 传输的任意 MCP 客户端指向托管端点:
{
"mcpServers": {
"otc-pricing": {
"url": "https://mcp-otc-pricing.example.com/sse"
}
}
}
或者,在运行服务时进行本地测试:
# In a second terminal:
curl -N http://localhost:8080/sse
# event: endpoint
# data: /messages/?session_id=<uuid>
3. 开始使用工具
连接后,Claude 可以调用 7 个可用工具中的任意一个。请参阅下文的 工具参考 部分。
工具参考
本服务提供 7 个 MCP 工具,用于执行不同的定价查询:
1. list_services
用途:获取所有可用的 OTC 服务
输入:无
输出:服务名称和元数据列表
Claude 使用示例:
"What OTC services are available for pricing?"
2. list_regions
用途:获取可用的 OTC 区域
输入:无
输出:区域代码列表(eu-de、eu-nl、eu-ch2 等)
Claude 使用示例:
"What regions does OTC support?"
3. get_service_schema
用途:获取服务中可筛选/可返回的列
输入:
service(字符串):服务名称(例如,“ecs”“evs”“obs”“s3”“rds”)
输出:包含可筛选和可返回列名称的架构
Claude 使用示例:
"What columns can I filter on for ECS pricing?"
4. query_pricing
用途:通过灵活筛选条件查询定价数据
输入:
services(数组):服务名称列表(例如,["ecs", "evs"])region(字符串,可选):按区域筛选(例如,“eu-de”)max_results(整数,可选):返回结果的最大数量(默认值:5000)
输出:符合筛选条件的定价行
Claude 使用示例:
"Show me ECS and EVS pricing in the eu-de region"
5. find_compute_flavor
用途:按 vCPU、RAM 和操作系统查找计算(ECS)实例
输入:
v_cpu(整数):虚拟 CPU 数量ram_gb(数字):RAM 容量,单位为 GiBos(字符串,可选):操作系统(Linux、Windows 等)region(字符串,可选):区域(默认值:eu-de)
输出:符合条件的 ECS 实例类型及其定价
Claude 使用示例:
"Find a Linux ECS instance with 4 CPUs and 16GB RAM in eu-nl"
6. estimate_monthly_cost
用途:计算多个资源的月度费用
输入:
items(数组):资源列表,包含:id(字符串):产品 ID(例如 "OTC_S3M1_LI")quantity(数字,可选):数量(默认值:1)hours_per_month(数字,可选):使用时长(默认值:730)
输出:明细费用及月度总计
Claude 使用示例:
"Calculate monthly cost for 100GB S3 storage and an ECS instance"
7. compare_billing_models
用途:比较 PAYG 与预留实例定价
输入:
product_id(字符串):产品 ID(例如 "OTC_S3M1_LI")quantity(数字,可选):数量(默认值:1)hours_per_month(数字,可选):使用时长(默认值:730)
输出:PAYG、12 个月、24 个月和 36 个月预留方案的费用比较
Claude 使用示例:
"Compare PAYG vs 12/24/36 month reserved pricing for ECS"
8. search_otc_docs
用途:在已索引的 OTC 用户手册和 API 参考文档中进行全文搜索
输入:
query(字符串):搜索词(按 BM25 排名,对词元取 AND)scope(字符串,可选):public|swiss|both(默认值:both)service(字符串,可选):限定在某个服务仓库中搜索(例如elastic-cloud-server)top_k(整数,可选):1-50,默认值为 5
输出:按排名排列的 {url, title, h2, h3, snippet, service, cloud, upstream_commit} 命中结果列表。
索引随软件包一同提供,并每周从上游
opentelekomcloud-docs/<service> Sphinx/RST 仓库(Apache-2.0)重新构建;运行时
不会访问受 Anubis 限制的 docs.otc.t-systems.com HTML。
Claude 使用示例:
"Find the OTC docs page that explains S3-flavor ECS specifications"
9. get_otc_doc_section
用途:以 Markdown 格式获取一个已索引文档页面(或其中一个章节)的正文
输入:
url(字符串):由search_otc_docs返回的规范 URL(可包含或不包含#anchor)section(字符串,可选):H2/H3 标题筛选条件(不区分大小写的子字符串)
输出:{url, title, sections: [{h2, h3, anchor, body}, ...], matched, ...}
Claude 使用示例:
"Show me the EVS Disk Types and Performance section"
配置
环境变量
使用环境变量控制服务行为:
| 变量 | 默认值 | 描述 |
|---|---|---|
LOG_LEVEL | INFO | 日志级别:DEBUG、INFO、WARNING、ERROR |
METRICS_PORT | 8080 | 指标/健康检查端点的端口 |
METRICS_HOST | 0.0.0.0 | HTTP 服务的绑定地址(非容器运行时设为 127.0.0.1) |
OTC_PRICING_API_BASE | https://calculator.otc-service.com/en/open-telekom-price-api/ | OTC API 端点 |
OTC_DOCS_DB | (auto) | 覆盖文档 FTS5 索引的路径(默认:随软件包提供的 data/otc_docs.sqlite3) |
示例:
LOG_LEVEL=DEBUG METRICS_PORT=9090 python -m otc_pricing_mcp
可观测性:指标与日志
此服务具备生产级可观测性,便于调试问题和监控性能。
结构化日志(JSON)
每项操作都会以 JSON 格式记录,便于机器读取并进行聚合分析。
使用 DEBUG 日志级别启动服务:
LOG_LEVEL=DEBUG python -m otc_pricing_mcp 2>&1
你会看到类似这样的 JSON 日志:
{"timestamp": "2026-05-06T18:00:00.123456Z", "event": "tool_invocation_start", "tool": "query_pricing", "request_id": "550e8400-e29b-41d4-a716-446655440000", "arguments": {"services": ["ecs"]}}
{"timestamp": "2026-05-06T18:00:00.234567Z", "event": "upstream_request_start", "service": "ecs", "request_id": "550e8400-e29b-41d4-a716-446655440000"}
{"timestamp": "2026-05-06T18:00:00.345678Z", "event": "upstream_request_success", "service": "ecs", "request_id": "550e8400-e29b-41d4-a716-446655440000", "status_code": 200, "duration_seconds": 0.111, "attempt": 1, "items_returned": 42}
{"timestamp": "2026-05-06T18:00:00.456789Z", "event": "tool_invocation_success", "tool": "query_pricing", "request_id": "550e8400-e29b-41d4-a716-446655440000", "duration_seconds": 0.333}
每条日志中的关键字段:
timestamp:事件发生时间(ISO 8601)event:发生的事件(tool_invocation_start、upstream_request_success 等)request_id:此请求的唯一 ID(所有相关日志中的 ID 相同)- 根据事件而定的自定义字段
日志会输出到 stderr,因此可将其重定向到文件或日志聚合器:
python -m otc_pricing_mcp 2>/var/log/otc-pricing-mcp.log
通过管道传给 jq 以美化输出:
python -m otc_pricing_mcp 2>&1 | jq .
HTTP 端点(端口 8080)
uvicorn 服务会在端口 8080 上公开所有端点:
| 路径 | 方法 | 描述 |
|---|---|---|
/sse | GET | MCP SSE 传输 — 在此处连接 MCP 客户端 |
/messages/ | POST | MCP SSE 消息处理程序(由客户端内部使用) |
/healthz | GET | 存活探针 — 只要进程正在运行,就始终返回 200 |
/readyz | GET | 就绪探针 — OTC API 可访问时返回 200,否则返回 503 |
/metrics | GET | Prometheus 文本展示格式指标 |
健康检查:
# Liveness check (always 200 if process is up)
curl http://localhost:8080/healthz
# {"status": "ok", "service": "otc-pricing-mcp"}
# Readiness check (verifies OTC API is reachable)
curl http://localhost:8080/readyz
# {"status": "ready", "upstream": "ok", "api_response_time": 0.042}
Prometheus 指标:
curl http://localhost:8080/metrics
返回 Prometheus 格式的指标:
# HELP otc_pricing_mcp_requests_total Total MCP tool requests (success and failure)
# TYPE otc_pricing_mcp_requests_total counter
otc_pricing_mcp_requests_total{status="success",tool="query_pricing"} 5.0
otc_pricing_mcp_requests_total{status="error",tool="query_pricing"} 1.0
# HELP otc_pricing_mcp_request_duration_seconds MCP tool request duration in seconds
# TYPE otc_pricing_mcp_request_duration_seconds histogram
otc_pricing_mcp_request_duration_seconds_bucket{le="0.005",tool="query_pricing"} 0.0
otc_pricing_mcp_request_duration_seconds_bucket{le="0.01",tool="query_pricing"} 1.0
...
# HELP otc_pricing_mcp_upstream_requests_total Total upstream OTC API requests (success and failure)
# TYPE otc_pricing_mcp_upstream_requests_total counter
otc_pricing_mcp_upstream_requests_total{service="ecs",status="success"} 10.0
otc_pricing_mcp_upstream_requests_total{service="ecs",status="error"} 2.0
...
可用指标:
otc_pricing_mcp_requests_total{tool, status}:工具调用次数otc_pricing_mcp_request_duration_seconds{tool}:工具执行时间otc_pricing_mcp_upstream_requests_total{service, status}:API 调用次数otc_pricing_mcp_upstream_duration_seconds{service}:API 调用延迟
使用 Prometheus:
添加到你的 prometheus.yml 中:
scrape_configs:
- job_name: 'otc-pricing-mcp'
static_configs:
- targets: ['localhost:8080']
然后在 Prometheus 中查询:
rate(otc_pricing_mcp_requests_total[5m]) # Requests per second
histogram_quantile(0.95, otc_pricing_mcp_request_duration_seconds_bucket) # p95 latency
调试指南
问题:API 调用缓慢
检查日志:
LOG_LEVEL=DEBUG python -m otc_pricing_mcp 2>&1 | jq 'select(.event == "upstream_request_success") | {service, duration_seconds}'
检查指标:
curl http://localhost:8080/metrics | grep upstream_duration_seconds
问题:工具失败
查找错误日志:
LOG_LEVEL=DEBUG python -m otc_pricing_mcp 2>&1 | jq 'select(.event == "tool_invocation_error")'
错误日志示例:
{
"event": "tool_invocation_error",
"tool": "query_pricing",
"request_id": "550e8400-e29b-41d4-a716-446655440000",
"error": "list index out of range",
"error_type": "IndexError",
"duration_seconds": 0.001,
"exc_info": true
}
问题:无法访问 OTC API
检查就绪端点:
curl -v http://localhost:8080/readyz
# HTTP/1.1 503 Service Unavailable
# {"status": "not_ready", "upstream": "unreachable", "error": "..."}
检查指标:
curl http://localhost:8080/metrics | grep upstream_requests_total
# Will show increased error counts
问题:需要完整请求跟踪
使用 request_id 跟踪请求:
# Get the request_id from any log
LOG_LEVEL=DEBUG python -m otc_pricing_mcp 2>&1 | jq 'select(.request_id == "550e8400-e29b-41d4-a716-446655440000")'
这会按顺序显示该请求的所有日志:
- tool_invocation_start
- upstream_request_start
- upstream_request_success(包含 items_returned)
- tool_invocation_success
本地运行(开发)
设置
# Clone repo
git clone https://github.com/seaser0/otc-pricing-mcp.git
cd otc-pricing-mcp
# Install with dev dependencies
uv sync
# Run tests
uv run pytest tests/ -v
# Check code quality
uv run ruff check src/
uv run mypy src/ --strict
在开发模式下运行
# With debug logging
LOG_LEVEL=DEBUG python -m otc_pricing_mcp
# In another terminal, test the endpoints
curl http://localhost:8080/healthz | jq .
curl http://localhost:8080/metrics
在生产环境中运行(Docker)
构建镜像
docker build -t otc-pricing-mcp:latest .
运行容器
docker run \
--name otc-pricing-mcp \
-e LOG_LEVEL=INFO \
-e METRICS_PORT=8080 \
-p 8080:8080 \
otc-pricing-mcp:latest
Kubernetes 部署
完整的清单集(Deployment、Service、Ingress、NetworkPolicy、ServiceMonitor、PodDisruptionBudget)请参阅 deploy/kubernetes/。
在 Kubernetes 上自托管时,将远程客户端连接到你的 Ingress 主机名:
https://mcp-otc-pricing.example.com/sse
主要特性:
- 非 root 用户,只读根文件系统
- 资源限制(100m–500m CPU、128Mi–512Mi RAM)
- 存活探针:在端口 8080 上执行 GET /healthz
- 就绪探针:在端口 8080 上执行 GET /readyz
- NetworkPolicy:仅允许来自 nginx 控制器的入站流量,出站流量仅允许访问 DNS 和 OTC API
- 用于 Prometheus 抓取的 ServiceMonitor
- 由 ArgoCD 管理,设置
selfHeal: true和prune: true
架构
请求流程
Claude Client
│
├─ STDIO transport (local) ──┐
│ stdin/stdout │
│ ▼
└─ SSE transport (remote) MCP Server (server.py)
GET /sse - List tools
POST /messages/ - Route tool calls
- Log invocations
- Record metrics
│
▼
HTTP Client (client.py)
- Build request
- Retry logic
- Parse response
│
▼
OTC Price Calculator API
两种传输方式共用同一个 MCP Server 实例,并在同一个 asyncio 事件循环中并发运行。
组件概览
| 组件 | 用途 |
|---|---|
__main__.py | 入口点 — 并发运行 STDIO 和 uvicorn SSE |
server.py | MCP 服务,路由工具调用并记录调用日志 |
client.py | OTC API 的 HTTP 客户端,包含重试逻辑和 API 日志记录 |
tools/ | 工具实现(发现、定价、估算) |
observability/http_server.py | Starlette 应用 — SSE 传输以及健康检查和指标路由 |
observability/ | 日志记录、Prometheus 指标、请求上下文 |
models.py | 数据模型(使用 Pydantic 验证) |
normalize.py | 价格解析与格式化 |
增强想法(未来开发)
Story 0–9 已完成。以下是 v1.0 之后的增强项:
增强建议
缓存
- 将定价数据缓存 N 秒,以减少 API 负载
- 提供 Redis 或内存缓存选项
- 缓存失效策略
高级查询
- 提供更多筛选选项(例如价格范围、承诺期限)
- 按价格、CPU、RAM 排序
- 聚合(按服务统计最低/最高/平均定价)
成本分析工具
- 历史定价趋势
- 成本异常检测
- 推荐引擎(调整资源规格)
多云支持
- 集成 AWS 定价 API
- 集成 Azure 定价 API
- 跨云成本比较
用户偏好
- 保存收藏的服务/区域
- 自定义定价提醒
- 按项目跟踪预算
更完善的错误恢复
- 带抖动的指数退避(而非固定指数退避)
- 断路器模式
- API 故障时回退到缓存数据
性能优化
- 查询结果分页
- 数据库缓存层
- 为大型数据集提供流式响应
可观测性增强
- 分布式追踪(OpenTelemetry)
- 自定义业务指标(已计算的成本、每项服务的查询次数)
- 日志聚合集成(Loki、ELK)
- 告警规则(Prometheus Alertmanager)
测试改进
- 负载测试(k6、Locust)
- 混沌测试(故障场景)
- 与 OTC API 进行契约测试
API 稳定性
- API 版本管理(v1、v2)
- 弃用策略
- 向后兼容保证
贡献
欢迎贡献!请参阅 CONTRIBUTING.md,了解:
- 开发环境设置
- 代码风格(ruff、mypy --strict)
- 测试要求(53+ 项测试并包含覆盖率)
- 安全扫描(bandit、cyclonedx-bom)
- 提交消息规范
快速 PR 检查清单:
- 测试通过:
uv run pytest tests/ - 代码检查通过:
uv run ruff check src/ - 类型检查通过:
uv run mypy src/ --strict - 安全扫描通过:
uv run bandit -r src/ - 提交消息有意义
许可证
Apache License 2.0 — 详见 LICENSE 文件。
版权:seaser0 ([email protected])
获取帮助
有问题或遇到故障?
- 查看上方的调试指南
- 创建 GitHub Issue:https://github.com/seaser0/otc-pricing-mcp/issues
- 使用以下命令查看日志:
LOG_LEVEL=DEBUG python -m otc_pricing_mcp 2>&1 | jq .
想要报告安全问题? 请参阅 SECURITY.md,了解负责任的披露方式。
项目状态
| Story | 功能 | 状态 |
|---|---|---|
| 0 | 项目设置、API 客户端、数据模型 | ✅ 已完成 |
| 1 | 目录发现工具 | ✅ 已完成 |
| 2 | 定价查询工具 | ✅ 已完成 |
| 3 | 多服务扇出 | ✅ 已完成 |
| 4 | 全面测试 | ✅ 已完成 |
| 5 | 安全与容器加固 | ✅ 已完成 |
| 6 | CI/CD 流水线(GHCR 镜像、PyPI、SBOM、GitHub Release) | ✅ 已完成 |
| 7 | 可观测性(结构化日志、Prometheus 指标、健康探针) | ✅ 已完成 |
| 8 | ArgoCD 部署(Kubernetes、SSE 传输、远程端点) | ✅ 已完成 |
| 9 | 开源文档(README、server.json、社区文档) | ✅ 已完成 |
架构决策
详细文档请参阅 docs/ 目录:
docs/ci-cd.md— CI/CD 工作流详情docs/deployment.md— 部署指南docs/security.md— 安全功能与注意事项
由 seaser0 倾情打造 ❤️
最后更新:2026-05-07
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。