MCP tools
The ERPBridge SDK wraps the official @modelcontextprotocol/client (D2) and
adds a typed surface. Use these surfaces to call and manage tools:
| Surface | What it is |
|---|---|
client.mcp | The raw MCP protocol client (connect, listTools, callTool, close) |
client.tools | The exact-name tool proxy (lazy, argument-validated) |
client.registry | REST CRUD over the stored tool resources |
Browser MCP and toolsโ
Browser applications can use the ESM build with client.mcp, client.tools,
and client.close():
import { createClient } from '@erpbridge/sdk'
const client = createClient({ baseUrl: 'https://bridge.example.com' })
await client.mcp.connect()
const result = await client.tools.list_employees({})
await client.close()
The ERPBridge /mcp/ endpoint must allow the frontend origin and the MCP
protocol and session headers. It must also expose Mcp-Session-Id. This
release supports only MCP and tools in browsers. Use Node.js, a same-origin
server, or an application proxy for logs, metrics, health, cache,
registry, and direct invoke operations.
The MCP clientโ
const client = createClient({ baseUrl: 'http://localhost:8080' })
await client.mcp.connect() // handshake + negotiation
const tools = await client.mcp.listTools() // ToolDefinition[]
const result = await client.mcp.callTool('system.progress_test', { steps: 1 })
await client.close()
connect()negotiates the protocol version with the server. The client negotiates down from2025-11-25and transparently reconnects once with a fresh session before it gives up with aProtocolErrorby default. SetmcpRetryPolicy: 'never'for side-effecting workflows that must not replay an operation after an ambiguous transport failure. In that mode, the first transport failure becomes aProtocolErrorand no reconnect occurs.listToolsmay include standard tool annotations and namespaced_metaguidance such aswhenToUse, examples, and allowed roles. Custom_metakeys are client-dependent and may not be forwarded into the model context.callToolreturns the complete MCPMcpToolResultenvelope. Inspect itscontentblocks and optionalstructuredContent. An unknown tool returnsNotFoundError. A tool that runs but reports failure returns{ isError: true }in the envelope.close()ends the session and its transport. The ERPBridge SDK client facade'sclose()does the same.
The tool proxyโ
client.tools is a lazy Proxy over the MCP tools/list result. It provides
an exact-name property for each registered tool:
await client.mcp.connect()
const result = await client.tools.list_employees({ department: 'engineering' })
Each property calls a registered tool by its exact registered name. Use
bare names such as list_employees, not erp.-prefixed names. Dotted names
also work: client.tools.system.progress_test({ steps: 1 }). The proxy validates
arguments against the tool input schema before the call. An unknown property
throws NotFoundError and lists the tools that the server exposes.
The tool registryโ
client.registry provides REST CRUD for stored tool resources. It is
separate from client.mcp.listTools() (C3):
registry.list({ name, version })returns exact-filtered resources in the full wire shape (RegistryTool:apiVersion: "erpbridge.io/v1"/kind: "MCPTool"/metadata/spec), not the flat MCPToolDefinition.registry.apply(def)posts a tool definition. The server's admission controller validates it and rejects violations with HTTP 422, surfaced as a typedClientError.registry.delete(name, version, { hard: true })soft- or hard-deletes a tool version.client.invoke(name, args, { role })calls a registered tool directly over REST. The optional role is sent asX-ERPBridge-Roleand is not added to the JSON arguments. No MCP session is needed. Built-insystem.*tools are reachable only through the MCP path. The REST invoke endpoint resolves only registered (stored) tools.
The registry deliberately lives outside client.tools so registered tool names
such as list, apply, or delete never shadow the registry methods.