Search with Bocha AI Search, recognizes the semantics of search terms and additionally returns structured modal cards with content from vertical domains. Args: query: Search query (required) freshness: The time range for the search results. (Available options noLimit, oneYea
(
query: str, freshness: str = "noLimit", count: int = 10
)
| 113 | |
| 114 | @server.tool() |
| 115 | async def bocha_ai_search( |
| 116 | query: str, freshness: str = "noLimit", count: int = 10 |
| 117 | ) -> str: |
| 118 | """Search with Bocha AI Search, recognizes the semantics of search terms |
| 119 | and additionally returns structured modal cards with content from vertical domains. |
| 120 | |
| 121 | Args: |
| 122 | query: Search query (required) |
| 123 | freshness: The time range for the search results. (Available options noLimit, oneYear, oneMonth, oneWeek, oneDay. Default is noLimit) |
| 124 | count: Number of results (1-50, default 10) |
| 125 | """ |
| 126 | # Get API key from environment |
| 127 | boch_api_key = os.environ.get("BOCHA_API_KEY", "") |
| 128 | |
| 129 | if not boch_api_key: |
| 130 | return ( |
| 131 | "Error: Bocha API key is not configured. Please set the " |
| 132 | "BOCHA_API_KEY environment variable." |
| 133 | ) |
| 134 | |
| 135 | # Endpoint |
| 136 | endpoint = "https://api.bochaai.com/v1/ai-search?utm_source=bocha-mcp-local" |
| 137 | |
| 138 | try: |
| 139 | payload = { |
| 140 | "query": query, |
| 141 | "freshness": freshness, |
| 142 | "count": count, |
| 143 | "answer": False, |
| 144 | "stream": False, |
| 145 | } |
| 146 | |
| 147 | headers = { |
| 148 | "Authorization": f"Bearer {boch_api_key}", |
| 149 | "Content-Type": "application/json", |
| 150 | } |
| 151 | |
| 152 | async with httpx.AsyncClient() as client: |
| 153 | response = await client.post( |
| 154 | endpoint, headers=headers, json=payload, timeout=10.0 |
| 155 | ) |
| 156 | |
| 157 | response.raise_for_status() |
| 158 | response = response.json() |
| 159 | results = [] |
| 160 | if "messages" in response: |
| 161 | for message in response["messages"]: |
| 162 | content = {} |
| 163 | try: |
| 164 | content = json.loads(message["content"]) |
| 165 | except (json.JSONDecodeError, TypeError): |
| 166 | content = {} |
| 167 | |
| 168 | # 网页 |
| 169 | if message["content_type"] == "webpage": |
| 170 | if "value" in content: |
| 171 | for item in content["value"]: |
| 172 | results.append( |