0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

claspでやるのが馬鹿らしくなってきた ── Python MCPでGASを直撃したら、修正が爆速になってコードの質まで上がった話

0
Posted at

はじめに

これまで私は、Excel と VBA を AI に操作させるための専用道具「秀エクセルマネージャー」を作り、記事にも書いてきました。AI が自分でマクロを読み、差分を直し、コンパイルしてアドインに登録する。手作業で画面を行き来するのをやめ、AI が直接 Excel を触るようにしたことで、作業の速度と精度は劇的に変わりました。

そんな日々のなかで、ふと気になったのが Google Apps Script(GAS)の開発でした。

GAS の開発や保守を AI に頼むとき、世の中の定番といえば Google 公式の CLI ツールである clasp です。手元にファイルを落とし(pull)、ローカルのエディタや AI で書き換え、コマンドを叩いてアップロードする(push)。

私も当たり前のようにその手順を踏んでいました。しかし、あるとき強い違和感を覚えたのです。

「クラウドの上で動いているものを、なぜわざわざ手元のパソコンにファイルとして落とし、Node.js を立ち上げて push しているのだろう?」

エクセルマネージャーで培った「AI と実行環境を道具で直結する」というやり方を、そのまま GAS に持ち込めないか。そう思って、Python の FastMCP を使った専用の MCP サーバー「gas-manager」を作ってみました。

結論から言うと、今までのやり方にはもう戻れなくなりました。待ち時間が消え、修正がその場で反映されるようになると、単に作業が楽になるだけでなく、できあがるコードの質そのものが明らかに上がったのです。

TL;DR

  • Google Apps Script(GAS)の開発で、手元にローカルファイルを一切置かず、Python の FastMCP サーバー経由で Google Apps Script API を直撃する「gas-manager」 を作りました
  • 認証は、すでに入っていた ~/.clasprc.json のリフレッシュトークンをそのまま拝借。面倒な OAuth の同意画面作成や GCP の設定は 1 秒もしていません
  • ローカルへのファイル保存や Node.js の起動を挟まないため、関数の取得や差分の反映が 1〜2 秒以内 で終わります
  • チャンネル登録も、最初に試した「コード書き換えとデプロイ」の手順(約 14 秒)から、Web アプリの直撃口を叩く形へ改良したことで、2.5 秒 に大幅短縮されました
  • 「過去の版はクラウドに残っているからローカル保存は不要」としつつも、保険として書き換え直前のコードを自動で退避する仕組みを入れています
  • 反映が即座に終わることで、AI との対話のテンポが崩れず、細かなクォータ対策や仕様の詰めが何往復も軽快に回り、結果として設計の質が高まりました

なぜ手元にファイルを落としていたのか

普段、ローカルのファイル(Python や TypeScript など)を Git で管理していると、「手元にリポジトリを clone して編集する」というのが染みついた自然な動作になります。

そのため、GAS を扱うときも、みんな疑問を持たずにこう考えます。

  1. clasp clone や clasp pull でローカルに .js や .html を落とす
  2. エディタや AI でコードを編集する
  3. clasp push でクラウドに上げる
  4. 必要ならブラウザを開いて新バージョンをデプロイする

しかし、GAS の本体は最初から最後まで Google のクラウド上にあります。過去の変更履歴も Google の版管理(バージョン履歴)にすべて残っています。

それなのに、なぜ AI にコードを直させるためだけに、一度手元のフォルダにファイルを展開し、重い Node.js のランタイムを走らせてファイルを同期しなければならないのでしょうか。

同期の途中で競合が起きたり、手元のファイルとクラウドの版がずれて「どっちが最新だっけ?」と迷ったりする時間は、完全に無駄です。AI がクラウドのコードを直接読んで、その場で直して保存してくれれば、手元の作業フォルダすら要りません。

clasp の認証をそのまま借りる

とはいえ、Google の API を直接叩くとなると、一番面倒なのが認証(OAuth 2.0)です。

Google Cloud のコンソールを開いてプロジェクトを作り、OAuth 同意画面を設定し、クライアント ID とシークレットを発行して……という作業を思い浮かべると、それだけでやる気が失せます。

そこで私は、AI(フラッシュ君)にこう言いました。手元に clasp のログイン情報がすでにあるのだから、そこからトークンを拝借できないか、と。

実は clasp login を一度でも実行したことがある環境なら、ホームディレクトリの ~/.clasprc.json に Google のリフレッシュトークンが保存されています。

Python の gas-manager は、このファイルを読み取ってトークンを取り出し、裏で Google の OAuth エンドポイントに投げてアクセストークンを自動更新します。これだけで、面倒な認証設定を一切することなく、Google Apps Script API への正規のアクセス権が得られます。

# ~/.clasprc.json から拝借してアクセストークンを自動取得する仕組み
def get_access_token():
    clasprc_path = Path.home() / ".clasprc.json"
    with open(clasprc_path, "r", encoding="utf-8") as f:
        data = json.load(f)
    token_data = data.get("token", {})
    refresh_token = token_data.get("refresh_token")
    client_id = token_data.get("client_id")
    client_secret = token_data.get("client_secret")
    
    # Google の token エンドポイントへ POST して新しい access_token を発行
    ...

認証の壁を 0 秒で突破したことで、構想からわずか数十分で直撃ツールが立ち上がりました。

直通

ファイルを持たない、メモリ直撃の仕組み

出来上がった gas-manager は、Python の FastMCP(mcp ライブラリ)で作られたシンプルな MCP サーバーです。

