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 3.x で何ができるのか全部試してみた ── Claude CodeでGAS を書いて push するまで

0
Posted at

はじめに

Google Apps Script(GAS)をブラウザのスクリプトエディタで書いて、動いたら放置、直すときはまたブラウザを開いてコピペ。私はこの運用を定期実行のボットで数か月続けて、いよいよ「どのコードが今動いているのか分からない」状態になりました。git で管理したいし、正直なところコードは Claude Code に書かせたい。そこで Google が公開している CLI の clasp を入れて、何ができるのかをひととおり触ってみた記録です。

clasp は「push と pull ができるやつ」くらいの認識で止まっていませんか? 私はそうでした。調べてみると 3.x でコマンド体系がまるごと変わっていて、しかも Claude Code のプラグインとして公式に配布されている。2.x 時代の記事を読んで入れた人ほど、今の clasp を知らないと思います。

対象読者

  • GAS を書いたことはあるが、スクリプトエディタ以外で書いたことがない人
  • GAS のコードを git で管理したい、または Claude Code に書かせたい人
  • 2.x 時代に clasp を触って、それきりになっている人

先に結論をまとめておきます。

知りたいこと 結論
clasp とは Apps Script API を叩いて、手元のファイルと script.google.com 上のプロジェクトを同期する CLI
主な用途 ローカル編集・git 管理・バージョンとデプロイの操作・CI からの自動反映
3.x で変わったこと コマンド名のフラット化、TypeScript の自動変換廃止、MCP サーバー機能の追加
Claude Code との相性 リポジトリに MCP 設定が同梱されている。MCP でできるのは同期・作成・clone・一覧の 5 操作で、デプロイは CLI を直接叩く

参考文献

一次情報はここです。特に README は 3.x の仕様が最も正確に書かれていて、Google 公式ガイドより新しい内容が載っています。

検証環境

  • macOS
  • Node.js v26.0.0
  • clasp 3.4.1(2026-08-28 リリース。執筆時点の最新)
  • Claude Code 2.1.197

そもそも clasp って何?

clasp は Command Line Apps Script Projects の略で、Google が GitHub で公開している Node.js 製のオープンソース CLI です。README の冒頭に「公式サポート対象の Google 製品ではない」と明記されているので、社内に導入するときはその前提で扱う必要があります。やっていることはシンプルで、Apps Script API を経由して、手元のディレクトリと script.google.com 上のプロジェクトの中身を同期します。

clasp-sync-structure.png

図の右側を見てください。実際に実行されるコードは常に Apps Script 側にあって、push は手元の一式でリモートの HEAD を丸ごと置き換え、pull はその逆をやります。どちらを正本にするかは clasp が決めるものではなく運用の話で、git で管理するなら手元のリポジトリを正本にして、リモートは「push 先」と割り切るのが自然です。この前提を押さえておくと、後述するバージョンとデプロイが別物である理由もすっと入ります。

一言で言い直すと、clasp は「スクリプトエディタの保存ボタンをターミナルから押せるようにするツール」です。ただし保存だけでなく、バージョンを切る、デプロイする、ログを見る、関数を実行する、といったエディタのメニューにある操作もひととおりコマンドになっています。

使う前の準備で詰まりやすいところ

インストール自体は npm でグローバルに入れるだけです。

npm install -g @google/clasp

準備で必ず踏むのが次の 2 つで、どちらも「やっていないと後で分かりにくいエラーになる」タイプです。

  1. Apps Script API を有効にする。https://script.google.com/home/usersettings を開いてトグルをオンにします。これをやらずに create-scriptpush を叩くと User has not enabled the Apps Script API. Enable it by visiting ... と、やるべきことが書かれたエラーで止まります。有効化してから反映まで数分かかることがあります
  2. clasp login でブラウザが開くので、GAS を使う Google アカウントで認可します。トークンはホームディレクトリの .clasprc.json に保存されます

ログイン状態は clasp show-authorized-user で確認できます。ログイン前に叩くと Not logged in. とだけ返ってきます。

clasp login のブラウザ同意画面は、スコープごとにチェックボックスが並ぶ形式です。チェックを入れずに「続行」を押してもログイン自体は成功してしまい、show-authorized-user にはメールアドレスが表示されます。ところがこの状態では Apps Script と Drive のスコープが 1 つも付いていないので、list-scriptscreate-script を叩いた瞬間に Request had insufficient authentication scopes. で落ちます。私はこれを実際に踏みました。同意画面では全部のチェックを入れてから続行してください。

ここで私が地味に混乱したのが Node.js のバージョン要件でした。Google 公式ガイドは「20.0.0 以上」、GitHub README の末尾は「22.0.0 以上」、そして package.json の engines>=20.0.0 と、3 か所で 2 通りの答えが書いてあります。実際に動く下限は 20 のようですが、README が 22 と言っている以上、これから入れるなら 22 以上にしておくのが無難です。私は 26 で問題なく動いています。

