);
}
```
**Setup Requirements:**
1. Use `.tsx` file extension for React component tools
2. Install React dependencies: `npm install react react-dom`
3. Configure `tsconfig.json`:
```json
{
"compilerOptions": {
"jsx": "react-jsx"
}
}
```
## 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:
```typescript
export default async function calculate() {
return "Result: 42"; // or return 42;
}
```
### Content Array
Return an object with a `content` array for rich media responses:
```typescript
export default async function getProfile() {
return {
content: [
{
type: "text",
text: "Profile information:",
},
{
type: "image",
data: "base64encodeddata",
mimeType: "image/jpeg",
},
{
type: "resource_link",
name: "Full Profile",
uri: "resource://profile/john",
},
],
};
}
```
**Supported content types:**
* `text` - Plain text content
* `image` - Base64-encoded images with mimeType
* `audio` - Base64-encoded audio with mimeType
* `resource_link` - Links to MCP resources
### Structured Outputs
You can declare an `outputSchema` when your tool returns `structuredContent` to enforce validation:
```typescript
import { z } from "zod";
export const outputSchema = {
user: z.object({
id: z.number(),
name: z.string(),
}),
};
```
Return structured data using the `structuredContent` property:
```typescript
export default async function getUserData() {
return {
structuredContent: {
user: {
id: 123,
name: "John Doe",
},
},
};
}
```
`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`.
```typescript
export default async function getData() {
return {
content: [
{
type: "text",
text: "Data retrieved successfully",
},
],
structuredContent: {
data: { key: "value" },
},
};
}
```
## 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 `default` export 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:
```txt
[xmcp] Failed to load tool file: src/tools/draft.ts
-> File is empty.
[xmcp] 1 tool skipped due to empty files or missing default exports
```
If the file exists but does not export a default handler, startup will log:
```txt
[xmcp] Failed to load tool file: src/tools/draft.ts
-> File does not export a default tool handler.
```