Skip to main content
Glama

execute_typescript

Execute TypeScript code locally to perform bulk Canvas operations with Node.js, accessing Canvas API credentials and modules while reducing token usage.

Instructions

Execute TypeScript code in a Node.js environment with access to Canvas API.

This tool enables token-efficient bulk operations by executing code locally rather than loading all data into Claude's context. The code runs in a sandboxed Node.js environment with access to: - Canvas API credentials from environment - All TypeScript modules in src/canvas_mcp/code_api/ - Standard Node.js modules IMPORTANT: This achieves 99.7% token savings for bulk operations! Args: code: TypeScript code to execute. Can import from './canvas/*' modules. timeout: Maximum execution time in seconds (default: 120) Example Usage - Bulk Grading: ```typescript import { bulkGrade } from './canvas/grading/bulkGrade.js'; await bulkGrade({ courseIdentifier: "60366", assignmentId: "123", gradingFunction: (submission) => { // This runs locally - no token cost! const notebook = submission.attachments?.find( f => f.filename.endsWith('.ipynb') ); if (!notebook) return null; // Your grading logic here return { points: 100, rubricAssessment: { "_8027": { points: 100 } }, comment: "Great work!" }; } }); ``` Returns: Combined stdout and stderr from the execution, or error message if failed. Security: - Code runs in a temporary file that is deleted after execution - Inherits Canvas API credentials from server environment - Timeout enforced to prevent runaway processes

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
codeYes
timeoutNo

Implementation Reference

  • The core handler function that executes the provided TypeScript code in a sandboxed Node.js environment using 'tsx'. It sets up Canvas API credentials, creates a temporary .ts file, runs the code with timeout, captures stdout/stderr, and returns formatted results. Handles errors and cleanup.
    async def execute_typescript( code: str, timeout: int = 120 ) -> str: """Execute TypeScript code in a Node.js environment with access to Canvas API. This tool enables token-efficient bulk operations by executing code locally rather than loading all data into Claude's context. The code runs in a sandboxed Node.js environment with access to: - Canvas API credentials from environment - All TypeScript modules in src/canvas_mcp/code_api/ - Standard Node.js modules IMPORTANT: This achieves 99.7% token savings for bulk operations! Args: code: TypeScript code to execute. Can import from './canvas/*' modules. timeout: Maximum execution time in seconds (default: 120) Example Usage - Bulk Grading: ```typescript import { bulkGrade } from './canvas/grading/bulkGrade.js'; await bulkGrade({ courseIdentifier: "60366", assignmentId: "123", gradingFunction: (submission) => { // This runs locally - no token cost! const notebook = submission.attachments?.find( f => f.filename.endsWith('.ipynb') ); if (!notebook) return null; // Your grading logic here return { points: 100, rubricAssessment: { "_8027": { points: 100 } }, comment: "Great work!" }; } }); ``` Returns: Combined stdout and stderr from the execution, or error message if failed. Security: - Code runs in a temporary file that is deleted after execution - Inherits Canvas API credentials from server environment - Timeout enforced to prevent runaway processes """ config = get_config() # Get the absolute path to the code_api directory code_api_dir = Path(__file__).parent.parent / "code_api" # Create a temporary file for the code with tempfile.NamedTemporaryFile( mode='w', suffix='.ts', dir=code_api_dir, delete=False ) as temp_file: # Write the user's code temp_file.write(code) temp_file_path = temp_file.name try: # Prepare environment variables env = os.environ.copy() env['CANVAS_API_URL'] = config.canvas_api_url env['CANVAS_API_TOKEN'] = config.canvas_api_token # Get the repository root (where package.json is) repo_root = Path(__file__).parent.parent.parent.parent # Execute using tsx (faster than ts-node) or ts-node as fallback # tsx is a fast TypeScript execution engine that doesn't require compilation cmd = [ 'npx', 'tsx', # Try tsx first temp_file_path ] # Run the TypeScript code process = await asyncio.create_subprocess_exec( *cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE, env=env, cwd=str(repo_root) ) try: stdout_bytes, stderr_bytes = await asyncio.wait_for( process.communicate(), timeout=timeout ) stdout = stdout_bytes.decode('utf-8', errors='replace') stderr = stderr_bytes.decode('utf-8', errors='replace') # Format output result_lines = [] if process.returncode == 0: result_lines.append("✅ TypeScript execution completed successfully\n") else: result_lines.append(f"❌ TypeScript execution failed with exit code {process.returncode}\n") if stdout: result_lines.append("=== Output ===") result_lines.append(stdout) if stderr: result_lines.append("=== Errors/Warnings ===") result_lines.append(stderr) return "\n".join(result_lines) if result_lines else "No output" except asyncio.TimeoutError: process.kill() await process.wait() return f"❌ Execution timed out after {timeout} seconds" except FileNotFoundError as e: return ( "❌ TypeScript execution environment not found.\n\n" "Please ensure Node.js and npx are installed:\n" " npm install -g tsx\n\n" f"Error: {str(e)}" ) except Exception as e: return f"❌ Execution error: {str(e)}" finally: # Clean up the temporary file try: os.unlink(temp_file_path) except Exception: pass # Ignore cleanup errors
  • The registration function for code execution tools, including the @mcp.tool() decorator on execute_typescript.
    def register_code_execution_tools(mcp: FastMCP) -> None: """Register code execution MCP tools.""" @mcp.tool()
  • Call to register_code_execution_tools within register_all_tools, which registers the execute_typescript tool to the MCP server.
    register_code_execution_tools(mcp)
  • Companion tool that lists all available TypeScript modules importable in execute_typescript for token-efficient bulk operations.
    @mcp.tool() @validate_params async def list_code_api_modules() -> str: """List all available TypeScript modules in the code execution API. Returns a formatted list of all TypeScript files that can be imported in the execute_typescript tool, organized by category with descriptions. This helps Claude discover what operations are available for token-efficient bulk processing. Returns: Formatted string listing all available modules by category with descriptions. """ code_api_dir = Path(__file__).parent.parent / "code_api" if not code_api_dir.exists(): return "❌ Code API directory not found" # Module descriptions mapping module_descriptions = { "bulkGrade": "Grade multiple submissions with local processing function - most token-efficient method", "gradeWithRubric": "Grade a single submission with rubric criteria and optional comments", "bulkGradeDiscussion": "Grade discussion posts in bulk with local processing function", "listSubmissions": "Retrieve all submissions for an assignment (supports includeUser for names/emails)", "listCourses": "List all courses accessible to the current user", "getCourseDetails": "Get detailed information about a specific course", "sendMessage": "Send a message/announcement to course participants", "listDiscussions": "List discussion topics in a course", "postEntry": "Post an entry to a discussion topic", } # Organize modules by directory modules_by_category: dict[str, list[tuple[str, str]]] = {} for ts_file in code_api_dir.rglob("*.ts"): # Skip certain files if ts_file.name in ['index.ts', 'client.ts']: continue # Get relative path from code_api rel_path = ts_file.relative_to(code_api_dir) # Get category (parent directory name) category = rel_path.parent.name if rel_path.parent.name != '.' else 'root' # Get import path (convert .ts to .js for ESM imports) import_path = f"./{rel_path.parent}/{rel_path.stem}.js" # Get description from mapping module_name = rel_path.stem description = module_descriptions.get(module_name, "") if category not in modules_by_category: modules_by_category[category] = [] modules_by_category[category].append((import_path, description)) # Format output result_lines = [] result_lines.append("Available TypeScript Modules for Code Execution") result_lines.append("=" * 60) result_lines.append("") result_lines.append("Import these in execute_typescript tool:") result_lines.append("") for category, modules in sorted(modules_by_category.items()): result_lines.append(f"📁 {category.upper()}") result_lines.append("-" * 40) for import_path, description in sorted(modules, key=lambda x: x[0]): result_lines.append(f" {import_path}") if description: result_lines.append(f" • {description}") result_lines.append("") result_lines.append("Example Usage:") result_lines.append("```typescript") result_lines.append("import { bulkGrade } from './canvas/grading/bulkGrade.js';") result_lines.append("import { listSubmissions } from './canvas/assignments/listSubmissions.js';") result_lines.append("") result_lines.append("// Your code here...") result_lines.append("```") return "\n".join(result_lines)

Other Tools

Latest Blog Posts

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/vishalsachdev/canvas-mcp'

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