Skip to content

Commit e5c9c70

Browse files
committed
feat: scholar search and SearchApi routing
1 parent 1496496 commit e5c9c70

27 files changed

Lines changed: 1710 additions & 80 deletions

.mcpbignore

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
*
2+
!manifest.json
3+
!LICENSE
4+
!README.md
5+
!README.ko.md
6+
!assets
7+
assets/*
8+
!assets/icon512.png
9+
!assets/searchapi-banner.png

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
# Changelog
22

3+
## [0.8.0]
4+
5+
### Added
6+
- `scholar_search` for Google Scholar paper metadata, citations, related versions, and available full text.
7+
- SearchApi primary and browser fallback modes for `search`, `search_parallel`, and `scholar_search`.
8+
- `SEARCH_API`, `SURF_SEARCH_PROVIDER`, and `SURF_SCHOLAR_PROVIDER` configuration.
9+
- SearchApi sponsorship banner and provider documentation.
10+
11+
### Changed
12+
- Browser search remains the default and requires no API key.
13+
- Provider selection and SearchApi key status are visible in `health` without exposing the key.
14+
315
## [0.6.6]
416

517
### Changed

README.ko.md

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,16 @@
99
[![ci](https://github.com/HarimxChoi/google-surf-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/HarimxChoi/google-surf-mcp/actions/workflows/ci.yml)
1010
[![google-surf-mcp MCP server](https://glama.ai/mcp/servers/HarimxChoi/google-surf-mcp/badges/score.svg)](https://glama.ai/mcp/servers/HarimxChoi/google-surf-mcp)
1111

12+
<p align="center">
13+
<a href="https://www.searchapi.io/?utm_source=github&utm_medium=sponsorship&utm_campaign=google_search_api&utm_content=HarimxChoi_google-surf-mcp"><img src="./assets/searchapi-banner.png" width="100%" alt="SearchApi Google Search API" /></a>
14+
</p>
15+
<p align="center"><a href="https://www.searchapi.io/?utm_source=github&utm_medium=sponsorship&utm_campaign=google_search_api&utm_content=HarimxChoi_google-surf-mcp">SearchApi</a> 후원</p>
16+
1217
![demo](./assets/demo.gif)
1318

1419
> 실제 사용은 기본 **headless**로 동작합니다 (Chrome 창 안 보임). 영상처럼 보이게 하려면 `SURF_HEADLESS=false` 설정
1520
16-
무료 Google 검색 MCP가 전부 안 돼서 직접 만든 MCP
21+
브라우저 모드는 API 키 없이 동작하고 SearchApi는 선택 사항입니다.
1722

1823
MCP 1개가 3개 역할: 검색 + URL fetcher + 학술 페이퍼 추출
1924

@@ -23,9 +28,9 @@ MCP 1개가 3개 역할: 검색 + URL fetcher + 학술 페이퍼 추출
2328
`search_extract` 기본 abstract 모드 (~1500자/결과, 토큰 절약), `mode="full"`로 본문 전체
2429
✅ 스폰서 광고 + 지식 패널 자동 제거 (geometric verification, 텍스트 매칭 아님)
2530
✅ CAPTCHA 자동 복구 4모드: OS 알림 (기본) / `SURF_HEADLESS=false` / `SURF_REMOTE_DEBUG` / `SURF_CLOUD_MODE` (fail-fast)
26-
✅ API 키 / 프록시 / 솔버 X
31+
브라우저 모드는 API 키, 프록시, 솔버 불필요
2732

28-
도구 5개: `search` / `search_parallel` / `extract` / `search_extract` / `health`
33+
도구 6개: `search` / `scholar_search` / `search_parallel` / `extract` / `search_extract` / `health`
2934

3035
## How
3136

@@ -58,7 +63,7 @@ CAPTCHA는 사람이 직접 함 (프로필 평판 유지 → 지속가능한 운
5863

5964
## Install
6065

61-
Node 18+, 시스템에 Google Chrome (또는 Chromium) 필요
66+
Node 18+ 필요. 브라우저 모드는 Google Chrome 또는 Chromium도 필요합니다.
6267

6368
```bash
6469
npx google-surf-mcp # 실제 MCP, 클라이언트 config에 등록
@@ -103,6 +108,34 @@ Claude Code 재시작
103108

104109
다른 MCP 클라이언트도 같은 JSON 구조 그대로 (config 파일 경로만 다름)
105110

111+
## 검색 provider
112+
113+
기본값은 기존 브라우저 검색입니다. [SearchApi](https://www.searchapi.io/?utm_source=github&utm_medium=sponsorship&utm_campaign=google_search_api&utm_content=HarimxChoi_google-surf-mcp)를 메인 provider 또는 브라우저 실패 시 fallback으로 설정할 수 있습니다.
114+
115+
|| 동작 |
116+
|---|---|
117+
| `browser` | 기본값. 기존 Google Surf 브라우저 경로를 사용하며 `SEARCH_API`가 필요하지 않습니다. |
118+
| `searchapi` | SearchApi를 메인 provider로 사용합니다. 해당 도구 실행 시 Chrome을 초기화하지 않습니다. |
119+
| `fallback` | 브라우저를 먼저 사용합니다. 브라우저 오류, CAPTCHA나 rate limit, 프로필 실패, 파서 열화 시에만 SearchApi로 전환합니다. 성공 응답과 정상적인 빈 결과는 다시 요청하지 않습니다. |
120+
121+
`SURF_SEARCH_PROVIDER``search`, `search_parallel`에 적용됩니다. `SURF_SCHOLAR_PROVIDER``scholar_search`에 적용됩니다. SearchApi 모드는 본인의 SearchApi 계정, API 키, 사용 가능한 크레딧이 필요합니다.
122+
123+
```json
124+
{
125+
"mcpServers": {
126+
"google-surf": {
127+
"command": "npx",
128+
"args": ["-y", "google-surf-mcp"],
129+
"env": {
130+
"SEARCH_API": "your-searchapi-key",
131+
"SURF_SEARCH_PROVIDER": "fallback",
132+
"SURF_SCHOLAR_PROVIDER": "searchapi"
133+
}
134+
}
135+
}
136+
}
137+
```
138+
106139
로컬 클론 사용 시:
107140
```json
108141
{
@@ -117,8 +150,9 @@ Claude Code 재시작
117150

118151
## Tools
119152

120-
- `search(query, limit?)` - 단일 검색, ~1.5초. title / url / snippet 반환. 스폰서 광고 + 지식 패널 자동 제거 (응답에 `dropped` 카운트 + `dropped_reasons` 포함). 결과 24h 캐시 (`SURF_CACHE_TTL_SEARCH_MS=0`으로 우회)
121-
- `search_parallel(queries[], limit?)` - 4-워커 풀, 호출당 최대 10개 쿼리
153+
- `search(query, limit?)` - 브라우저 모드 기준 단일 검색, ~1.5초. title / url / snippet 반환. 브라우저 경로에서는 스폰서 광고와 지식 패널을 제거합니다. 결과 24h 캐시 (`SURF_CACHE_TTL_SEARCH_MS=0`으로 우회)
154+
- `scholar_search(query, limit?)` - Google Scholar 논문 검색, 최대 10개. 저자, 출판 정보, 연도, 초록 일부, 인용 수, 관련 논문/버전 링크, 원문 링크 반환. 브라우저, SearchApi 메인, fallback 모드를 지원합니다.
155+
- `search_parallel(queries[], limit?)` - 브라우저 모드에서는 4-워커 풀을 사용합니다. 호출당 최대 10개 쿼리이며 `SURF_SEARCH_PROVIDER`를 따릅니다.
122156
- `extract(url, max_chars?, mode?)` - URL 가져와서 본문 반환
123157
- `mode="full"` (기본): 본문 전체, PDF는 `liteparse`(spatial parsing, 다단 읽기)
124158
- `mode="abstract"`: ~1500자 요약 (PDF 1페이지 또는 HTML meta description). 본문 가져오기 전 관련성 판단용
@@ -131,6 +165,10 @@ Claude Code 재시작
131165

132166
| 변수 | 기본값 | 설명 |
133167
|---|---|---|
168+
| `SEARCH_API` | 미설정 | SearchApi API 키. provider가 `searchapi` 또는 `fallback`일 때만 필요합니다. bearer token으로 전송하며 URL에는 넣지 않습니다. |
169+
| `SEARCHAPI_API_KEY` | 미설정 | `SEARCH_API` 별칭 |
170+
| `SURF_SEARCH_PROVIDER` | `browser` | `search`, `search_parallel` provider: `browser`, `searchapi`, `fallback` |
171+
| `SURF_SCHOLAR_PROVIDER` | `browser` | `scholar_search` provider: `browser`, `searchapi`, `fallback` |
134172
| `CHROME_PATH` | 자동 감지 | Chrome 바이너리 절대 경로 |
135173
| `SURF_PROFILE_ROOT` | `~/.google-surf-mcp` | warm 프로필 위치 |
136174
| `SURF_LOCALE` | `en-US` | 브라우저 로케일 |
@@ -144,7 +182,7 @@ Claude Code 재시작
144182
| `SURF_CLOUD_MODE` | `false` | headless/서버리스 모드: TLS 우회 + `--no-sandbox` + `--disable-dev-shm-usage` + 워커 풀 비활성 + CAPTCHA fail-fast |
145183
| `SURF_CASCADE_DISABLED` | `false` | 3-tier 자동 cascade 대신 단일 stealth 모드(`SURF_USE_STEALTH`로 선택)로 고정 |
146184
| `SURF_USE_STEALTH` | `true` | 초기 stealth tier — `SURF_CASCADE_DISABLED=true`일 때만 적용 |
147-
| `SURF_HUMANLIKE_MODE` | `off` | `off` / `background` (결과 반환 후 비동기 실행) / `inline` (반환 전 대기, 더 느림) — opt-in humanlike 브라우징 |
185+
| `SURF_HUMANLIKE_MODE` | `background` | `off` / `background` (결과 반환 후 비동기 실행) / `inline` (반환 전 대기, 더 느림) |
148186
| `SURF_RATE_LIMIT_PER_MIN` | `10` | 분당 Google 요청 내부 상한 |
149187
| `SURF_CACHE_TTL_SEARCH_MS` | `86400000` | search 캐시 TTL (24h); `0`이면 캐시 비활성화 |
150188
| `SURF_CACHE_MAX_ENTRIES` | `1000` | 캐시 namespace별 LRU 상한 |

README.md

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,16 @@ English | [한국어](./README.ko.md)
1010
[![MCP Toplist](https://mcptoplist.com/badge/io.github.HarimxChoi%2Fgoogle-surf-mcp.svg)](https://mcptoplist.com/server/io.github.HarimxChoi%2Fgoogle-surf-mcp)
1111
[![google-surf-mcp MCP server](https://glama.ai/mcp/servers/HarimxChoi/google-surf-mcp/badges/score.svg)](https://glama.ai/mcp/servers/HarimxChoi/google-surf-mcp)
1212

13+
<p align="center">
14+
<a href="https://www.searchapi.io/?utm_source=github&utm_medium=sponsorship&utm_campaign=google_search_api&utm_content=HarimxChoi_google-surf-mcp"><img src="./assets/searchapi-banner.png" width="100%" alt="SearchApi Google Search API" /></a>
15+
</p>
16+
<p align="center">Sponsored by <a href="https://www.searchapi.io/?utm_source=github&utm_medium=sponsorship&utm_campaign=google_search_api&utm_content=HarimxChoi_google-surf-mcp">SearchApi</a></p>
17+
1318
![demo](./assets/demo.gif)
1419

1520
> Demo only. Actual searches run **headless** by default (no visible browser). Set `SURF_HEADLESS=false` to make Chrome visible like in the clip above.
1621
17-
Google search MCP. No API key. Just works.
22+
Google search MCP. Browser mode needs no API key. SearchApi is optional.
1823

1924
One MCP replaces three: search + URL fetcher + academic-paper extractor.
2025

@@ -24,9 +29,9 @@ One MCP replaces three: search + URL fetcher + academic-paper extractor.
2429
-`search_extract` defaults to abstract mode (~1500 chars/result, token-cheap), `mode="full"` for whole bodies
2530
- ✅ Sponsored ads + knowledge panels dropped (geometric verification, not just text matching)
2631
- ✅ CAPTCHA recovery in 4 modes: OS notification (default) / `SURF_HEADLESS=false` / `SURF_REMOTE_DEBUG` / `SURF_CLOUD_MODE` (fail-fast)
27-
-No API key, no proxies, no solver
32+
-Browser mode needs no API key, proxy, or solver
2833

29-
5 tools: `search` / `search_parallel` / `extract` / `search_extract` / `health`
34+
6 tools: `search` / `scholar_search` / `search_parallel` / `extract` / `search_extract` / `health`
3035

3136
## What
3237

@@ -60,7 +65,7 @@ Measured on a workstation with a 1Gb/s connection.
6065

6166
## Install
6267

63-
Requires Node 18+ and Google Chrome (or Chromium) on the system.
68+
Requires Node 18+. Browser mode also requires Google Chrome or Chromium.
6469

6570
```bash
6671
npx google-surf-mcp # actual MCP - register in client config
@@ -101,10 +106,38 @@ Paste this into your `~/.claude.json`:
101106
}
102107
```
103108

104-
Restart Claude Code. Done. `search`, `search_parallel`, `extract`, `search_extract`, `health` are now available.
109+
Restart Claude Code. Done. `search`, `scholar_search`, `search_parallel`, `extract`, `search_extract`, `health` are now available.
105110

106111
For other MCP clients, use the same JSON shape in their config file.
107112

113+
## Search providers
114+
115+
Browser search remains the default. [SearchApi](https://www.searchapi.io/?utm_source=github&utm_medium=sponsorship&utm_campaign=google_search_api&utm_content=HarimxChoi_google-surf-mcp) can be selected as the primary provider or used only when browser search fails.
116+
117+
| value | behavior |
118+
|---|---|
119+
| `browser` | Default. Uses the existing Google Surf browser path and does not require `SEARCH_API`. |
120+
| `searchapi` | Uses SearchApi as the primary provider and does not initialize Chrome for that tool. |
121+
| `fallback` | Uses the browser first, then SearchApi on browser errors, CAPTCHA/rate limits, profile failure, or parser degradation. Successful and normal empty browser responses are not repeated. |
122+
123+
`SURF_SEARCH_PROVIDER` controls `search` and `search_parallel`. `SURF_SCHOLAR_PROVIDER` controls `scholar_search`. SearchApi modes require your own SearchApi account, key, and available credits.
124+
125+
```json
126+
{
127+
"mcpServers": {
128+
"google-surf": {
129+
"command": "npx",
130+
"args": ["-y", "google-surf-mcp"],
131+
"env": {
132+
"SEARCH_API": "your-searchapi-key",
133+
"SURF_SEARCH_PROVIDER": "fallback",
134+
"SURF_SCHOLAR_PROVIDER": "searchapi"
135+
}
136+
}
137+
}
138+
}
139+
```
140+
108141
Local clone variant:
109142
```json
110143
{
@@ -119,8 +152,9 @@ Local clone variant:
119152

120153
## Tools
121154

122-
- `search(query, limit?)` - single query, ~1.5s. Returns title / url / snippet. Sponsored ads + knowledge-panel dropped (response includes `dropped` count + `dropped_reasons`). Results cached 24h (`SURF_CACHE_TTL_SEARCH_MS=0` to bypass).
123-
- `search_parallel(queries[], limit?)` - pool of 4, max 10 queries per call.
155+
- `search(query, limit?)` - single query, ~1.5s in browser mode. Returns title / url / snippet. Sponsored ads + knowledge-panel dropped on the browser path. Results cached 24h (`SURF_CACHE_TTL_SEARCH_MS=0` to bypass).
156+
- `scholar_search(query, limit?)` - Google Scholar search, max 10 papers. Returns authors, publication, year, snippet, citation count, related/version links, and an available full-text link. Supports browser, SearchApi primary, and fallback modes.
157+
- `search_parallel(queries[], limit?)` - pool of 4 in browser mode, max 10 queries per call. Follows `SURF_SEARCH_PROVIDER`.
124158
- `extract(url, max_chars?, mode?)` - fetch a URL, return article content.
125159
- `mode="full"` (default): whole body. HTML via Readability, PDFs via `liteparse` (spatial parsing, multi-column reading order).
126160
- `mode="abstract"`: ~1500-char survey (PDF page 1 or HTML meta description). Triage relevance before paying for full text.
@@ -133,6 +167,10 @@ Local clone variant:
133167

134168
| var | default | notes |
135169
|---|---|---|
170+
| `SEARCH_API` | unset | SearchApi API key. Required only when either provider setting is `searchapi` or `fallback`. Sent as a bearer token and never placed in the request URL. |
171+
| `SEARCHAPI_API_KEY` | unset | Alias for `SEARCH_API`. |
172+
| `SURF_SEARCH_PROVIDER` | `browser` | Provider for `search` and `search_parallel`: `browser`, `searchapi`, or `fallback`. |
173+
| `SURF_SCHOLAR_PROVIDER` | `browser` | Provider for `scholar_search`: `browser`, `searchapi`, or `fallback`. |
136174
| `CHROME_PATH` | auto-detected | absolute path to Chrome binary |
137175
| `SURF_PROFILE_ROOT` | `~/.google-surf-mcp` | where the warm profile lives |
138176
| `SURF_LOCALE` | `en-US` | browser locale |
@@ -146,7 +184,7 @@ Local clone variant:
146184
| `SURF_CLOUD_MODE` | `false` | headless/serverless mode: TLS bypass + `--no-sandbox` + `--disable-dev-shm-usage` + worker pool disabled + fail-fast on CAPTCHA |
147185
| `SURF_CASCADE_DISABLED` | `false` | pin a single stealth mode (chosen by `SURF_USE_STEALTH`) instead of the 3-tier auto-cascade |
148186
| `SURF_USE_STEALTH` | `true` | initial stealth tier — only consulted when `SURF_CASCADE_DISABLED=true` |
149-
| `SURF_HUMANLIKE_MODE` | `off` | `off` / `background` (fire-and-forget after returning results) / `inline` (await before returning, slower) — opt-in humanlike browsing |
187+
| `SURF_HUMANLIKE_MODE` | `background` | `off` / `background` (fire-and-forget after returning results) / `inline` (await before returning, slower) |
150188
| `SURF_RATE_LIMIT_PER_MIN` | `10` | internal cap on Google-facing requests per minute |
151189
| `SURF_CACHE_TTL_SEARCH_MS` | `86400000` | search cache TTL (24h); `0` disables caching |
152190
| `SURF_CACHE_MAX_ENTRIES` | `1000` | LRU cap per cache namespace |

assets/searchapi-banner.png

488 KB
Loading

google-surf-mcp.mcpb

515 KB
Binary file not shown.

manifest.json

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
{
2-
"manifest_version": "0.3",
2+
"$schema": "https://raw.githubusercontent.com/anthropics/mcpb/main/schemas/mcpb-manifest-v0.4.schema.json",
3+
"manifest_version": "0.4",
34
"name": "google-surf-mcp",
45
"display_name": "Google Surf",
5-
"version": "0.7.0",
6-
"description": "Free Google search MCP that actually works — no API key, no proxies, no solvers. Search + extraction in one MCP.",
7-
"long_description": "Free Google search MCP that actually works — no API key, no proxies, no solvers (most free Google search MCPs fail in practice; this one drives a warm Chrome profile via Playwright + stealth). Search + page extraction in one MCP: `search_extract` returns SERP results already enriched with article bodies — replaces the usual search-MCP + fetch-MCP combo. CAPTCHA opens a visible Chrome window for a human to solve (shared-IP reputation protection); `SURF_CLOUD_MODE=true` for headless/serverless fail-fast.",
6+
"version": "0.8.0",
7+
"description": "Google and Google Scholar search with browser and optional SearchApi providers.",
8+
"long_description": "Google and Google Scholar search with page extraction. Browser mode uses a warm Chrome profile and requires no API key. SearchApi can be configured as the primary provider or as fallback for browser errors, CAPTCHA, rate limits, profile failure, and parser degradation.",
89
"author": {
910
"name": "harimxchoi",
1011
"url": "https://github.com/HarimxChoi"
@@ -20,25 +21,28 @@
2021
"keywords": [
2122
"google",
2223
"google-search",
24+
"google-scholar",
25+
"academic-search",
2326
"search",
2427
"web-search",
2528
"serp",
2629
"playwright",
2730
"headless-browser"
2831
],
29-
"icons": {
30-
"default": "https://raw.githubusercontent.com/HarimxChoi/google-surf-mcp/main/assets/icon-512.png"
31-
},
32+
"icon": "assets/icon512.png",
3233
"server": {
3334
"type": "node",
3435
"entry_point": "build/index.js",
3536
"mcp_config": {
3637
"command": "npx",
3738
"args": [
3839
"-y",
39-
"google-surf-mcp@0.7.0"
40+
"google-surf-mcp@0.8.0"
4041
],
4142
"env": {
43+
"SEARCH_API": "${user_config.search_api_key}",
44+
"SURF_SEARCH_PROVIDER": "${user_config.search_provider}",
45+
"SURF_SCHOLAR_PROVIDER": "${user_config.scholar_provider}",
4246
"CHROME_PATH": "${user_config.chrome_path}",
4347
"SURF_PROFILE_ROOT": "${user_config.profile_root}",
4448
"SURF_LOCALE": "${user_config.locale}",
@@ -56,11 +60,15 @@
5660
"tools": [
5761
{
5862
"name": "search",
59-
"description": "Single Google search -> title/url/snippet per result. Results cached 24h. First call ~4s, then ~2s. On CAPTCHA opens visible Chrome for human solving; SURF_CLOUD_MODE=true for fail-fast."
63+
"description": "Single Google search via browser, SearchApi primary, or browser-to-SearchApi fallback. Returns title, URL, and snippet."
64+
},
65+
{
66+
"name": "scholar_search",
67+
"description": "Google Scholar search via browser, SearchApi primary, or fallback. Returns paper metadata, citations, links, and available full text."
6068
},
6169
{
6270
"name": "search_parallel",
63-
"description": "Run 2-10 Google searches concurrently. Rate-limited (~10/min). Disabled in cloud mode."
71+
"description": "Run 2-10 Google searches using the provider selected by SURF_SEARCH_PROVIDER. SearchApi works in cloud mode."
6472
},
6573
{
6674
"name": "extract",
@@ -76,6 +84,27 @@
7684
}
7785
],
7886
"user_config": {
87+
"search_api_key": {
88+
"type": "string",
89+
"title": "SearchApi API key",
90+
"description": "Required only for SearchApi primary or fallback modes.",
91+
"sensitive": true,
92+
"required": false
93+
},
94+
"search_provider": {
95+
"type": "string",
96+
"title": "Google search provider",
97+
"description": "browser, searchapi, or fallback.",
98+
"default": "browser",
99+
"required": false
100+
},
101+
"scholar_provider": {
102+
"type": "string",
103+
"title": "Google Scholar provider",
104+
"description": "browser, searchapi, or fallback.",
105+
"default": "browser",
106+
"required": false
107+
},
79108
"chrome_path": {
80109
"type": "file",
81110
"title": "Chrome binary path",
@@ -153,4 +182,4 @@
153182
"node": ">=18.0.0"
154183
}
155184
}
156-
}
185+
}

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
{
22
"name": "google-surf-mcp",
3-
"version": "0.7.0",
3+
"version": "0.8.0",
44
"mcpName": "io.github.HarimxChoi/google-surf-mcp",
5-
"description": "MCP server for Google search via warm Chrome profile. No API key.",
5+
"description": "Google and Google Scholar MCP with browser and optional SearchApi providers.",
66
"type": "module",
77
"bin": {
88
"google-surf-mcp": "build/index.js"
99
},
1010
"files": [
1111
"build",
12+
"assets/searchapi-banner.png",
1213
"README.md",
1314
"LICENSE"
1415
],
@@ -29,6 +30,8 @@
2930
"model-context-protocol",
3031
"google",
3132
"google-search",
33+
"google-scholar",
34+
"academic-search",
3235
"search",
3336
"web-search",
3437
"serp",

0 commit comments

Comments
 (0)