OTC Pricing MCP について
OTC Pricing MCPは、Open Telekom Cloudの料金とドキュメントを検索するオープンソースのMCPサーバーです。STDIOとSSEに対応し、料金照会、コスト見積もり、課金方式の比較、索引化された文書の検索を提供します。
主な機能
- 01サービスとリージョン別の料金照会
- 02CPUとメモリによるコンピュート仕様の検索
- 03リソースの月額コスト見積もり
- 04従量課金と予約料金の比較
- 05OTC文書の検索とセクション取得
- 06ヘルスチェックとPrometheusメトリクス
活用シーン
- 01要件に合うECS仕様の検索
- 02クラウドリソースの月額コスト見積もり
- 03従量課金と予約プランの比較
- 04OTCサービスやAPI文書の参照
MCP 対応
MCPツールを通じて、OTCの料金データと索引化されたユーザーマニュアル、APIリファレンスを提供します。MCPクライアントはSTDIOまたはSSEで接続できます。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
ツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細
OTC 料金 MCP サーバー
Open Telekom Cloud(OTC)料金計算 API向けのオープンソース Model Context Protocol(MCP) サーバーです。
構造化ログ、Prometheus メトリクス、ヘルスチェックなど、完全な可観測性を備え、OTC の料金データを Claude やその他の LLM クライアントに提供します。
ステータス:v0.1.3 — STDIO + SSE トランスポート、Kubernetes デプロイ、完全な可観測性
MCP とは?
Model Context Protocol は、LLM アプリケーション(Claude など)が外部のツールやデータソースとやり取りできるようにする標準規格です。このサーバーは 2 種類のトランスポートに対応しています。
| トランスポート | 仕組み | 最適な用途 |
|---|---|---|
| STDIO | Claude がサブプロセスとしてサーバーを起動し、stdin/stdout 経由で通信します | ローカルの Claude Desktop、CLI ツール |
| SSE | HTTP 経由の Server-Sent Events — Claude が URL に接続します | リモート/ホスト型デプロイ、ウェブクライアント |
このサーバーを使うと、お好みのトランスポート経由で、9 つの専用ツールから OTC の料金データやユーザーマニュアル/API リファレンスのドキュメントに Claude がアクセスできます。
これで何ができますか?
ユースケースの例:
- Claude に「eu-de で CPU 4 個、RAM 8GB の最安の ECS インスタンスを探して」と尋ねます。
- Claude が
find_compute_flavorツールを呼び出し、料金データを取得して回答します。 - 「S3 ストレージの PAYG と 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/OS に基づいてコンピューティング(ECS)インスタンスを検索します。
入力:
v_cpu(整数):仮想 CPU 数ram_gb(数値):RAM 容量(GiB)os(文字列、任意):オペレーティングシステム(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 | (自動) | ドキュメント 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(関連するすべてのログで共通)- イベントに応じたカスタムフィールド
ログは 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 ユーザー、読み取り専用のルートファイルシステム
- リソース制限(CPU 100m~500m、RAM 128Mi~512Mi)
- 稼働確認プローブ:ポート 8080 で GET /healthz
- 準備状態プローブ:ポート 8080 で GET /readyz
- NetworkPolicy:nginx コントローラーからの Ingress のみ許可し、DNS と OTC API への egress を許可
- Prometheus によるスクレイピング用の ServiceMonitor
selfHeal: trueおよびprune: trueを設定して ArgoCD で管理
アーキテクチャ
リクエストフロー
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 | 価格の解析と整形 |
機能強化のアイデア(今後の開発)
ストーリー 0~9 は完了しています。以下は v1.0 以降の機能強化です:
拡張アイデア
キャッシュ
- API 負荷を軽減するため、価格データを N 秒間キャッシュします
- 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/ - Lint に合格する:
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 をご覧ください。
プロジェクトの状況
| ストーリー | 機能 | 状況 |
|---|---|---|
| 0 | プロジェクトのセットアップ、API クライアント、データモデル | ✅ 完了 |
| 1 | カタログ探索ツール | ✅ 完了 |
| 2 | 価格クエリツール | ✅ 完了 |
| 3 | 複数サービスへのファンアウト | ✅ 完了 |
| 4 | 包括的なテスト | ✅ 完了 |
| 5 | セキュリティとコンテナの強化 | ✅ 完了 |
| 6 | CI/CD パイプライン(GHCR イメージ、PyPI、SBOM、GitHub リリース) | ✅ 完了 |
| 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 サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。