Skip to main content
Glama
README.md9.23 kB
# Canvas Code Execution API This directory contains the TypeScript code execution API for token-efficient bulk operations with Canvas LMS. ## Overview The Code Execution API allows Claude to process large datasets locally in the execution environment rather than loading all data into the context window. This results in **99.7% token savings** for bulk operations. ### Token Savings Example | Approach | Token Usage | Efficiency | |----------|-------------|-----------| | **Traditional** (call MCP tools) | 1.35M tokens | Loads all 90 submissions into context | | **Code Execution** (run locally) | 3.5K tokens | **99.7% reduction!** | ## Architecture ``` code_api/ ├── client.ts # Canvas API HTTP client with retry logic ├── index.ts # Main entry point └── canvas/ ├── assignments/ # Assignment operations │ └── listSubmissions.ts ├── grading/ # Grading operations (HIGHEST VALUE) │ ├── gradeWithRubric.ts │ └── bulkGrade.ts # ⭐ 99.7% token savings! ├── courses/ # Course operations ├── discussions/ # Discussion operations └── communications/ # Messaging operations ``` ## Setup ### Environment Variables The code execution API requires these environment variables: ```bash # These should be available from the MCP server's .env file CANVAS_API_URL=https://canvas.instructure.com/api/v1 CANVAS_API_TOKEN=your_canvas_api_token_here ``` ### Initialization The client auto-initializes from environment variables: ```typescript import { initializeCanvasClient } from './client'; // Manual initialization (optional) initializeCanvasClient( 'https://canvas.instructure.com/api/v1', 'your_api_token', 30000 // timeout in ms ); ``` ## Usage ### Discovery Use the `search_canvas_tools` MCP tool to discover available operations: ```typescript // Search for grading tools search_canvas_tools("grading", "signatures") // List all available tools search_canvas_tools("", "names") ``` ### Basic Operations ```typescript import { listSubmissions, gradeWithRubric } from './canvas/grading'; // List submissions (stays in execution environment!) const submissions = await listSubmissions({ courseIdentifier: "60366", assignmentId: "123", includeUser: true // Include user details (name, email, etc.) }); // Access user information submissions.forEach(sub => { console.log(`${sub.user?.name} (${sub.user?.email}): ${sub.score ?? 'ungraded'}`); }); // Grade a single submission await gradeWithRubric({ courseIdentifier: "60366", assignmentId: "123", userId: 456, rubricAssessment: { "_8027": { points: 100, comments: "Excellent work!" } }, comment: "Great submission!" }); ``` ### Bulk Operations (⭐ Highest Value) ```typescript import { bulkGrade } from './canvas/grading'; // Grade 90 submissions with 99.7% token savings! await bulkGrade({ courseIdentifier: "60366", assignmentId: "123", maxConcurrent: 5, // Process 5 at a time rateLimitDelay: 1000, // 1s between batches gradingFunction: async (submission) => { // This runs LOCALLY - no token cost! const notebook = submission.attachments?.find( f => f.filename.endsWith('.ipynb') ); if (!notebook) { return null; // Skip } // Analyze notebook locally const hasErrors = await analyzeNotebook(notebook.url); if (hasErrors) { return { points: 0, rubricAssessment: { "_8027": { points: 0 } }, comment: "Notebook has errors" }; } return { points: 100, rubricAssessment: { "_8027": { points: 100 } }, comment: "Perfect!" }; } }); ``` ## Key Features ### ✅ Direct Canvas API Calls - No dependency on MCP tools (which return formatted strings) - Works with raw Canvas API responses (JSON) - Full type safety with TypeScript interfaces ### ✅ Error Handling & Retries - Automatic retry logic with exponential backoff (1s, 2s, 4s) - Don't retry 4xx errors (client errors) - Retry 5xx errors and network failures ### ✅ Input Validation - Rubric assessments validated before submission - Points must be non-negative numbers - Clear error messages for invalid data ### ✅ Concurrent Processing - Process multiple submissions in parallel - Configurable batch size (`maxConcurrent`) - Rate limiting between batches - Promise.allSettled for fault tolerance ### ✅ Form-Encoded Data Support - Proper Canvas API format for rubric assessments - Uses `rubric_assessment[criterion_id][field]` notation - Handles URL-encoded form data correctly ## API Reference ### Client Functions ```typescript // HTTP methods canvasGet<T>(endpoint, params): Promise<T> canvasPost<T>(endpoint, body): Promise<T> canvasPut<T>(endpoint, body): Promise<T> canvasPutForm<T>(endpoint, body): Promise<T> // Form-encoded canvasDelete<T>(endpoint): Promise<T> // Pagination fetchAllPaginated<T>(endpoint, params): Promise<T[]> ``` ### Response Types All responses use Canvas API's snake_case field names: ```typescript interface Submission { id: number; user_id: number; // NOT userId assignment_id: number; // NOT assignmentId submitted_at: string | null; score: number | null; attachments?: Array<{ id: number; filename: string; url: string; content_type: string; }>; user?: { // Included when includeUser: true id: number; name: string; email: string; login_id: string; sortable_name: string; }; } ``` ## Best Practices ### 1. Always Use Dry Run First ```typescript await bulkGrade({ ...params, dryRun: true // Test without actually grading }); ``` ### 2. Handle Errors Gracefully ```typescript gradingFunction: (submission) => { try { // Your logic here return gradeResult; } catch (error) { console.error(`Error processing ${submission.user_id}:`, error); return null; // Skip on error } } ``` ### 3. Validate Rubric Criterion IDs Canvas rubric criterion IDs often start with underscore: - ✅ `"_8027"` - Correct format - ❌ `"8027"` - May not work Use `list_assignment_rubrics` to get correct IDs before grading. ### 4. Respect Rate Limits ```typescript await bulkGrade({ ...params, maxConcurrent: 3, // Reduce if hitting rate limits rateLimitDelay: 2000 // Increase delay between batches }); ``` ### 5. Log Progress Use `console.log()` for visibility: ```typescript gradingFunction: (submission) => { console.log(`Processing user ${submission.user_id}...`); // ... your logic } ``` ## Troubleshooting ### "Canvas client not initialized" **Problem**: Environment variables not set **Solution**: ```typescript import { initializeCanvasClient } from './client'; initializeCanvasClient( process.env.CANVAS_API_URL!, process.env.CANVAS_API_TOKEN! ); ``` ### "Canvas API error (401)" **Problem**: Invalid or expired API token **Solution**: Generate a new token in Canvas → Account → Settings → New Access Token ### "Canvas API error (404)" **Problem**: Wrong course/assignment/user ID **Solution**: Verify IDs are correct and resources exist ### "Criterion ID not found" **Problem**: Rubric criterion ID is incorrect **Solution**: Use `search_canvas_tools("rubric", "full")` to find correct IDs ### Rate Limit Errors **Problem**: Too many concurrent requests **Solution**: Reduce `maxConcurrent` and increase `rateLimitDelay`: ```typescript await bulkGrade({ ...params, maxConcurrent: 2, // Slower but safer rateLimitDelay: 3000 // 3s between batches }); ``` ## Examples See `/examples/bulk_grading_example.md` for a comprehensive walkthrough. ## When to Use Code Execution vs MCP Tools ### Use Code Execution When: - ✅ Processing 10+ submissions/items - ✅ Performing bulk operations - ✅ Need to analyze data locally - ✅ Want maximum token efficiency ### Use MCP Tools When: - ✅ Single queries ("Show me course details") - ✅ Simple lookups ("Get assignment 123") - ✅ Interactive exploration - ✅ Small datasets ## Performance ### Token Usage | Operation | Traditional | Code Execution | Savings | |-----------|-------------|----------------|---------| | 10 submissions | 150K tokens | 1K tokens | **99.3%** | | 90 submissions | 1.35M tokens | 3.5K tokens | **99.7%** | | 1000 submissions | 15M tokens | 30K tokens | **99.8%** | ### Processing Time With concurrent processing (`maxConcurrent: 5`): - **90 submissions**: ~3-5 minutes (vs 10-15 minutes sequential) - **Concurrent batches**: 5x faster than sequential - **Rate limiting**: Prevents Canvas API throttling ## Contributing When adding new wrapper functions: 1. ✅ Use direct Canvas API calls (`canvasGet`, `canvasPost`, etc.) 2. ✅ Use snake_case for Canvas API field names 3. ✅ Add TypeScript type definitions 4. ✅ Include JSDoc comments with examples 5. ✅ Add error handling with clear messages 6. ✅ Update this README ## References - [Anthropic Blog: Code Execution with MCP](https://www.anthropic.com/engineering/code-execution-with-mcp) - [Canvas LMS API Documentation](https://canvas.instructure.com/doc/api/) - [Canvas MCP Server](../../README.md)

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