mcpField
A
Agent Mesh

Agent Mesh

ローカル
github.com/googleその他1.2k今日更新

Agent Mesh について

Agent Meshは、Node.jsやブラウザのエージェントがメッシュに参加するためのJavaScript SDKで、stdio対応のMCPサーバーでもあります。認証済みメンバーはポリシーに従ってリモートサービスを検索・呼び出せますが、このSDK自体はサービスを公開しません。

主な機能

  1. 01認証済みメンバーとしてメッシュに参加
  2. 02サービスとリモートツールの検索
  3. 03リモートツールの説明と呼び出し
  4. 04エージェント宛てA2Aリクエストへの応答
  5. 05次回セッション用のID保存

活用シーン

  1. 01MCPクライアントからAgent Mesh上のツールを利用
  2. 02メッシュサービスを呼び出すNode.jsエージェントの構築
  3. 03A2Aリクエストに応答するエージェントの作成

MCP 対応

`agentmesh`実行ファイルは、メッシュ情報の取得、サービスやツールの検索、ツールの説明とリモート呼び出しを行う5つのMCPツールをstdioで提供します。MCPクライアントがプロセスを起動・停止し、サービス提供側は`agentmesh-node`を通じてサービスを公開します。

設定

ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。

mcp.json · 共通設定
{
"mcpServers": {
"google-agentmesh": {
"command": "npx",
"args": [
"-y",
"@agentmesh-p2p/sdk"
],
"env": {
"AGENTMESH_CONTROL_PLANE_URL": "<AGENTMESH_CONTROL_PLANE_URL>",
"AGENTMESH_BOOTSTRAP_TOKEN_PATH": "<AGENTMESH_BOOTSTRAP_TOKEN_PATH>",
"AGENTMESH_JWT_PATH": "<AGENTMESH_JWT_PATH>",
"AGENTMESH_STATE_DIR": "<AGENTMESH_STATE_DIR>",
"AGENTMESH_INSECURE_CONTROL_PLANE": "<AGENTMESH_INSECURE_CONTROL_PLANE>"
}
}
}
}
起動コマンドnpx -y @agentmesh-p2p/sdk
設定が必要な環境変数
AGENTMESH_CONTROL_PLANE_URLControl plane URL supplied by your mesh operator. HTTPS is required beyond loopback unless explicitly permitted below.
AGENTMESH_BOOTSTRAP_TOKEN_PATHシークレットAbsolute path to a bootstrap token file for first enrollment. Set this OR AGENTMESH_JWT_PATH; leave both empty only when resuming saved credentials.
AGENTMESH_JWT_PATHシークレットAbsolute path to an OIDC/workload token file. Alternative to the bootstrap token; reread during credential refresh.
AGENTMESH_STATE_DIRAbsolute directory for this client identity. Use a distinct directory per client and mesh. If omitted, uses ~/.config/agentmesh/mcp.
AGENTMESH_INSECURE_CONTROL_PLANEAllow plaintext HTTP beyond loopback. Development only: exposes enrollment traffic to the network.

ローカルサーバーにはマシン上の実行環境(Node.js 18 以上など)が必要です。設定ファイルの場所はクライアントごとに異なります。

パッケージ
npm@agentmesh-p2p/sdk0.2.0

ツール

ツール一覧はまだ取得されていません

ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。

詳細

@agentmesh-p2p/sdk

エージェントプロセス内から Agent Mesh に参加するためのネイティブ JavaScript SDK です。Node.js 向けに書かれたエージェントや、ブラウザページで実行されるエージェントでは、agentmesh-node サイドカーの代わりに使用できます。 エージェントはコントロールプレーンに登録し、ルーターを介してメッシュに参加し、サービスを検索して呼び出し、エージェント自身への A2A リクエストに応答します。また、実行中はコントロールプレーンの鍵、禁止設定、ポリシーに従います。サービスは公開しません。名前で検索されるツールやモデルは、agentmesh-node の背後で実行します。

ガイド:google.github.io/agentmesh/docs/guides/native-sdks。何もないマシンから、メッシュ上の 2 つのプログラムを動かすところまで説明します。 ソース:github.com/google/agentmesh/tree/main/sdk/js。

インストール

npm install @agentmesh-p2p/sdk @modelcontextprotocol/sdk zod

Node.js 22.18 以降が必要です。ブラウザでは、ページにバンドルしてください(パッケージの browser フィールドでブラウザ用ファイルが選択されます)。詳しくは、ガイドのブラウザでの使用セクションをご覧ください。サンプルページもあります。

stdio 経由の MCP クライアント

パッケージの agentmesh 実行ファイルは、それ自体がメッシュメンバーとして参加し、5 つの MCP ツール(get_mesh_info、discover_remote_services、find_remote_tools、describe_remote_tool、call_remote_tool)を公開します。stdio 対応の MCP クライアントがプロセスを起動・停止するため、この呼び出し元にノードデーモンは必要ありません。プロバイダーは引き続き agentmesh-node を介してサービスを公開します。

ソースチェックアウトから実行ファイルを試すには、次のようにします。

