Client — rcp-sdk/client
For whoever is building the AI application. Discovers a server's manifest, exposes its tools, and executes calls against them.
import { createRcpClient } from 'rcp-sdk/client';createRcpClient(options?)
Creates one client bound to a single server’s auth/resolver/header configuration. Registering a second server means calling createRcpClient() again with different config — there’s no multi-server registry inside one instance.
const client = createRcpClient({
auth: { type: 'header', secret: process.env.SERVER_TOKEN! },
resolvers: {
userId: (ctx) => ctx.currentUserId,
},
headers: {
'X-Request-Id': () => crypto.randomUUID(),
},
});createRcpClient() only sets up how to talk to a server — auth, resolvers, headers. Which server (its manifest URL) is passed separately to discover() below, and the tool objects it returns already carry their own URL for every subsequent call(). One client instance can discover any number of servers that share this auth/resolver/header setup.Options
| Option | Type | Notes |
|---|---|---|
auth | {type:'none'} | {type:'header',...} | {type:'oauth2'} | Defaults to { type: 'none' }. oauth2 throws immediately — use none or header. |
resolvers | Record<string, (ctx) => unknown> | Param name → resolver. Removed from exposedParams at discovery time, filled from the resolver at call time. |
headers | Record<string, (ctx) => string> | Attached to every outgoing request, independent of anything the manifest declares. |
logger | { info, warn, error } | Silent by default. Pass console, or your own logger. |
client.discover(url, ctx?)
Fetches, validates, and returns a server’s manifest.
const { manifest, tools } = await client.discover('https://example.com/rcp/manifest');Returns { manifest, tools }. Each discovered tool is the raw tool plus exposedParams — the same params array with every resolver-bound name removed. Show exposedParams, not params, to your model.
| Throws | When |
|---|---|
Error | The manifest URL returned a non-2xx status. |
RcpManifestValidationError | The response body doesn’t match the manifest schema. |
RcpVersionMismatchError | rcpVersion isn’t one this client supports. |
client.call(tool, agentArgs?, ctx?)
Renders every token in the tool’s url/queryParams/headers/body, resolving each from a registered resolver or from agentArgs, attaches auth and injected headers, makes the request, and applies responseMappings.
const result = await client.call(tool, { city: 'Paris' }, { currentUserId: 'u_42' });
// { status: 200, ok: true, raw: {...}, mapped: {...} }Pass the raw tool object from discover()’s tools array — call() needs the full params list to know which tokens are resolver-bound versus model-fillable.
| Throws | When |
|---|---|
MissingTemplateValueError | A required, non-resolver-bound token has no value in agentArgs. |
RcpResolverError | A registered resolver ran but returned null/undefined. |
RcpToolAuthOverrideNotImplementedError | The tool declares its own auth, overriding the client’s — not implemented yet. |
Logging
Pass logger: console to see what the client is doing. Only structural facts are ever logged — tool names, HTTP methods, status codes, param names. Header values, request/response bodies, resolved values, and the auth secret are never logged.
const client = createRcpClient({ logger: console });
await client.discover('https://example.com/rcp/manifest');
// info: [RCP] discover: GET https://example.com/rcp/manifest
// info: [RCP] discover: found 2 tool(s) at ... (auth: header): get_weather, search
// info: [RCP] discover: "get_weather" hides 1 resolver-bound param(s) from the model: cityError classes
All exported from rcp-sdk/client, all plain Error subclasses (safe to instanceof-check): RcpAuthNotImplementedError, RcpVersionMismatchError, RcpManifestValidationError, RcpResolverError, RcpToolAuthOverrideNotImplementedError, MissingTemplateValueError.