From ae73ddf542d2ff14708d4dd30d42c52d38367639 Mon Sep 17 00:00:00 2001 From: vitocchi <38712518+vitocchi@users.noreply.github.com> Date: Thu, 5 Mar 2026 16:45:42 +0900 Subject: [PATCH 1/4] docs: add HODL1 fork notice and branch strategy to README Describe that this repo is a fork of googleworkspace/cli maintained by HODL1 (kushim-team), and document the branch strategy: main stays in sync with upstream, custom carries all HODL1-specific changes. Co-Authored-By: Claude Opus 4.6 --- README.md | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b28f3f38..c0e1da0f 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,33 @@ -

gws

+

gws (HODL1 Fork)

**One CLI for all of Google Workspace — built for humans and AI agents.**
Drive, Gmail, Calendar, and every Workspace API. Zero boilerplate. Structured JSON output. 40+ agent skills included. > [!NOTE] +> This is a fork of [googleworkspace/cli](https://github.com/googleworkspace/cli) maintained by **HODL1** (kushim-team). > This is **not** an officially supported Google product. +## Fork Branch Strategy + +This repository is a fork of [googleworkspace/cli](https://github.com/googleworkspace/cli) with the following branch strategy: + +| Branch | Purpose | +|--------|---------| +| `main` | Kept in sync with upstream `googleworkspace/cli` main. No custom changes. | +| `custom` | All HODL1-specific changes are developed here. | + +### Syncing with upstream + +```bash +git fetch upstream +git checkout main +git merge upstream/main +git checkout custom +git merge main +``` + +Upstream updates are merged (not rebased) into `custom` to preserve a clean, shared-friendly history. +

npm version license From fbe230e1c58a594936b46707770b442f178e40b9 Mon Sep 17 00:00:00 2001 From: vitocchi <38712518+vitocchi@users.noreply.github.com> Date: Thu, 5 Mar 2026 16:46:37 +0900 Subject: [PATCH 2/4] chore: add CLAUDE.md symlink to AGENTS.md Co-Authored-By: Claude Opus 4.6 --- CLAUDE.md | 1 + 1 file changed, 1 insertion(+) create mode 120000 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 120000 index 00000000..47dc3e3d --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +AGENTS.md \ No newline at end of file From 1313200c3a6ac3dac313739fad7eac4f98da6b40 Mon Sep 17 00:00:00 2001 From: vitocchi <38712518+vitocchi@users.noreply.github.com> Date: Thu, 5 Mar 2026 17:34:36 +0900 Subject: [PATCH 3/4] docs: update AGENTS.md and README.md with fork strategy and AI-DLC development cycle; add design, requirements, and tasks documents for Remote MCP Gateway --- AGENTS.md | 25 ++++ README.md | 22 ++++ specs/remote-mcp-gateway/design.md | 155 +++++++++++++++++++++++ specs/remote-mcp-gateway/requirements.md | 41 ++++++ specs/remote-mcp-gateway/tasks.md | 56 ++++++++ 5 files changed, 299 insertions(+) create mode 100644 specs/remote-mcp-gateway/design.md create mode 100644 specs/remote-mcp-gateway/requirements.md create mode 100644 specs/remote-mcp-gateway/tasks.md diff --git a/AGENTS.md b/AGENTS.md index 12fa1cad..4781b30d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -4,6 +4,31 @@ `gws` is a Rust CLI tool for interacting with Google Workspace APIs. It dynamically generates its command surface at runtime by parsing Google Discovery Service JSON documents. +> [!NOTE] +> This is a fork of [googleworkspace/cli](https://github.com/googleworkspace/cli) maintained by **HODL1** (kushim-team). +> This is **not** an officially supported Google product. + +### Fork Branch Strategy + +This repository is a fork of [googleworkspace/cli](https://github.com/googleworkspace/cli) with the following branch strategy: + +| Branch | Purpose | +|--------|---------| +| `main` | Kept in sync with upstream `googleworkspace/cli` main. No custom changes. | +| `custom` | All HODL1-specific changes are developed here. | + +#### Syncing with upstream + +```bash +git fetch upstream +git checkout main +git merge upstream/main +git checkout custom +git merge main +``` + +Upstream updates are merged (not rebased) into `custom` to preserve a clean, shared-friendly history. + > [!IMPORTANT] > **Dynamic Discovery**: This project does NOT use generated Rust crates (e.g., `google-drive3`) for API interaction. Instead, it fetches the Discovery JSON at runtime and builds `clap` commands dynamically. When adding a new service, you only need to register it in `src/services.rs` and verify the Discovery URL pattern in `src/discovery.rs`. Do NOT add new crates to `Cargo.toml` for standard Google APIs. diff --git a/README.md b/README.md index c0e1da0f..14559294 100644 --- a/README.md +++ b/README.md @@ -385,6 +385,28 @@ cargo test # unit tests ./scripts/coverage.sh # HTML coverage report → target/llvm-cov/html/ ``` +### AI-DLC 開発サイクル + +本プロジェクト (HODL1 fork) では [AI-DLC (AI-Driven Development Life Cycle)](https://aws.amazon.com/jp/blogs/devops/ai-driven-development-life-cycle/) に基づく開発サイクルを採用しています。 + +各フィーチャーの中間成果物は `specs//` に配置します。 + +``` +specs/ + remote-mcp-gateway/ + requirements.md # Inception: 要件定義 + design.md # Inception → Construction: 設計・決定事項 + tasks.md # Construction: 実装タスクのブレイクダウン +``` + +**開発の流れ:** + +1. **Inception** — 要件を `requirements.md` に整理し、設計判断を `design.md` にまとめる +2. **Construction** — `tasks.md` のタスクリストに従い実装する。AI エージェントは specs を読んでコンテキストを得る +3. **Operations** — デプロイ・運用に関する知見を specs にフィードバックする + +新しいフィーチャーを始めるときは `specs//` ディレクトリを作成し、同じ 3 ファイル構成で進めてください。 + ## License Apache-2.0 diff --git a/specs/remote-mcp-gateway/design.md b/specs/remote-mcp-gateway/design.md new file mode 100644 index 00000000..fb204016 --- /dev/null +++ b/specs/remote-mcp-gateway/design.md @@ -0,0 +1,155 @@ +# Remote MCP Gateway - Design + +## アーキテクチャ概要 + +``` +┌─────────────────────────┐ +│ Claude Desktop / │ +│ Claude Code │ +│ (各メンバーの端末) │ +└───────────┬─────────────┘ + │ MCP (Streamable HTTP) + │ + セッショントークン + ▼ +┌───────────────────────────────────┐ +│ MCP Gateway (Cloud Run) │ +│ │ +│ ┌─────────┐ ┌───────────────┐ │ +│ │ 認証層 │ │ 権限制御層 │ │ +│ │ OAuth2 │ │ メソッドID │ │ +│ │ Google │ │ ホワイトリスト │ │ +│ └────┬────┘ └───────┬───────┘ │ +│ │ │ │ +│ ┌────▼───────────────▼───────┐ │ +│ │ 実行層 │ │ +│ │ gws コア (Discovery JSON │ │ +│ │ → API 呼び出し) │ │ +│ └────────────┬───────────────┘ │ +│ │ │ +│ ┌────────────▼───────────────┐ │ +│ │ ログ層 │ │ +│ │ Cloud Logging │ │ +│ └────────────────────────────┘ │ +└───────────────────────────────────┘ + │ + ▼ + Google Workspace API +``` + +## 決定事項 + +| 項目 | 決定 | 理由 | +|------|------|------| +| MCP トランスポート | Streamable HTTP | 組織コネクタに必要 | +| 認証方式 | MCP OAuth フロー + Google OAuth 兼用 | 1回のログインで MCP 認証と Google API 認可を両立 | +| 権限粒度 | Discovery JSON メソッド ID 単位 | Google 公式の命名体系をそのまま利用でき、自前定義不要 | +| 権限デフォルト | 未登録ユーザーは何もできない | セキュリティ優先 | +| tools/list | ユーザー権限でフィルタ | エージェントの不要な試行を防止 | +| OAuth トークン保管 | サーバー側保持 | 組織コネクタの仕組み上クライアント送信は不可 | +| 権限設定 | Git リポジトリ内 YAML | PR レビューで変更管理、DB 不要 | +| 管理方法 | YAML 編集 → PR → マージ → 再デプロイ | エンジニア向け、変更履歴が残る | +| デプロイ先 | Cloud Run (GCP) | コンテナ化、スケーリング、IAM 連携 | +| 利用統計 | Cloud Logging | 20名規模なら十分 | +| OAuth スコープ | 全サービス一括要求 | 権限制御は自前レイヤーで絞る | + +## 認証フロー + +``` +1. ユーザーが Claude 上でコネクタを初回利用 +2. Claude が MCP Gateway の認可エンドポイントにリダイレクト +3. MCP Gateway が Google OAuth 同意画面を表示 +4. ユーザーが自分の Google アカウントで同意 +5. MCP Gateway が Google OAuth トークンをサーバー側に保存 +6. MCP Gateway がセッショントークンを発行し Claude に返す +7. 以降、Claude はセッショントークンを MCP リクエストに付与 +8. MCP Gateway はセッショントークンからユーザーを特定し、 + 保存済みの Google OAuth トークンで API を呼び出す +``` + +## 権限制御 + +### メソッド ID + +Discovery JSON で Google が公式に定義する一意識別子。 + +| メソッド ID | 操作内容 | +|-------------|----------| +| `gmail.users.messages.list` | メール一覧取得 | +| `gmail.users.messages.get` | メール取得 | +| `gmail.users.messages.send` | メール送信 | +| `drive.files.list` | ファイル一覧取得 | +| `drive.files.get` | ファイル取得 | +| `drive.files.create` | ファイル作成 | + +### ワイルドカード + +- `*` — 全メソッド許可 +- `gmail.*` — Gmail の全メソッド許可 +- `gmail.users.messages.*` — Gmail メッセージ関連の全メソッド許可 + +### 権限設定ファイル + +```yaml +# config/permissions.yaml + +roles: + admin: + allow: + - "*" + + workspace-reader: + allow: + - "gmail.users.messages.list" + - "gmail.users.messages.get" + - "gmail.users.labels.list" + - "drive.files.list" + - "drive.files.get" + - "calendar.events.list" + - "calendar.events.get" + + gmail-full: + allow: + - "gmail.*" + +users: + admin@company.com: + role: admin + + tanaka@company.com: + role: workspace-reader + + suzuki@company.com: + role: gmail-full +``` + +### リクエスト処理フロー + +``` +1. Claude から MCP リクエスト受信 +2. セッショントークンからユーザーを特定 +3. リクエストされたメソッド ID を権限設定と照合 +4. 許可されていれば実行、拒否ならエラーを返す +``` + +## データストア + +| データ | 保存先 | 備考 | +|--------|--------|------| +| 権限設定 (YAML) | Git リポジトリ → コンテナイメージに同梱 | PR レビューで変更管理 | +| OAuth トークン | Secret Manager または暗号化ストレージ | 機密情報 | +| 利用ログ | Cloud Logging | 構造化ログ | + +## 利用統計 + +### 記録項目 + +| 項目 | 例 | +|------|-----| +| ユーザー email | tanaka@company.com | +| タイムスタンプ | 2026-03-05T10:30:00Z | +| メソッド ID | gmail.users.messages.list | +| 成功/失敗 | success | + +### 基盤 + +Cloud Logging に構造化ログとして出力。必要に応じて BigQuery にエクスポートし可視化。 diff --git a/specs/remote-mcp-gateway/requirements.md b/specs/remote-mcp-gateway/requirements.md new file mode 100644 index 00000000..32c8bd99 --- /dev/null +++ b/specs/remote-mcp-gateway/requirements.md @@ -0,0 +1,41 @@ +# Remote MCP Gateway - Requirements + +## 背景 + +会社で契約している Claude Desktop / Claude Code から Google Workspace API を安全に利用したい。 +gws を Claude for Business/Enterprise の組織コネクタ(Integrations)として全社配布する。 + +## ユーザー + +- 社員約20名 +- 管理者ユーザー: 権限設定を管理する +- 通常ユーザー: 許可された操作のみ実行する + +## 要件 + +### R1: 組織コネクタとしての配布 + +- Claude 管理コンソールから組織コネクタとして登録し、全メンバーに自動配布する +- メンバーは Claude Desktop / Claude.ai 上でコネクタを利用開始できる + +### R2: Google アカウントによる認証 + +- 各メンバーが自分の Google アカウントで OAuth し、MCP 経由で Google Workspace を操作する +- MCP Gateway への認証と Google API への認可を 1 回の Google OAuth ログインで兼用する + +### R3: ホワイトリスト方式の権限制御 + +- 管理者が通常ユーザーに対して、実行可能な操作をホワイトリスト方式で設定する +- 権限の粒度は Google Discovery JSON のメソッド ID 単位(例: `gmail.users.messages.send`) +- 未登録ユーザーは何もできない +- MCP の `tools/list` はユーザーに許可されたメソッドのみ返す(エージェントが不許可操作を試みること自体を防ぐ) + +### R4: 利用統計 + +- 各ユーザーの利用状況(誰が・いつ・どの操作を・何回呼んだか)を記録する +- 目的は活用度の把握 + +## 非機能要件 + +- GCP 上でホストする +- 20名規模に対応できればよい(大規模スケーリングは不要) diff --git a/specs/remote-mcp-gateway/tasks.md b/specs/remote-mcp-gateway/tasks.md new file mode 100644 index 00000000..71527f4e --- /dev/null +++ b/specs/remote-mcp-gateway/tasks.md @@ -0,0 +1,56 @@ +# Remote MCP Gateway - Tasks + +## 実装ロードマップ + +| Phase | タスク | 依存 | ステータス | +|-------|--------|------|-----------| +| 1 | 既存 stdio MCP を Streamable HTTP 対応に変更 | - | TODO | +| 2 | ユーザーごとの OAuth トークン管理 | Phase 1 | TODO | +| 3 | Cloud Run にデプロイ | Phase 2 | TODO | +| 4 | Claude 管理コンソールで組織コネクタとして登録・動作確認 | Phase 3 | TODO | +| 5 | 権限制御 (YAML ホワイトリスト) | Phase 2 | TODO | +| 6 | tools/list のユーザー別フィルタ | Phase 5 | TODO | +| 7 | 利用統計 (Cloud Logging) | Phase 2 | TODO | + +## Phase 詳細 + +### Phase 1: Streamable HTTP 対応 + +- [ ] HTTP サーバー追加(既存 `mcp_server.rs` の stdio 実装をベースに) +- [ ] MCP Streamable HTTP トランスポート実装 +- [ ] ローカルで HTTP モードでの動作確認 + +### Phase 2: OAuth トークン管理 + +- [ ] Google OAuth フロー実装(認可エンドポイント、コールバック) +- [ ] ユーザー識別(Google email) +- [ ] トークンの暗号化保存 +- [ ] トークンリフレッシュ処理 + +### Phase 3: Cloud Run デプロイ + +- [ ] Dockerfile 作成 +- [ ] CI/CD パイプライン構築 +- [ ] Secret Manager 連携 + +### Phase 4: 組織コネクタ登録 + +- [ ] Claude 管理コンソールでの登録手順確認 +- [ ] エンドツーエンド動作確認 + +### Phase 5: 権限制御 + +- [ ] YAML パーサー実装 +- [ ] ワイルドカードマッチング実装 +- [ ] リクエスト時の権限チェックミドルウェア +- [ ] 未登録ユーザーの拒否処理 + +### Phase 6: tools/list フィルタ + +- [ ] ユーザー権限に基づく tools/list レスポンスフィルタ +- [ ] 未登録ユーザーへの空リスト返却 + +### Phase 7: 利用統計 + +- [ ] 構造化ログ出力(email, timestamp, method ID, result) +- [ ] Cloud Logging への連携確認 From 35a1512bb07114009364522c210796b91df41a0f Mon Sep 17 00:00:00 2001 From: vitocchi <38712518+vitocchi@users.noreply.github.com> Date: Thu, 5 Mar 2026 17:53:10 +0900 Subject: [PATCH 4/4] feat: add Claude Code workflow for automated issue and PR comment handling --- .github/workflows/claude.yml | 58 ++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 .github/workflows/claude.yml diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml new file mode 100644 index 00000000..81c94302 --- /dev/null +++ b/.github/workflows/claude.yml @@ -0,0 +1,58 @@ +name: Claude Code + +on: + issue_comment: + types: [created] + pull_request_review_comment: + types: [created] + issues: + types: [opened, assigned] + pull_request_review: + types: [submitted] + +jobs: + claude: + if: | + (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) || + (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) || + (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) || + (github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude'))) + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + issues: write + id-token: write + actions: read # Required for Claude to read CI results on PRs + steps: + - name: Checkout repository + uses: actions/checkout@v6 + with: + fetch-depth: 1 + + - name: Run Claude Code + id: claude + uses: anthropics/claude-code-action@v1 + with: + anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} + + # Optional: Customize the trigger phrase (default: @claude) + # trigger_phrase: "/claude" + + # Optional: Trigger when specific user is assigned to an issue + # assignee_trigger: "claude-bot" + + # Optional: Configure Claude's behavior with CLI arguments + # claude_args: | + # --model claude-opus-4-1-20250805 + # --max-turns 10 + # --allowedTools "Bash(npm install),Bash(npm run build),Bash(npm run test:*),Bash(npm run lint:*)" + # --system-prompt "Follow our coding standards. Ensure all new code has tests. Use TypeScript for new files." + + # Optional: Advanced settings configuration + # settings: | + # { + # "env": { + # "NODE_ENV": "test" + # } + # } \ No newline at end of file