mcp-xray-pilot 0.10.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/LICENSE +21 -0
- package/README.md +502 -0
- package/data/docs/_index.json +533 -0
- package/data/docs/basic__api.md +148 -0
- package/data/docs/basic__dns.md +366 -0
- package/data/docs/basic__fakedns.md +202 -0
- package/data/docs/basic__geodata.md +64 -0
- package/data/docs/basic__inbound.md +159 -0
- package/data/docs/basic__index.md +136 -0
- package/data/docs/basic__log.md +67 -0
- package/data/docs/basic__metrics.md +262 -0
- package/data/docs/basic__observatory.md +115 -0
- package/data/docs/basic__outbound.md +164 -0
- package/data/docs/basic__policy.md +140 -0
- package/data/docs/basic__reverse.md +268 -0
- package/data/docs/basic__routing.md +474 -0
- package/data/docs/basic__stats.md +61 -0
- package/data/docs/basic__transport.md +1283 -0
- package/data/docs/features__features_browser_dialer.md +61 -0
- package/data/docs/features__features_env.md +66 -0
- package/data/docs/features__features_fallback.md +110 -0
- package/data/docs/features__features_index.md +17 -0
- package/data/docs/features__features_multiple.md +144 -0
- package/data/docs/features__features_xtls.md +13 -0
- package/data/docs/inbounds__inbounds_dokodemo.md +11 -0
- package/data/docs/inbounds__inbounds_http.md +80 -0
- package/data/docs/inbounds__inbounds_hysteria.md +60 -0
- package/data/docs/inbounds__inbounds_index.md +22 -0
- package/data/docs/inbounds__inbounds_shadowsocks.md +118 -0
- package/data/docs/inbounds__inbounds_socks.md +87 -0
- package/data/docs/inbounds__inbounds_trojan.md +78 -0
- package/data/docs/inbounds__inbounds_tun.md +47 -0
- package/data/docs/inbounds__inbounds_tunnel.md +86 -0
- package/data/docs/inbounds__inbounds_vless.md +135 -0
- package/data/docs/inbounds__inbounds_vmess.md +95 -0
- package/data/docs/inbounds__inbounds_wireguard.md +78 -0
- package/data/docs/outbounds__outbounds_blackhole.md +42 -0
- package/data/docs/outbounds__outbounds_dns.md +97 -0
- package/data/docs/outbounds__outbounds_freedom.md +170 -0
- package/data/docs/outbounds__outbounds_http.md +70 -0
- package/data/docs/outbounds__outbounds_hysteria.md +39 -0
- package/data/docs/outbounds__outbounds_index.md +24 -0
- package/data/docs/outbounds__outbounds_loopback.md +65 -0
- package/data/docs/outbounds__outbounds_shadowsocks.md +105 -0
- package/data/docs/outbounds__outbounds_socks.md +58 -0
- package/data/docs/outbounds__outbounds_trojan.md +49 -0
- package/data/docs/outbounds__outbounds_vless.md +122 -0
- package/data/docs/outbounds__outbounds_vmess.md +76 -0
- package/data/docs/outbounds__outbounds_wireguard.md +141 -0
- package/data/docs/transports__transports_grpc.md +137 -0
- package/data/docs/transports__transports_h2.md +11 -0
- package/data/docs/transports__transports_http.md +11 -0
- package/data/docs/transports__transports_httpupgrade.md +61 -0
- package/data/docs/transports__transports_hysteria.md +110 -0
- package/data/docs/transports__transports_index.md +19 -0
- package/data/docs/transports__transports_mkcp.md +125 -0
- package/data/docs/transports__transports_quic.md +11 -0
- package/data/docs/transports__transports_raw.md +156 -0
- package/data/docs/transports__transports_splithttp.md +11 -0
- package/data/docs/transports__transports_tcp.md +11 -0
- package/data/docs/transports__transports_websocket.md +75 -0
- package/data/docs/transports__transports_xhttp.md +11 -0
- package/dist/data/compatibility.js +170 -0
- package/dist/data/compatibility.js.map +1 -0
- package/dist/data/geocatalogue.js +191 -0
- package/dist/data/geocatalogue.js.map +1 -0
- package/dist/docs.js +339 -0
- package/dist/docs.js.map +1 -0
- package/dist/handlers.js +217 -0
- package/dist/handlers.js.map +1 -0
- package/dist/index.js +66 -0
- package/dist/index.js.map +1 -0
- package/dist/lint.js +737 -0
- package/dist/lint.js.map +1 -0
- package/dist/schemas/protocols/blackhole.js +16 -0
- package/dist/schemas/protocols/blackhole.js.map +1 -0
- package/dist/schemas/protocols/common.js +32 -0
- package/dist/schemas/protocols/common.js.map +1 -0
- package/dist/schemas/protocols/dns.js +14 -0
- package/dist/schemas/protocols/dns.js.map +1 -0
- package/dist/schemas/protocols/dokodemo.js +17 -0
- package/dist/schemas/protocols/dokodemo.js.map +1 -0
- package/dist/schemas/protocols/freedom.js +45 -0
- package/dist/schemas/protocols/freedom.js.map +1 -0
- package/dist/schemas/protocols/http.js +38 -0
- package/dist/schemas/protocols/http.js.map +1 -0
- package/dist/schemas/protocols/hysteria.js +51 -0
- package/dist/schemas/protocols/hysteria.js.map +1 -0
- package/dist/schemas/protocols/index.js +50 -0
- package/dist/schemas/protocols/index.js.map +1 -0
- package/dist/schemas/protocols/loopback.js +11 -0
- package/dist/schemas/protocols/loopback.js.map +1 -0
- package/dist/schemas/protocols/shadowsocks.js +60 -0
- package/dist/schemas/protocols/shadowsocks.js.map +1 -0
- package/dist/schemas/protocols/socks.js +42 -0
- package/dist/schemas/protocols/socks.js.map +1 -0
- package/dist/schemas/protocols/trojan.js +34 -0
- package/dist/schemas/protocols/trojan.js.map +1 -0
- package/dist/schemas/protocols/tun.js +19 -0
- package/dist/schemas/protocols/tun.js.map +1 -0
- package/dist/schemas/protocols/vless.js +44 -0
- package/dist/schemas/protocols/vless.js.map +1 -0
- package/dist/schemas/protocols/vmess.js +48 -0
- package/dist/schemas/protocols/vmess.js.map +1 -0
- package/dist/schemas/protocols/wireguard.js +34 -0
- package/dist/schemas/protocols/wireguard.js.map +1 -0
- package/dist/schemas/security/index.js +16 -0
- package/dist/schemas/security/index.js.map +1 -0
- package/dist/schemas/security/reality.js +35 -0
- package/dist/schemas/security/reality.js.map +1 -0
- package/dist/schemas/security/tls.js +46 -0
- package/dist/schemas/security/tls.js.map +1 -0
- package/dist/schemas/security/xtls.js +17 -0
- package/dist/schemas/security/xtls.js.map +1 -0
- package/dist/schemas/transports/grpc.js +18 -0
- package/dist/schemas/transports/grpc.js.map +1 -0
- package/dist/schemas/transports/httpupgrade.js +14 -0
- package/dist/schemas/transports/httpupgrade.js.map +1 -0
- package/dist/schemas/transports/hysteria.js +25 -0
- package/dist/schemas/transports/hysteria.js.map +1 -0
- package/dist/schemas/transports/index.js +32 -0
- package/dist/schemas/transports/index.js.map +1 -0
- package/dist/schemas/transports/mkcp.js +34 -0
- package/dist/schemas/transports/mkcp.js.map +1 -0
- package/dist/schemas/transports/raw.js +19 -0
- package/dist/schemas/transports/raw.js.map +1 -0
- package/dist/schemas/transports/websocket.js +15 -0
- package/dist/schemas/transports/websocket.js.map +1 -0
- package/dist/schemas/transports/xhttp.js +34 -0
- package/dist/schemas/transports/xhttp.js.map +1 -0
- package/dist/search.js +78 -0
- package/dist/search.js.map +1 -0
- package/dist/state.js +87 -0
- package/dist/state.js.map +1 -0
- package/dist/tools.js +274 -0
- package/dist/tools.js.map +1 -0
- package/dist/tools_impl/diff.js +55 -0
- package/dist/tools_impl/diff.js.map +1 -0
- package/dist/tools_impl/github.js +416 -0
- package/dist/tools_impl/github.js.map +1 -0
- package/dist/tools_impl/merge.js +181 -0
- package/dist/tools_impl/merge.js.map +1 -0
- package/dist/tools_impl/refresh.js +46 -0
- package/dist/tools_impl/refresh.js.map +1 -0
- package/dist/tools_impl/suggest.js +169 -0
- package/dist/tools_impl/suggest.js.map +1 -0
- package/dist/types.js +10 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.js +81 -0
- package/dist/utils.js.map +1 -0
- package/dist/validate.js +408 -0
- package/dist/validate.js.map +1 -0
- package/package.json +62 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 beekamai
|
|
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.
|
package/README.md
ADDED
|
@@ -0,0 +1,502 @@
|
|
|
1
|
+
# mcp-xray-pilot
|
|
2
|
+
|
|
3
|
+
[Русская версия ниже / Russian version below](#mcp-xray-pilot-ru)
|
|
4
|
+
|
|
5
|
+
A Model Context Protocol (MCP) server that gives an LLM offline access to the
|
|
6
|
+
official **xray-core** documentation, plus deep structural validation,
|
|
7
|
+
best-practice lint, a protocol/transport/security compatibility matrix, a
|
|
8
|
+
geosite/geoip catalogue, an alternative-stack suggester and a multi-config
|
|
9
|
+
merge helper.
|
|
10
|
+
|
|
11
|
+
## What it does
|
|
12
|
+
|
|
13
|
+
- **Bundles ~60 docs pages** from the upstream
|
|
14
|
+
[`XTLS/Xray-docs-next`](https://github.com/XTLS/Xray-docs-next) repo as
|
|
15
|
+
raw markdown (no html→md mess).
|
|
16
|
+
- **Refreshes on demand**: `xray_fetch_topic` tries the network first and
|
|
17
|
+
silently overwrites the bundled cache on success. If you're offline (or
|
|
18
|
+
upstream is down), it falls back to the packaged copy and surfaces a
|
|
19
|
+
`warning` field.
|
|
20
|
+
- **Searches the corpus** with a tiny title/body relevance scorer.
|
|
21
|
+
- **Validates** xray JSON config: required top-level fields, per-protocol
|
|
22
|
+
Zod schemas (vless / vmess / trojan / shadowsocks / socks / http /
|
|
23
|
+
wireguard / hysteria / freedom / blackhole / dns / loopback / dokodemo /
|
|
24
|
+
tun), per-transport `*Settings` schemas (raw / xhttp / grpc / ws / mkcp /
|
|
25
|
+
httpupgrade / hysteria), TLS / REALITY security blocks, routing tag
|
|
26
|
+
cross-references.
|
|
27
|
+
- **Lints** ~20 best-practice rules: VLESS `decryption: "none"`, REALITY
|
|
28
|
+
pubkey/shortId/target syntax, XTLS vision flow compatibility, TLS
|
|
29
|
+
fingerprint enum, ALPN collisions, geosite/geoip typo catcher, protocol
|
|
30
|
+
× transport × security incompatibilities, `xhttp.path` leading slash,
|
|
31
|
+
`geoip:private` block rule, sniffing on 80/443 etc.
|
|
32
|
+
- **Geo catalogue**: search ~500 known geoip/geosite tags by substring.
|
|
33
|
+
- **Compares protocols**: side-by-side table of vless/vmess/trojan/ss/
|
|
34
|
+
hysteria2/wireguard on transports, security, anti-DPI, mobile, battery.
|
|
35
|
+
- **Recommends a stack** for a stated goal (anti-DPI in RU/IR/CN, low
|
|
36
|
+
latency, mobile battery, high throughput, stealth-CDN, getting started).
|
|
37
|
+
- **Merges configs**: joins inbounds/outbounds/routing.rules from N JSON
|
|
38
|
+
configs, auto-resolves tag collisions, warns on port collisions.
|
|
39
|
+
|
|
40
|
+
## Tools
|
|
41
|
+
|
|
42
|
+
| Tool | What it does |
|
|
43
|
+
| -------------------------- | ------------------------------------------------------------------------------------- |
|
|
44
|
+
| `xray_list_topics` | List doc topics, grouped by category. Use first to discover slugs. |
|
|
45
|
+
| `xray_fetch_topic` | Fetch one topic as markdown. Network → fall back to bundled cache → update cache. |
|
|
46
|
+
| `xray_search` | Full-text search over all cached docs. Returns ranked hits + snippets. |
|
|
47
|
+
| `xray_validate_config` | Structural+schema validation of an xray JSON config (Zod under the hood). |
|
|
48
|
+
| `xray_lint` | ~20 best-practice lint rules. Returns issues with severity, rule id, JSON-pointer. |
|
|
49
|
+
| `xray_geo_search` | Substring search over the embedded geosite/geoip catalogue. |
|
|
50
|
+
| `xray_diff_protocols` | Side-by-side feature table for two protocols. |
|
|
51
|
+
| `xray_suggest_alternative` | Recommend protocol+transport+security for a goal (anti-DPI / battery / latency / …). |
|
|
52
|
+
| `xray_merge_configs` | Merge N xray configs with tag-collision resolution and conflict warnings. |
|
|
53
|
+
| `xray_github_search` | Search issues/PRs/discussions across XTLS GitHub repos (Xray-core/REALITY/docs). |
|
|
54
|
+
| `xray_github_fetch_issue` | Fetch one issue/PR/discussion with full body + top comments. |
|
|
55
|
+
| `xray_refresh_cache` | Bulk re-fetch cached docs (`scope: all/stale/category`). Optional `discover` for new upstream slugs. |
|
|
56
|
+
|
|
57
|
+
It also exposes a single MCP **resource**: `xray://docs/index` — the raw
|
|
58
|
+
`_index.json` of cached topics.
|
|
59
|
+
|
|
60
|
+
## Examples
|
|
61
|
+
|
|
62
|
+
### Example 1 — lint a broken cascade config
|
|
63
|
+
|
|
64
|
+
Prompt:
|
|
65
|
+
|
|
66
|
+
> Lint this xray config and tell me what's wrong.
|
|
67
|
+
>
|
|
68
|
+
> ```json
|
|
69
|
+
> {
|
|
70
|
+
> "inbounds":[{"tag":"in1","port":443,"protocol":"vless","settings":{"clients":[{"id":"00000000-0000-4000-8000-000000000000","flow":"xtls-rprx-vision"}]},"streamSettings":{"network":"ws","security":"reality","realitySettings":{"target":"yandex.com","privateKey":"short","shortIds":["zz"],"serverNames":["yandex.com"],"fingerprint":"netscape"}}}],
|
|
71
|
+
> "outbounds":[{"tag":"out","protocol":"freedom"}],
|
|
72
|
+
> "routing":{"rules":[{"type":"field","outboundTag":"missing","domain":["geosite:tinkoff-bank"]}]}
|
|
73
|
+
> }
|
|
74
|
+
> ```
|
|
75
|
+
|
|
76
|
+
`xray_lint` response (excerpt):
|
|
77
|
+
|
|
78
|
+
```json
|
|
79
|
+
{
|
|
80
|
+
"summary": { "error_count": 6, "warn_count": 5, "info_count": 2 },
|
|
81
|
+
"issues": [
|
|
82
|
+
{ "rule": "reality_pubkey_format", "severity": "error",
|
|
83
|
+
"path": "/inbounds/0/streamSettings/realitySettings/privateKey",
|
|
84
|
+
"message": "REALITY privateKey must be 43 base64url chars, got 'short'" },
|
|
85
|
+
{ "rule": "reality_shortid_format", "severity": "error",
|
|
86
|
+
"path": "/inbounds/0/streamSettings/realitySettings/shortIds/0",
|
|
87
|
+
"message": "shortIds[0] 'zz' must be hex (0..16 chars, even length)" },
|
|
88
|
+
{ "rule": "flow_requires_specific_transport", "severity": "error",
|
|
89
|
+
"path": "/inbounds/0/streamSettings/network",
|
|
90
|
+
"message": "flow=xtls-rprx-vision requires raw/tcp transport, got 'ws'" },
|
|
91
|
+
{ "rule": "routing_dangling_outbound", "severity": "error",
|
|
92
|
+
"path": "/routing/rules/0/outboundTag",
|
|
93
|
+
"message": "outboundTag 'missing' does not match any outbound tag" },
|
|
94
|
+
{ "rule": "tls_fingerprint_enum", "severity": "warn",
|
|
95
|
+
"path": "/inbounds/0/streamSettings/realitySettings/fingerprint",
|
|
96
|
+
"message": "'netscape' is not a known fingerprint (chrome/firefox/safari/ios/android/edge/360/qq/random/randomized)" },
|
|
97
|
+
{ "rule": "geo_unknown_category", "severity": "warn",
|
|
98
|
+
"path": "/routing/rules/0/domain/0",
|
|
99
|
+
"message": "geosite:tinkoff-bank is not in the bundled catalogue (typo? try geosite:category-ru)" }
|
|
100
|
+
]
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Example 2 — research RKN bypass via GitHub
|
|
105
|
+
|
|
106
|
+
Prompt:
|
|
107
|
+
|
|
108
|
+
> Find recent xray issues about RKN/TSPU and suggest an anti-DPI stack for Russia.
|
|
109
|
+
|
|
110
|
+
Step 1 — `xray_github_search`:
|
|
111
|
+
|
|
112
|
+
```jsonc
|
|
113
|
+
// args
|
|
114
|
+
{ "query": "RKN", "type": "issue", "repo": "all", "sort": "updated" }
|
|
115
|
+
// response (excerpt)
|
|
116
|
+
{
|
|
117
|
+
"total_count": 47,
|
|
118
|
+
"items": [
|
|
119
|
+
{ "repo": "XTLS/Xray-core", "number": 5747, "state": "open",
|
|
120
|
+
"title": "REALITY blocked by TSPU after recent RKN update",
|
|
121
|
+
"comments": 38, "reactions": { "+1": 21 },
|
|
122
|
+
"snippet": "Starting last week our REALITY inbound on :443 stops responding after ~30s of traffic from RU clients. xhttp+REALITY survives longer than raw+vision…" },
|
|
123
|
+
{ "repo": "XTLS/Xray-core", "number": 5332, "state": "closed",
|
|
124
|
+
"title": "RKN: shortId enumeration probe",
|
|
125
|
+
"comments": 22,
|
|
126
|
+
"snippet": "TSPU appears to brute-force shortIds. Recommendation: rotate, keep list >=4 entries, do not include empty string…" }
|
|
127
|
+
]
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Step 2 — `xray_suggest_alternative`:
|
|
132
|
+
|
|
133
|
+
```jsonc
|
|
134
|
+
// args
|
|
135
|
+
{ "goal": "anti-dpi-russia" }
|
|
136
|
+
// response (excerpt)
|
|
137
|
+
{
|
|
138
|
+
"recommendation": {
|
|
139
|
+
"protocol": "vless",
|
|
140
|
+
"transport": "xhttp",
|
|
141
|
+
"security": "reality",
|
|
142
|
+
"flow": null,
|
|
143
|
+
"rationale": [
|
|
144
|
+
"xhttp survives TSPU active probing better than raw/tcp+vision in 2025",
|
|
145
|
+
"REALITY hides SNI; pick a target popular in RU (yandex.com, mail.ru)",
|
|
146
|
+
"Rotate shortIds[] (>=4 entries, hex, no empty string)",
|
|
147
|
+
"Keep packet padding default; do not enable kcp on top of REALITY"
|
|
148
|
+
]
|
|
149
|
+
},
|
|
150
|
+
"see_also": ["xray_fetch_topic transports/xhttp", "xray_fetch_topic features/reality"]
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Install
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
npm i -g mcp-xray-pilot
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Or run from source:
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
git clone https://github.com/beekamai/mcp-xray-pilot.git
|
|
164
|
+
cd mcp-xray-pilot
|
|
165
|
+
npm install
|
|
166
|
+
npm run build
|
|
167
|
+
npm run fetch-docs # fills data/docs/ if you cloned without it
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## Add to Claude Code
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
claude mcp add xray-pilot --scope user -- npx -y mcp-xray-pilot
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
With a GitHub PAT (raises `xray_github_*` rate limit, enables discussions):
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
claude mcp add xray-pilot --scope user --env GITHUB_TOKEN=ghp_xxx -- npx -y mcp-xray-pilot
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Or, from a local clone:
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
claude mcp add xray-pilot --scope user -- node /absolute/path/to/mcp-xray-pilot/dist/index.js
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## Add to Cursor / Windsurf / Cline
|
|
189
|
+
|
|
190
|
+
```jsonc
|
|
191
|
+
{
|
|
192
|
+
"mcpServers": {
|
|
193
|
+
"xray-pilot": {
|
|
194
|
+
"command": "npx",
|
|
195
|
+
"args": ["-y", "mcp-xray-pilot"]
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## Offline cache vs. online refresh
|
|
202
|
+
|
|
203
|
+
The `data/docs/` directory ships with the package. Each call to
|
|
204
|
+
`xray_fetch_topic`:
|
|
205
|
+
|
|
206
|
+
1. If `force_offline=true` → reads only the packaged copy.
|
|
207
|
+
2. Otherwise → tries the upstream raw markdown URL (10s timeout). On HTTP
|
|
208
|
+
200, the response body replaces the on-disk markdown and the index
|
|
209
|
+
entry's `fetched_at` is updated. Subsequent calls in the same process
|
|
210
|
+
serve from in-memory cache.
|
|
211
|
+
3. On any network failure → falls back to the packaged copy, returning the
|
|
212
|
+
markdown plus `warning: "network fetch failed: …"`.
|
|
213
|
+
|
|
214
|
+
To refresh everything in bulk, run `npm run fetch-docs -- --refresh`. To
|
|
215
|
+
discover newly-added pages upstream without writing them: `npm run
|
|
216
|
+
fetch-docs -- --discover`.
|
|
217
|
+
|
|
218
|
+
### Keeping cache fresh
|
|
219
|
+
|
|
220
|
+
There are three complementary ways to keep `data/docs/` aligned with
|
|
221
|
+
upstream:
|
|
222
|
+
|
|
223
|
+
1. **On-demand per page** — every `xray_fetch_topic` call already tries
|
|
224
|
+
the network first and silently overwrites the on-disk copy on success.
|
|
225
|
+
No action needed.
|
|
226
|
+
2. **Bulk via MCP tool** — call `xray_refresh_cache` from the LLM:
|
|
227
|
+
- `{ "scope": "stale", "max_age_days": 30 }` (default) re-fetches only
|
|
228
|
+
entries older than N days.
|
|
229
|
+
- `{ "scope": "all" }` re-fetches every page (~60).
|
|
230
|
+
- `{ "scope": "category", "category": "transports" }` restricts to one
|
|
231
|
+
category.
|
|
232
|
+
- Add `"discover": true` to also report slugs that exist upstream but
|
|
233
|
+
are missing from `DOCS_CATALOGUE` in `src/docs.ts`.
|
|
234
|
+
3. **CI weekly cron** — `.github/workflows/refresh-docs.yml` runs
|
|
235
|
+
`npm run fetch-docs -- --refresh` every Monday 06:00 UTC and opens a
|
|
236
|
+
PR if anything changed (also triggerable manually via `workflow_dispatch`).
|
|
237
|
+
|
|
238
|
+
## Optional `GITHUB_TOKEN` env variable
|
|
239
|
+
|
|
240
|
+
`xray_github_search` and `xray_github_fetch_issue` work anonymously, but
|
|
241
|
+
the GitHub API caps unauthenticated requests at **60/hour**. Setting
|
|
242
|
+
`GITHUB_TOKEN` to any classic or fine-grained PAT (no scopes needed for
|
|
243
|
+
public repos) raises the limit to **5000/hour** and additionally enables
|
|
244
|
+
the **discussions** endpoint (GraphQL), which has no anonymous access.
|
|
245
|
+
|
|
246
|
+
```bash
|
|
247
|
+
export GITHUB_TOKEN=ghp_xxx # Linux / macOS
|
|
248
|
+
$env:GITHUB_TOKEN = "ghp_xxx" # PowerShell
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
When `X-RateLimit-Remaining` drops below 10, the tool surfaces an inline
|
|
252
|
+
warning in the response.
|
|
253
|
+
|
|
254
|
+
## Roadmap
|
|
255
|
+
|
|
256
|
+
See [ROADMAP.md](./ROADMAP.md). All v0.1–v0.10 milestones are checked off.
|
|
257
|
+
|
|
258
|
+
## License
|
|
259
|
+
|
|
260
|
+
MIT.
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
<a id="mcp-xray-pilot-ru"></a>
|
|
265
|
+
|
|
266
|
+
# mcp-xray-pilot (RU)
|
|
267
|
+
|
|
268
|
+
MCP-сервер, дающий LLM офлайн-доступ к официальной документации **xray-core**,
|
|
269
|
+
плюс глубокую валидацию по схемам, lint best-practice, матрицу
|
|
270
|
+
совместимости протоколов/транспортов/security, каталог geosite/geoip,
|
|
271
|
+
рекомендатор альтернативного стека и helper для слияния конфигов.
|
|
272
|
+
|
|
273
|
+
## Что делает
|
|
274
|
+
|
|
275
|
+
- **Упаковывает ~60 страниц** документации из upstream-репозитория
|
|
276
|
+
[`XTLS/Xray-docs-next`](https://github.com/XTLS/Xray-docs-next) как
|
|
277
|
+
raw markdown (без html→md мусора).
|
|
278
|
+
- **Обновляется по запросу**: `xray_fetch_topic` сначала идёт в сеть и при
|
|
279
|
+
успехе молча перезаписывает упакованный кеш. Если оффлайн (или upstream
|
|
280
|
+
лёг), возвращает упакованную копию и выставляет `warning`.
|
|
281
|
+
- **Поиск по корпусу** простым title/body relevance scorer.
|
|
282
|
+
- **Валидирует** xray JSON: обязательные top-level поля, per-protocol
|
|
283
|
+
Zod-схемы (vless / vmess / trojan / shadowsocks / socks / http /
|
|
284
|
+
wireguard / hysteria / freedom / blackhole / dns / loopback / dokodemo /
|
|
285
|
+
tun), per-transport `*Settings` (raw / xhttp / grpc / ws / mkcp /
|
|
286
|
+
httpupgrade / hysteria), security блоки TLS/REALITY, routing tag
|
|
287
|
+
cross-references.
|
|
288
|
+
- **Lint** ~20 правил: VLESS `decryption: "none"`, REALITY pubkey/shortId/
|
|
289
|
+
target syntax, XTLS vision flow compatibility, TLS fingerprint enum,
|
|
290
|
+
ALPN collisions, geo typo catcher, protocol × transport × security
|
|
291
|
+
несовместимости, `xhttp.path` слеш, `geoip:private` block, sniffing на
|
|
292
|
+
80/443 и т.д.
|
|
293
|
+
- **Geo catalogue**: поиск по ~500 известным geoip/geosite тегам.
|
|
294
|
+
- **Сравнение протоколов**: таблица vless/vmess/trojan/ss/hysteria2/
|
|
295
|
+
wireguard по transports, security, anti-DPI, mobile, battery.
|
|
296
|
+
- **Рекомендует стек** под цель (anti-DPI в РФ/Иране/КНР, low-latency,
|
|
297
|
+
mobile-battery, high-throughput, stealth-CDN, getting started).
|
|
298
|
+
- **Сливает конфиги**: объединяет inbounds/outbounds/routing.rules из N
|
|
299
|
+
JSON конфигов, авто-резолвит коллизии тегов, варнит на коллизиях портов.
|
|
300
|
+
|
|
301
|
+
## Тулы
|
|
302
|
+
|
|
303
|
+
| Тул | Что делает |
|
|
304
|
+
| -------------------------- | --------------------------------------------------------------------------------------- |
|
|
305
|
+
| `xray_list_topics` | Список тем по категориям. Дёргать первым. |
|
|
306
|
+
| `xray_fetch_topic` | Получить тему как markdown. Сеть → fallback на кеш → обновление кеша. |
|
|
307
|
+
| `xray_search` | Полнотекстовый поиск по докам. Хиты + сниппеты. |
|
|
308
|
+
| `xray_validate_config` | Структурная валидация + Zod-схемы по протоколу/transport/security. |
|
|
309
|
+
| `xray_lint` | ~20 правил best-practice. Issues с severity, rule id, JSON-pointer. |
|
|
310
|
+
| `xray_geo_search` | Поиск по embedded каталогу geosite/geoip по подстроке. |
|
|
311
|
+
| `xray_diff_protocols` | Side-by-side таблица фич двух протоколов. |
|
|
312
|
+
| `xray_suggest_alternative` | Рекомендация protocol+transport+security под цель. |
|
|
313
|
+
| `xray_merge_configs` | Слить N конфигов с разрешением коллизий тегов. |
|
|
314
|
+
| `xray_github_search` | Поиск issues/PR/discussions по XTLS GitHub репозиториям. |
|
|
315
|
+
| `xray_github_fetch_issue` | Получить одну issue/PR/discussion с полным body + топ комментариев. |
|
|
316
|
+
| `xray_refresh_cache` | Bulk перезатяжка кеша доков (`scope: all/stale/category`). Опц. `discover` для новых slug'ов. |
|
|
317
|
+
|
|
318
|
+
Также один MCP **ресурс**: `xray://docs/index`.
|
|
319
|
+
|
|
320
|
+
## Примеры
|
|
321
|
+
|
|
322
|
+
### Пример 1 — линт сломанного каскадного конфига
|
|
323
|
+
|
|
324
|
+
Промпт:
|
|
325
|
+
|
|
326
|
+
> Прогони линт по этому xray конфигу и скажи что не так.
|
|
327
|
+
>
|
|
328
|
+
> ```json
|
|
329
|
+
> {
|
|
330
|
+
> "inbounds":[{"tag":"in1","port":443,"protocol":"vless","settings":{"clients":[{"id":"00000000-0000-4000-8000-000000000000","flow":"xtls-rprx-vision"}]},"streamSettings":{"network":"ws","security":"reality","realitySettings":{"target":"yandex.com","privateKey":"short","shortIds":["zz"],"serverNames":["yandex.com"],"fingerprint":"netscape"}}}],
|
|
331
|
+
> "outbounds":[{"tag":"out","protocol":"freedom"}],
|
|
332
|
+
> "routing":{"rules":[{"type":"field","outboundTag":"missing","domain":["geosite:tinkoff-bank"]}]}
|
|
333
|
+
> }
|
|
334
|
+
> ```
|
|
335
|
+
|
|
336
|
+
Ответ `xray_lint` (выжимка):
|
|
337
|
+
|
|
338
|
+
```json
|
|
339
|
+
{
|
|
340
|
+
"summary": { "error_count": 6, "warn_count": 5, "info_count": 2 },
|
|
341
|
+
"issues": [
|
|
342
|
+
{ "rule": "reality_pubkey_format", "severity": "error",
|
|
343
|
+
"path": "/inbounds/0/streamSettings/realitySettings/privateKey",
|
|
344
|
+
"message": "REALITY privateKey must be 43 base64url chars, got 'short'" },
|
|
345
|
+
{ "rule": "reality_shortid_format", "severity": "error",
|
|
346
|
+
"path": "/inbounds/0/streamSettings/realitySettings/shortIds/0",
|
|
347
|
+
"message": "shortIds[0] 'zz' must be hex (0..16 chars, even length)" },
|
|
348
|
+
{ "rule": "flow_requires_specific_transport", "severity": "error",
|
|
349
|
+
"path": "/inbounds/0/streamSettings/network",
|
|
350
|
+
"message": "flow=xtls-rprx-vision requires raw/tcp transport, got 'ws'" },
|
|
351
|
+
{ "rule": "routing_dangling_outbound", "severity": "error",
|
|
352
|
+
"path": "/routing/rules/0/outboundTag",
|
|
353
|
+
"message": "outboundTag 'missing' does not match any outbound tag" },
|
|
354
|
+
{ "rule": "tls_fingerprint_enum", "severity": "warn",
|
|
355
|
+
"path": "/inbounds/0/streamSettings/realitySettings/fingerprint",
|
|
356
|
+
"message": "'netscape' is not a known fingerprint (chrome/firefox/safari/ios/android/edge/360/qq/random/randomized)" },
|
|
357
|
+
{ "rule": "geo_unknown_category", "severity": "warn",
|
|
358
|
+
"path": "/routing/rules/0/domain/0",
|
|
359
|
+
"message": "geosite:tinkoff-bank is not in the bundled catalogue (typo? try geosite:category-ru)" }
|
|
360
|
+
]
|
|
361
|
+
}
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
### Пример 2 — ресёрч обхода РКН через GitHub
|
|
365
|
+
|
|
366
|
+
Промпт:
|
|
367
|
+
|
|
368
|
+
> Найди свежие xray issues про РКН/ТСПУ и предложи anti-DPI стек под Россию.
|
|
369
|
+
|
|
370
|
+
Шаг 1 — `xray_github_search`:
|
|
371
|
+
|
|
372
|
+
```jsonc
|
|
373
|
+
// args
|
|
374
|
+
{ "query": "RKN", "type": "issue", "repo": "all", "sort": "updated" }
|
|
375
|
+
// response (выжимка)
|
|
376
|
+
{
|
|
377
|
+
"total_count": 47,
|
|
378
|
+
"items": [
|
|
379
|
+
{ "repo": "XTLS/Xray-core", "number": 5747, "state": "open",
|
|
380
|
+
"title": "REALITY blocked by TSPU after recent RKN update",
|
|
381
|
+
"comments": 38, "reactions": { "+1": 21 },
|
|
382
|
+
"snippet": "Starting last week our REALITY inbound on :443 stops responding after ~30s of traffic from RU clients. xhttp+REALITY survives longer than raw+vision…" },
|
|
383
|
+
{ "repo": "XTLS/Xray-core", "number": 5332, "state": "closed",
|
|
384
|
+
"title": "RKN: shortId enumeration probe",
|
|
385
|
+
"comments": 22,
|
|
386
|
+
"snippet": "TSPU appears to brute-force shortIds. Recommendation: rotate, keep list >=4 entries, do not include empty string…" }
|
|
387
|
+
]
|
|
388
|
+
}
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
Шаг 2 — `xray_suggest_alternative`:
|
|
392
|
+
|
|
393
|
+
```jsonc
|
|
394
|
+
// args
|
|
395
|
+
{ "goal": "anti-dpi-russia" }
|
|
396
|
+
// response (выжимка)
|
|
397
|
+
{
|
|
398
|
+
"recommendation": {
|
|
399
|
+
"protocol": "vless",
|
|
400
|
+
"transport": "xhttp",
|
|
401
|
+
"security": "reality",
|
|
402
|
+
"flow": null,
|
|
403
|
+
"rationale": [
|
|
404
|
+
"xhttp survives TSPU active probing better than raw/tcp+vision in 2025",
|
|
405
|
+
"REALITY hides SNI; pick a target popular in RU (yandex.com, mail.ru)",
|
|
406
|
+
"Rotate shortIds[] (>=4 entries, hex, no empty string)",
|
|
407
|
+
"Keep packet padding default; do not enable kcp on top of REALITY"
|
|
408
|
+
]
|
|
409
|
+
},
|
|
410
|
+
"see_also": ["xray_fetch_topic transports/xhttp", "xray_fetch_topic features/reality"]
|
|
411
|
+
}
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
## Установка
|
|
415
|
+
|
|
416
|
+
```bash
|
|
417
|
+
npm i -g mcp-xray-pilot
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
Или из исходников:
|
|
421
|
+
|
|
422
|
+
```bash
|
|
423
|
+
git clone https://github.com/beekamai/mcp-xray-pilot.git
|
|
424
|
+
cd mcp-xray-pilot
|
|
425
|
+
npm install
|
|
426
|
+
npm run build
|
|
427
|
+
npm run fetch-docs
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
## Подключить к Claude Code
|
|
431
|
+
|
|
432
|
+
```bash
|
|
433
|
+
claude mcp add xray-pilot --scope user -- npx -y mcp-xray-pilot
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
С GitHub PAT (поднимает rate-limit `xray_github_*`, включает discussions):
|
|
437
|
+
|
|
438
|
+
```bash
|
|
439
|
+
claude mcp add xray-pilot --scope user --env GITHUB_TOKEN=ghp_xxx -- npx -y mcp-xray-pilot
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
Или из локального клона:
|
|
443
|
+
|
|
444
|
+
```bash
|
|
445
|
+
claude mcp add xray-pilot --scope user -- node /absolute/path/to/mcp-xray-pilot/dist/index.js
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
## Офлайн-кеш vs онлайн-обновление
|
|
449
|
+
|
|
450
|
+
Папка `data/docs/` едет в пакете. Каждый вызов `xray_fetch_topic`:
|
|
451
|
+
|
|
452
|
+
1. При `force_offline=true` → читает только упакованную копию.
|
|
453
|
+
2. Иначе → пробует upstream raw URL (10s таймаут). При HTTP 200 ответ
|
|
454
|
+
перезаписывает markdown на диске, `fetched_at` обновляется. Последующие
|
|
455
|
+
вызовы в том же процессе отдаются из in-memory кеша.
|
|
456
|
+
3. При любой сетевой ошибке → fallback на упакованную копию, возвращает
|
|
457
|
+
markdown плюс `warning: "network fetch failed: …"`.
|
|
458
|
+
|
|
459
|
+
Bulk-обновление — `npm run fetch-docs -- --refresh`. Discover новых
|
|
460
|
+
страниц в upstream без записи — `npm run fetch-docs -- --discover`.
|
|
461
|
+
|
|
462
|
+
### Поддержание кеша актуальным
|
|
463
|
+
|
|
464
|
+
Три способа держать `data/docs/` в синхроне с upstream:
|
|
465
|
+
|
|
466
|
+
1. **На каждый запрос** — `xray_fetch_topic` сам ходит в сеть и при HTTP
|
|
467
|
+
200 перезаписывает on-disk копию. Ничего делать не надо.
|
|
468
|
+
2. **Bulk через MCP-тул** — позови `xray_refresh_cache`:
|
|
469
|
+
- `{ "scope": "stale", "max_age_days": 30 }` (default) — только
|
|
470
|
+
устаревшие старше N дней.
|
|
471
|
+
- `{ "scope": "all" }` — все ~60 страниц.
|
|
472
|
+
- `{ "scope": "category", "category": "transports" }` — одна категория.
|
|
473
|
+
- `"discover": true` — дополнительно вернёт список slug'ов, которые
|
|
474
|
+
появились upstream, но отсутствуют в `DOCS_CATALOGUE` (`src/docs.ts`).
|
|
475
|
+
3. **CI weekly cron** — `.github/workflows/refresh-docs.yml` каждый
|
|
476
|
+
понедельник 06:00 UTC гоняет `npm run fetch-docs -- --refresh` и
|
|
477
|
+
открывает PR если что-то поменялось (есть `workflow_dispatch` для
|
|
478
|
+
ручного триггера).
|
|
479
|
+
|
|
480
|
+
## Опциональный `GITHUB_TOKEN`
|
|
481
|
+
|
|
482
|
+
`xray_github_search` и `xray_github_fetch_issue` работают анонимно, но
|
|
483
|
+
GitHub API лимитирует unauth запросы **60/час**. Установка `GITHUB_TOKEN`
|
|
484
|
+
(любой classic или fine-grained PAT, для публичных репо scope не нужен)
|
|
485
|
+
поднимает лимит до **5000/час** и дополнительно включает поиск/чтение
|
|
486
|
+
**discussions** (GraphQL, у него нет anon-доступа).
|
|
487
|
+
|
|
488
|
+
```bash
|
|
489
|
+
export GITHUB_TOKEN=ghp_xxx # Linux / macOS
|
|
490
|
+
$env:GITHUB_TOKEN = "ghp_xxx" # PowerShell
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
Когда `X-RateLimit-Remaining` падает ниже 10, тул возвращает inline-warning
|
|
494
|
+
в ответе.
|
|
495
|
+
|
|
496
|
+
## Roadmap
|
|
497
|
+
|
|
498
|
+
См. [ROADMAP.md](./ROADMAP.md) — все вехи v0.1–v0.10 закрыты.
|
|
499
|
+
|
|
500
|
+
## Лицензия
|
|
501
|
+
|
|
502
|
+
MIT.
|