diff --git a/examples/browser_mcp_server.py b/examples/browser_mcp_server.py
new file mode 100644
index 000000000..209f59584
--- /dev/null
+++ b/examples/browser_mcp_server.py
@@ -0,0 +1,190 @@
+"""
+Browser-compatible FastMCP Server Example
+
+This example shows how to adapt FastMCP for browser environments,
+with tools that can access web page content and make authenticated requests.
+"""
+
+from fastmcp import FastMCP
+from typing import Dict, Any, Optional
+import asyncio
+
+# Create a browser-friendly MCP server
+mcp = FastMCP("Browser Web Assistant")
+
+@mcp.tool
+async def read_page_text(selector: str = "body") -> str:
+ """
+ Read text content from the current web page using CSS selector.
+ Useful for LLMs to understand what's currently displayed.
+
+ Args:
+ selector: CSS selector to target specific elements (default: "body")
+ """
+ # This would be implemented using PyScript's DOM access
+ # In actual browser environment, this would use:
+ # from js import document
+ # element = document.querySelector(selector)
+ # return element.textContent if element else "Element not found"
+ return f"[Browser] Would read content from selector: {selector}"
+
+@mcp.tool
+async def get_page_metadata() -> Dict[str, str]:
+ """
+ Extract metadata from the current page (title, URL, meta tags, etc.).
+ Provides context about the current page to the LLM.
+ """
+ # In browser environment:
+ # from js import document
+ # return {
+ # "title": document.title,
+ # "url": document.location.href,
+ # "description": document.querySelector('meta[name="description"]')?.content || "",
+ # "keywords": document.querySelector('meta[name="keywords"]')?.content || ""
+ # }
+ return {
+ "title": "[Browser] Current Page Title",
+ "url": "[Browser] https://example.com",
+ "description": "Page description from meta tag",
+ "keywords": "web, mcp, fastmcp"
+ }
+
+@mcp.tool
+async def extract_form_data(form_selector: str = "form") -> Dict[str, Any]:
+ """
+ Extract current values from web forms on the page.
+ Allows LLM to understand user input and form state.
+
+ Args:
+ form_selector: CSS selector for the form to analyze
+ """
+ # Browser implementation would iterate through form elements:
+ # form = document.querySelector(form_selector)
+ # Extract input values, selections, etc.
+ return {
+ "form_found": True,
+ "fields": {
+ "username": "user_input_value",
+ "email": "user@example.com",
+ "preferences": ["option1", "option2"]
+ }
+ }
+
+@mcp.tool
+async def make_authenticated_request(
+ url: str,
+ method: str = "GET",
+ include_cookies: bool = True
+) -> str:
+ """
+ Make HTTP request with user's authentication context.
+ This allows the LLM to access APIs the user has access to.
+
+ Args:
+ url: The URL to request
+ method: HTTP method (GET, POST, etc.)
+ include_cookies: Whether to include cookies for authentication
+ """
+ # Browser implementation using fetch API:
+ # from js import fetch
+ # response = await fetch(url, {
+ # "method": method,
+ # "credentials": "include" if include_cookies else "omit",
+ # "headers": {"Content-Type": "application/json"}
+ # })
+ # return await response.text()
+ return f"[Browser] Would make {method} request to {url} with cookies: {include_cookies}"
+
+@mcp.tool
+async def get_user_session_info() -> Dict[str, Any]:
+ """
+ Get information about the user's current session.
+ Helps LLM understand user context and permissions.
+ """
+ # Browser implementation:
+ # from js import document, navigator, localStorage
+ # return {
+ # "cookies": document.cookie,
+ # "localStorage_keys": list(localStorage.keys()),
+ # "userAgent": navigator.userAgent,
+ # "language": navigator.language
+ # }
+ return {
+ "session_active": True,
+ "user_preferences": {"theme": "dark", "language": "en"},
+ "permissions": ["read", "write"],
+ "browser": "Chrome/Safari/Firefox"
+ }
+
+@mcp.tool
+async def inject_content(selector: str, content: str, mode: str = "replace") -> str:
+ """
+ Inject content into the web page at specified location.
+ Allows LLM to make live updates to the UI.
+
+ Args:
+ selector: CSS selector for target element
+ content: HTML/text content to inject
+ mode: How to inject - "replace", "append", "prepend"
+ """
+ # Browser implementation:
+ # element = document.querySelector(selector)
+ # if mode == "replace":
+ # element.innerHTML = content
+ # elif mode == "append":
+ # element.innerHTML += content
+ # elif mode == "prepend":
+ # element.innerHTML = content + element.innerHTML
+ return f"[Browser] Would {mode} content in {selector}: {content[:50]}..."
+
+@mcp.resource("page://current")
+async def current_page_resource() -> str:
+ """Resource providing the current page's full content"""
+ return "[Browser] Full current page HTML content would be returned here"
+
+@mcp.resource("session://user")
+async def user_session_resource() -> Dict[str, Any]:
+ """Resource providing user session data"""
+ return {
+ "authenticated": True,
+ "user_id": "user_123",
+ "permissions": ["read_content", "make_requests"],
+ "session_start": "2024-01-15T10:30:00Z"
+ }
+
+@mcp.prompt("web_context")
+async def web_context_prompt(task: str) -> str:
+ """
+ Generate a prompt with current web page context for the LLM.
+
+ Args:
+ task: The task the LLM should perform
+ """
+ return f"""
+You are an AI assistant with access to the user's current web browser session.
+
+Current Context:
+- Page: [Browser] Current page title and URL
+- Available Tools: {list(mcp.tools.keys())}
+- User Task: {task}
+
+You can:
+1. Read content from the current page
+2. Make authenticated requests using the user's cookies
+3. Extract form data and user inputs
+4. Update page content dynamically
+5. Access user session information
+
+How can I help you with: {task}
+"""
+
+# Export the server for use in different contexts
+__all__ = ["mcp"]
+
+if __name__ == "__main__":
+ # This would run in a standard Python environment
+ # In browser, the server would be imported and used directly
+ print(f"FastMCP Browser Server '{mcp.name}' ready")
+ print(f"Tools: {list(mcp.tools.keys())}")
+ print(f"Resources: {list(mcp.resources.keys())}")
+ print(f"Prompts: {list(mcp.prompts.keys())}")
\ No newline at end of file
diff --git a/examples/pyscript_browser_demo.html b/examples/pyscript_browser_demo.html
new file mode 100644
index 000000000..93f73f2fc
--- /dev/null
+++ b/examples/pyscript_browser_demo.html
@@ -0,0 +1,286 @@
+
+
+
+
+
+ FastMCP PyScript Browser Demo
+
+
+
+
+
+
+
+
š FastMCP in the Browser with PyScript
+
This demo shows FastMCP running directly in your browser, with tools that can access web page content and make AJAX calls.
+
+
+
+
Web Page Content
+
+
Sample Web Content
+
This is some sample content that our MCP tools can access.
+
Current time:
+
User data: Loading...
+
+
+
+
+
+
MCP Server Controls
+
+
+
+
+
+
+
+
+
Implementation Details
+
This demo showcases:
+
+
DOM Access: Tools that can read and interact with page elements
+
AJAX Calls: Tools that can make HTTP requests with user cookies
+
Client-Side MCP: Full MCP server running in the browser
+
Real-time Updates: Dynamic content that tools can observe
+
+
+
+
+
+ packages = ["pydantic", "typing-extensions"]
+
+
+
+import asyncio
+from js import document, fetch, console, JSON
+from pyodide.ffi import create_proxy, to_js
+import json
+import time
+from typing import Any, Dict
+
+# Mock FastMCP classes for browser environment
+class FastMCP:
+ def __init__(self, name: str):
+ self.name = name
+ self.tools = {}
+ self.resources = {}
+
+ def tool(self, func):
+ """Register a tool function"""
+ self.tools[func.__name__] = func
+ return func
+
+ def resource(self, uri_template):
+ """Register a resource function"""
+ def decorator(func):
+ self.resources[uri_template] = func
+ return func
+ return decorator
+
+ async def call_tool(self, name: str, args: Dict[str, Any]) -> Any:
+ """Call a registered tool"""
+ if name in self.tools:
+ return await self.tools[name](**args)
+ else:
+ raise ValueError(f"Tool {name} not found")
+
+# Create our FastMCP server instance
+mcp = FastMCP("Browser MCP Server")
+
+@mcp.tool
+async def get_page_content(selector: str = "body") -> str:
+ """Get content from the current web page using CSS selector"""
+ try:
+ element = document.querySelector(selector)
+ if element:
+ return element.textContent or element.innerHTML
+ else:
+ return f"No element found with selector: {selector}"
+ except Exception as e:
+ return f"Error accessing DOM: {str(e)}"
+
+@mcp.tool
+async def get_page_title() -> str:
+ """Get the current page title"""
+ return document.title
+
+@mcp.tool
+async def update_page_element(selector: str, content: str) -> str:
+ """Update content of a page element"""
+ try:
+ element = document.querySelector(selector)
+ if element:
+ element.innerHTML = content
+ return f"Updated element {selector} with new content"
+ else:
+ return f"Element not found: {selector}"
+ except Exception as e:
+ return f"Error updating element: {str(e)}"
+
+@mcp.tool
+async def make_ajax_request(url: str, method: str = "GET") -> str:
+ """Make an AJAX request (cookies will be included automatically)"""
+ try:
+ # Use JavaScript fetch API from Python
+ response = await fetch(url, to_js({
+ "method": method,
+ "credentials": "include", # Include cookies
+ "headers": {
+ "Content-Type": "application/json"
+ }
+ }))
+
+ if response.ok:
+ text_data = await response.text()
+ return f"Request to {url} successful: {text_data[:200]}..."
+ else:
+ return f"Request failed with status: {response.status}"
+ except Exception as e:
+ return f"Error making request: {str(e)}"
+
+@mcp.tool
+async def get_cookies() -> str:
+ """Get current page cookies"""
+ try:
+ cookies = document.cookie
+ if cookies:
+ return f"Current cookies: {cookies}"
+ else:
+ return "No cookies found"
+ except Exception as e:
+ return f"Error accessing cookies: {str(e)}"
+
+@mcp.tool
+async def get_current_url() -> str:
+ """Get the current page URL"""
+ return document.location.href
+
+@mcp.resource("page://content")
+async def page_content_resource():
+ """Resource that provides current page content"""
+ return document.body.textContent
+
+def log_output(message: str):
+ """Helper to log output to the page"""
+ output_element = document.getElementById("mcp-output")
+ current_content = output_element.textContent
+ output_element.textContent = current_content + "\n" + str(message)
+
+async def run_mcp_demo(*args):
+ """Main demo function"""
+ try:
+ log_output("š Starting FastMCP Browser Demo...")
+ log_output(f"Server name: {mcp.name}")
+ log_output(f"Registered tools: {list(mcp.tools.keys())}")
+ log_output(f"Registered resources: {list(mcp.resources.keys())}")
+
+ # Test basic tool calls
+ title = await mcp.call_tool("get_page_title", {})
+ log_output(f"Page title: {title}")
+
+ url = await mcp.call_tool("get_current_url", {})
+ log_output(f"Current URL: {url}")
+
+ log_output("ā MCP Server demo completed successfully!")
+
+ except Exception as e:
+ log_output(f"ā Error: {str(e)}")
+
+async def test_dom_access(*args):
+ """Test DOM access tools"""
+ try:
+ log_output("\nš Testing DOM Access...")
+
+ # Get sample content
+ content = await mcp.call_tool("get_page_content", {"selector": "#sample-content"})
+ log_output(f"Sample content: {content[:100]}...")
+
+ # Update an element
+ current_time = time.strftime("%H:%M:%S")
+ result = await mcp.call_tool("update_page_element", {
+ "selector": "#current-time",
+ "content": current_time
+ })
+ log_output(result)
+
+ except Exception as e:
+ log_output(f"ā DOM Access Error: {str(e)}")
+
+async def test_ajax_tool(*args):
+ """Test AJAX functionality"""
+ try:
+ log_output("\nš Testing AJAX Tool...")
+
+ # Make a simple request to JSONPlaceholder API
+ result = await mcp.call_tool("make_ajax_request", {
+ "url": "https://jsonplaceholder.typicode.com/posts/1"
+ })
+ log_output(result)
+
+ except Exception as e:
+ log_output(f"ā AJAX Error: {str(e)}")
+
+async def test_cookie_tool(*args):
+ """Test cookie access"""
+ try:
+ log_output("\nšŖ Testing Cookie Access...")
+
+ # Set a test cookie first
+ document.cookie = "fastmcp_demo=test_value; path=/"
+
+ result = await mcp.call_tool("get_cookies", {})
+ log_output(result)
+
+ except Exception as e:
+ log_output(f"ā Cookie Error: {str(e)}")
+
+# Register event handlers
+run_mcp_demo_proxy = create_proxy(run_mcp_demo)
+test_dom_access_proxy = create_proxy(test_dom_access)
+test_ajax_tool_proxy = create_proxy(test_ajax_tool)
+test_cookie_tool_proxy = create_proxy(test_cookie_tool)
+
+# Make functions available globally
+globals()['run_mcp_demo'] = run_mcp_demo_proxy
+globals()['test_dom_access'] = test_dom_access_proxy
+globals()['test_ajax_tool'] = test_ajax_tool_proxy
+globals()['test_cookie_tool'] = test_cookie_tool_proxy
+
+# Initialize demo
+log_output("FastMCP PyScript Demo Loaded! Click buttons above to test.")
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/pyscript_integration_guide.md b/examples/pyscript_integration_guide.md
new file mode 100644
index 000000000..567d6c2ee
--- /dev/null
+++ b/examples/pyscript_integration_guide.md
@@ -0,0 +1,228 @@
+# FastMCP + PyScript Browser Integration Guide
+
+This guide demonstrates how to run FastMCP servers in the browser using PyScript, enabling web applications to provide LLM context through the Model Context Protocol.
+
+## Use Cases
+
+### 1. Chatbot Web Integration
+- **Problem**: Web chatbots lack access to current page content, user session, and authenticated APIs
+- **Solution**: FastMCP tools can read DOM, access cookies, and make authenticated requests
+
+### 2. Context-Aware Web Assistants
+- **Problem**: AI assistants need understanding of current user context in web apps
+- **Solution**: MCP resources provide real-time page state, form data, and session info
+
+### 3. Dynamic Content Generation
+- **Problem**: AI needs to update web UI based on conversation
+- **Solution**: MCP tools can inject content, update elements, and modify page state
+
+## Implementation Approaches
+
+### Approach 1: Pure PyScript (Demo)
+```python
+# Simplified FastMCP implementation for browser
+class FastMCP:
+ def __init__(self, name: str):
+ self.name = name
+ self.tools = {}
+
+ def tool(self, func):
+ self.tools[func.__name__] = func
+ return func
+
+# Browser-specific tools
+@mcp.tool
+async def get_page_content(selector: str) -> str:
+ from js import document
+ element = document.querySelector(selector)
+ return element.textContent if element else ""
+```
+
+### Approach 2: Hybrid Client-Server
+```python
+# Server runs FastMCP normally
+# Browser client connects via WebSocket/HTTP
+# Tools proxy between browser DOM and server
+
+# Browser side
+async def proxy_dom_access(selector: str) -> str:
+ content = document.querySelector(selector).textContent
+ return await send_to_server("dom_content", {"content": content})
+```
+
+### Approach 3: FastMCP Lite (Recommended)
+```python
+# Subset of FastMCP optimized for browser
+# Direct DOM integration
+# Minimal dependencies
+```
+
+## PyScript Compatibility Analysis
+
+### Compatible Components ā
+- **Core FastMCP classes**: Server, tool decorators, resource management
+- **Pydantic models**: For data validation and serialization
+- **Basic HTTP clients**: Using fetch API through JS interop
+- **JSON/dict operations**: Native Python data handling
+
+### Incompatible Components ā
+- **HTTPX**: Uses threading/async libraries not available in PyScript
+- **Rich console**: Terminal formatting not relevant in browser
+- **File system operations**: Browser security restrictions
+- **Process management**: No subprocess support in browser
+
+### Workarounds š§
+- Replace HTTPX with JavaScript fetch API
+- Use browser console instead of Rich
+- Store data in localStorage/sessionStorage instead of files
+- Use Web Workers for concurrent operations
+
+## Browser Security Considerations
+
+### Same-Origin Policy
+```python
+@mcp.tool
+async def make_request(url: str) -> str:
+ # Must respect CORS policies
+ # Can only access same-origin or CORS-enabled endpoints
+ response = await fetch(url, {"credentials": "include"})
+ return await response.text()
+```
+
+### Cookie Access
+```python
+@mcp.tool
+async def get_auth_context() -> dict:
+ # Can access cookies for same domain
+ # Enables authenticated API calls
+ from js import document
+ return {"cookies": document.cookie}
+```
+
+### DOM Manipulation
+```python
+@mcp.tool
+async def update_ui(selector: str, content: str) -> str:
+ # Full DOM access within page
+ # Can modify any page element
+ element = document.querySelector(selector)
+ element.innerHTML = content
+ return "Updated successfully"
+```
+
+## Integration Examples
+
+### Example 1: E-commerce Assistant
+```python
+@mcp.tool
+async def get_cart_items() -> list:
+ """Read current shopping cart contents"""
+ cart_elements = document.querySelectorAll('.cart-item')
+ return [item.textContent for item in cart_elements]
+
+@mcp.tool
+async def get_product_details() -> dict:
+ """Extract current product information"""
+ return {
+ "name": document.querySelector('.product-name').textContent,
+ "price": document.querySelector('.price').textContent,
+ "availability": document.querySelector('.stock-status').textContent
+ }
+```
+
+### Example 2: Dashboard Analytics
+```python
+@mcp.tool
+async def get_dashboard_metrics() -> dict:
+ """Read current dashboard metrics"""
+ return {
+ "revenue": document.querySelector('#revenue').textContent,
+ "users": document.querySelector('#active-users').textContent,
+ "conversion": document.querySelector('#conversion-rate').textContent
+ }
+
+@mcp.tool
+async def update_dashboard_filter(date_range: str) -> str:
+ """Update dashboard date filter"""
+ filter_select = document.querySelector('#date-filter')
+ filter_select.value = date_range
+ filter_select.dispatchEvent(Event('change'))
+ return f"Updated filter to {date_range}"
+```
+
+### Example 3: Form Assistant
+```python
+@mcp.tool
+async def analyze_form_fields() -> dict:
+ """Analyze current form state and validation"""
+ form = document.querySelector('form')
+ fields = {}
+
+ for input_elem in form.querySelectorAll('input, select, textarea'):
+ fields[input_elem.name] = {
+ "value": input_elem.value,
+ "valid": input_elem.checkValidity(),
+ "required": input_elem.required
+ }
+
+ return fields
+
+@mcp.tool
+async def fill_form_field(field_name: str, value: str) -> str:
+ """Fill a form field with provided value"""
+ field = document.querySelector(f'[name="{field_name}"]')
+ if field:
+ field.value = value
+ field.dispatchEvent(Event('input'))
+ return f"Filled {field_name} with {value}"
+ return f"Field {field_name} not found"
+```
+
+## Performance Considerations
+
+### Memory Management
+- PyScript runs in browser memory constraints
+- Limit large data processing in tools
+- Use streaming for large responses
+
+### Async Operations
+- All browser APIs are async
+- FastMCP tools should use async/await
+- Consider request timeouts
+
+### Bundle Size
+- PyScript loads full Python runtime
+- Minimize dependencies
+- Consider lazy loading for complex tools
+
+## Getting Started
+
+1. **Create HTML page** with PyScript CDN
+2. **Define FastMCP server** with browser-specific tools
+3. **Test DOM access** and API integration
+4. **Add error handling** for browser-specific issues
+5. **Deploy and test** in target browsers
+
+## Deployment Options
+
+### Static Hosting
+- Deploy HTML + PyScript to CDN
+- No server required for basic functionality
+- Suitable for client-side only features
+
+### Hybrid Architecture
+- FastMCP server for heavy processing
+- Browser client for UI interaction
+- WebSocket connection between them
+
+### Progressive Enhancement
+- Start with basic web functionality
+- Add MCP features as enhancement layer
+- Graceful degradation if PyScript fails
+
+## Future Possibilities
+
+- **WebAssembly integration**: Faster Python execution
+- **Service Worker**: Background MCP processing
+- **Web Components**: Reusable MCP-enabled UI elements
+- **Extension APIs**: Browser extension integration
\ No newline at end of file
diff --git a/examples/simple_browser_demo.html b/examples/simple_browser_demo.html
new file mode 100644
index 000000000..3351385cb
--- /dev/null
+++ b/examples/simple_browser_demo.html
@@ -0,0 +1,341 @@
+
+
+
+
+
+ FastMCP Browser Demo - Simple Example
+
+
+
+
+
+
+
š FastMCP + PyScript
+
Browser-based MCP Server Demo
+
Making web content accessible to LLMs through the Model Context Protocol
+
+
+
+
šÆ Use Case: Chatbot Web Integration
+
This demonstrates how a chatbot integrated into a web application can access page content, user session data, and make authenticated API calls using FastMCP.
+
+
+
š Sample Web Application Content
+
User:john.doe@example.com
+
Current Page: Dashboard
+
Last Updated:Loading...
+
Session ID:abc123def456
+
+
+
+
+
+
+
+
+
š MCP Tools Demo
+
Click buttons below to test MCP tools that can access web page content:
+
+
+
+
+
+
+
+
FastMCP tools ready. Click buttons above to test functionality.
+
+
+
+
š” How This Enables LLM Context
+
+
Page Awareness: LLM can understand what user is currently viewing
+
Session Context: Access to user preferences, authentication state
+
Form Interaction: Can help fill forms or validate user input
+
API Access: Make authenticated requests using user's cookies
+
Dynamic Updates: Modify page content based on conversation
+
+
+
+
+ packages = []
+
+
+
+import asyncio
+from js import document, console, JSON, fetch, Date
+import json
+import time
+from pyodide.ffi import create_proxy
+
+# Lightweight FastMCP implementation for browser
+class BrowserMCP:
+ def __init__(self, name: str):
+ self.name = name
+ self.tools = {}
+
+ def tool(self, func):
+ """Register a tool function"""
+ self.tools[func.__name__] = func
+ return func
+
+ async def call_tool(self, name: str, **kwargs):
+ """Call a registered tool"""
+ if name in self.tools:
+ try:
+ return await self.tools[name](**kwargs)
+ except Exception as e:
+ return f"Error in tool {name}: {str(e)}"
+ else:
+ return f"Tool {name} not found"
+
+# Create MCP server
+mcp = BrowserMCP("Web Context Server")
+
+@mcp.tool
+async def read_page_content(selector: str = "body") -> dict:
+ """Read content from the current web page"""
+ try:
+ if selector == "body":
+ title = document.title
+ url = document.location.href
+ text_content = document.body.textContent[:500] # Limit content
+ return {
+ "title": title,
+ "url": url,
+ "content_preview": text_content,
+ "success": True
+ }
+ else:
+ element = document.querySelector(selector)
+ if element:
+ return {
+ "selector": selector,
+ "content": element.textContent,
+ "html": element.innerHTML,
+ "success": True
+ }
+ else:
+ return {"error": f"Element not found: {selector}", "success": False}
+ except Exception as e:
+ return {"error": str(e), "success": False}
+
+@mcp.tool
+async def get_user_context() -> dict:
+ """Extract user context from the current page"""
+ try:
+ username = document.getElementById("username").textContent if document.getElementById("username") else "Unknown"
+ session_id = document.getElementById("session-id").textContent if document.getElementById("session-id") else "None"
+ theme = document.getElementById("theme-selector").value if document.getElementById("theme-selector") else "light"
+
+ return {
+ "username": username,
+ "session_id": session_id,
+ "theme": theme,
+ "page_title": document.title,
+ "url": document.location.href,
+ "user_agent": document.navigator.userAgent,
+ "timestamp": Date.new().toISOString(),
+ "success": True
+ }
+ except Exception as e:
+ return {"error": str(e), "success": False}
+
+@mcp.tool
+async def extract_form_data() -> dict:
+ """Extract data from forms on the page"""
+ try:
+ form_data = {}
+
+ # Get theme selector
+ theme_selector = document.getElementById("theme-selector")
+ if theme_selector:
+ form_data["theme"] = theme_selector.value
+
+ # Get any input elements
+ inputs = document.querySelectorAll("input")
+ for i in range(inputs.length):
+ input_elem = inputs[i]
+ if input_elem.name:
+ form_data[input_elem.name] = input_elem.value
+
+ return {
+ "form_data": form_data,
+ "form_count": len(form_data),
+ "success": True
+ }
+ except Exception as e:
+ return {"error": str(e), "success": False}
+
+@mcp.tool
+async def simulate_api_call(endpoint: str = "/api/user/profile") -> dict:
+ """Simulate making an authenticated API call"""
+ try:
+ # In real implementation, this would use:
+ # response = await fetch(endpoint, {"credentials": "include"})
+ # For demo, we simulate the response
+
+ simulated_response = {
+ "endpoint": endpoint,
+ "method": "GET",
+ "status": 200,
+ "data": {
+ "user_id": "12345",
+ "email": "john.doe@example.com",
+ "preferences": {
+ "theme": "light",
+ "notifications": True
+ },
+ "last_login": "2024-01-15T10:30:00Z"
+ },
+ "cookies_included": True,
+ "success": True
+ }
+
+ return simulated_response
+ except Exception as e:
+ return {"error": str(e), "success": False}
+
+@mcp.tool
+async def update_page_element(element_id: str, new_content: str) -> dict:
+ """Update content of a page element"""
+ try:
+ element = document.getElementById(element_id)
+ if element:
+ element.textContent = new_content
+ return {
+ "element_id": element_id,
+ "new_content": new_content,
+ "success": True
+ }
+ else:
+ return {"error": f"Element with ID '{element_id}' not found", "success": False}
+ except Exception as e:
+ return {"error": str(e), "success": False}
+
+def log_output(message):
+ """Helper to display output"""
+ output_elem = document.getElementById("tool-output")
+ if isinstance(message, dict):
+ message = json.dumps(message, indent=2)
+ output_elem.textContent = str(message)
+
+async def demo_page_reading():
+ """Demo reading page content"""
+ result = await mcp.call_tool("read_page_content")
+ log_output(f"š Page Content Tool Result:\n{json.dumps(result, indent=2)}")
+
+async def demo_user_context():
+ """Demo getting user context"""
+ result = await mcp.call_tool("get_user_context")
+ log_output(f"š¤ User Context Tool Result:\n{json.dumps(result, indent=2)}")
+
+async def demo_form_data():
+ """Demo extracting form data"""
+ result = await mcp.call_tool("extract_form_data")
+ log_output(f"š Form Data Tool Result:\n{json.dumps(result, indent=2)}")
+
+async def demo_api_simulation():
+ """Demo API call simulation"""
+ result = await mcp.call_tool("simulate_api_call", endpoint="/api/dashboard/stats")
+ log_output(f"š API Call Tool Result:\n{json.dumps(result, indent=2)}")
+
+async def demo_update_content():
+ """Demo updating page content"""
+ new_time = Date.new().toLocaleTimeString()
+ result = await mcp.call_tool("update_page_element", element_id="timestamp", new_content=new_time)
+ log_output(f"āļø Update Content Tool Result:\n{json.dumps(result, indent=2)}")
+
+# Create proxies for event handlers
+demo_page_reading_proxy = create_proxy(demo_page_reading)
+demo_user_context_proxy = create_proxy(demo_user_context)
+demo_form_data_proxy = create_proxy(demo_form_data)
+demo_api_simulation_proxy = create_proxy(demo_api_simulation)
+demo_update_content_proxy = create_proxy(demo_update_content)
+
+# Make functions available globally
+globals()['demo_page_reading'] = demo_page_reading_proxy
+globals()['demo_user_context'] = demo_user_context_proxy
+globals()['demo_form_data'] = demo_form_data_proxy
+globals()['demo_api_simulation'] = demo_api_simulation_proxy
+globals()['demo_update_content'] = demo_update_content_proxy
+
+# Initialize
+def update_timestamp():
+ timestamp_elem = document.getElementById("timestamp")
+ if timestamp_elem:
+ timestamp_elem.textContent = Date.new().toLocaleString()
+
+update_timestamp()
+console.log("FastMCP Browser Demo initialized successfully!")
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/test_browser_demo.py b/examples/test_browser_demo.py
new file mode 100644
index 000000000..528bc77df
--- /dev/null
+++ b/examples/test_browser_demo.py
@@ -0,0 +1,118 @@
+#!/usr/bin/env python3
+"""
+Test script for browser demo files
+"""
+import os
+import sys
+
+def test_html_files():
+ """Test that HTML demo files are properly structured"""
+ html_files = [
+ 'simple_browser_demo.html',
+ 'pyscript_browser_demo.html'
+ ]
+
+ for filename in html_files:
+ filepath = os.path.join('examples', filename)
+ if not os.path.exists(filepath):
+ print(f"ā {filename}: File not found")
+ continue
+
+ with open(filepath, 'r') as f:
+ content = f.read()
+
+ # Basic HTML validation
+ if not content.startswith(''):
+ print(f"ā {filename}: Missing DOCTYPE")
+ continue
+
+ if '