A Node.js server for the Model Context Protocol (MCP) with dynamic tool loading, HTTP API, and authentication. Easily extendable with custom tools for AI and automation workflows. Supports both CommonJS and ESM.
- Model Context Protocol (MCP) server implementation for Node.js
- Dynamic tool loading from a directory (
tools/
)- Loads
.mjs
files in ESM mode,.cjs
files in CommonJS mode
- Loads
- HTTP API with authentication (Bearer token or custom async callback)
- Express-based, easy to extend
- Utility helpers for tool responses and BigInt-safe serialization
- TypeScript type definitions included
- Supports both CommonJS and ESM usage
npm install @purinton/mcp-server
// Example for ESM (module JS) usage
import { mcpServer } from '@purinton/mcp-server';
(async () => {
const { app, httpInstance } = await mcpServer({
// port: 1234, // You can change the port as needed
// authToken: 'your-secret-token', // You can still use this for static token auth
// toolsDir: './tools', // Path to your tools directory
// name: 'Example MCP Server', // Set your server name
// version: '1.0.0', // Set your server version
// // Example: custom async auth callback
// authCallback: async (token) => {
// // Replace with your own logic, e.g. check token in DB or against a list
// return token === 'your-secret-token';
// }
});
console.log('MCP Server started!');
})();
// Example for CommonJS usage
const { mcpServer } = require('@purinton/mcp-server');
(async () => {
const { app, httpInstance } = await mcpServer({
// port: 1234, // You can change the port as needed
// authToken: 'your-secret-token', // You can still use this for static token auth
// toolsDir: './tools', // Path to your tools directory
// name: 'Example MCP Server', // Set your server name
// version: '1.0.0', // Set your server version
// // Example: custom async auth callback
// authCallback: async (token) => {
// // Replace with your own logic, e.g. check token in DB or against a list
// return token === 'your-secret-token';
// }
});
console.log('MCP Server started!');
})();
Note:
- In ESM mode, tools must be
.mjs
files and use the ESM export signature.- In CommonJS mode, tools must be
.cjs
files and use the CommonJS export signature.
To add your own tool for ESM, create a file in the tools/
directory (e.g., tools/echo.mjs
):
import { z, buildResponse } from '@purinton/mcp-server';
export default async function ({ mcpServer, toolName, log }) {
mcpServer.tool(
toolName,
"Echo Tool",
{ echoText: z.string() },
async (_args, _extra) => {
log.debug(`${toolName} Request`, { _args });
const response = {
message: "echo-reply",
data: {
text: _args.echoText
}
};
log.debug(`${toolName} Response`, { response });
return buildResponse(response);
}
);
}
To add your own tool for CommonJS, create a file in the tools/
directory (e.g., tools/echo.cjs
):
const { z, buildResponse } = require('@purinton/mcp-server');
module.exports = async function ({ mcpServer, toolName, log }) {
mcpServer.tool(
toolName,
"Echo Tool",
{ echoText: z.string() },
async (_args, _extra) => {
log.debug(`${toolName} Request`, { _args });
const response = {
message: "echo-reply",
data: {
text: _args.echoText
}
};
log.debug(`${toolName} Response`, { response });
return buildResponse(response);
}
);
};
Starts the MCP + HTTP server. Options:
log
(optional): Logger instance (default: @purinton/log)toolsDir
(optional): Path to tools directory (default:./tools
relative to the entry file)port
(optional): Port for HTTP server (default: 1234 orprocess.env.MCP_PORT
)authToken
(optional): Bearer token for authentication (default:process.env.MCP_TOKEN
)authCallback
(optional): Custom async callback for authentication. Receives(token)
and returnstrue
/false
or a Promise.name
(optional): Name for the MCP serverversion
(optional): Version for the MCP server
Returns an object with:
app
: Express application instancehttpInstance
: HTTP server instancemcpServer
: MCP server instancetransport
: HTTP transport instance
Recursively converts all BigInt values in an object to strings.
Wraps a plain JS object into the standard tool response payload.
Re-exports zod for schema validation.
Type definitions are included:
export interface McpServerOptions {
log?: any;
toolsDir?: string;
port?: number | string;
authToken?: string;
authCallback?: (token?: string) => boolean | Promise<boolean>;
name?: string;
version?: string;
}
export interface McpServerResult {
app: import('express').Application;
httpInstance: import('http').Server;
mcpServer: any;
transport: any;
}
export function mcpServer(options?: McpServerOptions): Promise<McpServerResult>;
export function convertBigIntToString(value: any): any;
export function buildResponse(data: any): { content: { type: 'text'; text: string }[] };
export { z };
For help, questions, or to chat with the author and community, visit: