Goose を使ったAIエージェントコーディングやPuppeteer MCP Server によるブラウザ操作自動化


Goose

Gooseとは

Gooseは、Block社がオープンソースとして公開したAIエージェント開発フレームワークです。Block社とは旧Square社のことで、創業者兼CEOのジャック・ドーシー(Jack Patrick Dorsey)は、Twitter の共同創業者としても有名です。

Gooseを利用することで、開発効率を最大20%向上させる効果があったと報告されています。

現在、Goose用のアプリケーションとしてはMacのみリリースされており、Windows及びLinuxではコマンドラインでの利用になります。VS Codeなどの拡張機能でも利用可能であるかは調査中です。

今回はGooseのもう一つのポイントであるMCPを利用したPC操作の自動化に取り組んでみます。

個人的にはGooseがRust製というところも興味があります。

MCP(Model Context Protocol)とは

Model Context Protocol(MCP)は、AIシステムと外部のデータソースやツールを効率的に連携させるための新しいオープンスタンダードです。Anthropicが開発したこのプロトコルにより、AIアシスタントが様々なデータやツールにシームレスにアクセスできるようになります。MCPの主な特徴は以下の通りです:

  1. 普遍性とオープン性:様々な環境で柔軟に接続可能な汎用的な規格を提供します。
  2. 双方向接続:AIがデータの取得だけでなく、必要に応じて書き込みも行えます。
  3. 安全性:アクセス制御やセキュリティ機能が組み込まれており、機密データの利用も安全です。
  4. 拡張性:新しいデータソースやAIサービスに対応可能で、エコシステムの成長に合わせて拡張できます。

MCPを使用することで、開発者はGoogle Drive、Slack、GitHub、Postgresなどの多様なデータソースやツールとAIシステムを統一的に連携させることができます。これにより、これまで個別に開発が必要だった連携作業が大幅に簡素化されます。MCPのアーキテクチャは、MCPホスト(AIツールなど)、MCPクライアント(サーバーとの接続を維持するプロトコルクライアント)、MCPサーバー(特定の機能を公開する軽量プログラム)、そしてローカルデータソースやリモートサービスから構成されています。この技術により、AIアシスタントがより豊富な情報源にアクセスし、より適切で関連性の高い応答を生成できるようになります。また、ユーザーは技術的な知識がなくても、チャットを通じてデータにアクセスしたり操作したりすることが可能になります。

RPA(Robotic Process Automation)さらに簡単に使えるようにしたイメージではないかと思います。

Gooseのインストール

インストールはとても簡単です。下記ページの手順に従ってインストールしてください。

今回はWindowsのWSL環境にインストールしました。

Microsoft Storeから「Ubuntu 24.04.1 LTS」をインストールします。

スタートメニューから「Ubuntu 24.04.1 LTS」をクリックして起動します。

今回はLLMにGoogle Geminiを使うので、事前にGoogle AI StudioからAPI KEYを取得しておき、控えておきます。

echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
echo 'export GOOGLE_API_KEY=your_api_key' >> ~/.bashrc
source ~/.bashrc

Gooseインストールスクリプトを実行します。

sudo apt update && sudo apt install bzip2 -y
curl -fsSL https://github.com/block/goose/releases/download/stable/download_cli.sh | bash

LLMモデルの初期設定などはインストールマニュアルを参照してください。

Gooseの起動

次のコマンドで起動します。

goose session

プロンプト入力画面になるので、ここに命令を入力していきます。

starting session | provider: google model: gemini-2.0-flash-exp
    logging to /home/wohl/.config/goose/sessions/vjs0QoEE.jsonl


Goose is running! Enter your instructions, or try asking what goose can do.


( O)> あなたは誰ですか?
私はGoogleによってトレーニングされた、大規模言語モデルです。

( O)>  

Goose Extensions(MCPサーバー)のインストール

GooseのExtensionsは、MCPサーバーとして実装されています。これにより、Gooseの機能を拡張し、さまざまなアプリケーションやツールと連携することができます。独自開発のExtenxionsを追加することも可能です。

Built-In Extensionのインストール

