import asyncio
import requests
from typing import Dict, List, Optional
from urllib.parse import urljoin, urlparse
from bs4 import BeautifulSoup
from fastmcp import FastMCP
# Initialize FastMCP server
mcp = FastMCP("Unsloth AI Documentation Server")
# Base URL for Unsloth documentation
BASE_URL = "https://docs.unsloth.ai"
def fetch_page_content(url: str) -> Dict[str, str]:
"""Fetch content from a documentation page."""
try:
response = requests.get(url, timeout=10)
response.raise_for_status()
soup = BeautifulSoup(response.content, 'html.parser')
# Extract main content
# GitBook documentation typically has content in these selectors
content_selectors = [
'div[data-testid="page-content"]',
'.page-content',
'main',
'.markdown-body',
'article'
]
content = ""
title = soup.find('title').get_text() if soup.find('title') else "Unsloth Documentation"
for selector in content_selectors:
content_elem = soup.select_one(selector)
if content_elem:
content = content_elem.get_text(strip=True)
break
if not content:
# Fallback to body content
body = soup.find('body')
if body:
content = body.get_text(strip=True)
return {
"title": title,
"content": content,
"url": url
}
except Exception as e:
return {
"title": "Error",
"content": f"Failed to fetch content: {str(e)}",
"url": url
}
@mcp.tool
def search_unsloth_docs(query: str) -> str:
"""
Search the Unsloth AI documentation for relevant information.
Args:
query: The search term or topic you want to find information about
Returns:
Relevant documentation content from Unsloth AI docs
"""
try:
# Fetch the main documentation page
main_page = fetch_page_content(BASE_URL)
# Simple keyword matching in content
query_lower = query.lower()
content_lower = main_page["content"].lower()
if query_lower in content_lower:
# Find the section containing the query
lines = main_page["content"].split('\n')
relevant_lines = []
for i, line in enumerate(lines):
if query_lower in line.lower():
# Include context around the matching line
start = max(0, i - 3)
end = min(len(lines), i + 4)
relevant_lines.extend(lines[start:end])
relevant_lines.append("---")
if relevant_lines:
return f"Found relevant information about '{query}':\n\n" + "\n".join(relevant_lines)
return f"No specific information found for '{query}' in the main documentation. Here's the general overview:\n\n{main_page['content'][:1000]}..."
except Exception as e:
return f"Error searching documentation: {str(e)}"
@mcp.tool
def get_unsloth_quickstart() -> str:
"""
Get the Unsloth quickstart guide and installation instructions.
Returns:
Quickstart guide content from Unsloth documentation
"""
try:
main_page = fetch_page_content(BASE_URL)
# Extract quickstart and installation information
content = main_page["content"]
# Look for quickstart-related sections
quickstart_keywords = ["quickstart", "install", "getting started", "pip install"]
relevant_sections = []
lines = content.split('\n')
for i, line in enumerate(lines):
for keyword in quickstart_keywords:
if keyword.lower() in line.lower():
start = max(0, i - 2)
end = min(len(lines), i + 5)
section = "\n".join(lines[start:end])
if section not in relevant_sections:
relevant_sections.append(section)
break
if relevant_sections:
return "Unsloth Quickstart Guide:\n\n" + "\n\n---\n\n".join(relevant_sections)
else:
return f"Unsloth Documentation Overview:\n\n{content[:2000]}..."
except Exception as e:
return f"Error fetching quickstart guide: {str(e)}"
@mcp.tool
def get_unsloth_models() -> str:
"""
Get information about available models in Unsloth.
Returns:
Information about Unsloth supported models
"""
try:
main_page = fetch_page_content(BASE_URL)
content = main_page["content"]
# Look for model-related information
model_keywords = ["llama", "qwen", "gemma", "models", "phi", "mistral", "deepseek"]
relevant_sections = []
lines = content.split('\n')
for i, line in enumerate(lines):
for keyword in model_keywords:
if keyword.lower() in line.lower():
start = max(0, i - 1)
end = min(len(lines), i + 3)
section = "\n".join(lines[start:end])
if section not in relevant_sections:
relevant_sections.append(section)
break
if relevant_sections:
return "Unsloth Supported Models:\n\n" + "\n\n---\n\n".join(relevant_sections)
else:
return "Model information not found in the main page. Please use search_unsloth_docs with specific model names."
except Exception as e:
return f"Error fetching model information: {str(e)}"
@mcp.tool
def get_unsloth_tutorials() -> str:
"""
Get information about Unsloth tutorials and fine-tuning guides.
Returns:
Tutorial and guide information from Unsloth documentation
"""
try:
main_page = fetch_page_content(BASE_URL)
content = main_page["content"]
# Look for tutorial-related information
tutorial_keywords = ["tutorial", "fine-tuning", "guide", "notebook", "colab", "training"]
relevant_sections = []
lines = content.split('\n')
for i, line in enumerate(lines):
for keyword in tutorial_keywords:
if keyword.lower() in line.lower():
start = max(0, i - 1)
end = min(len(lines), i + 4)
section = "\n".join(lines[start:end])
if section not in relevant_sections:
relevant_sections.append(section)
break
if relevant_sections:
return "Unsloth Tutorials and Guides:\n\n" + "\n\n---\n\n".join(relevant_sections)
else:
return "Tutorial information not found in the main page. Try searching for specific topics."
except Exception as e:
return f"Error fetching tutorial information: {str(e)}"
@mcp.tool
def get_unsloth_installation() -> str:
"""
Get detailed installation instructions for Unsloth.
Returns:
Installation instructions and requirements
"""
try:
main_page = fetch_page_content(BASE_URL)
content = main_page["content"]
# Look for installation-related information
install_keywords = ["install", "pip", "requirements", "setup", "dependencies"]
relevant_sections = []
lines = content.split('\n')
for i, line in enumerate(lines):
for keyword in install_keywords:
if keyword.lower() in line.lower():
start = max(0, i - 1)
end = min(len(lines), i + 5)
section = "\n".join(lines[start:end])
if section not in relevant_sections:
relevant_sections.append(section)
break
if relevant_sections:
return "Unsloth Installation Guide:\n\n" + "\n\n---\n\n".join(relevant_sections)
else:
return f"Installation information:\n\n{content[:1500]}..."
except Exception as e:
return f"Error fetching installation information: {str(e)}"
if __name__ == "__main__":
mcp.run()