@myatkyawthu/mcp-connect 0.2.1 → 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 +319 -95
- package/package.json +7 -11
- package/src/cli.js +41 -4
- package/src/defineMCP.js +3 -1
- package/src/index.js +2 -0
- package/src/server/dashboard.js +212 -0
- package/src/server/mcpServer.js +449 -68
- package/src/server/relay.js +162 -0
- package/src/utils/configLoader.js +96 -0
- package/src/utils/configValidation.js +3 -3
- package/src/utils/crypto.js +57 -0
- package/src/utils/validation.js +3 -3
package/README.md
CHANGED
|
@@ -1,170 +1,394 @@
|
|
|
1
1
|
# mcp-connect
|
|
2
2
|
|
|
3
|
-
> Dead simple MCP
|
|
3
|
+
> Dead simple MCP server framework. Define your tools as async functions — it handles the protocol, transport, security, and dashboard.
|
|
4
4
|
|
|
5
|
-
[](https://www.npmjs.com/package/@myatkyawthu/mcp-connect)
|
|
6
6
|
[](https://opensource.org/licenses/MIT)
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
### Step 1: Install mcp-connect
|
|
11
|
-
|
|
12
|
-
```bash
|
|
13
|
-
npm install -g @myatkyawthu/mcp-connect
|
|
14
|
-
```
|
|
15
|
-
### Step 2: Create mcp.config.js
|
|
8
|
+
---
|
|
16
9
|
|
|
17
|
-
|
|
10
|
+
## What is this?
|
|
18
11
|
|
|
19
|
-
|
|
20
|
-
# Navigate to your project directory
|
|
21
|
-
cd your-project
|
|
12
|
+
**Model Context Protocol (MCP)** is the standard way AI tools (Claude, Cursor, Cline, etc.) call your app's functions. Think of it like a plugin system — any MCP-compatible AI can discover and call your tools.
|
|
22
13
|
|
|
23
|
-
|
|
24
|
-
mcp-connect init
|
|
25
|
-
```
|
|
14
|
+
`mcp-connect` removes all the boilerplate. You write async functions. It handles the rest: JSON-RPC wiring, transport, schema advertisement, rate limiting, auth, error handling, and a live inspector dashboard.
|
|
26
15
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
```javascript
|
|
16
|
+
```js
|
|
30
17
|
import { defineMCP } from "@myatkyawthu/mcp-connect";
|
|
31
18
|
|
|
32
19
|
export default defineMCP({
|
|
33
|
-
name: "
|
|
20
|
+
name: "my-server",
|
|
34
21
|
version: "1.0.0",
|
|
35
22
|
tools: [
|
|
36
23
|
["hello", async ({ name = "World" }) => `Hello ${name}!`],
|
|
37
|
-
|
|
24
|
+
{
|
|
25
|
+
name: "echo",
|
|
26
|
+
description: "Echo back the input",
|
|
27
|
+
schema: {
|
|
28
|
+
type: "object",
|
|
29
|
+
properties: { message: { type: "string" } },
|
|
30
|
+
required: ["message"]
|
|
31
|
+
},
|
|
32
|
+
handler: async ({ message }) => `Echo: ${message}`
|
|
33
|
+
}
|
|
38
34
|
]
|
|
39
35
|
});
|
|
40
36
|
```
|
|
41
|
-
### Step 3: Test Locally
|
|
42
37
|
|
|
43
|
-
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Install
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
# Global CLI (recommended)
|
|
44
|
+
npm install -g @myatkyawthu/mcp-connect
|
|
45
|
+
|
|
46
|
+
# Or as a project dependency
|
|
47
|
+
npm install @myatkyawthu/mcp-connect
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Requires **Node.js 18+**.
|
|
44
51
|
|
|
45
|
-
|
|
46
|
-
- **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
|
|
47
|
-
- **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
52
|
+
---
|
|
48
53
|
|
|
49
|
-
|
|
54
|
+
## Quick Start
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
# 1. Create a config file
|
|
58
|
+
mcp-connect init
|
|
59
|
+
|
|
60
|
+
# 2. Edit mcp.config.js and add your tools
|
|
61
|
+
|
|
62
|
+
# 3. Run it
|
|
63
|
+
mcp-connect # STDIO mode (for Claude Desktop)
|
|
64
|
+
mcp-connect --port 3000 # SSE/HTTP mode (for web clients, IDEs)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Three Modes — Pick One
|
|
70
|
+
|
|
71
|
+
### Mode 1 — STDIO (Local, for Claude Desktop)
|
|
72
|
+
|
|
73
|
+
Your AI tool spawns the process. Communication happens via stdin/stdout pipes. No port, no HTTP.
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
mcp-connect mcp.config.js
|
|
77
|
+
```
|
|
50
78
|
|
|
79
|
+
**Claude Desktop config** (`~/Library/Application Support/Claude/claude_desktop_config.json`):
|
|
51
80
|
```json
|
|
52
81
|
{
|
|
53
82
|
"mcpServers": {
|
|
54
83
|
"my-app": {
|
|
55
84
|
"command": "mcp-connect",
|
|
56
|
-
"args": ["
|
|
85
|
+
"args": ["/absolute/path/to/mcp.config.js"]
|
|
57
86
|
}
|
|
58
87
|
}
|
|
59
88
|
}
|
|
60
89
|
```
|
|
61
90
|
|
|
62
|
-
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
### Mode 2 — SSE / HTTP (Deployed on a Server)
|
|
94
|
+
|
|
95
|
+
Starts an HTTP server. AI clients connect to `/sse` and send requests to `/message`. **This is the mode for deploying on a VPS or cloud** so any client can reach it over the internet.
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
mcp-connect mcp.config.js --port 3000
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Once deployed behind HTTPS, clients connect to:
|
|
102
|
+
```
|
|
103
|
+
https://yourserver.com/sse
|
|
104
|
+
```
|
|
63
105
|
|
|
64
|
-
|
|
106
|
+
**Client compatibility:**
|
|
65
107
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
108
|
+
| Client | SSE Support |
|
|
109
|
+
| :--- | :---: |
|
|
110
|
+
| Claude.ai (web) | ✅ |
|
|
111
|
+
| Cursor | ✅ |
|
|
112
|
+
| Cline (VS Code) | ✅ |
|
|
113
|
+
| Windsurf | ✅ |
|
|
114
|
+
| Continue.dev | ✅ |
|
|
115
|
+
| Zed | ✅ |
|
|
116
|
+
| Claude Desktop | ❌ (STDIO only) |
|
|
69
117
|
|
|
70
|
-
|
|
118
|
+
**Endpoints exposed:**
|
|
119
|
+
|
|
120
|
+
| Endpoint | Description |
|
|
121
|
+
| :--- | :--- |
|
|
122
|
+
| `GET /sse` | AI client connects here (long-lived SSE stream) |
|
|
123
|
+
| `POST /message` | AI client sends JSON-RPC requests |
|
|
124
|
+
| `GET /health` | JSON health check with tool list |
|
|
125
|
+
| `GET /` | Live inspector dashboard |
|
|
71
126
|
|
|
72
127
|
---
|
|
73
128
|
|
|
74
|
-
|
|
129
|
+
### Mode 3 — Tunnel (Behind NAT, No Open Port)
|
|
130
|
+
|
|
131
|
+
If your machine can't receive inbound connections (home laptop, office network), use the tunnel. Run a tiny relay on any $5/month VPS — your local machine connects outbound to it. Remote clients hit the VPS and get proxied to your machine.
|
|
132
|
+
|
|
133
|
+
**Step 1 — Start the relay on your VPS (one-time setup):**
|
|
134
|
+
```bash
|
|
135
|
+
mcp-connect relay --port 4000
|
|
136
|
+
```
|
|
75
137
|
|
|
76
|
-
|
|
138
|
+
**Step 2 — Start your server on your local machine:**
|
|
139
|
+
```bash
|
|
140
|
+
mcp-connect mcp.config.js --port 3111 --tunnel
|
|
141
|
+
```
|
|
77
142
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
143
|
+
Your terminal will print:
|
|
144
|
+
```
|
|
145
|
+
MCP Tunnel bridge active!
|
|
146
|
+
Remote SSE endpoint: http://your-vps.com/t/<tunnelId>/sse
|
|
81
147
|
```
|
|
82
|
-
## 🔧 CLI Usage
|
|
83
148
|
|
|
84
|
-
|
|
149
|
+
Share that URL with any MCP client. Done.
|
|
85
150
|
|
|
86
|
-
|
|
151
|
+
> The relay auto-reconnects if the tunnel drops. All payloads can be AES-256-GCM encrypted end-to-end (see Security section below).
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## Tool Definition Formats
|
|
156
|
+
|
|
157
|
+
### Short format (tuple)
|
|
158
|
+
For simple one-liner tools:
|
|
159
|
+
```js
|
|
160
|
+
["toolName", async (args) => result]
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Full format (object)
|
|
164
|
+
For tools that need schema validation, descriptions, or a security confirmation gate:
|
|
165
|
+
```js
|
|
87
166
|
{
|
|
88
|
-
name: "
|
|
89
|
-
description: "
|
|
167
|
+
name: "delete_record",
|
|
168
|
+
description: "Permanently delete a record by ID",
|
|
90
169
|
schema: {
|
|
91
170
|
type: "object",
|
|
92
171
|
properties: {
|
|
93
|
-
|
|
172
|
+
id: { type: "string", description: "Record ID to delete" }
|
|
94
173
|
},
|
|
95
|
-
required: ["
|
|
174
|
+
required: ["id"]
|
|
96
175
|
},
|
|
97
|
-
|
|
176
|
+
confirm: true, // asks "y/N?" in terminal before executing
|
|
177
|
+
handler: async ({ id }) => {
|
|
178
|
+
await db.delete(id);
|
|
179
|
+
return `Deleted ${id}`;
|
|
180
|
+
}
|
|
98
181
|
}
|
|
99
182
|
```
|
|
100
183
|
|
|
101
|
-
|
|
184
|
+
The AI receives the schema and knows exactly what arguments to pass. You don't have to document it separately.
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## Security
|
|
189
|
+
|
|
190
|
+
All security features are optional — enable only what you need.
|
|
191
|
+
|
|
192
|
+
### Bearer Token Auth
|
|
193
|
+
|
|
194
|
+
Protect the `/sse` and `/message` endpoints. Any request without the correct token gets a `401`.
|
|
102
195
|
|
|
103
196
|
```bash
|
|
104
|
-
#
|
|
105
|
-
|
|
197
|
+
# Set via environment variable
|
|
198
|
+
MCP_TUNNEL_TOKEN=my-secret-token mcp-connect mcp.config.js --port 3000
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Or in config:
|
|
202
|
+
```js
|
|
203
|
+
server: {
|
|
204
|
+
tunnel: { token: "my-secret-token" }
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
Clients must send: `Authorization: Bearer my-secret-token`
|
|
106
209
|
|
|
107
|
-
|
|
108
|
-
mcp-connect /path/to/your/mcp.config.js
|
|
210
|
+
---
|
|
109
211
|
|
|
110
|
-
|
|
111
|
-
npm run format
|
|
212
|
+
### CORS Origin Allowlist
|
|
112
213
|
|
|
113
|
-
|
|
114
|
-
|
|
214
|
+
Restrict which origins can connect. Without this, all origins are allowed (`*`).
|
|
215
|
+
|
|
216
|
+
```js
|
|
217
|
+
server: {
|
|
218
|
+
cors: {
|
|
219
|
+
origins: ["https://claude.ai", "https://cursor.sh"]
|
|
220
|
+
}
|
|
221
|
+
}
|
|
115
222
|
```
|
|
116
223
|
|
|
117
|
-
|
|
224
|
+
Requests from unlisted origins get `403 Origin not allowed`.
|
|
118
225
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
### End-to-End Encryption (Tunnel mode)
|
|
229
|
+
|
|
230
|
+
Encrypt all payloads over the tunnel so the relay server only sees ciphertext. Uses AES-256-GCM.
|
|
231
|
+
|
|
232
|
+
```js
|
|
233
|
+
server: {
|
|
234
|
+
tunnel: {
|
|
235
|
+
encryptionKey: "my-32-char-passphrase-or-64hex"
|
|
236
|
+
}
|
|
237
|
+
}
|
|
123
238
|
```
|
|
124
239
|
|
|
125
|
-
|
|
126
|
-
1. Check config file path is absolute
|
|
127
|
-
2. Restart Claude Desktop completely
|
|
128
|
-
3. Check Claude Desktop logs for errors
|
|
240
|
+
The relay cannot read your tool calls or responses even if it's compromised.
|
|
129
241
|
|
|
130
|
-
|
|
131
|
-
1. Verify tool syntax in `mcp.config.js`
|
|
132
|
-
2. Check server logs for errors
|
|
133
|
-
3. Test with simple tools first
|
|
242
|
+
---
|
|
134
243
|
|
|
135
|
-
|
|
244
|
+
### Confirm Gate for Dangerous Tools
|
|
136
245
|
|
|
137
|
-
|
|
138
|
-
```javascript
|
|
139
|
-
["readFile", async ({ path }) => {
|
|
140
|
-
const fs = await import('fs/promises');
|
|
141
|
-
return await fs.readFile(path, 'utf8');
|
|
142
|
-
}]
|
|
246
|
+
Add `confirm: true` to any tool. Before it runs, the terminal prompts you:
|
|
143
247
|
```
|
|
248
|
+
⚠️ [MCP SECURITY] Allow tool "delete_record" execution? (y/N):
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
The tool only runs if you type `y`. Otherwise it's rejected with an error.
|
|
144
252
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
## Built-in Protections (Always On)
|
|
256
|
+
|
|
257
|
+
These run automatically without any config:
|
|
258
|
+
|
|
259
|
+
| Protection | Detail |
|
|
260
|
+
| :--- | :--- |
|
|
261
|
+
| **Rate limiting** | 100 requests/minute per server |
|
|
262
|
+
| **Tool timeout** | 30 seconds max per tool call |
|
|
263
|
+
| **Response size cap** | 1MB max, truncated if exceeded |
|
|
264
|
+
| **Error sanitization** | Stack traces stripped before returning to AI |
|
|
265
|
+
| **Circular reference guard** | Safe JSON serialization |
|
|
266
|
+
|
|
267
|
+
---
|
|
268
|
+
|
|
269
|
+
## Inspector Dashboard
|
|
270
|
+
|
|
271
|
+
Available at `http://localhost:<port>/` whenever running in SSE mode.
|
|
272
|
+
|
|
273
|
+
- **Logs tab** — live feed of every tool call with timestamp, duration, pass/fail status. Click any row to see full request args and response.
|
|
274
|
+
- **Test Tool tab** — pick a tool, fill in args as JSON, hit Execute. See the response immediately. No AI client needed for debugging.
|
|
275
|
+
|
|
276
|
+
The dashboard connects to `/api/events` over SSE — it updates in real-time without refreshing.
|
|
277
|
+
|
|
278
|
+
---
|
|
279
|
+
|
|
280
|
+
## Full Config Reference
|
|
281
|
+
|
|
282
|
+
```js
|
|
283
|
+
import { defineMCP } from "@myatkyawthu/mcp-connect";
|
|
284
|
+
|
|
285
|
+
export default defineMCP({
|
|
286
|
+
name: "my-server", // required
|
|
287
|
+
version: "1.0.0", // required
|
|
288
|
+
description: "...", // optional
|
|
289
|
+
|
|
290
|
+
server: {
|
|
291
|
+
port: 3000, // optional — same as --port flag
|
|
292
|
+
|
|
293
|
+
cors: {
|
|
294
|
+
origins: [ // optional — allowlist of origins
|
|
295
|
+
"https://claude.ai",
|
|
296
|
+
"http://localhost:5173"
|
|
297
|
+
]
|
|
298
|
+
},
|
|
299
|
+
|
|
300
|
+
tunnel: {
|
|
301
|
+
enabled: true, // optional — same as --tunnel flag
|
|
302
|
+
relayUrl: "http://your-vps.com:4000", // relay address
|
|
303
|
+
token: "secret", // bearer token for auth
|
|
304
|
+
encryptionKey: "..." // AES-256-GCM key (passphrase or 64-char hex)
|
|
305
|
+
}
|
|
306
|
+
},
|
|
307
|
+
|
|
308
|
+
tools: [
|
|
309
|
+
// Short format
|
|
310
|
+
["hello", async ({ name = "World" }) => `Hello ${name}!`],
|
|
311
|
+
|
|
312
|
+
// Full format
|
|
313
|
+
{
|
|
314
|
+
name: "echo",
|
|
315
|
+
description: "Echo back the input",
|
|
316
|
+
schema: {
|
|
317
|
+
type: "object",
|
|
318
|
+
properties: {
|
|
319
|
+
message: { type: "string" }
|
|
320
|
+
},
|
|
321
|
+
required: ["message"]
|
|
322
|
+
},
|
|
323
|
+
handler: async ({ message }) => `Echo: ${message}`
|
|
324
|
+
},
|
|
325
|
+
|
|
326
|
+
// Dangerous tool with confirmation gate
|
|
327
|
+
{
|
|
328
|
+
name: "delete_all",
|
|
329
|
+
description: "Wipe everything",
|
|
330
|
+
confirm: true,
|
|
331
|
+
handler: async () => {
|
|
332
|
+
await nuke();
|
|
333
|
+
return "Done.";
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
]
|
|
337
|
+
});
|
|
151
338
|
```
|
|
152
339
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
340
|
+
---
|
|
341
|
+
|
|
342
|
+
## CLI Reference
|
|
343
|
+
|
|
344
|
+
```bash
|
|
345
|
+
mcp-connect init # Scaffold mcp.config.js in current directory
|
|
346
|
+
mcp-connect [config.js] # Start in STDIO mode
|
|
347
|
+
mcp-connect [config.js] --port <port> # Start in SSE/HTTP mode
|
|
348
|
+
mcp-connect [config.js] --tunnel # Start with outbound tunnel
|
|
349
|
+
mcp-connect relay --port <port> # Run a relay gateway (deploy on VPS)
|
|
159
350
|
```
|
|
160
351
|
|
|
161
|
-
|
|
352
|
+
Config file defaults to `mcp.config.js` in the current directory if not specified.
|
|
162
353
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
354
|
+
---
|
|
355
|
+
|
|
356
|
+
## Deployment Recipes
|
|
357
|
+
|
|
358
|
+
### Deploy on Railway / Render / Fly.io
|
|
359
|
+
|
|
360
|
+
1. Push your repo with `mcp.config.js`
|
|
361
|
+
2. Set start command: `mcp-connect mcp.config.js --port 3000`
|
|
362
|
+
3. Set env var: `MCP_TUNNEL_TOKEN=your-secret`
|
|
363
|
+
4. Add your domain/URL to your AI client as the MCP server URL: `https://yourapp.railway.app/sse`
|
|
364
|
+
|
|
365
|
+
### Self-hosted VPS (nginx + HTTPS)
|
|
366
|
+
|
|
367
|
+
```nginx
|
|
368
|
+
location / {
|
|
369
|
+
proxy_pass http://localhost:3000;
|
|
370
|
+
proxy_http_version 1.1;
|
|
371
|
+
proxy_set_header Connection ''; # keep SSE alive
|
|
372
|
+
proxy_buffering off; # required for SSE streaming
|
|
373
|
+
proxy_cache off;
|
|
374
|
+
proxy_set_header Host $host;
|
|
375
|
+
}
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
Then run: `mcp-connect mcp.config.js --port 3000`
|
|
379
|
+
|
|
380
|
+
### Laptop behind NAT (tunnel setup)
|
|
381
|
+
|
|
382
|
+
```bash
|
|
383
|
+
# On VPS
|
|
384
|
+
mcp-connect relay --port 4000
|
|
385
|
+
|
|
386
|
+
# On laptop
|
|
387
|
+
MCP_TUNNEL_TOKEN=secret mcp-connect mcp.config.js --port 3111 --tunnel
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
---
|
|
167
391
|
|
|
168
|
-
##
|
|
392
|
+
## License
|
|
169
393
|
|
|
170
394
|
MIT © [myat-kyaw-thu](https://github.com/myat-kyaw-thu)
|
package/package.json
CHANGED
|
@@ -1,18 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@myatkyawthu/mcp-connect",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Dead simple MCP (Model Context Protocol) server for exposing your app functions to AI agents",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.js",
|
|
7
|
-
"module": "./src/index.js",
|
|
8
7
|
"exports": {
|
|
9
|
-
".":
|
|
10
|
-
"import": "./src/index.js",
|
|
11
|
-
"require": "./src/index.js"
|
|
12
|
-
}
|
|
8
|
+
".": "./src/index.js"
|
|
13
9
|
},
|
|
14
10
|
"bin": {
|
|
15
|
-
"mcp-connect": "src/cli.js"
|
|
11
|
+
"mcp-connect": "./src/cli.js"
|
|
16
12
|
},
|
|
17
13
|
"files": [
|
|
18
14
|
"src",
|
|
@@ -23,7 +19,7 @@
|
|
|
23
19
|
"start": "node src/cli.js",
|
|
24
20
|
"dev": "nodemon src/cli.js",
|
|
25
21
|
"test": "node --test",
|
|
26
|
-
"test:unit": "node --test tests/unit",
|
|
22
|
+
"test:unit": "node --test tests/unit/*.test.js",
|
|
27
23
|
"test:integration": "node --test tests/integration",
|
|
28
24
|
"lint": "eslint src/",
|
|
29
25
|
"format": "prettier --write src/"
|
|
@@ -53,11 +49,11 @@
|
|
|
53
49
|
"node": ">=18.0.0"
|
|
54
50
|
},
|
|
55
51
|
"dependencies": {
|
|
56
|
-
"@modelcontextprotocol/sdk": "^
|
|
52
|
+
"@modelcontextprotocol/sdk": "^1.29.0"
|
|
57
53
|
},
|
|
58
54
|
"devDependencies": {
|
|
59
|
-
"nodemon": "^3.0.0",
|
|
60
55
|
"eslint": "^8.0.0",
|
|
56
|
+
"nodemon": "^3.0.0",
|
|
61
57
|
"prettier": "^3.0.0"
|
|
62
58
|
}
|
|
63
|
-
}
|
|
59
|
+
}
|
package/src/cli.js
CHANGED
|
@@ -23,7 +23,7 @@ export default defineMCP({
|
|
|
23
23
|
tools: [
|
|
24
24
|
// Simple tuple format: [name, handler]
|
|
25
25
|
["hello", async ({ name = "World" }) => \`Hello \${name}!\`],
|
|
26
|
-
|
|
26
|
+
|
|
27
27
|
// Object format with schema validation
|
|
28
28
|
{
|
|
29
29
|
name: "echo",
|
|
@@ -72,10 +72,31 @@ async function main() {
|
|
|
72
72
|
return;
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
+
if (process.argv[2] === 'relay') {
|
|
76
|
+
const portIndex = process.argv.indexOf('--port');
|
|
77
|
+
const relayPort = portIndex !== -1 ? parseInt(process.argv[portIndex + 1], 10) : 4000;
|
|
78
|
+
const { MCPRelayServer } = await import('./server/relay.js');
|
|
79
|
+
const relay = new MCPRelayServer();
|
|
80
|
+
await relay.start(relayPort);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
75
84
|
console.error('Starting MCP-Connect CLI...');
|
|
76
85
|
|
|
77
|
-
|
|
86
|
+
// Parse --port flag
|
|
87
|
+
let port = null;
|
|
88
|
+
const portIndex = process.argv.indexOf('--port');
|
|
89
|
+
if (portIndex !== -1) {
|
|
90
|
+
port = parseInt(process.argv[portIndex + 1], 10);
|
|
91
|
+
if (!port || port < 1 || port > 65535) {
|
|
92
|
+
console.error('Invalid port. Usage: mcp-connect --port 3000');
|
|
93
|
+
process.exit(1);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Find config path (skip flags)
|
|
78
98
|
let configPath = null;
|
|
99
|
+
const configArg = process.argv.find((a, i) => i >= 2 && !a.startsWith('--') && process.argv[i - 1] !== '--port' && a !== 'relay');
|
|
79
100
|
|
|
80
101
|
if (configArg) {
|
|
81
102
|
const fullPath = resolve(configArg);
|
|
@@ -158,7 +179,7 @@ export default defineMCP({
|
|
|
158
179
|
error.message.includes('Cannot resolve') ||
|
|
159
180
|
error.message.includes('MODULE_NOT_FOUND')
|
|
160
181
|
) {
|
|
161
|
-
console.error(
|
|
182
|
+
console.error('Make sure \'@myatkyawthu/mcp-connect\' is installed: npm install mcp-connect');
|
|
162
183
|
} else if (error.message.includes('SyntaxError')) {
|
|
163
184
|
console.error('Config file has syntax errors. Check your JavaScript syntax.');
|
|
164
185
|
} else if (error.message.includes('ERR_MODULE_NOT_FOUND')) {
|
|
@@ -185,7 +206,23 @@ export default defineMCP({
|
|
|
185
206
|
}
|
|
186
207
|
|
|
187
208
|
const server = new MCPConnectServer(validatedConfig);
|
|
188
|
-
|
|
209
|
+
|
|
210
|
+
const finalPort = port || validatedConfig.server?.port;
|
|
211
|
+
const useSSE = !!finalPort || validatedConfig.server?.transport === 'sse' || validatedConfig.server?.transport === 'hybrid';
|
|
212
|
+
const useTunnel = process.argv.includes('--tunnel') || !!validatedConfig.server?.tunnel?.enabled;
|
|
213
|
+
const relayUrl = process.env.MCP_RELAY_URL || validatedConfig.server?.tunnel?.relayUrl || 'http://localhost:4000';
|
|
214
|
+
|
|
215
|
+
if (useSSE) {
|
|
216
|
+
await server.startSSE(finalPort || 3000);
|
|
217
|
+
} else {
|
|
218
|
+
await server.start();
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
if (useTunnel) {
|
|
222
|
+
server.startTunnel(relayUrl).catch((err) => {
|
|
223
|
+
console.error('Tunnel failed to start:', err.message);
|
|
224
|
+
});
|
|
225
|
+
}
|
|
189
226
|
|
|
190
227
|
process.on('SIGINT', async () => {
|
|
191
228
|
console.error('Shutting down...');
|
package/src/defineMCP.js
CHANGED
|
@@ -33,7 +33,7 @@ export function defineMCP(config) {
|
|
|
33
33
|
handler,
|
|
34
34
|
};
|
|
35
35
|
} else {
|
|
36
|
-
const { name, handler, description, schema } = tool;
|
|
36
|
+
const { name, handler, description, schema, confirm } = tool;
|
|
37
37
|
return {
|
|
38
38
|
name: name.trim(),
|
|
39
39
|
description: description || `Tool: ${name}`,
|
|
@@ -43,6 +43,7 @@ export function defineMCP(config) {
|
|
|
43
43
|
additionalProperties: true,
|
|
44
44
|
},
|
|
45
45
|
handler,
|
|
46
|
+
confirm: !!confirm,
|
|
46
47
|
};
|
|
47
48
|
}
|
|
48
49
|
});
|
|
@@ -51,6 +52,7 @@ export function defineMCP(config) {
|
|
|
51
52
|
name: config.name,
|
|
52
53
|
version: config.version,
|
|
53
54
|
description: config.description,
|
|
55
|
+
server: config.server || {},
|
|
54
56
|
tools: mcpTools,
|
|
55
57
|
};
|
|
56
58
|
}
|
package/src/index.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
export { defineMCP } from './defineMCP.js';
|
|
2
2
|
export { MCPConnectServer } from './server/mcpServer.js';
|
|
3
|
+
export { MCPRelayServer } from './server/relay.js';
|
|
4
|
+
export { encrypt, decrypt } from './utils/crypto.js';
|
|
3
5
|
export { isValidMCPConfig, isValidMCPTool, isValidToolDefinition } from './types/mcp.js';
|