まずは、基本的なExtensionsをインストールします。

マニュアルに従い、必要なBuilt-In Extensionをインストールします。

外部のExtension(MCPサーバー)のインストール

特にGoose用として公開されていなくても、MCPサーバーであれば利用できます。

今回はブラウザ操作を行う「Puppeteer」をインストールします。

PuppeterにはNode.jsが必要なので、まずはNode.jsをインストールします。

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.5/install.sh | bash
source ~/.bashrc
nvm install --lts

インストールが完了したら、以下のコマンドでNode.jsとnpmのバージョンを確認できます。

node --version
npm --version

必要な依存関係をインストールします。

sudo apt install -y \
  libx11-xcb1 \
  libxcomposite1 \
  libxcursor1 \
  libxdamage1 \
  libxi6 \
  libxtst6 \
  libnss3 \
  libxrandr2 \
  libasound2t64 \
  libatk1.0-0t64 \
  libatk-bridge2.0-0t64 \
  libcups2t64 \
  libxss1 \
  libgtk-3-0t64 \
  libgbm-dev

続いて、Puppeteerをインストールします。

┌   goose-configure 
│
◇  What would you like to configure?
│  Add Extension 
│
◇  What type of extension would you like to add?
│  Command-line Extension 
│
◇  What would you like to call this extension?
│  puppeteer
│
◇  What command should be run?
│  npx -y @modelcontextprotocol/server-puppeteer
│
◇  Would you like to add environment variables?
│  No 
│
└  Added fetch extension

これで、Gooseからブラウザ操作ができるようになりました。

ブラウザが自動的に起動し指定したサイトが表示されます。

$ goose session
starting session | provider: google model: gemini-2.0-flash-exp


Goose is running! Enter your instructions, or try asking what goose can do.


( O)> puppeteerで https://wohl-yz.net にアクセスしてください

─── puppeteer_navigate | puppeteer ──────────────────────────
url: https://wohl-yz.net



アクセスしました。何か他に操作はありますか?                                                          
( O)>            

GooseからPuppetterでブラウザを自動操作しWebサイトから情報を取得し保存する

Gooseにプロンプトを送信すると、ブラウザが起動して画面が遷移する様子が確認できます。

