plot_math_function
Generate 2D plots of mathematical functions using Desmos API or local rendering to visualize equations with customizable x and y ranges.
Instructions
Generates a 2D plot. Tries Desmos API if available, otherwise falls back to local rendering.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| formula | Yes | ||
| x_range | No | ||
| y_range | No | ||
| use_api | No |
Implementation Reference
- src/main.py:102-172 (handler)The main handler function for the 'plot_math_function' tool. It handles plotting using Desmos API if available, falling back to local SymPy rendering, and returns a base64-encoded image URI.@mcp.tool() async def plot_math_function( ctx: MCPContext, formula: str, x_range: Optional[List[float]] = [-10, 10], y_range: Optional[List[float]] = None, use_api: bool = True ) -> str: """Generates a 2D plot. Tries Desmos API if available, otherwise falls back to local rendering.""" await ctx.progress.start(message="Initializing plot...") if use_api and desmos_client: ctx.info("Attempting to plot with Desmos API...") await ctx.progress.report(1, 2, "Calling Desmos API...") try: image_bytes = await desmos_client.plot_formula(formula, x_range, y_range) if image_bytes: await ctx.progress.report(2, 2, "Encoding image...") img_base64 = base64.b64encode(image_bytes).decode('utf-8') data_uri = f"data:image/png;base64,{img_base64}" await ctx.progress.end() return f"Successfully plotted '{formula}' using Desmos API. Image: {data_uri}" else: ctx.warning("Desmos API call failed, falling back to local rendering.") except Exception as e: ctx.error(f"An exception occurred with Desmos API: {e}. Falling back to local rendering.") ctx.info("Using local rendering...") try: await ctx.progress.start(total=3, message="Starting local rendering...") await ctx.progress.report(1, 3, "Parsing formula...") expr = sympy.sympify(formula) x = sympy.symbols('x') await ctx.progress.report(2, 3, "Generating plot data...") plot_kwargs = { 'show': False, 'xlabel': 'x', 'ylabel': 'y', 'title': formula } if x_range: plot_kwargs['xlim'] = x_range if y_range: plot_kwargs['ylim'] = y_range p = sympy.plot(expr, (x, x_range[0], x_range[1]), **plot_kwargs) # Save the plot to a file desktop_path = os.path.join(os.path.expanduser('~'), 'Desktop') save_dir = os.path.join(desktop_path, 'Desmos-MCP') os.makedirs(save_dir, exist_ok=True) timestamp = datetime.now().strftime("%Y%m%d%H%M%S") filename = f"plot_{timestamp}.png" p.save(os.path.join(save_dir, filename)) await ctx.progress.report(3, 3, "Encoding image...") buf = io.BytesIO() p.save(buf) buf.seek(0) img_base64 = base64.b64encode(buf.read()).decode('utf-8') data_uri = f"data:image/png;base64,{img_base64}" await ctx.progress.end() return f"Successfully plotted '{formula}' using local rendering. Image: {data_uri}" except Exception as e: await ctx.progress.end() return f"Error plotting formula '{formula}' locally. Details: {e}"
- src/desmos_api.py:17-41 (helper)Supporting method in DesmosAPIClient that performs the actual API call to plot the formula, used by the main handler when use_api is True.async def plot_formula(self, formula: str, x_range: List[float], y_range: List[float]) -> Optional[bytes]: """Requests a plot from the Desmos API and returns the image bytes.""" headers = { "Authorization": f"Bearer {self.api_key}" } # 注意:此处的 payload 结构是基于通用 API 设计的推断,可能需要根据实际的 Desmos API 文档进行调整 payload = { "formula": formula, "x_range": x_range, "y_range": y_range, "format": "png" } async with httpx.AsyncClient() as client: try: response = await client.post(f"{API_BASE_URL}/plot", headers=headers, json=payload, timeout=15.0) response.raise_for_status() # 如果状态码是 4xx 或 5xx,则引发异常 return response.content except httpx.HTTPStatusError as e: print(f"Desmos API returned an error: {e.response.status_code} {e.response.text}") return None except httpx.RequestError as e: print(f"Error connecting to Desmos API: {e}") return None