☁️

プロンプトだけでCloudflare Workersにブログを作る

2024/12/16に公開

MCPイントロ

MCP = Model Context Protocolを活用する話です。MCPとはAnthropicが11月26日に発表したAIが外部のコンテンツやツール、環境にアクセスするためのプロトコルです。プロトコルなので、Anthropicが自分のためだけにつくってものではなく標準的なものです。MCPを使うことは、ファインチューンやRAGなどAIを特化するための手法の一つとも言えます。やっていることはFunction Callingに近いです。今回「MCPとは?」はこのくらいにしておきます。ここでやりたいのは「MCPを活用するとこんなことができるんだ」というデモを一緒に体験することです。

空前のMCPブーム

11月26日にMCPが発表になるとCloudflare社内で盛り上がります。早速、MCP専用のチャットルームが作られ、「Cloudflare MCP Server」の実装が始まります。

https://github.com/cloudflare/mcp-server-cloudflare

11月28日にはDevRelチームのマネージャーのRicky(つまり僕の上司)がYouTubeとXにCloudflare MCP Serverのデモ動画をアップします。

https://www.youtube.com/watch?v=vGajZpl_9yA

また、Cloudflare MCP Serverをガリガリ書いてたGlen(普段はD1を作ってて、僕をCloudflareに誘ってくれたエンジニア)が別実装を作りだし、12月6日にデモを公開。また、先日12月14日にworkers-mcpというnpmパッケージとしてパブリッシュしました。

https://github.com/geelen/workers-mcp

MCPサーバー

MCPではClaude DesktopをMCPクライントとして、ローカルにMCPサーバーを立てて、それが提供する「Tool」を使うことができます。図にするとこんな感じです。

MCP

例えば、Model Context Protocol serversというレポジトリにはMCPサーバーの参考実装があるのですが、そこからいくつかピックアップするとこのような具合です。

  • Fetch - ウェブコンテンツ取得と変換
  • Filesystem - セキュアなファイル操作
  • GitHub - GitHub管理とAPI連携
  • Google Drive - Google Driveのファイルアクセス
  • Google Maps - 位置情報とルート検索
  • Puppeteer - ブラウザ自動化とスクレイピング
  • Sentry - Sentry.ioの課題分析
  • Slack - チャンネル管理とメッセージ送信
  • Sqlite - データベース操作

簡単に言えば、これらのMCPサーバーをローカルに立てれば、ClaudeがGitHubやGoogle、Slackへアクセスし、操作することができるのです。例えば、プロンプトでGitHubのレポジトリを作成したり、Slackへメッセージを送信することができます。

MCPサーバーの実装

MCPサーバーは自分でも実装できます。プロトコルなので、どんな言語でもいいのですが、TypeScriptにはSDKがあるので、それを使ってみます。

https://github.com/modelcontextprotocol/typescript-sdk

では「じゃんけん」をするだけのMCPサーバーを作ってみます。MCPを実行する単位を「Tool」と呼びます。今回はdo_gameというToolにします。最低限以下の2つのことをやればMCPサーバーになります。

  • Toolのリスト - do_gameを定義
  • Toolの実行 - do_gameの実行、結果を返却

コードの一部を抜粋すると、do_gameの定義はこのようになります。do_gamechoiceという変数名は後ほど使うのですが、descriptionには自然言語を書きます。するとClaudeがよしなにしてくれて、この場合は英語で「Rock, paper, scissors game」としてますが、日本語で「じゃんけん」というのを汲み取ってくれます。

server.setRequestHandler(ListToolsRequestSchema, () => ({
  tools: [
    {
      name: 'do_game',
      description: 'Rock, paper, scissors game',
      inputSchema: {
        type: 'object',
        properties: {
          choice: {
            type: 'string',
            description: 'Choose from rock, paper, or scissors'
          }
        },
        required: ['choice']
      }
    }
  ]
}))

次にdo_gameの中身を書きますが、これはただただ実装すればいいというものです。今回はAIが必ず勝つというロジックにしました。