それでは、試してみます。指示内容は次の通りです。

  1. 弊社Webサイト(https://wohl-yz.net)にアクセスする。
  2. グローバルメニューの「Contact」をクリックする。
  3. Contactページのにある電話関連の<li>を取得する。
  4. 結果をテキストファイルとして保存する。

$ goose session
starting session | provider: google model: gemini-2.0-flash-exp

Goose is running! Enter your instructions, or try asking what goose can do.

( O)> 次の処理を行ってください。

実行ステップ:
1. puppeteerを使って https://wohl-yz.netにアクセスする。
2. グローバルメニューにある「Contact」をクリックする。
3. Contactページにある電話問い合わせに関する<li>を取得する。

成果物の要件:
- 形式: プレーンテキスト
- ファイル名: web.txt
- 内容:取得したliの内容
タスクを再開します。https://wohl-yz.net にアクセスし、Contact ページの内容にある電話問い合わせに関する `<li>` を取得しま
す。


─── puppeteer_navigate | puppeteer ──────────────────────────
url: https://wohl-yz.net


─── puppeteer_click | puppeteer ──────────────────────────
selector: a[href*='contact']


─── puppeteer_evaluate | puppeteer ──────────────────────────
script: ...

javascript でh2にTELを含む要素を探すことができませんでした。
もう一度試します。

─── puppeteer_evaluate | puppeteer ──────────────────────────
script: ...

まだjavascriptでh2にTELを含む要素を探すことができません。web_scrapeとrgでliの内容を取得することを試みます。

─── web_scrape | computercontroller ──────────────────────────
save_as: text
url: https://wohl-yz.net/contact/

```

─── shell | developer ──────────────────────────
command: rg  -A 3  '<h2>TEL</h2>' /home/wohl/.cache/goose/computer_controller/web_20250206_201050.txt | rg '<li'

─── shell | developer ──────────────────────────
command: rg  -A 3  '<h2>TEL</h2>' /home/wohl/.cache/goose/computer_controller/web_20250206_201050.txt | grep '<li'

```

─── shell | developer ──────────────────────────
command: rg  -A 10  '<h2>TEL</h2>' /home/wohl/.cache/goose/computer_controller/web_20250206_201050.txt | grep '<li'

```

Contactページにある電話問い合わせに関する `<li>` が見つかりませんでした。より大きな範囲で検索します。

─── shell | developer ──────────────────────────
command: rg  '<li>' /home/wohl/.cache/goose/computer_controller/web_20250206_201050.txt

─── shell | developer ──────────────────────────
command: grep  '<li>' /home/wohl/.cache/goose/computer_controller/web_20250206_201050.txt

```

─── shell | developer ──────────────────────────
command: grep  '<li>' /home/wohl/.cache/goose/computer_controller/web_20250206_201050.txt  > web.txt

─── text_editor | developer ──────────────────────────
path: web.txt
command: view

─── text_editor | developer ──────────────────────────
path: ~/web.txt
command: view

─── text_editor | developer ──────────────────────────
path: ~/web.txt
command: view

次の内容でファイル `/home/wohl/web.txt` を作成します。

```
<li>音声ガイダンスにつながりますので、ご希望の番号を押してください。</li>
<li>弊社に対する新規のご提案・ご案内等は問い合わせフォームをご利用ください。</li>
<li>電話よりもメールの方が早く返答できる場合が多いです。</li>
<li>スタッフ不在時には留守番電話につながりますので、ご了承ください。</li>
```

結果を保存したテキストファイルの内容

<li>音声ガイダンスにつながりますので、ご希望の番号を押してください。</li>
<li>弊社に対する新規のご提案・ご案内等は問い合わせフォームをご利用ください。</li>
<li>電話よりもメールの方が早く返答できる場合が多いです。</li>
<li>スタッフ不在時には留守番電話につながりますので、ご了承ください。</li>

簡単なAIコーディング カレンダー作成

下図のようなシンプルなカレンダーを作成するよう指示してみました。ボタンクリックで先月、翌月表示に切り替わります。

webブラウザで表示可能なカレンダーを作成してください。イベント機能は不要でシンプルなデザインがよいです。
Gooseで生成したカレンダー
Webブラウザで表示可能なカレンダーを作成するために、HTML、CSS、JavaScriptを使用します。
以下に手順を示します。

1.  **HTMLファイルを作成 (calendar.html)**: カレンダーの基本的な構造を記述します。
2.  **CSSファイルを作成 (calendar.css)**: カレンダーのデザインを定義します。
3.  **JavaScriptファイルを作成 (calendar.js)**: カレンダーの動的な動作を制御します(例えば、月の切り替え)。
最初にHTMLファイルから作成します。

```html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>シンプルなカレンダー</title>
    <link rel="stylesheet" href="calendar.css">
</head>
<body>
    <div class="calendar">
        <div class="header">
            <button id="prevMonth"><</button>
            <h2 id="currentMonth"></h2>
            <button id="nextMonth">></button>
        </div>
        <table id="calendarTable">
            <thead>
                <tr>
                    <th>日</th>
                    <th>月</th>
                    <th>火</th>
                    <th>水</th>
                    <th>木</th>
                    <th>金</th>
                    <th>土</th>
                </tr>
            </thead>
            <tbody></tbody>
        </table>
    </div>
    <script src="calendar.js"></script>
</body>
</html>
```

次に、CSSファイルを作成します。

```css
.calendar {
    width: 300px;
    border: 1px solid #ccc;
    margin: 20px auto;
}

.header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 10px;
    background-color: #f0f0f0;
}

.header button {
    padding: 5px 10px;
    cursor: pointer;
}

#calendarTable {
    width: 100%;
    border-collapse: collapse;
}

#calendarTable th,
#calendarTable td {
    text-align: center;
    padding: 8px;
    border: 1px solid #eee;
}

#calendarTable th {
    background-color: #eee;
}
```

最後に、JavaScriptファイルを作成します。

```javascript
const currentMonth = document.getElementById('currentMonth');
const calendarTable = document.getElementById('calendarTable').getElementsByTagName('tbody')[0];
const prevMonthButton = document.getElementById('prevMonth');
const nextMonthButton = document.getElementById('nextMonth');

let today = new Date();
let currentYear = today.getFullYear();
let currentMonthIndex = today.getMonth();

const monthNames = ["1月", "2月", "3月", "4月", "5月", "6月",
    "7月", "8月", "9月", "10月", "11月", "12月"];

function updateCalendar(year, month) {
    currentMonth.textContent = `${year}年${monthNames[month]}`;
    calendarTable.innerHTML = '';

    let firstDay = new Date(year, month, 1);
    let lastDay = new Date(year, month + 1, 0);
    let daysInMonth = lastDay.getDate();
    let startingDay = firstDay.getDay();

    let row = calendarTable.insertRow();
    let cellCount = 0;

    for (let i = 0; i < startingDay; i++) {
        let cell = row.insertCell();
        cellCount++;
    }

    for (let day = 1; day <= daysInMonth; day++) {
        let cell = row.insertCell();
        cell.textContent = day;
        cellCount++;

        if (cellCount % 7 === 0) {
            row = calendarTable.insertRow();
        }
    }
}

prevMonthButton.addEventListener('click', () => {
    currentMonthIndex--;
    if (currentMonthIndex < 0) {
        currentMonthIndex = 11;
        currentYear--;
    }
    updateCalendar(currentYear, currentMonthIndex);
});

nextMonthButton.addEventListener('click', () => {
    currentMonthIndex++;
    if (currentMonthIndex > 11) {
        currentMonthIndex = 0;
        currentYear++;
    }
    updateCalendar(currentYear, currentMonthIndex);
});

updateCalendar(currentYear, currentMonthIndex);
```

上記のHTML, CSS, JavaScriptをそれぞれ`calendar.html`, `calendar.css`, `calendar.js`というファイル名で保存し、同じディレ
クトリに置いてください。
次に、これらのファイルを保存します。


─── write |  ──────────────────────────
file_text: ...
path: /mnt/c/temp/web/calendar.html


─── write |  ──────────────────────────
file_text: ...
path: /mnt/c/temp/web/calendar.css


─── write |  ──────────────────────────
file_text: ...
path: /mnt/c/temp/web/calendar.js



これで、カレンダーのファイルが作成されました。`calendar.html`をブラウザで開くと、シンプルなカレンダーが表示されます。左
右のボタンをクリックすることで、月を移動できます。

Tool not found: write
Tool not found: write
Tool not found: write

申し訳ありません。以前の応答で、存在しない`write`というツールを呼び出してしまいました。代わりに、`developer__text_editor
`ツールを使用してファイルを作成する必要があります。以下に修正した手順を示します。

1.  **HTMLファイルを作成 (calendar.html)**: カレンダーの基本的な構造を記述します。
2.  **CSSファイルを作成 (calendar.css)**: カレンダーのデザインを定義します。
3.  **JavaScriptファイルを作成 (calendar.js)**: カレンダーの動的な動作を制御します(例えば、月の切り替え)。
最初にHTMLファイルから作成します。

```html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>シンプルなカレンダー</title>
    <link rel="stylesheet" href="calendar.css">
</head>
<body>
    <div class="calendar">
        <div class="header">
            <button id="prevMonth"><</button>
            <h2 id="currentMonth"></h2>
            <button id="nextMonth">></button>
        </div>
        <table id="calendarTable">
            <thead>
                <tr>
                    <th>日</th>
                    <th>月</th>
                    <th>火</th>
                    <th>水</th>
                    <th>木</th>
                    <th>金</th>
                    <th>土</th>
                </tr>
            </thead>
            <tbody></tbody>
        </table>
    </div>
    <script src="calendar.js"></script>
</body>
</html>
```

次に、CSSファイルを作成します。

```css
.calendar {
    width: 300px;
    border: 1px solid #ccc;
    margin: 20px auto;
}

.header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 10px;
    background-color: #f0f0f0;
}

.header button {
    padding: 5px 10px;
    cursor: pointer;
}

#calendarTable {
    width: 100%;
    border-collapse: collapse;
}

#calendarTable th,
#calendarTable td {
    text-align: center;
    padding: 8px;
    border: 1px solid #eee;
}

#calendarTable th {
    background-color: #eee;
}
```

最後に、JavaScriptファイルを作成します。

```javascript
const currentMonth = document.getElementById('currentMonth');
const calendarTable = document.getElementById('calendarTable').getElementsByTagName('tbody')[0];
const prevMonthButton = document.getElementById('prevMonth');
const nextMonthButton = document.getElementById('nextMonth');

let today = new Date();
let currentYear = today.getFullYear();
let currentMonthIndex = today.getMonth();

const monthNames = ["1月", "2月", "3月", "4月", "5月", "6月",
    "7月", "8月", "9月", "10月", "11月", "12月"];

function updateCalendar(year, month) {
    currentMonth.textContent = `${year}年${monthNames[month]}`;
    calendarTable.innerHTML = '';

    let firstDay = new Date(year, month, 1);
    let lastDay = new Date(year, month + 1, 0);
    let daysInMonth = lastDay.getDate();
    let startingDay = firstDay.getDay();

    let row = calendarTable.insertRow();
    let cellCount = 0;

    for (let i = 0; i < startingDay; i++) {
        let cell = row.insertCell();
        cellCount++;
    }

    for (let day = 1; day <= daysInMonth; day++) {
        let cell = row.insertCell();
        cell.textContent = day;
        cellCount++;

        if (cellCount % 7 === 0) {
            row = calendarTable.insertRow();
        }
    }
}

prevMonthButton.addEventListener('click', () => {
    currentMonthIndex--;
    if (currentMonthIndex < 0) {
        currentMonthIndex = 11;
        currentYear--;
    }
    updateCalendar(currentYear, currentMonthIndex);
});

nextMonthButton.addEventListener('click', () => {
    currentMonthIndex++;
    if (currentMonthIndex > 11) {
        currentMonthIndex = 0;
        currentYear++;
    }
    updateCalendar(currentYear, currentMonthIndex);
});

updateCalendar(currentYear, currentMonthIndex);
```

上記のHTML, CSS, JavaScriptをそれぞれ`calendar.html`, `calendar.css`, `calendar.js`というファイル名で保存し、同じディレ
クトリに置いてください。
次に、これらのファイルを保存します。


─── text_editor | developer ──────────────────────────
path: /mnt/c/temp/web/calendar.html
command: write
file_text: ...


### /mnt/c/temp/web/calendar.html
```html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>シンプルなカレンダー</title>
    <link rel="stylesheet" href="calendar.css">
</head>
<body>
    <div class="calendar">
        <div class="header">
            <button id="prevMonth"><</button>
            <h2 id="currentMonth"></h2>
            <button id="nextMonth">></button>
        </div>
        <table id="calendarTable">
            <thead>
                <tr>
                    <th>日</th>
                    <th>月</th>
                    <th>火</th>
                    <th>水</th>
                    <th>木</th>
                    <th>金</th>
                    <th>土</th>
                </tr>
            </thead>
            <tbody></tbody>
        </table>
    </div>
    <script src="calendar.js"></script>
</body>
</html>
```


─── text_editor | developer ──────────────────────────
path: /mnt/c/temp/web/calendar.css
command: write
file_text: ...



### /mnt/c/temp/web/calendar.css
```css
.calendar {
    width: 300px;
    border: 1px solid #ccc;
    margin: 20px auto;
}

.header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 10px;
    background-color: #f0f0f0;
}

.header button {
    padding: 5px 10px;
    cursor: pointer;
}

#calendarTable {
    width: 100%;
    border-collapse: collapse;
}

#calendarTable th,
#calendarTable td {
    text-align: center;
    padding: 8px;
    border: 1px solid #eee;
}

#calendarTable th {
    background-color: #eee;
}
```


─── text_editor | developer ──────────────────────────
path: /mnt/c/temp/web/calendar.js
command: write
file_text: ...



### /mnt/c/temp/web/calendar.js
```js
const currentMonth = document.getElementById('currentMonth');
const calendarTable = document.getElementById('calendarTable').getElementsByTagName('tbody')[0];
const prevMonthButton = document.getElementById('prevMonth');
const nextMonthButton = document.getElementById('nextMonth');

let today = new Date();
let currentYear = today.getFullYear();
let currentMonthIndex = today.getMonth();

const monthNames = ["1月", "2月", "3月", "4月", "5月", "6月",
    "7月", "8月", "9月", "10月", "11月", "12月"];

function updateCalendar(year, month) {
    currentMonth.textContent = `${year}年${monthNames[month]}`;
    calendarTable.innerHTML = '';

    let firstDay = new Date(year, month, 1);
    let lastDay = new Date(year, month + 1, 0);
    let daysInMonth = lastDay.getDate();
    let startingDay = firstDay.getDay();

    let row = calendarTable.insertRow();
    let cellCount = 0;

    for (let i = 0; i < startingDay; i++) {
        let cell = row.insertCell();
        cellCount++;
    }

    for (let day = 1; day <= daysInMonth; day++) {
        let cell = row.insertCell();
        cell.textContent = day;
        cellCount++;

        if (cellCount % 7 === 0) {
            row = calendarTable.insertRow();
        }
    }
}

prevMonthButton.addEventListener('click', () => {
    currentMonthIndex--;
    if (currentMonthIndex < 0) {
        currentMonthIndex = 11;
        currentYear--;
    }
    updateCalendar(currentYear, currentMonthIndex);
});

nextMonthButton.addEventListener('click', () => {
    currentMonthIndex++;
    if (currentMonthIndex > 11) {
        currentMonthIndex = 0;
        currentYear++;
    }
    updateCalendar(currentYear, currentMonthIndex);
});

updateCalendar(currentYear, currentMonthIndex);
```

これで、カレンダーのファイルが作成されました。`calendar.html`をブラウザで開くと、シンプルなカレンダーが表示されます。左
右のボタンをクリックすることで、月を移動できます。

まとめ

今回の検証では、Block社が開発したオープンソースのAIエージェント開発フレームワークGooseの基本的な機能と実用性を確認しました。検証は WSL(Windows Subsystem for Linux) 環境で行ない、Ubuntu 24.04.1 LTSを使用しました。

まず、Gooseのインストールプロセスを実施しました。インストールは比較的簡単で、公式ドキュメントに従って進めることができました。Google GeminiのAPI KEYを環境変数として設定し、Gooseの基本機能を利用可能にしました。

次に、Gooseの拡張機能であるExtensionsのインストールを行いました。特に注目したのは、ブラウザ操作を可能にするPuppeteerです。Node.jsとその依存関係のインストールが必要でしたが、手順に従って問題なく設定できました。Puppeteerを利用して指定のWEBサイトから情報を取得し、キストファイルとして保存することに成功しました。

最後に、AIコーディング機能を使用してシンプルなカレンダーアプリケーションの作成も試みました。この機能により、基本的なウェブアプリケーションの迅速な開発が可能であることが確認できました。

今回の検証を通じて、GooseとMCPの組み合わせが、AIエージェントの開発と外部ツールとの連携を効果的に簡素化できることが明らかになりました。

FAQ

GooseはどのOSに対応していますか?

現在、Mac向けにデスクトップアプリが提供され、Windows/LinuxではCLI経由での利用が可能です。

MCPの最大の利点は何ですか?

複数のデータソースとAIツールを単一のプロトコルで統合できる点が特徴です。従来は個別実装が必要だった連携作業が簡素化されます。

GooseのWSL環境でのインストール時に発生しやすい問題は?

主にNode.jsとPuppeteerの依存関係ライブラリ不足が報告されています。Ubuntu 24.04 LTSではlibgtk-3-0t64などのパッケージ追加が必要です。

GooseではGoogle Gemini以外のLLMは利用可能ですか?

OpenAIのGPT-4、AnthropicのClaudeなど主要なLLMプロバイダーに対応しています。APIキー設定で切り替え可能です。