il2cpp-dump-analyzer-mcp
Version:
Agentic RAG system for analyzing IL2CPP dump.cs files from Unity games
475 lines • 20 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Logger = exports.Document = exports.IL2CPPVectorStore = void 0;
exports.initializeServer = initializeServer;
exports.initializeVectorStore = initializeVectorStore;
exports.startMcpStdioServer = startMcpStdioServer;
exports.startMcpServerWithTransport = startMcpServerWithTransport;
exports.startMcpServer = startMcpServer;
exports.startMcpServerStdio = startMcpServerStdio;
exports.getServerStatus = getServerStatus;
exports.shutdown = shutdown;
const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
const path_1 = __importDefault(require("path"));
// Import transport infrastructure
const transport_1 = require("../transport");
// Import IL2CPP components
const indexer_1 = require("../indexer/indexer");
const vector_store_1 = require("../embeddings/vector-store");
Object.defineProperty(exports, "IL2CPPVectorStore", { enumerable: true, get: function () { return vector_store_1.IL2CPPVectorStore; } });
const documents_1 = require("@langchain/core/documents");
Object.defineProperty(exports, "Document", { enumerable: true, get: function () { return documents_1.Document; } });
// Import error types
const error_types_1 = require("./error-types");
// ============================================================================
// GLOBAL STATE MANAGEMENT
// ============================================================================
// Global vector store instance
let vectorStore = null;
// Server configuration
let serverConfig = {};
// Initialization state
let isInitialized = false;
// Logging configuration
let logLevel = process.env.LOG_LEVEL || 'info';
// Add global error handlers to prevent crashes
process.on('uncaughtException', (error) => {
console.error('[FATAL] Uncaught Exception:', error);
console.error('Stack:', error.stack);
});
process.on('unhandledRejection', (reason, promise) => {
console.error('[FATAL] Unhandled Rejection at:', promise, 'reason:', reason);
});
// ============================================================================
// UTILITY FUNCTIONS
// ============================================================================
/**
* Safely stringify JSON with error handling
*/
function safeJsonStringify(obj, space) {
try {
return JSON.stringify(obj, null, space);
}
catch (error) {
Logger.error('JSON stringify error:', error);
return JSON.stringify({
error: 'Failed to serialize response',
message: error instanceof Error ? error.message : 'Unknown serialization error'
}, null, space);
}
}
// ============================================================================
// LOGGING UTILITIES
// ============================================================================
/**
* Enhanced logging utility
*/
class Logger {
static shouldLog(level) {
const levels = ['debug', 'info', 'warn', 'error'];
const currentLevelIndex = levels.indexOf(logLevel);
const messageLevelIndex = levels.indexOf(level);
return messageLevelIndex >= currentLevelIndex;
}
static debug(message, ...args) {
if (this.shouldLog('debug')) {
console.debug(`[DEBUG] ${new Date().toISOString()} - ${message}`, ...args);
}
}
static info(message, ...args) {
if (this.shouldLog('info')) {
console.info(`[INFO] ${new Date().toISOString()} - ${message}`, ...args);
}
}
static warn(message, ...args) {
if (this.shouldLog('warn')) {
console.warn(`[WARN] ${new Date().toISOString()} - ${message}`, ...args);
}
}
static error(message, error) {
if (this.shouldLog('error')) {
console.error(`[ERROR] ${new Date().toISOString()} - ${message}`, error);
}
}
}
exports.Logger = Logger;
// ============================================================================
// INITIALIZATION FUNCTIONS
// ============================================================================
/**
* Initialize the MCP server with comprehensive setup
* @param options Configuration options
*/
async function initializeServer(options = {}) {
try {
Logger.info('Starting MCP server initialization...');
// Store configuration
const nodeEnv = process.env.NODE_ENV;
const environment = nodeEnv === 'development' || nodeEnv === 'test' ? nodeEnv : 'production';
serverConfig = {
environment,
enableCaching: true,
logLevel: 'info',
chunkSize: 1000,
chunkOverlap: 200,
...options
};
// Set log level
if (serverConfig.logLevel) {
logLevel = serverConfig.logLevel;
}
Logger.debug('Server configuration:', serverConfig);
// Determine dump file path
let dumpFilePath = serverConfig.dumpFilePath;
if (!dumpFilePath) {
const currentDir = __dirname;
const projectRoot = path_1.default.resolve(currentDir, '..', '..');
dumpFilePath = path_1.default.join(projectRoot, 'dump.cs');
}
Logger.info(`Loading dump file from: ${dumpFilePath}`);
// Progress callback wrapper
const progressCallback = serverConfig.progressCallback || ((progress, message) => {
Logger.info(`Progress: ${progress}% - ${message}`);
});
progressCallback(10, 'Initializing IL2CPP indexer...');
// Create and initialize the indexer with enhanced parser
const indexer = new indexer_1.IL2CPPIndexer(serverConfig.chunkSize, serverConfig.chunkOverlap, serverConfig.model, serverConfig.hashFilePath);
progressCallback(20, 'Loading and parsing dump file...');
// Index the dump file
Logger.info('Indexing dump file...');
vectorStore = await indexer.indexFile(dumpFilePath, progressCallback, serverConfig.forceReprocess);
progressCallback(100, 'Initialization complete');
Logger.info('Indexing complete');
// Mark as initialized
isInitialized = true;
Logger.info('MCP server initialization completed successfully');
}
catch (error) {
const errorMessage = `Failed to initialize MCP server: ${error instanceof Error ? error.message : 'Unknown error'}`;
Logger.error(errorMessage, error);
throw new error_types_1.MCPServerError(errorMessage, error_types_1.ErrorType.INITIALIZATION_ERROR);
}
}
/**
* Initialize the MCP server with a pre-existing vector store (backward compatibility)
* @param store Vector store instance
*/
function initializeVectorStore(store) {
Logger.info('Initializing MCP server with existing vector store');
vectorStore = store;
isInitialized = true;
Logger.info('Vector store initialization completed');
}
/**
* Check if the server is properly initialized
*/
function ensureInitialized() {
if (!isInitialized || !vectorStore) {
throw new error_types_1.MCPServerError('MCP server not initialized. Call initializeServer() first.', error_types_1.ErrorType.INITIALIZATION_ERROR);
}
}
// ============================================================================
// MCP SERVER FACTORY
// ============================================================================
/**
* Create and configure the MCP server with all tools and resources
* @returns Configured MCP server
*/
function createMcpServer() {
Logger.debug('Creating MCP server instance');
// Create an MCP server with enhanced metadata
const server = new mcp_js_1.McpServer({
name: "IL2CPP Dump Analyzer",
version: "1.0.0",
description: "A specialized RAG system for analyzing IL2CPP dump.cs files from Unity games",
metadata: {
capabilities: [
"Unity IL2CPP dump analysis",
"MonoBehaviour discovery",
"Class hierarchy analysis",
"Method signature lookup",
"Enum value retrieval",
"Advanced filtering and search",
"Dependency mapping and analysis",
"Cross-reference analysis",
"Design pattern detection and analysis",
"C# class wrapper generation",
"Method stub generation",
"Unity MonoBehaviour template generation",
"IL2CPP metadata extraction and analysis"
],
supportedGameEngines: ["Unity"],
supportedLanguages: ["C#"],
author: "IL2CPP Dump Analyzer Team",
version: "1.0.0",
protocol: "MCP",
features: {
stdio_transport: true,
http_transport: true,
sse_transport: true,
network_transport: true,
resource_templates: true,
advanced_tools: true,
remote_access: true,
authentication: true,
rate_limiting: true
}
}
});
// Register resources
registerResources(server);
// Register tools
registerTools(server);
Logger.debug('MCP server created successfully');
return server;
}
// ============================================================================
// RESOURCE HANDLERS
// ============================================================================
/**
* Register all resource handlers
*/
function registerResources(server) {
Logger.debug('Registering resource handlers');
// Enhanced IL2CPP code search resource
server.resource("il2cpp-code", new mcp_js_1.ResourceTemplate("il2cpp://{query}", {
list: async () => {
// Return some example resources that clients can discover
return {
resources: [
{
uri: "il2cpp://MonoBehaviour",
name: "MonoBehaviour Classes",
description: "Search for MonoBehaviour classes"
},
{
uri: "il2cpp://Player",
name: "Player Classes",
description: "Search for Player-related classes"
},
{
uri: "il2cpp://GameObject",
name: "GameObject Classes",
description: "Search for GameObject-related classes"
},
{
uri: "il2cpp://WildMapPokemon",
name: "WildMapPokemon Classes",
description: "Search for WildMapPokemon-related classes"
}
]
};
}
}), async (uri, { query }) => {
try {
ensureInitialized();
Logger.debug(`Resource request for il2cpp-code: ${uri.href}`);
// Extract options from query parameters
const url = new URL(uri.href);
const topK = parseInt(url.searchParams.get('top_k') || '5');
const filterType = url.searchParams.get('filter_type');
const filterNamespace = url.searchParams.get('filter_namespace');
const filterMonoBehaviour = url.searchParams.get('filter_monobehaviour') === 'true';
// Build filter
const filter = {};
if (filterType)
filter.type = filterType;
if (filterNamespace)
filter.namespace = filterNamespace;
if (filterMonoBehaviour)
filter.isMonoBehaviour = true;
// Ensure query is a string (not an array)
const queryString = Array.isArray(query) ? query[0] : query;
Logger.debug(`Searching with query: "${queryString}", filter:`, filter, `top_k: ${topK}`);
// Perform search
let results;
if (Object.keys(filter).length > 0) {
results = await vectorStore.searchWithFilter(queryString, filter, topK);
}
else {
results = await vectorStore.similaritySearch(queryString, topK);
}
Logger.debug(`Found ${results.length} results for resource request`);
// Format response
return {
contents: results.map(doc => ({
uri: `il2cpp://${encodeURIComponent(doc.metadata.fullName || doc.metadata.name)}`,
text: doc.pageContent,
metadata: {
...doc.metadata,
searchQuery: queryString,
appliedFilters: filter,
resultCount: results.length
}
}))
};
}
catch (error) {
Logger.error('Error in il2cpp-code resource handler:', error);
throw new error_types_1.MCPServerError(`Resource error: ${error instanceof Error ? error.message : 'Unknown error'}`, error_types_1.ErrorType.RESOURCE_ERROR);
}
});
Logger.debug('Resource handlers registered successfully');
}
// ============================================================================
// TOOL IMPLEMENTATIONS
// ============================================================================
// Import the new tool registry
const tool_registry_1 = require("./tools/tool-registry");
/**
* Register all tool handlers using the new registry system
*/
function registerTools(server) {
Logger.debug('Registering tool handlers using new registry system');
// Create tool execution context
const context = {
vectorStore: vectorStore,
logger: Logger,
isInitialized: () => isInitialized
};
// Register all tools using the new registry
(0, tool_registry_1.registerAllTools)(server, context);
Logger.debug('All tools registered successfully via registry');
}
// ============================================================================
// TRANSPORT FUNCTIONS
// ============================================================================
/**
* Start the MCP server with stdio transport (for command-line tools)
*/
async function startMcpStdioServer() {
try {
Logger.info('Starting MCP server with stdio transport...');
ensureInitialized();
const server = createMcpServer();
const transport = new stdio_js_1.StdioServerTransport();
await server.connect(transport);
Logger.info("MCP server started successfully with stdio transport");
}
catch (error) {
Logger.error('Failed to start stdio server:', error);
throw new error_types_1.MCPServerError(`Failed to start stdio server: ${error instanceof Error ? error.message : 'Unknown error'}`, error_types_1.ErrorType.TRANSPORT_ERROR);
}
}
/**
* Start the MCP server with configurable transport (stdio, HTTP, WebSocket, SSE)
*/
async function startMcpServerWithTransport(transportConfig) {
try {
Logger.info('Starting MCP server with configurable transport...');
ensureInitialized();
// Load transport configuration
const config = transportConfig || (0, transport_1.loadTransportConfig)();
// Validate configuration
const validation = (0, transport_1.validateTransportConfig)(config);
if (!validation.valid) {
throw new error_types_1.MCPServerError(`Invalid transport configuration: ${validation.errors.join(', ')}`, error_types_1.ErrorType.VALIDATION_ERROR);
}
// Print configuration summary
(0, transport_1.printTransportConfigSummary)(config);
const server = createMcpServer();
// Create transport based on configuration
let transport;
if (config.type === transport_1.TransportType.STDIO) {
// Use stdio transport directly for backward compatibility
transport = new stdio_js_1.StdioServerTransport();
}
else {
// Use transport factory for network transports
transport = await (0, transport_1.createValidatedTransport)(config);
}
await server.connect(transport);
Logger.info(`MCP server started successfully with ${config.type} transport`);
// Log connection information for network transports
if (config.type !== transport_1.TransportType.STDIO) {
const protocol = config.enableSsl ? 'https' : 'http';
const url = `${protocol}://${config.host}:${config.port}`;
Logger.info(`Server accessible at: ${url}`);
if (config.apiKey) {
Logger.info('Authentication: API key required');
}
else {
Logger.warn('Authentication: No API key configured (open access)');
}
}
}
catch (error) {
Logger.error('Failed to start MCP server with transport:', error);
throw new error_types_1.MCPServerError(`Failed to start MCP server: ${error instanceof Error ? error.message : 'Unknown error'}`, error_types_1.ErrorType.TRANSPORT_ERROR);
}
}
// ============================================================================
// STARTUP FUNCTIONS (from stdio-server.ts)
// ============================================================================
/**
* Complete server startup with initialization and configurable transport
* This function combines the initialization and startup logic with transport selection
*/
async function startMcpServer(options = {}) {
try {
// Set up the environment for the MCP server
process.env.NODE_ENV = process.env.NODE_ENV || 'production';
Logger.info('Starting complete MCP server initialization and startup...');
// Initialize the server with the provided options
await initializeServer(options);
// Start the MCP server with configurable transport
await startMcpServerWithTransport(options.transportConfig);
}
catch (error) {
Logger.error('Failed to start MCP server:', error);
process.exit(1);
}
}
/**
* Legacy function for backward compatibility - starts with stdio transport only
*/
async function startMcpServerStdio(options = {}) {
try {
// Set up the environment for the MCP server
process.env.NODE_ENV = process.env.NODE_ENV || 'production';
Logger.info('Starting MCP server with stdio transport (legacy mode)...');
// Initialize the server with the provided options
await initializeServer(options);
// Start the MCP stdio server
await startMcpStdioServer();
}
catch (error) {
Logger.error('Failed to start MCP server:', error);
process.exit(1);
}
}
// ============================================================================
// UTILITY FUNCTIONS
// ============================================================================
/**
* Get server status and statistics
*/
function getServerStatus() {
return {
initialized: isInitialized,
vectorStoreReady: vectorStore !== null,
configuration: serverConfig
};
}
/**
* Gracefully shutdown the server
*/
async function shutdown() {
Logger.info('Shutting down MCP server...');
// Reset state
vectorStore = null;
isInitialized = false;
serverConfig = {};
Logger.info('MCP server shutdown complete');
}
// ============================================================================
// EXPORTS FOR BACKWARD COMPATIBILITY
// ============================================================================
// Export the main startup function as default for stdio-server.ts compatibility
exports.default = startMcpServer;
//# sourceMappingURL=mcp-sdk-server.js.map