π§© Extendable MCP Framework
ext-mcp introduces two core concepts: middleware and mods.
- Middleware: carries shared capabilities and follows an onion-style execution model.
- Mods: extends functionality; a mod is a collection of MCP features β features here refer to tool/prompt/resource in the MCP protocol.
βββββββββββββββββββββββββββ
β LLM Request β
βββββββββββββββββββββββββββ
β
βββββββββββββββ
β middleware1 β
βββββββββββββββ
β
βββββββββββββββ
β middleware2 β
βββββββββββββββ
β
βββββββββββββββββββββββββββββ
β mods β
β βββββββ βββββββ βββββββ β
β βmod1 β βmod2 β βmod3 β β
β βββββββ βββββββ βββββββ β
βββββββββββββββββββββββββββββ
β
βββββββββββββββ
β middleware2 β
βββββββββββββββ
β
βββββββββββββββ
β middleware1 β
βββββββββββββββ
π° See the complete example in the demo directory
npm i ext-mcpimport path from "path";
import XMCP from "ext-mcp";
import errorHandler from "./middlewares/error-handler";
import sayGoodbye from "./mods/say-goodbye";
const app = new XMCP({
name: "my-mcp",
version: "0.0.1",
});
// ποΈ Middleware
app.use(path.join(__dirname, "./middlewares/logger")); // file path
app.use(errorHandler); // function
app.use(require.resolve('@foo/mcp-middleware-logger')); // npm/workspace package
// π§© Mods
app.installMod(path.join(__dirname, "./mods/say-hello")); // file path
app.installMod(sayGoodbye); // function
app.installMod(require.resolve('@foo/mcp-mod-demo')); // npm/workspace package
// Start the service. Currently only stdio mode is supported
app.start();Example: implement a logger middleware that injects
logIdandloggerinto the context
import { type Middleware } from "ext-mcp";
export interface LoggerContext {
logId: string;
logger: {
info: (message: string) => void;
error: (message: string) => void;
};
}
const middleware: Middleware<LoggerContext> = async (context, next) => {
context.logId = `foo-log-id`;
context.logger = createLogger(context.logId);
context.logger.info(`mcp started: ${context.actionName}`);
const res = await next();
context.logger.info(`mcp finished: ${context.actionName}`);
return res;
};
export default middleware;import type { Mod, Tool } from "ext-mcp";
import { z } from "zod/v3";
const sayHello: Tool<{ name: z.ZodString }> = {
name: "say-hello",
config: {
title: "Say hello",
description: "Used for MCP mod demo",
inputSchema: { name: z.string().describe("user's name") },
},
handler: (context) => {
const { name } = context.args;
return {
content: [
{
type: "text",
text: `Hello, ${name}!`,
},
],
};
},
};
const demoMod: Mod = {
name: "demo-mod",
version: "0.0.1",
description: "Demo mod",
tools: [sayHello],
};
export default demoMod;Core source is in the src folder; the demo lives under demo.
# Install dependencies
npm install
# Build
npm run build
# Test
npm test# Start the inspector. @see https://github.com/modelcontextprotocol/inspector
npx @modelcontextprotocol/inspectorAfter the inspector starts, paste the absolute path to demo/run.sh into the Command field to begin debugging.
This repository includes configuration for several IDEs to view the demo directly: