run-script
Execute JavaScript scripts on the Claude MCP Data Explorer to perform data analysis and generate visualizations, enabling advanced insights from CSV files.
Instructions
Execute a JavaScript script for data analysis and visualization
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| script | Yes | JavaScript script to execute |
Implementation Reference
- src/tools/script-runner.ts:12-140 (handler)TypeScript handler function 'runScript' that safely executes user-provided JavaScript code in a sandboxed context with access to loaded dataframes, limited modules, and DataFrame helper methods.export async function runScript(args: RunScriptArgs): Promise<{ type: string, text: string }[]> { const { script } = args; if (!script) { return [{ type: 'text', text: 'Error: script is required' }]; } // Capture console output let consoleOutput: string[] = []; const originalConsoleLog = console.log; const originalConsoleError = console.error; const originalConsoleWarn = console.warn; console.log = (...args) => { consoleOutput.push(args.map(formatOutput).join(' ')); }; console.error = (...args) => { consoleOutput.push(`ERROR: ${args.map(formatOutput).join(' ')}`); }; console.warn = (...args) => { consoleOutput.push(`WARNING: ${args.map(formatOutput).join(' ')}`); }; try { // Create a context with available libraries and data const contextObject: Record<string, any> = { // Make loaded data frames available to the script ...getAllDataFrames(), // Add utilities require: (moduleName: string) => { try { // Only allow specific modules for security const allowedModules: { [key: string]: any } = { 'simple-statistics': require('simple-statistics'), 'papaparse': require('papaparse'), }; if (moduleName in allowedModules) { return allowedModules[moduleName]; } else { throw new Error(`Module not allowed: ${moduleName}`); } } catch (error) { throw new Error(`Error requiring module '${moduleName}': ${error}`); } }, // Add global variables and functions console: { log: console.log, error: console.error, warn: console.warn }, Math, Date, JSON, Object, Array, String, Number, Boolean, Map, Set, Promise, Error, }; // Add Data Frame helper methods for (const [name, data] of Object.entries(getAllDataFrames())) { contextObject[name] = data; // Add common DataFrame operations if (Array.isArray(data) && data.length > 0) { // Use method binding to ensure 'this' is preserved contextObject[`${name}_describe`] = () => describeDataFrame(data); contextObject[`${name}_columns`] = () => Object.keys(data[0] || {}); contextObject[`${name}_head`] = (n = 5) => data.slice(0, n); contextObject[`${name}_tail`] = (n = 5) => data.slice(-n); contextObject[`${name}_filter`] = (fn: (row: any) => boolean) => data.filter(fn); contextObject[`${name}_map`] = (fn: (row: any) => any) => data.map(fn); contextObject[`${name}_groupBy`] = (key: string) => { const groups: Record<string, any[]> = {}; for (const row of data) { const groupKey = String(row[key]); if (!groups[groupKey]) { groups[groupKey] = []; } groups[groupKey].push(row); } return groups; }; } } // Create a secure function for execution const AsyncFunction = Object.getPrototypeOf(async function(){}).constructor; const secureFunction = new AsyncFunction( ...Object.keys(contextObject), `"use strict"; try { return (async () => { ${script} return "Script executed successfully"; })(); } catch (error) { throw error; }` ); // Execute the function with context const result = await secureFunction(...Object.values(contextObject)); // Add result to console output if we got something back if (result !== "Script executed successfully") { consoleOutput.push(formatOutput(result)); } // Clean up and return the result return [{ type: 'text', text: consoleOutput.join('\n') }]; } catch (error: any) { return [{ type: 'text', text: `Error executing script: ${error.message}\n\nConsole output:\n${consoleOutput.join('\n')}` }]; } finally { // Restore original console methods console.log = originalConsoleLog; console.error = originalConsoleError; console.warn = originalConsoleWarn; } }
- Python handler functions 'handle_run_script' and 'execute_script' that execute user-provided Python code using exec() with access to data science libraries (pandas, numpy, etc.) and loaded dataframes.async def handle_run_script(arguments): """Handle the run-script tool""" script = arguments.get("script") if not script: return [TextContent(type="text", text="Error: script is required")] try: # Execute the script with access to loaded dataframes result = await execute_script(script) return [TextContent(type="text", text=result)] except Exception as e: error_message = f"Error executing script: {str(e)}\n{traceback.format_exc()}" logging.error(error_message) return [TextContent( type="text", text=f"Error executing script: {str(e)}\n{traceback.format_exc()}" )] async def execute_script(script): """Execute a Python script with access to loaded dataframes""" loop = asyncio.get_event_loop() # Capture stdout and stderr stdout = io.StringIO() stderr = io.StringIO() def run_script(): # Create a globals dictionary with loaded dataframes globals_dict = { "pd": __import__("pandas"), "np": __import__("numpy"), "plt": __import__("matplotlib.pyplot"), "sns": __import__("seaborn"), "sklearn": __import__("sklearn"), "stats": __import__("scipy.stats"), } # Add all loaded dataframes to the globals globals_dict.update(get_all_dataframes()) # Redirect stdout and stderr with contextlib.redirect_stdout(stdout), contextlib.redirect_stderr(stderr): # Execute the script exec(script, globals_dict) # Combine stdout and stderr out = stdout.getvalue() err = stderr.getvalue() if err: return f"Script output:\n{out}\n\nErrors:\n{err}" else: return f"Script output:\n{out}" # Run the script in a separate thread return await loop.run_in_executor(None, run_script)
- src/index.ts:74-86 (schema)TypeScript input schema definition for the 'run-script' tool in the list_tools response.name: "run-script", description: "Execute a JavaScript script for data analysis and visualization", inputSchema: { type: "object", properties: { script: { type: "string", description: "JavaScript script to execute" } }, required: ["script"] } }]
- Python input schema definition for the 'run-script' tool in the list_tools handler.name="run-script", description="Execute a Python script for data analysis and visualization", inputSchema={ "type": "object", "properties": { "script": { "type": "string", "description": "Python script to execute" } }, "required": ["script"] } )
- src/index.ts:105-114 (registration)TypeScript dispatch/registration logic in the CallToolRequestSchema handler that routes 'run-script' calls to the runScript function.if (request.params.name === "run-script") { try { const args = request.params.arguments as any; const result = await runScript(args); return { content: result }; } catch (error) { log(`Error executing run-script: ${error}`); throw new McpError(ErrorCode.InternalError, `Error: ${error}`); } }