mcp-xray-pilot 0.11.0 → 0.15.0
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/README.md +250 -7
- package/data/geocatalogue.json +162 -1
- package/dist/data/geocatalogue.js +37 -7
- package/dist/data/geocatalogue.js.map +1 -1
- package/dist/handlers.js +27 -0
- package/dist/handlers.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/lint.js +177 -1
- package/dist/lint.js.map +1 -1
- package/dist/tools.js +95 -1
- package/dist/tools.js.map +1 -1
- package/dist/tools_impl/geocatalogue_fetch.js +246 -4
- package/dist/tools_impl/geocatalogue_fetch.js.map +1 -1
- package/dist/tools_impl/test_reality_live.js +932 -0
- package/dist/tools_impl/test_reality_live.js.map +1 -0
- package/dist/tools_impl/whitelist_sni_candidates.js +283 -0
- package/dist/tools_impl/whitelist_sni_candidates.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -30,11 +30,13 @@ a curated SNI suggester per exit-country and a multi-config merge helper.
|
|
|
30
30
|
tun), per-transport `*Settings` schemas (raw / xhttp / grpc / ws / mkcp /
|
|
31
31
|
httpupgrade / hysteria), TLS / REALITY security blocks, routing tag
|
|
32
32
|
cross-references.
|
|
33
|
-
- **Lints** ~
|
|
33
|
+
- **Lints** ~22 best-practice rules: VLESS `decryption: "none"`, REALITY
|
|
34
34
|
pubkey/shortId/target syntax, XTLS vision flow compatibility, TLS
|
|
35
35
|
fingerprint enum, ALPN collisions, geosite/geoip typo catcher, protocol
|
|
36
36
|
× transport × security incompatibilities, `xhttp.path` leading slash,
|
|
37
|
-
`geoip:private` block rule, sniffing on 80/443
|
|
37
|
+
`geoip:private` block rule, sniffing on 80/443, **DNS-over-proxy leaks
|
|
38
|
+
on `.ru` direct routing** (v0.12), **`geosite:` categories absent from
|
|
39
|
+
xray-core release `geosite.dat`** (v0.12) etc.
|
|
38
40
|
- **Geo catalogue**: search ~1500 known geoip/geosite tags by substring (full
|
|
39
41
|
v2fly/domain-list-community catalogue, hydrated from `data/geocatalogue.json`).
|
|
40
42
|
- **REALITY toolbelt**: `xray_generate_reality_keypair` (drop-in replacement
|
|
@@ -56,20 +58,22 @@ a curated SNI suggester per exit-country and a multi-config merge helper.
|
|
|
56
58
|
| `xray_fetch_topic` | Fetch one topic as markdown. Network → fall back to bundled cache → update cache. |
|
|
57
59
|
| `xray_search` | Full-text search over all cached docs. Returns ranked hits + snippets. |
|
|
58
60
|
| `xray_validate_config` | Structural+schema validation of an xray JSON config (Zod under the hood). |
|
|
59
|
-
| `xray_lint` | ~
|
|
61
|
+
| `xray_lint` | ~22 best-practice lint rules. Returns issues with severity, rule id, JSON-pointer. |
|
|
60
62
|
| `xray_geo_search` | Substring search over the embedded geosite/geoip catalogue (~1500 tags). |
|
|
61
63
|
| `xray_diff_protocols` | Side-by-side feature table for two protocols. |
|
|
62
64
|
| `xray_suggest_alternative` | Recommend protocol+transport+security for a goal (anti-DPI / battery / latency / …). |
|
|
63
65
|
| `xray_generate_short_ids` | Cryptographically random REALITY shortIds (default `[4,8,16]` bytes, legacy empty prefix). |
|
|
64
66
|
| `xray_generate_reality_keypair` | Fresh REALITY X25519 keypair, base64url 43 chars — drop-in for `xray x25519`. |
|
|
65
67
|
| `xray_validate_sni_target` | Live TLS 1.3 + ALPN h2 + HTTP probe of a candidate REALITY target host. |
|
|
68
|
+
| `xray_test_reality_live` | Spin up real local xray server+client, run a full REALITY handshake against the target, probe HTTPS through the cascade. Strictly stronger than `xray_validate_sni_target`. |
|
|
69
|
+
| `xray_whitelist_sni_candidates` | Pull a public RU-traffic whitelist (default: hxehex/russia-mobile-internet-whitelist) and TLS-validate the top N hosts as REALITY SNI front candidates. Returns ranked, sorted by ok desc, latency asc. |
|
|
66
70
|
| `xray_suggest_sni_for_country` | Curated REALITY SNI/target hosts per exit-country (DE/PL/NL/FR/LV/SE/FI/US/UK/JP/SG/AU/CA). |
|
|
67
71
|
| `xray_merge_configs` | Merge N xray configs with tag-collision resolution and conflict warnings. |
|
|
68
72
|
| `xray_github_search` | Search issues/PRs/discussions across XTLS GitHub repos (Xray-core/REALITY/docs). |
|
|
69
73
|
| `xray_github_fetch_issue` | Fetch one issue/PR/discussion with full body + top comments. |
|
|
70
74
|
| `xray_refresh_cache` | Bulk re-fetch cached docs (`scope: all/stale/category`). Optional `discover` for new upstream slugs. Optional `refresh_geocatalogue: true` to also re-pull the v2fly category list. |
|
|
71
75
|
|
|
72
|
-
Total: **
|
|
76
|
+
Total: **18 tools**.
|
|
73
77
|
|
|
74
78
|
### Quick toolbelt
|
|
75
79
|
|
|
@@ -96,6 +100,74 @@ Live-check a candidate REALITY SNI:
|
|
|
96
100
|
}
|
|
97
101
|
```
|
|
98
102
|
|
|
103
|
+
Live REALITY handshake (catches what `xray_validate_sni_target` cannot):
|
|
104
|
+
|
|
105
|
+
```jsonc
|
|
106
|
+
// xray_test_reality_live { "target_host": "2gis.ru" }
|
|
107
|
+
{
|
|
108
|
+
"ok": true,
|
|
109
|
+
"target": "2gis.ru:443",
|
|
110
|
+
"reality_handshake_complete": true,
|
|
111
|
+
"client_received_real_cert": false,
|
|
112
|
+
"http_probe_status": 200,
|
|
113
|
+
"latency_ms": 824,
|
|
114
|
+
"issues": [],
|
|
115
|
+
"used_keypair": { "privateKey": "...", "publicKey": "...", "shortId": "a1b2c3d4" },
|
|
116
|
+
"cached": false,
|
|
117
|
+
"cached_at": "2026-05-06T12:30:00.000Z"
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
> Verdicts are persisted to `data/reality-verdicts.json` (LRU cap 50, TTL 24h,
|
|
122
|
+
> key `host:port`). Subsequent calls with the same target return instantly with
|
|
123
|
+
> `cached: true`. Pass `force_refresh: true` to bypass the cache and rerun xray.
|
|
124
|
+
|
|
125
|
+
Compare a list of candidates in one shot — runs sequentially, each entry hits
|
|
126
|
+
the cache, results are sorted by `ok desc, latency_ms asc`:
|
|
127
|
+
|
|
128
|
+
```jsonc
|
|
129
|
+
// xray_test_reality_live {
|
|
130
|
+
// "multi_targets": ["2gis.ru", "yandex.ru", "vk.com", "mail.ru"]
|
|
131
|
+
// }
|
|
132
|
+
{
|
|
133
|
+
"results": [
|
|
134
|
+
{ "target": "2gis.ru:443", "ok": true, "latency_ms": 824, "cached": true, "cached_at": "..." },
|
|
135
|
+
{ "target": "mail.ru:443", "ok": true, "latency_ms": 1102, "cached": false, "cached_at": "..." },
|
|
136
|
+
{ "target": "yandex.ru:443", "ok": false, "latency_ms": 0, "cached": false, "cached_at": "...", "issues": ["client received a real certificate ..."] },
|
|
137
|
+
{ "target": "vk.com:443", "ok": false, "latency_ms": 0, "cached": false, "cached_at": "...", "issues": ["target unreachable"] }
|
|
138
|
+
],
|
|
139
|
+
"summary": { "ok_count": 2, "total": 4 }
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Pull a public RU-traffic whitelist and rank live SNI candidates for an
|
|
144
|
+
inbound RU-relay node:
|
|
145
|
+
|
|
146
|
+
```jsonc
|
|
147
|
+
// xray_whitelist_sni_candidates { "max_candidates": 10 }
|
|
148
|
+
{
|
|
149
|
+
"source_url": "https://raw.githubusercontent.com/hxehex/russia-mobile-internet-whitelist/main/whitelist.txt",
|
|
150
|
+
"fetched_at": "2026-05-06T12:34:00.000Z",
|
|
151
|
+
"total_domains": 412,
|
|
152
|
+
"tested": 10,
|
|
153
|
+
"candidates": [
|
|
154
|
+
{ "host": "ya.ru", "ok": true, "tls_version": "TLSv1.3", "alpn": "h2", "http_status": 200, "latency_ms": 41, "cert_subject": "ya.ru", "issues": [] },
|
|
155
|
+
{ "host": "vk.com", "ok": true, "tls_version": "TLSv1.3", "alpn": "h2", "http_status": 200, "latency_ms": 78, "cert_subject": "*.vk.com", "issues": [] },
|
|
156
|
+
{ "host": "ozon.ru", "ok": false, "tls_version": "TLSv1.3", "alpn": "h2", "http_status": 200, "latency_ms": 134, "cert_subject": "*.ozon.ru", "issues": [] }
|
|
157
|
+
],
|
|
158
|
+
"summary": { "ok_count": 8, "failed_count": 2 },
|
|
159
|
+
"cache": { "used": false, "age_seconds": null },
|
|
160
|
+
"notes": ["latency_ms is measured from the MCP host (your laptop), not from the relay node — re-test from the node for geo-accurate values"]
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
> The whitelist body is cached on disk in `data/whitelist-cache.json`
|
|
165
|
+
> (default TTL 24h, override via `cache_ttl_hours`). Verdicts are NOT cached
|
|
166
|
+
> — every call re-probes its slice live so latency numbers stay fresh.
|
|
167
|
+
> NB: the probe runs from your laptop, not from the РФ relay; for
|
|
168
|
+
> geo-accurate latency, use `xray_test_reality_live` from the actual
|
|
169
|
+
> node (or ssh + curl on it).
|
|
170
|
+
|
|
99
171
|
It also exposes a single MCP **resource**: `xray://docs/index` — the raw
|
|
100
172
|
`_index.json` of cached topics.
|
|
101
173
|
|
|
@@ -293,6 +365,58 @@ $env:GITHUB_TOKEN = "ghp_xxx" # PowerShell
|
|
|
293
365
|
When `X-RateLimit-Remaining` drops below 10, the tool surfaces an inline
|
|
294
366
|
warning in the response.
|
|
295
367
|
|
|
368
|
+
## Security model
|
|
369
|
+
|
|
370
|
+
This package runs entirely in the MCP host's process and the only
|
|
371
|
+
"interesting" thing it does on disk/network is `xray_test_reality_live`,
|
|
372
|
+
which downloads the official **xray-core** binary from
|
|
373
|
+
[XTLS/Xray-core releases](https://github.com/XTLS/Xray-core/releases/latest)
|
|
374
|
+
into `~/.cache/mcp-xray-pilot/xray-bin/` and spawns it locally on
|
|
375
|
+
ephemeral ports.
|
|
376
|
+
|
|
377
|
+
**Approvals.** There is no in-package permission prompt by design — all
|
|
378
|
+
tool invocations are gated by the MCP host (Claude Code / Claude Desktop
|
|
379
|
+
/ Cursor). Each host has its own permission UX (per-call confirm,
|
|
380
|
+
allowlist, etc.). Pin a specific version in your MCP config
|
|
381
|
+
(`mcp-xray-pilot@0.15.0`, not `mcp-xray-pilot`) so a malicious npm
|
|
382
|
+
release cannot silently roll in.
|
|
383
|
+
|
|
384
|
+
**Integrity of the xray binary.** Since v0.15:
|
|
385
|
+
|
|
386
|
+
1. The matching `<asset>.zip.dgst` from the same GitHub release is
|
|
387
|
+
downloaded alongside the zip, and the zip is verified against its
|
|
388
|
+
`SHA2-256=` line **before** extraction. Mismatched payloads are
|
|
389
|
+
renamed to `xray.rejected-<timestamp>.zip` for inspection and the
|
|
390
|
+
tool aborts.
|
|
391
|
+
2. If you want a stronger guarantee than "trust whatever XTLS ships
|
|
392
|
+
right now", set `XRAY_PILOT_PINNED_HASH` to a known SHA-256 — the
|
|
393
|
+
`.dgst` is then ignored and the pinned value is enforced. This
|
|
394
|
+
defends against a hypothetical compromised XTLS release that ships a
|
|
395
|
+
matching `.dgst`.
|
|
396
|
+
|
|
397
|
+
```bash
|
|
398
|
+
# Linux / macOS — read the hash once, then pin it.
|
|
399
|
+
curl -sL https://github.com/XTLS/Xray-core/releases/latest/download/Xray-linux-64.zip.dgst \
|
|
400
|
+
| awk '/^SHA2-256=/ {print $2}'
|
|
401
|
+
export XRAY_PILOT_PINNED_HASH=23cd9af9...
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
```powershell
|
|
405
|
+
$env:XRAY_PILOT_PINNED_HASH = "23cd9af9..."
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
**What this does NOT do.** XTLS does not GPG-sign `.dgst` files, so an
|
|
409
|
+
attacker with write access to the releases page can ship a coherent
|
|
410
|
+
zip+dgst pair. The pinned-hash path is your defense against that. The
|
|
411
|
+
package does not sandbox the spawned xray binary — it runs with the
|
|
412
|
+
permissions of the MCP host process. If you need stronger isolation,
|
|
413
|
+
run the MCP host inside a container or a dedicated user account.
|
|
414
|
+
|
|
415
|
+
**`GITHUB_TOKEN`.** Optional, used only by `xray_github_search` /
|
|
416
|
+
`xray_github_fetch_issue`. A **fine-grained PAT with read-only public
|
|
417
|
+
repo scope** is recommended over classic PATs. The token is read from
|
|
418
|
+
the process env at call time and never persisted by the package.
|
|
419
|
+
|
|
296
420
|
## Roadmap
|
|
297
421
|
|
|
298
422
|
See [ROADMAP.md](./ROADMAP.md). All v0.1–v0.11 milestones are checked off.
|
|
@@ -327,11 +451,13 @@ MCP-сервер, дающий LLM офлайн-доступ к официаль
|
|
|
327
451
|
tun), per-transport `*Settings` (raw / xhttp / grpc / ws / mkcp /
|
|
328
452
|
httpupgrade / hysteria), security блоки TLS/REALITY, routing tag
|
|
329
453
|
cross-references.
|
|
330
|
-
- **Lint** ~
|
|
454
|
+
- **Lint** ~22 правил: VLESS `decryption: "none"`, REALITY pubkey/shortId/
|
|
331
455
|
target syntax, XTLS vision flow compatibility, TLS fingerprint enum,
|
|
332
456
|
ALPN collisions, geo typo catcher, protocol × transport × security
|
|
333
457
|
несовместимости, `xhttp.path` слеш, `geoip:private` block, sniffing на
|
|
334
|
-
80/443
|
|
458
|
+
80/443, **утечка DNS через прокси ломает `.ru` direct routing** (v0.12),
|
|
459
|
+
**`geosite:` категории, которых нет в xray-core release `geosite.dat`**
|
|
460
|
+
(v0.12) и т.д.
|
|
335
461
|
- **Geo catalogue**: поиск по ~1500 известным geoip/geosite тегам (полный
|
|
336
462
|
v2fly/domain-list-community каталог, гидратируется из `data/geocatalogue.json`).
|
|
337
463
|
- **REALITY toolbelt**: `xray_generate_reality_keypair` (drop-in замена
|
|
@@ -360,13 +486,15 @@ MCP-сервер, дающий LLM офлайн-доступ к официаль
|
|
|
360
486
|
| `xray_generate_short_ids` | Криптослучайные REALITY shortIds (default `[4,8,16]` байт, с empty-prefix для легаси). |
|
|
361
487
|
| `xray_generate_reality_keypair` | Свежая X25519 пара REALITY, base64url 43 chars — drop-in для `xray x25519`. |
|
|
362
488
|
| `xray_validate_sni_target` | Live проба TLS 1.3 + ALPN h2 + HTTP кандидата на REALITY target. |
|
|
489
|
+
| `xray_test_reality_live` | Поднимает локальную пару xray (server+client), реально гоняет REALITY handshake к target, probe HTTPS сквозь каскад. Строго сильнее `xray_validate_sni_target`. |
|
|
490
|
+
| `xray_whitelist_sni_candidates` | Тянет публичный whitelist РФ-трафика (default: hxehex/russia-mobile-internet-whitelist), TLS-валидирует топ-N как REALITY SNI-кандидаты. Сортировка ok desc, latency asc. |
|
|
363
491
|
| `xray_suggest_sni_for_country` | Курируемые REALITY-фронты по стране exit'а (DE/PL/NL/FR/LV/SE/FI/US/UK/JP/SG/AU/CA). |
|
|
364
492
|
| `xray_merge_configs` | Слить N конфигов с разрешением коллизий тегов. |
|
|
365
493
|
| `xray_github_search` | Поиск issues/PR/discussions по XTLS GitHub репозиториям. |
|
|
366
494
|
| `xray_github_fetch_issue` | Получить одну issue/PR/discussion с полным body + топ комментариев. |
|
|
367
495
|
| `xray_refresh_cache` | Bulk перезатяжка кеша доков (`scope: all/stale/category`). Опц. `discover` + `refresh_geocatalogue: true` (заодно перетянет v2fly категории). |
|
|
368
496
|
|
|
369
|
-
Всего: **
|
|
497
|
+
Всего: **18 тулов**.
|
|
370
498
|
|
|
371
499
|
### Quick toolbelt
|
|
372
500
|
|
|
@@ -395,6 +523,71 @@ Live-проверить кандидата на REALITY SNI:
|
|
|
395
523
|
|
|
396
524
|
> ⚠️ Проба идёт с локальной машины, где запущен `mcp-xray-pilot`. Для решения «работает ли SNI из РФ» — гоняй с РФ-IP отдельно.
|
|
397
525
|
|
|
526
|
+
Реальный REALITY handshake (ловит то, что `xray_validate_sni_target` пропускает):
|
|
527
|
+
|
|
528
|
+
```jsonc
|
|
529
|
+
// xray_test_reality_live { "target_host": "2gis.ru" }
|
|
530
|
+
{
|
|
531
|
+
"ok": true,
|
|
532
|
+
"target": "2gis.ru:443",
|
|
533
|
+
"reality_handshake_complete": true,
|
|
534
|
+
"client_received_real_cert": false,
|
|
535
|
+
"http_probe_status": 200,
|
|
536
|
+
"latency_ms": 824,
|
|
537
|
+
"issues": [],
|
|
538
|
+
"used_keypair": { "privateKey": "...", "publicKey": "...", "shortId": "a1b2c3d4" },
|
|
539
|
+
"cached": false,
|
|
540
|
+
"cached_at": "2026-05-06T12:30:00.000Z"
|
|
541
|
+
}
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
> При первом вызове скачивает xray-binary в `~/.cache/mcp-xray-pilot/xray-bin/` (~30MB), дальше переиспользует. Если REALITY несовместим с target (как `outlook.live.com` или `www.ozon.ru` — реальные кейсы Flare VPN), `client_received_real_cert: true` и `ok: false`.
|
|
545
|
+
|
|
546
|
+
> Вердикты пишутся на диск в `data/reality-verdicts.json` (LRU 50, TTL 24h, ключ `host:port`). Повторный вызов на тот же таргет возвращается мгновенно с `cached: true`. Чтобы прогнать заново — `force_refresh: true`.
|
|
547
|
+
|
|
548
|
+
Сравнить пачку кандидатов одним вызовом — запускаются последовательно, каждый через кэш, сорт `ok desc, latency_ms asc`:
|
|
549
|
+
|
|
550
|
+
```jsonc
|
|
551
|
+
// xray_test_reality_live {
|
|
552
|
+
// "multi_targets": ["2gis.ru", "yandex.ru", "vk.com", "mail.ru"]
|
|
553
|
+
// }
|
|
554
|
+
{
|
|
555
|
+
"results": [
|
|
556
|
+
{ "target": "2gis.ru:443", "ok": true, "latency_ms": 824, "cached": true },
|
|
557
|
+
{ "target": "mail.ru:443", "ok": true, "latency_ms": 1102, "cached": false },
|
|
558
|
+
{ "target": "yandex.ru:443", "ok": false, "issues": ["client received a real certificate ..."] },
|
|
559
|
+
{ "target": "vk.com:443", "ok": false, "issues": ["target unreachable"] }
|
|
560
|
+
],
|
|
561
|
+
"summary": { "ok_count": 2, "total": 4 }
|
|
562
|
+
}
|
|
563
|
+
```
|
|
564
|
+
|
|
565
|
+
Затянуть публичный whitelist РФ-трафика и проранжировать кандидатов на REALITY SNI для inbound РФ-relay-ноды:
|
|
566
|
+
|
|
567
|
+
```jsonc
|
|
568
|
+
// xray_whitelist_sni_candidates { "max_candidates": 10 }
|
|
569
|
+
{
|
|
570
|
+
"source_url": "https://raw.githubusercontent.com/hxehex/russia-mobile-internet-whitelist/main/whitelist.txt",
|
|
571
|
+
"fetched_at": "2026-05-06T12:34:00.000Z",
|
|
572
|
+
"total_domains": 412,
|
|
573
|
+
"tested": 10,
|
|
574
|
+
"candidates": [
|
|
575
|
+
{ "host": "ya.ru", "ok": true, "tls_version": "TLSv1.3", "alpn": "h2", "http_status": 200, "latency_ms": 41, "cert_subject": "ya.ru", "issues": [] },
|
|
576
|
+
{ "host": "vk.com", "ok": true, "tls_version": "TLSv1.3", "alpn": "h2", "http_status": 200, "latency_ms": 78, "cert_subject": "*.vk.com", "issues": [] }
|
|
577
|
+
],
|
|
578
|
+
"summary": { "ok_count": 8, "failed_count": 2 },
|
|
579
|
+
"cache": { "used": false, "age_seconds": null },
|
|
580
|
+
"notes": ["latency_ms is measured from the MCP host (your laptop), not from the relay node — re-test from the node for geo-accurate values"]
|
|
581
|
+
}
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
> Тело whitelist кешируется на диск в `data/whitelist-cache.json` (TTL по
|
|
585
|
+
> умолчанию 24h, переопределение через `cache_ttl_hours`). Verdicts НЕ
|
|
586
|
+
> кешируются — каждый вызов делает свежие пробы на своём срезе. NB:
|
|
587
|
+
> latency меряется с тачки где запущен MCP, а НЕ с РФ-relay-ноды; для
|
|
588
|
+
> гео-релевантной задержки используй `xray_test_reality_live` прямо с
|
|
589
|
+
> ноды (или ssh + curl на ней).
|
|
590
|
+
|
|
398
591
|
Также один MCP **ресурс**: `xray://docs/index`.
|
|
399
592
|
|
|
400
593
|
## Примеры
|
|
@@ -573,6 +766,56 @@ $env:GITHUB_TOKEN = "ghp_xxx" # PowerShell
|
|
|
573
766
|
Когда `X-RateLimit-Remaining` падает ниже 10, тул возвращает inline-warning
|
|
574
767
|
в ответе.
|
|
575
768
|
|
|
769
|
+
## Модель безопасности
|
|
770
|
+
|
|
771
|
+
Пакет крутится внутри процесса MCP-хоста, и единственное «опасное»
|
|
772
|
+
действие на диск/сеть — `xray_test_reality_live`, который скачивает
|
|
773
|
+
официальный бинарь **xray-core** из
|
|
774
|
+
[XTLS/Xray-core releases](https://github.com/XTLS/Xray-core/releases/latest)
|
|
775
|
+
в `~/.cache/mcp-xray-pilot/xray-bin/` и запускает его локально на
|
|
776
|
+
ephemeral портах.
|
|
777
|
+
|
|
778
|
+
**Approvals.** Встроенного permission-prompt'а в пакете нет — это by
|
|
779
|
+
design. Все тулколлы гейтятся MCP-хостом (Claude Code / Claude Desktop /
|
|
780
|
+
Cursor) — у каждого хоста свой UX (per-call confirm, allowlist и т.д.).
|
|
781
|
+
Пиньте конкретную версию в MCP-конфиге (`mcp-xray-pilot@0.15.0`, а не
|
|
782
|
+
просто `mcp-xray-pilot`), чтобы вредоносный npm-релиз не подкатился
|
|
783
|
+
тихо.
|
|
784
|
+
|
|
785
|
+
**Целостность бинаря xray.** Начиная с v0.15:
|
|
786
|
+
|
|
787
|
+
1. Рядом со скачиванием zip-а тянется `<asset>.zip.dgst` из того же
|
|
788
|
+
GitHub-релиза, и **до** распаковки zip проверяется против строки
|
|
789
|
+
`SHA2-256=`. Если хэши не совпали — payload переименовывается в
|
|
790
|
+
`xray.rejected-<timestamp>.zip` для разбора, и тул abort'ится.
|
|
791
|
+
2. Если хочется жёстче чем «доверяю тому что XTLS залил прямо сейчас» —
|
|
792
|
+
задайте `XRAY_PILOT_PINNED_HASH` с известным SHA-256. Тогда `.dgst`
|
|
793
|
+
игнорируется, проверяется ваше захардкоженное значение. Это защищает
|
|
794
|
+
от гипотетического compromised XTLS-релиза, где злоумышленник залил
|
|
795
|
+
согласованную пару zip+dgst.
|
|
796
|
+
|
|
797
|
+
```bash
|
|
798
|
+
# Linux / macOS — снять хэш один раз, потом пиннуть.
|
|
799
|
+
curl -sL https://github.com/XTLS/Xray-core/releases/latest/download/Xray-linux-64.zip.dgst \
|
|
800
|
+
| awk '/^SHA2-256=/ {print $2}'
|
|
801
|
+
export XRAY_PILOT_PINNED_HASH=23cd9af9...
|
|
802
|
+
```
|
|
803
|
+
|
|
804
|
+
```powershell
|
|
805
|
+
$env:XRAY_PILOT_PINNED_HASH = "23cd9af9..."
|
|
806
|
+
```
|
|
807
|
+
|
|
808
|
+
**Чего пакет НЕ делает.** XTLS не GPG-подписывает `.dgst`, поэтому
|
|
809
|
+
атакер с правами на releases-страницу может выкатить согласованную пару
|
|
810
|
+
zip+dgst. Защита от этого — pinned-hash. Sandbox для запущенного xray
|
|
811
|
+
пакет не делает — бинарь работает с правами процесса MCP-хоста. Хотите
|
|
812
|
+
жёстче — запускайте MCP-хост в контейнере или под отдельным юзером.
|
|
813
|
+
|
|
814
|
+
**`GITHUB_TOKEN`.** Опционально, используется только
|
|
815
|
+
`xray_github_search` / `xray_github_fetch_issue`. Рекомендуется
|
|
816
|
+
**fine-grained PAT с read-only scope для публичных репо** вместо
|
|
817
|
+
classic PAT. Токен читается из env при вызове и пакетом не сохраняется.
|
|
818
|
+
|
|
576
819
|
## Roadmap
|
|
577
820
|
|
|
578
821
|
См. [ROADMAP.md](./ROADMAP.md) — все вехи v0.1–v0.11 закрыты.
|
package/data/geocatalogue.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"fetched_at": "2026-05-
|
|
2
|
+
"fetched_at": "2026-05-05T01:29:27.654Z",
|
|
3
3
|
"source": "github.com/v2fly/domain-list-community/tree/master/data",
|
|
4
4
|
"count": 1464,
|
|
5
5
|
"names": [
|
|
@@ -1467,5 +1467,166 @@
|
|
|
1467
1467
|
"zto-express",
|
|
1468
1468
|
"zuoyebang",
|
|
1469
1469
|
"zynga"
|
|
1470
|
+
],
|
|
1471
|
+
"release_source": "hand-curated fallback (network fetch failed)",
|
|
1472
|
+
"release_count": 157,
|
|
1473
|
+
"release_names": [
|
|
1474
|
+
"1c",
|
|
1475
|
+
"alfabank",
|
|
1476
|
+
"alibaba",
|
|
1477
|
+
"amazon",
|
|
1478
|
+
"amazon-aws",
|
|
1479
|
+
"amazon-cn",
|
|
1480
|
+
"anthropic",
|
|
1481
|
+
"apple",
|
|
1482
|
+
"apple-cn",
|
|
1483
|
+
"archive",
|
|
1484
|
+
"atlassian",
|
|
1485
|
+
"baidu",
|
|
1486
|
+
"bilibili",
|
|
1487
|
+
"binance",
|
|
1488
|
+
"bitbucket",
|
|
1489
|
+
"blizzard",
|
|
1490
|
+
"bybit",
|
|
1491
|
+
"category-ads",
|
|
1492
|
+
"category-ads-all",
|
|
1493
|
+
"category-ads-ir",
|
|
1494
|
+
"category-ai-!cn",
|
|
1495
|
+
"category-ai-chat-!cn",
|
|
1496
|
+
"category-ai-chat-cn",
|
|
1497
|
+
"category-anticn",
|
|
1498
|
+
"category-banks-ru",
|
|
1499
|
+
"category-bittorrent",
|
|
1500
|
+
"category-cdn",
|
|
1501
|
+
"category-cryptocurrency",
|
|
1502
|
+
"category-cryptocurrency-!cn",
|
|
1503
|
+
"category-cryptocurrency-cn",
|
|
1504
|
+
"category-dev",
|
|
1505
|
+
"category-forums",
|
|
1506
|
+
"category-game-platforms",
|
|
1507
|
+
"category-game-platforms-download",
|
|
1508
|
+
"category-games-cn",
|
|
1509
|
+
"category-gov-ru",
|
|
1510
|
+
"category-ir",
|
|
1511
|
+
"category-kp",
|
|
1512
|
+
"category-media-ru",
|
|
1513
|
+
"category-porn",
|
|
1514
|
+
"category-public-cdn",
|
|
1515
|
+
"category-public-tracker",
|
|
1516
|
+
"category-ru",
|
|
1517
|
+
"category-scholar-!cn",
|
|
1518
|
+
"category-scholar-cn",
|
|
1519
|
+
"category-social",
|
|
1520
|
+
"category-social-!cn",
|
|
1521
|
+
"category-social-cn",
|
|
1522
|
+
"claude",
|
|
1523
|
+
"cloudflare",
|
|
1524
|
+
"cloudfront",
|
|
1525
|
+
"cn",
|
|
1526
|
+
"coinbase",
|
|
1527
|
+
"discord",
|
|
1528
|
+
"docker",
|
|
1529
|
+
"dropbox",
|
|
1530
|
+
"ea",
|
|
1531
|
+
"ea-games",
|
|
1532
|
+
"epicgames",
|
|
1533
|
+
"ethereum",
|
|
1534
|
+
"facebook",
|
|
1535
|
+
"fastly",
|
|
1536
|
+
"figma",
|
|
1537
|
+
"geolocation-!cn",
|
|
1538
|
+
"geolocation-cn",
|
|
1539
|
+
"geolocation-ir",
|
|
1540
|
+
"gfw",
|
|
1541
|
+
"github",
|
|
1542
|
+
"gitlab",
|
|
1543
|
+
"golang",
|
|
1544
|
+
"google",
|
|
1545
|
+
"google-cn",
|
|
1546
|
+
"googleads",
|
|
1547
|
+
"googleapis",
|
|
1548
|
+
"googlefcm",
|
|
1549
|
+
"googleplay",
|
|
1550
|
+
"googlescholar",
|
|
1551
|
+
"gosuslugi",
|
|
1552
|
+
"greatfire",
|
|
1553
|
+
"habr",
|
|
1554
|
+
"huggingface",
|
|
1555
|
+
"icloud",
|
|
1556
|
+
"imgur",
|
|
1557
|
+
"instagram",
|
|
1558
|
+
"jetbrains",
|
|
1559
|
+
"kinopoisk",
|
|
1560
|
+
"kucoin",
|
|
1561
|
+
"linkedin",
|
|
1562
|
+
"mail-ru",
|
|
1563
|
+
"medium",
|
|
1564
|
+
"meta",
|
|
1565
|
+
"metamask",
|
|
1566
|
+
"microsoft",
|
|
1567
|
+
"microsoft-cn",
|
|
1568
|
+
"miscellaneous",
|
|
1569
|
+
"netflix",
|
|
1570
|
+
"nicovideo",
|
|
1571
|
+
"nintendo",
|
|
1572
|
+
"nodejs",
|
|
1573
|
+
"notion",
|
|
1574
|
+
"npmjs",
|
|
1575
|
+
"okx",
|
|
1576
|
+
"onedrive",
|
|
1577
|
+
"openai",
|
|
1578
|
+
"ozon",
|
|
1579
|
+
"pinterest",
|
|
1580
|
+
"pixiv",
|
|
1581
|
+
"playstation",
|
|
1582
|
+
"private",
|
|
1583
|
+
"pypi",
|
|
1584
|
+
"python",
|
|
1585
|
+
"qq",
|
|
1586
|
+
"reddit",
|
|
1587
|
+
"riot-games",
|
|
1588
|
+
"rockstargames",
|
|
1589
|
+
"rust-lang",
|
|
1590
|
+
"rutracker",
|
|
1591
|
+
"rutube",
|
|
1592
|
+
"sberbank",
|
|
1593
|
+
"slack",
|
|
1594
|
+
"snapchat",
|
|
1595
|
+
"speedtest",
|
|
1596
|
+
"spotify",
|
|
1597
|
+
"stackexchange",
|
|
1598
|
+
"steam",
|
|
1599
|
+
"steam@cn",
|
|
1600
|
+
"substack",
|
|
1601
|
+
"taobao",
|
|
1602
|
+
"telegram",
|
|
1603
|
+
"test",
|
|
1604
|
+
"tiktok",
|
|
1605
|
+
"tinkoff",
|
|
1606
|
+
"tld-!cn",
|
|
1607
|
+
"tld-cn",
|
|
1608
|
+
"tld-net",
|
|
1609
|
+
"tld-proxy",
|
|
1610
|
+
"tron",
|
|
1611
|
+
"twitch",
|
|
1612
|
+
"twitter",
|
|
1613
|
+
"ubisoft",
|
|
1614
|
+
"vk",
|
|
1615
|
+
"vscode",
|
|
1616
|
+
"vtb",
|
|
1617
|
+
"wechat",
|
|
1618
|
+
"weibo",
|
|
1619
|
+
"whatsapp",
|
|
1620
|
+
"wikipedia",
|
|
1621
|
+
"wildberries",
|
|
1622
|
+
"win-extra",
|
|
1623
|
+
"win-spy",
|
|
1624
|
+
"win-update",
|
|
1625
|
+
"windowsupdate",
|
|
1626
|
+
"xboxlive",
|
|
1627
|
+
"yandex",
|
|
1628
|
+
"yapomogu",
|
|
1629
|
+
"youtube",
|
|
1630
|
+
"zoom"
|
|
1470
1631
|
]
|
|
1471
1632
|
}
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
import { readFileSync } from "node:fs";
|
|
19
19
|
import path from "node:path";
|
|
20
20
|
import { fileURLToPath } from "node:url";
|
|
21
|
+
import { RELEASE_FALLBACK_NAMES } from "../tools_impl/geocatalogue_fetch.js";
|
|
21
22
|
/* All ISO 3166-1 alpha-2 country codes (lowercase). Most are valid geoip:* /
|
|
22
23
|
* geosite:geolocation-* tags. */
|
|
23
24
|
export const ISO_COUNTRY_CODES = [
|
|
@@ -155,7 +156,7 @@ for (const code of ISO_COUNTRY_CODES) {
|
|
|
155
156
|
const human = COUNTRY_NAMES[code] ?? code.toUpperCase();
|
|
156
157
|
entries.push(geosite(`geolocation-${code}`, `Domains geolocated to ${human}`));
|
|
157
158
|
}
|
|
158
|
-
function
|
|
159
|
+
function loadCataloguePayload() {
|
|
159
160
|
/* Resolve relative to this module's filesystem location.
|
|
160
161
|
* - source (tsx): src/data/geocatalogue.ts → ../../data/geocatalogue.json
|
|
161
162
|
* - dist (node): dist/data/geocatalogue.js → ../../data/geocatalogue.json
|
|
@@ -165,18 +166,16 @@ function loadFullGeositeNames() {
|
|
|
165
166
|
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
166
167
|
const jsonPath = path.resolve(here, "..", "..", "data", "geocatalogue.json");
|
|
167
168
|
const raw = readFileSync(jsonPath, "utf8");
|
|
168
|
-
|
|
169
|
-
if (Array.isArray(data.names))
|
|
170
|
-
return data.names;
|
|
171
|
-
return [];
|
|
169
|
+
return JSON.parse(raw);
|
|
172
170
|
}
|
|
173
171
|
catch {
|
|
174
172
|
/* No JSON yet → fall back to curated list only. Silent: the lint warning
|
|
175
173
|
* "geo_unknown_category" still works, just with a smaller corpus. */
|
|
176
|
-
return
|
|
174
|
+
return {};
|
|
177
175
|
}
|
|
178
176
|
}
|
|
179
|
-
const
|
|
177
|
+
const payload = loadCataloguePayload();
|
|
178
|
+
const fullNames = Array.isArray(payload.names) ? payload.names : [];
|
|
180
179
|
const seenGeosite = new Set(GEOSITE_NAMES);
|
|
181
180
|
for (const code of ISO_COUNTRY_CODES)
|
|
182
181
|
seenGeosite.add(`geolocation-${code}`);
|
|
@@ -202,6 +201,35 @@ export function isKnownGeoTag(tag) {
|
|
|
202
201
|
return GEOSITE_SET.has(name);
|
|
203
202
|
return false;
|
|
204
203
|
}
|
|
204
|
+
/* ---- v0.12: which categories actually ship in xray-core's geosite.dat ----
|
|
205
|
+
*
|
|
206
|
+
* v2fly source has ~1500 categories, but the published xray-core release
|
|
207
|
+
* geosite.dat only carries a curated subset (~150). Routing rules that
|
|
208
|
+
* reference a v2fly-source-only category will make xray refuse to start.
|
|
209
|
+
*
|
|
210
|
+
* Source priority:
|
|
211
|
+
* 1. data/geocatalogue.json's release_names[] (kept fresh by
|
|
212
|
+
* `npm run fetch-geocatalogue` from Loyalsoldier release asset).
|
|
213
|
+
* 2. RELEASE_FALLBACK_NAMES — hand-curated whitelist used when the JSON
|
|
214
|
+
* lacks the field (older format, or fetch failed in the past).
|
|
215
|
+
*/
|
|
216
|
+
const releaseNamesFromJson = Array.isArray(payload.release_names)
|
|
217
|
+
? payload.release_names
|
|
218
|
+
: [];
|
|
219
|
+
const RELEASE_GEOSITE_SET = new Set((releaseNamesFromJson.length > 0 ? releaseNamesFromJson : RELEASE_FALLBACK_NAMES).map((s) => s.toLowerCase()));
|
|
220
|
+
export const releaseCatalogueSize = () => RELEASE_GEOSITE_SET.size;
|
|
221
|
+
/* "geosite:category-ru" → known to ship in xray release? Returns false for
|
|
222
|
+
* geoip:* (release vs source distinction doesn't apply there), and for
|
|
223
|
+
* tags whose category is missing from the release set. */
|
|
224
|
+
export function isGeositeInXrayRelease(tag) {
|
|
225
|
+
if (!tag.startsWith("geosite:"))
|
|
226
|
+
return false;
|
|
227
|
+
const raw = tag.slice("geosite:".length);
|
|
228
|
+
/* Strip "@cn" attribute suffix (steam@cn) for matching, treat negation
|
|
229
|
+
* "geolocation-!cn" as-is — it is its own category in the dat file. */
|
|
230
|
+
const name = raw.split("@")[0].toLowerCase();
|
|
231
|
+
return RELEASE_GEOSITE_SET.has(name);
|
|
232
|
+
}
|
|
205
233
|
export function searchGeoCatalogue(query, limit = 30) {
|
|
206
234
|
const q = query.toLowerCase().trim();
|
|
207
235
|
if (!q)
|
|
@@ -226,6 +254,8 @@ export function searchGeoCatalogue(query, limit = 30) {
|
|
|
226
254
|
name: e.name,
|
|
227
255
|
description: e.description,
|
|
228
256
|
tag: `${e.prefix}:${e.name}`,
|
|
257
|
+
in_v2fly_source: true,
|
|
258
|
+
in_xray_release: e.prefix === "geosite" && RELEASE_GEOSITE_SET.has(e.name.split("@")[0].toLowerCase()),
|
|
229
259
|
}));
|
|
230
260
|
}
|
|
231
261
|
//# sourceMappingURL=geocatalogue.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"geocatalogue.js","sourceRoot":"","sources":["../../src/data/geocatalogue.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"geocatalogue.js","sourceRoot":"","sources":["../../src/data/geocatalogue.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,sBAAsB,EAAE,MAAM,qCAAqC,CAAC;AAE7E;iCACiC;AACjC,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;IAClF,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;IAClF,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;IAClF,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;IAClF,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;IAClF,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;IAClF,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;IAClF,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;IAClF,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;IAClF,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;IAClF,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;IAClF,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;IAClF,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;IAClF,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;IAClF,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;IAClF,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,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"}
|