📖

Service worker で (MCP) サーバを動かすメモ

に公開

ServiceWorker

web(ブラウザ上)でデーモンみたいなことができる.
URL アクセス(fetch)を横取りしてなんか処理とかできる.
(MCP) サーバたてたい.

制約

  • セキュリティ上, https か localhost でないと動かせない.
  • worker として動かすスクリプトは eval() など動的コード実行や, import() での動的 import ができない制約がある
    (webassembly は実行できる)
  • ブラウザ内だけなので, 外部(e.g. curl)からのアクセスはできない.

ちなみに Chrome だと, serviceWorker.register 使うと

というエラーがでるけど, serviceWorker.register での実行がエラーというわけではないのでややこしい.

serviceWorker の登録(起動)

https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts

にあるように window.isSecureContext のチェックを入れるとよい


if (window.isSecureContext) {
  if ("serviceWorker" in navigator) {
    navigator.serviceWorker.register('/mcp-service-worker.js').then(function(reg){
       if (reg.active) console.log('serviceworker installed')
    })
    .catch(function(err){
       console.log('registration failed: ' + err)
     })
  } else {
  console.log("no serviceworker")
}

こんなかんじでしょうか.
ちなみに著者は if ("serviceworker" in navigator) { と書いて, servieworker 検出されんのー, とうんうん悩んで半営業日消費しただよ...

worker 側

  • install
  • active
  • fetch

あたりに eventListener をしかけることができます.

install は register の最初に呼ばれる?
active はページリロードのたびに呼ばれる?
(stop イベントで deactivate できる?)
fetch はページへのアクセスがあったときに呼ばれる.

self.addEventListener('install', (event) => {
  console.log('[MCP server] Installing...');
});

self.addEventListener('activate', function (e) {
    console.info('[MCP server] activate', e);
});

self.addEventListener('fetch', function (e) {
    console.info('[MCP server] fetch', e);
});

こんなかんじでしょうか.

動作確認 tips

コード変更した場合, vite とかでのリロード or ブラウザリロードではうまく反映されないことが多いようです.

Chrome の場合 Application -> unregister してあげると良いようです.

MCP サーバ

あとは MCP のプロトコルに沿って JSON-RPC 通信をぺろぺろやればいけるはず!

service worker ではいろいろ制約あるので, proxy 的に使うのも手カモ.

ブラウザから別ホストの MCP サーバにつなぐときに, ブラウザ内で処理したい tool や resource は service worker ので処理させるとか.

(e.g. スクリーンショット取るとか. しかしスクリーンショット(DOM アクセス)は serviceworker 内では取得できないため, メッセージ通信でメインスレッドにリクエストを出すことで対応となろう)

さらなる高みへ

ChatGPT くんなり Claude くんへ相談しよう
(セキュリティ関連もありややこしいため, 以外といい返事もらえないけど)

Discussion