📦

WASMコンポーネントを作成しMCPサーバから呼び出してみる

に公開

TL;DR

  • 以下の構成でMCPサーバとしてWassetteを活用し、WASMコンポーネントをGithub Copilotから使ってみます。
  • 呼び出すWASMコンポーネントも作ってみます。

Wassette とは? WASM × MCP がもたらす強力なセキュリティ

Wassetteは、WebAssembly (Wasm) を活用し、信頼できないツールに信頼できる実行環境を提供する、オープンソースのMCPサーバです。
WebAssemblyランタイムを組み込み、きめ細かなセキュリティポリシーを適用することで、Wassetteはホストシステムに悪影響を与えることなく、サードパーティ製のMCPツールを安全に実行できます。

生殺与奪の権をAgentに握らせるな!

事前準備

すでにインストールされていたらスキップで大丈夫です。

rustup target add wasm32-wasip1
cargo install cargo-component --locked
cargo install wkg

手順

コンポーネント作成

今回は文字数をカウントするToolとしてcharcountを作成します。

cargo component new --lib charcount

WITおよびコンポーネントのロジックの定義

まずはWITでWasmコンポーネントのインターフェースを定義します

wit/world.wit
package tools:charcount@0.1.0;

interface counter {
  /// Return the number of Unicode scalar values in the string.
  count: func(text: string) -> u32;
}

world component {
  export counter;
}

今回はシンプルな文字数カウンタを作成します

src/lib.rs
#[allow(warnings)]
mod bindings;
use bindings::exports::tools::charcount::counter::Guest;

struct Component;

impl Guest for Component {
    fn count(text: String) -> u32 {
        // Unicodeスカラ値(.chars())の個数を返す
        text.chars().count() as u32
    }
}

bindings::export!(Component with_types_in bindings);

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn ascii() { assert_eq!(Component::count("Hello".into()), 5); }
    #[test]
    fn jp()    { assert_eq!(Component::count("こんにちは".into()), 5); }
    #[test]
    fn emoji() { assert_eq!(Component::count("👍".into()), 1); } // 絵文字は1カウント
}

Buildします

cargo component check
cargo component build --release
  Generating bindings for charcount (src/bindings.rs)
   Compiling wit-bindgen-rt v0.44.0
   Compiling bitflags v2.9.4
   Compiling charcount v0.1.0 
    Finished `release` profile [optimized] target(s) in 1.96s
    Creating component target/wasm32-wasip1/release/charcount.wasm

charcount.wasmが生成されました!

作成したwasmコンポーネントをghcr.ioにpush

まずはGithubにてPATを作成します。
write:packages権限が付与されてることを確認してください。

その後作成したPATとusernameでdocker loginします。

echo YOUR_GITHUB_PAT | docker login ghcr.io -u YOUR_GITHUB_USERNAME --password-stdin

ghcr.ioにpushします!

wkg oci push ghcr.io/<YOUR_GITHUB_USERNAME>/charcount:0.1.0 target/wasm32-wasip1/release/charcount.wasm
pushed: ghcr.io/<YOUR_GITHUB_USERNAME>/charcount:0.1.0
digest: sha256:458ad93f9914d56a10971ab5948640e095a7a5bcb2d2a782e2627dce8cc5f3f9

PushしたPackageを確認

確認できたら、wassetteから読み込めるようにPackage settings -> Change package visibility -> Publicにします。

Publicになりました。

Copilotからwassetteを使ってWASMコンポーネントを呼び出す

VScodeでCopilotを開き、以下に設定します

  • Agentモードになっている
  • Tool🛠️ -> MCPサーバとしてwassetteにチェック

CopilotのチャットでまずはWASMコンポーネントをロードします。以下で指示してみます。

以下をロードして
oci://ghcr.io/<YOUR_GITHUB_USERNAME>/charcount:0.1.0

確認されるのでContinueをクリックします。
ロードできました。

続いて、以下を聞いてみます。

次の文字列の文字数を教えて
"hello wasm mcp"

先ほど同様Continueをクリックすると、Toolとして作成した文字数カウンタのWASMコンポーネントcharcountを使って答えが返ってきました!

Wassetteの機能の補足

- ファイルシステムやネットワークエンドポイントに対し厳密にポリシーを定義し、機能ベースのセキュリティを適用できます。

ファイルシステムやネットワークのpolicy
version: "1.0"
description: "An example policy"
permissions:
  storage:
    allow:
    - uri: "fs://workspace/**"
      access: ["read", "write"]
    - uri: "fs://config/app.yaml"
      access: ["read"]
  network:
    allow:
    - host: "api.openai.com"

https://microsoft.github.io/wassette/design/permission-system.html#permission-types-and-structure

- TL;DRに簡易的な構成を示しましたが、正確には以下のようなシーケンスで動いているようです。


https://microsoft.github.io/wassette/design/architecture.html

まとめ

個人レベルでAgentを使う場合にはそこまで気にならないセキュリティですが、規模が大きくなると気にしていかなければならないポイントだと思ってます。
WASM × MCP に期待してます!

Discussion