Skip to content

Publish a SAM MCP server to the official MCP registry from the JS SDK #544

Description

@aojea

Goal

List SAM in the official MCP registry (https://registry.modelcontextprotocol.io) so that an MCP client installs the mesh the way it installs any other server: pick the entry, provide the enrollment values, done. The entry is published under dev.sam-mesh/, authenticated by DNS on sam-mesh.dev.

What the registry accepts

The registry stores a server.json per server and validates it automatically; there is no review. An entry names either packages[] (npm, PyPI, NuGet, crates.io, OCI on ghcr.io/docker.io/…, or an MCPB archive on GitHub Releases) that the client launches over stdio, or remotes[] (a streamable-HTTP URL). Two checks apply: namespace ownership (a TXT record on sam-mesh.dev for dev.sam-mesh/*) and package ownership (mcpName in package.json for npm, a mcp-name: line in the README for PyPI, a label on the image for OCI).

Why not sam-node

sam-node is a daemon. The user starts it, and the client connects to http://127.0.0.1:8080/mcp with X-Sam-Authentication (docs/guides/connecting-agents). A registry client does neither of those things: it launches a package over stdio or connects to a URL. A hosted remote does not fit either, because the node carries the member's identity and one URL for everyone would give every client the same identity. Making the node fit would mean a new stdio entrypoint plus a new distribution channel (MCPB archives or a labelled OCI image), for a binary that also runs egress enforcement, publishes services and hosts sandboxes. The node stays the deployment unit for those. The client story is the SDK.

Why the SDK, and why the JS one

Both SDKs are already on the registries the MCP registry accepts (@sam-mesh/sdk on npm, sam-mesh on PyPI), published from release.yml. Both are agents on the mesh with their own identity and enrollment, which is what a per-client MCP server should be. Both already depend on an MCP SDK (@modelcontextprotocol/sdk, mcp). Adding a stdio server on top of the existing session is a thin layer in either language.

The entrypoint goes in one SDK only; we do not maintain the same server twice. It goes in the JS SDK:

  • uvx sam-mesh does not install on a clean machine. py-libp2p 0.8 pins fastecdsa==2.3.2, which ships wheels only for macOS arm64 up to CPython 3.12 and is excluded on Windows; everywhere else it builds from source and needs a C compiler and GMP headers (sdk.yml installs libgmp-dev for this reason). npx @sam-mesh/sdk has no native build step.
  • The Python SDK carries more upstream workarounds: it replaces WebsocketTransport.dial through a private method (py-libp2p#1549, #1550), reimplements the circuit relay v2 client and the Kademlia provider walk, is pinned to libp2p<0.9, and has no lock file. The JS SDK uses @libp2p/circuit-relay-v2, @libp2p/kad-dht and @libp2p/gossipsub as shipped, has one internal access (Public API to listen on an address after start() (relay reservation gated by an application handshake) libp2p/js-libp2p#3645, #3601, tracked in sdk/js: cite the js-libp2p issues behind the relay workarounds #543) and a package-lock.json.
  • npx is the install path MCP clients show first, and the JS SDK is also the browser SDK, so the same code base covers Node and the page.

The Python SDK keeps its scope: a library for agents that run in a Python process.

Tasks

  1. sam-mesh executable in @sam-mesh/sdk (bin in package.json): a stdio MCP server (McpServer + StdioServerTransport) over MeshSession.
    • Tool names and schemas identical to sam-node: get_mesh_info, discover_remote_services, find_remote_tools, describe_remote_tool, call_remote_tool. agents/skills/sam-mesh/SKILL.md then applies to both without change. No list_local_services (an SDK member publishes nothing). Inference: decide whether to expose it as a tool or leave it out; the /v1 endpoint does not exist here.
    • Configuration from the environment, the names the SDK examples already use: SAM_CONTROL_PLANE_URL, SAM_BOOTSTRAP_TOKEN_PATH or SAM_JWT_PATH, SAM_STATE_DIR, SAM_INSECURE_CONTROL_PLANE. First run enrolls; later runs resume as the same peer. No secret on the command line.
    • Logs to stderr only; stdout is the MCP transport.
  2. "mcpName": "dev.sam-mesh/<name>" in sdk/js/package.json. Name to decide: dev.sam-mesh/mesh or dev.sam-mesh/sdk.
  3. sdk/js/server.json: one npm entry in packages[], transport.type: stdio, environmentVariables for the values above with the token path marked isSecret; version stamped by hack/sdk-version.sh with the rest.
  4. DNS: TXT record on sam-mesh.dev with the registry publisher key (operator task, one time).
  5. release.yml: after npm publish, mcp-publisher login dns and mcp-publisher publish, skipping when the version is already listed.
  6. Tests: unit tests for the tool mapping in sdk/js; an integration case in TestNativeSDK* that drives the executable with a stdio MCP client against sam-one.
  7. Docs: rework Connecting agents around the registry entry, and move the sam-node HTTP setup to the deployment side, where it remains the way to publish services, enforce egress and share one identity among several harnesses on a machine.

Refs

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestjavascriptPull requests that update javascript code

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions