@meldocio/mcp-stdio-proxy 1.0.3 → 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 +156 -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,66 +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:
|
|
58
75
|
|
|
59
|
-
|
|
60
|
-
|
|
76
|
+
```bash
|
|
77
|
+
export MELDOC_TOKEN=your_token_here
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
For permanent setup (macOS/Linux):
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
echo 'export MELDOC_TOKEN=your_token_here' >> ~/.zshrc # or ~/.bashrc
|
|
84
|
+
source ~/.zshrc
|
|
85
|
+
```
|
|
61
86
|
|
|
62
|
-
|
|
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)
|
|
139
|
+
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | \
|
|
140
|
+
MELDOC_TOKEN=your_token_here npx @meldocio/mcp-stdio-proxy@latest
|
|
141
|
+
|
|
142
|
+
# Test with debug logging
|
|
91
143
|
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | \
|
|
92
|
-
|
|
93
|
-
MELDOC_API_URL=https://custom.api.example.com \
|
|
94
|
-
npx @meldocio/mcp-stdio-proxy
|
|
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
|
|
110
|
-
- ✅
|
|
162
|
+
- ✅ Custom error codes: `AUTH_REQUIRED`, `NOT_FOUND`, `RATE_LIMIT`
|
|
163
|
+
- ✅ Request timeout handling (25 seconds)
|
|
111
164
|
- ✅ Network error recovery
|
|
112
165
|
- ✅ Line-by-line processing for streaming
|
|
166
|
+
- ✅ Automatic support for all MCP tools (including `server_info`)
|
|
167
|
+
- ✅ Configurable logging levels (ERROR, WARN, INFO, DEBUG)
|
|
168
|
+
- ✅ Graceful shutdown on SIGINT/SIGTERM
|
|
169
|
+
- ✅ No required arguments at startup
|
|
113
170
|
|
|
114
171
|
## JSON-RPC Error Codes
|
|
115
172
|
|
|
116
|
-
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
|
|
117
176
|
|
|
118
177
|
- `-32700`: Parse error (invalid JSON)
|
|
119
178
|
- `-32600`: Invalid Request (malformed JSON-RPC)
|
|
@@ -122,11 +181,67 @@ The proxy uses standard JSON-RPC 2.0 error codes:
|
|
|
122
181
|
- `-32603`: Internal error (network errors, timeouts, etc.)
|
|
123
182
|
- `-32000`: Server error (HTTP 4xx/5xx responses)
|
|
124
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
|
+
|
|
196
|
+
## Available Tools
|
|
197
|
+
|
|
198
|
+
The proxy automatically supports all tools provided by the meldoc MCP API, including:
|
|
199
|
+
|
|
200
|
+
- **`server_info`** - Get information about the server configuration, available projects, and token capabilities
|
|
201
|
+
- **`docs_list`** - List available documentation
|
|
202
|
+
- **`docs_get`** - Get specific documentation content
|
|
203
|
+
- And other tools as provided by the API
|
|
204
|
+
|
|
205
|
+
### Example: Using `server_info`
|
|
206
|
+
|
|
207
|
+
You can get server information using the `server_info` tool:
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
echo '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"server_info","arguments":{}}}' | \
|
|
211
|
+
MELDOC_MCP_TOKEN=your_token_here npx @meldocio/mcp-stdio-proxy
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
The response includes:
|
|
215
|
+
|
|
216
|
+
- Server name (from token)
|
|
217
|
+
- Token description (if provided)
|
|
218
|
+
- Available projects with IDs, names, and aliases
|
|
219
|
+
- Token capabilities (read, update, create, delete)
|
|
220
|
+
- Usage hints
|
|
221
|
+
|
|
222
|
+
### Response Metadata
|
|
223
|
+
|
|
224
|
+
All tool responses now include a `_meta` field with contextual information:
|
|
225
|
+
|
|
226
|
+
```json
|
|
227
|
+
{
|
|
228
|
+
"items": [...],
|
|
229
|
+
"_meta": {
|
|
230
|
+
"server": "My Token",
|
|
231
|
+
"projects": ["Frontend Docs", "Backend API"],
|
|
232
|
+
"capabilities": ["read"],
|
|
233
|
+
"hint": "Read permission required for this operation"
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
This metadata helps AI assistants understand the context and limitations of the current token.
|
|
239
|
+
|
|
125
240
|
## Troubleshooting
|
|
126
241
|
|
|
127
|
-
### Error:
|
|
242
|
+
### Error: AUTH_REQUIRED - Meldoc token not found
|
|
128
243
|
|
|
129
|
-
**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.
|
|
130
245
|
|
|
131
246
|
### Connection timeout
|
|
132
247
|
|
|
@@ -157,15 +272,19 @@ curl https://api.meldoc.io/mcp/v1/rpc \
|
|
|
157
272
|
To debug issues, you can test the proxy directly:
|
|
158
273
|
|
|
159
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
|
+
|
|
160
279
|
# Test with a simple request
|
|
161
280
|
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | \
|
|
162
|
-
|
|
281
|
+
MELDOC_TOKEN=your_token npx @meldocio/mcp-stdio-proxy@latest
|
|
163
282
|
|
|
164
|
-
# Test with
|
|
283
|
+
# Test with debug logging
|
|
165
284
|
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | \
|
|
166
|
-
|
|
167
|
-
DEBUG
|
|
168
|
-
npx @meldocio/mcp-stdio-proxy
|
|
285
|
+
MELDOC_TOKEN=your_token \
|
|
286
|
+
LOG_LEVEL=DEBUG \
|
|
287
|
+
npx @meldocio/mcp-stdio-proxy@latest
|
|
169
288
|
```
|
|
170
289
|
|
|
171
290
|
## Development
|
|
@@ -201,8 +320,8 @@ npm publish --access public
|
|
|
201
320
|
|
|
202
321
|
## Requirements
|
|
203
322
|
|
|
204
|
-
- Node.js >=
|
|
205
|
-
- Valid meldoc MCP token
|
|
323
|
+
- Node.js >= 18.0.0
|
|
324
|
+
- Valid meldoc MCP token (required for tool calls, not for startup)
|
|
206
325
|
|
|
207
326
|
## License
|
|
208
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
|
+
}
|