Primitives
Use primitives with the current published Askr packages.
@askrjs/askr0.0.59
How to use primitives
Start with this complete primitives shape, then replace the example data and application service with your own.
- Import the published @askrjs/askr entrypoint.
- Keep primitives configuration next to the component, route, or server composition root that owns it.
- Handle pending, unavailable, cancellation, and failure states, then verify the production path.
const mcp = createMcpServer({ name: 'project-tools', version: '1.0.0' })
.tool('lookup-project', { input: projectInput }, async (context, input) => {
return { content: [{ type: 'text', text: await lookup(input.id) }] };
});Tools
A tool is registered with `server.tool(name, { input, output, auth, ... }, handler)`; the handler receives an `McpContext` and the parsed input, and returns `{ content, structuredContent, isError }`. If you declare an `output` schema and the handler sets `structuredContent`, the result is validated with `safeParse` too — a mismatch produces a JSON-RPC internal error rather than a silently wrong response. `tools/list` returns each tool's name, its declared options, `inputSchema`, and `outputSchema` when present, paginated with a numeric-string cursor.
Resources
`server.resource(uri, options, handler)` registers an exact-match URI; `resources/read` looks it up directly and calls the handler with the parsed `URL`. The handler can return a single `McpContent` object or a readonly array — the server normalizes either into a `contents` array in the response. `resources/list` returns `{ uri, name, ...options }` for every visible resource, where `name` defaults to the URI itself if you don't set `options.name`.
Resource templates
`server.resourceTemplate(template, options, handler)` accepts a URI pattern with `{name}` placeholders; incoming reads are matched against every registered template with a generated regular expression, and the first match supplies the extracted variables to your handler. Templates also support an optional `complete(argument, value)` function used by `completion/complete` to return argument suggestions — the server caps returned values at 100 and reports `hasMore` if there were more. Unlike exact resources, template matching happens on every `resources/read` call whose URI isn't an exact registry hit, so keep templates reasonably specific to avoid ambiguous matches.
Prompts
`server.prompt(name, options, handler)` registers a named prompt whose `arguments` schema (an `ObjectSchema`, defaulting to empty) is parsed before the handler runs, mirroring tool input validation. The handler returns `{ description?, messages }`, and `prompts/list` derives each argument's `name`, `description`, and `required` flag directly from the schema's JSON Schema `properties` and `required` array — there's no separate argument-metadata API to keep in sync. Invalid prompt arguments produce a `-32602` JSON-RPC error with the schema's `issues` attached, the same shape tools use for invalid input.