@ontrove/mcp
@ontrove/mcp — the thin standard library for authoring hosted Trove MCP
servers. It owns the MCP protocol, JSON-RPC, schema validation, auth-context
injection, secret access, and error envelopes, so authors write only the
handlers (see the hosted-MCP SDK reference).
Example
Section titled “Example”import { defineMcpServer, z, ToolError } from "@ontrove/mcp";
export default defineMcpServer({ tools: [ { name: "lookup_order", description: "Look up an internal order by ID.", input: z.object({ orderId: z.string().describe("e.g. 'ORD-10423'.") }), async handler({ orderId }, ctx) { const token = await ctx.secret("ORDERS_API_TOKEN"); const res = await ctx.fetch(`https://orders.acme.internal/v1/${orderId}`, { headers: { authorization: `Bearer ${token}` }, }); if (res.status === 404) throw new ToolError(`Order ${orderId} not found`); return { text: `Order ${orderId}: ok`, structured: await res.json() }; }, }, ],});Classes
Section titled “Classes”ToolError
Section titled “ToolError”An intentional, model-visible tool error.
Never include secret values or internal stack traces in the message — it is visible to the model and potentially the user. Describe the problem at the level of the tool’s semantics, not the implementation.
Example
Section titled “Example”throw new ToolError(`Order ${orderId} not found`, { retryable: false });Extends
Section titled “Extends”Error
Constructors
Section titled “Constructors”Constructor
Section titled “Constructor”new ToolError(message: string, options?: ToolErrorOptions): ToolError;Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
message | string | Human-readable, model-safe error message. |
options? | ToolErrorOptions | Optional retryable hint and structured data. |
Returns
Section titled “Returns”Overrides
Section titled “Overrides”Error.constructorProperties
Section titled “Properties”Interfaces
Section titled “Interfaces”DefineOptions
Section titled “DefineOptions”Options for defineMcpServer — primarily injection points for tests.
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
fetchImpl? | FetchLike | Override the fetch implementation used by ctx callbacks/egress. |
FetchHandler
Section titled “FetchHandler”A minimal fetch handler shape, matching the fetch signature the hosted
runtime exposes for each request.
Methods
Section titled “Methods”fetch()
Section titled “fetch()”fetch(request: Request): Promise<Response>;Handle one HTTP request into the runtime.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
request | Request |
Returns
Section titled “Returns”Promise<Response>
FetchJsonOpts
Section titled “FetchJsonOpts”Options for ToolContext.fetchJson. Supply schema (as part of the
call, not this base type) to validate and type the result via z.infer.
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
errorMap? | (res: Response, body: string) => ToolError | undefined | Map a non-2xx response to a custom ToolError, given the response and its already-read body text (so the upstream’s own error message can be surfaced). Return undefined to fall back to the default status mapping. |
init? | RequestInit | Standard fetch init (method, headers, body). |
JsonSchema
Section titled “JsonSchema”A JSON Schema object for a tool’s inputSchema, as surfaced in tools/list.
Indexable
Section titled “Indexable”[key: string]: unknownAny further JSON Schema keywords emitted by the compiler.
Properties
Section titled “Properties”McpServerConfig
Section titled “McpServerConfig”The configuration passed to defineMcpServer.
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
auth? | OAuth2ClientCredentials | Optional declarative auth. When set, the SDK mints/caches/attaches the credential to egress automatically (see OAuth2ClientCredentials), so handlers issue plain ctx.fetch/ctx.fetchJson calls. |
egress? | readonly string[] | Optional egress host allowlist (each entry a hostname or host:port). When non-empty, the SDK denies any ctx.fetch to a host not on the list (deny-by-default), in addition to the always-on block of private/loopback/ link-local addresses. Mirror the manifest egress here to make the server self-protecting even when embedded standalone; the hosted egress proxy enforces the manifest allowlist regardless. |
scopes? | readonly string[] | The manifest-declared Trove capability scopes (e.g. ['trove:search']). Used only to auto-derive a conservative readOnlyHint default: a server that declares trove:ingest writes, so its tools are not read-only by default. Authors who set annotations.readOnlyHint explicitly override this. Optional and back-compatible — omitting it assumes no write scope. |
tools | readonly ToolDefinition<ZodTypeAny, ZodTypeAny>[] | The tools this server exposes. At least one is required. |
McpServerDefinition
Section titled “McpServerDefinition”The compiled server, produced by defineMcpServer. It carries the
tools/list descriptors and a normalized request handler the runtime entry
wires to the hosted runtime’s fetch.
Properties
Section titled “Properties”| Property | Modifier | Type | Description |
|---|---|---|---|
tools | readonly | readonly ToolListEntry[] | The tools/list descriptors (names un-namespaced, schemas compiled). |
Methods
Section titled “Methods”handle()
Section titled “handle()”handle(call: McpToolCall): Promise<McpToolCallResult>;Handle one normalized tool call: validate args, build ctx, run the
handler inside a try/catch, and normalize the outcome.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
call | McpToolCall |
Returns
Section titled “Returns”Promise<McpToolCallResult>
McpToolCall
Section titled “McpToolCall”A normalized tool-call request as POSTed by the gateway into the hosted
runtime. callbackBase is the Trove-provided origin the SDK’s ctx
callbacks target; it is appended to the egress allowlist server-side.
Properties
Section titled “Properties”McpToolCallErr
Section titled “McpToolCallErr”A normalized failed tool result, as returned to the gateway.
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
code | McpErrorCode | A stable error code, e.g. INVALID_PARAMS, UNKNOWN_TOOL, TOOL_ERROR. |
error | string | A model-safe error message — never a stack trace. |
ok | false | Discriminant: the call failed. |
retryable | boolean | Whether the model should consider retrying. |
McpToolCallOk
Section titled “McpToolCallOk”A normalized successful tool result, as returned to the gateway.
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
ok | true | Discriminant: the call succeeded. |
result | ToolResult | The wrapped result ({ text, structured? }). |
structuredContent? | unknown | The spec structuredContent object — present only when the invoked tool declared an output schema and the handler returned a structured value. Mirrors result.structured so a host can lift it straight into the tools/call result alongside the text content block. |
OAuth2ClientCredentials
Section titled “OAuth2ClientCredentials”Declarative OAuth2 client-credentials auth. When set on McpServerConfig,
the SDK mints, caches, and attaches a Bearer token to egress automatically,
so handlers never touch the token dance. The client id/secret are resolved
from the vault by name (both must appear in the manifest secrets), and the
tokenUrl host and apiHost must appear in the manifest egress.
Properties
Section titled “Properties”ToolAnnotations
Section titled “ToolAnnotations”Behavioral hints for a tool (MCP annotations, spec 2025-06-18 / 2025-11-25).
Hosts use these to decide confirmation friction and whether a tool reaches the
open world. Per the spec, the conservative absence default treats a tool as
readOnlyHint: false, destructiveHint: true, openWorldHint: true — so the
SDK auto-derives a safer readOnlyHint default (see ToolDefinition).
Clients MUST treat annotations as untrusted unless the server is trusted.
Properties
Section titled “Properties”ToolContext
Section titled “ToolContext”The invocation context handed to every tool handler — a small capability object with no ambient authority.
Each member maps to a Trove-provided callback the SDK closes over the
short-TTL ctxToken; the blast radius of a handler is exactly its declared
secrets ∪ scopes ∪ egress.
Properties
Section titled “Properties”| Property | Modifier | Type | Description |
|---|---|---|---|
trove? | readonly | TroveClient | A scoped client over the caller’s own knowledge base — present only if the manifest scopes requested trove:search and/or trove:ingest. |
userId | readonly | string | The authenticated Clerk user id of the caller — identity, not a credential. |
Methods
Section titled “Methods”fetch()
Section titled “fetch()”fetch(url: string | URL, init?: RequestInit): Promise<Response>;The only egress path out of the server. Behaves like the standard fetch.
The SDK itself enforces a baseline guard on every call — only http(s) is
allowed, and requests to private/loopback/link-local/reserved IP literals (and
localhost) are refused — and, when the server declares an egress allowlist,
denies any host not on it (deny by default). In the hosted runtime this is
backed by an egress proxy that blocks requests to private/loopback/link-local
addresses, which additionally enforces the manifest egress allowlist (and
defeats DNS-rebinding). A default User-Agent is added
when the caller does not set one; an explicit user-agent header always wins.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
url | string | URL |
init? | RequestInit |
Returns
Section titled “Returns”Promise<Response>
fetchJson()
Section titled “fetchJson()”Call Signature
Section titled “Call Signature”fetchJson<S>(url: string | URL, opts: FetchJsonOpts & { schema: S;}): Promise<TypeOf<S>>;Fetch JSON with batteries included: routes through fetch (so the
default UA and any declarative auth apply), maps a non-2xx status to a
ToolError (4xx≠429 → non-retryable; 429/5xx/network → retryable),
guards malformed JSON, and — when opts.schema is supplied — validates the
body and returns the typed result. Omit schema to receive parsed unknown.
Keep the schema lenient (.default()/.nullish()); it is for parsing the
upstream shape, not the tool’s strict output contract.
Type Parameters
Section titled “Type Parameters”| Type Parameter |
|---|
S extends ZodTypeAny |
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
url | string | URL |
opts | FetchJsonOpts & { schema: S; } |
Returns
Section titled “Returns”Promise<TypeOf<S>>
Call Signature
Section titled “Call Signature”fetchJson(url: string | URL, opts?: FetchJsonOpts): Promise<unknown>;Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
url | string | URL |
opts? | FetchJsonOpts |
Returns
Section titled “Returns”Promise<unknown>
log(...args: unknown[]): void;Structured log entry, redacted against known secret values, surfaced in trove logs.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
…args | unknown[] |
Returns
Section titled “Returns”void
requireSecret()
Section titled “requireSecret()”requireSecret(name: string): Promise<string>;Fetch a required secret, throwing a clear non-retryable ToolError
("<name> is not set. Run trove secret set …") when it is missing or
empty. The ergonomic default for credentials; secret is the escape hatch.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
name | string |
Returns
Section titled “Returns”Promise<string>
secret()
Section titled “secret()”secret(name: string): Promise<string>;Fetch one declared secret from the encrypted vault, decrypted only for
this invocation. name must appear in the manifest secrets array.
Throws a generic error if the secret is missing — prefer requireSecret
for required credentials, which throws a clear, model-visible message.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
name | string |
Returns
Section titled “Returns”Promise<string>
ToolDefinition
Section titled “ToolDefinition”A single tool definition. The input Zod schema is compiled to JSON Schema
for tools/list and used to validate arguments before handler runs.
Type Parameters
Section titled “Type Parameters”| Type Parameter | Default type | Description |
|---|---|---|
I extends z.ZodTypeAny | z.ZodTypeAny | The Zod schema type for the tool’s arguments. |
O extends z.ZodTypeAny | z.ZodTypeAny | The Zod schema type for the tool’s structured output, if declared. |
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
alwaysOn? | boolean | Budget hint: surface this tool even when the per-session cap is reached. |
annotations? | ToolAnnotations | Behavioral hints surfaced in tools/list. Any field the author omits is filled by a conservative default: readOnlyHint is true UNLESS the tool declares write intent (mutating: true, or the server is invoked with a trove:ingest scope). An explicit author value always wins. |
description | string | The description Claude reads to decide whether to call this tool. |
input | I | A Zod schema describing the tool’s arguments. |
mutating? | boolean | Marks the tool as mutating, which forces client consent. Defaults to false. |
name | string | A short snake_case identifier, unique within the server. |
output? | O | An optional Zod schema describing the tool’s structured output. When set, it is compiled to an outputSchema in tools/list and the handler’s structured field is surfaced as the spec structuredContent object. |
title? | string | A human-readable display name for client tool pickers (MCP title). |
Methods
Section titled “Methods”handler()
Section titled “handler()”handler(args: TypeOf<I>, ctx: ToolContext): Promise<string | ToolResult>;The async handler — receives validated args and the ToolContext.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
args | TypeOf<I> |
ctx | ToolContext |
Returns
Section titled “Returns”Promise<string | ToolResult>
ToolErrorOptions
Section titled “ToolErrorOptions”Options for ToolError.
Properties
Section titled “Properties”ToolListEntry
Section titled “ToolListEntry”The tools/list-shaped descriptor of a single tool.
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
alwaysOn? | boolean | Budget hint mirrored from the definition, when set. |
annotations | ToolAnnotations | Behavioral hints (MCP annotations), always present — either the author’s explicit values or the SDK’s conservative auto-derived defaults. |
description | string | The tool description. |
inputSchema | JsonSchema | The compiled JSON Schema for the tool’s arguments. |
mutating? | boolean | Mutating hint mirrored from the definition, when set. |
name | string | The tool name (un-namespaced; the gateway adds the {slug}__ prefix). |
outputSchema? | JsonSchema | The compiled JSON Schema for the tool’s structured output, present only when the definition declares an output schema (MCP outputSchema). |
title? | string | The human-readable display name (MCP title), when set. |
ToolResult
Section titled “ToolResult”The object a handler returns. text is the model-visible body; structured
is optional JSON-serializable data some clients display. When the tool
declares an output schema, structured is surfaced to the host as the
spec structuredContent object alongside the text mirror.
A handler may also return a bare string as shorthand for { text }.
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
structured? | unknown | Optional structured data attached to the result. |
text | string | The model-visible response body. Always provide this. |
TroveClient
Section titled “TroveClient”A scoped client over the calling user’s own Trove knowledge base.
Present on ToolContext.trove only when the manifest scopes
granted it (trove:search for reads, trove:ingest for writes); otherwise
ctx.trove is undefined.
Methods
Section titled “Methods”getDocument()
Section titled “getDocument()”getDocument(id: string): Promise<TroveDocument>;Fetch a full document by id. Requires trove:search.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
id | string |
Returns
Section titled “Returns”Promise<TroveDocument>
ingest()
Section titled “ingest()”ingest(docs: TroveIngestDoc[]): Promise<TroveIngestResult>;Write documents into the knowledge base. Requires trove:ingest.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
docs | TroveIngestDoc[] |
Returns
Section titled “Returns”Promise<TroveIngestResult>
search()
Section titled “search()”search(query: string, opts?: TroveSearchOpts): Promise<TroveSearchResult[]>;Semantic search over the user’s knowledge base. Requires trove:search.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
query | string |
opts? | TroveSearchOpts |
Returns
Section titled “Returns”Promise<TroveSearchResult[]>
TroveDocument
Section titled “TroveDocument”A full document fetched by id.
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
author? | string | The document author / podcast show name, if known. |
id | string | The document id. |
text | string | The full (possibly paged) document text. |
title | string | The document title. |
TroveIngestDoc
Section titled “TroveIngestDoc”A document to write into the knowledge base via TroveClient.ingest.
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
author? | string | Optional author / byline. |
text | string | The full document text to index. |
title | string | The document title. |
url? | string | Optional canonical URL of the source. |
TroveIngestResult
Section titled “TroveIngestResult”The result of an TroveClient.ingest call.
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
ingested | number | Number of documents accepted for ingestion. |
TroveSearchOpts
Section titled “TroveSearchOpts”Parameters to TroveClient.search.
Properties
Section titled “Properties”TroveSearchResult
Section titled “TroveSearchResult”A single semantic-search hit from the user’s knowledge base.
Properties
Section titled “Properties”Type Aliases
Section titled “Type Aliases”FetchLike
Section titled “FetchLike”type FetchLike = (input: string | URL, init?: RequestInit) => Promise<Response>;The fetch implementation the SDK uses for callbacks and egress. Injectable so
tests can supply a mock; defaults to the global fetch.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
input | string | URL |
init? | RequestInit |
Returns
Section titled “Returns”Promise<Response>
McpErrorCode
Section titled “McpErrorCode”type McpErrorCode = "INVALID_PARAMS" | "UNKNOWN_TOOL" | "TOOL_ERROR" | "BAD_REQUEST";Stable machine-readable error codes the SDK emits.
McpToolCallResult
Section titled “McpToolCallResult”type McpToolCallResult = McpToolCallOk | McpToolCallErr;The discriminated union of normalized tool-call outcomes.
Functions
Section titled “Functions”compileInputSchema()
Section titled “compileInputSchema()”function compileInputSchema(schema: ZodTypeAny): JsonSchema;Compile a Zod schema to a JSON Schema object suitable for inputSchema.
The schema is emitted fully inline ($refStrategy: 'none'), so the result is
a self-contained object schema with no top-level $ref. A non-object root
(e.g. z.string()) is rejected — tool arguments are always a named-field
object.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
schema | ZodTypeAny | The Zod schema for a tool’s arguments. |
Returns
Section titled “Returns”A JSON Schema object with type: 'object'.
Throws
Section titled “Throws”If the schema does not compile to an object schema.
defineMcpServer()
Section titled “defineMcpServer()”function defineMcpServer(config: McpServerConfig, options?: DefineOptions): McpServerDefinition;Define a hosted MCP server from a set of tool definitions.
The returned McpServerDefinition exposes the compiled tools/list
descriptors and a handle(call) that the runtime entry wires to the
hosted runtime’s fetch. Authoring errors (empty/duplicate/invalid tools,
non-object schemas) throw eagerly so trove deploy can statically validate.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
config | McpServerConfig | The { tools } configuration. |
options | DefineOptions | Optional injection points (test fetch). |
Returns
Section titled “Returns”The compiled server definition.
dispatch()
Section titled “dispatch()”function dispatch(server: McpServerDefinition, call: McpToolCall): Promise<McpToolCallResult>;Dispatch one normalized call against a server definition.
This is the seam the in-process test dispatcher drives: it runs the real SDK end-to-end without an isolated-sandbox boundary.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
server | McpServerDefinition | The compiled server definition. |
call | McpToolCall | The normalized tool call. |
Returns
Section titled “Returns”Promise<McpToolCallResult>
The normalized result.
listTools()
Section titled “listTools()”function listTools(server: McpServerDefinition): readonly ToolListEntry[];The tools/list descriptors for a server.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
server | McpServerDefinition | The compiled server definition. |
Returns
Section titled “Returns”readonly ToolListEntry[]
The list entries.
toFetchHandler()
Section titled “toFetchHandler()”function toFetchHandler(server: McpServerDefinition): FetchHandler;Wrap a server definition as a runtime fetch handler.
GET *→{ tools }(thetools/listcorpus)POST *→ run the body as a tool call, returns McpToolCallResult
Malformed JSON or a non-tool body yields a normalized BAD_REQUEST error
(HTTP 200 with { ok: false }), so the caller always parses a result rather
than a transport error.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
server | McpServerDefinition | The compiled server definition. |
Returns
Section titled “Returns”A fetch handler the bundle can export as default.