@veris-ai/sdk
Version:
A TypeScript package for Veris AI tools
235 lines • 9.78 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.VerisMCPServer = void 0;
exports.createMCPServer = createMCPServer;
const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
const streamableHttp_js_1 = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
const sse_js_1 = require("@modelcontextprotocol/sdk/server/sse.js");
const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
const express_1 = __importDefault(require("express"));
const zod_1 = require("zod");
const zod_to_json_schema_1 = require("zod-to-json-schema");
const toolMock_1 = require("./toolMock");
const node_crypto_1 = require("node:crypto");
class VerisMCPServer {
server;
registeredFunctions = new Map();
name;
description;
transport;
requireAuth;
port;
app;
httpServer;
transports = {
streamable: {},
sse: {}
};
constructor(options) {
this.name = options.name;
this.description = options.description;
this.transport = options.transport || 'http';
this.requireAuth = options.requireAuth || false;
this.port = options.port;
}
createMcpServer(authInfo) {
const server = new mcp_js_1.McpServer({
name: this.name,
version: '1.0.0'
});
// Register all tools with the server using registerTool
for (const [name, registered] of this.registeredFunctions) {
const parametersSchema = registered.parametersSchema instanceof zod_1.z.ZodObject
? registered.parametersSchema.shape
: {};
server.registerTool(name, {
title: name,
description: registered.description,
inputSchema: parametersSchema,
}, async (args) => {
try {
// Set session ID from auth token if available
const token = authInfo?.token;
if (token) {
toolMock_1.veris.parseToken(token);
}
// Execute the function
const result = await registered.func(args);
// Clear session ID after execution
toolMock_1.veris.clearContext();
return {
content: [{
type: 'text',
text: typeof result === 'string' ? result : JSON.stringify(result)
}]
};
}
catch (error) {
toolMock_1.veris.clearContext();
const errorMessage = error instanceof Error ? error.message : String(error);
throw new Error(errorMessage);
}
});
}
return server;
}
registerFunction(func, options) {
this.registeredFunctions.set(options.name, {
func,
...options
});
}
getTools() {
const tools = [];
for (const [name, registered] of this.registeredFunctions) {
const inputSchema = (0, zod_to_json_schema_1.zodToJsonSchema)(registered.parametersSchema);
tools.push({
name,
description: registered.description,
inputSchema: {
type: 'object',
properties: (inputSchema.properties || {}),
required: (inputSchema.required || [])
}
});
}
return tools;
}
extractBearerToken(authHeader) {
if (!authHeader)
return null;
const parts = authHeader.split(' ');
if (parts.length === 2 && parts[0] === 'Bearer') {
return parts[1];
}
return null;
}
setupExpressApp() {
const app = (0, express_1.default)();
app.use(express_1.default.json());
if (this.transport === 'http') {
// Handle POST requests for streamable HTTP transport
app.post('/mcp', async (req, res) => {
const sessionId = req.headers['mcp-session-id'];
const authHeader = req.headers.authorization;
let transport;
// Extract bearer token for session ID if present
const bearerToken = this.extractBearerToken(authHeader);
if (sessionId && this.transports.streamable[sessionId]) {
transport = this.transports.streamable[sessionId];
}
else if (!sessionId && (0, types_js_1.isInitializeRequest)(req.body)) {
transport = new streamableHttp_js_1.StreamableHTTPServerTransport({
sessionIdGenerator: () => (0, node_crypto_1.randomUUID)(),
onsessioninitialized: (sessionId) => {
this.transports.streamable[sessionId] = transport;
}
});
transport.onclose = () => {
if (transport.sessionId) {
delete this.transports.streamable[transport.sessionId];
}
};
// Create MCP server with auth info if bearer token present
const authInfo = bearerToken ? { token: bearerToken } : undefined;
const server = this.createMcpServer(authInfo);
await server.connect(transport);
}
else {
res.status(400).json({
jsonrpc: '2.0',
error: {
code: -32000,
message: 'Bad Request: No valid session ID provided',
},
id: null,
});
return;
}
await transport.handleRequest(req, res, req.body);
});
// Handle GET and DELETE requests for session management
const handleSessionRequest = async (req, res) => {
const sessionId = req.headers['mcp-session-id'];
if (!sessionId || !this.transports.streamable[sessionId]) {
res.status(400).send('Invalid or missing session ID');
return;
}
const transport = this.transports.streamable[sessionId];
await transport.handleRequest(req, res);
};
app.get('/mcp', handleSessionRequest);
app.delete('/mcp', handleSessionRequest);
}
else if (this.transport === 'sse') {
// SSE transport setup with custom auth middleware
const sseMiddleware = (req, res, next) => {
const token = this.extractBearerToken(req.headers.authorization);
if (this.requireAuth && !token) {
return res.status(401).json({ error: 'Unauthorized' });
}
if (token) {
req.authInfo = { token };
}
next();
};
app.get('/sse', sseMiddleware, async (req, res) => {
// Create SSE transport
const transport = new sse_js_1.SSEServerTransport('/messages', res);
this.transports.sse[transport.sessionId] = transport;
res.on('close', () => {
delete this.transports.sse[transport.sessionId];
});
// Create MCP server with auth info
const authInfo = req.authInfo;
const server = this.createMcpServer(authInfo);
await server.connect(transport);
});
// Handle messages for SSE transport
app.post('/messages', sseMiddleware, async (req, res) => {
const sessionId = req.query.sessionId;
const transport = this.transports.sse[sessionId];
if (transport) {
await transport.handlePostMessage(req, res, req.body);
}
else {
res.status(400).send('No transport found for sessionId');
}
});
}
return app;
}
async listen(port) {
if (this.transport === 'stdio') {
// For stdio transport, use the standard MCP SDK transport
const transport = new stdio_js_1.StdioServerTransport();
const server = this.createMcpServer();
await server.connect(transport);
return {}; // Return dummy server for consistency
}
// For HTTP/SSE transport, use Express
this.app = this.setupExpressApp();
this.httpServer = this.app.listen(port);
console.log(`${this.name} MCP server listening on port ${port} (${this.transport} transport)`);
return this.httpServer;
}
async start() {
if (!this.port) {
throw new Error('Port must be specified for standalone server');
}
return this.listen(this.port);
}
static createStandalone(options) {
return new VerisMCPServer(options);
}
}
exports.VerisMCPServer = VerisMCPServer;
// Export a function to create and configure an MCP server with decorated functions
function createMCPServer(options) {
return new VerisMCPServer(options);
}
//# sourceMappingURL=mcpServer.js.map