AI(Claude や Gemini)には、次のような道具が見えています。

  • list_projects: プロジェクト一覧の取得
  • list_files: プロジェクト内のファイル一覧
  • get_function: 指定した関数のコードだけをピンポイント取得
  • patch_code: コードの一部分を安全に置換
  • replace_file: ファイル全体を丸ごと更新
  • deploy: 新バージョンの作成と Web アプリデプロイの自動更新

最大の特徴は、ローカルディスクに作業ファイルを一切書き出さない 点です。

AI が「あの関数の処理を見せて」と言えば、道具が Google Apps Script API を叩いてメモリ上にコードを読み込み、AI に直接渡します。AI が「ここをこう直したよ」と言えば、道具が差分を組み立てて API に POST し、クラウド上のプロジェクトを一撃で更新します。

保険としての自動バックアップ

ただし、手元にファイルを持たないからといって、完全にノーガードでは不安です。

クラウドに履歴があるとはいえ、AI が誤った置換をして動かなくなったときに、パッと元の状態に戻せる保険は欲しい。そこで、ファイルを更新する直前には、対象スクリプトの全コードを .backups/<script_id>/ 配下にタイムスタンプ付きの JSON として自動退避する仕組みを入れました。

「ローカルでファイル管理はしないけれど、事故を防ぐ命綱だけは手元で静かに握っておく」。この割り切りによって、軽快さと安全性を両立させました。

控え

最初のやり方から改良したら、大幅に時間が縮んだ ── Qクイック NEXT の改修

この gas-manager がどれほどの威力を発揮するか、自作の YouTube RSS リーダー Web アプリ「Qクイック NEXT」の実戦改修で試してみました。

このアプリは、登録した YouTube チャンネルの最新動画を GAS で一括取得し、HTML 画面に高速表示する Web アプリです。
通常、新しいチャンネルを追加するときは、ユーザーがブラウザ上で画面を開いて追加ボタンを押します。

これを AI との連携のなかで、「AI の側からチャンネルを追加できないか」と試してみました。

最初にやってみたやり方は、スクリプトのコード側にチャンネル情報を書き足して、Web アプリの新バージョンをデプロイし直すという手順でした。これだと、画面を再読み込みしないと反映されませんし、一連の処理に約 14 秒かかっていました。

毎回デプロイして画面を更新し直すのも手間ですし、もっと直接できないかということで、やり方を改良しました。Web アプリのサーバー側(doGet)に直接クエリを受け付ける受付口を設け、Python 側からも requests.Session() の HTTP Keep-Alive でその口を直接叩くようにしたのです。

その結果、YouTube のチャンネル ID の解決から GAS への登録完了まで、デプロイを挟むことなく、わずか 2.5 秒 で走り抜けるようになりました。

[最初に試したやり方]
コード書き換え ➔ 新版デプロイ ➔ 画面の再読み込み(約 14 秒)

[改良後のやり方]
doGet の受付口へ直撃 API 呼び出し(2.5 秒・デプロイ不要で即反映)

最初にやってみた手番から無駄な段を削って改良したことで、大幅な時間短縮ができました。

もちろん、アプリ自体の改修も爆速で進みました。9KB の容量制限エラーは、保存するデータ構造を { id, name } だけの最小限に絞り込み、画面へ返すときに動的にプロパティを補完するロジックへその場で書き換えました。削除したチャンネルの ID を控えて復活を防ぐ履歴ガードも、わずか 1 分足らずでコードに組み込まれました。

二秒半

反映の速さが、コードの質を引き上げる

この一連の作業を通じて、私はある確信を得ました。

「修正が即座に反映できると、作業の質そのものが跳ね上がる」ということです。

これまでの clasp を使った開発では、コードを直してから動かして確認するまでに、どうしても数十秒の「待ち時間」が発生していました。待ち時間があると、人間の側も AI の側も集中が途切れがちになり、「まあ、だいたいこれで動くだろう」と大雑把な修正で妥協してしまいやすくなります。

ところが、修正が 1 秒や 2 秒で反映され、手応えが即座に返ってくる環境では、リズムがまったく崩れません。

「この条件分岐の端っこはどうなる?」「キャッシュの有効期限を 15 分にしたらどう変わる?」「削除したときの挙動をもっと綺麗にできないか?」といった細かな疑問や改善点を、思いついたその瞬間に試すことができます。

1 回あたりの試行錯誤のコストがゼロに近くなるため、AI とキャッチボールをする回数が自然と 3 倍にも 5 倍にも増えます。結果として、コードの粗が削ぎ落とされ、細部まで配慮が行き届いた質の高いプログラムが短時間で組み上がるのです。

VBA の改修をやっているときよりも、GAS を触っているときの AI(フラッシュ君)は心なしか生き生きとして見えました。Web 標準の JavaScript や REST API は、現代の LLM にとって最も得意な土俵だからです。相棒の得意な土俵に、最速の道具を渡してあげることの大切さを実感しました。

おわりに

「クラウドにあるものを、わざわざ手元に落としてから送り返す」という当たり前を疑ってみる。

たったそれだけの発想の転換でしたが、出来上がった世界は想像以上に快適でした。もう手動で clasp push を待つ日々には戻れそうにありません。

もちろん、チーム開発で厳密な PR レビューを回す現場などでは、Git を中心としたローカルリポジトリ管理が必要な場面もあるでしょう。しかし、個人開発や業務改善の現場において、AI と二人三脚で爆速で課題を解決していくなら、この「メモリ直結型」のアプローチこそが正解だと感じています。

Excel でも、GAS でも、本質は同じでした。人間と AI を隔てる待ち時間を 1 秒でも削り、一番近い距離で動かすこと。それが、開発を楽しくし、成果物の質を高める一番の近道なのだと思います。

0
1
1

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
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?