Tools
Tools are functions that your LLM can actively call and decides when to use based on user requests. They enable AI models to perform actions such as writing to databases, calling external APIs, modifying files, or triggering other logic.
By default, xmcp detects files under the /src/tools/ directory and registers them as tools, but you can specify a custom directory if you prefer. The directory to use can be configured in the xmcp.config.ts file.
A tool file consists of three main exports:
- Default: The tool handler function.
- Schema (optional): The input parameters using Zod schemas.
- Metadata (optional): The tool's identity and behavior hints. If omitted, the name is inferred from the file name and the description defaults to a placeholder.
If you're returning a string or number only, you can shortcut the return value to be the string or number directly.
We encourage to use this shortcut for readability, and restrict the usage of the content array type only for complex responses, like images, audio or videos.
Schema Definition
The schema defines your tool's input parameters using Zod. Use .describe() on each parameter to help LLMs understand how to use your tool correctly.
Type Inference
The InferSchema utility automatically infers TypeScript types from your Zod schema, giving you full type safety without manual type definitions:
Clear descriptions are crucial for LLM tool discovery. For comprehensive Zod validation options (regex patterns, constraints, transformations), see the Zod documentation.
Metadata
The metadata export defines your tool's identity and provides behavioral hints to LLMs and clients.
Core Properties
name (required)
- Unique identifier for the tool
- Defaults to the filename if not provided
- Use kebab-case (e.g.,
get-user-profile)
description (required)
- Clear explanation of what the tool does
- Defaults to placeholder if not provided
- Critical for LLM tool discovery and selection
Annotations
Behavioral hints that help LLMs and UIs understand how to use your tool:
These hints are advisory only. LLMs may use them to make better decisions about when and how to call your tools, but they don't enforce any behavior.
MCP Apps metadata
MCP Apps widgets work automatically for React tools. Add ui metadata only
when you need CSP or rendering hints.
Resource-specific properties:
csp.connectDomains- Origins for fetch/XHR/WebSocket connectionscsp.resourceDomains- Origins for images, scripts, stylesheets, fonts, mediadomain- Optional dedicated subdomain for the widget's sandbox originprefersBorder- Request visible border + background (true/false/omitted)
Handler Types
Tools support three types of handlers, each suited for different use cases:
| Type | Best For | Returns |
|---|---|---|
| Standard | Data queries, calculations, API calls | Unstructured or structured content |
| Template Literal | Simple widgets with external scripts | HTML string |
| React Component | Interactive, stateful widgets | React component |
1. Standard Handlers
Standard handlers are functions that return text, structured content, or simple data. This is the default approach for most tools.
When to use:
- Performing calculations or data transformations
- Calling external APIs and returning results
- Querying databases
- Any task that returns text or structured data without UI interaction
Elicitation
Tool handlers also receive an extra argument. Use extra.elicit() when you want the client to collect a small piece of user input before the tool continues.
When the client sends an MCP initialize request, extra.clientInfo is available with protocol-level client identity (name, version, and optional fields like title). This is available for HTTP transports and stdio (after initialization completes).
Quick check with MCPJam
- From the repo root, run
pnpm --dir examples/http-transport dev. - In another terminal, run
npx @mcpjam/inspector@latest. - Connect MCPJam to
http://127.0.0.1:3001/mcp. - Call
preview-elicitation. - MCPJam opens a small form with an environment select. Accepting returns
action: "accept"pluscontent.environment. Cancel or decline returns the matchingaction.
2. Template Literal Handlers
Return HTML directly to create interactive widgets. xmcp automatically generates the widget resource.
3. React Component Handlers
Return React components for interactive, composable widgets. xmcp renders the component to HTML and generates a widget resource automatically.
Setup Requirements:
- Use
.tsxfile extension for React component tools - Install React dependencies:
npm install react react-dom - Configure
tsconfig.json:
Return Values
Tools support multiple return formats depending on your needs:
Simple Values
Return strings or numbers directly - xmcp automatically wraps them in the proper format:
Content Array
Return an object with a content array for rich media responses:
Supported content types:
text- Plain text contentimage- Base64-encoded images with mimeTypeaudio- Base64-encoded audio with mimeTyperesource_link- Links to MCP resources
Structured Outputs
You can declare an outputSchema when your tool returns structuredContent to enforce validation:
Return structured data using the structuredContent property:
structuredContent works without declaring outputSchema.
If outputSchema is declared and structuredContent is returned, structuredContent must conform to it.
If your handler returns a primitive (string or number) and outputSchema has exactly one field that accepts it, xmcp auto-injects it into structuredContent using that field.
Undeclared keys are rejected when validating structuredContent against outputSchema.
You can also return a plain object directly (for example return content) and xmcp will treat it as structuredContent when outputSchema is declared.
When structuredContent is returned without content, xmcp auto-generates a text fallback (JSON.stringify(structuredContent)) for compatibility with clients that only render content.
Combined Response
Return both content and structuredContent for backwards compatibility. If the client cannot process structured outputs, it will fallback to content.
Troubleshooting
Tool Loading Errors
When xmcp starts, it loads every file under your tools directory.
- Empty tool files are skipped with a friendly warning
- Files without a
defaultexport are skipped with a friendly warning - Real syntax or import errors still fail normally so you can see the full stack trace
For example, if src/tools/draft.ts is empty, startup will log:
If the file exists but does not export a default handler, startup will log:
Friendly handling is intentionally limited to empty files and missing default exports. Invalid implementations and real import/syntax errors still surface as normal runtime errors.
CLI Scaffolding
You can use the CLI to scaffold tools, resources, and prompts.
Create a tool
Create a resource
Create a prompt
Output
Each command creates a starter file in the default directory for that primitive:
xmcp create tool my-tool→src/tools/my-tool.tsxmcp create resource my-resource→src/resources/my-resource.tsxmcp create prompt my-prompt→src/prompts/my-prompt.ts
The generated file already includes the basic exports you need to continue:
- tools:
schema,metadata, and a default function - resources:
metadataand a default function - prompts:
schema,metadata, and a default function
So instead of starting from an empty file, you get a ready-to-edit template with placeholder descriptions and example return values.