cd sdk/js
npm ci
npm run build

MCP クライアントの設定では、絶対パスを使用してください。

{
  "mcpServers": {
    "agentmesh": {
      "command": "node",
      "args": ["/absolute/path/to/agentmesh/sdk/js/dist/cli.js"],
      "env": {
        "AGENTMESH_CONTROL_PLANE_URL": "https://your-control-plane.example",
        "AGENTMESH_BOOTSTRAP_TOKEN_PATH": "/absolute/path/to/join-token",
        "AGENTMESH_STATE_DIR": "/absolute/path/to/this-client-identity"
      }
    }
  }
}

コントロールプレーンの URL とトークンファイルは、メッシュの運用担当者または agentmesh-oneから入手してください。代わりに、AGENTMESH_JWT_PATH にワークロード/OIDC トークンファイルを設定することもできます。両方のトークンパスを設定しないでください。認証情報はファイルから読み込まれ、コマンドラインの値から読み込まれることはありません。

初回実行時に登録が行われ、ID が保存されます。以降の実行では、ブートストラップトークンなしで状態ディレクトリから再開します。JWT による登録では、更新時にトークンファイルを再読み込みします。クライアント ID とメッシュごとに別々の状態ディレクトリを使用し、複数のプロセスで同じディレクトリを共有しないでください。デフォルトは ~/.config/agentmesh/mcp です。AGENTMESH_INSECURE_CONTROL_PLANE=true で明示的に許可しない限り、HTTP の使用はループバックに限られます。

標準出力には MCP メッセージのみが出力され、診断情報は標準エラー出力に送られます。標準入力を閉じるか SIGINT/SIGTERM を送信すると、メッシュセッションが終了します。ツール呼び出しでは、プロバイダーラベルのチェックを含め、メンバーの既存の認証済みストリームとポリシーが使用されます。リモートツールの結果では、テキスト、非テキストコンテンツ、構造化出力、エラーが保持されます。検出ではツールのページネーションに従い、カタログのループを拒否します。また、検索ごとにプロバイダーは 64 件、プロバイダーごとのサービスは 256 件、サービスごとのツールは 256 件、結果は 1024 件に制限されます。リクエストの期限は 10 秒です。検索範囲が広すぎる場合は、ピアまたはサービスで絞り込んでください。intent は受け付けますが、現在のノードのツールと同様に無視されます。

このメンバーはサービスを公開しないため、list_local_services ツールはありません。推論と A2A の検出ではメタデータが返されますが、この実行ファイルには HTTP プロキシ、/v1 エンドポイント、ローカルソケット、local_proxy_url はありません。これらのプロトコルを呼び出すには、SDK クライアントまたは agentmesh-node の HTTP プロキシを使用してください。

使用方法

以下の2つのプログラムはどちらも examples/ にあり、 リポジトリのテストで実際のメッシュに対して実行されます。メッシュは AGENTMESH_CONTROL_PLANE_URL から、登録トークンは AGENTMESH_BOOTSTRAP_TOKEN_PATH から読み込みます。両方の取得方法は、agentmesh-one を使う方法と、既存のメッシュの運用者から入手する方法について、ガイドで説明しています。

サービスを見つけて呼び出します:

// Calls something on the mesh: a tool of an MCP service or a path of an
// inference or A2A service someone published, found by name, or an agent that
// published nothing, reached by its peer ID.
//
//   node call.js mcp://everything echo '{"message": "hi"}'
//   node call.js inference://ollama /v1/models
//   node call.js 12D3KooW... a2a://agent /card
//
// AGENTMESH_CONTROL_PLANE_URL names the mesh. The first run enrolls with the file
// AGENTMESH_BOOTSTRAP_TOKEN_PATH (a token the mesh operator gave you) or
// AGENTMESH_JWT_PATH (a workload identity token your platform issues, such as a
// Kubernetes projected service account token), and keeps the identity and
// credential in AGENTMESH_STATE_DIR; later runs resume from there without it.
import { homedir } from "node:os";
import { AgentMesh, type DiscoveredProvider } from "@agentmesh-p2p/sdk";

let argv = process.argv.slice(2);
// A first argument that is not a service target is the peer ID of an agent.
let peerId: string | undefined;
if (argv[0] !== undefined && !argv[0].includes("://")) {
  [peerId, ...argv] = argv as [string, ...string[]];
}
const [service = peerId !== undefined ? "a2a://agent" : "mcp://everything", toolOrPath = peerId !== undefined ? "/card" : "echo", args = '{"message": "hi"}'] = argv;

const mesh = await AgentMesh.enroll({
  controlPlaneUrl: process.env.AGENTMESH_CONTROL_PLANE_URL ?? "https://mesh.example.com",
  bootstrapTokenPath: process.env.AGENTMESH_BOOTSTRAP_TOKEN_PATH,
  jwtPath: process.env.AGENTMESH_JWT_PATH,
  stateDir: process.env.AGENTMESH_STATE_DIR ?? `${homedir()}/.config/agentmesh/caller`,
  // A plaintext http:// control plane is otherwise accepted only on loopback.
  allowInsecure: process.env.AGENTMESH_INSECURE_CONTROL_PLANE === "true",
});
const session = await mesh.join();
console.log(`on the mesh as ${session.peerId}`);

