Tools, resources & prompts
Author the core MCP surface with the @noodleseed/one SDK. Typed tools, readable resources, and reusable prompts.
A Noodle Seed server is a server(name, options, definitions) call. The definitions array holds
your tools, resources, and prompts. Everything imports from the bare @noodleseed/one package.
import { server, tool, resource, prompt, z } from '@noodleseed/one';
export default server('support', { title: 'Support', version: '1.0.0' }, [
// tools, resources, prompts go here
]);Tools
A tool is a typed action the model can call. It declares a Zod input schema, an optional output
schema, and a fulfil function that returns the result.
tool('greet', {
description: 'Greet a person by name.',
input: z.object({ name: z.string().default('world') }),
output: z.object({ message: z.string() }),
fulfil: ({ input }) => {
return { message: `Hello, ${input.name}!` };
},
});tool(name, options) accepts:
| Option | Type | Notes |
|---|---|---|
description | string | Shown to the model in tools/list. |
input | Zod schema | Compiled to JSON Schema 2020-12. |
output | Zod schema | Optional but recommended for structured results. |
fulfil | (ctx) => result | Returns the output. Receives { input, user, connectors }. |
annotations | object | Behavior hints (see below). |
visibility | ('model' | 'app')[] | Defaults to both. Use ['app'] for app-only tools. |
view | React entry or raw HTML | Links the tool result to an MCP App view. |
Annotations
Use the annotations helper to declare behavior hints so hosts can present the tool correctly.
import { annotations } from '@noodleseed/one';
tool('list_orders', {
description: 'List recent orders.',
input: z.object({ limit: z.number().int().min(1).max(50).default(10) }),
output: z.object({ orders: z.array(z.object({ id: z.string() })) }),
annotations: annotations.readOnly(),
fulfil: ({ input }) => ({ orders: [] }),
});annotations.readOnly(), annotations.action(), annotations.localAction(), and
annotations.openAction() map to the MCP readOnlyHint / destructiveHint / idempotentHint /
openWorldHint fields.
Calling connectors
To reach an external API, bind a connector on the server's use map and call it inside fulfil via
ctx.connectors. See the Connectors guide for the full pattern.
tool('current_weather', {
description: 'Get the current temperature for a city.',
input: z.object({ city: z.string() }),
output: z.object({ temp_c: z.number() }),
fulfil: ({ input, connectors }) => connectors.weather.current({ city: input.city }),
});Resources
A resource exposes readable context at a URI. The URI can be fixed or a {var} template.
resource('changelog', {
uri: 'docs://changelog',
title: 'Changelog',
mimeType: 'text/markdown',
fulfil: () => ({
contents: [{ uri: 'docs://changelog', mimeType: 'text/markdown', text: '# Changelog\n...' }],
}),
});For a templated URI, the variable is available in the resource context:
resource('case', {
uri: 'case://{case_id}',
title: 'Support case',
fulfil: ({ input }) => ({
contents: [{ uri: `case://${input.case_id}`, mimeType: 'application/json', text: '{}' }],
}),
});Prompts
A prompt is a reusable, argument-driven template surfaced through prompts/list. Declare
arguments with a Zod object, and return messages from fulfil.
prompt('incident_update', {
title: 'Incident update',
description: 'Draft a customer-safe update from an internal case.',
arguments: z.object({
case_id: z.string(),
audience: z.enum(['customer', 'executive']).default('customer'),
}),
fulfil: () => ({
messages: [{ role: 'user', content: { type: 'text', text: 'Draft a customer-safe update...' } }],
}),
});Check your work
noodle validate # compile + schema + connector-reference checks
noodle test # loopback MCP smoke (initialize, tools/list, a tool call)noodle validate and noodle test are local and need no account. See the
Quickstart for the full loop.
Next: design them well
This page covers the mechanics. What separates a usable agentic product from an API wrapper is how you
shape these tools: task-oriented rather than endpoint-shaped, titled and annotated, with bounded
outputs and deliberate context. Read Designing tools for agents before you
add your second tool, and run noodle check to hold yourself to it.
Noodle Seed developer plugin
Install Noodle Seed in Codex, Claude Code, or Cursor, then let your coding agent build and operate MCP servers and apps on Noodle Cloud.
Designing tools for agents
What separates a usable agentic product from an API wrapper. Task-shaped tools, host-facing titles and hints, bounded outputs, a small surface, and deliberate context.