├── .env.example ├── .gitignore ├── LICENSE ├── README.md ├── google_open_api.yaml ├── mcp_server.py ├── requirements.txt └── tests └── test_get_current_time.py /.env.example: -------------------------------------------------------------------------------- 1 | # SearchAPI.io API密钥 2 | SEARCHAPI_API_KEY=your_api_key_here -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Python 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # Virtual Environment 7 | venv/ 8 | env/ 9 | ENV/ 10 | 11 | # IDE 12 | .idea/ 13 | .vscode/ 14 | *.swp 15 | *.swo 16 | 17 | # OS generated files 18 | .DS_Store 19 | .DS_Store? 20 | ._* 21 | .Spotlight-V100 22 | .Trashes 23 | ehthumbs.db 24 | Thumbs.db 25 | 26 | # Test files 27 | 1.html 28 | 29 | # Environment variables 30 | .env 31 | *.env -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 RmMargt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SearchAPI MCP Server 2 | 3 | 一个基于 Model Context Protocol (MCP) 的搜索 API 服务器,提供了对 Google Maps、Google Flights、Google Hotels 等服务的标准化访问接口。该服务器使 AI 助手能够通过统一的接口访问各种搜索服务。 4 | 5 | A Model Context Protocol (MCP) based search API server that provides standardized access to Google Maps, Google Flights, Google Hotels and other services. This server enables AI assistants to access various search services through a unified interface. 6 | 7 | ## 概述 | Overview 8 | 9 | SearchAPI-MCP-Server 实现了 Model Context Protocol,将各种搜索操作封装为工具和资源。它作为 AI 助手和搜索服务之间的桥梁,支持地图搜索、航班查询、酒店预订等多种功能。 10 | 11 | SearchAPI-MCP-Server implements the Model Context Protocol, encapsulating various search operations as tools and resources. It serves as a bridge between AI assistants and search services, supporting map search, flight queries, hotel bookings, and more. 12 | 13 | ## 功能特性 | Features 14 | 15 | ### Google 搜索 | Google Search 16 | * 网页搜索结果 | Web search results 17 | * 知识图谱集成 | Knowledge graph integration 18 | * 相关问题推荐 | Related questions 19 | * 搜索建议 | Search suggestions 20 | * 多语言支持 | Multi-language support 21 | * 地区特定结果 | Region-specific results 22 | * 时间范围过滤 | Time range filtering 23 | * 安全搜索选项 | Safe search options 24 | 25 | ### Google Video 搜索 | Google Video Search 26 | * 视频内容搜索 | Video content search 27 | * 视频列表获取 | Video list retrieval 28 | * 视频轮播支持 | Video carousel support 29 | * 短视频内容 | Short video content 30 | * 按时长筛选 | Duration filtering 31 | * 按来源过滤 | Source filtering 32 | * 按上传时间排序 | Upload time sorting 33 | * 高清预览支持 | HD preview support 34 | 35 | ### Google Maps 搜索 | Google Maps Search 36 | * 搜索地点和服务 | Search places and services 37 | * 获取地点详细信息 | Get place details 38 | * 查看用户评论 | View user reviews 39 | * 获取位置坐标 | Get location coordinates 40 | 41 | ### Google Flights 航班搜索 | Google Flights Search 42 | * 单程/往返航班搜索 | One-way/round-trip flight search 43 | * 多城市行程规划 | Multi-city itinerary planning 44 | * 航班价格日历 | Flight price calendar 45 | * 航班筛选和排序 | Flight filtering and sorting 46 | * 行李额度查询 | Baggage allowance query 47 | * 航空公司选择 | Airline selection 48 | 49 | ### Google Hotels 酒店搜索 | Google Hotels Search 50 | * 酒店位置搜索 | Hotel location search 51 | * 价格和可用性查询 | Price and availability query 52 | * 设施和服务筛选 | Facilities and services filtering 53 | * 用户评分和评论 | User ratings and reviews 54 | * 特殊优惠查询 | Special offers query 55 | 56 | * 房型选择 | Room type selection 57 | 58 | ### SearchAPI 新增功能 | Additional SearchAPI Features 59 | * SearchAPI Dashboard 与账号信息 | Dashboard and account management 60 | * 搜索历史记录查看 | View search history 61 | * 更多搜索引擎支持,如 Google Ads Transparency、Google Shopping、Google Images、Google News、Bing、Baidu、Naver、Yahoo、Amazon、Shein、eBay、Google Play Store、Apple App Store、DuckDuckGo、YouTube 62 | * 专用接口:Google Travel Explore、Google Hotels Autocomplete、Google Flights Location Search、Google Maps Photos、Google Maps Reviews、Google Maps Place 63 | 64 | ## 安装说明 | Installation 65 | 66 | ### 环境要求 | Requirements 67 | * Python 3.7 或更高版本 | Python 3.7 or higher 68 | * pip 包管理器 | pip package manager 69 | 70 | ### 基础安装 | Basic Installation 71 | 72 | ```bash 73 | # 克隆仓库 | Clone repository 74 | git clone https://github.com/RmMargt/searchAPI-mcp.git 75 | cd searchAPI-mcp 76 | 77 | # 创建并激活虚拟环境 | Create and activate virtual environment 78 | python -m venv venv 79 | source venv/bin/activate # Linux/Mac 80 | # 或 | or 81 | .\venv\Scripts\activate # Windows 82 | 83 | # 安装依赖 | Install dependencies 84 | pip install -r requirements.txt 85 | ``` 86 | 87 | ## MCP 配置 | MCP Configuration 88 | 89 | ### Claude for Desktop 配置示例 | Claude for Desktop Configuration Example 90 | 91 | 在 Claude for Desktop 的配置文件中添加以下内容: 92 | Add the following to your Claude for Desktop configuration file: 93 | 94 | ```json 95 | { 96 | "mcpServers": { 97 | "searchapi": { 98 | "command": "uv", 99 | "args": [ 100 | "run", 101 | "--with", 102 | "mcp[cli]", 103 | "/path/to/searchAPI-mcp/mcp_server.py" 104 | ], 105 | "env": { 106 | "SEARCHAPI_API_KEY": "your_api_key_here" 107 | } 108 | } 109 | } 110 | } 111 | ``` 112 | 113 | 配置文件位置 | Configuration file location: 114 | * macOS: `~/Library/Application Support/Claude/claude_desktop_config.json` 115 | * Windows: `%APPDATA%\Claude\claude_desktop_config.json` 116 | 117 | ## 许可证 | License 118 | 119 | 本项目采用 MIT 许可证 - 详见 LICENSE 文件 120 | This project is licensed under the MIT License - see the LICENSE file for details 121 | 122 | ## 致谢 | Acknowledgments 123 | 124 | * Model Context Protocol - 协议规范 | Protocol specification 125 | * FastMCP - Python MCP 实现 | Python MCP implementation 126 | * SearchAPI.io - 搜索服务提供商 | Search service provider 127 | 128 | --- 129 | 130 | _注意:本服务器会与外部 API 进行交互。在使用 MCP 客户端确认操作之前,请始终验证请求的操作是否合适。_ 131 | _Note: This server interacts with external APIs. Always verify that requested operations are appropriate before confirming them in MCP clients._ -------------------------------------------------------------------------------- /google_open_api.yaml: -------------------------------------------------------------------------------- 1 | openapi: 3.0.0 2 | info: 3 | title: Google Search API 4 | version: 1.0.0 5 | description: | 6 | The Google Search API allows access to SERP data. It provides information such as organic results, ads, knowledge graph, answer box, related questions, and many more! 7 | 8 | servers: 9 | - url: https://www.searchapi.io/api/v1 10 | 11 | paths: 12 | /search: 13 | get: 14 | tags: 15 | - Google Search 16 | operationId: googleSearch 17 | summary: Search results 18 | description: | 19 | Searches for organic_results, knowledge_graph, answer_box, related_questions, ads, local_results and many more. 20 | parameters: 21 | - in: query 22 | name: q 23 | schema: 24 | type: string 25 | required: true 26 | description: | 27 | Parameter defines the query you want to search. You can use anything that you would use in a regular Google search. e.g. inurl:, site:, intitle:. We also support advanced search query parameters such as as_dt and as_eq. 28 | - in: query 29 | name: device 30 | schema: 31 | type: string 32 | enum: ["desktop", "tablet", "mobile"] 33 | default: "desktop" 34 | description: | 35 | The default parameter `desktop` defines the search on a desktop device. The `mobile` parameter defines the search on a mobile device. The `tablet` parameter defines the search on a tablet device. 36 | - in: query 37 | name: location 38 | schema: 39 | type: string 40 | description: | 41 | Parameter defines from where you want the search to originate. If several locations match the location requested, we'll pick the most popular one. For example - New York,United States. 42 | - in: query 43 | name: uule 44 | schema: 45 | type: string 46 | description: | 47 | Parameter is the Google encoded location you want to use for the search. SearchApi automatically generated the uule parameter when you use the location parameter but we allow you to overwrite it directly. uule and location parameters can't be used together. 48 | - in: query 49 | name: google_domain 50 | schema: 51 | type: string 52 | default: "google.com" 53 | enum: ["google.com","google.ad","google.ae","google.com.af","google.com.ag","google.com.ai","google.al","google.am","google.co.ao","google.com.ar","google.as","google.at","google.com.au","google.az","google.ba","google.com.bd","google.be","google.bf","google.bg","google.com.bh","google.bi","google.bj","google.com.bn","google.com.bo","google.com.br","google.bs","google.bt","google.co.bw","google.by","google.com.bz","google.ca","google.com.kh","google.cd","google.cf","google.cg","google.ch","google.ci","google.co.ck","google.cl","google.cm","google.com.co","google.co.cr","google.com.cu","google.cv","google.com.cy","google.cz","google.de","google.dj","google.dk","google.dm","google.com.do","google.dz","google.com.ec","google.ee","google.com.eg","google.es","google.com.et","google.fi","google.fm","google.com.fj","google.fr","google.ga","google.ge","google.com.gh","google.com.gi","google.gl","google.gm","google.gp","google.gr","google.com.gt","google.gy","google.com.hk","google.hn","google.hr","google.ht","google.hu","google.co.id","google.iq","google.ie","google.co.il","google.co.in","google.is","google.it","google.com.jm","google.jo","google.co.jp","google.co.ke","google.ki","google.kg","google.co.kr","google.com.kw","google.kz","google.la","google.com.lb","google.li","google.lk","google.co.ls","google.lt","google.lu","google.lv","google.com.ly","google.co.ma","google.md","google.mg","google.mk","google.ml","google.com.mm","google.mn","google.ms","google.com.mt","google.mu","google.mv","google.mw","google.com.mx","google.com.my","google.co.mz","google.com.na","google.ne","google.com.ng","google.com.ni","google.nl","google.no","google.com.np","google.nr","google.nu","google.co.nz","google.com.om","google.com.pk","google.com.pa","google.com.pe","google.com.ph","google.pl","google.com.pg","google.com.pr","google.ps","google.pt","google.com.py","google.com.qa","google.ro","google.rs","google.ru","google.rw","google.com.sa","google.com.sb","google.sc","google.se","google.com.sg","google.sh","google.si","google.sk","google.com.sl","google.sn","google.sm","google.so","google.sr","google.com.sv","google.td","google.tg","google.co.th","google.com.tj","google.tk","google.tl","google.tm","google.to","google.tn","google.com.tr","google.tt","google.com.tw","google.co.tz","google.com.ua","google.co.ug","google.co.uk","google.com.uy","google.co.uz","google.com.vc","google.co.ve","google.vg","google.co.vi","google.com.vn","google.vu","google.ws","google.co.za","google.co.zm","google.co.zw"] 54 | description: | 55 | The default parameter `google.com` defines the Google domain of the search. 56 | - in: query 57 | name: gl 58 | schema: 59 | type: string 60 | default: "us" 61 | enum: ["af", "al", "dz", "as", "ad", "ao", "ai", "aq", "ag", "ar", "am", "aw", "au", "at", "az", "bs", "bh", "bd", "bb", "by", "be", "bz", "bj", "bm", "bt", "bo", "ba", "bw", "bv", "br", "io", "bn", "bg", "bf", "bi", "kh", "cm", "ca", "cv", "ky", "cf", "td", "cl", "cn", "cx", "cc", "co", "km", "cg", "cd", "ck", "cr", "ci", "hr", "cu", "cy", "cz", "dk", "dj", "dm", "do", "ec", "eg", "sv", "gq", "er", "ee", "et", "fk", "fo", "fj", "fi", "fr", "gf", "pf", "tf", "ga", "gm", "ge", "de", "gh", "gi", "gr", "gl", "gd", "gp", "gu", "gt", "gn", "gw", "gy", "ht", "hm", "va", "hn", "hk", "hu", "is", "in", "id", "ir", "iq", "ie", "il", "it", "jm", "jp", "jo", "kz", "ke", "ki", "kp", "kr", "kw", "kg", "la", "lv", "lb", "ls", "lr", "ly", "li", "lt", "lu", "mo", "mk", "mg", "mw", "my", "mv", "ml", "mt", "mh", "mq", "mr", "mu", "yt", "mx", "fm", "md", "mc", "mn", "ms", "ma", "mz", "mm", "na", "nr", "np", "nl", "an", "nc", "nz", "ni", "ne", "ng", "nu", "nf", "mp", "no", "om", "pk", "pw", "ps", "pa", "pg", "py", "pe", "ph", "pn", "pl", "pt", "pr", "qa", "re", "ro", "ru", "rw", "sh", "kn", "lc", "pm", "vc", "ws", "sm", "st", "sa", "sn", "rs", "sc", "sl", "sg", "sk", "si", "sb", "so", "za", "gs", "es", "lk", "sd", "sr", "sj", "sz", "se", "ch", "sy", "tw", "tj", "tz", "th", "tl", "tg", "tk", "to", "tt", "tn", "tr", "tm", "tc", "tv", "ug", "ua", "ae", "uk", "gb", "us", "um", "uy", "uz", "vu", "ve", "vn", "vg", "vi", "wf", "eh", "ye", "zm", "zw"] 62 | description: | 63 | The default parameter `us` defines the country of the search. 64 | - in: query 65 | name: hl 66 | schema: 67 | type: string 68 | default: "en" 69 | enum: ["af", "ak", "sq", "ws", "am", "ar", "hy", "az", "eu", "be", "bem", "bn", "bh", "xx-bork", "bs", "br", "bg", "bt", "km", "ca", "chr", "ny", "zh-cn", "zh-tw", "co", "hr", "cs", "da", "nl", "xx-elmer", "en", "eo", "et", "ee", "fo", "tl", "fi", "fr", "fy", "gaa", "gl", "ka", "de", "el", "kl", "gn", "gu", "xx-hacker", "ht", "ha", "haw", "iw", "hi", "hu", "is", "ig", "id", "ia", "ga", "it", "ja", "jw", "kn", "kk", "rw", "rn", "xx-klingon", "kg", "ko", "kri", "ku", "ckb", "ky", "lo", "la", "lv", "ln", "lt", "loz", "lg", "ach", "mk", "mg", "my", "ml", "mt", "mv", "mi", "mr", "mfe", "mo", "mn", "sr-me", "ne", "pcm", "nso", "no", "nn", "oc", "or", "om", "ps", "fa", "xx-pirate", "pl", "pt", "pt-br", "pt-pt", "pa", "qu", "ro", "rm", "nyn", "ru", "gd", "sr", "sh", "st", "tn", "crs", "sn", "sd", "si", "sk", "sl", "so", "es", "es-419", "su", "sw", "sv", "tg", "ta", "tt", "te", "th", "ti", "to", "lua", "tum", "tr", "tk", "tw", "ug", "uk", "ur", "uz", "vu", "vi", "cy", "wo", "xh", "yi", "yo", "zu"] 70 | description: | 71 | The default parameter en defines the interface language of the search. 72 | - in: query 73 | name: lr 74 | schema: 75 | type: string 76 | description: | 77 | The lr parameter restricts search results to documents written in a particular language or a set of languages. 78 | - in: query 79 | name: cr 80 | schema: 81 | type: string 82 | enum: ["af", "al", "dz", "as", "ad", "ao", "ai", "aq", "ag", "ar", "am", "aw", "au", "at", "az", "bs", "bh", "bd", "bb", "by", "be", "bz", "bj", "bm", "bt", "bo", "ba", "bw", "bv", "br", "io", "bn", "bg", "bf", "bi", "kh", "cm", "ca", "cv", "ky", "cf", "td", "cl", "cn", "cx", "cc", "co", "km", "cg", "cd", "ck", "cr", "ci", "hr", "cy", "cz", "dk", "dj", "dm", "do", "tl", "ec", "eg", "sv", "gq", "er", "ee", "et", "fk", "fo", "fj", "fi", "fr", "gf", "pf", "tf", "ga", "gm", "ge", "de", "gh", "gi", "gr", "gl", "gd", "gp", "gu", "gt", "gn", "gw", "gy", "ht", "hm", "hn", "hk", "hu", "is", "in", "id", "iq", "ie", "il", "it", "jm", "jp", "jo", "kz", "ke", "ki", "kw", "kg", "la", "lv", "lb", "ls", "lr", "ly", "li", "lt", "lu", "mo", "mk", "mg", "mw", "my", "mv", "ml", "mt", "mh", "mq", "mr", "mu", "yt", "mx", "fm", "md", "mc", "mn", "ms", "ma", "mz", "na", "nr", "np", "nl", "an", "nc", "nz", "ni", "ne", "ng", "nu", "nf", "mp", "no", "om", "pk", "pw", "ps", "pa", "pg", "py", "pe", "ph", "pn", "pl", "pt", "pr", "qa", "re", "ro", "ru", "rw", "kn", "lc", "vc", "ws", "sm", "st", "sa", "sn", "cs", "sc", "sl", "sg", "sk", "si", "sb", "so", "za", "gs", "kr", "es", "lk", "sh", "pm", "sr", "sj", "sz", "se", "ch", "tw", "tj", "tz", "th", "tg", "tk", "to", "tt", "tn", "tr", "tm", "tc", "tv", "ug", "ua", "ae", "gb", "us", "um", "uy", "uz", "vu", "va", "ve", "vn", "vg", "vi", "wf", "eh", "ye", "zm", "zw"] 83 | description: | 84 | The cr parameter restricts search results to documents originating in a particular country. Google determines the country of a document by the top-level domain (TLD) of the document's URL or by Web server's IP address geographic location. 85 | - in: query 86 | name: nfpr 87 | schema: 88 | type: integer 89 | default: 0 90 | enum: [0, 1] 91 | description: | 92 | This parameter controls whether results from queries that have been auto-corrected for spelling errors are included. To exclude these auto-corrected results, set the value to `1`. By default, the value is `0`, meaning auto-corrected results are included. 93 | - in: query 94 | name: filter 95 | schema: 96 | type: integer 97 | default: 1 98 | enum: [0, 1] 99 | description: | 100 | This parameter controls whether the "Duplicate Content" and "Host Crowding" filters are enabled. Set the value to 1 to enable these filters, which is the default setting. To disable these filters, set the value to 0. 101 | - in: query 102 | name: safe 103 | schema: 104 | type: string 105 | default: "off" 106 | enum: ["active", "off"] 107 | description: | 108 | This parameter toggles the SafeSearch feature for the results. SafeSearch operates by filtering out adult content from your search results. Google's filters use proprietary technology to check keywords, phrases and URLs. 109 | - in: query 110 | name: time_period 111 | schema: 112 | type: string 113 | enum: ["last_hour", "last_day", "last_week", "last_month", "last_year"] 114 | description: | 115 | This parameter restricts results to URLs based on date. 116 | - in: query 117 | name: time_period_min 118 | schema: 119 | type: string 120 | description: | 121 | This parameter specifies the start of the time period. It could be used in combination with the time_period_max parameter. The value should be in the format `MM/DD/YYYY`. 122 | - in: query 123 | name: time_period_max 124 | schema: 125 | type: string 126 | description: | 127 | This parameter specifies the end of the time period. It could be used in combination with the time_period_min parameter. The value should be in the format MM/DD/YYYY. 128 | - in: query 129 | name: num 130 | schema: 131 | type: integer 132 | default: 10 133 | minimum: 1 134 | maximum: 100 135 | description: | 136 | This parameter specifies the number of results to display per page. By default, it is set to 10. Use in combination with the `page` parameter to implement pagination functionality. Max `num` per page is 100, min - 1. 137 | - in: query 138 | name: page 139 | schema: 140 | type: integer 141 | minimum: 1 142 | description: | 143 | This parameter indicates which page of results to return. By default, it is set to 1. Use in combination with the `num` parameter to implement pagination. 144 | - in: query 145 | name: engine 146 | schema: 147 | type: string 148 | enum: [google] 149 | required: true 150 | description: Parameter defines an engine that will be used to retrieve real-time data. It must be set to `google`. 151 | - in: query 152 | name: api_key 153 | schema: 154 | type: string 155 | required: true 156 | description: The `api_key` authenticates your requests. Use it as a query parameter or in the Authorization header (Bearer YOUR_API_KEY). 157 | responses: 158 | '200': 159 | description: Successful operation 160 | content: 161 | application/json: 162 | schema: 163 | type: object 164 | properties: 165 | search_metadata: 166 | type: object 167 | properties: 168 | id: 169 | type: string 170 | status: 171 | type: string 172 | created_at: 173 | type: string 174 | format: date-time 175 | request_time_taken: 176 | type: number 177 | parsing_time_taken: 178 | type: number 179 | total_time_taken: 180 | type: number 181 | request_url: 182 | type: string 183 | html_url: 184 | type: string 185 | json_url: 186 | type: string 187 | search_information: 188 | type: object 189 | properties: 190 | query_displayed: 191 | type: string 192 | total_results: 193 | type: integer 194 | page: 195 | type: integer 196 | time_taken_displayed: 197 | type: integer 198 | detected_location: 199 | type: string 200 | did_you_mean: 201 | type: string 202 | shopping_ads: 203 | type: array 204 | items: 205 | $ref: '#/components/schemas/ShoppingAd' 206 | shopping_ads_more_link: 207 | type: string 208 | ads: 209 | type: array 210 | items: 211 | $ref: '#/components/schemas/Ad' 212 | local_ads: 213 | $ref: '#/components/schemas/LocalAd' 214 | answer_box: 215 | $ref: '#/components/schemas/AnswerBox' 216 | sport_results: 217 | $ref: '#/components/schemas/SportResult' 218 | weather_result: 219 | $ref: '#/components/schemas/WeatherResult' 220 | salary_estimates: 221 | $ref: '#/components/schemas/SalaryEstimates' 222 | knowledge_graph: 223 | $ref: '#/components/schemas/KnowledgeGraph' 224 | organic_results: 225 | type: array 226 | items: 227 | $ref: '#/components/schemas/OrganicResult' 228 | events: 229 | type: array 230 | items: 231 | $ref: '#/components/schemas/Event' 232 | universities: 233 | type: array 234 | items: 235 | $ref: '#/components/schemas/University' 236 | about_this_result: 237 | $ref: '#/components/schemas/AboutThisResult' 238 | about_this_result_more_link: 239 | type: string 240 | job_results: 241 | $ref: '#/components/schemas/JobResults' 242 | inline_images: 243 | $ref: '#/components/schemas/InlineImages' 244 | inline_images_more_link: 245 | type: object 246 | properties: 247 | link: 248 | type: string 249 | inline_shopping: 250 | $ref: '#/components/schemas/InlineShopping' 251 | local_map: 252 | $ref: '#/components/schemas/LocalMap' 253 | local_results: 254 | $ref: '#/components/schemas/LocalResults' 255 | local_results_more_link: 256 | type: object 257 | properties: 258 | link: 259 | type: string 260 | from_sources_across_the_web: 261 | $ref: '#/components/schemas/FromSourcesAcrossTheWeb' 262 | discussions_and_forums: 263 | $ref: '#/components/schemas/DiscussionsAndForums' 264 | related_questions: 265 | $ref: '#/components/schemas/RelatedQuestions' 266 | questions_and_answers: 267 | $ref: '#/components/schemas/QuestionsAndAnswers' 268 | explore_brands: 269 | $ref: '#/components/schemas/ExploreBrands' 270 | courses: 271 | $ref: '#/components/schemas/Courses' 272 | top_stories: 273 | $ref: '#/components/schemas/TopStories' 274 | top_stories_more_link: 275 | type: object 276 | properties: 277 | link: 278 | type: string 279 | things_to_do: 280 | $ref: '#/components/schemas/ThingsToDo' 281 | things_to_do_more_link: 282 | type: object 283 | properties: 284 | link: 285 | type: string 286 | inline_videos: 287 | $ref: '#/components/schemas/InlineVideos' 288 | inline_videos_more_link: 289 | type: string 290 | inline_tweets: 291 | $ref: '#/components/schemas/InlineTweets' 292 | inline_tweets_more_link: 293 | type: object 294 | properties: 295 | link: 296 | type: string 297 | scholarly_articles: 298 | $ref: '#/components/schemas/ScholarlyArticles' 299 | inline_recipes: 300 | $ref: '#/components/schemas/InlineRecipes' 301 | related_searches: 302 | $ref: '#/components/schemas/RelatedSearches' 303 | pagination: 304 | type: object 305 | properties: 306 | current: 307 | type: integer 308 | previous: 309 | type: string 310 | next: 311 | type: string 312 | 313 | 314 | '400': 315 | description: Validation Error. There is an issue with query parameters. 316 | '401': 317 | description: Authentication Error. The API key is missing or invalid. 318 | '429': 319 | description: Rate Limit. The search limit is reached. Consider upgrading your plan. 320 | '500': 321 | description: Server Error. Internal server error. 322 | '503': 323 | description: Timeout. We could not retrieve results in 90 seconds. 324 | 325 | security: 326 | - ApiKeyAuth: [] 327 | 328 | components: 329 | schemas: 330 | ShoppingAd: 331 | type: object 332 | properties: 333 | position: 334 | type: integer 335 | block_position: 336 | type: string 337 | title: 338 | type: string 339 | seller: 340 | type: string 341 | link: 342 | type: string 343 | deal: 344 | type: string 345 | price: 346 | type: string 347 | extracted_price: 348 | type: number 349 | original_price: 350 | type: string 351 | extracted_original_price: 352 | type: number 353 | order_fullfillmed_method: 354 | type: string 355 | promo_code: 356 | type: object 357 | properties: 358 | code: 359 | type: string 360 | expiration_date: 361 | type: string 362 | format: date 363 | installment: 364 | type: object 365 | properties: 366 | down_payment: 367 | type: string 368 | extracted_down_payment: 369 | type: number 370 | months: 371 | type: string 372 | extracted_months: 373 | type: number 374 | cost_per_month: 375 | type: string 376 | extracted_cost_per_month: 377 | type: number 378 | rating: 379 | type: number 380 | reviews: 381 | type: integer 382 | durability: 383 | type: string 384 | delivery: 385 | type: string 386 | source: 387 | type: object 388 | properties: 389 | title: 390 | type: string 391 | link: 392 | type: string 393 | extensions: 394 | type: array 395 | items: 396 | type: string 397 | image: 398 | type: string 399 | 400 | Ad: 401 | type: object 402 | properties: 403 | position: 404 | type: integer 405 | block_position: 406 | type: string 407 | title: 408 | type: string 409 | link: 410 | type: string 411 | source: 412 | type: string 413 | domain: 414 | type: string 415 | displayed_link: 416 | type: string 417 | snippet: 418 | type: string 419 | snippet_highlighted_words: 420 | type: array 421 | items: 422 | type: string 423 | sitelinks: 424 | type: object 425 | properties: 426 | expanded: 427 | type: array 428 | items: 429 | type: object 430 | properties: 431 | title: 432 | type: string 433 | snippet: 434 | type: string 435 | snippet_highlighted_words: 436 | type: array 437 | items: 438 | type: string 439 | link: 440 | type: string 441 | inline: 442 | type: array 443 | items: 444 | type: object 445 | properties: 446 | title: 447 | type: string 448 | link: 449 | type: string 450 | address: 451 | type: object 452 | properties: 453 | title: 454 | type: string 455 | tracking_link: 456 | type: string 457 | sale: 458 | type: object 459 | properties: 460 | title: 461 | type: string 462 | link: 463 | type: string 464 | products: 465 | type: array 466 | items: 467 | type: object 468 | properties: 469 | title: 470 | type: string 471 | tracking_link: 472 | type: string 473 | extensions: 474 | type: array 475 | items: 476 | type: string 477 | extensions: 478 | type: array 479 | items: 480 | type: string 481 | rating: 482 | type: number 483 | reviews: 484 | type: integer 485 | rating_link: 486 | type: string 487 | thumbnail: 488 | type: string 489 | favicon: 490 | type: string 491 | 492 | LocalAd: 493 | type: object 494 | properties: 495 | title: 496 | type: string 497 | badge: 498 | type: string 499 | ads: 500 | type: array 501 | items: 502 | type: object 503 | properties: 504 | title: 505 | type: string 506 | link: 507 | type: string 508 | badge: 509 | type: string 510 | phone: 511 | type: string 512 | rating: 513 | type: number 514 | reviews: 515 | type: integer 516 | message_link: 517 | type: string 518 | extensions: 519 | type: array 520 | items: 521 | type: string 522 | thumbnail: 523 | type: string 524 | see_more_link: 525 | type: object 526 | properties: 527 | title: 528 | type: string 529 | link: 530 | type: string 531 | categories: 532 | type: array 533 | items: 534 | type: object 535 | properties: 536 | title: 537 | type: string 538 | link: 539 | type: string 540 | 541 | AnswerBox: 542 | oneOf: 543 | - $ref: '#/components/schemas/PopulationType' 544 | - $ref: '#/components/schemas/OpenHoursType' 545 | - $ref: '#/components/schemas/FinanceType' 546 | - $ref: '#/components/schemas/CurrencyConverterType' 547 | - $ref: '#/components/schemas/LocalTimeType' 548 | - $ref: '#/components/schemas/OrganicResultType' 549 | - $ref: '#/components/schemas/LocationType' 550 | 551 | PopulationType: 552 | type: object 553 | properties: 554 | type: 555 | type: string 556 | enum: 557 | - population_type 558 | place: 559 | type: string 560 | answer: 561 | type: string 562 | population: 563 | type: string 564 | year: 565 | type: integer 566 | others: 567 | type: array 568 | items: 569 | type: object 570 | properties: 571 | place: 572 | type: string 573 | population: 574 | type: string 575 | link: 576 | type: string 577 | sources: 578 | type: array 579 | items: 580 | type: object 581 | properties: 582 | text: 583 | type: string 584 | link: 585 | type: string 586 | explore_more_Link: 587 | type: string 588 | 589 | OpenHoursType: 590 | type: object 591 | properties: 592 | type: 593 | type: string 594 | enum: 595 | - open_hours 596 | answer: 597 | type: string 598 | title: 599 | type: string 600 | rating: 601 | type: number 602 | reviews: 603 | type: integer 604 | time: 605 | type: string 606 | description: 607 | type: string 608 | hours_list: 609 | type: array 610 | items: 611 | type: object 612 | properties: 613 | title: 614 | type: string 615 | items: 616 | type: array 617 | items: 618 | type: object 619 | properties: 620 | day: 621 | type: string 622 | time: 623 | type: string 624 | local_results: 625 | type: array 626 | items: 627 | type: object 628 | properties: 629 | title: 630 | type: string 631 | link: 632 | type: string 633 | time: 634 | type: string 635 | 636 | FinanceType: 637 | type: object 638 | properties: 639 | type: 640 | type: string 641 | enum: 642 | - finance_results 643 | title: 644 | type: string 645 | link: 646 | type: string 647 | answer: 648 | type: string 649 | exchange: 650 | type: string 651 | stock: 652 | type: string 653 | price: 654 | type: number 655 | previous_close: 656 | type: number 657 | price_change: 658 | type: object 659 | properties: 660 | amount: 661 | type: number 662 | percentage: 663 | type: number 664 | period: 665 | type: string 666 | is_up: 667 | type: boolean 668 | is_down: 669 | type: boolean 670 | market: 671 | type: object 672 | properties: 673 | is_closed: 674 | type: boolean 675 | date: 676 | type: string 677 | trading: 678 | type: string 679 | price: 680 | type: number 681 | price_change: 682 | type: object 683 | properties: 684 | amount: 685 | type: number 686 | percentage: 687 | type: number 688 | is_up: 689 | type: boolean 690 | is_down: 691 | type: boolean 692 | market_table: 693 | type: array 694 | items: 695 | type: object 696 | properties: 697 | name: 698 | type: string 699 | value: 700 | type: string 701 | 702 | CurrencyConverterType: 703 | type: object 704 | properties: 705 | type: 706 | type: string 707 | enum: 708 | - currency_converter 709 | answer: 710 | type: string 711 | price: 712 | type: number 713 | currency: 714 | type: string 715 | date: 716 | type: string 717 | price_change: 718 | type: object 719 | properties: 720 | amount: 721 | type: number 722 | percentage: 723 | type: number 724 | period: 725 | type: string 726 | from: 727 | type: object 728 | properties: 729 | price: 730 | type: number 731 | currency: 732 | type: string 733 | to: 734 | type: object 735 | properties: 736 | price: 737 | type: number 738 | currency: 739 | type: string 740 | chart: 741 | type: array 742 | items: 743 | type: object 744 | properties: 745 | price: 746 | type: number 747 | datetime: 748 | type: string 749 | unix_date: 750 | type: integer 751 | 752 | LocalTimeType: 753 | type: object 754 | properties: 755 | type: 756 | type: string 757 | enum: 758 | - local_time 759 | answer: 760 | type: string 761 | local_time: 762 | type: string 763 | location: 764 | type: string 765 | 766 | OrganicResultType: 767 | type: object 768 | properties: 769 | type: 770 | type: string 771 | enum: 772 | - organic_result 773 | title: 774 | type: string 775 | answer: 776 | type: string 777 | answer_date: 778 | type: string 779 | link: 780 | type: string 781 | answer_table: 782 | type: object 783 | properties: 784 | headers: 785 | type: array 786 | items: 787 | type: string 788 | rows: 789 | type: array 790 | items: 791 | type: string 792 | answer_list: 793 | type: array 794 | items: 795 | type: string 796 | snippet: 797 | type: string 798 | date: 799 | type: string 800 | organic_result: 801 | type: object 802 | properties: 803 | title: 804 | type: string 805 | link: 806 | type: string 807 | domain: 808 | type: string 809 | displayed_link: 810 | type: string 811 | about_this_result: 812 | type: object 813 | properties: 814 | source: 815 | type: object 816 | properties: 817 | name: 818 | type: string 819 | type: 820 | type: string 821 | description: 822 | type: string 823 | link: 824 | type: string 825 | favicon: 826 | type: string 827 | about_page_link: 828 | type: string 829 | favicon: 830 | type: string 831 | 832 | people_also_search_for: 833 | type: array 834 | items: 835 | type: object 836 | properties: 837 | title: 838 | type: string 839 | link: 840 | type: string 841 | thumbnail: 842 | type: string 843 | thumbnail: 844 | type: string 845 | 846 | LocationType: 847 | type: object 848 | properties: 849 | type: 850 | type: string 851 | enum: 852 | - location 853 | answer: 854 | type: string 855 | landmark: 856 | type: string 857 | 858 | SportResult: 859 | oneOf: 860 | - $ref: '#/components/schemas/AthleteStats' 861 | - $ref: '#/components/schemas/IndividualSport' 862 | - $ref: '#/components/schemas/IndividualSportStandings' 863 | - $ref: '#/components/schemas/TeamSports' 864 | 865 | AthleteStats: 866 | type: object 867 | properties: 868 | type: 869 | type: string 870 | enum: 871 | - athlete_stats 872 | title: 873 | type: string 874 | proffesion: 875 | type: string 876 | stats: 877 | type: array 878 | items: 879 | type: object 880 | properties: 881 | team: 882 | type: string 883 | games: 884 | type: array 885 | items: 886 | type: object 887 | properties: 888 | title: 889 | type: string 890 | games_table: 891 | type: object 892 | properties: 893 | headers: 894 | type: array 895 | items: 896 | type: string 897 | rows: 898 | type: array 899 | items: 900 | type: array 901 | items: 902 | type: string 903 | thumbnail: 904 | type: string 905 | 906 | IndividualSport: 907 | type: object 908 | properties: 909 | type: 910 | type: string 911 | enum: 912 | - individual_sport 913 | title: 914 | type: string 915 | subtitle: 916 | type: string 917 | proffesion: 918 | type: string 919 | date: 920 | type: string 921 | track: 922 | type: object 923 | properties: 924 | title: 925 | type: string 926 | link: 927 | type: string 928 | tournament_details: 929 | type: array 930 | items: 931 | type: object 932 | properties: 933 | name: 934 | type: string 935 | value: 936 | type: string 937 | video: 938 | type: object 939 | properties: 940 | title: 941 | type: string 942 | length: 943 | type: string 944 | link: 945 | type: string 946 | thumbnail: 947 | type: string 948 | status: 949 | type: string 950 | games: 951 | type: array 952 | items: 953 | type: object 954 | properties: 955 | date: 956 | type: string 957 | stage: 958 | type: string 959 | status: 960 | type: string 961 | location: 962 | type: string 963 | video: 964 | type: object 965 | properties: 966 | link: 967 | type: string 968 | length: 969 | type: string 970 | thumbnail: 971 | type: string 972 | players: 973 | type: array 974 | items: 975 | type: object 976 | properties: 977 | name: 978 | type: string 979 | nationality: 980 | type: string 981 | ranking: 982 | type: integer 983 | sets: 984 | type: object 985 | additionalProperties: 986 | type: string 987 | teams: 988 | type: array 989 | items: 990 | type: object 991 | properties: 992 | name: 993 | type: string 994 | score: 995 | type: string 996 | leaderboard: 997 | type: array 998 | items: 999 | type: object 1000 | properties: 1001 | position: 1002 | type: integer 1003 | nationality: 1004 | type: string 1005 | name: 1006 | type: string 1007 | team: 1008 | type: string 1009 | car_number: 1010 | type: string 1011 | time: 1012 | type: string 1013 | points: 1014 | type: number 1015 | results: 1016 | type: object 1017 | properties: 1018 | name: 1019 | type: string 1020 | value: 1021 | type: string 1022 | thumbnail: 1023 | type: string 1024 | 1025 | IndividualSportStandings: 1026 | type: object 1027 | properties: 1028 | type: 1029 | type: string 1030 | enum: 1031 | - individual_sport_standings 1032 | title: 1033 | type: string 1034 | subtitle: 1035 | type: string 1036 | date: 1037 | type: string 1038 | standings: 1039 | type: array 1040 | items: 1041 | type: object 1042 | properties: 1043 | rank: 1044 | type: integer 1045 | name: 1046 | type: string 1047 | team: 1048 | type: string 1049 | link: 1050 | type: string 1051 | results: 1052 | type: array 1053 | items: 1054 | type: object 1055 | properties: 1056 | name: 1057 | type: string 1058 | value: 1059 | type: number 1060 | thumbnail: 1061 | type: string 1062 | 1063 | TeamSports: 1064 | type: object 1065 | properties: 1066 | type: 1067 | type: string 1068 | enum: 1069 | - team_sport 1070 | title: 1071 | type: string 1072 | subtitle: 1073 | type: string 1074 | game_spotlight: 1075 | type: object 1076 | properties: 1077 | league: 1078 | type: string 1079 | stage: 1080 | type: string 1081 | date: 1082 | type: string 1083 | time: 1084 | type: string 1085 | stadium: 1086 | type: string 1087 | city: 1088 | type: string 1089 | status: 1090 | type: string 1091 | videos: 1092 | type: array 1093 | items: 1094 | type: object 1095 | properties: 1096 | title: 1097 | type: string 1098 | link: 1099 | type: string 1100 | length: 1101 | type: string 1102 | source: 1103 | type: string 1104 | teams: 1105 | type: array 1106 | items: 1107 | type: object 1108 | properties: 1109 | name: 1110 | type: string 1111 | rankings: 1112 | type: string 1113 | stats: 1114 | type: object 1115 | properties: 1116 | wins: 1117 | type: integer 1118 | losses: 1119 | type: integer 1120 | score: 1121 | type: string 1122 | score_table: 1123 | type: object 1124 | properties: 1125 | headers: 1126 | type: array 1127 | items: 1128 | type: string 1129 | rows: 1130 | type: array 1131 | items: 1132 | type: array 1133 | items: 1134 | type: string 1135 | games: 1136 | type: array 1137 | items: 1138 | type: object 1139 | properties: 1140 | league: 1141 | type: string 1142 | stage: 1143 | type: string 1144 | date: 1145 | type: string 1146 | time: 1147 | type: string 1148 | stadium: 1149 | type: string 1150 | status: 1151 | type: string 1152 | videos: 1153 | type: array 1154 | items: 1155 | type: object 1156 | properties: 1157 | title: 1158 | type: string 1159 | link: 1160 | type: string 1161 | length: 1162 | type: string 1163 | source: 1164 | type: string 1165 | teams: 1166 | type: array 1167 | items: 1168 | type: object 1169 | properties: 1170 | name: 1171 | type: string 1172 | rankings: 1173 | type: string 1174 | stats: 1175 | type: object 1176 | properties: 1177 | wins: 1178 | type: integer 1179 | losses: 1180 | type: integer 1181 | score: 1182 | type: string 1183 | standings: 1184 | type: object 1185 | properties: 1186 | season: 1187 | type: string 1188 | round: 1189 | type: string 1190 | headers: 1191 | type: array 1192 | items: 1193 | type: string 1194 | rows: 1195 | type: array 1196 | items: 1197 | type: array 1198 | items: 1199 | type: string 1200 | thumbnail: 1201 | type: string 1202 | 1203 | WeatherResult: 1204 | type: object 1205 | properties: 1206 | temperature: 1207 | type: object 1208 | properties: 1209 | fahrenheit: 1210 | type: number 1211 | celsius: 1212 | type: number 1213 | unit: 1214 | type: string 1215 | precipitation: 1216 | type: string 1217 | humidity: 1218 | type: string 1219 | wind: 1220 | type: object 1221 | properties: 1222 | kmh: 1223 | type: number 1224 | mph: 1225 | type: number 1226 | location: 1227 | type: string 1228 | date: 1229 | type: string 1230 | weather: 1231 | type: string 1232 | thumbnail: 1233 | type: string 1234 | forecast: 1235 | type: array 1236 | items: 1237 | type: object 1238 | properties: 1239 | day: 1240 | type: string 1241 | weather: 1242 | type: string 1243 | temperature: 1244 | type: object 1245 | properties: 1246 | high: 1247 | type: integer 1248 | low: 1249 | type: integer 1250 | precipitation: 1251 | type: string 1252 | humidity: 1253 | type: string 1254 | wind: 1255 | type: string 1256 | thumbnail: 1257 | type: string 1258 | hourly_forecast: 1259 | type: array 1260 | items: 1261 | type: object 1262 | properties: 1263 | time: 1264 | type: string 1265 | weather: 1266 | type: string 1267 | temperature: 1268 | type: string 1269 | precipitation: 1270 | type: string 1271 | humidity: 1272 | type: string 1273 | wind: 1274 | type: string 1275 | precipitation_forecast: 1276 | type: array 1277 | items: 1278 | type: object 1279 | properties: 1280 | precipitation: 1281 | type: string 1282 | day: 1283 | type: string 1284 | time: 1285 | type: string 1286 | wind_forecast: 1287 | type: array 1288 | items: 1289 | type: object 1290 | properties: 1291 | speed: 1292 | type: string 1293 | direction: 1294 | type: string 1295 | day: 1296 | type: string 1297 | time: 1298 | type: string 1299 | angle: 1300 | type: integer 1301 | 1302 | SalaryEstimates: 1303 | type: array 1304 | items: 1305 | type: object 1306 | properties: 1307 | title: 1308 | type: string 1309 | salary: 1310 | type: object 1311 | properties: 1312 | text: 1313 | type: string 1314 | range: 1315 | type: string 1316 | range_from: 1317 | type: number 1318 | range_to: 1319 | type: number 1320 | frequency: 1321 | type: string 1322 | link: 1323 | type: string 1324 | location: 1325 | type: string 1326 | source: 1327 | type: string 1328 | favicon: 1329 | type: string 1330 | 1331 | KnowledgeGraph: 1332 | type: object 1333 | properties: 1334 | kgmid: 1335 | type: string 1336 | knowledge_graph_type: 1337 | type: string 1338 | title: 1339 | type: string 1340 | rating: 1341 | type: number 1342 | reviews: 1343 | type: integer 1344 | type: 1345 | type: string 1346 | price: 1347 | type: string 1348 | price_description: 1349 | type: string 1350 | website: 1351 | type: string 1352 | directions: 1353 | type: string 1354 | phone: 1355 | type: string 1356 | place_actions: 1357 | type: array 1358 | items: 1359 | type: object 1360 | properties: 1361 | name: 1362 | type: string 1363 | link: 1364 | type: string 1365 | tooltips: 1366 | type: array 1367 | items: 1368 | type: string 1369 | description: 1370 | type: string 1371 | source: 1372 | type: object 1373 | properties: 1374 | name: 1375 | type: string 1376 | link: 1377 | type: string 1378 | manufacturer: 1379 | type: object 1380 | properties: 1381 | title: 1382 | type: string 1383 | link: 1384 | type: string 1385 | name: 1386 | type: string 1387 | type: 1388 | type: string 1389 | stock: 1390 | type: object 1391 | properties: 1392 | ticker: 1393 | type: string 1394 | link: 1395 | type: string 1396 | price: 1397 | type: string 1398 | extracted_price: 1399 | type: number 1400 | change: 1401 | type: number 1402 | change_percent: 1403 | type: number 1404 | last_updated: 1405 | type: string 1406 | service_options: 1407 | type: array 1408 | items: 1409 | type: string 1410 | ludocid: 1411 | type: string 1412 | address: 1413 | type: string 1414 | menu: 1415 | type: object 1416 | properties: 1417 | text: 1418 | type: string 1419 | link: 1420 | type: string 1421 | local_time: 1422 | type: string 1423 | weather: 1424 | type: string 1425 | additionalProperties1: 1426 | type: string 1427 | additionalProperties2: 1428 | type: array 1429 | items: 1430 | type: object 1431 | properties: 1432 | text: 1433 | type: string 1434 | link: 1435 | type: string 1436 | products: 1437 | type: array 1438 | items: 1439 | type: object 1440 | properties: 1441 | title: 1442 | type: string 1443 | price: 1444 | type: string 1445 | extracted_price: 1446 | type: number 1447 | image: 1448 | type: string 1449 | offers: 1450 | type: array 1451 | items: 1452 | type: object 1453 | properties: 1454 | product_id: 1455 | type: string 1456 | name: 1457 | type: string 1458 | link: 1459 | type: string 1460 | price: 1461 | type: string 1462 | extracted_price: 1463 | type: number 1464 | installment: 1465 | type: object 1466 | properties: 1467 | down_payment: 1468 | type: string 1469 | extracted_down_payment: 1470 | type: number 1471 | months: 1472 | type: string 1473 | cost_per_month: 1474 | type: string 1475 | extracted_cost_per_month: 1476 | type: number 1477 | delivery_price: 1478 | type: string 1479 | extracted_delivery_price: 1480 | type: number 1481 | tax_price: 1482 | type: string 1483 | extracted_tax_price: 1484 | type: number 1485 | total_price: 1486 | type: string 1487 | extracted_total_price: 1488 | type: number 1489 | merchant: 1490 | type: object 1491 | properties: 1492 | name: 1493 | type: string 1494 | domain: 1495 | type: string 1496 | country_code: 1497 | type: string 1498 | rating: 1499 | type: number 1500 | reviews: 1501 | type: string 1502 | link: 1503 | type: string 1504 | favicon: 1505 | type: string 1506 | return_days: 1507 | type: string 1508 | details: 1509 | type: array 1510 | items: 1511 | type: string 1512 | features: 1513 | type: array 1514 | items: 1515 | type: object 1516 | properties: 1517 | name: 1518 | type: string 1519 | value: 1520 | type: string 1521 | details: 1522 | type: object 1523 | properties: 1524 | description: 1525 | type: string 1526 | source: 1527 | type: object 1528 | properties: 1529 | name: 1530 | type: string 1531 | link: 1532 | type: string 1533 | specifications: 1534 | type: array 1535 | items: 1536 | type: object 1537 | properties: 1538 | category: 1539 | type: string 1540 | attributes: 1541 | type: array 1542 | items: 1543 | type: object 1544 | properties: 1545 | name: 1546 | type: string 1547 | value: 1548 | type: string 1549 | hours: 1550 | type: string 1551 | open_hours: 1552 | type: array 1553 | items: 1554 | type: object 1555 | properties: 1556 | name: 1557 | type: string 1558 | value: 1559 | type: string 1560 | popular_times: 1561 | type: object 1562 | properties: 1563 | live: 1564 | type: object 1565 | properties: 1566 | time: 1567 | type: string 1568 | info: 1569 | type: string 1570 | wait_time: 1571 | type: string 1572 | busyness_score: 1573 | type: integer 1574 | typical_time_spent: 1575 | type: string 1576 | chart: 1577 | type: object 1578 | properties: 1579 | additionalProperties: 1580 | type: array 1581 | items: 1582 | type: object 1583 | properties: 1584 | time: 1585 | type: string 1586 | busyness_score: 1587 | type: integer 1588 | info: 1589 | type: string 1590 | wait_time: 1591 | type: string 1592 | wait_time_minutes: 1593 | type: string 1594 | web_reviews: 1595 | type: array 1596 | items: 1597 | type: object 1598 | properties: 1599 | title: 1600 | type: string 1601 | link: 1602 | type: string 1603 | rating_text: 1604 | type: string 1605 | rating: 1606 | type: number 1607 | rating_out_of: 1608 | type: number 1609 | reviews: 1610 | type: integer 1611 | user_reviews: 1612 | type: array 1613 | items: 1614 | type: object 1615 | properties: 1616 | review: 1617 | type: string 1618 | review_highlighted_words: 1619 | type: array 1620 | items: 1621 | type: string 1622 | link: 1623 | type: string 1624 | rating: 1625 | type: number 1626 | user: 1627 | type: object 1628 | properties: 1629 | name: 1630 | type: string 1631 | link: 1632 | type: string 1633 | image: 1634 | type: string 1635 | product_reviews: 1636 | type: object 1637 | properties: 1638 | rating: 1639 | type: number 1640 | reviews: 1641 | type: integer 1642 | reviews_histogram: 1643 | type: object 1644 | properties: 1645 | "1": 1646 | type: integer 1647 | "2": 1648 | type: integer 1649 | "3": 1650 | type: integer 1651 | "4": 1652 | type: integer 1653 | "5": 1654 | type: integer 1655 | top_review: 1656 | type: object 1657 | properties: 1658 | review: 1659 | type: string 1660 | date: 1661 | type: string 1662 | rating: 1663 | type: number 1664 | source: 1665 | type: string 1666 | user: 1667 | type: object 1668 | properties: 1669 | name: 1670 | type: string 1671 | link: 1672 | type: string 1673 | image: 1674 | type: string 1675 | popular_questions: 1676 | type: array 1677 | items: 1678 | type: string 1679 | merchant_description: 1680 | type: object 1681 | properties: 1682 | title: 1683 | type: string 1684 | description: 1685 | type: string 1686 | profiles: 1687 | type: array 1688 | items: 1689 | type: object 1690 | properties: 1691 | name: 1692 | type: string 1693 | link: 1694 | type: string 1695 | image: 1696 | type: string 1697 | company_reviews: 1698 | type: array 1699 | items: 1700 | type: object 1701 | properties: 1702 | title: 1703 | type: string 1704 | link: 1705 | type: string 1706 | rating_text: 1707 | type: string 1708 | rating: 1709 | type: number 1710 | rating_out_of: 1711 | type: number 1712 | reviews: 1713 | type: integer 1714 | extensions: 1715 | type: array 1716 | items: 1717 | type: string 1718 | typical_salaries: 1719 | type: array 1720 | items: 1721 | type: object 1722 | properties: 1723 | title: 1724 | type: string 1725 | rating_text: 1726 | type: string 1727 | rating: 1728 | type: number 1729 | rating_out_of: 1730 | type: number 1731 | reviews: 1732 | type: integer 1733 | link: 1734 | type: string 1735 | editorial_reviews: 1736 | type: array 1737 | items: 1738 | type: object 1739 | properties: 1740 | title: 1741 | type: string 1742 | review: 1743 | type: string 1744 | rating: 1745 | type: number 1746 | source: 1747 | type: object 1748 | properties: 1749 | name: 1750 | type: string 1751 | link: 1752 | type: string 1753 | people_also_search_for: 1754 | type: array 1755 | items: 1756 | type: object 1757 | properties: 1758 | name: 1759 | type: string 1760 | extension: 1761 | type: string 1762 | link: 1763 | type: string 1764 | image: 1765 | type: string 1766 | people_also_search_for_link: 1767 | type: string 1768 | image: 1769 | type: string 1770 | local_map: 1771 | type: object 1772 | properties: 1773 | link: 1774 | type: string 1775 | gps_coordinates: 1776 | type: object 1777 | properties: 1778 | latitude: 1779 | type: number 1780 | longitude: 1781 | type: number 1782 | image: 1783 | type: string 1784 | images: 1785 | type: array 1786 | items: 1787 | type: string 1788 | 1789 | OrganicResult: 1790 | type: object 1791 | properties: 1792 | position: 1793 | type: integer 1794 | title: 1795 | type: string 1796 | link: 1797 | type: string 1798 | source: 1799 | type: string 1800 | domain: 1801 | type: string 1802 | displayed_link: 1803 | type: string 1804 | snippet: 1805 | type: string 1806 | snippet_highlighted_words: 1807 | type: array 1808 | items: 1809 | type: string 1810 | date: 1811 | type: string 1812 | displayed_results: 1813 | type: string 1814 | sitelinks: 1815 | type: object 1816 | properties: 1817 | inline: 1818 | type: array 1819 | items: 1820 | type: object 1821 | properties: 1822 | title: 1823 | type: string 1824 | link: 1825 | type: string 1826 | expanded: 1827 | type: array 1828 | items: 1829 | type: object 1830 | properties: 1831 | title: 1832 | type: string 1833 | link: 1834 | type: string 1835 | snippet: 1836 | type: string 1837 | list: 1838 | type: array 1839 | items: 1840 | type: object 1841 | properties: 1842 | title: 1843 | type: string 1844 | link: 1845 | type: string 1846 | answer_count: 1847 | type: integer 1848 | date: 1849 | type: string 1850 | searchbox: 1851 | type: boolean 1852 | rich_snippet: 1853 | type: object 1854 | properties: 1855 | detected_extensions: 1856 | type: object 1857 | properties: 1858 | rating: 1859 | type: number 1860 | reviews: 1861 | type: integer 1862 | time: 1863 | type: string 1864 | table: 1865 | type: object 1866 | properties: 1867 | headers: 1868 | type: array 1869 | items: 1870 | type: string 1871 | rows: 1872 | type: array 1873 | items: 1874 | type: array 1875 | items: 1876 | type: string 1877 | questions: 1878 | type: array 1879 | items: 1880 | type: object 1881 | properties: 1882 | question: 1883 | type: string 1884 | answer: 1885 | type: string 1886 | list: 1887 | type: array 1888 | items: 1889 | type: string 1890 | attributes: 1891 | type: array 1892 | items: 1893 | type: object 1894 | properties: 1895 | name: 1896 | type: string 1897 | value: 1898 | type: string 1899 | extensions: 1900 | type: array 1901 | items: 1902 | type: string 1903 | about_page_link: 1904 | type: string 1905 | favicon: 1906 | type: string 1907 | nested_results: 1908 | type: array 1909 | items: 1910 | $ref: '#/components/schemas/OrganicResult' 1911 | video: 1912 | type: object 1913 | properties: 1914 | link: 1915 | type: string 1916 | source: 1917 | type: string 1918 | channel: 1919 | type: string 1920 | date: 1921 | type: string 1922 | length: 1923 | type: string 1924 | key_moments: 1925 | type: array 1926 | items: 1927 | type: object 1928 | properties: 1929 | time: 1930 | type: string 1931 | seconds: 1932 | type: integer 1933 | title: 1934 | type: string 1935 | link: 1936 | type: string 1937 | thumbnail: 1938 | type: string 1939 | thumbnail: 1940 | type: string 1941 | images: 1942 | type: array 1943 | items: 1944 | type: string 1945 | 1946 | Event: 1947 | type: object 1948 | properties: 1949 | title: 1950 | type: string 1951 | link: 1952 | type: string 1953 | date: 1954 | type: object 1955 | properties: 1956 | day: 1957 | type: string 1958 | month: 1959 | type: string 1960 | duration: 1961 | type: string 1962 | address: 1963 | type: string 1964 | location: 1965 | type: string 1966 | thumbnail: 1967 | type: string 1968 | 1969 | University: 1970 | type: object 1971 | properties: 1972 | title: 1973 | type: string 1974 | link: 1975 | type: string 1976 | city: 1977 | type: string 1978 | education_type: 1979 | type: string 1980 | education_duration: 1981 | type: string 1982 | extracted_education_duration: 1983 | type: number 1984 | thumbnail: 1985 | type: string 1986 | 1987 | AboutThisResult: 1988 | type: array 1989 | items: 1990 | type: object 1991 | properties: 1992 | title: 1993 | type: string 1994 | link: 1995 | type: string 1996 | source: 1997 | type: string 1998 | domain: 1999 | type: string 2000 | displayed_link: 2001 | type: string 2002 | snippet: 2003 | type: string 2004 | date: 2005 | type: string 2006 | rating: 2007 | type: number 2008 | reviews: 2009 | type: integer 2010 | favicon: 2011 | type: string 2012 | 2013 | JobResults: 2014 | type: object 2015 | properties: 2016 | location: 2017 | type: string 2018 | filters: 2019 | type: array 2020 | items: 2021 | type: object 2022 | properties: 2023 | title: 2024 | type: string 2025 | is_trending: 2026 | type: boolean 2027 | link: 2028 | type: string 2029 | jobs: 2030 | type: array 2031 | items: 2032 | type: object 2033 | properties: 2034 | title: 2035 | type: string 2036 | company: 2037 | type: string 2038 | location: 2039 | type: string 2040 | via: 2041 | type: string 2042 | extensions: 2043 | type: array 2044 | items: 2045 | type: string 2046 | jobs_more_link: 2047 | type: object 2048 | properties: 2049 | title: 2050 | type: string 2051 | link: 2052 | type: string 2053 | 2054 | InlineImages: 2055 | type: object 2056 | properties: 2057 | suggestions: 2058 | type: array 2059 | items: 2060 | type: object 2061 | properties: 2062 | title: 2063 | type: string 2064 | link: 2065 | type: string 2066 | chips: 2067 | type: string 2068 | thumbnail: 2069 | type: string 2070 | images: 2071 | type: array 2072 | items: 2073 | type: object 2074 | properties: 2075 | title: 2076 | type: string 2077 | source: 2078 | type: object 2079 | properties: 2080 | name: 2081 | type: string 2082 | link: 2083 | type: string 2084 | original: 2085 | type: object 2086 | properties: 2087 | link: 2088 | type: string 2089 | width: 2090 | type: integer 2091 | height: 2092 | type: integer 2093 | size: 2094 | type: string 2095 | tag: 2096 | type: string 2097 | thumbnail: 2098 | type: string 2099 | 2100 | InlineShopping: 2101 | type: array 2102 | items: 2103 | type: object 2104 | properties: 2105 | position: 2106 | type: integer 2107 | title: 2108 | type: string 2109 | seller: 2110 | type: string 2111 | rating: 2112 | type: number 2113 | reviews: 2114 | type: integer 2115 | price: 2116 | type: string 2117 | extracted_price: 2118 | type: number 2119 | original_price: 2120 | type: string 2121 | extracted_original_price: 2122 | type: number 2123 | deal: 2124 | type: string 2125 | durability: 2126 | type: string 2127 | comments: 2128 | type: array 2129 | items: 2130 | type: string 2131 | review: 2132 | type: object 2133 | properties: 2134 | link: 2135 | type: string 2136 | source: 2137 | type: string 2138 | extensions: 2139 | type: array 2140 | items: 2141 | type: string 2142 | thumbnail: 2143 | type: string 2144 | 2145 | LocalMap: 2146 | type: object 2147 | properties: 2148 | link: 2149 | type: string 2150 | gps_coordinates: 2151 | type: object 2152 | properties: 2153 | latitude: 2154 | type: number 2155 | longitude: 2156 | type: number 2157 | image: 2158 | type: string 2159 | streetview: 2160 | type: object 2161 | properties: 2162 | link: 2163 | type: string 2164 | image: 2165 | type: string 2166 | 2167 | LocalResults: 2168 | type: array 2169 | items: 2170 | type: object 2171 | properties: 2172 | position: 2173 | type: integer 2174 | title: 2175 | type: string 2176 | link: 2177 | type: string 2178 | ludocid: 2179 | type: string 2180 | rating: 2181 | type: number 2182 | reviews: 2183 | type: integer 2184 | price: 2185 | type: string 2186 | price_description: 2187 | type: string 2188 | type: 2189 | type: string 2190 | address: 2191 | type: string 2192 | phone: 2193 | type: string 2194 | is_closed: 2195 | type: boolean 2196 | comment: 2197 | type: string 2198 | service_options: 2199 | type: array 2200 | items: 2201 | type: string 2202 | order: 2203 | type: string 2204 | website: 2205 | type: string 2206 | direction: 2207 | type: string 2208 | extensions: 2209 | type: array 2210 | items: 2211 | type: string 2212 | image: 2213 | type: string 2214 | 2215 | FromSourcesAcrossTheWeb: 2216 | type: object 2217 | properties: 2218 | title: 2219 | type: string 2220 | items: 2221 | type: array 2222 | items: 2223 | type: object 2224 | properties: 2225 | name: 2226 | type: string 2227 | thumbnail: 2228 | type: string 2229 | 2230 | DiscussionsAndForums: 2231 | type: array 2232 | items: 2233 | type: object 2234 | properties: 2235 | title: 2236 | type: string 2237 | link: 2238 | type: string 2239 | source: 2240 | type: string 2241 | date: 2242 | type: string 2243 | community: 2244 | type: string 2245 | posts: 2246 | type: string 2247 | 2248 | RelatedQuestions: 2249 | type: array 2250 | items: 2251 | type: object 2252 | properties: 2253 | question: 2254 | type: string 2255 | answer: 2256 | type: string 2257 | answer_highlight: 2258 | type: string 2259 | answer_list: 2260 | type: array 2261 | items: 2262 | type: object 2263 | properties: 2264 | text: 2265 | type: string 2266 | link: 2267 | type: string 2268 | image: 2269 | type: string 2270 | answer_table: 2271 | type: object 2272 | properties: 2273 | headers: 2274 | type: array 2275 | items: 2276 | type: string 2277 | rows: 2278 | type: array 2279 | items: 2280 | type: array 2281 | items: 2282 | type: string 2283 | date: 2284 | type: string 2285 | duration: 2286 | type: string 2287 | entity: 2288 | type: object 2289 | properties: 2290 | subject: 2291 | type: string 2292 | attribute: 2293 | type: string 2294 | value: 2295 | type: string 2296 | source: 2297 | $ref: '#/components/schemas/OrganicResult' 2298 | search: 2299 | type: object 2300 | properties: 2301 | title: 2302 | type: string 2303 | link: 2304 | type: string 2305 | 2306 | QuestionsAndAnswers: 2307 | type: array 2308 | items: 2309 | type: object 2310 | properties: 2311 | question: 2312 | type: string 2313 | answer: 2314 | type: string 2315 | link: 2316 | type: string 2317 | votes: 2318 | type: integer 2319 | source: 2320 | type: string 2321 | 2322 | ExploreBrands: 2323 | type: array 2324 | items: 2325 | type: object 2326 | properties: 2327 | title: 2328 | type: string 2329 | link: 2330 | type: string 2331 | snippet: 2332 | type: string 2333 | merchant: 2334 | type: object 2335 | properties: 2336 | rating: 2337 | type: number 2338 | reviews: 2339 | type: integer 2340 | link: 2341 | type: string 2342 | badge: 2343 | type: string 2344 | thumbnail: 2345 | type: string 2346 | 2347 | Courses: 2348 | type: array 2349 | items: 2350 | type: object 2351 | properties: 2352 | title: 2353 | type: string 2354 | link: 2355 | type: string 2356 | source: 2357 | type: string 2358 | rating: 2359 | type: number 2360 | reviews: 2361 | type: integer 2362 | extensions: 2363 | type: array 2364 | items: 2365 | type: string 2366 | thumbnail: 2367 | type: string 2368 | 2369 | TopStories: 2370 | type: array 2371 | items: 2372 | type: object 2373 | properties: 2374 | title: 2375 | type: string 2376 | link: 2377 | type: string 2378 | author: 2379 | type: string 2380 | author_link: 2381 | type: string 2382 | source: 2383 | type: string 2384 | date: 2385 | type: string 2386 | snippet: 2387 | type: string 2388 | is_live: 2389 | type: boolean 2390 | is_video: 2391 | type: boolean 2392 | thumbnail: 2393 | type: string 2394 | 2395 | ThingsToDo: 2396 | type: array 2397 | items: 2398 | type: object 2399 | properties: 2400 | title: 2401 | type: string 2402 | link: 2403 | type: string 2404 | rating: 2405 | type: number 2406 | reviews: 2407 | type: integer 2408 | attraction: 2409 | type: string 2410 | price: 2411 | type: string 2412 | extracted_price: 2413 | type: number 2414 | thumbnail: 2415 | type: string 2416 | 2417 | InlineVideos: 2418 | type: array 2419 | items: 2420 | type: object 2421 | properties: 2422 | position: 2423 | type: integer 2424 | title: 2425 | type: string 2426 | link: 2427 | type: string 2428 | is_live: 2429 | type: boolean 2430 | source: 2431 | type: string 2432 | channel: 2433 | type: string 2434 | date: 2435 | type: string 2436 | length: 2437 | type: string 2438 | key_moments: 2439 | type: array 2440 | items: 2441 | type: object 2442 | properties: 2443 | time: 2444 | type: string 2445 | seconds: 2446 | type: integer 2447 | title: 2448 | type: string 2449 | link: 2450 | type: string 2451 | thumbnail: 2452 | type: string 2453 | image: 2454 | type: string 2455 | 2456 | InlineTweets: 2457 | type: object 2458 | properties: 2459 | title: 2460 | type: string 2461 | link: 2462 | type: string 2463 | displayed_link: 2464 | type: string 2465 | tweets: 2466 | type: array 2467 | items: 2468 | type: object 2469 | properties: 2470 | tweet_id: 2471 | type: string 2472 | link: 2473 | type: string 2474 | snippet: 2475 | type: string 2476 | snippet_link: 2477 | type: string 2478 | is_video: 2479 | type: boolean 2480 | date: 2481 | type: string 2482 | author: 2483 | type: object 2484 | properties: 2485 | name: 2486 | type: string 2487 | screen_name: 2488 | type: string 2489 | link: 2490 | type: string 2491 | thumbnail: 2492 | type: string 2493 | images: 2494 | type: array 2495 | items: 2496 | type: string 2497 | thumbnail: 2498 | type: string 2499 | 2500 | ScholarlyArticles: 2501 | type: object 2502 | properties: 2503 | title: 2504 | type: string 2505 | link: 2506 | type: string 2507 | articles: 2508 | type: array 2509 | items: 2510 | type: object 2511 | properties: 2512 | title: 2513 | type: string 2514 | link: 2515 | type: string 2516 | title_highlighted_words: 2517 | type: array 2518 | items: 2519 | type: string 2520 | author: 2521 | type: string 2522 | cited_by: 2523 | type: integer 2524 | 2525 | InlineRecipes: 2526 | type: array 2527 | items: 2528 | type: object 2529 | properties: 2530 | title: 2531 | type: string 2532 | link: 2533 | type: string 2534 | rating: 2535 | type: number 2536 | reviews: 2537 | type: integer 2538 | ingredients_count: 2539 | type: integer 2540 | ingredients: 2541 | type: array 2542 | items: 2543 | type: string 2544 | source: 2545 | type: string 2546 | duration: 2547 | type: string 2548 | thumbnail: 2549 | type: string 2550 | 2551 | RelatedSearches: 2552 | type: array 2553 | items: 2554 | type: object 2555 | properties: 2556 | query: 2557 | type: string 2558 | link: 2559 | type: string 2560 | 2561 | securitySchemes: 2562 | ApiKeyAuth: 2563 | type: apiKey 2564 | in: query 2565 | name: api_key 2566 | 2567 | security: 2568 | - ApiKeyAuth: [] 2569 | 2570 | tags: 2571 | - name: Google Search 2572 | description: Third party API for Google Search from SearchApi 2573 | -------------------------------------------------------------------------------- /mcp_server.py: -------------------------------------------------------------------------------- 1 | # 建议将此代码保存为 mcp_server.py 2 | 3 | import os 4 | from typing import Any, Dict, List, Optional 5 | import httpx 6 | from mcp.server.fastmcp import FastMCP 7 | from datetime import datetime, timedelta 8 | 9 | # 从环境变量中读取 API Key,更安全 10 | SEARCHAPI_API_KEY = os.environ.get("SEARCHAPI_API_KEY") # 重要:运行前请设置环境变量 SEARCHAPI_API_KEY 11 | 12 | if not SEARCHAPI_API_KEY: 13 | print("错误:请设置环境变量 SEARCHAPI_API_KEY") 14 | # exit(1) # 如果希望在API Key缺失时阻止服务器启动,可以取消此注释 15 | 16 | # 初始化 FastMCP 服务器 17 | mcp = FastMCP("searchapi") 18 | 19 | # 常量 20 | SEARCHAPI_URL = "https://www.searchapi.io/api/v1/search" 21 | 22 | async def make_searchapi_request(params: Dict[str, Any]) -> Dict[str, Any]: 23 | """向searchapi.io发送请求并处理错误情况""" 24 | # 确保API Key被添加到参数中 25 | params["api_key"] = SEARCHAPI_API_KEY 26 | 27 | async with httpx.AsyncClient() as client: 28 | try: 29 | response = await client.get(SEARCHAPI_URL, params=params, timeout=30.0) 30 | response.raise_for_status() 31 | return response.json() 32 | except httpx.HTTPError as e: 33 | error_detail = None 34 | try: 35 | if hasattr(e, 'response') and e.response: 36 | error_detail = e.response.json() 37 | except ValueError: 38 | if hasattr(e, 'response') and e.response: 39 | error_detail = e.response.text 40 | 41 | error_message = f"调用searchapi.io时出错: {e}" 42 | if error_detail: 43 | error_message += f", 详情: {error_detail}" 44 | 45 | return {"error": error_message} 46 | except Exception as e: 47 | return {"error": f"处理请求时发生未知错误: {e}"} 48 | 49 | @mcp.tool() 50 | async def search_google_maps(query: str, location_ll: str = None) -> Dict[str, Any]: 51 | """搜索Google地图上的地点或服务""" 52 | params = { 53 | "engine": "google_maps", 54 | "q": query 55 | } 56 | 57 | if location_ll: 58 | params["ll"] = location_ll 59 | 60 | return await make_searchapi_request(params) 61 | 62 | @mcp.tool() 63 | async def search_google_flights( 64 | departure_id: str, 65 | arrival_id: str, 66 | outbound_date: str, 67 | flight_type: str = "round_trip", 68 | return_date: str = None, 69 | gl: str = None, 70 | hl: str = None, 71 | currency: str = None, 72 | travel_class: str = None, 73 | stops: str = None, 74 | sort_by: str = None, 75 | adults: str = None, 76 | children: str = None, 77 | multi_city_json: str = None, 78 | show_cheapest_flights: str = None, 79 | show_hidden_flights: str = None, 80 | max_price: str = None, 81 | carry_on_bags: str = None, 82 | checked_bags: str = None, 83 | included_airlines: str = None, 84 | excluded_airlines: str = None, 85 | outbound_times: str = None, 86 | return_times: str = None, 87 | emissions: str = None, 88 | included_connecting_airports: str = None, 89 | excluded_connecting_airports: str = None, 90 | layover_duration_min: str = None, 91 | layover_duration_max: str = None, 92 | max_flight_duration: str = None, 93 | separate_tickets: str = None, 94 | infants_in_seat: str = None, 95 | infants_on_lap: str = None, 96 | departure_token: str = None, 97 | booking_token: str = None 98 | ) -> Dict[str, Any]: 99 | """搜索Google航班信息""" 100 | params = { 101 | "engine": "google_flights", 102 | "flight_type": flight_type 103 | } 104 | 105 | # 处理flight_type不同情况下的必填参数 106 | if flight_type == "multi_city": 107 | if not multi_city_json: 108 | return {"error": "多城市行程需要'multi_city_json'参数"} 109 | params["multi_city_json"] = multi_city_json 110 | else: 111 | params["departure_id"] = departure_id 112 | params["arrival_id"] = arrival_id 113 | params["outbound_date"] = outbound_date 114 | 115 | if flight_type == "round_trip": 116 | if not return_date: 117 | return {"error": "往返行程需要'return_date'参数"} 118 | params["return_date"] = return_date 119 | 120 | # 添加可选参数 121 | optional_params = { 122 | "gl": gl, 123 | "hl": hl, 124 | "currency": currency, 125 | "travel_class": travel_class, 126 | "stops": stops, 127 | "sort_by": sort_by, 128 | "adults": adults, 129 | "children": children, 130 | "show_cheapest_flights": show_cheapest_flights, 131 | "show_hidden_flights": show_hidden_flights, 132 | "max_price": max_price, 133 | "carry_on_bags": carry_on_bags, 134 | "checked_bags": checked_bags, 135 | "included_airlines": included_airlines, 136 | "excluded_airlines": excluded_airlines, 137 | "outbound_times": outbound_times, 138 | "return_times": return_times, 139 | "emissions": emissions, 140 | "included_connecting_airports": included_connecting_airports, 141 | "excluded_connecting_airports": excluded_connecting_airports, 142 | "layover_duration_min": layover_duration_min, 143 | "layover_duration_max": layover_duration_max, 144 | "max_flight_duration": max_flight_duration, 145 | "separate_tickets": separate_tickets, 146 | "infants_in_seat": infants_in_seat, 147 | "infants_on_lap": infants_on_lap, 148 | "departure_token": departure_token, 149 | "booking_token": booking_token 150 | } 151 | 152 | # 添加有值的可选参数 153 | for key, value in optional_params.items(): 154 | if value is not None: 155 | params[key] = value 156 | 157 | return await make_searchapi_request(params) 158 | 159 | @mcp.tool() 160 | async def search_google_hotels( 161 | q: str, 162 | check_in_date: str, 163 | check_out_date: str, 164 | gl: str = None, 165 | hl: str = None, 166 | currency: str = None, 167 | property_type: str = None, 168 | sort_by: str = None, 169 | price_min: str = None, 170 | price_max: str = None, 171 | property_types: str = None, 172 | amenities: str = None, 173 | rating: str = None, 174 | free_cancellation: str = None, 175 | special_offers: str = None, 176 | for_displaced_individuals: str = None, 177 | eco_certified: str = None, 178 | hotel_class: str = None, 179 | brands: str = None, 180 | bedrooms: str = None, 181 | bathrooms: str = None, 182 | adults: str = None, 183 | children_ages: str = None, 184 | next_page_token: str = None 185 | ) -> Dict[str, Any]: 186 | """搜索Google酒店信息""" 187 | params = { 188 | "engine": "google_hotels", 189 | "q": q, 190 | "check_in_date": check_in_date, 191 | "check_out_date": check_out_date 192 | } 193 | 194 | # 添加可选参数 195 | optional_params = { 196 | "gl": gl, 197 | "hl": hl, 198 | "currency": currency, 199 | "property_type": property_type, 200 | "sort_by": sort_by, 201 | "price_min": price_min, 202 | "price_max": price_max, 203 | "property_types": property_types, 204 | "amenities": amenities, 205 | "rating": rating, 206 | "free_cancellation": free_cancellation, 207 | "special_offers": special_offers, 208 | "for_displaced_individuals": for_displaced_individuals, 209 | "eco_certified": eco_certified, 210 | "hotel_class": hotel_class, 211 | "brands": brands, 212 | "bedrooms": bedrooms, 213 | "bathrooms": bathrooms, 214 | "adults": adults, 215 | "children_ages": children_ages, 216 | "next_page_token": next_page_token 217 | } 218 | 219 | # 添加有值的可选参数 220 | for key, value in optional_params.items(): 221 | if value is not None: 222 | params[key] = value 223 | 224 | return await make_searchapi_request(params) 225 | 226 | @mcp.tool() 227 | async def search_google_maps_reviews( 228 | place_id: str = None, 229 | data_id: str = None, 230 | topic_id: str = None, 231 | next_page_token: str = None, 232 | sort_by: str = None, 233 | rating: str = None, 234 | hl: str = None, 235 | gl: str = None, 236 | reviews_limit: str = None 237 | ) -> Dict[str, Any]: 238 | """搜索Google地图上的评论数据""" 239 | params = { 240 | "engine": "google_maps_reviews" 241 | } 242 | 243 | # 检查必填参数 244 | if place_id: 245 | params["place_id"] = place_id 246 | elif data_id: 247 | params["data_id"] = data_id 248 | else: 249 | return {"error": "必须提供place_id或data_id参数"} 250 | 251 | # 添加其他可选参数 252 | optional_params = { 253 | "topic_id": topic_id, 254 | "next_page_token": next_page_token, 255 | "sort_by": sort_by, 256 | "rating": rating, 257 | "hl": hl, 258 | "gl": gl, 259 | "reviews_limit": reviews_limit 260 | } 261 | 262 | # 添加有值的可选参数 263 | for key, value in optional_params.items(): 264 | if value is not None: 265 | params[key] = value 266 | 267 | return await make_searchapi_request(params) 268 | 269 | @mcp.tool() 270 | async def search_google_hotels_property( 271 | property_token: str, 272 | check_in_date: str, 273 | check_out_date: str, 274 | gl: str = None, 275 | hl: str = None, 276 | currency: str = None, 277 | adults: str = None, 278 | children: str = None, 279 | children_ages: str = None 280 | ) -> Dict[str, Any]: 281 | """查询Google酒店详细信息""" 282 | params = { 283 | "engine": "google_hotels_property", 284 | "property_token": property_token, 285 | "check_in_date": check_in_date, 286 | "check_out_date": check_out_date 287 | } 288 | 289 | # 添加可选参数 290 | optional_params = { 291 | "gl": gl, 292 | "hl": hl, 293 | "currency": currency, 294 | "adults": adults, 295 | "children": children, 296 | "children_ages": children_ages 297 | } 298 | 299 | # 添加有值的可选参数 300 | for key, value in optional_params.items(): 301 | if value is not None: 302 | params[key] = value 303 | 304 | return await make_searchapi_request(params) 305 | 306 | @mcp.tool() 307 | async def search_google_flights_calendar( 308 | flight_type: str, 309 | departure_id: str, 310 | arrival_id: str, 311 | outbound_date: str, 312 | return_date: str = None, 313 | outbound_date_start: str = None, 314 | outbound_date_end: str = None, 315 | return_date_start: str = None, 316 | return_date_end: str = None, 317 | gl: str = None, 318 | hl: str = None, 319 | currency: str = None, 320 | adults: str = None, 321 | children: str = None, 322 | travel_class: str = None, 323 | stops: str = None 324 | ) -> Dict[str, Any]: 325 | """查询Google航班日历价格""" 326 | params = { 327 | "engine": "google_flights_calendar", 328 | "flight_type": flight_type, 329 | "departure_id": departure_id, 330 | "arrival_id": arrival_id, 331 | "outbound_date": outbound_date 332 | } 333 | 334 | # 检查航班类型,确保提供必要参数 335 | if flight_type == "round_trip" and not return_date: 336 | return {"error": "往返航班需要提供return_date参数"} 337 | elif flight_type == "round_trip": 338 | params["return_date"] = return_date 339 | 340 | # 添加可选参数 341 | optional_params = { 342 | "outbound_date_start": outbound_date_start, 343 | "outbound_date_end": outbound_date_end, 344 | "return_date_start": return_date_start, 345 | "return_date_end": return_date_end, 346 | "gl": gl, 347 | "hl": hl, 348 | "currency": currency, 349 | "adults": adults, 350 | "children": children, 351 | "travel_class": travel_class, 352 | "stops": stops 353 | } 354 | 355 | # 添加有值的可选参数 356 | for key, value in optional_params.items(): 357 | if value is not None: 358 | params[key] = value 359 | 360 | return await make_searchapi_request(params) 361 | 362 | @mcp.tool() 363 | async def get_current_time( 364 | format: str = "iso", 365 | days_offset: str = "0", 366 | return_future_dates: str = "false", 367 | future_days: str = "7" 368 | ) -> Dict[str, Any]: 369 | """获取当前系统时间和旅行日期建议""" 370 | now = datetime.now() 371 | 372 | # 将字符串参数转换为对应的数据类型 373 | try: 374 | days_offset_int = int(days_offset) if days_offset is not None else 0 375 | except (TypeError, ValueError): 376 | return {"error": "days_offset must be an integer"} 377 | 378 | return_future_dates_bool = return_future_dates.lower() == "true" if return_future_dates is not None else False 379 | 380 | try: 381 | future_days_int = int(future_days) if future_days is not None else 7 382 | except (TypeError, ValueError): 383 | return {"error": "future_days must be an integer"} 384 | 385 | target_date = now + timedelta(days=days_offset_int) 386 | 387 | result = { 388 | "now": { 389 | "iso": now.strftime("%Y-%m-%d"), 390 | "slash": now.strftime("%d/%m/%Y"), 391 | "chinese": now.strftime("%Y年%m月%d日"), 392 | "timestamp": int(now.timestamp()), 393 | "full": now.strftime("%Y-%m-%d %H:%M:%S"), 394 | "time": now.strftime("%H:%M:%S"), 395 | "weekday": now.strftime("%A"), 396 | "weekday_short": now.strftime("%a"), 397 | "year": now.year, 398 | "month": now.month, 399 | "day": now.day, 400 | "hour": now.hour, 401 | "minute": now.minute, 402 | "second": now.second 403 | }, 404 | "target_date": { 405 | "iso": target_date.strftime("%Y-%m-%d"), 406 | "slash": target_date.strftime("%d/%m/%Y"), 407 | "chinese": target_date.strftime("%Y年%m月%d日"), 408 | "timestamp": int(target_date.timestamp()), 409 | "full": target_date.strftime("%Y-%m-%d %H:%M:%S"), 410 | "time": target_date.strftime("%H:%M:%S"), 411 | "weekday": target_date.strftime("%A"), 412 | "weekday_short": target_date.strftime("%a"), 413 | "year": target_date.year, 414 | "month": target_date.month, 415 | "day": target_date.day, 416 | "hour": target_date.hour, 417 | "minute": target_date.minute, 418 | "second": target_date.second 419 | } 420 | } 421 | 422 | # 旅行场景常用日期 423 | result["travel_dates"] = { 424 | "today": now.strftime("%Y-%m-%d"), 425 | "tomorrow": (now + timedelta(days=1)).strftime("%Y-%m-%d"), 426 | "next_week": (now + timedelta(days=7)).strftime("%Y-%m-%d"), 427 | "next_month": (now + timedelta(days=30)).strftime("%Y-%m-%d"), 428 | "weekend": (now + timedelta((5 - now.weekday()) % 7)).strftime("%Y-%m-%d"), # 下一个周五 429 | "weekend_end": (now + timedelta((6 - now.weekday()) % 7 + 1)).strftime("%Y-%m-%d"), # 下一个周日 430 | } 431 | 432 | # 对于旅行预订常用的入住-退房日期对 433 | result["hotel_stay_suggestions"] = [ 434 | { 435 | "check_in": (now + timedelta(days=1)).strftime("%Y-%m-%d"), 436 | "check_out": (now + timedelta(days=3)).strftime("%Y-%m-%d"), 437 | "nights": 2, 438 | "description": "短暂周末度假" 439 | }, 440 | { 441 | "check_in": (now + timedelta(days=1)).strftime("%Y-%m-%d"), 442 | "check_out": (now + timedelta(days=8)).strftime("%Y-%m-%d"), 443 | "nights": 7, 444 | "description": "一周度假" 445 | }, 446 | { 447 | "check_in": (now + timedelta(days=30)).strftime("%Y-%m-%d"), 448 | "check_out": (now + timedelta(days=32)).strftime("%Y-%m-%d"), 449 | "nights": 2, 450 | "description": "下个月短暂出行" 451 | } 452 | ] 453 | 454 | # 如果需要一系列未来日期 455 | if return_future_dates_bool: 456 | future_dates = [] 457 | for i in range(future_days_int): 458 | future_date = now + timedelta(days=i) 459 | future_dates.append({ 460 | "iso": future_date.strftime("%Y-%m-%d"), 461 | "slash": future_date.strftime("%d/%m/%Y"), 462 | "chinese": future_date.strftime("%Y年%m月%d日"), 463 | "weekday": future_date.strftime("%A"), 464 | "weekday_short": future_date.strftime("%a"), 465 | "days_from_now": i 466 | }) 467 | result["future_dates"] = future_dates 468 | 469 | # 使用请求的格式作为主要返回值 470 | if format == "iso": 471 | result["date"] = target_date.strftime("%Y-%m-%d") 472 | elif format == "slash": 473 | result["date"] = target_date.strftime("%d/%m/%Y") 474 | elif format == "chinese": 475 | result["date"] = target_date.strftime("%Y年%m月%d日") 476 | elif format == "timestamp": 477 | result["date"] = int(target_date.timestamp()) 478 | elif format == "full": 479 | result["date"] = target_date.strftime("%Y-%m-%d %H:%M:%S") 480 | else: 481 | result["date"] = target_date.strftime("%Y-%m-%d") 482 | 483 | return result 484 | 485 | @mcp.tool() 486 | async def search_google( 487 | q: str, 488 | device: str = "desktop", 489 | location: str = None, 490 | uule: str = None, 491 | google_domain: str = "google.com", 492 | gl: str = "us", 493 | hl: str = "en", 494 | lr: str = None, 495 | cr: str = None, 496 | nfpr: str = "0", 497 | filter: str = "1", 498 | safe: str = "off", 499 | time_period: str = None, 500 | time_period_min: str = None, 501 | time_period_max: str = None, 502 | num: str = "10", 503 | page: str = "1" 504 | ) -> Dict[str, Any]: 505 | """搜索Google搜索结果,包括有机结果、知识图谱、回答框、相关问题、广告等""" 506 | params = { 507 | "engine": "google", 508 | "q": q 509 | } 510 | 511 | # 添加可选参数 512 | optional_params = { 513 | "device": device, 514 | "location": location, 515 | "uule": uule, 516 | "google_domain": google_domain, 517 | "gl": gl, 518 | "hl": hl, 519 | "lr": lr, 520 | "cr": cr, 521 | "nfpr": nfpr, 522 | "filter": filter, 523 | "safe": safe, 524 | "time_period": time_period, 525 | "time_period_min": time_period_min, 526 | "time_period_max": time_period_max, 527 | "num": num, 528 | "page": page 529 | } 530 | 531 | # 添加有值的可选参数 532 | for key, value in optional_params.items(): 533 | if value is not None: 534 | params[key] = value 535 | 536 | return await make_searchapi_request(params) 537 | 538 | @mcp.tool() 539 | async def search_google_videos( 540 | q: str, 541 | device: str = "desktop", 542 | location: str = None, 543 | uule: str = None, 544 | google_domain: str = "google.com", 545 | gl: str = "us", 546 | hl: str = "en", 547 | lr: str = None, 548 | cr: str = None, 549 | nfpr: str = "0", 550 | filter: str = "1", 551 | safe: str = "off", 552 | time_period: str = None, 553 | time_period_min: str = None, 554 | time_period_max: str = None, 555 | num: str = "10", 556 | page: str = "1" 557 | ) -> Dict[str, Any]: 558 | """搜索Google视频结果,根据设备类型返回视频列表、视频轮播或短视频""" 559 | params = { 560 | "engine": "google_videos", 561 | "q": q 562 | } 563 | 564 | # 添加可选参数 565 | optional_params = { 566 | "device": device, 567 | "location": location, 568 | "uule": uule, 569 | "google_domain": google_domain, 570 | "gl": gl, 571 | "hl": hl, 572 | "lr": lr, 573 | "cr": cr, 574 | "nfpr": nfpr, 575 | "filter": filter, 576 | "safe": safe, 577 | "time_period": time_period, 578 | "time_period_min": time_period_min, 579 | "time_period_max": time_period_max, 580 | "num": num, 581 | "page": page 582 | } 583 | 584 | # 添加有值的可选参数 585 | for key, value in optional_params.items(): 586 | if value is not None: 587 | params[key] = value 588 | 589 | return await make_searchapi_request(params) 590 | 591 | if __name__ == "__main__": 592 | # 从环境变量获取 transport 类型,默认为 stdio 593 | transport = os.environ.get("MCP_TRANSPORT", "stdio") 594 | # 初始化并运行服务器 595 | mcp.run(transport=transport) -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | httpx>=0.24.0 2 | fastmcp>=0.1.0 3 | python-dotenv>=1.0.0 -------------------------------------------------------------------------------- /tests/test_get_current_time.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from unittest.mock import patch 3 | from datetime import datetime 4 | 5 | import mcp_server 6 | 7 | FIXED_NOW = datetime(2023, 1, 1, 12, 0, 0) 8 | 9 | class FixedDateTime(datetime): 10 | @classmethod 11 | def now(cls, tz=None): 12 | return FIXED_NOW 13 | 14 | class GetCurrentTimeTests(unittest.IsolatedAsyncioTestCase): 15 | async def test_default_output(self): 16 | with patch('mcp_server.datetime', FixedDateTime): 17 | result = await mcp_server.get_current_time() 18 | self.assertEqual(result['date'], '2023-01-01') 19 | self.assertEqual(result['target_date']['iso'], '2023-01-01') 20 | self.assertEqual(result['now']['iso'], '2023-01-01') 21 | 22 | async def test_non_zero_offset(self): 23 | with patch('mcp_server.datetime', FixedDateTime): 24 | result = await mcp_server.get_current_time(days_offset='3') 25 | self.assertEqual(result['date'], '2023-01-04') 26 | self.assertEqual(result['target_date']['iso'], '2023-01-04') 27 | 28 | async def test_invalid_offset(self): 29 | result = await mcp_server.get_current_time(days_offset='bad') 30 | self.assertIn('error', result) 31 | 32 | if __name__ == '__main__': 33 | unittest.main() 34 | --------------------------------------------------------------------------------