Skip to main content
Glama

get_course_content_overview

Retrieve course content overview including pages, modules, and syllabus from Canvas LMS to understand course structure and materials.

Instructions

Get a comprehensive overview of course content including pages, modules, and syllabus.

    Args:
        course_identifier: The Canvas course code (e.g., badm_554_120251_246794) or ID
        include_pages: Whether to include pages information
        include_modules: Whether to include modules and their items
        include_syllabus: Whether to include syllabus content
    

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
course_identifierYes
include_pagesNo
include_modulesNo
include_syllabusNo

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
resultYes

Implementation Reference

  • Main implementation of the get_course_content_overview tool handler, including decorators for registration and validation. Fetches and summarizes course pages, modules, and syllabus.
    @mcp.tool()
    @validate_params
    async def get_course_content_overview(course_identifier: str | int,
                                        include_pages: bool = True,
                                        include_modules: bool = True,
                                        include_syllabus: bool = True) -> str:
        """Get a comprehensive overview of course content including pages, modules, and syllabus.
    
        Args:
            course_identifier: The Canvas course code (e.g., badm_554_120251_246794) or ID
            include_pages: Whether to include pages information
            include_modules: Whether to include modules and their items
            include_syllabus: Whether to include syllabus content
        """
        course_id = await get_course_id(course_identifier)
    
        overview_sections = []
    
        # Get course details for context
        course_response = await make_canvas_request("get", f"/courses/{course_id}")
        if "error" not in course_response:
            course_name = course_response.get("name", "Unknown Course")
            overview_sections.append(f"Course: {course_name}")
    
        # Get pages if requested
        if include_pages:
            pages = await fetch_all_paginated_results(f"/courses/{course_id}/pages", {"per_page": 100})
            if isinstance(pages, list):
                published_pages = [p for p in pages if p.get("published", False)]
                unpublished_pages = [p for p in pages if not p.get("published", False)]
                front_pages = [p for p in pages if p.get("front_page", False)]
    
                pages_summary = [
                    "\nPages Summary:",
                    f"  Total Pages: {len(pages)}",
                    f"  Published: {len(published_pages)}",
                    f"  Unpublished: {len(unpublished_pages)}",
                    f"  Front Pages: {len(front_pages)}"
                ]
    
                if published_pages:
                    pages_summary.append("\nRecent Published Pages:")
                    # Sort by updated_at and show first 5
                    sorted_pages = sorted(published_pages,
                                        key=lambda x: x.get("updated_at", ""),
                                        reverse=True)
                    for page in sorted_pages[:5]:
                        title = page.get("title", "Untitled")
                        updated = format_date(page.get("updated_at"))
                        pages_summary.append(f"    {title} (Updated: {updated})")
    
                overview_sections.append("\n".join(pages_summary))
    
        # Get modules if requested
        if include_modules:
            modules = await fetch_all_paginated_results(f"/courses/{course_id}/modules", {"per_page": 100})
            if isinstance(modules, list):
                modules_summary = [
                    "\nModules Summary:",
                    f"  Total Modules: {len(modules)}"
                ]
    
                # Count module items by type across all modules
                item_type_counts = {}
                total_items = 0
    
                for module in modules[:10]:  # Limit to first 10 modules to avoid too many API calls
                    module_id = module.get("id")
                    if module_id:
                        items = await fetch_all_paginated_results(
                            f"/courses/{course_id}/modules/{module_id}/items",
                            {"per_page": 100}
                        )
                        if isinstance(items, list):
                            total_items += len(items)
                            for item in items:
                                item_type = item.get("type", "Unknown")
                                item_type_counts[item_type] = item_type_counts.get(item_type, 0) + 1
    
                modules_summary.append(f"  Total Items Analyzed: {total_items}")
                if item_type_counts:
                    modules_summary.append("  Item Types:")
                    for item_type, count in sorted(item_type_counts.items()):
                        modules_summary.append(f"    {item_type}: {count}")
    
                # Show module structure for first few modules
                if modules:
                    modules_summary.append("\nModule Structure (first 3):")
                    for module in modules[:3]:
                        name = module.get("name", "Unnamed")
                        state = module.get("state", "unknown")
                        modules_summary.append(f"    {name} (Status: {state})")
    
                overview_sections.append("\n".join(modules_summary))
    
        # Get syllabus content if requested
        if include_syllabus:
            # Fetch the course details with syllabus_body included
            course_with_syllabus = await make_canvas_request(
                "get",
                f"/courses/{course_id}",
                params={"include[]": "syllabus_body"}
            )
    
            if "error" not in course_with_syllabus:
                syllabus_body = course_with_syllabus.get('syllabus_body', '')
    
                if syllabus_body:
                    # Clean the HTML content
                    clean_syllabus = strip_html_tags(syllabus_body)
    
                    # For overview, limit to first 1000 characters
                    if len(clean_syllabus) > 1000:
                        clean_syllabus = clean_syllabus[:1000] + "..."
    
                    syllabus_summary = [
                        "\nSyllabus Content:",
                        # Indent the content
                        "\n".join([f"  {line}" for line in clean_syllabus.split('\n') if line.strip()])
                    ]
    
                    overview_sections.append("\n".join(syllabus_summary))
                else:
                    overview_sections.append("\nSyllabus Content: No syllabus content found")
            else:
                overview_sections.append("\nSyllabus Content: Error fetching syllabus")
        # Try to get the course code for display
        course_display = await get_course_code(course_id) or course_identifier
        result = f"Content Overview for Course {course_display}:" + "\n".join(overview_sections)
    
        return result
  • register_all_tools function calls register_course_tools(mcp) which in turn defines and registers the get_course_content_overview tool using @mcp.tool() decorator.
    # Register tools by category
    register_course_tools(mcp)
    register_assignment_tools(mcp)
    register_discussion_tools(mcp)
    register_other_tools(mcp)
    register_rubric_tools(mcp)
    register_peer_review_tools(mcp)
    register_peer_review_comment_tools(mcp)
    register_messaging_tools(mcp)
    register_student_tools(mcp)
    register_accessibility_tools(mcp)
    register_discovery_tools(mcp)
    register_code_execution_tools(mcp)
    
    # Register resources and prompts
    register_resources_and_prompts(mcp)
    
    log_info("All Canvas MCP tools registered successfully!")
  • Helper function used by get_course_content_overview to clean syllabus HTML content into plain text.
    def strip_html_tags(html_content: str) -> str:
        """Remove HTML tags and clean up text content."""
        if not html_content:
            return ""
    
        # Remove HTML tags
        clean_text = re.sub(r'<[^>]+>', '', html_content)
    
        # Replace common HTML entities
        clean_text = clean_text.replace(' ', ' ')
        clean_text = clean_text.replace('&', '&')
        clean_text = clean_text.replace('<', '<')
        clean_text = clean_text.replace('>', '>')
        clean_text = clean_text.replace('"', '"')
    
        # Clean up whitespace
        clean_text = re.sub(r'\s+', ' ', clean_text)
        clean_text = clean_text.strip()
    
        return clean_text
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden of behavioral disclosure. While it mentions what data is included (pages, modules, syllabus), it doesn't describe important behavioral aspects: whether this is a read-only operation, if it requires specific permissions, what the output format looks like (though there's an output schema), or any rate limits. The description is minimal beyond stating the basic functionality.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is appropriately concise with a clear two-part structure: a purpose statement followed by parameter explanations. The Args section is formatted clearly. There's no unnecessary verbiage, though the parameter explanations could be slightly more detailed given the 0% schema coverage.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given that there's an output schema (which handles return values), 0% schema coverage for parameters, and no annotations, the description is minimally adequate. It explains what the tool does and what each parameter controls, but doesn't provide important context about permissions, data format, or differentiation from sibling tools. For a tool with 4 parameters and no annotation coverage, it should do more to guide proper usage.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It provides a brief explanation of each parameter in the Args section, clarifying that 'course_identifier' can be a code or ID, and explaining what each boolean flag controls. This adds meaningful context beyond the bare schema, but doesn't provide format details (e.g., what the 'comprehensive overview' output structure looks like) or usage examples.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: 'Get a comprehensive overview of course content including pages, modules, and syllabus.' It specifies the verb ('Get') and resource ('course content overview'), and mentions the key components included. However, it doesn't explicitly differentiate from sibling tools like 'get_course_details' or 'list_pages' which might provide overlapping functionality.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to use this tool versus alternatives. There are many sibling tools (e.g., 'get_course_details', 'list_pages', 'list_module_items') that might retrieve similar or overlapping data, but the description doesn't explain when this comprehensive overview is preferred over more specific tools or how it differs from them.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

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