#!/usr/bin/env node
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
const SCARTOOLKIT_URL = "http://localhost:52737";
const HEARTBEAT_INTERVAL_MS = 2000;
// HTTP client helper
async function fetchJson(url, options = {}) {
    try {
        const response = await fetch(url, {
            ...options,
            headers: {
                "Content-Type": "application/json",
                ...options.headers,
            },
        });
        return await response.json();
    }
    catch (error) {
        return {
            success: false,
            error: `Connection failed: ${error instanceof Error ? error.message : String(error)}`,
        };
    }
}
// Tool definitions
const tools = [
    {
        name: "get_status",
        description: "Get the current status of ScarToolkit including game attachment, SCAR state, and MCP connection status",
        inputSchema: {
            type: "object",
            properties: {},
            required: [],
        },
    },
    {
        name: "execute_lua",
        description: "Execute a Lua script in the game. The game must be attached and SCAR must be ready (state == 3)",
        inputSchema: {
            type: "object",
            properties: {
                code: {
                    type: "string",
                    description: "The Lua code to execute",
                },
                mode: {
                    type: "string",
                    enum: ["safe", "raw"],
                    description: "Execution mode: 'safe' wraps code in pcall, 'raw' executes directly. Default: safe",
                },
            },
            required: ["code"],
        },
    },
    {
        name: "debug_lua",
        description: "Execute a Lua script with the debug overlay enabled. Shows debug HUD during script execution",
        inputSchema: {
            type: "object",
            properties: {
                code: {
                    type: "string",
                    description: "The Lua code to execute with debug overlay",
                },
            },
            required: ["code"],
        },
    },
    {
        name: "list_scripts",
        description: "List all saved .lua scripts in the lua_scripts directory",
        inputSchema: {
            type: "object",
            properties: {},
            required: [],
        },
    },
    {
        name: "load_script",
        description: "Load and return the content of a saved script by name",
        inputSchema: {
            type: "object",
            properties: {
                name: {
                    type: "string",
                    description: "The script filename (e.g., 'my_script.lua' or 'my_script')",
                },
            },
            required: ["name"],
        },
    },
    {
        name: "save_script",
        description: "Save a script to the lua_scripts directory",
        inputSchema: {
            type: "object",
            properties: {
                name: {
                    type: "string",
                    description: "The script filename (e.g., 'my_script.lua' or 'my_script')",
                },
                content: {
                    type: "string",
                    description: "The Lua script content to save",
                },
            },
            required: ["name", "content"],
        },
    },
    {
        name: "delete_script",
        description: "Delete a saved script by name",
        inputSchema: {
            type: "object",
            properties: {
                name: {
                    type: "string",
                    description: "The script filename to delete",
                },
            },
            required: ["name"],
        },
    },
    {
        name: "wait_for_scar",
        description: "Poll until SCAR is ready (state == 3). Useful for waiting until a game match has started",
        inputSchema: {
            type: "object",
            properties: {
                timeout_seconds: {
                    type: "number",
                    description: "Maximum time to wait in seconds. Default: 60, Max: 300",
                },
                poll_interval_ms: {
                    type: "number",
                    description: "How often to check status in milliseconds. Default: 1000",
                },
            },
            required: [],
        },
    },
    {
        name: "get_editor",
        description: "Read the current content of the script text editor in ScarToolkit",
        inputSchema: {
            type: "object",
            properties: {},
            required: [],
        },
    },
    {
        name: "set_editor",
        description: "Set/paste content into the script text editor in ScarToolkit. This replaces the current editor content.",
        inputSchema: {
            type: "object",
            properties: {
                content: {
                    type: "string",
                    description: "The Lua code to paste into the editor",
                },
            },
            required: ["content"],
        },
    },
];
// Tool handlers
async function handleGetStatus() {
    const result = await fetchJson(`${SCARTOOLKIT_URL}/status`);
    if (!result.success) {
        return JSON.stringify({
            error: result.error || "Failed to get status",
            connected: false,
        });
    }
    return JSON.stringify(result.data);
}
async function handleExecuteLua(code, mode = "safe") {
    const result = await fetchJson(`${SCARTOOLKIT_URL}/execute?mode=${encodeURIComponent(mode)}`, {
        method: "POST",
        body: code,
    });
    if (!result.success) {
        return JSON.stringify({ error: result.error || "Execution failed" });
    }
    return JSON.stringify({ success: true, message: "Script executed" });
}
async function handleDebugLua(code) {
    const result = await fetchJson(`${SCARTOOLKIT_URL}/debug`, {
        method: "POST",
        body: code,
    });
    if (!result.success) {
        return JSON.stringify({ error: result.error || "Debug execution failed" });
    }
    return JSON.stringify({
        success: true,
        message: "Script executed with debug overlay",
    });
}
async function handleListScripts() {
    const result = await fetchJson(`${SCARTOOLKIT_URL}/scripts`);
    if (!result.success) {
        return JSON.stringify({ error: result.error || "Failed to list scripts" });
    }
    return JSON.stringify({ scripts: result.data });
}
async function handleLoadScript(name) {
    // Ensure .lua extension
    const filename = name.endsWith(".lua") ? name : `${name}.lua`;
    const result = await fetchJson(`${SCARTOOLKIT_URL}/scripts/${encodeURIComponent(filename)}`);
    if (!result.success) {
        return JSON.stringify({ error: result.error || "Failed to load script" });
    }
    return JSON.stringify(result.data);
}
async function handleSaveScript(name, content) {
    // Ensure .lua extension
    const filename = name.endsWith(".lua") ? name : `${name}.lua`;
    const result = await fetchJson(`${SCARTOOLKIT_URL}/scripts/${encodeURIComponent(filename)}`, {
        method: "POST",
        body: content,
    });
    if (!result.success) {
        return JSON.stringify({ error: result.error || "Failed to save script" });
    }
    return JSON.stringify({ success: true, message: `Script '${filename}' saved` });
}
async function handleDeleteScript(name) {
    // Ensure .lua extension
    const filename = name.endsWith(".lua") ? name : `${name}.lua`;
    const result = await fetchJson(`${SCARTOOLKIT_URL}/scripts/${encodeURIComponent(filename)}`, {
        method: "DELETE",
    });
    if (!result.success) {
        return JSON.stringify({ error: result.error || "Failed to delete script" });
    }
    return JSON.stringify({
        success: true,
        message: `Script '${filename}' deleted`,
    });
}
async function handleGetEditor() {
    const result = await fetchJson(`${SCARTOOLKIT_URL}/editor`);
    if (!result.success) {
        return JSON.stringify({ error: result.error || "Failed to read editor" });
    }
    return JSON.stringify(result.data);
}
async function handleSetEditor(content) {
    const result = await fetchJson(`${SCARTOOLKIT_URL}/editor`, {
        method: "POST",
        body: content,
    });
    if (!result.success) {
        return JSON.stringify({ error: result.error || "Failed to set editor content" });
    }
    return JSON.stringify({
        success: true,
        message: `Editor content set (${content.length} characters)`,
    });
}
async function handleWaitForScar(timeoutSeconds = 60, pollIntervalMs = 1000) {
    const maxTimeout = Math.min(timeoutSeconds, 300);
    const startTime = Date.now();
    const endTime = startTime + maxTimeout * 1000;
    while (Date.now() < endTime) {
        const result = await fetchJson(`${SCARTOOLKIT_URL}/status`);
        if (result.success && typeof result.data === "object" && result.data !== null) {
            const data = result.data;
            if (data.scarReady) {
                return JSON.stringify({
                    success: true,
                    message: "SCAR is ready",
                    scarState: data.scarState,
                    waitedMs: Date.now() - startTime,
                });
            }
        }
        await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
    }
    return JSON.stringify({
        success: false,
        error: `Timeout after ${maxTimeout} seconds waiting for SCAR to be ready`,
    });
}
// Create and run the server
async function main() {
    const server = new Server({
        name: "scartoolkit",
        version: "1.0.0",
    }, {
        capabilities: {
            tools: {},
        },
    });
    // Start heartbeat to keep connection indicator active
    let heartbeatInterval = null;
    const startHeartbeat = () => {
        if (heartbeatInterval)
            return;
        heartbeatInterval = setInterval(async () => {
            try {
                await fetch(`${SCARTOOLKIT_URL}/heartbeat`, { method: "POST" });
            }
            catch {
                // Ignore heartbeat failures
            }
        }, HEARTBEAT_INTERVAL_MS);
    };
    const stopHeartbeat = () => {
        if (heartbeatInterval) {
            clearInterval(heartbeatInterval);
            heartbeatInterval = null;
        }
    };
    // List available tools
    server.setRequestHandler(ListToolsRequestSchema, async () => {
        return { tools };
    });
    // Handle tool calls
    server.setRequestHandler(CallToolRequestSchema, async (request) => {
        const { name, arguments: args } = request.params;
        // Ensure heartbeat is running when tools are called
        startHeartbeat();
        let result;
        try {
            switch (name) {
                case "get_status":
                    result = await handleGetStatus();
                    break;
                case "execute_lua":
                    result = await handleExecuteLua(args.code, args.mode);
                    break;
                case "debug_lua":
                    result = await handleDebugLua(args.code);
                    break;
                case "list_scripts":
                    result = await handleListScripts();
                    break;
                case "load_script":
                    result = await handleLoadScript(args.name);
                    break;
                case "save_script":
                    result = await handleSaveScript(args.name, args.content);
                    break;
                case "delete_script":
                    result = await handleDeleteScript(args.name);
                    break;
                case "wait_for_scar":
                    result = await handleWaitForScar(args.timeout_seconds, args.poll_interval_ms);
                    break;
                case "get_editor":
                    result = await handleGetEditor();
                    break;
                case "set_editor":
                    result = await handleSetEditor(args.content);
                    break;
                default:
                    result = JSON.stringify({ error: `Unknown tool: ${name}` });
            }
        }
        catch (error) {
            result = JSON.stringify({
                error: `Tool execution failed: ${error instanceof Error ? error.message : String(error)}`,
            });
        }
        return {
            content: [
                {
                    type: "text",
                    text: result,
                },
            ],
        };
    });
    // Handle shutdown
    process.on("SIGINT", () => {
        stopHeartbeat();
        process.exit(0);
    });
    process.on("SIGTERM", () => {
        stopHeartbeat();
        process.exit(0);
    });
    // Connect via stdio
    const transport = new StdioServerTransport();
    await server.connect(transport);
    // Start heartbeat immediately
    startHeartbeat();
}
main().catch((error) => {
    console.error("Fatal error:", error);
    process.exit(1);
});
//# sourceMappingURL=index.js.map