@crush-protocol/mcp-client 0.2.0 → 0.3.1
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 +786 -139
- package/dist/__tests__/e2e.test.js +2 -2
- package/dist/cli.js +28 -6
- package/dist/setup/setupClients.d.ts +4 -0
- package/dist/setup/setupClients.js +209 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,246 +1,893 @@
|
|
|
1
|
-
# Crush Protocol MCP
|
|
1
|
+
# Crush Protocol MCP Client
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@crush-protocol/mcp-client)
|
|
4
|
-
[](./LICENSE)
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
`@crush-protocol/mcp-client` is the npm entrypoint for Crush Protocol MCP.
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Crush Protocol is an AI-native quantitative trading product. It lets an MCP host connect to Crush and use trading-focused tools for strategy research, backtest creation, live strategy management, and market data discovery.
|
|
9
9
|
|
|
10
|
-
##
|
|
10
|
+
## Quick Setup
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
-
|
|
14
|
-
|
|
12
|
+
```sh
|
|
13
|
+
npx -y @crush-protocol/mcp-client setup --all
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
This writes MCP config for all **9** supported hosts: Cursor, Claude Code, Codex, Gemini CLI, OpenCode, VS Code, Windsurf, Claude Desktop, Warp.
|
|
17
|
+
|
|
18
|
+
To target a single host: `npx -y @crush-protocol/mcp-client setup --cursor`
|
|
19
|
+
|
|
20
|
+
**[All Client Configurations →](#client-configuration)**
|
|
21
|
+
|
|
22
|
+
## Connection Modes
|
|
23
|
+
|
|
24
|
+
| Mode | Transport | Auth | Best For |
|
|
25
|
+
|------|-----------|------|----------|
|
|
26
|
+
| **Local** | stdio (npx) | OAuth — browser opens automatically | Most MCP clients |
|
|
27
|
+
| **Remote** | Streamable HTTP | OAuth — browser opens automatically | Clients with native HTTP support |
|
|
15
28
|
|
|
16
|
-
|
|
29
|
+
**Remote Server URL:** `https://crush-mcp-ats.dev.xexlab.com/mcp`
|
|
17
30
|
|
|
18
|
-
|
|
31
|
+
Authentication is automatic (OAuth 2.1 Authorization Code + PKCE). On first use, a browser window opens for login; tokens are cached locally for reuse.
|
|
19
32
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
33
|
+
For hosts that support URL-only MCP (Remote mode), the full flow is:
|
|
34
|
+
|
|
35
|
+
1. Host connects to the MCP URL
|
|
36
|
+
2. Server returns `401` with `WWW-Authenticate` header
|
|
37
|
+
3. Host performs OAuth discovery and dynamic client registration
|
|
38
|
+
4. Completes Authorization Code + PKCE via browser
|
|
39
|
+
5. Persists tokens locally and reconnects
|
|
40
|
+
|
|
41
|
+
If a host cannot complete OAuth automatically, pre-authorize with:
|
|
42
|
+
|
|
43
|
+
```sh
|
|
44
|
+
npx -y @crush-protocol/mcp-client login
|
|
23
45
|
```
|
|
24
46
|
|
|
25
|
-
|
|
26
|
-
|
|
47
|
+
## Available Tools
|
|
48
|
+
|
|
49
|
+
**Market Data** — `list_tables` · `list_tokens` · `list_indicators` · `list_timeframes` · `get_data_range` · `check_query_size` · `fetch_ohlcv` · `fetch_indicator` · `fetch_news` · `get_connection_config` · `save_custom_indicator` · `list_custom_indicators` · `get_custom_indicator` · `delete_custom_indicator`
|
|
50
|
+
|
|
51
|
+
**Backtest** — `get_backtest_config_schema` · `get_available_tokens` · `validate_expression` · `create_backtest` · `list_backtests`
|
|
52
|
+
|
|
53
|
+
**Strategy** — `create_strategy` · `list_strategies` · `get_strategy` · `update_strategy` · `delete_strategy` · `toggle_strategy` · `get_strategy_logs`
|
|
54
|
+
|
|
55
|
+
**Signal** — `get_signal_metadata` · `get_signals_by_category`
|
|
56
|
+
|
|
57
|
+
**Utilities** — `search_tokens` · `get_token_info` · `get_trending_tokens` · `get_alpha_feed` · `get_token_feed`
|
|
58
|
+
|
|
59
|
+
Detailed tool guidance is in [INSTRUCTIONS.md](./INSTRUCTIONS.md).
|
|
60
|
+
|
|
61
|
+
## Client Configuration
|
|
62
|
+
|
|
63
|
+
### Cursor
|
|
64
|
+
|
|
65
|
+
[](https://cursor.com/install-mcp?name=crush-protocol&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkBjcnVzaC1wcm90b2NvbC9tY3AtY2xpZW50Il19)
|
|
66
|
+
|
|
67
|
+
[Cursor MCP docs](https://docs.cursor.com/context/model-context-protocol)
|
|
68
|
+
|
|
69
|
+
Go to: `Settings` → `Cursor Settings` → `MCP` → `Add new global MCP server`
|
|
70
|
+
|
|
71
|
+
#### Local Server Connection
|
|
72
|
+
|
|
73
|
+
```json
|
|
74
|
+
{
|
|
75
|
+
"mcpServers": {
|
|
76
|
+
"crush-protocol": {
|
|
77
|
+
"command": "npx",
|
|
78
|
+
"args": ["-y", "@crush-protocol/mcp-client"]
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
27
82
|
```
|
|
28
83
|
|
|
29
|
-
|
|
84
|
+
#### Remote Server Connection
|
|
85
|
+
|
|
86
|
+
```json
|
|
87
|
+
{
|
|
88
|
+
"mcpServers": {
|
|
89
|
+
"crush-protocol": {
|
|
90
|
+
"url": "https://crush-mcp-ats.dev.xexlab.com/mcp"
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
```
|
|
30
95
|
|
|
31
96
|
---
|
|
32
97
|
|
|
33
|
-
|
|
98
|
+
### Claude Code
|
|
34
99
|
|
|
35
|
-
|
|
100
|
+
[Claude Code MCP docs](https://docs.anthropic.com/en/docs/claude-code/mcp)
|
|
36
101
|
|
|
37
|
-
|
|
102
|
+
#### Local Server Connection
|
|
38
103
|
|
|
39
|
-
|
|
104
|
+
```sh
|
|
105
|
+
claude mcp add --scope user crush-protocol -- npx -y @crush-protocol/mcp-client
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
#### Remote Server Connection
|
|
109
|
+
|
|
110
|
+
```sh
|
|
111
|
+
claude mcp add --scope user --transport http crush-protocol https://crush-mcp-ats.dev.xexlab.com/mcp
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
### OpenCode
|
|
40
117
|
|
|
41
|
-
|
|
42
|
-
- host integrations such as Claude Code / Cursor / Windsurf can also provide only the MCP URL
|
|
43
|
-
- both paths ultimately use the same OAuth access tokens against `/mcp`
|
|
118
|
+
[OpenCode MCP docs](https://opencode.ai/docs/mcp-servers)
|
|
44
119
|
|
|
45
|
-
|
|
120
|
+
Add to `~/.config/opencode/opencode.json`:
|
|
46
121
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
122
|
+
#### Local Server Connection
|
|
123
|
+
|
|
124
|
+
```json
|
|
125
|
+
{
|
|
126
|
+
"$schema": "https://opencode.ai/config.json",
|
|
127
|
+
"mcp": {
|
|
128
|
+
"crush-protocol": {
|
|
129
|
+
"type": "local",
|
|
130
|
+
"command": ["npx", "-y", "@crush-protocol/mcp-client"],
|
|
131
|
+
"enabled": true
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
#### Remote Server Connection
|
|
138
|
+
|
|
139
|
+
```json
|
|
140
|
+
{
|
|
141
|
+
"$schema": "https://opencode.ai/config.json",
|
|
142
|
+
"mcp": {
|
|
143
|
+
"crush-protocol": {
|
|
144
|
+
"type": "remote",
|
|
145
|
+
"url": "https://crush-mcp-ats.dev.xexlab.com/mcp",
|
|
146
|
+
"enabled": true
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
```
|
|
50
151
|
|
|
51
152
|
---
|
|
52
153
|
|
|
53
|
-
|
|
154
|
+
### OpenAI Codex
|
|
54
155
|
|
|
55
|
-
|
|
156
|
+
[OpenAI Codex MCP docs](https://developers.openai.com/codex/mcp)
|
|
56
157
|
|
|
57
|
-
|
|
158
|
+
#### Using CLI
|
|
58
159
|
|
|
59
160
|
```sh
|
|
60
|
-
|
|
61
|
-
|
|
161
|
+
codex mcp add crush-protocol -- npx -y @crush-protocol/mcp-client
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
#### Local Server Connection
|
|
62
165
|
|
|
63
|
-
|
|
64
|
-
npx -y @crush-protocol/mcp-client login --url https://mcp.crush-protocol.com/mcp
|
|
166
|
+
Add to `~/.codex/config.toml`:
|
|
65
167
|
|
|
66
|
-
|
|
67
|
-
|
|
168
|
+
```toml
|
|
169
|
+
[mcp_servers.crush-protocol]
|
|
170
|
+
command = "npx"
|
|
171
|
+
args = ["-y", "@crush-protocol/mcp-client"]
|
|
172
|
+
startup_timeout_ms = 20000
|
|
173
|
+
```
|
|
68
174
|
|
|
69
|
-
|
|
70
|
-
npx -y @crush-protocol/mcp-client ping --url https://mcp.crush-protocol.com/mcp
|
|
175
|
+
#### Remote Server Connection
|
|
71
176
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
--name get_backtest_config_schema
|
|
177
|
+
```toml
|
|
178
|
+
[mcp_servers.crush-protocol]
|
|
179
|
+
url = "https://crush-mcp-ats.dev.xexlab.com/mcp"
|
|
76
180
|
```
|
|
77
181
|
|
|
78
|
-
|
|
182
|
+
---
|
|
79
183
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
184
|
+
### Google Gemini CLI
|
|
185
|
+
|
|
186
|
+
[Gemini CLI Configuration](https://google-gemini.github.io/gemini-cli/docs/tools/mcp-server.html)
|
|
83
187
|
|
|
84
|
-
|
|
85
|
-
npx -y @crush-protocol/mcp-client backtest:tokens --url https://mcp.crush-protocol.com/mcp
|
|
188
|
+
Add to `~/.gemini/settings.json`:
|
|
86
189
|
|
|
87
|
-
|
|
88
|
-
|
|
190
|
+
#### Remote Server Connection
|
|
191
|
+
|
|
192
|
+
```json
|
|
193
|
+
{
|
|
194
|
+
"mcpServers": {
|
|
195
|
+
"crush-protocol": {
|
|
196
|
+
"httpUrl": "https://crush-mcp-ats.dev.xexlab.com/mcp"
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
89
200
|
```
|
|
90
201
|
|
|
91
|
-
|
|
202
|
+
#### Local Server Connection
|
|
92
203
|
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
|
|
204
|
+
```json
|
|
205
|
+
{
|
|
206
|
+
"mcpServers": {
|
|
207
|
+
"crush-protocol": {
|
|
208
|
+
"command": "npx",
|
|
209
|
+
"args": ["-y", "@crush-protocol/mcp-client"]
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
### VS Code
|
|
218
|
+
|
|
219
|
+
[VS Code MCP docs](https://code.visualstudio.com/docs/copilot/chat/mcp-servers)
|
|
220
|
+
|
|
221
|
+
Add to `.vscode/mcp.json`:
|
|
222
|
+
|
|
223
|
+
#### Remote Server Connection
|
|
224
|
+
|
|
225
|
+
```json
|
|
226
|
+
{
|
|
227
|
+
"servers": {
|
|
228
|
+
"crush-protocol": {
|
|
229
|
+
"type": "http",
|
|
230
|
+
"url": "https://crush-mcp-ats.dev.xexlab.com/mcp"
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
#### Local Server Connection
|
|
237
|
+
|
|
238
|
+
```json
|
|
239
|
+
{
|
|
240
|
+
"servers": {
|
|
241
|
+
"crush-protocol": {
|
|
242
|
+
"type": "stdio",
|
|
243
|
+
"command": "npx",
|
|
244
|
+
"args": ["-y", "@crush-protocol/mcp-client"]
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
### Windsurf
|
|
253
|
+
|
|
254
|
+
[Windsurf MCP docs](https://docs.windsurf.com/windsurf/cascade/mcp)
|
|
96
255
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
256
|
+
#### Remote Server Connection
|
|
257
|
+
|
|
258
|
+
```json
|
|
259
|
+
{
|
|
260
|
+
"mcpServers": {
|
|
261
|
+
"crush-protocol": {
|
|
262
|
+
"serverUrl": "https://crush-mcp-ats.dev.xexlab.com/mcp"
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
101
266
|
```
|
|
102
267
|
|
|
103
|
-
|
|
268
|
+
#### Local Server Connection
|
|
104
269
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
270
|
+
```json
|
|
271
|
+
{
|
|
272
|
+
"mcpServers": {
|
|
273
|
+
"crush-protocol": {
|
|
274
|
+
"command": "npx",
|
|
275
|
+
"args": ["-y", "@crush-protocol/mcp-client"]
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
```
|
|
108
280
|
|
|
109
|
-
|
|
281
|
+
---
|
|
282
|
+
|
|
283
|
+
### Claude Desktop
|
|
284
|
+
|
|
285
|
+
[Claude Desktop MCP docs](https://modelcontextprotocol.io/quickstart/user)
|
|
286
|
+
|
|
287
|
+
Edit `claude_desktop_config.json`:
|
|
288
|
+
|
|
289
|
+
#### Local Server Connection
|
|
290
|
+
|
|
291
|
+
```json
|
|
292
|
+
{
|
|
293
|
+
"mcpServers": {
|
|
294
|
+
"crush-protocol": {
|
|
295
|
+
"command": "npx",
|
|
296
|
+
"args": ["-y", "@crush-protocol/mcp-client"]
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
```
|
|
110
301
|
|
|
111
302
|
---
|
|
112
303
|
|
|
113
|
-
|
|
304
|
+
### Kiro
|
|
114
305
|
|
|
115
|
-
|
|
306
|
+
[Kiro MCP docs](https://kiro.dev/docs/mcp/configuration/)
|
|
307
|
+
|
|
308
|
+
Navigate `Kiro` → `MCP Servers` → `+ Add`, paste the configuration:
|
|
309
|
+
|
|
310
|
+
#### Remote Server Connection
|
|
311
|
+
|
|
312
|
+
```json
|
|
313
|
+
{
|
|
314
|
+
"mcpServers": {
|
|
315
|
+
"crush-protocol": {
|
|
316
|
+
"url": "https://crush-mcp-ats.dev.xexlab.com/mcp"
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
#### Local Server Connection
|
|
323
|
+
|
|
324
|
+
```json
|
|
325
|
+
{
|
|
326
|
+
"mcpServers": {
|
|
327
|
+
"crush-protocol": {
|
|
328
|
+
"command": "npx",
|
|
329
|
+
"args": ["-y", "@crush-protocol/mcp-client"]
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
---
|
|
336
|
+
|
|
337
|
+
### Roo Code
|
|
338
|
+
|
|
339
|
+
[Roo Code MCP docs](https://docs.roocode.com/features/mcp/using-mcp-in-roo)
|
|
340
|
+
|
|
341
|
+
#### Remote Server Connection
|
|
342
|
+
|
|
343
|
+
```json
|
|
344
|
+
{
|
|
345
|
+
"mcpServers": {
|
|
346
|
+
"crush-protocol": {
|
|
347
|
+
"type": "streamable-http",
|
|
348
|
+
"url": "https://crush-mcp-ats.dev.xexlab.com/mcp"
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
#### Local Server Connection
|
|
355
|
+
|
|
356
|
+
```json
|
|
357
|
+
{
|
|
358
|
+
"mcpServers": {
|
|
359
|
+
"crush-protocol": {
|
|
360
|
+
"command": "npx",
|
|
361
|
+
"args": ["-y", "@crush-protocol/mcp-client"]
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
---
|
|
368
|
+
|
|
369
|
+
### Cline
|
|
370
|
+
|
|
371
|
+
[Cline MCP Marketplace](https://cline.bot/mcp-marketplace)
|
|
372
|
+
|
|
373
|
+
#### Remote Server Connection
|
|
374
|
+
|
|
375
|
+
```json
|
|
376
|
+
{
|
|
377
|
+
"mcpServers": {
|
|
378
|
+
"crush-protocol": {
|
|
379
|
+
"url": "https://crush-mcp-ats.dev.xexlab.com/mcp",
|
|
380
|
+
"type": "streamableHttp"
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
#### Local Server Connection
|
|
387
|
+
|
|
388
|
+
```json
|
|
389
|
+
{
|
|
390
|
+
"mcpServers": {
|
|
391
|
+
"crush-protocol": {
|
|
392
|
+
"command": "npx",
|
|
393
|
+
"args": ["-y", "@crush-protocol/mcp-client"]
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
---
|
|
400
|
+
|
|
401
|
+
### Trae
|
|
402
|
+
|
|
403
|
+
[Trae MCP docs](https://docs.trae.ai/ide/model-context-protocol?_lang=en)
|
|
404
|
+
|
|
405
|
+
#### Remote Server Connection
|
|
406
|
+
|
|
407
|
+
```json
|
|
408
|
+
{
|
|
409
|
+
"mcpServers": {
|
|
410
|
+
"crush-protocol": {
|
|
411
|
+
"url": "https://crush-mcp-ats.dev.xexlab.com/mcp"
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
#### Local Server Connection
|
|
418
|
+
|
|
419
|
+
```json
|
|
420
|
+
{
|
|
421
|
+
"mcpServers": {
|
|
422
|
+
"crush-protocol": {
|
|
423
|
+
"command": "npx",
|
|
424
|
+
"args": ["-y", "@crush-protocol/mcp-client"]
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
---
|
|
431
|
+
|
|
432
|
+
### Augment Code
|
|
433
|
+
|
|
434
|
+
1. Click hamburger menu → Settings → Tools → `+ Add MCP`
|
|
435
|
+
2. Enter command: `npx -y @crush-protocol/mcp-client`
|
|
436
|
+
3. Name: `crush-protocol` → Click Add
|
|
437
|
+
|
|
438
|
+
Manual config in VS Code settings:
|
|
439
|
+
|
|
440
|
+
```json
|
|
441
|
+
"augment.advanced": {
|
|
442
|
+
"mcpServers": [
|
|
443
|
+
{
|
|
444
|
+
"name": "crush-protocol",
|
|
445
|
+
"command": "npx",
|
|
446
|
+
"args": ["-y", "@crush-protocol/mcp-client"]
|
|
447
|
+
}
|
|
448
|
+
]
|
|
449
|
+
}
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
---
|
|
453
|
+
|
|
454
|
+
### Copilot Coding Agent
|
|
455
|
+
|
|
456
|
+
[GitHub Copilot MCP docs](https://docs.github.com/en/enterprise-cloud@latest/copilot/how-tos/agents/copilot-coding-agent/extending-copilot-coding-agent-with-mcp)
|
|
457
|
+
|
|
458
|
+
#### Remote Server Connection
|
|
459
|
+
|
|
460
|
+
```json
|
|
461
|
+
{
|
|
462
|
+
"mcpServers": {
|
|
463
|
+
"crush-protocol": {
|
|
464
|
+
"type": "http",
|
|
465
|
+
"url": "https://crush-mcp-ats.dev.xexlab.com/mcp"
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
#### Local Server Connection
|
|
472
|
+
|
|
473
|
+
```json
|
|
474
|
+
{
|
|
475
|
+
"mcpServers": {
|
|
476
|
+
"crush-protocol": {
|
|
477
|
+
"type": "local",
|
|
478
|
+
"command": "npx",
|
|
479
|
+
"args": ["-y", "@crush-protocol/mcp-client"]
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
---
|
|
486
|
+
|
|
487
|
+
### Copilot CLI
|
|
488
|
+
|
|
489
|
+
Add to `~/.copilot/mcp-config.json`:
|
|
490
|
+
|
|
491
|
+
#### Remote Server Connection
|
|
492
|
+
|
|
493
|
+
```json
|
|
494
|
+
{
|
|
495
|
+
"mcpServers": {
|
|
496
|
+
"crush-protocol": {
|
|
497
|
+
"type": "http",
|
|
498
|
+
"url": "https://crush-mcp-ats.dev.xexlab.com/mcp"
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
#### Local Server Connection
|
|
505
|
+
|
|
506
|
+
```json
|
|
507
|
+
{
|
|
508
|
+
"mcpServers": {
|
|
509
|
+
"crush-protocol": {
|
|
510
|
+
"type": "local",
|
|
511
|
+
"command": "npx",
|
|
512
|
+
"args": ["-y", "@crush-protocol/mcp-client"]
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
---
|
|
519
|
+
|
|
520
|
+
### Amazon Q Developer CLI
|
|
521
|
+
|
|
522
|
+
[Amazon Q Developer CLI docs](https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/command-line-mcp-configuration.html)
|
|
523
|
+
|
|
524
|
+
```json
|
|
525
|
+
{
|
|
526
|
+
"mcpServers": {
|
|
527
|
+
"crush-protocol": {
|
|
528
|
+
"command": "npx",
|
|
529
|
+
"args": ["-y", "@crush-protocol/mcp-client"]
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
---
|
|
536
|
+
|
|
537
|
+
### Warp
|
|
538
|
+
|
|
539
|
+
[Warp MCP docs](https://docs.warp.dev/knowledge-and-collaboration/mcp#adding-an-mcp-server)
|
|
540
|
+
|
|
541
|
+
Navigate `Settings` → `AI` → `Manage MCP servers` → `+ Add`:
|
|
542
|
+
|
|
543
|
+
```json
|
|
544
|
+
{
|
|
545
|
+
"crush-protocol": {
|
|
546
|
+
"command": "npx",
|
|
547
|
+
"args": ["-y", "@crush-protocol/mcp-client"],
|
|
548
|
+
"env": {},
|
|
549
|
+
"working_directory": null,
|
|
550
|
+
"start_on_launch": true
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
---
|
|
556
|
+
|
|
557
|
+
### Amp
|
|
558
|
+
|
|
559
|
+
[Amp MCP docs](https://ampcode.com/manual#mcp)
|
|
116
560
|
|
|
117
561
|
```sh
|
|
118
|
-
|
|
119
|
-
-- npx -y @crush-protocol/mcp-client \
|
|
120
|
-
--url https://mcp.crush-protocol.com/mcp
|
|
562
|
+
amp mcp add crush-protocol https://crush-mcp-ats.dev.xexlab.com/mcp
|
|
121
563
|
```
|
|
122
564
|
|
|
123
|
-
|
|
565
|
+
---
|
|
124
566
|
|
|
125
|
-
###
|
|
567
|
+
### Zed
|
|
126
568
|
|
|
127
|
-
|
|
569
|
+
[Zed Context Server docs](https://zed.dev/docs/assistant/context-servers)
|
|
570
|
+
|
|
571
|
+
Add to `settings.json`:
|
|
128
572
|
|
|
129
573
|
```json
|
|
130
574
|
{
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
"CRUSH_MCP_SERVER_URL": "https://mcp.crush-protocol.com/mcp"
|
|
137
|
-
}
|
|
138
|
-
}
|
|
575
|
+
"context_servers": {
|
|
576
|
+
"crush-protocol": {
|
|
577
|
+
"source": "custom",
|
|
578
|
+
"command": "npx",
|
|
579
|
+
"args": ["-y", "@crush-protocol/mcp-client"]
|
|
139
580
|
}
|
|
581
|
+
}
|
|
140
582
|
}
|
|
141
583
|
```
|
|
142
584
|
|
|
143
|
-
|
|
585
|
+
---
|
|
144
586
|
|
|
145
|
-
|
|
587
|
+
### JetBrains AI Assistant
|
|
588
|
+
|
|
589
|
+
[JetBrains AI Assistant docs](https://www.jetbrains.com/help/ai-assistant/configure-an-mcp-server.html)
|
|
590
|
+
|
|
591
|
+
Go to `Settings` → `Tools` → `AI Assistant` → `Model Context Protocol (MCP)` → `+ Add`
|
|
592
|
+
|
|
593
|
+
#### Remote Server Connection
|
|
146
594
|
|
|
147
595
|
```json
|
|
148
596
|
{
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
"args": ["-y", "@crush-protocol/mcp-client"],
|
|
153
|
-
"env": {
|
|
154
|
-
"CRUSH_MCP_SERVER_URL": "https://mcp.crush-protocol.com/mcp"
|
|
155
|
-
}
|
|
156
|
-
}
|
|
597
|
+
"mcpServers": {
|
|
598
|
+
"crush-protocol": {
|
|
599
|
+
"url": "https://crush-mcp-ats.dev.xexlab.com/mcp"
|
|
157
600
|
}
|
|
601
|
+
}
|
|
158
602
|
}
|
|
159
603
|
```
|
|
160
604
|
|
|
161
|
-
|
|
605
|
+
#### Local Server Connection
|
|
162
606
|
|
|
163
|
-
|
|
607
|
+
```json
|
|
608
|
+
{
|
|
609
|
+
"mcpServers": {
|
|
610
|
+
"crush-protocol": {
|
|
611
|
+
"command": "npx",
|
|
612
|
+
"args": ["-y", "@crush-protocol/mcp-client"]
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
```
|
|
617
|
+
|
|
618
|
+
---
|
|
164
619
|
|
|
165
|
-
|
|
620
|
+
### Qwen Code
|
|
166
621
|
|
|
167
|
-
|
|
168
|
-
2. Let the client attempt `/mcp`
|
|
169
|
-
3. When the server returns `401` with `WWW-Authenticate`, start OAuth discovery
|
|
170
|
-
4. Complete Authorization Code + PKCE in the browser
|
|
171
|
-
5. Persist tokens locally and reconnect
|
|
622
|
+
[Qwen Code MCP docs](https://qwenlm.github.io/qwen-code-docs/en/users/features/mcp/)
|
|
172
623
|
|
|
173
|
-
|
|
624
|
+
#### Using CLI
|
|
174
625
|
|
|
175
626
|
```sh
|
|
176
|
-
crush-
|
|
627
|
+
qwen mcp add crush-protocol npx -y @crush-protocol/mcp-client
|
|
177
628
|
```
|
|
178
629
|
|
|
179
|
-
|
|
630
|
+
#### Remote Server Connection
|
|
180
631
|
|
|
181
|
-
|
|
632
|
+
Add to `~/.qwen/settings.json`:
|
|
182
633
|
|
|
183
|
-
|
|
634
|
+
```json
|
|
635
|
+
{
|
|
636
|
+
"mcpServers": {
|
|
637
|
+
"crush-protocol": {
|
|
638
|
+
"httpUrl": "https://crush-mcp-ats.dev.xexlab.com/mcp"
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
```
|
|
184
643
|
|
|
185
|
-
|
|
186
|
-
2. The MCP server returns OAuth discovery hints when auth is required
|
|
187
|
-
3. The client dynamically registers, runs Authorization Code + PKCE, and persists credentials locally
|
|
188
|
-
4. Authorization codes, access tokens, and refresh tokens are all managed server-side under the OAuth data model
|
|
644
|
+
#### Local Server Connection
|
|
189
645
|
|
|
190
|
-
|
|
646
|
+
```json
|
|
647
|
+
{
|
|
648
|
+
"mcpServers": {
|
|
649
|
+
"crush-protocol": {
|
|
650
|
+
"command": "npx",
|
|
651
|
+
"args": ["-y", "@crush-protocol/mcp-client"]
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
```
|
|
191
656
|
|
|
192
657
|
---
|
|
193
658
|
|
|
194
|
-
|
|
659
|
+
### LM Studio
|
|
660
|
+
|
|
661
|
+
[LM Studio MCP Support](https://lmstudio.ai/blog/lmstudio-v0.3.17)
|
|
662
|
+
|
|
663
|
+
Navigate `Program` → `Install` → `Edit mcp.json`:
|
|
664
|
+
|
|
665
|
+
```json
|
|
666
|
+
{
|
|
667
|
+
"mcpServers": {
|
|
668
|
+
"crush-protocol": {
|
|
669
|
+
"command": "npx",
|
|
670
|
+
"args": ["-y", "@crush-protocol/mcp-client"]
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
```
|
|
675
|
+
|
|
676
|
+
---
|
|
677
|
+
|
|
678
|
+
### Visual Studio 2022
|
|
195
679
|
|
|
196
|
-
|
|
197
|
-
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
198
|
-
| **Signal Discovery** | `get_signal_metadata`, `get_signals_by_category` |
|
|
199
|
-
| **Backtest** | `get_backtest_config_schema`, `get_available_tokens`, `validate_expression`, `create_backtest`, `list_backtests` |
|
|
200
|
-
| **Market Data** | `list_tables`, `list_tokens`, `list_indicators`, `list_timeframes`, `get_data_range`, `check_query_size`, `fetch_ohlcv`, `fetch_indicator`, `get_connection_config` |
|
|
201
|
-
| **Custom Indicators** | `save_custom_indicator`, `list_custom_indicators`, `get_custom_indicator`, `delete_custom_indicator` |
|
|
202
|
-
| **Strategy Management** | `create_strategy`, `list_strategies`, `get_strategy`, `update_strategy`, `delete_strategy`, `toggle_strategy`, `get_strategy_logs` |
|
|
203
|
-
| **Trading** | `place_order`, `get_positions`, `get_account_info`, `get_portfolio` |
|
|
204
|
-
| **Market Intelligence** | `search_tokens`, `get_token_info`, `get_trending_tokens`, `get_alpha_feed`, `get_token_feed`, `fetch_news` |
|
|
680
|
+
[Visual Studio MCP docs](https://learn.microsoft.com/visualstudio/ide/mcp-servers?view=vs-2022)
|
|
205
681
|
|
|
206
|
-
|
|
682
|
+
#### Remote Server Connection
|
|
683
|
+
|
|
684
|
+
```json
|
|
685
|
+
{
|
|
686
|
+
"inputs": [],
|
|
687
|
+
"servers": {
|
|
688
|
+
"crush-protocol": {
|
|
689
|
+
"type": "http",
|
|
690
|
+
"url": "https://crush-mcp-ats.dev.xexlab.com/mcp"
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
```
|
|
695
|
+
|
|
696
|
+
#### Local Server Connection
|
|
697
|
+
|
|
698
|
+
```json
|
|
699
|
+
{
|
|
700
|
+
"mcp": {
|
|
701
|
+
"servers": {
|
|
702
|
+
"crush-protocol": {
|
|
703
|
+
"type": "stdio",
|
|
704
|
+
"command": "npx",
|
|
705
|
+
"args": ["-y", "@crush-protocol/mcp-client"]
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
```
|
|
711
|
+
|
|
712
|
+
---
|
|
713
|
+
|
|
714
|
+
### BoltAI
|
|
715
|
+
|
|
716
|
+
[BoltAI docs](https://docs.boltai.com/docs/plugins/mcp-servers)
|
|
717
|
+
|
|
718
|
+
```json
|
|
719
|
+
{
|
|
720
|
+
"mcpServers": {
|
|
721
|
+
"crush-protocol": {
|
|
722
|
+
"command": "npx",
|
|
723
|
+
"args": ["-y", "@crush-protocol/mcp-client"]
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
```
|
|
207
728
|
|
|
208
729
|
---
|
|
209
730
|
|
|
210
|
-
|
|
731
|
+
### Perplexity Desktop
|
|
211
732
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
733
|
+
[Perplexity MCP docs](https://www.perplexity.ai/help-center/en/articles/11502712-local-and-remote-mcps-for-perplexity)
|
|
734
|
+
|
|
735
|
+
Navigate `Perplexity` → `Settings` → `Connectors` → `Add Connector` → `Advanced`
|
|
736
|
+
|
|
737
|
+
Server Name: `crush-protocol`
|
|
738
|
+
|
|
739
|
+
```json
|
|
740
|
+
{
|
|
741
|
+
"args": ["-y", "@crush-protocol/mcp-client"],
|
|
742
|
+
"command": "npx",
|
|
743
|
+
"env": {}
|
|
744
|
+
}
|
|
745
|
+
```
|
|
216
746
|
|
|
217
747
|
---
|
|
218
748
|
|
|
219
|
-
|
|
749
|
+
### Kilo Code
|
|
220
750
|
|
|
221
|
-
|
|
751
|
+
[Kilo Code docs](https://kilocode.ai)
|
|
222
752
|
|
|
223
|
-
|
|
224
|
-
import { OAuthRemoteMcpClient, BacktestClient } from '@crush-protocol/mcp-client'
|
|
753
|
+
#### Remote Server Connection
|
|
225
754
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
755
|
+
```json
|
|
756
|
+
{
|
|
757
|
+
"mcpServers": {
|
|
758
|
+
"crush-protocol": {
|
|
759
|
+
"type": "streamable-http",
|
|
760
|
+
"url": "https://crush-mcp-ats.dev.xexlab.com/mcp"
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
```
|
|
230
765
|
|
|
231
|
-
|
|
232
|
-
const bt = await backtest.createBacktest({
|
|
233
|
-
config: {
|
|
234
|
-
/* ... */
|
|
235
|
-
},
|
|
236
|
-
})
|
|
237
|
-
const result = await backtest.list({ limit: 10 })
|
|
766
|
+
#### Local Server Connection
|
|
238
767
|
|
|
239
|
-
|
|
768
|
+
```json
|
|
769
|
+
{
|
|
770
|
+
"mcpServers": {
|
|
771
|
+
"crush-protocol": {
|
|
772
|
+
"command": "npx",
|
|
773
|
+
"args": ["-y", "@crush-protocol/mcp-client"]
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
```
|
|
778
|
+
|
|
779
|
+
---
|
|
780
|
+
|
|
781
|
+
### Zencoder
|
|
782
|
+
|
|
783
|
+
1. Go to Zencoder menu → Agent tools → Add custom MCP
|
|
784
|
+
2. Paste:
|
|
785
|
+
|
|
786
|
+
```json
|
|
787
|
+
{
|
|
788
|
+
"command": "npx",
|
|
789
|
+
"args": ["-y", "@crush-protocol/mcp-client"]
|
|
790
|
+
}
|
|
240
791
|
```
|
|
241
792
|
|
|
242
793
|
---
|
|
243
794
|
|
|
795
|
+
### Qodo Gen
|
|
796
|
+
|
|
797
|
+
[Qodo Gen docs](https://docs.qodo.ai/qodo-documentation/qodo-gen/qodo-gen-chat/agentic-mode/agentic-tools-mcps)
|
|
798
|
+
|
|
799
|
+
Open Qodo Gen chat → Connect more tools → `+ Add new MCP`:
|
|
800
|
+
|
|
801
|
+
#### Remote Server Connection
|
|
802
|
+
|
|
803
|
+
```json
|
|
804
|
+
{
|
|
805
|
+
"mcpServers": {
|
|
806
|
+
"crush-protocol": {
|
|
807
|
+
"url": "https://crush-mcp-ats.dev.xexlab.com/mcp"
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
```
|
|
812
|
+
|
|
813
|
+
#### Local Server Connection
|
|
814
|
+
|
|
815
|
+
```json
|
|
816
|
+
{
|
|
817
|
+
"mcpServers": {
|
|
818
|
+
"crush-protocol": {
|
|
819
|
+
"command": "npx",
|
|
820
|
+
"args": ["-y", "@crush-protocol/mcp-client"]
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
```
|
|
825
|
+
|
|
826
|
+
---
|
|
827
|
+
|
|
828
|
+
### Using Bun or Deno
|
|
829
|
+
|
|
830
|
+
#### Bun
|
|
831
|
+
|
|
832
|
+
```json
|
|
833
|
+
{
|
|
834
|
+
"mcpServers": {
|
|
835
|
+
"crush-protocol": {
|
|
836
|
+
"command": "bunx",
|
|
837
|
+
"args": ["-y", "@crush-protocol/mcp-client"]
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
```
|
|
842
|
+
|
|
843
|
+
#### Deno
|
|
844
|
+
|
|
845
|
+
```json
|
|
846
|
+
{
|
|
847
|
+
"mcpServers": {
|
|
848
|
+
"crush-protocol": {
|
|
849
|
+
"command": "deno",
|
|
850
|
+
"args": [
|
|
851
|
+
"run",
|
|
852
|
+
"--allow-env",
|
|
853
|
+
"--allow-net",
|
|
854
|
+
"--allow-read",
|
|
855
|
+
"--allow-write",
|
|
856
|
+
"npm:@crush-protocol/mcp-client"
|
|
857
|
+
]
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
```
|
|
862
|
+
|
|
863
|
+
---
|
|
864
|
+
|
|
865
|
+
### Windows
|
|
866
|
+
|
|
867
|
+
Use `cmd` as the command wrapper:
|
|
868
|
+
|
|
869
|
+
```json
|
|
870
|
+
{
|
|
871
|
+
"mcpServers": {
|
|
872
|
+
"crush-protocol": {
|
|
873
|
+
"command": "cmd",
|
|
874
|
+
"args": ["/c", "npx", "-y", "@crush-protocol/mcp-client"]
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
```
|
|
879
|
+
|
|
880
|
+
## CLI Usage
|
|
881
|
+
|
|
882
|
+
```sh
|
|
883
|
+
npx -y @crush-protocol/mcp-client login # 预授权 OAuth(浏览器登录)
|
|
884
|
+
npx -y @crush-protocol/mcp-client setup --all # 写入所有客户端配置
|
|
885
|
+
npx -y @crush-protocol/mcp-client tools:list # 列出可用工具
|
|
886
|
+
npx -y @crush-protocol/mcp-client ping # 测试连通性
|
|
887
|
+
npx -y @crush-protocol/mcp-client backtest:schema # 获取回测配置 schema
|
|
888
|
+
npx -y @crush-protocol/mcp-client backtest:list --limit 10
|
|
889
|
+
```
|
|
890
|
+
|
|
244
891
|
## License
|
|
245
892
|
|
|
246
893
|
MIT
|
|
@@ -5,10 +5,10 @@ import { OAuthRemoteMcpClient } from "../mcp/oauthRemoteClient.js";
|
|
|
5
5
|
* E2E 测试:验证 MCP client 能成功连接服务端并调用工具。
|
|
6
6
|
*
|
|
7
7
|
* 前置条件(通过环境变量或 .env.e2e 配置):
|
|
8
|
-
* CRUSH_MCP_SERVER_URL — 指向运行中的 MCP server(默认
|
|
8
|
+
* CRUSH_MCP_SERVER_URL — 指向运行中的 MCP server(默认 https://crush-mcp-ats.dev.xexlab.com/mcp)
|
|
9
9
|
* CRUSH_OAUTH_ACCESS_TOKEN — 有效的 OAuth access token
|
|
10
10
|
*/
|
|
11
|
-
const serverUrl = process.env.CRUSH_MCP_SERVER_URL ?? "
|
|
11
|
+
const serverUrl = process.env.CRUSH_MCP_SERVER_URL ?? "https://crush-mcp-ats.dev.xexlab.com/mcp";
|
|
12
12
|
const token = process.env.CRUSH_OAUTH_ACCESS_TOKEN ?? "";
|
|
13
13
|
// 没有 token 时跳过所有 e2e 测试
|
|
14
14
|
const describeE2E = token ? describe : describe.skip;
|
package/dist/cli.js
CHANGED
|
@@ -4,8 +4,10 @@ import { BacktestClient } from "./backtest/backtestClient.js";
|
|
|
4
4
|
import { ClickHouseDirectClient } from "./clickhouse/directClient.js";
|
|
5
5
|
import { OAuthRemoteMcpClient } from "./mcp/oauthRemoteClient.js";
|
|
6
6
|
import { RemoteMcpClient } from "./mcp/remoteClient.js";
|
|
7
|
+
import { ALL_TARGETS, installClientConfig } from "./setup/setupClients.js";
|
|
8
|
+
const MCP_SERVER_URL = "https://crush-mcp-ats.dev.xexlab.com/mcp";
|
|
7
9
|
const printUsage = () => {
|
|
8
|
-
console.log(`\ncrush-mcp-client\n\nGeneral:\n login [--
|
|
10
|
+
console.log(`\ncrush-mcp-client\n\nGeneral:\n login\n setup [--cursor] [--claude] [--codex] [--gemini] [--opencode] [--all] [--scope user|project]\n tools:list [--token TOKEN]\n tool:call --name TOOL_NAME [--args JSON] [--token TOKEN]\n ping [--token TOKEN]\n\nBacktest:\n backtest:schema [--token TOKEN]\n backtest:tokens [--platform PLATFORM] [--token TOKEN]\n backtest:validate --expression JSON [--data-source kline|factors] [--token TOKEN]\n backtest:create --config JSON [--backtest-id ID] [--token TOKEN]\n backtest:list [--status STATUS] [--limit N] [--offset N] [--token TOKEN]\n\nClickHouse:\n clickhouse:list-tables [--ch-host HOST --ch-port PORT --ch-user USER --ch-password PASS --ch-database DB]\n clickhouse:query --sql SQL [--ch-host HOST --ch-port PORT --ch-user USER --ch-password PASS --ch-database DB --ch-row-cap N]\n\nAuth:\n --token TOKEN uses a provided OAuth access token.\n Without --token, OAuth runs automatically in the browser when needed.\n\nEnv:\n CRUSH_OAUTH_ACCESS_TOKEN\n CH_HOST, CH_PORT, CH_USER, CH_PASSWORD, CH_DATABASE, CH_ROW_CAP\n`);
|
|
9
11
|
};
|
|
10
12
|
const parseFlags = (args) => {
|
|
11
13
|
const flags = {};
|
|
@@ -30,9 +32,13 @@ const requireString = (value, message) => {
|
|
|
30
32
|
}
|
|
31
33
|
return value;
|
|
32
34
|
};
|
|
33
|
-
const getServerUrl = (
|
|
34
|
-
|
|
35
|
-
|
|
35
|
+
const getServerUrl = () => MCP_SERVER_URL;
|
|
36
|
+
const getSetupTargets = (flags) => {
|
|
37
|
+
if (flags.all === true) {
|
|
38
|
+
return [...ALL_TARGETS];
|
|
39
|
+
}
|
|
40
|
+
return ALL_TARGETS.filter((target) => flags[target] === true);
|
|
41
|
+
};
|
|
36
42
|
/**
|
|
37
43
|
* 创建 MCP 客户端(统一认证入口)
|
|
38
44
|
*
|
|
@@ -45,7 +51,7 @@ const getServerUrl = (flags) => typeof flags.url === "string"
|
|
|
45
51
|
* - 无 token → 自动拉起浏览器登录
|
|
46
52
|
*/
|
|
47
53
|
const createSmartClient = (flags) => {
|
|
48
|
-
const serverUrl = getServerUrl(
|
|
54
|
+
const serverUrl = getServerUrl();
|
|
49
55
|
// 显式传了 token → 用简单客户端
|
|
50
56
|
const explicitToken = typeof flags.token === "string" ? flags.token : process.env.CRUSH_OAUTH_ACCESS_TOKEN || "";
|
|
51
57
|
if (explicitToken) {
|
|
@@ -107,7 +113,7 @@ const run = async () => {
|
|
|
107
113
|
const flags = parseFlags(rest);
|
|
108
114
|
switch (command) {
|
|
109
115
|
case "login": {
|
|
110
|
-
const serverUrl = getServerUrl(
|
|
116
|
+
const serverUrl = getServerUrl();
|
|
111
117
|
const client = new OAuthRemoteMcpClient({ serverUrl });
|
|
112
118
|
try {
|
|
113
119
|
await client.ensureAuthorized();
|
|
@@ -118,6 +124,22 @@ const run = async () => {
|
|
|
118
124
|
}
|
|
119
125
|
return;
|
|
120
126
|
}
|
|
127
|
+
case "setup": {
|
|
128
|
+
const targets = getSetupTargets(flags);
|
|
129
|
+
if (targets.length === 0) {
|
|
130
|
+
throw new Error(`Specify at least one setup target: ${ALL_TARGETS.map((t) => "--" + t).join(", ")}, or --all`);
|
|
131
|
+
}
|
|
132
|
+
const rawScope = typeof flags.scope === "string" ? flags.scope : "user";
|
|
133
|
+
if (rawScope !== "user" && rawScope !== "project") {
|
|
134
|
+
throw new Error("Invalid --scope. Expected 'user' or 'project'.");
|
|
135
|
+
}
|
|
136
|
+
const scope = rawScope;
|
|
137
|
+
for (const target of targets) {
|
|
138
|
+
const location = installClientConfig(target, scope);
|
|
139
|
+
console.log(`[setup] ${target}: configured (${location})`);
|
|
140
|
+
}
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
121
143
|
case "tools:list": {
|
|
122
144
|
const client = await connectClient(flags);
|
|
123
145
|
try {
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export type SetupTarget = "cursor" | "claude" | "codex" | "gemini" | "opencode" | "vscode" | "windsurf" | "claude-desktop" | "warp";
|
|
2
|
+
export type SetupScope = "user" | "project";
|
|
3
|
+
export declare const ALL_TARGETS: readonly SetupTarget[];
|
|
4
|
+
export declare const installClientConfig: (target: SetupTarget, scope: SetupScope) => string;
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
const SERVER_NAME = "crush-protocol";
|
|
6
|
+
const PACKAGE_NAME = "@crush-protocol/mcp-client";
|
|
7
|
+
const REMOTE_URL = "https://crush-mcp-ats.dev.xexlab.com/mcp";
|
|
8
|
+
export const ALL_TARGETS = [
|
|
9
|
+
"cursor",
|
|
10
|
+
"claude",
|
|
11
|
+
"codex",
|
|
12
|
+
"gemini",
|
|
13
|
+
"opencode",
|
|
14
|
+
"vscode",
|
|
15
|
+
"windsurf",
|
|
16
|
+
"claude-desktop",
|
|
17
|
+
"warp",
|
|
18
|
+
];
|
|
19
|
+
const ensureDir = (filePath) => {
|
|
20
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
21
|
+
};
|
|
22
|
+
const readJson = (filePath) => {
|
|
23
|
+
if (!fs.existsSync(filePath))
|
|
24
|
+
return {};
|
|
25
|
+
try {
|
|
26
|
+
return JSON.parse(fs.readFileSync(filePath, "utf8"));
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
throw new Error(`Failed to parse JSON config at ${filePath}: ${error.message}`);
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
const writeJson = (filePath, value) => {
|
|
33
|
+
ensureDir(filePath);
|
|
34
|
+
fs.writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\n`, "utf8");
|
|
35
|
+
};
|
|
36
|
+
const createNpxConfig = () => ({
|
|
37
|
+
command: "npx",
|
|
38
|
+
args: ["-y", PACKAGE_NAME],
|
|
39
|
+
});
|
|
40
|
+
// ─── Cursor ─────────────────────────────────────────────
|
|
41
|
+
const getCursorConfigPath = (scope) => scope === "project"
|
|
42
|
+
? path.join(process.cwd(), ".cursor", "mcp.json")
|
|
43
|
+
: path.join(os.homedir(), ".cursor", "mcp.json");
|
|
44
|
+
const installCursor = (scope) => {
|
|
45
|
+
const filePath = getCursorConfigPath(scope);
|
|
46
|
+
const config = readJson(filePath);
|
|
47
|
+
const mcpServers = (config.mcpServers ?? {});
|
|
48
|
+
mcpServers[SERVER_NAME] = createNpxConfig();
|
|
49
|
+
config.mcpServers = mcpServers;
|
|
50
|
+
writeJson(filePath, config);
|
|
51
|
+
return filePath;
|
|
52
|
+
};
|
|
53
|
+
// ─── Gemini CLI ─────────────────────────────────────────
|
|
54
|
+
const getGeminiConfigPath = () => path.join(os.homedir(), ".gemini", "settings.json");
|
|
55
|
+
const installGemini = () => {
|
|
56
|
+
const filePath = getGeminiConfigPath();
|
|
57
|
+
const config = readJson(filePath);
|
|
58
|
+
const mcpServers = (config.mcpServers ?? {});
|
|
59
|
+
mcpServers[SERVER_NAME] = createNpxConfig();
|
|
60
|
+
config.mcpServers = mcpServers;
|
|
61
|
+
writeJson(filePath, config);
|
|
62
|
+
return filePath;
|
|
63
|
+
};
|
|
64
|
+
// ─── OpenCode ───────────────────────────────────────────
|
|
65
|
+
const getOpenCodeConfigPath = (scope) => scope === "project"
|
|
66
|
+
? path.join(process.cwd(), "opencode.json")
|
|
67
|
+
: path.join(os.homedir(), ".config", "opencode", "opencode.json");
|
|
68
|
+
const installOpenCode = (scope) => {
|
|
69
|
+
const filePath = getOpenCodeConfigPath(scope);
|
|
70
|
+
const config = readJson(filePath);
|
|
71
|
+
const mcp = (config.mcp ?? {});
|
|
72
|
+
if (typeof config.$schema !== "string") {
|
|
73
|
+
config.$schema = "https://opencode.ai/config.json";
|
|
74
|
+
}
|
|
75
|
+
mcp[SERVER_NAME] = {
|
|
76
|
+
type: "local",
|
|
77
|
+
command: ["npx", "-y", PACKAGE_NAME],
|
|
78
|
+
enabled: true,
|
|
79
|
+
};
|
|
80
|
+
config.mcp = mcp;
|
|
81
|
+
writeJson(filePath, config);
|
|
82
|
+
return filePath;
|
|
83
|
+
};
|
|
84
|
+
// ─── OpenAI Codex ───────────────────────────────────────
|
|
85
|
+
const getCodexConfigPath = () => path.join(os.homedir(), ".codex", "config.toml");
|
|
86
|
+
const installCodex = () => {
|
|
87
|
+
const filePath = getCodexConfigPath();
|
|
88
|
+
const section = `[mcp_servers.${SERVER_NAME}]
|
|
89
|
+
command = "npx"
|
|
90
|
+
args = ["-y", "${PACKAGE_NAME}"]
|
|
91
|
+
startup_timeout_ms = 20000
|
|
92
|
+
`;
|
|
93
|
+
ensureDir(filePath);
|
|
94
|
+
const existing = fs.existsSync(filePath) ? fs.readFileSync(filePath, "utf8") : "";
|
|
95
|
+
if (!existing.includes(`[mcp_servers.${SERVER_NAME}]`)) {
|
|
96
|
+
const next = existing.trim().length > 0 ? `${existing.trimEnd()}\n\n${section}` : section;
|
|
97
|
+
fs.writeFileSync(filePath, next, "utf8");
|
|
98
|
+
}
|
|
99
|
+
return filePath;
|
|
100
|
+
};
|
|
101
|
+
// ─── Claude Code CLI ────────────────────────────────────
|
|
102
|
+
const installClaude = (scope) => {
|
|
103
|
+
const configJson = JSON.stringify({
|
|
104
|
+
type: "stdio",
|
|
105
|
+
command: "npx",
|
|
106
|
+
args: ["-y", PACKAGE_NAME],
|
|
107
|
+
});
|
|
108
|
+
const result = spawnSync("claude", ["mcp", "add-json", "--scope", scope, SERVER_NAME, configJson], {
|
|
109
|
+
stdio: "pipe",
|
|
110
|
+
encoding: "utf8",
|
|
111
|
+
});
|
|
112
|
+
if (result.error) {
|
|
113
|
+
throw new Error(`Failed to run Claude CLI: ${result.error.message}`);
|
|
114
|
+
}
|
|
115
|
+
if (result.status !== 0) {
|
|
116
|
+
const output = [result.stdout, result.stderr].filter(Boolean).join("\n").trim();
|
|
117
|
+
throw new Error(output || "Claude CLI returned a non-zero exit code.");
|
|
118
|
+
}
|
|
119
|
+
return "claude-managed-config";
|
|
120
|
+
};
|
|
121
|
+
// ─── VS Code ────────────────────────────────────────────
|
|
122
|
+
const getVSCodeConfigPath = (scope) => scope === "project"
|
|
123
|
+
? path.join(process.cwd(), ".vscode", "mcp.json")
|
|
124
|
+
: path.join(os.homedir(), ".vscode", "mcp.json");
|
|
125
|
+
const installVSCode = (scope) => {
|
|
126
|
+
const filePath = getVSCodeConfigPath(scope);
|
|
127
|
+
const config = readJson(filePath);
|
|
128
|
+
const servers = (config.servers ?? {});
|
|
129
|
+
servers[SERVER_NAME] = {
|
|
130
|
+
type: "stdio",
|
|
131
|
+
command: "npx",
|
|
132
|
+
args: ["-y", PACKAGE_NAME],
|
|
133
|
+
};
|
|
134
|
+
config.servers = servers;
|
|
135
|
+
writeJson(filePath, config);
|
|
136
|
+
return filePath;
|
|
137
|
+
};
|
|
138
|
+
// ─── Windsurf ───────────────────────────────────────────
|
|
139
|
+
const getWindsurfConfigPath = () => path.join(os.homedir(), ".codeium", "windsurf", "mcp_config.json");
|
|
140
|
+
const installWindsurf = () => {
|
|
141
|
+
const filePath = getWindsurfConfigPath();
|
|
142
|
+
const config = readJson(filePath);
|
|
143
|
+
const mcpServers = (config.mcpServers ?? {});
|
|
144
|
+
mcpServers[SERVER_NAME] = createNpxConfig();
|
|
145
|
+
config.mcpServers = mcpServers;
|
|
146
|
+
writeJson(filePath, config);
|
|
147
|
+
return filePath;
|
|
148
|
+
};
|
|
149
|
+
// ─── Claude Desktop ─────────────────────────────────────
|
|
150
|
+
const getClaudeDesktopConfigPath = () => {
|
|
151
|
+
const platform = os.platform();
|
|
152
|
+
if (platform === "darwin") {
|
|
153
|
+
return path.join(os.homedir(), "Library", "Application Support", "Claude", "claude_desktop_config.json");
|
|
154
|
+
}
|
|
155
|
+
if (platform === "win32") {
|
|
156
|
+
return path.join(process.env.APPDATA ?? path.join(os.homedir(), "AppData", "Roaming"), "Claude", "claude_desktop_config.json");
|
|
157
|
+
}
|
|
158
|
+
// Linux
|
|
159
|
+
return path.join(os.homedir(), ".config", "Claude", "claude_desktop_config.json");
|
|
160
|
+
};
|
|
161
|
+
const installClaudeDesktop = () => {
|
|
162
|
+
const filePath = getClaudeDesktopConfigPath();
|
|
163
|
+
const config = readJson(filePath);
|
|
164
|
+
const mcpServers = (config.mcpServers ?? {});
|
|
165
|
+
mcpServers[SERVER_NAME] = createNpxConfig();
|
|
166
|
+
config.mcpServers = mcpServers;
|
|
167
|
+
writeJson(filePath, config);
|
|
168
|
+
return filePath;
|
|
169
|
+
};
|
|
170
|
+
// ─── Warp ───────────────────────────────────────────────
|
|
171
|
+
const getWarpConfigPath = () => path.join(os.homedir(), ".warp", "mcp_config.json");
|
|
172
|
+
const installWarp = () => {
|
|
173
|
+
const filePath = getWarpConfigPath();
|
|
174
|
+
const config = readJson(filePath);
|
|
175
|
+
config[SERVER_NAME] = {
|
|
176
|
+
command: "npx",
|
|
177
|
+
args: ["-y", PACKAGE_NAME],
|
|
178
|
+
env: {},
|
|
179
|
+
working_directory: null,
|
|
180
|
+
start_on_launch: true,
|
|
181
|
+
};
|
|
182
|
+
writeJson(filePath, config);
|
|
183
|
+
return filePath;
|
|
184
|
+
};
|
|
185
|
+
// ─── Router ─────────────────────────────────────────────
|
|
186
|
+
export const installClientConfig = (target, scope) => {
|
|
187
|
+
switch (target) {
|
|
188
|
+
case "cursor":
|
|
189
|
+
return installCursor(scope);
|
|
190
|
+
case "claude":
|
|
191
|
+
return installClaude(scope);
|
|
192
|
+
case "codex":
|
|
193
|
+
return installCodex();
|
|
194
|
+
case "gemini":
|
|
195
|
+
return installGemini();
|
|
196
|
+
case "opencode":
|
|
197
|
+
return installOpenCode(scope);
|
|
198
|
+
case "vscode":
|
|
199
|
+
return installVSCode(scope);
|
|
200
|
+
case "windsurf":
|
|
201
|
+
return installWindsurf();
|
|
202
|
+
case "claude-desktop":
|
|
203
|
+
return installClaudeDesktop();
|
|
204
|
+
case "warp":
|
|
205
|
+
return installWarp();
|
|
206
|
+
default:
|
|
207
|
+
throw new Error(`Unsupported setup target: ${target}`);
|
|
208
|
+
}
|
|
209
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crush-protocol/mcp-client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Crush MCP npm client package (remote Streamable HTTP + optional ClickHouse direct)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
27
27
|
"dotenv": "^17.2.1",
|
|
28
28
|
"zod": "^3.25.76",
|
|
29
|
-
"@crush-protocol/mcp-contracts": "0.1.
|
|
29
|
+
"@crush-protocol/mcp-contracts": "0.1.2"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@types/node": "^24.3.0",
|