npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@robota-sdk/agent-mcp

v3.0.0-beta.100

Published

MCP client for the Robota SDK: server definitions, activation, connections, tool catalog and OAuth sign-in

Readme

@robota-sdk/agent-mcp

The Model Context Protocol (MCP) client for the Robota SDK: everything needed to let an agent use tools from external MCP servers. It keeps three concerns separate:

  • Definitions — what an MCP server is: decoding configuration entries, environment templates, precedence between configuration sources, disable overlays, redacted projections for display, and the identity and fingerprint an approval is tied to. Pure; nothing here connects or spawns.
  • Activation — whether a definition may be used: a deny-by-default admission port, exact identity matching, and a replaceable approval and audit store. The host decides workspace trust.
  • Client, catalog and supervision — the official @modelcontextprotocol/client, one client for both protocol eras, behind an admit-then-construct transport seam, the canonical catalog of discovered tools, prompts and resources, and a supervisor for the connection and catalog lifecycle.

Transports are Streamable HTTP and host-authorized stdio. Discovered tools enter the agent through the ordinary tool slot, so there is no MCP-specific runtime path. The agent runtime CLI uses this package for its mcpServers configuration; see the MCP guide for that side. To expose a agent session as an MCP server, use @robota-sdk/agent-transport-mcp.

Tool results retain ordered resource links, embedded text or binary resources, and inline audio alongside structured state, including failed observations. Resource URIs remain opaque references; receiving a link never fetches or activates it. Adapters without native resource/audio support project resource text and explicit binary/audio limitations into the linked tool response. Binary bytes remain in the typed receipt and persisted session; these text projections do not claim native audio delivery. The complete result envelope counts toward the host's admission bound and is preserved when spilled.

Explicit stateless wire surface

SDK hosts can pass protocolVersion: '2026-07-28' to openMcpSession after normal transport admission. A server definition can also select this path with protocolVersion: '2026-07-28' on HTTP or stdio. Omitting it preserves the legacy handshake. Protocol changes invalidate existing activation approvals; management projections retain the selected version. Unsupported versions or carriers are refused by name. The selected path sends server/discover and includes protocol version, client identity and empty optional client capabilities in every request. The HTTP header matches the body; an unsolicited legacy session header is never inherited. Selection cannot grant process/network authority or fall back to replay a mutation on another protocol.

The wire contract is pinned to the official schema at revision 046fa30. One @modelcontextprotocol/client serves both eras. This path pins it to 2026-07-28: a server that does not offer that revision is refused by name and never retried over the legacy handshake, while omitting the version negotiates the legacy era. A result without its resultType is refused rather than assumed complete. An invalid freshness hint on server/discover is read as the safest one (ttlMs 0, cacheScope private) instead of rejecting the server; a list page or resource read with one is refused.

Discovery validates and exposes each page's ttlMs, cacheScope and host receive time, and exposes the server discovery hint as the client read it. These values are freshness hints, not integrity or authority. Retained catalog identity includes a fresh carrier generation, preventing private data reuse across reconnects. If optional server information is absent, the configured server ID labels the source and the version is empty with serverInfoProvided: false; no external revision is invented.

This initial SDK surface supports declared tools, prompts and resources discovery plus completed tool calls. A host that opens the session with elicitation: true lets a server's form-mode elicitation during a tool call reach a person as ask prompts through that call's ask port, titled with the configured server id; the answer continues the same call, and the prompt is withdrawn when the call ends (when the last in-flight call to that server ends, if there are several). Otherwise compatibilityDiagnostics names the unavailable MRTR client input, as it does subscription watches and unselected optional extensions. Unsupported result types close the carrier and require operation inspection; so does an embedded request this surface does not answer (sampling, roots, more rounds than the client allows), while an embedded elicitation the client refuses on its face (URL mode, a malformed form) fails the call with the carrier open; none ever becomes a successful tool observation or causes automatic replay. A deadline or abort also closes uncertain execution. Hosts must refresh lists explicitly; this does not implement automatic TTL-based catalog refresh. Reading a generic resource cannot activate a skill.

Opt-in Skills wire view

SDK hosts can additionally pass skills: true to openMcpSession. This requires the explicitly selected stateless protocol and the server's valid Skills extension and Resources capability. session.skills is otherwise absent, with a compatibility diagnostic when requested but unavailable. The Skills extension defines the metadata and complete file manifests used here.

skills.list({ maxPages }) reads metadata only; skills.get(uri) confirms an explicitly referenced skill even after an empty listing. Entries retain the server identity, carrier generation, complete frontmatter and content fingerprint. skills.read(entry, fileUri) lazily verifies the requested file's raw byte size and SHA-256 before returning it. Refreshes invalidate old manifests; malformed or changed bytes require a fresh manifest. Dynamic manifests are exposed but verified reads are refused. The host's opt-in enables bounded file responses supporting 512 files and a 16 MiB raw manifest, including JSON/base64 framing; ordinary metadata and tool responses retain their existing receive limit.

