@purinton/mcp-server 


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.
Table of Contents
Features
- 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
Installation
npm install @purinton/mcp-server
Usage
ESM Example
// 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';
// },
// context: { example: 'context' } // Optional context to pass to tools _extra (db, redis, etc.)
});
console.log('MCP Server started!');
})();
CommonJS Example
// 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';
// },
// context: { example: 'context' } // Optional context to pass to tools _extra (db, redis, etc.)
});
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.
Custom Tool Example (ESM)
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);
}
);
}
Custom Tool Example (CommonJS)
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);
}
);
};
API
async mcpServer(options): Promise<{ app, httpInstance, mcpServer, transport }>``
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 servercontext
(optional): Context object to attach to the MCP server and pass to tools (e.g. database, redis, etc.)
Returns an object with:
app
: Express application instancehttpInstance
: HTTP server instancemcpServer
: MCP server instancetransport
: HTTP transport instance
convertBigIntToString(value)
Recursively converts all BigInt values in an object to strings.
buildResponse(data)
Wraps a plain JS object into the standard tool response payload.
z
Re-exports zod for schema validation.
TypeScript
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;
context?: any;
}
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 };
Support
For help, questions, or to chat with the author and community, visit: