ウェブツールを依存関係ゼロのMCPサーバーに変換する

私はDomainIntelという小さなウェブアプリを運営しています。これをModel Context Protocol (MCP) サーバーに変換したいと考えました。

ユーザーが実行するのは、たった一つのコマンド npx -y @domainintel/mcp だけにしたいと考えました。

これにより、摩擦(フリクション)をゼロにできます。リポジトリのクローンも、長いインストール時間も必要ありません。サーバーは、ランタイムの依存関係がない単一のファイルとして動作する必要があります。

以下に、esbuildを使用して構築した方法を紹介します。

課題:パッケージング

すべてをバンドルするためにesbuildを使用しました。いくつかの技術的なハードルを解決する必要がありました。

静的インポート: esbuildは実行時のrequire呼び出しを追跡できません。そのため、createRequireから標準的なESMインポートに切り替えました。これにより、esbuildが依存関係グラフを追跡できるようになりました。

CommonJSの互換性: ある依存関係が内部でrequire('net')を使用していました。esbuildの設定にバナーを追加しました。このバナーがcreateRequireを注入することで、組み込みモジュールに対してシム(shim)が機能するようにしました。

ロガーの競合: MCPは通信にstdoutを使用します。既存のロガーはローカルディレクトリに書き込もうとしていましたが、これはグローバルなCLIでは失敗します。onResolveプラグインを使用して、ロガーをスタブ化しました。

二重のシバン (Shebang): エントリファイルとバナーの両方にシバンがありました。これにより、無効なファイルが生成されてしまいます。そのため、ソースコードからシバンを削除しました。

モジュールタイプ: package.jsonから"type": "module"を削除しました。これにより、esbuildがCommonJSファイルをESMとして扱うのを防ぎました。エントリファイルの.mjsは、拡張子によってESMのまま維持されます。

バージョンの固定: ある依存関係がESMに切り替わったことで、ビルドが壊れてしまいました。バンドルを再現可能にするために、バージョンを固定しました。

結果

最終的なファイルは mcp/dist/server.mjs です。サイズは約1.7 MBで、ランタイムの依存関係は一切ありません。

次のコマンドでClaudeに追加できます: claude mcp add domainintel -- npx -y @domainintel/mcp

これで、エージェントに「stripe.comに関する詳細なレポートをください」と指示するだけで、即座にデータを受け取れるようになります。

コアロジックを持つツールをお持ちなら、それをMCPサーバーとしてラップしてみてください。そうすることで、あなたのツールをAIエージェントにとって有用なものにできます。

Source: https://dev.to/chris_morris/turning-a-web-tool-into-a-zero-dependency-mcp-server-21ca

Optional learning community: https://t.me/GyaanSetuAi