会社のアカウントと個人のアカウントを使い分けたい場合は、clasp login --user work のように名前を付けて認可しておくと、以降 clasp --user work push で切り替えられます。ログインし直す必要はありません。

基本の使い方 ── 作る・持ってくる・送る

日常的に使うのはこの 4 つです。

やりたいこと コマンド 補足
新規プロジェクトを作る clasp create-script --type sheets --title "集計" --type は standalone / docs / sheets / slides / forms。webapp / api も受け付けるが standalone の別名で、Web アプリや API としての設定は別途マニフェストとデプロイで行う
既存プロジェクトを手元に持ってくる clasp clone-script <scriptId> スクリプト ID はエディタの「プロジェクトの設定」にある
リモートの内容を手元に反映 clasp pull
手元の内容をリモートに反映 clasp push --watch を付けると保存のたびに自動 push

create-scriptclone-script を実行すると、カレントディレクトリに .clasp.json ができます。中身は主に scriptIdrootDir で、このファイルがあるディレクトリが clasp にとってのプロジェクトのルートです。

.clasp.json
{
  "scriptId": "1AbC...(省略)",
  "rootDir": "src"
}

push の対象から外したいファイルは .claspignore に書きます。書き方は .gitignore に似ていますが、マッチングのライブラリが違うので、ディレクトリを除外するときは **/node_modules/** のように書く必要があります。.claspignore を作らなければ、マニフェストと .js / .gs / .html だけを対象にする既定のパターンが適用されます。空でもファイルを置くと既定は使われなくなるので、作るなら除外規則をちゃんと書きます。

pull すると、スクリプトエディタで .gs に見えていたファイルが手元では .js で落ちてきます。逆に手元の .js を push すると、リモートでは .gs として表示されます。最初に見たとき「拡張子を直さないといけないのか」と思って調べましたが、これは clasp が意図的にやっている変換で、そのままで大丈夫です。手元を .gs で揃えたい場合は .clasp.jsonscriptExtensions で先頭の拡張子を変えられます。

公開まわり ── バージョンとデプロイ

ここは GAS 側の概念を先に整理しておかないと、コマンドを覚えても使い分けられません。

  • push が書き換えるのは HEAD、つまり「エディタで今見えている最新の保存内容」だけです
  • バージョンは HEAD のスナップショットで、一度切ると変更できません
  • デプロイは「どのバージョンを、Web アプリや API としてどの URL で公開するか」の設定です

コマンドはこの 3 層にそのまま対応しています。

clasp create-deployment --description "本番"
clasp list-deployments
clasp create-version "集計ロジック修正"
clasp update-deployment <deploymentId> --versionNumber 3 --description "本番"

最初の create-deployment はバージョン番号を渡さなければ新しいバージョンを自動で切ってからデプロイします。逆に create-version で先に番号を作ったのに create-deployment に番号を渡さないと、もう 1 つ新しいバージョンができて最初のものが使われません。更新時は --versionNumber で番号を明示し、--description も毎回付けます。省略すると説明が空で上書きされます。

Web アプリとして公開している場合は clasp open-web-app でデプロイ済み URL をブラウザで開けます。コンテナバインド型なら clasp open-container で紐づいたスプレッドシートが開きますが、これは .clasp.jsonparentId が保存されている場合だけです。create-script --type sheets で作ったプロジェクトには入りますが、既存プロジェクトを clone-script しただけでは入らないので、必要なら手で追記します。

ブラウザの「デプロイを管理」を開いてバージョン番号を選んで、という操作が全部コマンドになっているので、push → create-version → update-deployment までをシェルスクリプトにしておくと反映漏れが減ります。手貼り運用で一番怖いのは「コードは直したのに、公開中のデプロイが古いバージョンを指したまま」という状態で、コマンド化しておけばここを機械的に潰せます。

3.x で変わったこと(2.x 時代の記事を読む人へ)

日本語の clasp 記事の多くは 2.x 時代のもので、そのまま真似すると微妙にズレます。CHANGELOG で破壊的変更として挙がっているのは次の 3 つで、それに MCP の追加を足した 4 点を順に見ていきます。
意外と量が多くなったので別記事に切り出しています。

Claude Code との相性 ── プラグインと MCP

clasp の GitHub リポジトリには .claude-plugin/plugin.jsonclaude-mcp.json が同梱されています。v3.2.0(2026-02)で「Claude Code CLI support」として入ったもので、中身は clasp を MCP サーバーとして起動する設定です。

登録は 1 行で済みます。

claude mcp add clasp -- npx -y @google/clasp mcp

README にはプラグインとしてインストールする方法も書かれていますが、中身は同じ MCP サーバーの登録なので、この記事では上の 1 行で進めます。認証は CLI と同じ .clasprc.json を使うので、先に clasp login を済ませておく必要があります。

登録したら claude mcp listclasp: npx -y @google/clasp mcp - ✔ Connected と並びます。露出されるツールは執筆時点で 5 つだけです。

ツール名 対応する CLI
push_files clasp push
pull_files clasp pull
create_project clasp create-script
clone_project clasp clone-script
list_projects clasp list-scripts

clasp-claude-code-roles.png

つまり MCP でできるのは同期・作成・clone・一覧の 5 つだけで、デプロイ・バージョン・関数実行・ログは MCP には無い。create_project も standalone を作るだけで、CLI の --type--parentId にあたる指定はありません。とはいえ Claude Code は Bash が使えるので、そこは普通に clasp create-deployment を叩いてもらえば済みます。MCP は「プロジェクトのディレクトリをツール呼び出し時に渡す」設計なので、複数の GAS プロジェクトを行き来してもサーバーの再起動が要らないのが地味に効きます。

相性の話でもう一つ大事なのが、Claude Code に GAS の制約を教えておくことです。何も言わないと Node.js のつもりで require を書いたり、npm パッケージを入れようとしたりします。私はプロジェクトの CLAUDE.md にこう書いています。

CLAUDE.md
# このリポジトリは Google Apps Script のプロジェクトです

- ランタイムは V8。モダンな構文は使えるが Node.js ではない。require / import / npm は使えない
- 実行時の require / import は使えない。外部の機能が要るなら UrlFetchApp で REST API を叩くか、Apps Script のライブラリ機能を使うか、Rollup 等で事前に 1 ファイルへバンドルする
- 通常の実行は 6 分で強制終了される(カスタム関数やアドオンは別の短い上限がある)。長い処理はトリガーで分割する
- タイムゾーンは appsscript.json の timeZone に従う。日付文字列を手で組み立てない
- ローカルは .js で書く。push すると Apps Script 側では .gs として表示される
- 反映は clasp push(MCP の push_files でも同じ)
- デプロイは clasp create-deployment。MCP にデプロイ用ツールは無いので Bash で実行する
- .clasp.json の scriptId は書き換えない

ポイントは「Node.js ではない」と「MCP に無い操作は CLI で」の 2 点を明文化しておくことです。Claude Code は clasp --help も読めるので、コマンド名は新名で揃えておきます。

実際に Claude Code から GAS を作って push してみた

最後に、スプレッドシートの A 列を集計する小さな GAS を Claude Code に作らせて、MCP 経由で push するところまでを通しました。

1. clasp でプロジェクトを作る

空のディレクトリで、スプレッドシートに紐づいたプロジェクトを作ります。

clasp create-script --type sheets --title "clasp-playground"
Created new document: https://drive.google.com/open?id=1e54...(省略)
Created new script: https://script.google.com/d/1_mm...(省略)/edit
└─ appsscript.json
Cloned one file..

Drive に新しいスプレッドシートが 1 枚でき、それに紐づいた Apps Script プロジェクトが作られ、マニフェストが手元に落ちてきます。生成された .clasp.json はこうでした。README の例より項目が多く、parentId に紐づいたスプレッドシートの ID が入っています。

.clasp.json
{
  "scriptId": "1_mm...(省略)",
  "rootDir": "",
  "parentId": "1e54...(省略)",
  "scriptExtensions": [".js", ".gs"],
  "htmlExtensions": [".html"],
  "jsonExtensions": [".json"],
  "filePushOrder": [],
  "skipSubdirectories": false
}

ここで 1 つ注意点があります。落ちてきた appsscript.jsontimeZoneAmerica/New_York でした。このまま時間主導トリガーを組むと日本時間から 13 時間(冬時間の時期は 14 時間)ずれます。私は先に Asia/Tokyo に書き換えてから進めました。

appsscript.json
{
  "timeZone": "Asia/Tokyo",
  "dependencies": {},
  "exceptionLogging": "STACKDRIVER",
  "runtimeVersion": "V8"
}

2. Claude Code に書かせて、MCP で push させる

前節の CLAUDE.md をプロジェクトに置き、Claude Code にこう頼みました。MCP が本当に使われたかを確かめたかったので、この実験では --disallowedTools で Bash を明示的に禁止し、--allowedTools で clasp の MCP ツールとファイル操作だけを自動承認にしています。--allowedTools は「それ以外を使えなくする」設定ではなく「確認なしで通す」設定なので、完全に閉じたいなら --tools で候補自体を絞ります。

claude -p "GAS プロジェクトが <ディレクトリ> にあります。CLAUDE.md を読んでから、A 列(2 行目以降)の値ごとに件数を数えて Summary シートに書き出す関数 summarizeColumnA を Code.js に実装し、clasp の MCP ツール push_files で push してください。Bash は使わないでください。" \
  --allowedTools "mcp__clasp__push_files,mcp__clasp__pull_files,mcp__clasp__list_projects,Read,Write,Edit,Glob" \
  --disallowedTools "Bash"

Claude Code の動きを追うと、Read で CLAUDE.md を読み、Glob でディレクトリを確認し、Write で Code.js を書き、そのあと mcp__clasp__push_files を呼びました。全体で 13 ターン、約 75 秒です。Claude Code を起動したディレクトリはプロジェクトの外で、MCP ツールの引数 projectDir でプロジェクトの場所を渡しています。

書かれたコードは次のとおりです。require も npm も出てこず、Map で数えて setValues で一括書き込みする GAS らしい形になりました。

Code.js
function summarizeColumnA() {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sourceSheet = ss.getSheets()[0];

  const lastRow = sourceSheet.getLastRow();
  const counts = new Map();
  const order = [];

  if (lastRow >= 2) {
    const values = sourceSheet.getRange(2, 1, lastRow - 1, 1).getValues();
    for (let i = 0; i < values.length; i++) {
      const cell = values[i][0];
      if (cell === '' || cell === null) {
        continue;
      }
      const key = String(cell);
      if (counts.has(key)) {
        counts.set(key, counts.get(key) + 1);
      } else {
        counts.set(key, 1);
        order.push(key);
      }
    }
  }

  let summarySheet = ss.getSheetByName('Summary');
  if (summarySheet === null) {
    summarySheet = ss.insertSheet('Summary');
  } else {
    summarySheet.clear();
  }

  const output = [['', '件数']];
  for (let i = 0; i < order.length; i++) {
    const key = order[i];
    output.push([key, counts.get(key)]);
  }

  summarySheet.getRange(1, 1, output.length, 2).setValues(output);
}

push の結果は MCP ツールの戻り値として JSON で返ってきます。

{"scriptId":"1_mm...(省略)","projectDir":"/Users/.../clasp-playground","files":[".../appsscript.json",".../Code.js"]}

ただし一発では通りませんでした。最初、プロジェクトを /private/tmp 配下に置いていたところ、push_files がこう返してきました。

Security Error: projectDir must be within the user home directory or current working directory.

MCP モードの clasp は、ホームディレクトリの配下か、MCP サーバー自身のカレントディレクトリ(つまり Claude Code を起動した場所)の配下しか触らせない制限を持っています。今回はプロジェクトの外で Claude Code を起動していたので弾かれました。CLI で直接 clasp push する分には /private/tmp でも通るので、MCP 側だけの制約です。Claude Code はこのエラーを読んで、ホーム配下に同じ一式をコピーしてから push をやり直しました。私はその後プロジェクトごとホーム配下に移しています。プロジェクトのディレクトリで Claude Code を起動すれば、この制限には当たりませんし、CLAUDE.md も自動で読み込まれます。

3. 反映を確かめる

別のディレクトリで clasp clone-script <scriptId> を実行すると appsscript.jsonCode.js の 2 ファイルが落ちてきて、手元の Code.js と差分なしでした。スクリプトエディタを開くと、手元で .js だったファイルが Code.gs として並んでいます。

4. バージョンとデプロイは CLI で

MCP にはデプロイが無いので、ここは CLI です。ついでに前述の「create-deployment は番号を渡さないと新しいバージョンを切る」を確認しました。

clasp create-version "A列集計の初版"
clasp create-deployment --description "検証用"
clasp list-versions
Created version 1
Deployed AKfycbx...(省略) @2
Found 2 versions.
1 - A列集計の初版
2 - 検証用

先に切ったバージョン 1 は使われず、デプロイは自動で作られたバージョン 2 を指しています。バージョンを自分で管理したいなら create-deployment --versionNumber 1 のように明示が必要です。list-deployments を見ると、自分で作ったものとは別に @HEAD を指すデプロイが最初から 1 つ存在していて、これはエディタの「テストデプロイ」に相当します。

まとめ

clasp を「push と pull のツール」だと思っていた頃と比べると、3.x はだいぶ別物でした。コマンドがエディタの操作をひととおりカバーしていて、git で履歴を持てて、Claude Code から MCP で直接触れる。GAS をブラウザで書く理由が、正直ほとんど無くなりました。

一方で MCP はまだ experimental で、ツールも 5 つだけです。デプロイまで MCP で完結する日は来そうな気がしていて、CHANGELOG を追いながらこの記事も更新していくつもりです。

次は GitHub Actions から clasp push を回して、main にマージしたら本番の GAS が更新される構成を試します。すでに CI 連携をやっている方がいたら、認証情報の持ち方をどうしているか教えてもらえると嬉しいです。

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