stepsearch.py 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
  1. import json
  2. import time
  3. from typing import Any, Dict, List, Optional
  4. import requests
  5. from app.core.config import settings
  6. class StepSearchMCPClient:
  7. """Small synchronous Streamable HTTP MCP client for StepSearch."""
  8. def __init__(self, timeout: float = 45.0):
  9. self.endpoint = settings.final_base_url.rstrip("/") + "/mcp/web_search/mcp"
  10. self.timeout = timeout
  11. self._next_id = 1
  12. def _call(self, method: str, params: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
  13. request_id = self._next_id
  14. self._next_id += 1
  15. response = requests.post(
  16. self.endpoint,
  17. headers={
  18. "Authorization": f"Bearer {settings.final_api_key}",
  19. "Accept": "application/json, text/event-stream",
  20. "Content-Type": "application/json",
  21. },
  22. json={"jsonrpc": "2.0", "id": request_id, "method": method, "params": params or {}},
  23. timeout=self.timeout,
  24. )
  25. response.raise_for_status()
  26. payload = response.json()
  27. if payload.get("error"):
  28. raise RuntimeError("StepSearch MCP request failed")
  29. return payload.get("result") or {}
  30. def call_tool(self, name: str, arguments: Dict[str, Any]) -> Dict[str, Any]:
  31. return self._call("tools/call", {"name": name, "arguments": arguments})
  32. @staticmethod
  33. def text(result: Dict[str, Any]) -> str:
  34. chunks = []
  35. for item in result.get("content", []):
  36. if isinstance(item, dict) and item.get("type") == "text":
  37. chunks.append(str(item.get("text", "")))
  38. return "\n".join(chunks)
  39. class StepSearchPersonaTool:
  40. def __init__(self, client: Optional[StepSearchMCPClient] = None):
  41. self.client = client or StepSearchMCPClient()
  42. def search(self, query: str, n: int = 5) -> str:
  43. result = self.client.call_tool("web_search", {"query": query, "n": n, "use_common_search": True})
  44. return self.client.text(result) or "未找到可用搜索结果"
  45. def fetch(self, url: str) -> str:
  46. result = self.client.call_tool("web_fetch", {"url": url})
  47. return self.client.text(result) or "未找到网页内容"