Slack MCP Agent — 技術選定
v1.3 / 2026-04-20
ADR (Architecture Decision Record) 形式で、MVP の技術選定理由と棄却した代替案を記録する。
将来の選定見直し時に「なぜこの判断をしたか」を追跡可能にする。
ADR-001: Backend 言語 — Python
ステータス: 採用
コンテキスト
- Anthropic SDK の Python 版が最も機能が充実 (Managed Agents beta 含む)
- Slack Bolt の Python 版が安定
- 開発者 (1 名) が Python に精通
- プロトタイプが既に Python で実装済み
決定
Python 3.12+ を使用する。
代替案と棄却理由
| 代替案 |
棄却理由 |
| TypeScript (Node.js) |
Anthropic SDK の beta 機能 (Managed Agents) が Python 版でのみ先行リリースされている。Slack Bolt も Python 版と同等だが、プロトタイプからの移行コストが発生 |
| Go |
Anthropic 公式 SDK なし。Slack SDK は存在するが Bolt 相当のフレームワークがない |
影響
- Backend と MCP Server を同一言語で統一できる
- 型安全性は dataclass + Pydantic v2 で補完
ADR-002: LLM — Anthropic Claude (Messages API + Managed Agents)
ステータス: 採用
コンテキスト
- 先行プロジェクト caster-division-ai が Anthropic Managed Agents で実装済み
- L1-L3 は Messages API (1-shot)、L4 は Managed Agents API (エージェントループ)
- Custom Tool パターンで認証情報を Agent に渡さない設計が可能
決定
- L1-L3:
anthropic.AsyncAnthropic.messages.create (claude-sonnet-4-6)
- L4:
beta.sessions.create/retrieve/events (Managed Agents)
代替案と棄却理由
| 代替案 |
棄却理由 |
| OpenAI GPT-4o + Assistants API |
Custom Tool の pause/resume パターンが Anthropic ほど成熟していない。caster-division-ai の知見が活かせない |
| LangChain / LangGraph |
抽象化レイヤーが厚く、Managed Agents の beta API に追従が遅れる。直接 SDK 利用の方がデバッグ容易 |
| 自前 Agent ループ |
L4 のツール呼出ループ、リトライ、コンテキスト管理を自前実装するコストが大きい。Managed Agents に委譲する方が MVP 速度に寄与 |
影響
- Anthropic API の beta 変更に追従が必要
- Managed Agents の制約 (MCP Server 必須、ngrok 必要) を受け入れる
ADR-003: DB — SQLite (aiosqlite)
ステータス: 採用
コンテキスト
- MVP はローカル実行、1 人運用
- Backend (Python) と Web (Next.js) の両方から同一データを参照する必要がある
- デプロイ・インフラの最小化が優先
決定
SQLite (WAL モード) + aiosqlite (Python 側) + better-sqlite3 (Node.js 側)。
代替案と棄却理由
| 代替案 |
棄却理由 |
| PostgreSQL |
ローカル開発でも別プロセスの起動が必要。1 人運用 MVP にはオーバースペック。Post-MVP で検討 |
| Firestore |
caster-division-ai で使用中だが、ローカル開発にエミュレータが必要。リアルタイムリスナーは本プロジェクトでは不要 |
| DynamoDB |
AWS 依存。ローカル開発コスト大 |
| Turso (libSQL) |
SQLite 互換で将来の分散化に有利だが、MVP では通常 SQLite で十分 |
トレードオフ
- 利点: ファイル 1 つで完結、デプロイ不要、Backend/Web で共有容易
- 欠点: 同時書込に弱い (WAL で軽減)、スケールアウト不可
- 移行パス: Post-MVP で PostgreSQL or Turso への移行を想定。SQL は標準的な構文で書き、ORM は使わない (移行容易性)
ADR-004: Slack 連携 — Slack Bolt (Socket Mode)
ステータス: 採用
コンテキスト
- プロトタイプが Socket Mode で実装済み
- Socket Mode はインバウンド HTTPS 不要 (ngrok は MCP 用のみ)
- Events API + Interactive Components + Agent Container を統合的に扱えるフレームワークが必要
決定
slack-bolt (Python) + Socket Mode。
代替案と棄却理由
| 代替案 |
棄却理由 |
| HTTP Mode (Events API) |
開発環境で ngrok が必要になる (MCP Server と合わせて 2 つ)。Socket Mode の方がローカル開発が楽 |
| slack-sdk のみ (Bolt なし) |
Event ルーティング、ack タイムアウト処理、ミドルウェアを自前実装する必要がある |
| Slack API 直接 (requests) |
SDK の型安全性・retry 処理を自前で再実装する意味がない |
影響
- Socket Mode ではアプリ配信先が制限される (Slack App Directory 非公開)
- Post-MVP で HTTP Mode への切替を検討
ADR-005: Web フレームワーク — Next.js (App Router)
ステータス: 採用
コンテキスト
- 管理画面は MVP 4 画面(パイプライン一覧/詳細、設定、外部連携)。監査ログとログイン画面は Post-MVP
- 主に読み取り表示 (Server Components に適合)
- 設定変更・外部連携は Server Actions で処理
決定
Next.js 16+ (App Router, Server Components 主体)。現行は next@16.2.4。
代替案と棄却理由
| 代替案 |
棄却理由 |
| Remix |
Server Components のストリーミング対応が Next.js に劣る。コミュニティ・エコシステムが小さい |
| SvelteKit |
開発者の習熟度が低い。shadcn/ui 相当のコンポーネントライブラリが少ない |
| Streamlit |
Python 完結だが、カスタム UI の自由度が低い。shadcn/ui 相当のデザインシステムが使えない |
| Flask/FastAPI + React SPA |
Backend が 2 プロセスになる (Slack Bolt + Web API)。Next.js は SSR + SQLite 直接参照でプロセス増を避けられる |
| Gradio |
ML デモ向き。管理画面の CRUD には不向き |
影響
- TypeScript でのフロントエンド実装が必要 (Backend は Python)
- SQLite を Node.js から読むため better-sqlite3 を使用
ADR-006: UI コンポーネント — Tailwind CSS v4 + shadcn/ui
ステータス: 採用
コンテキスト
- DESIGN.md でデザイントークン・コンポーネント規約を定義済み
- AI による実装を前提に、コードベースに直接存在するコンポーネントが望ましい
- ダークモード対応が必要
決定
Tailwind CSS v4 + shadcn/ui (Radix UI ベース)。
代替案と棄却理由
| 代替案 |
棄却理由 |
| MUI (Material UI) |
バンドルサイズ大。テーマカスタマイズの学習コスト。Server Components との相性が悪い |
| Chakra UI |
v3 で RSC 対応が進んでいるが、shadcn/ui の方がソースコードが手元にあり AI がカスタマイズしやすい |
| Ant Design |
企業向け UI だが日本語ロケール・ダークモード対応にカスタムが必要 |
| CSS Modules |
コンポーネントライブラリなし。全て自前実装が必要 |
影響
npx shadcn@latest add でコンポーネントをプロジェクトにコピーする運用
- コンポーネントは
components/ui/ に配置され、直接編集可能
ADR-007: パッケージ管理 — uv (Python) + pnpm (Node.js)
ステータス: 採用
コンテキスト
- Python 側: Backend + MCP Servers で依存管理が必要
- Node.js 側: Web フロントエンドの依存管理
- 開発速度と再現性を重視
決定
- Python: uv (高速な pip 互換 + venv 管理 + pyproject.toml)
- Node.js: pnpm (高速・ディスク効率の良い node_modules)
代替案と棄却理由
| 代替案 |
棄却理由 |
| Poetry (Python) |
uv の方が 10-100 倍高速。lock ファイル形式は uv が標準化の方向 |
| pip + venv (Python) |
lock ファイルが標準でない。依存解決が遅い |
| npm (Node.js) |
pnpm の方がディスク効率が良く、phantom dependency を防げる |
| yarn (Node.js) |
pnpm と比較して大きな優位性なし。Plug'n'Play モードはツール互換性に課題 |
ADR-008: ID 生成 — ULID
ステータス: 採用
コンテキスト
- 全テーブルの PK に使用
- 時系列ソートが可能な分散 ID が望ましい
- SQLite は TEXT 型で PK を管理
決定
ULID (Universally Unique Lexicographically Sortable Identifier)。ulid-py ライブラリ使用。
代替案と棄却理由
| 代替案 |
棄却理由 |
| UUID v4 |
ランダムのためソート不可。インデックス性能で ULID に劣る |
| UUID v7 |
時系列ソート可能だが、Python のネイティブサポートが限定的 |
| AUTO INCREMENT |
分散環境で衝突。Post-MVP のマルチテナント・マイグレーション時に問題 |
| nanoid |
時系列ソート不可 |
ADR-009: MCP Server フレームワーク — FastMCP
ステータス: 採用
コンテキスト
- Managed Agents がツール実行に MCP プロトコルを使用
- MCP Server は HTTP (streamable-http) で公開
- プロトタイプで FastMCP を採用済み
決定
FastMCP (mcp.server.fastmcp.FastMCP) + streamable-http トランスポート。
代替案と棄却理由
| 代替案 |
棄却理由 |
| mcp-server (低レベル SDK) |
FastMCP の方がデコレータベースで記述量が少ない |
| 自前 HTTP サーバー |
MCP プロトコルのハンドシェイク・ストリーミングを自前実装する意味がない |
ステータス: 採用
コンテキスト
- freee OAuth トークンは HR 個人情報へのアクセス権を持つ
- caster-division-ai の Custom Tool パターンを踏襲
- 認証情報を Anthropic Cloud や MCP Server に渡したくない
決定
freee API の呼出は Backend プロセス内の Custom Tool Executor で行う。Managed Agent の custom_tool_use イベントを Backend がポーリングで検知し、Backend 内で freee API を呼出、結果を tool_result として返送する。
代替案と棄却理由
| 代替案 |
棄却理由 |
| MCP Server 経由 (hr-freee) |
OAuth トークンが MCP Server プロセスに存在する。ngrok 経由で Anthropic Cloud からアクセスされるため、トークンが外部経路を通るリスクがある |
| freee SDK 直接 (Agent 内) |
認証情報が Agent のコンテキストに入る。セキュリティポリシー違反 |
トレードオフ
- 利点: 認証情報が Backend 内で完結。監査ログ統合。Policy Engine 対応可能
- 欠点: L4 のポーリングループ内で
custom_tool_use イベントをハンドリングするコードが必要。MCP Server パターンより実装が複雑
備考
MVP 初期は MCP Server (hr-freee) 経由で動作確認し、Custom Tool Executor への移行はセキュリティ要件確認後に実施する可能性あり。
ADR-011: テスト — pytest + Playwright
ステータス: 採用
コンテキスト
- Backend は Python、Web は TypeScript
- TDD ベースの開発プロセス
- パイプライン各層の契約テストが重要
決定
- Python (Backend / MCP): pytest + pytest-asyncio
- Web: Vitest (ユニット) + Playwright (E2E)
- モック: unittest.mock (Python) + MSW (Web)
代替案と棄却理由
| 代替案 |
棄却理由 |
| unittest (Python) |
pytest の方がフィクスチャ・パラメタライズが強力 |
| Jest (Web) |
Vitest の方が Vite/Next.js との親和性が高く、ESM 対応が良い |
| Cypress (E2E) |
Playwright の方がマルチブラウザ対応が優れ、CI での安定性が高い |
ADR-012: 開発トンネル — ngrok
ステータス: 採用
コンテキスト
- Anthropic Cloud の Managed Agent が MCP Server にアクセスするため、localhost のポートを外部公開する必要がある
- Slack は Socket Mode のため ngrok 不要
決定
ngrok で MCP Server のポート (8001, 8002) を公開。
代替案と棄却理由
| 代替案 |
棄却理由 |
| Cloudflare Tunnel |
無料枠の制約。ngrok の方がセットアップが簡単 |
| localtunnel |
安定性に課題。商用利用での SLA なし |
| tailscale funnel |
Tailscale ネットワークのセットアップが必要 |
影響
- ngrok の URL は変動するため、Agent 定義の再作成が必要 (固定ドメインは有料)
setup-managed-agent.py で Agent 定義時に ngrok URL を指定
ADR-013: E2E 動作確認 — アクションシミュレーション + Playwright
ステータス: 採用
コンテキスト
- AI エージェントが自律的に動作確認を行う仕組みが必要
- Slack の承認/却下ボタン操作を自動化する方法として、Slack Web UI の Playwright 自動化と、Backend ハンドラの直接呼出しの 2 つの選択肢がある
- 管理画面(Next.js)のブラウザ検証には Playwright が適している
決定
- Slack ボタン操作:
scripts/simulate-action.py で backend/src/slack/actions.py の async ハンドラを直接呼出し。Slack Web UI の自動化は行わない
- Slack メッセージ送受信: Cursor の Slack MCP ツール (
slack_send_message, slack_read_thread) を使用
- 管理画面検証:
tests/e2e/ の Playwright (Chromium のみ) で事前定義スペック + 統合ユーティリティスクリプト
- ログ監視: Cursor ターミナルファイルの直接読み取り
代替案と棄却理由
| 代替案 |
棄却理由 |
| Playwright で Slack Web UI を自動化 |
DOM 構造が頻繁に変更される。Slack ログイン認証の管理が複雑。脆弱なテストになる |
| Backend に HTTP エンドポイントを追加 |
Socket Mode のアーキテクチャに HTTP サーバーを追加する必要があり、本番コードへの影響が大きい |
| pytest の既存 E2E テストのみ |
モック前提のため、実際の Slack カード更新や管理画面との整合性は検証できない |
トレードオフ
- 利点: 安定した自動化。実際の DB と Slack API を使用するため擬似 E2E として高い信頼性。管理画面は本物のブラウザで検証
- 欠点: Slack のボタン UI 自体のレンダリングは検証しない。DB 同時アクセスのタイミング制御が必要(WAL モード前提)
決定サマリー
| # |
領域 |
決定 |
代替案 (主要) |
| 001 |
Backend 言語 |
Python 3.12+ |
TypeScript |
| 002 |
LLM |
Anthropic Claude (Messages + Managed Agents) |
OpenAI, LangChain |
| 003 |
DB |
SQLite (aiosqlite + better-sqlite3) |
PostgreSQL, Firestore |
| 004 |
Slack |
slack-bolt (Socket Mode) |
HTTP Mode |
| 005 |
Web |
Next.js 16+ (App Router) |
Remix, Streamlit |
| 006 |
UI |
Tailwind CSS v4 + shadcn/ui |
MUI, Chakra UI |
| 007 |
パッケージ管理 |
uv + pnpm |
Poetry + npm |
| 008 |
ID |
ULID |
UUID v4/v7 |
| 009 |
MCP |
FastMCP (streamable-http) |
低レベル SDK |
| 010 |
freee 統合 |
Custom Tool Executor |
MCP Server 経由 |
| 011 |
テスト |
pytest + Vitest + Playwright |
unittest + Jest + Cypress |
| 012 |
トンネル |
ngrok |
Cloudflare Tunnel |
| 013 |
E2E 動作確認 |
アクションシミュレーション + Playwright |
Slack UI Playwright, HTTP エンドポイント |
| 014 |
ホスティング |
Railway (単一コンテナ + nginx) |
Cloud Run, ECS, Fly.io |
ADR-014: Railway 単一コンテナデプロイ
ステータス: 採用
コンテキスト
- チームメンバーが管理画面を触れるようにデプロイが必要
- main マージでの自動デプロイ (CD) を確立したい
- Backend + MCP Server + Web の 3 プロセスが SQLite ファイルを共有する
決定
Railway に単一コンテナとしてデプロイする。nginx リバースプロキシで / (Web) と /mcp/ (MCP Server) をルーティング。Backend は Socket Mode のためインバウンドポート不要。
代替案
| 案 |
棄却理由 |
| Cloud Run |
SQLite ファイル共有が困難 (サービス分割が必要) |
| ECS |
セットアップが重い (VPC, ALB, ECR 等) |
| Fly.io |
Volume サポートはあるが Railway の方が GitHub 連携と環境変数管理が優秀 |
| サービス分割 (Backend / Web / MCP 別コンテナ) |
SQLite 共有が不可能。PostgreSQL 移行が前提になりコストが増大 |
トレードオフ
- 利点: GitHub 連携 CD、Volume で SQLite 永続化、環境変数 UI、Free トライアルで検証可能
- 欠点: 単一コンテナのため個別スケール不可、プロセス管理がシェルスクリプトで簡素
- 移行パス: PostgreSQL 移行時にサービス分割し、Cloud Run / ECS に移行
変更履歴
| 日付 |
バージョン |
変更内容 |
| 2026-04-18 |
v1.0 |
初版: ADR-001 〜 ADR-012 |
| 2026-04-20 |
v1.1 |
ADR-013 追加: E2E 動作確認アプローチ |
| 2026-04-20 |
v1.2 |
ADR-014 追加: Railway 単一コンテナデプロイ (issue #31) |
| 2026-04-20 |
v1.3 |
実装整合: Next.js を 16+ に更新、管理画面 MVP 4 画面 + Post-MVP(監査ログ UI・ログイン画面)を明記 |