xmcp: Model Context Protocol Framework
xmcp is a TypeScript-first framework designed for building and deploying Model Context Protocol (MCP) servers. It aims to simplify the development experience for creating powerful tools within the MCP ecosystem, providing features like file system routing for automatic tool and prompt registration, hot reloading for rapid development, and a robust middleware system for authentication and custom logic. Currently at version 0.6.7, the project maintains an active development pace with frequent minor and patch releases (often weekly or bi-weekly), incorporating new features, security updates, and performance improvements. Key differentiators include its focus on developer experience, support for various deployment targets like Vercel and Cloudflare, and an 'elicit' mechanism within tool handlers for requesting structured user input.
Common errors
-
Error: Cannot find module 'react' or 'zod'
cause A peer dependency (e.g., React or Zod) is missing or has a version incompatible with xmcp's requirements.fixInstall the required peer dependencies with `npm install react react-dom zod` and ensure their versions satisfy xmcp's peer dependency ranges (e.g., `react@'>=19.0.0'`, `zod@'^3.25.76 || ^4.0.0'`). -
TypeError: Cannot read properties of undefined (reading 'elicit')
cause The `extra` object, which contains the `elicit` function, was not correctly destructured or provided to the tool handler, or the handler signature is incorrect.fixEnsure your tool handler function is defined as `export default async function (_args, extra: ToolHandlerContext) { ... }` and that `extra` is correctly named and typed. -
Error: Tool file 'src/tools/my-tool.ts' must have a default export.
cause xmcp's file system routing requires each tool file to have a default export, which is treated as the tool handler function.fixAdd `export default async function (...) { ... }` to your tool file, ensuring it exports a valid asynchronous function. -
Deployment cancelled or not confirmed.
cause The `elicit` function was invoked, but the user either explicitly declined the prompt (`result.action !== 'accept'`) or did not provide the necessary confirmations based on the `requestedSchema`.fixThis is expected behavior. When using `extra.elicit()`, always check `result.action` and `result.content` to handle user cancellations or incomplete input gracefully. Provide clear feedback to the user on why an action was not taken.
Warnings
- breaking The experimental OAuth configuration and proxy were removed in version 0.6.0. Projects relying on these features will require refactoring to use alternative authentication plugins (e.g., Auth0, WorkOS, Clerk) or custom middleware.
- breaking As of v0.6.0, the `resource` parameter for the OAuth authorization server changed from `baseurl` to `audience`. This change affects how OAuth clients should be configured.
- gotcha xmcp relies on peer dependencies `react`, `react-dom` (both `>=19.0.0`), and `zod` (`^3.25.76 || ^4.0.0`). Mismatched versions can lead to runtime errors or unexpected behavior.
- gotcha Prior to v0.6.7, error handling for empty or malformed tool files was less robust, potentially leading to crashes or silent failures during server startup or tool invocation.
- breaking Multiple security updates were released across versions 0.6.2 and 0.6.5. Running older versions exposes projects to known vulnerabilities.
Install
-
npm install xmcp -
yarn add xmcp -
pnpm add xmcp
Imports
- defineConfig
const { defineConfig } = require('xmcp')import { defineConfig } from 'xmcp' - ToolHandlerContext
import { ToolHandlerContext } from 'xmcp'import { type ToolHandlerContext } from 'xmcp' - elicit
import { elicit } from 'xmcp'const result = await extra.elicit({...});
Quickstart
// First, initialize a new xmcp project:
// npx create-xmcp-app@latest my-xmcp-app
// cd my-xmcp-app
// Then, create a tool file within your project, for example, at src/tools/deploy.ts.
// xmcp automatically registers tools based on file system routing.
import { type ToolHandlerContext } from 'xmcp';
export default async function (
_args: Record<string, any>, // Arguments received by the tool
extra: ToolHandlerContext // Context object providing utilities
) {
console.log("Deployment tool invoked. Awaiting user input...");
const result = await extra.elicit({
message: "Please choose deployment parameters:",
requestedSchema: {
type: "object",
properties: {
environment: {
type: "string",
title: "Deployment Environment",
enum: ["staging", "production"],
description: "Target environment for deployment."
},
confirmAction: {
type: "boolean",
title: "Confirm Deployment",
description: "Are you sure you want to proceed with deployment?",
default: false
}
},
required: ["environment", "confirmAction"],
},
});
if (result.action !== "accept" || !result.content || !result.content.confirmAction) {
return "Deployment action cancelled or not confirmed by the user.";
}
const { environment } = result.content;
console.log(`Initiating deployment to ${environment}...`);
// In a real application, replace this with actual deployment logic
await new Promise(resolve => setTimeout(resolve, 3000)); // Simulate work
return `Deployment to ${environment} completed successfully!`;
}
// To run this tool, start your xmcp development server (e.g., `npm run dev`).
// Then, interact with your MCP server via a compatible client or interface
// to invoke the 'deploy' tool, which will trigger the elicitation flow.