Skip to main content
Glama
yokko001

Company Secure Python MCP

by yokko001
README.md
# Company Secure Python MCP

Copilot Studio から使うことだけを想定した、クリーンルーム設計の最小MCPサーバーです。旧 `m365-copilot-companion-mcp` のコードは再利用していません。親ディレクトリの監査レポートを負の要件として扱い、機能を6ツールに削減しています。

現時点の位置付けは「セキュリティレビュー可能な参照実装」です。専用VMまたは専用rootless Docker、Entra ID、TLS終端、鍵ACL、社内レジストリ、DLP/SIEMを構成し、実Docker結合試験を完了するまでは本番投入しないでください。

## 提供する機能

| ツール | 機能 | 主な制約 |
|---|---|---|
| `workspace_list` | 1階層の一覧 | 共通入力・本人入力・本人出力のみ、最大200件 |
| `workspace_read_text` | UTF-8テキスト読取り | 許可拡張子、1 MiB、最大20万文字、未信頼データ表示 |
| `workspace_write_text` | テキスト新規作成 | 本人出力のみ、上書き・削除不可、許可拡張子のみ |
| `python_prepare` | 実行要求の固定 | コード・入力ハッシュ・出力名を固定し、実行しない |
| `python_status` | 本人要求の状態確認 | コード本文や承認署名は返さない |
| `python_run` | 承認済み要求の実行 | 別経路署名、1回限り、Docker、ネットワークなし |

メール、予定表、クリップボード、レジストリ、ODBC、Web取得、任意URL、Shell、PowerShell、パッケージ導入、自己更新、自動起動、ブラウザ操作、Tool Forge、トンネル、汎用ツール中継は実装していません。

## 信頼境界

```mermaid
flowchart LR
    CS[Copilot Studio] -->|OAuth 2.0 delegated token / TLS| RP[Reverse proxy / WAF]
    RP -->|loopback or private hop| MCP[6-tool MCP service]
    MCP -->|JWKS only| ENTRA[Microsoft Entra ID]
    MCP -->|scoped access| WS[Per-user workspace]
    MCP -->|immutable request| Q[Control queue]
    REVIEW[Separate reviewer account] -->|Ed25519 signed approval| Q
    Q -->|one-time claim| RUN[Dedicated/rootless Docker runner]
    RUN -->|network=none / read-only / limits| JOB[Python container]
    JOB -->|declared UTF-8 outputs only| WS
    MCP -->|HMAC chain; no content| AUDIT[Audit log -> SIEM]
```

承認秘密鍵はMCPサービスに渡しません。MCPサービスが持つのは承認公開鍵と監査鍵だけです。PythonコードはホストPythonで実行せず、ローカル実行へのフォールバックもありません。

## 最初に読む文書

- [セキュリティ設計レポート](SECURITY_DESIGN_REPORT_JA.md)
- [導入手順](DEPLOYMENT_JA.md)
- [脅威モデル](THREAT_MODEL_JA.md)
- [セキュリティ試験計画](SECURITY_TEST_PLAN_JA.md)
- [脆弱性対応方針](SECURITY.md)

## 開発環境での確認

```powershell
python -m venv .venv
.\.venv\Scripts\python.exe -m pip install uv
.\.venv\Scripts\uv.exe sync --frozen --extra dev
.\scripts\Invoke-SecurityChecks.ps1 -PythonExecutable .\.venv\Scripts\python.exe
```

本番ではインターネット上のPyPIから直接導入せず、承認済み社内ミラーと `requirements.lock` の固定hashを使用してください。`uv.lock` は開発・検証環境も固定します。`.env` は読み込みません。設定はサービス管理基盤からプロセス環境へ渡します。

## Pythonジョブの契約

- 入力: `/work/input/manifest.json` と `/work/input/<固定名>`(読取り専用)
- 出力: `/work/output/<python_prepareで宣言したファイル名>`
- 公開名: 衝突防止のため `<request-id>-<連番>.<拡張子>` として本人出力へ新規作成
- 出力形式: UTF-8の `.txt`、`.md`、`.csv`、`.json`
- 標準出力・標準エラー: 破棄し、モデルへ返さない
- ネットワーク: なし
- 実行時間: 既定60秒、最大300秒
- メモリ: 256 MiB、CPU: 1、PID: 64

ASTのimport許可リストは多層防御であり、Pythonサンドボックスとはみなしません。実際の境界は、別経路承認と専用VM/rootless DockerのOS分離です。

タイムアウト時に `docker rm -f` の成功を確認できなければランナーをquarantine状態にし、以後のPython実行を全拒否して実行ディレクトリを保全します。運用者が専用VMを破棄・再構築するまで再開しません。