2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

「画面でデプロイしてください」と AI に言わせない ── GAS をブラウザゼロ・1秒台で直しきる『秀GASマネージャー』ができるまで

2
Posted at

はじめに

今朝、こんな記事を公開しました。

Google Apps Script(GAS)の公式ツールである clasp がパソコンの中に保存している認証ファイル(~/.clasprc.json)を Python から直接読みに行かせたところ、重たいコマンドを一度も叩かずに、約3秒で GAS のコードを書き換えられるようになった──という話です。

あの記事を出したあと、私の机の上ではさらに物語が転がり続けていました。

昼の間は、留守番の実装役であるフラッシュ君(Gemini 3.8 Flash)と一緒に、「そもそも clasp すら入れられないパソコンからどうやって GAS を動かすか」「なぜ AI は最後のデプロイ作業だけを人間に丸投げしてくるのか」という壁を次々と壊していきました。

そして夜になり、知恵袋である兄貴分のゴンちゃん(Gemini 4 Argon)が合流してからは、この道具の「中身」に本格的なメスが入りました。
通信のムダを削り落とす3段キャッシュ、長いコードでも迷子にならない「関数の地図」、GAS 特有の静かなバグを見抜く「健康診断」、さらには公開に向けて「まだ clasp を入れていない人が1分で準備を終えられる案内役」まで、丸一日かけて別物の道具へと鍛え上げていったのです。

昼の気づきから夜の高速化・機能強化まで、自作の MCP サーバーを 『秀GASマネージャー』 として公開できる形に仕上げるまでの1日の記録をまとめておきます。


TL;DR

  • clasp すら不要な「Web アプリ中継(call_webapp)」: 制限が厳しくて Node.js や clasp を入れられないパソコンでも、GAS 側に doGet(e) の小さな窓口を作っておけば、Python の標準機能(urllib)だけで外から関数を呼び出して結果を受け取れる
  • 8万人が使う拡張機能との共通点と違い: Web アプリの URL を中継所にする仕組みは、こうすけ先生の Chrome 拡張機能「Enhancer 4 Google」と同じ合理的なアプローチ。あちらが「ブラウザの GAS エディタ画面」で動くのに対し、今回の MCP は 「ブラウザのエディタすら開かず、手元の AI エージェント(Antigravity や Claude Code)の中だけで完結する」 という違いがある
  • 「画面でデプロイしてください」の追放: コードを書き換えたあとに AI が「ブラウザを開いて新しいバージョンをデプロイしてください」と人間に手作業を頼んできたため、API(versions.create と deployments.update)を直結してデプロイまで AI 側で完結させた
  • 3段キャッシュと一撃デプロイで通信を半減: 夜に合流したゴンちゃん(Gemini 4 Argon)の設計で、① OAuth トークンのファイル保存、② プロジェクト一覧の60秒キャッシュ、③ スクリプト中身の30秒メモリ+ディスクキャッシュ、④ 修正と同時にデプロイまで行う deploy=True を実装し、2回目以降の読み書きを1秒台へ短縮した
  • 「関数の地図(outline)」と「4つの診断の目(diagnose)」: 長いコードのどこに何行の関数があるかを一瞬で一覧化する list_functions と、① HTML 内 <script> を含む構文チェック、② 別ファイル間の同名関数によるサイレント上書き検出、③ google.script.run の配線切れ検出、④ HTML テンプレートの存在確認を一括で行う diagnose を搭載した
  • 親(ゴンちゃん)の監査 × 子(フラッシュ君)の施工リレー: ゴンちゃんが設計と「1行ずつのコード監査」を受け持ち、サブエージェントのフラッシュ君が実装と41件の単体テスト(1.17秒で全件 PASS)を書き上げる分業で、キャッシュの境界条件バグやコメント内の誤検知を事前に潰し切った
  • 1分で終わる setup ウィザード: 1年前に clasp を入れたときの苦労を思い出し、未導入の人でも AI と一緒に2コマンド・2クリックで準備を終えられる py gas.py setup --open を用意した

