Skip to main content
Glama

OneTech MCP Server

by jordnlvr
index.ts•7.21 kB
#!/usr/bin/env node /** * OneTech MCP Server * Extract and document Mendix Studio Pro modules via Model Context Protocol */ import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js"; import { execFile } from "child_process"; import { promisify } from "util"; import { readFile, access, mkdir } from "fs/promises"; import { resolve, join, dirname } from "path"; import { fileURLToPath } from "url"; import { constants } from "fs"; const execFileAsync = promisify(execFile); // Get __dirname equivalent in ESM const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); /** * Server configuration */ const SERVER_CONFIG = { name: "onetech-mcp-server", version: "0.1.0", description: "OneTech MCP Server - Extract and document Mendix Studio Pro modules", }; /** * Default mx.exe path (Studio Pro 11.3.0) */ const DEFAULT_MX_PATH = "D:\\Program Files\\Mendix\\11.3.0.80734\\modeler\\mx.exe"; /** * Validates that a file exists and is accessible */ async function validateFileExists(filePath: string, description: string): Promise<void> { try { await access(filePath, constants.R_OK); } catch (error) { throw new Error(`${description} not found or not accessible: ${filePath}`); } } /** * Validates that mx.exe exists at the specified path */ async function validateMxExe(mxPath: string): Promise<void> { await validateFileExists(mxPath, "mx.exe"); } /** * Validates that the .mpr file exists */ async function validateMprFile(mprPath: string): Promise<void> { await validateFileExists(mprPath, "MPR file"); } /** * Ensures output directory exists */ async function ensureOutputDir(outputPath: string): Promise<void> { try { await mkdir(outputPath, { recursive: true }); } catch (error) { throw new Error(`Failed to create output directory: ${outputPath}`); } } /** * Runs mx.exe command and returns result */ async function runMxCommand(mxPath: string, args: string[]): Promise<{ stdout: string; stderr: string }> { try { const result = await execFileAsync(mxPath, args, { maxBuffer: 50 * 1024 * 1024, // 50MB buffer for large JSON outputs timeout: 300000, // 5 minute timeout }); return result; } catch (error: any) { throw new Error(`mx.exe execution failed: ${error.message}`); } } /** * Extracts module documentation using mx.exe dump-mpr commands */ async function extractModule( mprPath: string, moduleName: string, outputPath: string, mxPath: string = DEFAULT_MX_PATH ): Promise<{ success: boolean; files: Array<{ name: string; size: number }>; message: string; }> { // Validate inputs await validateMxExe(mxPath); await validateMprFile(mprPath); await ensureOutputDir(outputPath); const files: Array<{ name: string; size: number }> = []; const errors: string[] = []; // Define the 4 mx.exe commands to extract module data const commands = [ { name: "DomainModel", unitType: "DomainModels$DomainModel", outputFile: join(outputPath, `${moduleName}-DomainModel.json`), }, { name: "Pages", unitType: "Pages$Page", outputFile: join(outputPath, `${moduleName}-Pages.json`), }, { name: "Microflows", unitType: "Microflows$Microflow", outputFile: join(outputPath, `${moduleName}-Microflows.json`), }, { name: "Enumerations", unitType: "Enumerations$Enumeration", outputFile: join(outputPath, `${moduleName}-Enumerations.json`), }, ]; // Execute each command sequentially for (const cmd of commands) { try { const args = ["dump-mpr", "--unit-type", cmd.unitType, "--module-names", moduleName, "--output-file", cmd.outputFile, mprPath]; await runMxCommand(mxPath, args); // Verify file was created and get size let fileContent = await readFile(cmd.outputFile, "utf-8"); // Remove UTF-8 BOM if present (mx.exe outputs BOM) if (fileContent.charCodeAt(0) === 0xfeff) { fileContent = fileContent.substring(1); } files.push({ name: `${cmd.name}.json`, size: Buffer.byteLength(fileContent, "utf-8"), }); } catch (error: any) { errors.push(`${cmd.name}: ${error.message}`); } } // Return results if (files.length === 0) { return { success: false, files: [], message: `Failed to extract module. Errors: ${errors.join(", ")}`, }; } if (errors.length > 0) { return { success: true, files, message: `Extracted ${files.length}/4 files successfully. Partial errors: ${errors.join(", ")}`, }; } return { success: true, files, message: `Successfully extracted ${files.length} files from module '${moduleName}'`, }; } /** * Main server initialization */ async function main() { const server = new Server( { name: SERVER_CONFIG.name, version: SERVER_CONFIG.version, }, { capabilities: { tools: {}, }, } ); /** * Handler: List available tools */ server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ { name: "onetech_extract_module", description: "Extract domain model, pages, microflows, and enumerations from a Mendix module using mx.exe. Returns JSON files with complete module structure.", inputSchema: { type: "object", properties: { mprPath: { type: "string", description: "Absolute path to the .mpr file (e.g., D:\\Projects\\OneTech.mpr)", }, moduleName: { type: "string", description: "Name of the module to extract (e.g., RequestHub)", }, outputPath: { type: "string", description: "Absolute path to output directory for JSON files", }, mxPath: { type: "string", description: `Optional: Path to mx.exe (default: ${DEFAULT_MX_PATH})`, }, }, required: ["mprPath", "moduleName", "outputPath"], }, }, ], }; }); /** * Handler: Execute tool */ server.setRequestHandler(CallToolRequestSchema, async (request) => { if (request.params.name === "onetech_extract_module") { const { mprPath, moduleName, outputPath, mxPath } = request.params.arguments as { mprPath: string; moduleName: string; outputPath: string; mxPath?: string; }; try { const result = await extractModule(mprPath, moduleName, outputPath, mxPath || DEFAULT_MX_PATH); return { content: [ { type: "text", text: JSON.stringify(result, null, 2), }, ], }; } catch (error: any) { return { content: [ { type: "text", text: JSON.stringify( { success: false, files: [], message: `Error: ${error.message}`, }, null, 2 ), }, ], isError: true, }; } } throw new Error(`Unknown tool: ${request.params.name}`); }); // Start server const transport = new StdioServerTransport(); await server.connect(transport); console.error("OneTech MCP Server running on stdio"); } // Run server main().catch((error) => { console.error("Fatal error:", error); process.exit(1); });

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/jordnlvr/onetech-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server