@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 CHANGED
@@ -1,170 +1,394 @@
1
1
  # mcp-connect
2
2
 
3
- > Dead simple MCP (Model Context Protocol) server for exposing your app functions to AI agents
3
+ > Dead simple MCP server framework. Define your tools as async functions it handles the protocol, transport, security, and dashboard.
4
4
 
5
- [![npm version](https://badge.fury.io/js/mcp-connect.svg)](https://www.npmjs.com/package/mcp-connect)
5
+ [![npm version](https://img.shields.io/npm/v/@myatkyawthu/mcp-connect.svg)](https://www.npmjs.com/package/@myatkyawthu/mcp-connect)
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
7
 
8
- ## 🚀 Claude Desktop Setup (5 Minutes)
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
- ### Step 2: Create Your MCP Server
10
+ ## What is this?
18
11
 
19
- ```bash
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
- # Generate sample config
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
- This creates `mcp.config.js` with example tools:
28
-
29
- ```javascript
16
+ ```js
30
17
  import { defineMCP } from "@myatkyawthu/mcp-connect";
31
18
 
32
19
  export default defineMCP({
33
- name: "My MCP App",
20
+ name: "my-server",
34
21
  version: "1.0.0",
35
22
  tools: [
36
23
  ["hello", async ({ name = "World" }) => `Hello ${name}!`],
37
- ["echo", async ({ message }) => `Echo: ${message}`]
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
- ### Step 3: Configure Claude Desktop
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
- Open Claude Desktop config file:
46
- - **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
47
- - **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
52
+ ---
48
53
 
49
- Add your MCP server:
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": ["C:/full/path/to/your/mcp.config.js"]
85
+ "args": ["/absolute/path/to/mcp.config.js"]
57
86
  }
58
87
  }
59
88
  }
60
89
  ```
61
90
 
62
- **Important**: Use the full absolute path to your `mcp.config.js` file.
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
- ### Step 4: Start & Test
106
+ **Client compatibility:**
65
107
 
66
- 1. **Restart Claude Desktop** completely
67
- 2. **Test connection**: Ask Claude *"What tools do you have available?"*
68
- 3. **Use your tools**: Try *"Hello there!"* or *"Echo this message"*
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
- **Done!** Your functions are now available to Claude Desktop.
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
- ## 📖 Tool Definition Guide
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
- ### Simple Format (Recommended)
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
- ```javascript
79
- // Just name and function
80
- ["toolName", async (args) => "result"]
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
- ### Advanced Format (With Validation)
149
+ Share that URL with any MCP client. Done.
85
150
 
86
- ```javascript
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: "toolName",
89
- description: "What this tool does",
167
+ name: "delete_record",
168
+ description: "Permanently delete a record by ID",
90
169
  schema: {
91
170
  type: "object",
92
171
  properties: {
93
- param: { type: "string", description: "Parameter description" }
172
+ id: { type: "string", description: "Record ID to delete" }
94
173
  },
95
- required: ["param"]
174
+ required: ["id"]
96
175
  },
97
- handler: async ({ param }) => `Result: ${param}`
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
- ## 🛠 Development Commands
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
- # Start with auto-reload during development
105
- npm run dev
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
- # Start server with specific config file
108
- mcp-connect /path/to/your/mcp.config.js
210
+ ---
109
211
 
110
- # Format code
111
- npm run format
212
+ ### CORS Origin Allowlist
112
213
 
113
- # Lint code
114
- npm run lint
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
- ## 🔧 Troubleshooting
224
+ Requests from unlisted origins get `403 Origin not allowed`.
118
225
 
119
- ### Config File Not Found
120
- ```bash
121
- # Create sample config
122
- mcp-connect init
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
- ### Claude Desktop Not Connecting
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
- ### Tool Not Working
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
- ## 📋 Examples
244
+ ### Confirm Gate for Dangerous Tools
136
245
 
137
- ### File Operations
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
- ### API Calls
146
- ```javascript
147
- ["getWeather", async ({ city }) => {
148
- const response = await fetch(`https://api.weather.com/${city}`);
149
- return await response.json();
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
- ### Database Queries
154
- ```javascript
155
- ["getUser", async ({ id }) => {
156
- // Your database logic here
157
- return { id, name: "John Doe", email: "john@example.com" };
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
- ## 🌐 Other MCP Clients
352
+ Config file defaults to `mcp.config.js` in the current directory if not specified.
162
353
 
163
- Claude Desktop setup is covered above. Tutorials for other MCP clients coming soon:
164
- - VS Code extensions
165
- - Custom applications
166
- - Other AI platforms
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
- ## 📄 License
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.2.1",
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": "^0.5.0"
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
- const configArg = process.argv[2];
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("Make sure 'mcp-connect' is installed: npm install mcp-connect");
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
- await server.start();
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';