// The peer to call: an agent named by ID, or a provider of a published service.
let provider: DiscoveredProvider = { peerId: peerId ?? "", addrs: [] };
if (peerId !== undefined) {
  // An agent is not in the discovery table; the SDK finds the path to its
  // peer ID through the routers.
  await session.connect(peerId);
} else {
  const providers = await session.discover(service);
  if (providers.length === 0) {
    throw new Error(`no member of the mesh serves ${service}`);
  }
  // A provider record can outlive its member; the first that answers is used.
  let reached = false;
  for (const candidate of providers) {
    try {
      await session.connect(candidate);
      provider = candidate;
      reached = true;
      break;
    } catch (err) {
      console.error(`${candidate.peerId}: ${(err as Error).message}`);
    }
  }
  if (!reached) {
    throw new Error(`no provider of ${service} is reachable`);
  }
}
console.log(`${service} is served by ${provider.peerId}`);

if (service.startsWith("mcp://")) {
  const tools = await session.listTools(provider, service);
  console.log(`tools: ${tools.map((t) => t.name).join(", ")}`);
  const result = await session.callTool(provider, service, toolOrPath, JSON.parse(args));
  console.log(result.text.join("\n"));
} else {
  const response = await session.request(provider, service, toolOrPath);
  console.log(response.status, response.text());
}

await session.close();

ほかのユーザーから呼び出せるエージェントになります。何も公開されません。呼び出し元は、エージェントが出力するピア ID を使い、ルーター経由でエージェントにアクセスします:

// An agent on the mesh: joins, then answers A2A requests from other members
// until stopped. It publishes nothing. There is no service name to look up; a
// caller reaches the agent by its peer ID, through a router, as a2a://agent.
// The mesh policy decides which members may call; the SDK turns the others
// away before anything reaches this code.
//
//   node agent.js                        # answered by the handler below
//   node agent.js http://127.0.0.1:9999  # forwarded to an A2A server beside it
//
// AGENTMESH_CONTROL_PLANE_URL names the mesh. The first run enrolls with the file
// AGENTMESH_BOOTSTRAP_TOKEN_PATH (a token the mesh operator gave you) or
// AGENTMESH_JWT_PATH (a workload identity token your platform issues, such as a
// Kubernetes projected service account token), and keeps the identity and
// credential in AGENTMESH_STATE_DIR; later runs resume from there, as the same
// peer, without it.
import { homedir } from "node:os";
import { AgentMesh } from "@agentmesh-p2p/sdk";

const [backendURL] = process.argv.slice(2);

const mesh = await AgentMesh.enroll({
  controlPlaneUrl: process.env.AGENTMESH_CONTROL_PLANE_URL ?? "https://mesh.example.com",
  bootstrapTokenPath: process.env.AGENTMESH_BOOTSTRAP_TOKEN_PATH,
  jwtPath: process.env.AGENTMESH_JWT_PATH,
  stateDir: process.env.AGENTMESH_STATE_DIR ?? `${homedir()}/.config/agentmesh/agent`,
  // A plaintext http:// control plane is otherwise accepted only on loopback.
  allowInsecure: process.env.AGENTMESH_INSECURE_CONTROL_PLANE === "true",
});
const session = await mesh.join();

// Answers every path with who was asked and who asked; a real agent runs an
// A2A server here, or beside this process at backendURL.
const target = await session.acceptA2A(
  backendURL !== undefined
    ? { url: backendURL }
    : { handler: (request, caller) => Response.json({ name: "agent", path: new URL(request.url).pathname, caller: caller.peerId }) },
);
console.log(`accepting ${target} as ${session.peerId}`);

const stop = () => void session.close().then(() => process.exit(0));
process.on("SIGINT", stop);
process.on("SIGTERM", stop);

enroll は、stateDir に保存された ID と認証情報が、そのコントロールプレーンで引き続き有効であれば再利用します。それ以外の場合は、bootstrapTokenPath、bootstrapToken、jwtPath、jwt のいずれか1つだけが必要です(トークン文字列、または登録時と更新のたびに呼び出される () => string | Promise<string> コールバック)。トークンはファイル、コールバック、環境変数から読み込んでください。コマンドラインには記載しないでください。labels は登録時に証明されます。join({ egressRequireLabels }) は、セッションが呼び出すすべてのピアが証明しなければならない要件の基準であり、セッション中はそのすべてが維持されます。

平文の http:// コントロールプレーンは、ループバック上でのみ利用できます。信頼できるネットワークでは allowInsecure: true を指定してください。

ライセンス

Apache-2.0。問題の報告や貢献については、 github.com/google/agentmesh をご覧ください。

コメント

MCP は初めてですか?

プロトコルの概要から最初のサーバーの導入まで、よくある疑問にまとめて答えます。

AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。