@meldocio/mcp-stdio-proxy 1.0.4 → 1.0.5
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 +111 -37
- package/bin/meldoc-mcp-proxy.js +140 -16
- package/package.json +9 -21
package/README.md
CHANGED
|
@@ -6,17 +6,23 @@ MCP stdio proxy for meldoc - connects Claude Desktop to meldoc MCP API without r
|
|
|
6
6
|
|
|
7
7
|
This npm package provides a lightweight proxy that bridges JSON-RPC communication between Claude Desktop and the meldoc MCP API. It reads JSON-RPC requests from stdin and forwards them to the meldoc API over HTTP, then returns the responses via stdout.
|
|
8
8
|
|
|
9
|
+
The package follows MCP best practices:
|
|
10
|
+
|
|
11
|
+
- ✅ Pure stdio communication (no interactive prompts)
|
|
12
|
+
- ✅ All logs go to stderr (stdout is clean JSON-RPC only)
|
|
13
|
+
- ✅ No required arguments at startup
|
|
14
|
+
- ✅ Graceful error handling with proper JSON-RPC error codes
|
|
15
|
+
- ✅ Configurable logging levels
|
|
16
|
+
|
|
9
17
|
## Installation
|
|
10
18
|
|
|
11
|
-
|
|
19
|
+
### Using Claude Desktop MCP Command
|
|
12
20
|
|
|
13
21
|
```bash
|
|
14
|
-
|
|
22
|
+
claude mcp add meldoc npx @meldocio/mcp-stdio-proxy@latest
|
|
15
23
|
```
|
|
16
24
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
### Claude Desktop Configuration
|
|
25
|
+
### Manual Configuration
|
|
20
26
|
|
|
21
27
|
Add the following configuration to your `claude_desktop_config.json` file:
|
|
22
28
|
|
|
@@ -43,9 +49,9 @@ Add the following configuration to your `claude_desktop_config.json` file:
|
|
|
43
49
|
"mcpServers": {
|
|
44
50
|
"meldoc": {
|
|
45
51
|
"command": "npx",
|
|
46
|
-
"args": ["-y", "@meldocio/mcp-stdio-proxy"],
|
|
52
|
+
"args": ["-y", "@meldocio/mcp-stdio-proxy@latest"],
|
|
47
53
|
"env": {
|
|
48
|
-
"
|
|
54
|
+
"MELDOC_TOKEN": "your_token_here"
|
|
49
55
|
}
|
|
50
56
|
}
|
|
51
57
|
}
|
|
@@ -54,68 +60,119 @@ Add the following configuration to your `claude_desktop_config.json` file:
|
|
|
54
60
|
|
|
55
61
|
After adding the configuration, restart Claude Desktop.
|
|
56
62
|
|
|
57
|
-
|
|
63
|
+
## Authentication
|
|
64
|
+
|
|
65
|
+
Meldoc MCP requires an access token. The token is checked in this order:
|
|
66
|
+
|
|
67
|
+
1. `MELDOC_TOKEN` environment variable (recommended)
|
|
68
|
+
2. `MELDOC_MCP_TOKEN` environment variable (backward compatibility)
|
|
69
|
+
3. `~/.meldoc/config.json` file
|
|
70
|
+
4. If none found, tools will return an authentication error
|
|
71
|
+
|
|
72
|
+
### Option 1: Environment variable (recommended)
|
|
73
|
+
|
|
74
|
+
Set the token as an environment variable:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
export MELDOC_TOKEN=your_token_here
|
|
78
|
+
```
|
|
58
79
|
|
|
59
|
-
|
|
60
|
-
- **MELDOC_API_URL** (optional): Base URL for the meldoc API. Defaults to `https://api.meldoc.io`
|
|
80
|
+
For permanent setup (macOS/Linux):
|
|
61
81
|
|
|
62
|
-
|
|
82
|
+
```bash
|
|
83
|
+
echo 'export MELDOC_TOKEN=your_token_here' >> ~/.zshrc # or ~/.bashrc
|
|
84
|
+
source ~/.zshrc
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
For Claude Desktop, add it to your configuration:
|
|
63
88
|
|
|
64
89
|
```json
|
|
65
90
|
{
|
|
66
91
|
"mcpServers": {
|
|
67
92
|
"meldoc": {
|
|
68
93
|
"command": "npx",
|
|
69
|
-
"args": ["-y", "@meldocio/mcp-stdio-proxy"],
|
|
94
|
+
"args": ["-y", "@meldocio/mcp-stdio-proxy@latest"],
|
|
70
95
|
"env": {
|
|
71
|
-
"
|
|
72
|
-
"MELDOC_API_URL": "https://custom.api.example.com"
|
|
96
|
+
"MELDOC_TOKEN": "your_token_here"
|
|
73
97
|
}
|
|
74
98
|
}
|
|
75
99
|
}
|
|
76
100
|
}
|
|
77
101
|
```
|
|
78
102
|
|
|
79
|
-
###
|
|
103
|
+
### Option 2: Meldoc CLI
|
|
80
104
|
|
|
81
|
-
|
|
105
|
+
If you have the Meldoc CLI installed, run:
|
|
82
106
|
|
|
83
107
|
```bash
|
|
84
|
-
|
|
85
|
-
MELDOC_MCP_TOKEN=your_token_here npx @meldocio/mcp-stdio-proxy
|
|
108
|
+
meldoc auth login
|
|
86
109
|
```
|
|
87
110
|
|
|
88
|
-
|
|
111
|
+
This will store the token in `~/.meldoc/config.json`, which the MCP proxy will automatically use.
|
|
112
|
+
|
|
113
|
+
### Option 3: Manual config file
|
|
114
|
+
|
|
115
|
+
Create `~/.meldoc/config.json` manually:
|
|
116
|
+
|
|
117
|
+
```json
|
|
118
|
+
{
|
|
119
|
+
"token": "your_token_here"
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Environment Variables
|
|
124
|
+
|
|
125
|
+
- **MELDOC_TOKEN** (recommended): Your meldoc authentication token
|
|
126
|
+
- **MELDOC_MCP_TOKEN** (optional): Alternative token variable (for backward compatibility)
|
|
127
|
+
- **LOG_LEVEL** (optional): Logging level - `ERROR`, `WARN`, `INFO`, or `DEBUG` (default: `ERROR`)
|
|
128
|
+
|
|
129
|
+
### Command Line Testing
|
|
130
|
+
|
|
131
|
+
You can test the proxy directly from the command line:
|
|
89
132
|
|
|
90
133
|
```bash
|
|
134
|
+
# Test initialize (works without token)
|
|
135
|
+
echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"test","version":"1.0.0"}}}' | \
|
|
136
|
+
npx @meldocio/mcp-stdio-proxy@latest
|
|
137
|
+
|
|
138
|
+
# Test tools/list (requires token)
|
|
91
139
|
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | \
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
140
|
+
MELDOC_TOKEN=your_token_here npx @meldocio/mcp-stdio-proxy@latest
|
|
141
|
+
|
|
142
|
+
# Test with debug logging
|
|
143
|
+
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | \
|
|
144
|
+
MELDOC_TOKEN=your_token_here LOG_LEVEL=DEBUG npx @meldocio/mcp-stdio-proxy@latest
|
|
95
145
|
```
|
|
96
146
|
|
|
97
147
|
## How It Works
|
|
98
148
|
|
|
99
149
|
1. The proxy reads JSON-RPC requests from `stdin` (newline-delimited JSON)
|
|
100
|
-
2.
|
|
101
|
-
3.
|
|
102
|
-
4.
|
|
103
|
-
5.
|
|
150
|
+
2. Protocol methods (`initialize`, `ping`, `resources/list`) are handled locally
|
|
151
|
+
3. Tool requests are forwarded to `https://api.meldoc.io/mcp/v1/rpc`
|
|
152
|
+
4. The `Authorization: Bearer {token}` header is automatically added
|
|
153
|
+
5. Responses are written to `stdout` in JSON-RPC format (stdout is clean - only JSON-RPC)
|
|
154
|
+
6. All logs and diagnostics go to `stderr`
|
|
155
|
+
7. Errors are handled and returned as proper JSON-RPC error responses
|
|
104
156
|
|
|
105
157
|
### Supported Features
|
|
106
158
|
|
|
107
159
|
- ✅ JSON-RPC 2.0 protocol
|
|
108
160
|
- ✅ Single and batch requests
|
|
109
161
|
- ✅ Proper error handling with JSON-RPC error codes
|
|
162
|
+
- ✅ Custom error codes: `AUTH_REQUIRED`, `NOT_FOUND`, `RATE_LIMIT`
|
|
110
163
|
- ✅ Request timeout handling (25 seconds)
|
|
111
164
|
- ✅ Network error recovery
|
|
112
165
|
- ✅ Line-by-line processing for streaming
|
|
113
166
|
- ✅ Automatic support for all MCP tools (including `server_info`)
|
|
114
|
-
- ✅
|
|
167
|
+
- ✅ Configurable logging levels (ERROR, WARN, INFO, DEBUG)
|
|
168
|
+
- ✅ Graceful shutdown on SIGINT/SIGTERM
|
|
169
|
+
- ✅ No required arguments at startup
|
|
115
170
|
|
|
116
171
|
## JSON-RPC Error Codes
|
|
117
172
|
|
|
118
|
-
The proxy uses standard JSON-RPC 2.0 error codes:
|
|
173
|
+
The proxy uses standard JSON-RPC 2.0 error codes plus custom codes:
|
|
174
|
+
|
|
175
|
+
### Standard JSON-RPC 2.0 Codes
|
|
119
176
|
|
|
120
177
|
- `-32700`: Parse error (invalid JSON)
|
|
121
178
|
- `-32600`: Invalid Request (malformed JSON-RPC)
|
|
@@ -124,6 +181,18 @@ The proxy uses standard JSON-RPC 2.0 error codes:
|
|
|
124
181
|
- `-32603`: Internal error (network errors, timeouts, etc.)
|
|
125
182
|
- `-32000`: Server error (HTTP 4xx/5xx responses)
|
|
126
183
|
|
|
184
|
+
### Custom Error Codes
|
|
185
|
+
|
|
186
|
+
- `-32001`: Authentication required (`AUTH_REQUIRED`) - Token missing or invalid
|
|
187
|
+
- `-32002`: Not found (`NOT_FOUND`) - Resource not found
|
|
188
|
+
- `-32003`: Rate limit exceeded (`RATE_LIMIT`) - Too many requests
|
|
189
|
+
|
|
190
|
+
Error responses include:
|
|
191
|
+
|
|
192
|
+
- `code`: Error code
|
|
193
|
+
- `message`: Human-readable error message
|
|
194
|
+
- `data` (optional, DEBUG level only): Additional error details
|
|
195
|
+
|
|
127
196
|
## Available Tools
|
|
128
197
|
|
|
129
198
|
The proxy automatically supports all tools provided by the meldoc MCP API, including:
|
|
@@ -143,6 +212,7 @@ echo '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"server_inf
|
|
|
143
212
|
```
|
|
144
213
|
|
|
145
214
|
The response includes:
|
|
215
|
+
|
|
146
216
|
- Server name (from token)
|
|
147
217
|
- Token description (if provided)
|
|
148
218
|
- Available projects with IDs, names, and aliases
|
|
@@ -169,9 +239,9 @@ This metadata helps AI assistants understand the context and limitations of the
|
|
|
169
239
|
|
|
170
240
|
## Troubleshooting
|
|
171
241
|
|
|
172
|
-
### Error:
|
|
242
|
+
### Error: AUTH_REQUIRED - Meldoc token not found
|
|
173
243
|
|
|
174
|
-
**Solution:**
|
|
244
|
+
**Solution:** Set the `MELDOC_TOKEN` environment variable or run `meldoc auth login` to store the token in `~/.meldoc/config.json`. The token is checked when tools are called, not at startup.
|
|
175
245
|
|
|
176
246
|
### Connection timeout
|
|
177
247
|
|
|
@@ -202,15 +272,19 @@ curl https://api.meldoc.io/mcp/v1/rpc \
|
|
|
202
272
|
To debug issues, you can test the proxy directly:
|
|
203
273
|
|
|
204
274
|
```bash
|
|
275
|
+
# Test initialize (works without token)
|
|
276
|
+
echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"test","version":"1.0.0"}}}' | \
|
|
277
|
+
npx @meldocio/mcp-stdio-proxy@latest
|
|
278
|
+
|
|
205
279
|
# Test with a simple request
|
|
206
280
|
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | \
|
|
207
|
-
|
|
281
|
+
MELDOC_TOKEN=your_token npx @meldocio/mcp-stdio-proxy@latest
|
|
208
282
|
|
|
209
|
-
# Test with
|
|
283
|
+
# Test with debug logging
|
|
210
284
|
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | \
|
|
211
|
-
|
|
212
|
-
DEBUG
|
|
213
|
-
npx @meldocio/mcp-stdio-proxy
|
|
285
|
+
MELDOC_TOKEN=your_token \
|
|
286
|
+
LOG_LEVEL=DEBUG \
|
|
287
|
+
npx @meldocio/mcp-stdio-proxy@latest
|
|
214
288
|
```
|
|
215
289
|
|
|
216
290
|
## Development
|
|
@@ -246,8 +320,8 @@ npm publish --access public
|
|
|
246
320
|
|
|
247
321
|
## Requirements
|
|
248
322
|
|
|
249
|
-
- Node.js >=
|
|
250
|
-
- Valid meldoc MCP token
|
|
323
|
+
- Node.js >= 18.0.0
|
|
324
|
+
- Valid meldoc MCP token (required for tool calls, not for startup)
|
|
251
325
|
|
|
252
326
|
## License
|
|
253
327
|
|
package/bin/meldoc-mcp-proxy.js
CHANGED
|
@@ -3,6 +3,26 @@
|
|
|
3
3
|
const axios = require('axios');
|
|
4
4
|
const https = require('https');
|
|
5
5
|
const { URL } = require('url');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
|
|
9
|
+
// Get package info - try multiple paths for different installation scenarios
|
|
10
|
+
let pkg;
|
|
11
|
+
try {
|
|
12
|
+
// Try relative path first (development)
|
|
13
|
+
pkg = require('../package.json');
|
|
14
|
+
} catch (e) {
|
|
15
|
+
try {
|
|
16
|
+
// Try from node_modules (when installed)
|
|
17
|
+
pkg = require(path.join(__dirname, '../../package.json'));
|
|
18
|
+
} catch (e2) {
|
|
19
|
+
// Fallback to hardcoded values
|
|
20
|
+
pkg = {
|
|
21
|
+
name: '@meldocio/mcp-stdio-proxy',
|
|
22
|
+
version: '1.0.5'
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
}
|
|
6
26
|
|
|
7
27
|
// JSON-RPC error codes
|
|
8
28
|
const JSON_RPC_ERROR_CODES = {
|
|
@@ -14,16 +34,73 @@ const JSON_RPC_ERROR_CODES = {
|
|
|
14
34
|
SERVER_ERROR: -32000
|
|
15
35
|
};
|
|
16
36
|
|
|
37
|
+
// Custom error codes
|
|
38
|
+
const CUSTOM_ERROR_CODES = {
|
|
39
|
+
AUTH_REQUIRED: -32001,
|
|
40
|
+
NOT_FOUND: -32002,
|
|
41
|
+
RATE_LIMIT: -32003
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// Log levels
|
|
45
|
+
const LOG_LEVELS = {
|
|
46
|
+
ERROR: 0,
|
|
47
|
+
WARN: 1,
|
|
48
|
+
INFO: 2,
|
|
49
|
+
DEBUG: 3
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
// Get token from environment or config file
|
|
53
|
+
// Priority: 1) MELDOC_TOKEN env var, 2) ~/.meldoc/config.json
|
|
54
|
+
function getToken() {
|
|
55
|
+
// First, try environment variable (recommended)
|
|
56
|
+
if (process.env.MELDOC_TOKEN) {
|
|
57
|
+
return process.env.MELDOC_TOKEN;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Fallback: try MELDOC_MCP_TOKEN for backward compatibility
|
|
61
|
+
if (process.env.MELDOC_MCP_TOKEN) {
|
|
62
|
+
return process.env.MELDOC_MCP_TOKEN;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Then, try config file
|
|
66
|
+
try {
|
|
67
|
+
const os = require('os');
|
|
68
|
+
const configPath = path.join(os.homedir(), '.meldoc', 'config.json');
|
|
69
|
+
if (fs.existsSync(configPath)) {
|
|
70
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
71
|
+
if (config.token) {
|
|
72
|
+
return config.token;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
} catch (e) {
|
|
76
|
+
// Silently ignore config file errors
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
|
|
17
82
|
// Configuration
|
|
18
|
-
const token =
|
|
83
|
+
const token = getToken();
|
|
19
84
|
const apiUrl = process.env.MELDOC_API_URL || 'https://api.meldoc.io';
|
|
20
85
|
const rpcEndpoint = `${apiUrl}/mcp/v1/rpc`;
|
|
21
86
|
const REQUEST_TIMEOUT = 25000; // 25 seconds (less than Claude Desktop's 30s timeout)
|
|
87
|
+
const LOG_LEVEL = getLogLevel(process.env.LOG_LEVEL || 'ERROR');
|
|
22
88
|
|
|
23
|
-
//
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
89
|
+
// Get log level from environment
|
|
90
|
+
function getLogLevel(level) {
|
|
91
|
+
const upper = (level || '').toUpperCase();
|
|
92
|
+
return LOG_LEVELS[upper] !== undefined ? LOG_LEVELS[upper] : LOG_LEVELS.ERROR;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Logging function - all logs go to stderr
|
|
96
|
+
function log(level, message, ...args) {
|
|
97
|
+
if (LOG_LEVEL >= level) {
|
|
98
|
+
const prefix = `[${Object.keys(LOG_LEVELS)[level]}]`;
|
|
99
|
+
process.stderr.write(`${prefix} ${message}\n`);
|
|
100
|
+
if (args.length > 0 && LOG_LEVEL >= LOG_LEVELS.DEBUG) {
|
|
101
|
+
process.stderr.write(JSON.stringify(args, null, 2) + '\n');
|
|
102
|
+
}
|
|
103
|
+
}
|
|
27
104
|
}
|
|
28
105
|
|
|
29
106
|
// Buffer for incomplete lines
|
|
@@ -73,6 +150,23 @@ process.stdout.on('error', (error) => {
|
|
|
73
150
|
}
|
|
74
151
|
});
|
|
75
152
|
|
|
153
|
+
// Handle SIGINT/SIGTERM for graceful shutdown
|
|
154
|
+
let isShuttingDown = false;
|
|
155
|
+
function gracefulShutdown(signal) {
|
|
156
|
+
if (isShuttingDown) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
isShuttingDown = true;
|
|
160
|
+
log(LOG_LEVELS.INFO, `Received ${signal}, shutting down gracefully...`);
|
|
161
|
+
// Give a moment for any pending requests to complete
|
|
162
|
+
setTimeout(() => {
|
|
163
|
+
process.exit(0);
|
|
164
|
+
}, 100);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
process.on('SIGINT', () => gracefulShutdown('SIGINT'));
|
|
168
|
+
process.on('SIGTERM', () => gracefulShutdown('SIGTERM'));
|
|
169
|
+
|
|
76
170
|
/**
|
|
77
171
|
* Handle a single line from stdin
|
|
78
172
|
*/
|
|
@@ -90,7 +184,7 @@ function handleLine(line) {
|
|
|
90
184
|
// For parse errors, we can't reliably get the id, so we skip the response
|
|
91
185
|
// to avoid Zod validation errors in Claude Desktop (it doesn't accept id: null)
|
|
92
186
|
// This is acceptable per JSON-RPC spec - parse errors can be ignored if id is unknown
|
|
93
|
-
|
|
187
|
+
log(LOG_LEVELS.ERROR, `Parse error: ${parseError.message}`);
|
|
94
188
|
}
|
|
95
189
|
}
|
|
96
190
|
|
|
@@ -199,12 +293,13 @@ function handleInitialize(request) {
|
|
|
199
293
|
resources: {}
|
|
200
294
|
},
|
|
201
295
|
serverInfo: {
|
|
202
|
-
name:
|
|
203
|
-
version:
|
|
296
|
+
name: pkg.name,
|
|
297
|
+
version: pkg.version
|
|
204
298
|
}
|
|
205
299
|
}
|
|
206
300
|
};
|
|
207
301
|
|
|
302
|
+
log(LOG_LEVELS.DEBUG, 'Initialize request received');
|
|
208
303
|
process.stdout.write(JSON.stringify(response) + '\n');
|
|
209
304
|
if (process.stdout.isTTY) {
|
|
210
305
|
process.stdout.flush();
|
|
@@ -251,6 +346,13 @@ function handleResourcesList(request) {
|
|
|
251
346
|
* Forwards the request to the backend MCP API
|
|
252
347
|
*/
|
|
253
348
|
async function processSingleRequest(request) {
|
|
349
|
+
// Check token before making request
|
|
350
|
+
if (!token) {
|
|
351
|
+
sendError(request.id, CUSTOM_ERROR_CODES.AUTH_REQUIRED,
|
|
352
|
+
'Meldoc token not found. Set MELDOC_TOKEN environment variable or run: meldoc auth login');
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
|
|
254
356
|
try {
|
|
255
357
|
// Ensure request has jsonrpc field
|
|
256
358
|
const requestWithJsonRpc = {
|
|
@@ -258,12 +360,14 @@ async function processSingleRequest(request) {
|
|
|
258
360
|
jsonrpc: request.jsonrpc || '2.0'
|
|
259
361
|
};
|
|
260
362
|
|
|
363
|
+
log(LOG_LEVELS.DEBUG, `Forwarding request: ${request.method || 'unknown'}`);
|
|
364
|
+
|
|
261
365
|
// Make HTTP request to MCP API
|
|
262
366
|
const response = await axios.post(rpcEndpoint, requestWithJsonRpc, {
|
|
263
367
|
headers: {
|
|
264
368
|
'Authorization': `Bearer ${token}`,
|
|
265
369
|
'Content-Type': 'application/json',
|
|
266
|
-
'User-Agent':
|
|
370
|
+
'User-Agent': `${pkg.name}/${pkg.version}`
|
|
267
371
|
},
|
|
268
372
|
timeout: REQUEST_TIMEOUT,
|
|
269
373
|
validateStatus: (status) => status < 500, // Don't throw on 4xx errors
|
|
@@ -310,24 +414,39 @@ async function processSingleRequest(request) {
|
|
|
310
414
|
|
|
311
415
|
let errorCode = JSON_RPC_ERROR_CODES.SERVER_ERROR;
|
|
312
416
|
if (status === 401) {
|
|
313
|
-
errorCode =
|
|
417
|
+
errorCode = CUSTOM_ERROR_CODES.AUTH_REQUIRED;
|
|
314
418
|
} else if (status === 404) {
|
|
315
|
-
errorCode =
|
|
419
|
+
errorCode = CUSTOM_ERROR_CODES.NOT_FOUND;
|
|
420
|
+
} else if (status === 429) {
|
|
421
|
+
errorCode = CUSTOM_ERROR_CODES.RATE_LIMIT;
|
|
316
422
|
}
|
|
317
423
|
|
|
318
|
-
|
|
424
|
+
log(LOG_LEVELS.WARN, `HTTP error ${status}: ${errorMessage}`);
|
|
425
|
+
sendError(request.id, errorCode, errorMessage, {
|
|
426
|
+
status,
|
|
427
|
+
code: errorData?.error?.code || `HTTP_${status}`
|
|
428
|
+
});
|
|
319
429
|
} else if (error.request) {
|
|
320
430
|
// Request was made but no response received
|
|
431
|
+
log(LOG_LEVELS.ERROR, `Network error: ${error.message || 'No response from server'}`);
|
|
321
432
|
sendError(request.id, JSON_RPC_ERROR_CODES.INTERNAL_ERROR,
|
|
322
|
-
`Network error: ${error.message || 'No response from server'}
|
|
433
|
+
`Network error: ${error.message || 'No response from server'}`, {
|
|
434
|
+
code: 'NETWORK_ERROR'
|
|
435
|
+
});
|
|
323
436
|
} else if (error.code === 'ECONNABORTED') {
|
|
324
437
|
// Timeout
|
|
438
|
+
log(LOG_LEVELS.WARN, `Request timeout after ${REQUEST_TIMEOUT}ms`);
|
|
325
439
|
sendError(request.id, JSON_RPC_ERROR_CODES.INTERNAL_ERROR,
|
|
326
|
-
`Request timeout after ${REQUEST_TIMEOUT}ms
|
|
440
|
+
`Request timeout after ${REQUEST_TIMEOUT}ms`, {
|
|
441
|
+
code: 'TIMEOUT'
|
|
442
|
+
});
|
|
327
443
|
} else {
|
|
328
444
|
// Other errors
|
|
445
|
+
log(LOG_LEVELS.ERROR, `Internal error: ${error.message || 'Unknown error'}`);
|
|
329
446
|
sendError(request.id, JSON_RPC_ERROR_CODES.INTERNAL_ERROR,
|
|
330
|
-
`Internal error: ${error.message || 'Unknown error'}
|
|
447
|
+
`Internal error: ${error.message || 'Unknown error'}`, {
|
|
448
|
+
code: 'INTERNAL_ERROR'
|
|
449
|
+
});
|
|
331
450
|
}
|
|
332
451
|
}
|
|
333
452
|
}
|
|
@@ -335,7 +454,7 @@ async function processSingleRequest(request) {
|
|
|
335
454
|
/**
|
|
336
455
|
* Send JSON-RPC error response
|
|
337
456
|
*/
|
|
338
|
-
function sendError(id, code, message) {
|
|
457
|
+
function sendError(id, code, message, details) {
|
|
339
458
|
// Only send error response if id is defined (not for notifications)
|
|
340
459
|
// Claude Desktop's Zod schema doesn't accept null for id
|
|
341
460
|
if (id === undefined || id === null) {
|
|
@@ -353,6 +472,11 @@ function sendError(id, code, message) {
|
|
|
353
472
|
}
|
|
354
473
|
};
|
|
355
474
|
|
|
475
|
+
// Add details if provided (for debugging)
|
|
476
|
+
if (details && LOG_LEVEL >= LOG_LEVELS.DEBUG) {
|
|
477
|
+
errorResponse.error.data = details;
|
|
478
|
+
}
|
|
479
|
+
|
|
356
480
|
process.stdout.write(JSON.stringify(errorResponse) + '\n');
|
|
357
481
|
// Flush stdout to ensure data is sent immediately
|
|
358
482
|
if (process.stdout.isTTY) {
|
package/package.json
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@meldocio/mcp-stdio-proxy",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"description": "MCP stdio proxy for meldoc - connects Claude Desktop to meldoc MCP API",
|
|
5
|
-
"main": "bin/meldoc-mcp-proxy.js",
|
|
6
5
|
"bin": {
|
|
7
|
-
"meldoc-mcp
|
|
8
|
-
},
|
|
9
|
-
"scripts": {
|
|
10
|
-
"test": "jest",
|
|
11
|
-
"prepublishOnly": "npm test"
|
|
6
|
+
"meldoc-mcp": "bin/meldoc-mcp-proxy.js"
|
|
12
7
|
},
|
|
8
|
+
"files": [
|
|
9
|
+
"bin/**",
|
|
10
|
+
"README.md",
|
|
11
|
+
"LICENSE"
|
|
12
|
+
],
|
|
13
13
|
"engines": {
|
|
14
|
-
"node": ">=
|
|
14
|
+
"node": ">=18.0.0"
|
|
15
15
|
},
|
|
16
16
|
"keywords": [
|
|
17
17
|
"mcp",
|
|
@@ -33,17 +33,5 @@
|
|
|
33
33
|
"homepage": "https://github.com/meldoc/mcp-stdio-proxy#readme",
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"axios": "^1.6.0"
|
|
36
|
-
},
|
|
37
|
-
"devDependencies": {
|
|
38
|
-
"jest": "^29.7.0"
|
|
39
|
-
},
|
|
40
|
-
"jest": {
|
|
41
|
-
"testEnvironment": "node",
|
|
42
|
-
"testMatch": [
|
|
43
|
-
"**/__tests__/**/*.test.js"
|
|
44
|
-
],
|
|
45
|
-
"collectCoverageFrom": [
|
|
46
|
-
"bin/**/*.js"
|
|
47
|
-
]
|
|
48
36
|
}
|
|
49
|
-
}
|
|
37
|
+
}
|