This SDK view grants no instruction activation or tool permissions. A host must separately compare the loaded YAML frontmatter with the advertised metadata, require explicit content-bound user consent, preserve server-plus-URI identity in registry/approvals/caches, and revoke consent when content changes. Nested SKILL.md files are supporting bytes until separately approved. CLI/app skill activation and optional directory reads are not provided by this wire view.

Installation

npm install @robota-sdk/agent-mcp @robota-sdk/agent-core

Requires Node.js 22.12 or later. @robota-sdk/agent-core is a peer dependency.

Usage

Admit a transport, open a session inside a connection supervisor, discover the server, build the catalog, and turn each discovered tool into a runtime tool:

import {
  createStreamableHttpAdapter,
  openMcpSession,
  MCPConnectionSupervisor,
  buildCatalog,
  createDiscoveredTool,
} from '@robota-sdk/agent-mcp';

const adapter = createStreamableHttpAdapter();
const admission = await adapter.admit({ url: 'https://example.com/mcp' });
if (!admission.ok) {
  throw new Error(`${admission.reason}: ${admission.message}`);
}

const timeouts = {
  startupMs: 10_000,
  perCallMs: 30_000,
  globalDefaultMs: 30_000,
  idleMs: 60_000,
  toolCallMs: 30_000,
};
const serverId = 'example';

const supervisor = new MCPConnectionSupervisor({
  serverId,
  openSession: (signal) =>
    openMcpSession({
      serverId,
      transport: adapter.construct(admission.admitted),
      timeouts,
      signal,
    }),
  timeouts,
});

const discovery = await supervisor.discover();
const catalog = buildCatalog([
  { serverId, origin: 'config:example', transport: 'streamable-http', discovery },
]);

const tools = catalog.adopted
  .filter((entry) => entry.kind === 'tool')
  .map((entry) => createDiscoveredTool(entry, supervisor));

The default HTTP carrier validates and pins each actual request, including authentication retries and SSE reconnects, to addresses from the resolver captured during admission. Closing a transport withdraws pending requests and late authentication results and releases its owned connections. Explicit deps.fetch injection is an owner/test carrier with its own socket-policy responsibility.

From a repository checkout, build core and this package, then use examples/verify-http-transport.mjs to exercise initialization, an actual persistent SSE connection and cleanup in Node or Bun against a separate disposable Node server:

pnpm --filter @robota-sdk/agent-core build
pnpm --filter @robota-sdk/agent-mcp build
node packages/agent-mcp/examples/verify-http-transport.mjs
mcp_fixture_node=$(node -p process.execPath)
bun packages/agent-mcp/examples/verify-http-transport.mjs "$mcp_fixture_node"
mcp_fixture_dir=$(mktemp -d)
bun build --compile --minify packages/agent-mcp/examples/verify-http-transport.mjs --outfile "$mcp_fixture_dir/mcp-smoke"
"$mcp_fixture_dir/mcp-smoke" "$mcp_fixture_node"
rm -rf "$mcp_fixture_dir"

The fixture explicitly permits its disposable local server; it does not verify a full CLI worker, cloud provider or physical egress containment. The HTTP socket, authentication, trace and receive limit suites cover their corresponding contracts separately.

admit runs the shared egress policy before any connection: plain http: outside loopback, private address ranges and cloud-metadata addresses are refused, and redirects are refused rather than followed. openMcpSession() identifies itself to the server as mcp-client unless you pass clientInfo.

The catalog sorts everything the server disclosed into adopted, adapted and rejected entries, with stable, collision-safe tool names. The supervisor retries only transient failures, with bounded backoff, and keeps a catalog marked stale rather than emptying it when a refresh fails.

stdio

Stdio needs a host-owned IMCPStdioAuthority: an allowed root directory, an absolute executable, exact argument vectors, an explicitly selected child environment, and a generation. Pass a resolved definition and its activation request to createStdioAdapter({ admission, authority }).admit(...) before opening a session; the adapter rechecks activation and authority before every spawn. The child inherits no ambient environment values: the SDK's default environment keys are present only with host-selected values or empty strings. Cancelling or timing out an active stdio request closes the direct child, because the SDK provides no cancellation acknowledgment; grandchild processes are outside this transport's guarantee. See the runnable --allowed / --denied example.

Authentication

A host registers an authenticator for one server identity, and the HTTP transport asks it for headers on every request to that server only. The package provides:

  • OAuth sign-in for servers that declare oauth: runMCPOAuthLogin, runMCPOAuthLogout, createOAuthAuthenticator, with storage (createFileOAuthCredentialStore) and a cross-process refresh lock (createFileOAuthRefreshLock) as replaceable ports.
  • A headers helper (createHeadersHelperAuthenticator): an exact argv the host allows and runs, whose output is parsed strictly into request headers.

A definition that asks for authentication the host cannot provide stays listed and is refused by name; it is never connected with its static headers alone.

Where it sits

Depends only on @robota-sdk/agent-core (peer) and the MCP client packages (@modelcontextprotocol/client and @modelcontextprotocol/core). It owns no tool registry and no product identity: the composition root (for example the CLI) chooses the client identity and wires the discovered tools in.

Documentation

  • docs/SPEC.md — the full contract: admission, precedence, secrecy, OAuth, stdio authority and supervision.
  • docs/README.md — documentation index.