MCP サーバー インフラ設計
| 項目 | 内容 |
|---|---|
| ステータス | 🟡 設計中 |
| 関連案件 | #13 Mappy MCP サーバー新設 |
| 親ドキュメント | MCP サーバー 全体像 |
| 関連設計 | DB(監査ログ) / DB(OAuth) |
1. 本ドキュメントの目的
MCP サーバーの AWS 上でのホスティング構成を確定する。
- 既存 GMAC インフラ(VPC
vpc-0b4c742f84f3b2d9d、リージョンap-northeast-1)への統合 - コンテナ運用(ECS Fargate)
- 認証・OAuth 状態管理ストア
- ネットワーク・セキュリティ
- 監視・アラート
- スタック両案(Python / TypeScript)に共通の構成
2. 既存インフラの活用方針
2.1 流用するもの
| 項目 | 既存リソース | 流用方針 |
|---|---|---|
| VPC | vpc-0b4c742f84f3b2d9d (10.0.0.0/16) | そのまま使用 |
| プライベートサブネット | subnet-095de9e00c1894a0c(1a), subnet-0f38ab1dce252e375(1c) | MCP ECS タスク配置先 |
| パブリックサブネット | subnet-0ff23c0ce66750053(1a), subnet-0ebe6abb3572271e8(1c) | MCP 専用 ALB 配置先 |
| RDS | h2t-db (MySQL 8.0) | mappy DB に MCP テーブル追加 |
| ECR | 新規リポジトリ h2t-mappy-mcp 追加 | 既存命名規則に従う |
| S3 | 既存バケット | 新規バケットは原則作らない |
| CloudWatch | 既存ロググループ構成に倣う | 新規ロググループ追加 |
| Route 53 | 既存 hosted zone | サブドメイン mcp.mappy.<existing-domain> を追加 |
| AWS Account | 635388747933 | 同一アカウント |
2.2 新規追加するもの
| 項目 | 理由 |
|---|---|
| ALB | MCP は独立ドメインで動かす(既存 ALB と分離) |
| ElastiCache(Redis) | OAuth 認可コード・セッション・レート制限カウンタ |
| Secrets Manager | JWT 署名鍵・OAuth クライアントシークレット |
| ECS サービス | h2t-mcp-server Fargate |
| セキュリティグループ | h2t-sg-mcp, h2t-sg-mcp-redis |
| ACM 証明書 | mcp.mappy.example.com(仮) |
| WAF | DDoS / レート制限の補強(任意) |
3. 全体構成図
4. コンテナ構成(ECS Fargate)
4.1 タスク定義
| 項目 | 値 |
|---|---|
| タスク定義ファミリー | h2t-mcp-server |
| 起動タイプ | Fargate |
| プラットフォームバージョン | LATEST |
| CPU | 0.5 vCPU(Phase 1)/ 1 vCPU(Phase 2 以降) |
| メモリ | 1 GB(Phase 1)/ 2 GB(Phase 2 以降) |
| ネットワークモード | awsvpc |
| タスクロール | h2t-mcp-task-role |
| 実行ロール | h2t-mcp-execution-role |
| ログドライバー | awslogs |
| ロググループ | /ecs/h2t-mcp-server |
4.2 コンテナ定義
| 項目 | 値 |
|---|---|
| イメージ | 635388747933.dkr.ecr.ap-northeast-1.amazonaws.com/h2t-mappy-mcp:<tag> |
| ポート | 8000(コンテナ内)→ ALB から HTTP で転送 |
| ヘルスチェック | GET /health(30 秒間隔、5 秒タイムアウト、リトライ 3 回) |
| ストップタイムアウト | 30 秒(Streamable HTTP のグレースフルシャットダウン) |
| 環境変数 | 後述「環境変数・シークレット」 |
4.3 サービス定義
| 項目 | 値 |
|---|---|
| サービス名 | h2t-mcp-server |
| クラスター | h2t-cluster(既存)または新規 h2t-mcp-cluster |
| 希望タスク数 | Phase 1: 2 / Phase 2: 4 / Phase 3: 6 |
| 最小タスク数 | 2 |
| 最大タスク数 | 10 |
| デプロイタイプ | Rolling Update(minimum healthy 50%、maximum 200%) |
| Auto Scaling | Target Tracking(CPU 70%、リクエスト数 100/分) |
| ロードバランサー | h2t-mcp-alb ターゲットグループ h2t-mcp-tg |
| サービスディスカバリ | 任意 |
Streamable HTTP の sticky session
MCP の Streamable HTTP セッションは long-lived。ALB の sticky session 設定が必要(同一クライアントは同一タスクへ)。または Redis にセッション状態を集中して、stateless にする設計も可。 本設計では Redis 集中管理(stateless) を採用する。
5. ロードバランサー(ALB)
5.1 構成
| 項目 | 値 |
|---|---|
| ALB 名 | h2t-mcp-alb |
| スキーム | internet-facing |
| サブネット | h2t-public-1a, h2t-public-1c |
| セキュリティグループ | h2t-sg-mcp-alb(新規) |
| アイドルタイムアウト | 600 秒(Streamable HTTP の長時間接続対応) |
| HTTP/2 | 有効 |
| WAF アタッチ | optional(Phase 2 以降検討) |
5.2 リスナー
| ポート | プロトコル | 動作 |
|---|---|---|
| 80 | HTTP | 301 リダイレクトで HTTPS へ |
| 443 | HTTPS | ACM 証明書、ターゲットグループ h2t-mcp-tg へ転送 |
5.3 ターゲットグループ
| 項目 | 値 |
|---|---|
| 名前 | h2t-mcp-tg |
| プロトコル | HTTP |
| ポート | 8000 |
| ヘルスチェックパス | /health |
| ヘルスチェック間隔 | 30 秒 |
| ヘルスチェック閾値 | 成功 2 回、失敗 3 回 |
| デレジストレーション遅延 | 30 秒(接続終了待ち) |
| Sticky session | 無効(Redis 集中管理のため) |
6. データストア
6.1 ElastiCache Redis(新規)
OAuth 認可コード・セッション・レート制限・idempotency キャッシュ用。
| 項目 | 値 |
|---|---|
| エンジン | Redis 7.x |
| ノードタイプ | cache.t4g.micro(Phase 1)/ cache.t4g.small(Phase 2 以降) |
| ノード数 | 1(Phase 1、Multi-AZ なし)/ Cluster Mode(Phase 3 で検討) |
| サブネット | h2t-private-1a, h2t-private-1c |
| セキュリティグループ | h2t-sg-mcp-redis |
| 暗号化 (at-rest) | 有効 |
| 暗号化 (in-transit) | 有効(TLS) |
| 認証 | Redis AUTH(Secrets Manager で管理) |
| バックアップ | 日次スナップショット、7 日保持 |
| maintenance window | 火曜 04:00-05:00 JST |
キー設計
| プレフィックス | 用途 | TTL |
|---|---|---|
oauth:code:<hash> | 認可コード | 60 秒 |
oauth:state:<hash> | state パラメータ検証 | 5 分 |
mcp:session:<id> | Streamable HTTP セッション | 30 分(idle) |
idempotency:<client_id>:<user_id>:<key> | 冪等性キャッシュ | 24 時間 |
confirm:<token> | 一括反映の確認トークン | 5 分 |
ratelimit:<scope>:<key> | レート制限カウンタ | 1 分〜1 時間 |
jwt:revoke:<jti> | アクセストークン失効リスト(Bloom Filter キャッシュ) | JWT exp まで |
6.2 RDS(既存)
mappy DB に MCP 用テーブル群を追加:
mappy_mcp_audit_logsmappy_mcp_batchesmappy_mcp_rate_limit_logsmappy_mcp_oauth_clientsmappy_mcp_oauth_consentsmappy_mcp_oauth_refresh_tokensmappy_mcp_oauth_access_token_revocations
RDS 接続元の SG 更新
既存 h2t-sg-rds のインバウンドに 新規 h2t-sg-mcp からの 3306 アクセスを追加する。
7. ECR・コンテナイメージ
7.1 リポジトリ
| 名前 | URI |
|---|---|
h2t-mappy-mcp | 635388747933.dkr.ecr.ap-northeast-1.amazonaws.com/h2t-mappy-mcp |
7.2 イメージタグ規約
| タグ | 用途 |
|---|---|
latest | 最新 main ブランチ |
v1.0.0 | リリース版 |
staging-<sha> | ステージング |
dev-<sha> | 開発環境 |
7.3 イメージ構成
案A: Python (FastMCP)
dockerfile
FROM python:3.11-slim
WORKDIR /app
COPY pyproject.toml uv.lock /app/
RUN pip install --no-cache-dir uv && \
uv sync --frozen --no-dev
COPY src/ /app/src/
USER 1000
EXPOSE 8000
CMD ["uvicorn", "src.main:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "4"]案B: TypeScript
dockerfile
FROM node:20-alpine AS build
WORKDIR /app
COPY package.json pnpm-lock.yaml /app/
RUN corepack enable && pnpm install --frozen-lockfile
COPY src/ /app/src/
COPY tsconfig.json /app/
RUN pnpm build
FROM node:20-alpine AS runtime
WORKDIR /app
COPY --from=build /app/node_modules /app/node_modules
COPY --from=build /app/dist /app/dist
COPY package.json /app/
USER 1000
EXPOSE 8000
CMD ["node", "dist/main.js"]7.4 イメージサイズ目安
| 言語 | 期待サイズ |
|---|---|
| Python (slim base) | 約 200 MB |
| Node.js (alpine base) | 約 150 MB |
8. ネットワーク・セキュリティグループ
8.1 新規 SG
| SG 名 | インバウンド | 用途 |
|---|---|---|
h2t-sg-mcp-alb | 80 / 443 from 0.0.0.0/0 | ALB |
h2t-sg-mcp | 8000 from h2t-sg-mcp-alb | ECS タスク |
h2t-sg-mcp-redis | 6379 from h2t-sg-mcp | Redis |
8.2 既存 SG への追加
| 既存 SG | 追加インバウンド |
|---|---|
h2t-sg-rds | 3306 from h2t-sg-mcp |
8.3 アウトバウンド
全 SG で:
- 443 to 0.0.0.0/0(GBP API・外部 API 用)
- 53 to 0.0.0.0/0(DNS)
- VPC エンドポイントを使う場合は不要
9. 環境変数・シークレット
9.1 環境変数(タスク定義に直接記述)
| 変数名 | 例 |
|---|---|
APP_ENV | production / staging |
LOG_LEVEL | INFO |
MCP_BASE_URL | https://mcp.mappy.example.com |
OAUTH_ISSUER | 同上 |
OAUTH_AUDIENCE | mappy-mcp |
LARAVEL_API_BASE_URL | https://api.mappy.example.com |
REDIS_HOST | h2t-mcp-redis.cache.amazonaws.com |
REDIS_PORT | 6379 |
RDS_HOST | 既存 |
RDS_DATABASE | mappy |
9.2 Secrets Manager(参照のみ)
| Secret 名 | 内容 |
|---|---|
h2t-mcp/jwt-signing-keys | JWT 署名鍵(RS256 のプライベートキー、複数 kid) |
h2t-mcp/redis-auth-token | Redis AUTH トークン |
h2t-mcp/rds-credentials | DB ユーザー名・パスワード |
h2t-mcp/laravel-api-token | Laravel API への内部認証トークン |
h2t-mcp/oauth-client-secrets | 信頼クライアントの secret(registry) |
タスクロールに以下の IAM ポリシーを付与:
json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["secretsmanager:GetSecretValue"],
"Resource": [
"arn:aws:secretsmanager:ap-northeast-1:635388747933:secret:h2t-mcp/*"
]
},
{
"Effect": "Allow",
"Action": [
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": [
"arn:aws:logs:ap-northeast-1:635388747933:log-group:/ecs/h2t-mcp-server:*"
]
}
]
}10. Route 53 / ドメイン
| 項目 | 値 |
|---|---|
| ドメイン | mcp.mappy.example.com(仮、確定はレビュー時) |
| ALB エイリアス | h2t-mcp-alb-xxxxxxxx.ap-northeast-1.elb.amazonaws.com |
| レコード種別 | A (alias) |
| ヘルスチェック | 任意(CloudWatch でカバー可) |
10.1 ドメイン候補
| 案 | 例 | 注意点 |
|---|---|---|
| サブドメイン分離 | mcp.mappy.example.com | 推奨。CORS・Cookie 分離が容易 |
| パス分離 | mappy.example.com/mcp | NG。Streamable HTTP の長時間接続と既存 ALB 設定が干渉 |
| 別ドメイン | mappy-mcp.com | 新規ドメイン取得コスト・SEO 配慮不要なら可 |
11. CI/CD
11.1 既存方式に倣う
| ステップ | 内容 |
|---|---|
| コードリポジトリ | h2t/mappy-mcp(新規)または h2t/mappy 配下に subdirectory |
| ビルドパイプライン | GitLab CI(既存 CI 流用) |
| ビルド対象 | Dockerfile から ECR h2t-mappy-mcp へ push |
| デプロイ | ECS サービス更新(タスク定義の新リビジョン適用) |
| ロールバック | 前リビジョンへ revert |
11.2 環境分け
| 環境 | ALB | ECS サービス | Redis | RDS |
|---|---|---|---|---|
| 本番 | h2t-mcp-alb | h2t-mcp-server | h2t-mcp-redis | h2t-db |
| ステージング | h2t-mcp-alb-stg | h2t-mcp-server-stg | h2t-mcp-redis-stg | h2t-db-stg |
| 開発 | (ローカル docker-compose) | - | (ローカル Redis) | (ローカル MySQL) |
12. 監視・アラート
12.1 CloudWatch Metrics
| メトリクス | 閾値 | アクション |
|---|---|---|
| ECS CPU 利用率 | > 80% (5 分) | Auto Scaling + 通知 |
| ECS Memory 利用率 | > 80% (5 分) | 通知 |
| ALB 5xx 率 | > 1% (5 分) | CRITICAL 通知 |
| ALB Target Health | < 50% healthy | CRITICAL 通知 |
| ALB レスポンス時間 | p99 > 3 秒 (5 分) | WARNING 通知 |
| Redis CPU | > 70% (5 分) | スケールアップ検討 |
| Redis メモリ | > 80% | スケールアップ |
| RDS 接続数 | > 80% max_connections | WARNING |
12.2 CloudWatch Logs
| ロググループ | 保持期間 |
|---|---|
/ecs/h2t-mcp-server | 30 日 |
/ecs/h2t-mcp-server-access | 90 日 |
/ecs/h2t-mcp-server-audit | 1 年 |
12.3 ログのフィールド規約
JSON 形式で構造化、以下のフィールドを必ず含める:
json
{
"timestamp": "2026-05-26T10:00:00Z",
"level": "INFO",
"service": "mcp-server",
"request_id": "...",
"user_id": 1435,
"client_id": "...",
"tool_name": "location.list",
"elapsed_ms": 123,
"message": "tool executed"
}12.4 アラート通知
- Slack #h2t-mcp-alerts チャンネル
- CRITICAL は電話通知 + メール
13. バックアップ・DR
| 対象 | 方法 | 頻度 |
|---|---|---|
| RDS データ | 自動バックアップ(既存) | 日次 7 日 |
| Redis データ | スナップショット | 日次 7 日 |
| ECS タスク定義 | バージョン管理(自動) | 自動 |
| Secrets Manager | バージョン保持 | 自動 |
RTO(復旧目標時間): 1 時間以内 RPO(復旧目標時点): 直近 24 時間以内のデータ復旧
14. コスト試算(Phase 1)
| リソース | 月額試算 |
|---|---|
| ECS Fargate(2 タスク × 0.5 vCPU / 1 GB) | 約 30 USD |
| ALB | 約 25 USD |
| ElastiCache Redis(cache.t4g.micro) | 約 15 USD |
| ACM 証明書 | 無料 |
| Route 53 | 約 1 USD |
| Secrets Manager(5 secret) | 約 2 USD |
| CloudWatch Logs(30 日 × 5 GB) | 約 5 USD |
| ECR ストレージ | 約 1 USD |
| データ転送 | 約 5 USD |
| 合計 | 約 84 USD/月 |
Phase 2 以降:
- ECS タスク増加(4 タスク × 1 vCPU / 2 GB) → 約 120 USD/月
- Redis スケールアップ → 約 30 USD/月
- 合計:約 180 USD/月
コスト最適化
- Phase 1 では Fargate Spot を活用すれば 30〜50% 削減可
- 既存 RDS に同居するため DB コストは追加なし
- ステージング環境は Fargate Spot + ノード 1 で運用可
15. セキュリティチェックリスト
| 項目 | 状態 |
|---|---|
| ALB は HTTPS のみ(HTTP は 301 リダイレクト) | ✅ |
| ECS タスクは private subnet 配置 | ✅ |
| Redis は in-transit + at-rest 暗号化 | ✅ |
| RDS は既存設定(暗号化済み) | ✅ |
| Secrets Manager の参照は IAM で制限 | ✅ |
| WAF(Phase 2 以降検討) | 🔵 |
| VPC エンドポイントで AWS API トラフィック内製化 | 🔵(推奨) |
| GuardDuty 有効(既存) | ✅ |
| AWS Config によるリソース変更追跡 | 既存設定に従う |
| アクセスログを S3 へ集約 | 🔵 |
16. デプロイ手順(Phase 1 初回)
基盤準備
- 新規 SG 作成(
h2t-sg-mcp-alb/h2t-sg-mcp/h2t-sg-mcp-redis) - 既存
h2t-sg-rdsにインバウンド追加 - ElastiCache Redis インスタンス作成
- Secrets Manager に JWT 鍵・各種シークレット保管
- ECR リポジトリ
h2t-mappy-mcp作成
- 新規 SG 作成(
DB マイグレーション
ALB 構築
- ACM 証明書発行(
mcp.mappy.example.com) - ALB / ターゲットグループ作成
- Route 53 レコード追加
- ACM 証明書発行(
ECS 構築
- クラスター(既存流用 or 新規)
- タスク定義(IAM ロール、環境変数、Secrets 参照)
- サービス作成(ALB 連携、Auto Scaling)
アプリ初回デプロイ
- Dockerfile ビルド & ECR push
- ECS サービス更新
動作確認
/health応答確認/.well-known/oauth-authorization-server確認- Claude Desktop / ChatGPT からの接続テスト
監視・アラート設定
- CloudWatch Alarm 作成
- Slack 通知設定
17. 未確定事項(設計レビューで決定)
| # | 項目 | 候補 |
|---|---|---|
| 1 | MCP 用ドメイン名 | mcp.mappy.example.com(仮) |
| 2 | ECS クラスター | 既存流用 / 新規 |
| 3 | WAF 導入時期 | Phase 1 / Phase 2 |
| 4 | Redis Multi-AZ | Phase 1 で対応 / Phase 2 以降 |
| 5 | Fargate Spot の活用範囲 | 全本番 / ステージングのみ |
| 6 | リポジトリ構成 | h2t/mappy-mcp 新設 / h2t/mappy 配下 |
| 7 | デプロイ承認フロー | 自動 / 手動承認 |
| 8 | VPC エンドポイント導入 | 即時 / Phase 2 |