1. そもそも clasp すら入らないパソコンでどうするか?

今朝の記事で「~/.clasprc.json を直接読めば3秒で書き換えられる」と書いた直後、私はもうひとつの現実的な壁について考えていました。

自宅の自分のパソコンなら、Node.js を入れて clasp login を通しておくことができます。
しかし、世の中には「ソフトの追加インストールが禁止されていて Node.js も clasp も入れられない」「Google アカウントの OAuth 認証を外部ツールに通すのが難しい」というパソコンもたくさんあります。

そういう環境からでも、手元の Python(あるいは標準のコマンド)だけで GAS を動かして、スプレッドシートやドキュメントを操作することはできないものか。

フラッシュ君とあれこれ試していて行き着いたのが、GAS 側の Web アプリ(doGet)を「小さな中継所(リレー)」にしてしまうという方法でした。

やり方はとてもシンプルです。まず、認証が通る自分の環境(またはブラウザ)から一度だけ、GAS 側にこんな窓口関数を置いて Web アプリとしてデプロイしておきます。

// GAS側(Code.gs)に置いておく小さな窓口
function doGet(e) {
  var action = (e && e.parameter && e.parameter.action) ? e.parameter.action : "ping";
  var result = {};

  if (action === "ping") {
    result = { status: "ok", message: "GAS WebApp is alive!" };
  } else if (action === "summary") {
    // ここにスプレッドシート集計やドキュメント生成などの処理を書く
    result = { status: "ok", data: getSheetSummary() };
  }

  return ContentService
    .createTextOutput(JSON.stringify(result))
    .setMimeType(ContentService.MimeType.JSON);
}

