MCP-wolfram-alpha

by SecretiveShell
Verified
MIT License
18
import base64 from mcp.server.models import InitializationOptions from mcp.server.lowlevel import NotificationOptions, Server import mcp.types as types import mcp.server.stdio from .wolfram_client import client import httpx server = Server("MCP-wolfram-alpha") @server.list_prompts() async def handle_list_prompts() -> list[types.Prompt]: """ List available prompts. """ return [ types.Prompt( name="wa", description="Ask Wolfram Alpha a question", arguments=[ types.PromptArgument( name="query", description="query to ask Wolfram Alpha", required=True, ) ], ) ] @server.get_prompt() async def handle_get_prompt( name: str, arguments: dict[str, str] | None ) -> types.GetPromptResult: """ Generate a prompt by combining arguments with server state. """ # TODO: Implement checks for this assert arguments is not None, "Arguments are required" return types.GetPromptResult( description="Ask Wolfram Alpha a question", messages=[ types.PromptMessage( role="user", content=types.TextContent( type="text", text=f"Use wolfram alpha to answer the following question: {arguments['query']}", ), ) ], ) @server.list_tools() async def handle_list_tools() -> list[types.Tool]: """ List available tools. Each tool specifies its arguments using JSON Schema validation. """ return [ types.Tool( name="query-wolfram-alpha", description="Use Wolfram Alpha to answer a question. This tool should be used when you need complex math or symbolic intelligence.", inputSchema={ "type": "object", "properties": { "query": {"type": "string"} # Correct property: `query` with type `string` }, "required": ["query"] # Marking `query` as required }, ) ] @server.call_tool() async def handle_call_tool( name: str, arguments: dict | None ) -> list[types.TextContent | types.ImageContent | types.EmbeddedResource]: """ Handle tool execution requests. Tools can modify server state and notify clients of changes. """ if not arguments: raise ValueError("Missing arguments") if name == "query-wolfram-alpha": results: list[types.TextContent | types.ImageContent | types.EmbeddedResource] = [] query = arguments.get("query") if not query: raise ValueError("Missing 'query' parameter for Wolfram Alpha tool") try: response = await client.aquery(query) except Exception as e: raise Exception("Failed to query Wolfram Alpha") from e try: async with httpx.AsyncClient() as http_client: for pod in response.pods: for subpod in pod.subpods: if subpod.get("plaintext"): # Handle text content results.append(types.TextContent( type="text", text=subpod.plaintext )) elif subpod.get("img"): # Handle image content img_url = subpod.img["@src"] img_response = await http_client.get(img_url) if img_response.status_code == 200: img_base64 = base64.b64encode(img_response.content).decode('utf-8') results.append(types.ImageContent( type="image", data=img_base64, mimeType="image/png" )) except Exception as e: raise Exception("Failed to parse response from Wolfram Alpha") from e return results raise ValueError(f"Unknown tool: {name}") async def main(): # Run the server using stdin/stdout streams async with mcp.server.stdio.stdio_server() as (read_stream, write_stream): await server.run( read_stream, write_stream, InitializationOptions( server_name="MCP-wolfram-alpha", server_version="0.2.1", capabilities=server.get_capabilities( notification_options=NotificationOptions(), experimental_capabilities={}, ), ), )