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)
Install Server

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