Resolvers
A resolver-bound param never reaches the model — it's removed from the tool schema at discovery time, not just hidden by convention.
A tool often needs a value that shouldn’t come from the model at all: which end user is asking, which tenant they belong to, a locale — anything the client’s own operator already knows and the model would otherwise have to guess, or could spoof.
Nothing is declared in the manifest. A param like learnerId is written exactly like any other model-fillable param — the server doesn’t tag it, doesn’t need a reserved name, and doesn’t need to know whether some client intercepts it. The mechanism lives entirely on the client.
Configuring one
const client = createRcpClient({
resolvers: {
// fills a declared {{learnerId}} param before the model ever sees
// the tool's schema — the model has no argument to fill for it
learnerId: (ctx) => ctx.currentUserId,
},
});What happens at each step
- Discovery — the client removes every param it has a registered resolver for before the tool schema is shown to the model. Structurally unfillable, not just discouraged.
- Execution — the client calls the resolver to get the real value and substitutes it into the request before the server ever sees it.
- No value to resolve — a resolver with nothing to resolve from (no verified caller behind this turn, say) fails the call before any HTTP request goes out.
Seeing what a server is asking for
describeManifest() is the programmatic way to check, before wiring a server into a live agent, which params it declares and which of those you already have a resolver for:
import { createRcpClient, describeManifest } from 'rcp-sdk/client';
const client = createRcpClient({ resolvers: { userId: (ctx) => ctx.currentUserId } });
const { manifest, tools } = await client.discover('https://example.com/rcp/manifest');
console.log(describeManifest(manifest, tools));
// RCP manifest v0.1 — auth: header "Authorization" (scheme: Bearer)
// 1 tool(s):
// - get_profile (GET) — Get the current user's profile.
// userId: string, required [resolved by client, hidden from model] — the user's iddescription on that param is the only hint a client operator gets.