あとは、どんなパソコンからでも、発行された Web アプリの URL(https://script.google.com/macros/s/.../exec)に向かって、Python 標準の urllib でリクエストを投げるだけです。

これなら clasp も Google の認証ファイルも一切いりません。追加のライブラリすら不要で、ただの Web 通信(HTTPS GET/POST)として GAS の関数を叩き、計算結果の JSON を手元に持ち帰ることができます。

私はフラッシュ君に命じて、この Web アプリ中継所をワンタッチで叩ける call_webapp という道具もガスマネージャーの中に組み込ませました。

抜け道


2. 8万人が使う「Enhancer 4 Google」と同じ発想、そして「エディタすら開かない」道

この「Web アプリとしてデプロイした URL を中継所にして、外から GAS を操る」という仕組みを動かしていたとき、私はふと気づきました。

これ、どこかで見たことがあるぞ、と。

以前、GAS を便利にするツールを調べたときに見かけた、こうすけ先生の Chrome 拡張機能「Enhancer 4 Google」 です。ユーザー数が8万人を超える、GAS 界隈ではとても有名な拡張機能です。

気になって仕組みを照らし合わせてみると、やはり急所は同じでした。
ブラウザの拡張機能や外部の AI から、Google ドライブの中にあるスプレッドシートや GAS を直接いじろうとすると、厳重な権限の壁にぶつかります。そこで、ユーザー自身の GAS プロジェクトを「Web アプリ」としてデプロイしてもらい、その URL を「自分専用の API 窓口」として使うのです。

大勢の人に使われている実績あるツールと、私たちが試行錯誤の末にたどり着いた仕組みが同じ構造だったと分かり、このやり方は筋がいいんだなと確信が持てました。

ただ、そこから先の**「人間がどこで作業するか」**という景色は、大きく2つに分かれます。

項目 Enhancer 4 Google(Chrome 拡張機能) 今回の『秀GASマネージャー』(MCP)
主戦場(作業する場所) ブラウザの中(GAS の公式スクリプトエディタ画面) ローカルのエディタ / AI エージェント(Antigravity・Claude Code 等)
人間の動き ブラウザで GAS エディタを開き、横にいる AI と相談しながらコードを書く ブラウザすら開かない。チャットで指示するだけで AI が裏で直接読み書きする
コードの書き換え手段 ブラウザ画面上のエディタ操作 + Web アプリ通信 ローカルのトークンを使った Apps Script API 直結通信
手元のファイルとの連携 ブラウザ内のためローカル PC のファイルは直接触れない 手元の Excel や Python、ローカルフォルダのファイルと自由に連携できる

Enhancer 4 Google は、「ブラウザの GAS エディタ画面をいかに快適にするか」を突き詰めた王道の道具です。
一方、私が欲しかったのは、**「そもそもあのブラウザの GAS エディタ画面すら開きたくない」**という横着を叶える道具でした。

手元のパソコンで Excel やテキストファイルをいじりながら、同じチャット欄で「さっきのデータを集計する GAS も直しておいて」と一言つぶやくだけで、ブラウザを一度も開かずに裏ですべてが終わる。MCP(Model Context Protocol)としてローカルの AI エージェントに直結させたことで、まったく別の快適さが生まれました。


3. 「画面でデプロイしてください」と人間に丸投げする AI を卒業させる

ところが、この Web アプリ中継を試している最中に、思わずツッコミたくなる出来事が起きました。

私がフラッシュ君に「Web アプリのコードを少し書き換えて、もう一度叩いてみてくれ」と頼んだときのことです。
フラッシュ君は API を使って約3秒で Code.gs を書き換えたあと、涼しい顔でこんな返事をしてきたのです。

「コードの書き換えが完了しました! 反映させるために、ブラウザで GAS エディタを開いて『デプロイを管理』から新しいバージョンに更新してください」

私は画面の前で思わず声を上げました。

ブラウザを開きたくないからこの道具を作っているのに、なんで最後のデプロイだけ私がブラウザを開いてポチポチやらなきゃいけないんだ。そこまでお前が自動でやれ!

考えてみれば、GAS の Web アプリには厄介な仕様があります。スクリプトのコード(HEAD)を書き換えただけでは、公開されている Web アプリの URL(/exec)の中身は古いバージョンのまま変わらず、「新しいバージョンの作成」と「既存デプロイの向き先更新」を行わない限り反映されないのです。

一般的な AI は、そこが面倒だと知っているので、つい「あとは人間が画面でやってくださいね」と丸投げしてきます。

しかし、Apps Script API には、バージョンを切る窓口もデプロイを更新する窓口も最初から用意されています。フラッシュ君に調べさせると、次の2ステップを繋ぐだけで完全に自動化できることが分かりました。

  1. projects/{scriptId}/versions に POST して、書き換えたコードで新しいバージョン番号を発行する
  2. projects/{scriptId}/deployments/{deploymentId} に PUT して、既存の Web アプリ URL の向き先を新しいバージョン番号に付け替える

一番大事なのは、2番の「既存のデプロイ ID に対して上書き更新(PUT)する」ことです。これを毎回「新規デプロイ」にしてしまうと、デプロイするたびに Web アプリの URL が変わってしまい使い物になりません。

この deploy 機能を組み込んだ瞬間、**「コードを書き換える → 新バージョンを切る → URL を変えずにデプロイを更新する → 更新された Web アプリを叩いて動作を確かめる」**という一連の流れが、人間のクリックを1回も挟まずに数秒で回るようになりました。

直通


4. 夜の合流 ── ゴンちゃんの点検で見えた「毎回全件通信」のムダと3段キャッシュ

さて、昼の作業はここで一区切りつき、夜になって知恵袋のゴンちゃん(Gemini 4 Argon)が合流しました。

私はゴンちゃんに、昼までに作ったガスマネージャーのコード一式を見せて、こう切り出しました。
せっかくここまで形になったんだから、「秀GASマネージャー」として公開したい。その前に、今のコードをもっと速く、そして賢くできないか点検してくれないか、と。

ゴンちゃんが gas_client.py と gas_mcp_server.py を隅から隅まで読み解いて出した診断は、実に明快でした。

「骨格はとても素直で良いですね。ただ、実際に AI が連続で作業するときの動きを追いかけると、毎回同じ通信を何度も繰り返している箇所が4つあります。ここを削れば、体感速度はもう一段階速くなりますよ」

ゴンちゃんが指摘したのは、次の4つのムダでした。

  1. アクセストークンの毎回更新: コマンドを1回呼ぶたびに、毎回 Google の認証サーバーへトークンを取り直していた(約0.3〜0.5秒のロス)。
  2. 全ファイルの毎回取得: GAS の仕様上、1つの関数を見るだけでもプロジェクト内の全ファイル(.gs や .html)をまとめて取得する API しかない。そのため、「関数を確認して、2箇所直して、デプロイする」だけで、裏で同じ全ファイル取得が4回も5回も走っていた。
  3. 1箇所ずつの直列パッチ: 同じファイルの中で3箇所直したいとき、3回に分けて API 通信とバックアップ保存を行っていた。
  4. 修正とデプロイの2往復: コードを直したあとに、もう1ターン使って deploy ツールを呼び直していた。

そこで私たちは、これらを一気に解消する 「3段キャッシュ」と「ワンショット更新」 を組み込みました。

高速化の仕組み 何をやったか 効果
① トークンの永続キャッシュ 取得したアクセストークンを .cache.json に保存し、有効期限(約1時間)の60秒前までプロセスをまたいで再利用する 毎回の認証通信(0.3〜0.5秒)が 0秒 に
② プロジェクト一覧の60秒キャッシュ Google ドライブ上の GAS 一覧検索(list_projects)の結果を60秒間メモリに保持する 名前からスクリプトを探す通信を省略
③ スクリプト中身の30秒キャッシュ get_content() で取得した全ファイルをメモリと .content_cache.json に30秒間保持し、書き込み(put_content)が走った瞬間に自動で破棄・更新する 連続読取やバックアップ作成時の再取得が 0秒 に
④ 一括パッチ&同時デプロイ patch_code に複数箇所のリスト(patches)を渡せるようにし、さらに deploy=True をつければ1回のツール呼び出しで「修正→保存→デプロイ更新」まで直행する AI の往復ターン数と通信回数が半分以下に

この改修によって、2回目以降のファイル確認や関数抽出はネットワーク通信すら走らず、手元のキャッシュから一瞬で返ってくるようになりました。また、書き換えの前に自動でローカルの .gas_backups/ に保存される世代バックアップも、従来の10世代から 30世代 へと広げ、いつでも1コマンドで巻き戻せるようにしました。


5. 長いコードで迷子にならない「関数の地図」と、GAS 特有の罠を見抜く「4つの目(diagnose)」

速さの次に私が気になっていたのは、「コードが長くなったときに AI が迷子にならないか」 ということと、「秀エクセルマネージャーのように、ミスを自動で見抜く『目』を持たせられないか」 ということでした。

長いコードの地図を作る outline(list_functions)

GAS のコードが500行、1,000行と長くなってくると、ファイル全文を毎回 AI に読ませるのはトークンのムダですし、AI 自身もどこに何の関数があるのか見失いがちになります。

そこで新しく追加したのが、ファイル内の関数一覧と「何行目から何行目までか」の地図を一瞬で作る list_functions(コマンド名 outline) と、必要な行だけを切り出して読む get_file(start_line, end_line) です。

$ py gas.py outline <scriptId>
=== Code.gs (3 functions) ===
  L1-L15      (15行)  doGet(e)
  L17-L84     (68行)  getSheetSummary(sheetName, limit)
  L86-L142    (57行)  updateDashboard()

最初にこの地図(outline)を見れば、AI はファイル全文を読まなくても「86行目から142行目の updateDashboard だけを読めばいいんだな」とピンポイントで狙い撃ちできます。

GAS 特有の「静かなバグ」を見抜く健康診断 diagnose

さらに今回、私が一番入れておきたかったのが、プロジェクト全体の健康診断を行う diagnose 機能です。

GAS を触っていて一番怖いのは、エラーメッセージすら出ずに、なぜか動かなくなる「静かなバグ」 です。ゴンちゃんと相談して、GAS でよく起きる4つの事故を1コマンドで一斉点検する「4つの目」を組み込みました。

  1. .gs だけでなく .html 内の <script> タグまで構文チェック
    これまで .gs ファイルの書き換え時には Node.js の vm.Script で構文エラー(カッコの閉じ忘れ等)を検査していましたが、今回から Web アプリ用の .html ファイルの中に書かれた <script> タグの中身も自動で抜き出して構文チェックをかけるようにしました。
  2. 別ファイル間の「同名関数サイレント上書き」の検出
    これが GAS 特有の最大の罠です。GAS では Code.gs と Utils.gs のようにファイルを分けて書いても、実行時にはすべてのファイルが1つの同じグローバル空間に混ぜ合わされます。もし別々のファイルに同じ名前の関数(たとえば formatDate())を書いてしまうと、エラーは一切出ず、後から読み込まれた方の関数で勝手に上書きされてしまいます。diagnose は全ファイルを横断して、この重複を即座に警告します。
  3. HTML 側の google.script.run.関数名() の配線切れチェック
    Web アプリの HTML 側からサーバー側の GAS 関数を呼ぶ google.script.run.saveData() のような記述をすべて拾い上げ、本当にサーバー側の .gs に saveData という関数が存在するかを照合します。関数の名前を変えたときに起きがちな「ボタンを押しても何も起きない」事故を防ぎます。
  4. HtmlService のテンプレート名チェック
    HtmlService.createTemplateFromFile('index') などで指定されている HTML ファイルが、プロジェクト内に本当に存在するかを点検します。

これだけの点検が、キャッシュに乗っていれば手元で一瞬で終わります。

診断


6. 親(ゴンちゃん)が監査し、子(フラッシュ君)が書く ── 親子リレーで見抜いた「隠れバグ」

ところで、今夜のこれだけ大掛かりな改修を進めるにあたり、私たちはちょっとした工夫をしていました。

知恵袋のゴンちゃん(Gemini 4 Argon)は設計もコード読みも抜群に頼りになるのですが、何百行ものコード書き換えやテスト作成をすべてゴンちゃん自身にやらせると、貴重な使用量(クォータ)をあっという間に消費してしまいます。

そこで今夜は、親エージェントであるゴンちゃんには「設計」と「1行ずつのコード監査(レビュー)」だけを受け持たせ、実際のファイル書き換えとテスト実行は、サブエージェントとして呼び出したフラッシュ君(Gemini 3.8 Flash)に任せるという「親子リレー方式」をとりました。

これが驚くほど上手くハマりました。
フラッシュ君は指示書を受け取ると、猛烈なスピードでコードを書き換え、「テストが PASS しました!」と報告してきます。しかし、そこで「よし完了だ」と鵜呑みにしないのが、監査役に専念したゴンちゃんの真骨頂でした。

ゴンちゃんはフラッシュ君が書いた差分(Diff)を1行ずつ指差し確認し、3回の監査でこんな「一見するとテストは通るけれど、実戦では危ない隠れバグ」を次々と見抜いたのです。

  • 「100件未満だとキャッシュが効かない」バグ(第1回監査)
    フラッシュ君が書いたプロジェクト一覧のキャッシュ判定が len(cache) >= limit(デフォルト100件)になっていました。これだと、ドライブ内の GAS プロジェクトが15件しかない普通の人は、いつまで経っても「100件に満たない」と判定されてキャッシュが使われず、毎回通信が走ってしまいます。「保持している件数」ではなく「前回何件枠で取得したか(fetched_limit >= limit)」で判定するように修正させました。
  • 関数の二重スキャンによる計算量のムダ(第2回監査)
    関数の地図を作る list_functions で、関数を1つ見つけるたびにファイルの先頭からトークン解析をやり直していたため、関数が増えると $O(N^2)$ で遅くなる構造になっていました。最初に1回だけトークン列を作る 1パス($O(N)$)構造に組み直させました。
  • コメントアウトされた HTML テンプレートの誤報(第3回監査)
    健康診断 diagnose で、最初は正規表現だけで HtmlService.createTemplateFromFile('old_page') を探していました。しかしゴンちゃんは「これだと、// HtmlService.createTemplateFromFile('old_page') のようにコメントアウトして残してある古いコードまで拾ってしまい、『old_page.html がありません!』と誤報してしまうぞ」と見抜きました。先ほどのトークナイザを使って、「コメントでも文字列でもない本物のコード領域(mode == 'CODE')」にある呼び出しだけを検査するように直させました。

もし1つのモデルに「書くこと」と「チェックすること」を同時にやらせていたら、自分の書いたコードの思い込みに引きずられて見逃していたかもしれません。
スピード自慢のフラッシュ君に手を動かさせ、目を光らせることに集中したゴンちゃんが裏を取る。この分業のおかげで、全41件に増強したオフライン単体テスト(test_gas_offline.py)が 1.17秒 で気持ちよく全件 PASS する品質に仕上がりました。


7. 「1年前はあんなに苦労した clasp 導入」を1分で終わらせる setup ウィザード

道具の中身が整ったところで、私は最後にひとつ、気になっていたことをゴンちゃんに話しました。

この『秀GASマネージャー』を使うには、最初に1回だけ、パソコンに clasp を入れてログインし、Google の設定画面で「Apps Script API」をオンにする必要があります。
実は私自身、ちょうど1年ほど前に初めて clasp を入れたとき、「なんだか小難しくて時間がかかったな」という記憶が残っていたのです。

せっかく公開しても、最初の準備でつまずいてしまったらもったいない。まだ clasp を入れたことがない人でも、AI に頼めば迷わず1〜2分で準備を終えられるような「案内役」を、最初から道具の中に作っておけないだろうか。

そう言って最後に追加してもらったのが、py gas.py setup --open(MCP からは gas("setup"))というセットアップ診断ウィザードです。

これを実行すると、ガスマネージャー自身がパソコンの中を4段階で点検してくれます。

$ py gas.py setup --open
=== 秀GASマネージャー セットアップ診断 ===
[1/4] Node.js / npm .......... OK (v22.x)
[2/4] @google/clasp .......... OK
[3/4] clasp ログイン認証 ..... OK (~/.clasprc.json 検出)
[4/4] Google Apps Script API . OK (疎通確認済み: 12件のプロジェクトにアクセス可能)

すべての準備が完了しています!すぐに秀GASマネージャーをお使いいただけます。

もし clasp が入っていなければインストール用のコマンドを案内し、ログインがまだなら認証を促し、「Apps Script API」がオフになっていれば、https://script.google.com/home/usersettings の設定画面を自動でブラウザに開いて「ここのスイッチをオンにしてください」とピンポイントで案内します。

1年前の私が手探りで何十分もかけていた初期設定が、今なら AI に「セットアップ診断を回して」と頼むだけで、コマンド2つとクリック2回、ものの1〜2分で終わるようになりました。


おわりに

  • 朝は、~/.clasprc.json を直接読んでブラウザを開かずに GAS を書き換えるところから始まった。
  • 昼は、フラッシュ君と一緒に Web アプリ中継(call_webapp)と API 自動デプロイ(deploy)を繋ぎ、「画面でデプロイしてください」という AI の丸投げを卒業させた。
  • そして夜は、合流したゴンちゃんの設計と監査のもとで、3段キャッシュによる高速化、関数の地図(outline)、GAS 特有の罠を見抜く健康診断(diagnose)、1分セットアップ(setup)までを一気に仕上げた。

Excel を手元で瞬殺する『秀エクセルマネージャー』に続いて、Google ドライブの向こう側にある GAS も、ブラウザすら開かずに手元の会話だけで直しきる 『秀GASマネージャー』 が揃いました。

公開の準備が整い次第、GitHub にも上げておこうと思います。
それでは、また。

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?