Skip to main content
Glama

download_resource

Download Moodle course materials like PPTs and PDFs from a URL to your local directory. Specify a custom folder path or use the default download location.

Instructions

Download Moodle resource file(s) (PPT, PDF, etc.) from a URL. Supports saving to a custom local directory.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
resource_urlYesThe exact Moodle resource URL to download from.
download_pathNoThe absolute folder path string (e.g. '/Users/cosmos/Desktop'). IMPORTANT: This must be a STRING value, NOT a boolean. WRONG: true, false. RIGHT: '/path/to/folder'. If not provided, it uses the default system download folder.

Implementation Reference

  • Core handler function in MUSTerClient that implements the download logic: ensures login, loads the resource page with Selenium, finds Moodle pluginfile download links, transfers session cookies to requests library, downloads files to the specified path (default ~/Downloads), skips existing files, returns detailed JSON with downloaded/skipped files and errors.
    def download_resource(self, resource_url: str, download_path: Optional[str] = None) -> Dict[str, Any]: """ Download resource(s) from Moodle using the authenticated session.""" resolved_download_path = download_path or DOWNLOAD_DIR self._ensure_driver() if not self.logged_in: if not self.login(): raise Exception("Login required to download resources.") self.heartBeat() try: # Navigate to the resource page to get the actual download URL self.driver.get(resource_url) # Wait for the page to load and find download links WebDriverWait(self.driver, 10).until( EC.presence_of_element_located((By.CSS_SELECTOR, "a[onclick*='target='], a[href*='pluginfile.php']")) ) # Find all direct download links download_links = self.driver.find_elements(By.CSS_SELECTOR, "a[onclick*='target='], a[href*='pluginfile.php']") if not download_links: return {"error": "No download links found on the resource page"} # Get cookies from Selenium session for requests cookies = {} for cookie in self.driver.get_cookies(): cookies[cookie['name']] = cookie['value'] self.heartBeat() # Download headers headers = { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36' } self.heartBeat() downloaded_files = [] skipped_files = [] errors = [] self.heartBeat() # Create download directory Path(resolved_download_path).mkdir(parents=True, exist_ok=True) self.heartBeat() for i, link in enumerate(download_links): try: download_url = link.get_attribute('href') if not download_url or not download_url.startswith('http'): continue self.heartBeat() # Skip non-file links if 'pluginfile.php' not in download_url: continue self.heartBeat() # Extract filename from URL or link text filename = None try: # Try to get filename from the link text first link_text = link.text.strip() if link_text and '.' in link_text and len(link_text) < 200: filename = link_text else: # Extract from URL parsed_url = urllib.parse.urlparse(download_url) path_parts = parsed_url.path.split('/') for part in reversed(path_parts): if '.' in part and len(part) < 200: filename = urllib.parse.unquote(part) break except Exception: pass self.heartBeat() if not filename: filename = f"download_{int(time.time())}_{i}" # Skip if file exists file_path = Path(resolved_download_path) / filename if file_path.exists(): skipped_files.append(filename) continue # Download the file response = requests.get(download_url, cookies=cookies, headers=headers, stream=True) response.raise_for_status() # Write file with open(file_path, 'wb') as f: for chunk in response.iter_content(chunk_size=8192): f.write(chunk) file_size = file_path.stat().st_size downloaded_files.append({ "filename": file_path.name, "file_path": str(file_path), "file_size": file_size, "download_url": download_url }) except requests.exceptions.RequestException as e: errors.append(f"Failed to download {download_url}: {str(e)}") except Exception as e: errors.append(f"Unexpected error downloading file {i+1}: {str(e)}") if downloaded_files or skipped_files: result = { "success": True, "total_downloaded": len(downloaded_files), "total_skipped": len(skipped_files), "downloaded_files": downloaded_files, "skipped_files": skipped_files, } if errors: result["errors"] = errors return result else: return {"error": f"No files were downloaded. Errors: {'; '.join(errors)}"} except Exception as e: return {"error": f"Unexpected error during download: {str(e)}"}
  • main.py:53-66 (schema)
    JSON Schema defining the input parameters for the download_resource tool: required resource_url (string), optional download_path (string or null).
    inputSchema={ "type": "object", "properties": { "resource_url": { "type": "string", "description": "The exact Moodle resource URL to download from.", }, "download_path": { "type": ["string", "null"], "description": "The absolute folder path string (e.g. '/Users/cosmos/Desktop'). \nIMPORTANT: This must be a STRING value, NOT a boolean. \nWRONG: true, false. \nRIGHT: '/path/to/folder'. \nIf not provided, it uses the default system download folder.", }, }, "required": ["resource_url"], },
  • main.py:50-67 (registration)
    Tool registration in list_muster_tools(): defines name, description, and input schema for the MCP server.list_tools().
    Tool( name="download_resource", description="Download Moodle resource file(s) (PPT, PDF, etc.) from a URL. Supports saving to a custom local directory.", inputSchema={ "type": "object", "properties": { "resource_url": { "type": "string", "description": "The exact Moodle resource URL to download from.", }, "download_path": { "type": ["string", "null"], "description": "The absolute folder path string (e.g. '/Users/cosmos/Desktop'). \nIMPORTANT: This must be a STRING value, NOT a boolean. \nWRONG: true, false. \nRIGHT: '/path/to/folder'. \nIf not provided, it uses the default system download folder.", }, }, "required": ["resource_url"], }, ),
  • main.py:154-158 (handler)
    Thin wrapper handler in main.py that calls the core MUSTerClient.download_resource and handles exceptions.
    def tool_download_resource(resource_url: str, download_path: Optional[str] = None) -> Dict[str, Any]: try: return muster_client.download_resource(resource_url, download_path) except Exception as e: return {"error": f"Failed to download resource: {str(e)}"}
  • main.py:213-214 (registration)
    Dispatch registration in @server.call_tool(): handles the tool call by invoking the wrapper function and wrapping result as TextContent.
    if name == "download_resource": return _wrap_json(tool_download_resource(args["resource_url"], args.get("download_path")))

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/Cosmostima/MUSTer_MCP'

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