server.setRequestHandler(CallToolRequestSchema, async (request) => {
  if (request.params.name !== 'do_game') {
    throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${request.params.name}`)
  }

  if (!isValidArgs(request.params.arguments)) {
    throw new McpError(ErrorCode.InvalidParams, 'Invalid arguments')
  }

  const choice = request.params.arguments.choice
  const winningChoices: Record<string, string> = {
    rock: 'paper',
    paper: 'scissors',
    scissors: 'rock'
  }
  const programChoice = winningChoices[choice]

  return {
    content: [
      {
        type: 'text',
        text: JSON.stringify({ message: `You chose ${choice}. I chose ${programChoice}. I win!` })
      }
    ]
  }
})

以上で、最低限のMCPサーバーの実装ができました。完全なコードは以下です。

https://github.com/yusukebe/my-first-mcp-server

これを動かすには、claude_desktop_config.jsonというファイルにこのMCPサーバーを登録して、Claudeを再起動するだけでOKです。

{
  "mcpServers": {
    "game": {
      "command": "node",
      "args": [
        "/Users/yusuke/work/m/mcp-server-hello/build/index.js"
      ]
    }
  }
}

この要領で、ClaudeデスクトップにMCPサーバーを次々追加していくことが出来ます。

Cloudflare MCP Server

Cloudflare MCP Serverでは、CloudflareのいくつもあるサービスにMCPでアクセスできるものです。ローカルで立ち上がり、CloudflareのAPIを叩きます。現在以下のサービスに対応しています。

  • KV
  • R2
  • D1
  • Analytics

例えば、KVでできること、つまりToolの一覧はこのようになっています。

  • get_kvs: アカウント内のKV名前空間を一覧表示
  • kv_get: KV名前空間から値を取得
  • kv_put: KV名前空間に値を保存
  • kv_list: KV名前空間のキーを一覧表示
  • kv_delete: KV名前空間からキーを削除

基本的な機能はすべて網羅されています。

Cloudflare Workers上にブログを作る

では、Cloudflare MCP Serverを使ってClaudeからプロンプトのみでWorkers上にブログシステムを作ってみます。以下のXのポストで動画版を見ることが出来ます。

https://x.com/yusukebe/status/1868546931183796717

D1のデータベースを作る

最初にD1のデータベースを作成します。今回はデモなんで意図的にD1を指定し「ポストのみ」としています。

D1にポストのみのシンプルなブログのデータベースを作ってください

と会話をするとClaudeが答えて、D1にデータベースをつくります。その際に、該当のToolにアクセスするけどよいかどうか尋ねてきますので、「Allow」を押します。毎回聞かれるのですが、これによって、勝手に予期せぬMCPサーバーが挙動しないようになります。

Claude

データベースを作り終えると、テーブルの作成、確認用のデータの挿入までやってくれます。

Workerを作る

先ほど作成したDBを利用して、Workers上にブログシステムをつくります。これもデモってことでかなり意図的なプロンプトになっています。コツはHonoを使わないことです。また、素のJavaScriptで書いてもらうことです。これは、外部ライブラリを使うとバンドルしなくてはいけないし、TypeScriptだとビルドしなくてはいけないので、今回はそうしています。バンドルやビルドができるMCPサーバーを用意すればできると思います。また、Bindingsの設定は手動でやりたいので、しなくていい旨を伝えます。

そのデータベースを利用して、Workers上にJSONを返す閲覧だけのブログシステムをつくってください。Honoを使わず、素のJavaScriptでお願いします。コードを書くのとデプロイを同時にしてください。コード内のD1のBindingはDBという名前をつかって、Bindingsの設定はしないでください

するとコードを生成して、デプロイまでやってくれます。

claude-02

確認する

本当にWorkersにデプロイされたか見てみましょう。

私のドメインはyusukebe.workers.devです

と尋ねるとデプロイした正確なURLを教えてくれます。

claude-03

そのアドレスにアクセスしてみると、おおJSONが返ってきています!

Web

これは明らかにCloudflare Workersのデプロイ済みのアプリです!

UIを作る

では、最後にHTMLのUIをつけてみましょう。

今のWorkerにHTMLを追加してUIをつけてください

claude-4

トップページにアクセスしてみるとブログが出来てます!さらにサンプルの記事をClaudeに入れてもらうと、かなりそれっぽい!

SS

5分間ほどでここまでできました!

デモのおさらい

デモのプロンプトのコツはこのようなものでした。「Honoを使わない」というのがなんとも味わい深いですね。

  • Cloudflare WorkersとD1を使う
  • ポストだけのシンプルなブログにする
  • Honoを使わず、素のJavaScriptで書いてもらう
  • D1のデータベースから作ってもらう

このデモでは、SQLデータベースのD1を使っただけでしたが、オブジェクトストレージのR2を使って画像を保存してブログに埋め込むなんてこともできます。また、Glenが作ってるworkers-mcpを使えば、Cloudflareのリソースを使った任意のメソッドをToolにできるので、例えば、Workers AIで画像生成をするToolができます。そうすると、ブログ記事をそこに食わせて画像を生成して、OGPにする、なんてこともできちゃいます。

まとめ

以上、MCP = Model Context ProtocolとCloudflare Workersについて紹介しました。Cloudflareのリソースを扱うMCPサーバー、Cloudflare MCP Serverを使ってWorkers上にブログシステムを作りました。この2つの組み合わせはかなり強力なので、みなさんも試してみてください!

Discussion