aws-samples / aws-samples/sample-ai-persona

[chore] MotherDuck MCP 廃止と DuckDB 構造化分析 tool 化

Open
#129 0 comments 0 reactions 0 assignees View on GitHub
enhancement
Dominant language
Python
Stars
24
Forks
6
Avg merge
8h 10m
Merged PRs (30d)
6

Description

## 概要

閉域対応(#128)の実装に着手する**前に**、公開環境で DuckDB 分析まわりの実行時インターネット依存を除去する。具体的には MotherDuck MCP(`uvx mcp-server-motherduck`)を廃止し、アプリケーション所有の構造化分析ツール(DuckDB backend)へ置換したうえで、DuckDB `httpfs` を container image へ事前組み込みする。

閉域化と dataset 分析方式の変更を同時に行わず、公開環境で機能回帰を確認してから同じ application artifact を閉域環境へ展開する。

調査根拠: `docs/note/closed-network-cognito-architecture-research.md`(8.2 / 8.3 / 10章)

## なぜ事前対応が必要か

現行の `src/services/mcp_server_manager.py` は `uvx mcp-server-motherduck` を `--read-write` で起動し、LLM へ任意 SQL を受け付ける `execute_query` を公開している。これは閉域対応の問題と密結合しており、先に切り離しておく:

- `uvx` による実行時 package download
- MCP subprocess と stdio session の起動・停止
- MCP 用 DuckDB と application 用 DuckDB の version 二重管理
- LLM による任意 SQL・任意 S3 path・local file 参照
- 公開用と閉域用で異なる dataset 分析実装

`INSTALL httpfs` は初回実行時に DuckDB extension repository へアクセスするため、閉域では動作しない。build 時に組み込み、runtime は `LOAD httpfs` のみとする。

> 対象は Fargate 内で起動する `mcp-server-motherduck`。AgentCore Gateway 用の `McpGatewayStack` は別機能であり、本対応の削除対象に含めない。

## 作業内容

### 1. 共通 tool contract と DuckDB backend

LLM には SQL ではなく分析目的を表す構造化引数だけを公開する。

```python
analyze_dataset(
dataset_id="...",
filters={"customer_id": {"eq": "123"}},
group_by=["category"],
metrics=["count", "sum:amount"],
order_by=["-sum:amount"],
limit=100,
)
```

`DatasetAnalysisService` で以下を強制:

- [ ] `dataset_id` から S3 path / Glue table を server 側で解決
- [ ] persona へ binding された dataset だけを許可
- [ ] binding filter を server 側で追加し、LLM から解除・上書き不可にする
- [ ] metadata 登録済みの column / operator / 集計関数だけを許可
- [ ] 値は parameterized query として渡す
- [ ] `LIMIT` / timeout / 返却文字数 / 同時 query 数へ上限を設ける
- [ ] SQL / S3 path / AWS credential / local file path を LLM へ公開しない
- [ ] query 対象・所要時間・件数・成功/失敗だけを監査 log へ記録
- [ ] 初期 backend は `DuckDBQueryBackend`(既存 parameterized query + pre-install 済み `httpfs`)。任意 SQL を受け取る method は公開しない
- [ ] ファイルからのペルソナ生成では temporary CSV path を LLM へ渡さず、server 発行の短命な `source_id` で解決し、処理終了時に必ず削除

### 2. 削除・変更対象(10.3)

| 対象 | 事前対応 |
|---|---|
| `src/services/mcp_server_manager.py` | subprocess lifecycle ごと削除 |
| `src/services/agent_service.py` | `get_mcp_tools()` を削除し、共通分析 tool factory を追加 |
| `src/services/survey_batch_service.py` | 構造化 query を実行する DuckDB backend を分離/共通化 |
| `src/managers/persona_generation_manager.py` | `use_mcp` を `enable_dataset_analysis` へ変更し、`source_id` を tool へ渡す |
| `src/managers/shared/agent_integration.py` | MCP ではなく共通分析 tool を Agent へ登録 |
| `src/managers/settings_manager.py` | MCP start/stop/status 操作を削除 |
| `web/routers/settings.py` | `/mcp/toggle`・`/mcp/status`・`/api/mcp/status` を削除 |
| `web/templates/settings/partials/mcp_status.html` | MCP process の toggle UI を削除 |
| `src/prompts/discussion_interview_prompts.py` | `execute_query`・`CREATE SECRET`・S3 path・SQL 例を削除 |
| MCP 関連 test | 共通 tool の allowlist / binding 強制 / 上限 / timeout test へ置換 |

kill switch が必要な場合は process 状態ではなく application 設定 `ENABLE_DATASET_ANALYSIS` で tool 登録自体を停止する。

### 3. Container の事前対応(10.4)

公開・閉域で Dockerfile を分けず、同じ image へ適用する。

- [ ] `uv sync --frozen` で DuckDB と Polars を固定
- [ ] Docker build 時に DuckDB `httpfs` を install
- [ ] runtime の `INSTALL httpfs` を `LOAD httpfs` へ変更
- [ ] `uv run` ではなく作成済み virtual environment の `uvicorn` を直接起動
- [ ] DuckDB の runtime extension 自動 install を無効化
- [ ] `uvx` および `mcp-server-motherduck` を application runtime から除去

```dockerfile
RUN uv sync --frozen \
&& /app/.venv/bin/python -c "import duckdb; c = duckdb.connect(); c.execute('INSTALL httpfs'); c.execute('LOAD httpfs'); c.close()"

CMD ["/app/.venv/bin/uvicorn", "web.main:app", "--host", "0.0.0.0", "--port", "80"]
```

## Rollout(10.5)

1. 共通 tool contract と `DuckDBQueryBackend` を追加
2. 既存 MCP と新 tool の結果を test dataset で比較
3. 公開 staging 環境で dataset binding / interview / discussion / persona 生成を回帰確認
4. 公開環境の Agent を新 tool へ切り替え
5. MCP manager / toggle API・UI / prompt 内 SQL 説明を削除
6. 公開本番で監査 log / error 率 / query 時間を確認
7. 完了後に閉域 stack 実装(#128)へ着手

移行中だけ内部 feature flag で旧・新実装を切り替え、移行完了後に旧 MCP 分岐と flag を削除。問題発生時は直前の immutable image digest へ rollback。

## 完了条件(10.6)

- [ ] application 起動後に package / DuckDB extension の download が発生しない
- [ ] application code から `uvx` / `mcp-server-motherduck` / `MCPServerManager` がなくなっている
- [ ] LLM へ任意 SQL / S3 path / local path / AWS credential を渡していない
- [ ] dataset binding を tool 引数で解除・上書きできない
- [ ] column / operator / 集計関数 / limit / timeout が server 側で制限されている
- [ ] network 無効の container test で `LOAD httpfs` と local dataset 分析が成功する
- [ ] 公開環境の dataset 連携と CSV ペルソナ生成の回帰 test が成功する
- [ ] 公開・閉域で同じ application image を使用できる

## スコープ外

- Athena 導入(8.7章): 本事前対応では追加せず、`DatasetQueryBackend` の実装差し替えで将来対応可能な構造にするに留める
- 閉域 stack 本体(VPC / VPCE / ALB / Fargate / Cognito API 認証): #128

Contributor guide

Open the contributing guide

Research direction

Start with docs/note/closed-network-cognito-architecture-research.md and trace the current MCP flow through src/services/mcp_server_manager.py, src/services/agent_service.py, src/services/survey_batch_service.py, and the listed managers, routers, prompts, and Dockerfile. Run the existing MCP-related tests and compare behavior on the test dataset; done means the structured backend passes binding, allowlist, limit, timeout, audit, and offline-container checks without runtime downloads or MotherDuck MCP.

Written by the indexing model from the issue text.

Assessment

Tech stack
aws, docker, python, sql
Domain
backend, cloud, data, databases
Issue type
Refactor
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.