read_course_file
Retrieve a file's content as base64 from a Canvas course, using file IDs from list_course_files or list_module_items. Specify course identifier and optional max size (default 25 MB) to control memory usage.
Instructions
Read a file from a Canvas course and return its content as base64.
Unlike download_course_file which saves to the server's local filesystem,
this tool returns the file content directly in the response. This is useful
when the MCP server runs on a different machine than the client.
Use list_course_files or list_module_items to find file IDs.
Args:
course_identifier: Course code or Canvas ID
file_id: Canvas file ID
max_size_mb: Maximum file size in MB to read (default: 25). Clamped server-side to
READ_FILE_MAX_SIZE_MB (default 100). Files larger than the effective limit are
rejected to avoid excessive memory usage.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| course_identifier | Yes | ||
| file_id | Yes | ||
| max_size_mb | No |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| result | Yes |
Implementation Reference
- src/canvas_mcp/tools/files.py:111-200 (handler)The actual handler function for the 'read_course_file' tool. Gets file metadata via Canvas API, downloads the file content into memory (streaming with size checks), encodes it as base64, and returns it as a formatted string.
@mcp.tool(annotations=ToolAnnotations(readOnlyHint=True)) @validate_params async def read_course_file( course_identifier: str | int, file_id: str | int, max_size_mb: float = 25.0, ) -> str: """Read a file from a Canvas course and return its content as base64. Unlike download_course_file which saves to the server's local filesystem, this tool returns the file content directly in the response. This is useful when the MCP server runs on a different machine than the client. Use list_course_files or list_module_items to find file IDs. Args: course_identifier: Course code or Canvas ID file_id: Canvas file ID max_size_mb: Maximum file size in MB to read (default: 25). Clamped server-side to READ_FILE_MAX_SIZE_MB (default 100). Files larger than the effective limit are rejected to avoid excessive memory usage. """ if max_size_mb <= 0: return ( f"Error: max_size_mb must be positive (got {max_size_mb}). " f"Pass a value like 25 for a 25 MB limit." ) server_max_mb = get_config().read_file_max_size_mb effective_max_mb = min(float(max_size_mb), server_max_mb) max_size_bytes = int(effective_max_mb * 1024 * 1024) course_id = await get_course_id(course_identifier) # Get file metadata from Canvas API file_info = await make_canvas_request( "get", f"/courses/{course_id}/files/{file_id}" ) if isinstance(file_info, dict) and "error" in file_info: return f"Error getting file info: {file_info['error']}" raw_filename = file_info.get("display_name") or file_info.get("filename", f"file_{file_id}") filename = sanitize_filename(raw_filename) download_url = file_info.get("url") content_type = file_info.get("content-type", "unknown") reported_size = file_info.get("size", 0) if not download_url: return "Error: No download URL available for this file. Check permissions." # Check reported file size before downloading if reported_size and reported_size > max_size_bytes: return ( f"Error: File '{filename}' is {format_file_size(reported_size)}, " f"which exceeds the {effective_max_mb} MB limit. " f"Use download_course_file instead for large files." ) # Download the file content into memory client = _get_http_client() try: buffer = bytearray() async with client.stream("GET", download_url, follow_redirects=True) as response: response.raise_for_status() async for chunk in response.aiter_bytes(chunk_size=8192): if len(buffer) + len(chunk) > max_size_bytes: return ( f"Error: File '{filename}' exceeds the {effective_max_mb} MB limit " f"during download. Use download_course_file instead for large files." ) buffer.extend(chunk) base64_content = base64.b64encode(buffer).decode("ascii") size_str = format_file_size(len(buffer)) course_display = await get_course_code(course_id) or course_identifier result = f"Read: {filename}\n" result += f" Size: {size_str}\n" result += f" Type: {content_type}\n" result += f" Course: {course_display}\n" result += " Encoding: base64\n" result += f" Content:\n{base64_content}\n" return result except Exception as e: return f"Error reading file: {str(e)}" - Docstring/parameter schema defining the inputs: course_identifier, file_id, max_size_mb (default 25.0, clamped server-side to READ_FILE_MAX_SIZE_MB).
"""Read a file from a Canvas course and return its content as base64. Unlike download_course_file which saves to the server's local filesystem, this tool returns the file content directly in the response. This is useful when the MCP server runs on a different machine than the client. Use list_course_files or list_module_items to find file IDs. Args: course_identifier: Course code or Canvas ID file_id: Canvas file ID max_size_mb: Maximum file size in MB to read (default: 25). Clamped server-side to READ_FILE_MAX_SIZE_MB (default 100). Files larger than the effective limit are rejected to avoid excessive memory usage. - src/canvas_mcp/tools/files.py:38-39 (registration)The registration function that wraps the tool. The @mcp.tool decorator on read_course_file (line 111) registers it as an MCP tool within register_shared_file_tools.
def register_shared_file_tools(mcp: FastMCP): """Register file tools accessible to both students and educators.""" - src/canvas_mcp/server.py:115-117 (registration)The call to register_shared_file_tools in the main server setup, which registers read_course_file along with other shared file tools.
register_shared_discussion_tools(mcp) register_shared_module_tools(mcp) register_shared_file_tools(mcp)