search-rotation 0.4.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +124 -0
- package/dist/abort.js +14 -0
- package/dist/config.js +109 -0
- package/dist/engines/base.js +72 -0
- package/dist/engines/duckduckgo.js +98 -0
- package/dist/engines/exa.js +113 -0
- package/dist/engines/firecrawl.js +78 -0
- package/dist/engines/googlecse.js +41 -0
- package/dist/engines/hosted-mcp.js +24 -0
- package/dist/engines/index.js +13 -0
- package/dist/engines/jina.js +28 -0
- package/dist/engines/parallel.js +74 -0
- package/dist/engines/tavily.js +74 -0
- package/dist/history.js +59 -0
- package/dist/index.js +182 -0
- package/dist/mcp/engine-status.js +58 -0
- package/dist/mcp/http.js +35 -0
- package/dist/mcp/server.js +105 -0
- package/dist/persistence.js +80 -0
- package/dist/quota.js +37 -0
- package/dist/router.js +183 -0
- package/dist/search-time.js +31 -0
- package/dist/status.js +141 -0
- package/dist/types.js +1 -0
- package/dist/usage.js +95 -0
- package/dist/version.js +5 -0
- package/dist/web/app.js +155 -0
- package/dist/web/security.js +116 -0
- package/docs/assets/brand/FONT-LICENSE.txt +93 -0
- package/docs/assets/brand/README.md +18 -0
- package/docs/assets/brand/icon-128.png +0 -0
- package/docs/assets/brand/icon-32.png +0 -0
- package/docs/assets/brand/icon-512.png +0 -0
- package/docs/assets/brand/icon-dark-128.png +0 -0
- package/docs/assets/brand/icon-dark-512.png +0 -0
- package/docs/assets/brand/icon-dark.svg +1 -0
- package/docs/assets/brand/icon-light-128.png +0 -0
- package/docs/assets/brand/icon-light-512.png +0 -0
- package/docs/assets/brand/icon-light.svg +1 -0
- package/docs/assets/brand/icon-mono.svg +1 -0
- package/docs/assets/brand/icon.svg +1 -0
- package/docs/assets/brand/preview.png +0 -0
- package/docs/assets/brand/preview.svg +1 -0
- package/docs/assets/brand/wordmark-dark.svg +1 -0
- package/docs/assets/brand/wordmark-light.svg +1 -0
- package/docs/assets/dashboard-dark.png +0 -0
- package/docs/assets/dashboard-light.png +0 -0
- package/docs/assets/dashboard.png +0 -0
- package/docs/assets/mcp-tools-dark.png +0 -0
- package/docs/assets/mcp-tools-light.png +0 -0
- package/docs/assets/mcp-tools.png +0 -0
- package/docs/assets/search-rotation.svg +52 -0
- package/docs/clients.md +93 -0
- package/docs/operations.md +66 -0
- package/docs/provider-access.md +38 -0
- package/docs/release-notes.md +52 -0
- package/package.json +65 -0
- package/static/app.js +1126 -0
- package/static/engine-logos/README.md +11 -0
- package/static/engine-logos/duckduckgo.png +0 -0
- package/static/engine-logos/exa.png +0 -0
- package/static/engine-logos/firecrawl.png +0 -0
- package/static/engine-logos/google-cse.png +0 -0
- package/static/engine-logos/jina.png +0 -0
- package/static/engine-logos/parallel.png +0 -0
- package/static/engine-logos/tavily.png +0 -0
- package/static/i18n.js +709 -0
- package/static/index.html +95 -0
- package/static/style.css +1258 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Betrieb und Konfiguration
|
|
2
|
+
|
|
3
|
+
[Zurück zur README](../README.md)
|
|
4
|
+
|
|
5
|
+
## Wie die Rotation arbeitet
|
|
6
|
+
|
|
7
|
+
1. Suche und Fetch haben unabhängige Round-Robin-Zähler. Die Reihenfolge kommt aus dem Dashboard.
|
|
8
|
+
2. Die Priorität bleibt über alle Aufrufe erhalten: **gesund → höchstens 10 % übrig → erschöpft**. Rotiert wird jeweils innerhalb einer Klasse.
|
|
9
|
+
3. Fehler führen zur nächsten Engine und erscheinen als `Failover after: …`. HTTP 429 pausiert eine Engine gemäß `Retry-After` (Sekunden oder HTTP-Datum; ohne Header 30 s). 401/403 pausieren 60 s; ab zwei sonstigen Fehlern steigt die Pause von 30 s bis maximal 5 min. Ein Keywechsel hebt die bisherige Pause auf.
|
|
10
|
+
4. Ein Gesamtzeitlimit von standardmäßig **60 s** umfasst Quota-Abfragen und alle Failover-Versuche. MCP-Abbruch bzw. HTTP-Verbindungsabbruch wird an die Anbieter weitergereicht. Nach Abbruch startet kein weiterer Versuch.
|
|
11
|
+
5. `engine` bevorzugt eine Engine, umgeht aber weder Cooldown noch den strikten Gratis-Modus.
|
|
12
|
+
6. **Strikter Gratis-Modus** (optional, Dashboard → Engines): Bereits ausgeschöpfte bekannte Kontingente werden vollständig ausgeschlossen; auch ein einzelner oder bevorzugter Anbieter wird dann nicht mehr aufgerufen. Unbekannte IP-Kontingente bleiben verwendbar. Laufende Aufrufe reservieren ihre Einheiten innerhalb eines Routers. Die Diagnose-Buttons testen nur die gewählte Engine (auch wenn deaktiviert), unterliegen aber denselben Zeit-, Cooldown- und Kontingentregeln.
|
|
13
|
+
|
|
14
|
+
Die Cooldowns und Rotationspositionen gelten pro Serverprozess und werden beim Neustart zurückgesetzt. Im stateless HTTP-Modus beendet ein geschlossener Request die zugehörige Operation; eine separate `notifications/cancelled`-Nachricht besitzt keine langlebige Session-Zuordnung. Bei stdio wird die MCP-Cancellation direkt verarbeitet.
|
|
15
|
+
|
|
16
|
+
### Kontingente und Speicherung
|
|
17
|
+
|
|
18
|
+
Dashboard und `engine_status` zeigen **Zeitraum, Einheit, Quelle und Schätzstatus**. Google zählt pro Tag in `America/Los_Angeles` einschließlich Sommerzeit; Monatszähler verwenden UTC. Keyless Firecrawl/Exa sowie Jina und DuckDuckGo werden als unbekanntes IP-Kontingent angezeigt, nicht als kostenloses Monatsguthaben.
|
|
19
|
+
|
|
20
|
+
Tavily/Firecrawl verwenden, soweit vorhanden, den Remote-Kontostand mit fünf Minuten Cache. Eigene erfolgreiche Aufrufe reduzieren den gecachten Rest sofort. Die lokalen Credit-Schätzungen sind derzeit Tavily Search 1 / Fetch 0,2 sowie Firecrawl Search 2 je angefangene 10 angefragte Treffer / Fetch 1. Die Aufrufzahl wird davon unabhängig gespeichert. Andere Engines zählen lokal Requests; ein aus Geldguthaben abgeleitetes Exa-Limit bleibt eine Schätzung.
|
|
21
|
+
|
|
22
|
+
Der Gratis-Modus ist **keine Ausgabengarantie**: andere Anwendungen können dasselbe Konto belasten, Anbieter können Kosten ändern oder bereits gestartete/abgebrochene Requests abrechnen. Externe Nutzung und parallele Serverprozesse können einen Remote-Cache überholen. Für eine verbindliche Kostenobergrenze zusätzlich das Ausgabenlimit beim Anbieter setzen.
|
|
23
|
+
|
|
24
|
+
`usage.json` und `history.json` bleiben im bisherigen Verzeichnis. Prozessübergreifende Sperren serialisieren vollständige Schreibtransaktionen; atomarer Rename mit individuellen temporären Dateien verhindert halbe Snapshots. Leser sehen Änderungen anderer Prozesse. Monatsdaten bleiben kompatibel, Tagesdaten werden für 62 Tage gehalten. Nachweislich tote Lock-Owner werden automatisch bereinigt; langsame lebende Prozesse werden nicht verdrängt. Bei einer blockierten Sperre schlägt das Schreiben nach 10 s mit einer Diagnose fehl. Ein seltener PID-Reuse-Fall nach einem Crash kann die automatische Bereinigung verzögern. Bereits laufende ältere Versionen vor dem Update beenden, da diese die neuen Sperren nicht verwenden.
|
|
25
|
+
|
|
26
|
+
## Remote-Betrieb (Streamable HTTP)
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npx -y --allow-git=all github:localfoundry/search-rotation-mcp#v0.4.9 --http --host 0.0.0.0 --port 6277 --public-origin https://search.example.com --token <geheim>
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Client-Config (Claude):
|
|
33
|
+
|
|
34
|
+
```json
|
|
35
|
+
{
|
|
36
|
+
"mcpServers": {
|
|
37
|
+
"search-rotation": {
|
|
38
|
+
"url": "https://search.example.com/mcp",
|
|
39
|
+
"headers": { "Authorization": "Bearer <geheim>" }
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Für dieses Beispiel leitet ein HTTPS-Reverse-Proxy `search.example.com` an Port 6277 weiter. Ein Bind außerhalb von Loopback benötigt einen Token. `--public-origin` legt die erlaubte externe Origin und den Host für Browser und MCP fest; fremde Hosts/Origins werden abgewiesen. Ohne Proxy kann eine passende `http://HOST:6277`-Origin verwendet werden.
|
|
46
|
+
|
|
47
|
+
`/mcp` bleibt Bearer-authentifiziert. Im Browser führt die Dashboard-URL zu **`/login`**: Token einmal im Passwortformular eingeben, anschließend gilt ein acht Stunden gültiges `HttpOnly`-/`SameSite=Strict`-Session-Cookie (bei HTTPS zusätzlich `Secure`). Geheimnisfreie Skripte und Styles sind öffentlich, die Dashboard-API ist geschützt. API-Schreibzugriffe benötigen JSON und eine erlaubte Origin, sofern der Client eine sendet.
|
|
48
|
+
|
|
49
|
+
Langlebige Tokens erscheinen weder in Logs noch in Tool-Ergebnissen oder URLs. `open_dashboard` öffnet intern einen 60 s gültigen Einmallink; der zurückgegebene Text enthält nur die Basis-URL. Die frühere `?token=…`-Anmeldung entfällt. `--no-dashboard` schaltet Dashboard, Login und Admin-API vollständig ab.
|
|
50
|
+
|
|
51
|
+
Ohne Keys verwenden Firecrawl/Exa die Server-Egress-IP; verfügbare IP-Kontingente hängen deshalb vom Hosting ab.
|
|
52
|
+
|
|
53
|
+
## Konfiguration
|
|
54
|
+
|
|
55
|
+
Datei: `~/.config/search-rotation/config.json` (0600, wird vom Dashboard gepflegt). Override: `SEARCH_ROTATION_HOME`. Reihenfolge = Array-Reihenfolge (`engines` = Suche, `fetchOrder` = Fetch). Token zusätzlich via `--token` oder `SEARCH_ROTATION_TOKEN`.
|
|
56
|
+
|
|
57
|
+
Zusätzliche `settings`-Felder (alte Configs erhalten Defaults):
|
|
58
|
+
|
|
59
|
+
| Feld | Default | Verhalten |
|
|
60
|
+
|---|---|---|
|
|
61
|
+
| `strictFreeMode` | `false` | Bekannte ausgeschöpfte Kontingente vollständig überspringen |
|
|
62
|
+
| `requestTimeoutMs` | `60000` | Gesamtbudget je Suche/Fetch, konfigurierbar von 1000 bis 300000 ms |
|
|
63
|
+
| `monthlyLimits` | `{}` | Lokales Monatslimit pro Engine, in deren angezeigter Einheit |
|
|
64
|
+
| `dailyLimits` | `{}` | Lokales Tageslimit pro Engine mit Tagesfenster, z. B. `{"google-cse": 100}` |
|
|
65
|
+
|
|
66
|
+
Ein Limit `0` bedeutet weiterhin „kein festes lokales Limit“; zum Abschalten den Engine-Toggle verwenden. Ein gültiger Remote-Kontostand hat Vorrang vor lokalen Limits. Änderungen an Token oder Port benötigen einen **Neustart**; die Config-API kennzeichnet sie mit `requiresRestart: true`. Gratis-Modus und Zeitlimit wirken sofort.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Provider access and quota accounting
|
|
2
|
+
|
|
3
|
+
Verified against provider documentation on 2026-09-05.
|
|
4
|
+
|
|
5
|
+
| Provider | Without an API key? | Default without credentials | Evidence / limitation |
|
|
6
|
+
| --- | --- | --- | --- |
|
|
7
|
+
| Exa | Yes, through its hosted MCP server | Enabled | [Official MCP guide](https://docs.exa.ai/reference/exa-mcp): free casual use; search and fetch. Direct REST API requires a key. No known account balance or fixed request allowance for anonymous access. |
|
|
8
|
+
| Firecrawl | Yes, search and scrape | Enabled | [Keyless rate limits](https://docs.firecrawl.dev/rate-limits#keyless-no-api-key) explicitly cover REST and hosted MCP. Shared IP/day request and credit limits; general API introduction still says authentication is required. |
|
|
9
|
+
| Jina Reader | Yes, page extraction | Enabled | [Reader documentation](https://jina.ai/reader/): anonymous rate limits; fetch only in this server. |
|
|
10
|
+
| DuckDuckGo HTML | Yes | Disabled (opt-in) | [Non-JavaScript search](https://duckduckgo.com/duckduckgo-help-pages/features/non-javascript): public HTML interface, not an officially supported search API. Can block automated traffic. |
|
|
11
|
+
| Tavily | Yes for search, using a keyless-access header | Enabled (search only) | [OpenCode 2 implementation](https://github.com/anomalyco/opencode/blob/b09a74591cbd4d2ea1488e56177898a13f21278d/packages/core/src/plugin/websearch/tavily.ts); independently verified without credentials. Standard quickstart only describes authenticated access. |
|
|
12
|
+
| Parallel | Yes for search via hosted MCP | Enabled (search only) | [OpenCode 2 implementation](https://github.com/anomalyco/opencode/blob/b09a74591cbd4d2ea1488e56177898a13f21278d/packages/core/src/plugin/websearch/parallel.ts); independently verified without credentials. Authenticated requests use the direct REST API. |
|
|
13
|
+
| Google CSE | No; API key and search-engine ID required | Disabled | [API overview](https://developers.google.com/custom-search/v1/overview): existing customers only; scheduled discontinuation January 1, 2027. |
|
|
14
|
+
|
|
15
|
+
“Without a key” never means unlimited. Rate limits and balances may be shared with other users behind the same public IP.
|
|
16
|
+
|
|
17
|
+
The dashboard distinguishes:
|
|
18
|
+
|
|
19
|
+
- **Provider account balance:** fetched with a configured key where supported. Firecrawl's billing period is not assumed to be a calendar month. Cached snapshots may include estimated consumption since the last refresh.
|
|
20
|
+
- **Local successful calls:** this installation's successful search/fetch calls in the current UTC calendar month. Failed calls are counted separately. This is not the provider's total consumption; other clients, shared IP traffic and potentially billed failed requests are not observable.
|
|
21
|
+
- **Unknown allowance:** no progress percentage or invented cap. Exa's former approximation of 1,400 requests has been removed, including for authenticated access. Explicit configured limits are local budgets, not verified provider balances.
|
|
22
|
+
|
|
23
|
+
Existing engines that require credentials are disabled when their key is absent. Configured keys and explicit disabled settings are preserved.
|
|
24
|
+
|
|
25
|
+
## OpenCode 2 implementation check
|
|
26
|
+
|
|
27
|
+
The installed `opencode2 v0.0.0-beta-18684` binary contains the same keyless branches as the linked beta source. These are built-in web-search plugins, not an installation of search-rotation.
|
|
28
|
+
|
|
29
|
+
- Tavily: POST `https://api.tavily.com/search`, `X-Tavily-Access-Mode: keyless`, basic search, 3 chunks per source. OpenCode identifies itself through `X-Client-Name: opencode2`; our independent test used `search-rotation` instead, without Authorization or an API key, and returned HTTP 200 with 3 results.
|
|
30
|
+
- Parallel: MCP `https://search.parallel.ai/mcp`, tool `web_search`, arguments `objective` and `search_queries`. No Authorization header without configured credentials. Independent SDK test using client name search-rotation returned 10 results. Tool discovery also exposed `web_fetch`, which was not tested.
|
|
31
|
+
|
|
32
|
+
This proves anonymous search access at verification time, not unlimited usage or support for every extraction endpoint. No account balance or cap is inferred. search-rotation now implements both anonymous search paths. Without credentials, these engines are omitted from fetch rotation and expose search only in the dashboard. With credentials, search and fetch use their direct APIs.
|
|
33
|
+
|
|
34
|
+
## Result count
|
|
35
|
+
|
|
36
|
+
In **Engines → Rotation settings**, choose **Custom count** (1–20) or **Provider default**. Existing and fresh configurations retain 8 until changed. An explicit `numResults` tool argument overrides this setting. Provider default omits the count from upstream requests; result counts may differ after rotation or failover. DuckDuckGo returns all results parsed from its HTML page; Parallel's hosted MCP returns its own result set (explicit counts are applied locally). Google CSE still caps explicit requests at 10.
|
|
37
|
+
|
|
38
|
+
Firecrawl documents a default of 10 results, so our cost estimate for an omitted count is 2 credits, not an assumed dashboard count. Explicit counts above 10 are estimated at 4 credits. Source: https://docs.firecrawl.dev/api-reference/endpoint/search . Anonymous provider balances remain unknown; local successful-call counters do not measure their true credit consumption.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
## v0.4.9 — Updated Node type definitions
|
|
2
|
+
|
|
3
|
+
Routine maintenance release: the Node type definitions move to 26.6.3. No behaviour change and no configuration migration. The GitHub release page now shows only the notes for the current version instead of the whole changelog.
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
brew update && brew upgrade localfoundry/tap/search-rotation
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
Or run the pinned GitHub version:
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
npx -y --allow-git=all github:localfoundry/search-rotation-mcp#v0.4.9
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
## v0.4.8 — Updated dependencies
|
|
17
|
+
|
|
18
|
+
Routine maintenance release: the MCP SDK moves to 1.30.1, Hono to 4.13.9, Zod to 4.6.5, tsx to 4.23.15 and the Node type definitions to 26.6.2, together with the matching transitive updates (jose, proxy-addr, ip-address, fast-uri, undici-types). No behaviour change and no configuration migration.
|
|
19
|
+
|
|
20
|
+
```sh
|
|
21
|
+
brew update && brew upgrade localfoundry/tap/search-rotation
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Or run the pinned GitHub version:
|
|
25
|
+
|
|
26
|
+
```sh
|
|
27
|
+
npx -y --allow-git=all github:localfoundry/search-rotation-mcp#v0.4.8
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
## v0.4.7 — Clearer dashboard usage, budgets, and activity
|
|
32
|
+
|
|
33
|
+
Engine call counts are now visible with or without an API key. Search, fetch, and error counts are displayed separately from provider credits, so services such as Firecrawl remain easy to inspect even when a quota API is available.
|
|
34
|
+
|
|
35
|
+
- Show monthly local engine attempts and their search/fetch/error breakdown consistently across the overview and engine cards.
|
|
36
|
+
- Rename Engine Health to Engine Usage & Budget, with explicit remaining percentages, budget units, and quota-source explanations.
|
|
37
|
+
- Add accessible activity-bar details for each two-hour window, including tool calls and per-engine attempts with fallbacks. Correct the 48-hour boundary and disclose the retained-history limit.
|
|
38
|
+
- Include failed fallback attempts in engine history filters; distinguish empty history from filter misses and add full timestamps to history tooltips.
|
|
39
|
+
- Refresh local call counts even when the quota percentage does not change. Empty history no longer implies a 0% error rate, and exhausted budgets have truly empty bars.
|
|
40
|
+
- Expand MCP setup by default, improve tablet/mobile navigation, and refresh the English light/dark README screenshots using demo data.
|
|
41
|
+
|
|
42
|
+
No configuration migration is required. Reconnect MCP clients after updating.
|
|
43
|
+
|
|
44
|
+
```sh
|
|
45
|
+
brew update && brew upgrade localfoundry/tap/search-rotation
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Or run the pinned GitHub version:
|
|
49
|
+
|
|
50
|
+
```sh
|
|
51
|
+
npx -y --allow-git=all github:localfoundry/search-rotation-mcp#v0.4.7
|
|
52
|
+
```
|
package/package.json
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "search-rotation",
|
|
3
|
+
"version": "0.4.9",
|
|
4
|
+
"description": "Round-robin web search over the free tiers of multiple search APIs (Tavily, Firecrawl, Parallel, Exa, Google PSE, Jina, DuckDuckGo) as an MCP server — with a local dashboard for API keys, engine order/toggles and live quota status.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": {
|
|
8
|
+
"name": "Robin Bially",
|
|
9
|
+
"url": "https://github.com/localfoundry"
|
|
10
|
+
},
|
|
11
|
+
"bin": {
|
|
12
|
+
"search-rotation": "dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"main": "dist/index.js",
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"static",
|
|
18
|
+
"docs",
|
|
19
|
+
"README.md",
|
|
20
|
+
"LICENSE"
|
|
21
|
+
],
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=20.3.0"
|
|
24
|
+
},
|
|
25
|
+
"keywords": [
|
|
26
|
+
"mcp",
|
|
27
|
+
"model-context-protocol",
|
|
28
|
+
"web-search",
|
|
29
|
+
"round-robin",
|
|
30
|
+
"free-tier",
|
|
31
|
+
"tavily",
|
|
32
|
+
"firecrawl",
|
|
33
|
+
"exa",
|
|
34
|
+
"parallel",
|
|
35
|
+
"search"
|
|
36
|
+
],
|
|
37
|
+
"scripts": {
|
|
38
|
+
"build": "tsc",
|
|
39
|
+
"prepare": "npm run build",
|
|
40
|
+
"dev": "tsx src/index.ts --http --port 6277",
|
|
41
|
+
"start": "node dist/index.js --http --port 6277",
|
|
42
|
+
"test": "node --import tsx --test test/*.test.ts",
|
|
43
|
+
"smoke:package": "node scripts/smoke-package.mjs",
|
|
44
|
+
"sync:version-refs": "node scripts/sync-version-refs.mjs"
|
|
45
|
+
},
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"@hono/node-server": "^2.1.1",
|
|
48
|
+
"@modelcontextprotocol/sdk": "^1.17.0",
|
|
49
|
+
"hono": "^4.9.0",
|
|
50
|
+
"zod": "^4.5.4"
|
|
51
|
+
},
|
|
52
|
+
"devDependencies": {
|
|
53
|
+
"@types/node": "^26.4.1",
|
|
54
|
+
"tsx": "^4.19.0",
|
|
55
|
+
"typescript": "^7.0.2"
|
|
56
|
+
},
|
|
57
|
+
"repository": {
|
|
58
|
+
"type": "git",
|
|
59
|
+
"url": "git+https://github.com/localfoundry/search-rotation-mcp.git"
|
|
60
|
+
},
|
|
61
|
+
"homepage": "https://github.com/localfoundry/search-rotation-mcp#readme",
|
|
62
|
+
"bugs": {
|
|
63
|
+
"url": "https://github.com/localfoundry/search-rotation-mcp/issues"
|
|
64
|
+
}
|
|
65
|
+
}
|