@meldocio/mcp-stdio-proxy 1.0.0 → 1.0.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/bin/meldoc-mcp-proxy.js +54 -10
- package/package.json +2 -2
package/bin/meldoc-mcp-proxy.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
const axios = require('axios');
|
|
4
|
+
const https = require('https');
|
|
4
5
|
const { URL } = require('url');
|
|
5
6
|
|
|
6
7
|
// JSON-RPC error codes
|
|
@@ -40,8 +41,10 @@ process.stdin.on('data', (chunk) => {
|
|
|
40
41
|
|
|
41
42
|
// Process complete lines
|
|
42
43
|
for (const line of lines) {
|
|
43
|
-
|
|
44
|
-
|
|
44
|
+
const trimmed = line.trim();
|
|
45
|
+
// Skip empty lines but don't exit
|
|
46
|
+
if (trimmed) {
|
|
47
|
+
handleLine(trimmed);
|
|
45
48
|
}
|
|
46
49
|
}
|
|
47
50
|
});
|
|
@@ -52,18 +55,33 @@ process.stdin.on('end', () => {
|
|
|
52
55
|
if (buffer.trim()) {
|
|
53
56
|
handleLine(buffer.trim());
|
|
54
57
|
}
|
|
58
|
+
// Don't exit - Claude Desktop may reconnect
|
|
59
|
+
// The process will be terminated by Claude Desktop when needed
|
|
55
60
|
});
|
|
56
61
|
|
|
57
|
-
// Handle errors
|
|
62
|
+
// Handle errors - don't exit, just log
|
|
58
63
|
process.stdin.on('error', (error) => {
|
|
59
|
-
|
|
60
|
-
|
|
64
|
+
// Log to stderr but don't exit - Claude Desktop may close stdin
|
|
65
|
+
// Silently handle stdin errors - they're normal when Claude Desktop closes the connection
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
// Handle stdout errors
|
|
69
|
+
process.stdout.on('error', (error) => {
|
|
70
|
+
// If stdout is closed (e.g., Claude Desktop disconnected), exit gracefully
|
|
71
|
+
if (error.code === 'EPIPE') {
|
|
72
|
+
process.exit(0);
|
|
73
|
+
}
|
|
61
74
|
});
|
|
62
75
|
|
|
63
76
|
/**
|
|
64
77
|
* Handle a single line from stdin
|
|
65
78
|
*/
|
|
66
79
|
function handleLine(line) {
|
|
80
|
+
// Skip empty lines
|
|
81
|
+
if (!line || !line.trim()) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
|
|
67
85
|
try {
|
|
68
86
|
const request = JSON.parse(line);
|
|
69
87
|
handleRequest(request);
|
|
@@ -81,11 +99,14 @@ function validateRequest(request) {
|
|
|
81
99
|
return { valid: false, error: 'Request must be an object' };
|
|
82
100
|
}
|
|
83
101
|
|
|
84
|
-
|
|
102
|
+
// Allow requests without jsonrpc for compatibility (some MCP clients may omit it)
|
|
103
|
+
if (request.jsonrpc && request.jsonrpc !== '2.0') {
|
|
85
104
|
return { valid: false, error: 'jsonrpc must be "2.0"' };
|
|
86
105
|
}
|
|
87
106
|
|
|
88
|
-
if (
|
|
107
|
+
// Allow requests without method if they're notifications (id is null/undefined)
|
|
108
|
+
// But batch requests must be arrays
|
|
109
|
+
if (!request.method && !Array.isArray(request) && request.id !== null && request.id !== undefined) {
|
|
89
110
|
return { valid: false, error: 'Request must have a method or be a batch array' };
|
|
90
111
|
}
|
|
91
112
|
|
|
@@ -96,6 +117,11 @@ function validateRequest(request) {
|
|
|
96
117
|
* Handle a JSON-RPC request
|
|
97
118
|
*/
|
|
98
119
|
async function handleRequest(request) {
|
|
120
|
+
// Handle null/undefined requests
|
|
121
|
+
if (!request) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
|
|
99
125
|
// Handle batch requests (array of requests)
|
|
100
126
|
if (Array.isArray(request)) {
|
|
101
127
|
// Process batch requests sequentially
|
|
@@ -122,14 +148,23 @@ async function handleRequest(request) {
|
|
|
122
148
|
*/
|
|
123
149
|
async function processSingleRequest(request) {
|
|
124
150
|
try {
|
|
151
|
+
// Ensure request has jsonrpc field
|
|
152
|
+
const requestWithJsonRpc = {
|
|
153
|
+
...request,
|
|
154
|
+
jsonrpc: request.jsonrpc || '2.0'
|
|
155
|
+
};
|
|
156
|
+
|
|
125
157
|
// Make HTTP request to MCP API
|
|
126
|
-
const response = await axios.post(rpcEndpoint,
|
|
158
|
+
const response = await axios.post(rpcEndpoint, requestWithJsonRpc, {
|
|
127
159
|
headers: {
|
|
128
160
|
'Authorization': `Bearer ${token}`,
|
|
129
|
-
'Content-Type': 'application/json'
|
|
161
|
+
'Content-Type': 'application/json',
|
|
162
|
+
'User-Agent': '@meldocio/mcp-stdio-proxy/1.0.0'
|
|
130
163
|
},
|
|
131
164
|
timeout: REQUEST_TIMEOUT,
|
|
132
|
-
validateStatus: (status) => status < 500 // Don't throw on 4xx errors
|
|
165
|
+
validateStatus: (status) => status < 500, // Don't throw on 4xx errors
|
|
166
|
+
// Keep connection alive for better performance
|
|
167
|
+
httpsAgent: new https.Agent({ keepAlive: true, keepAliveMsecs: 1000 })
|
|
133
168
|
});
|
|
134
169
|
|
|
135
170
|
// Handle successful response
|
|
@@ -146,7 +181,12 @@ async function processSingleRequest(request) {
|
|
|
146
181
|
}
|
|
147
182
|
}
|
|
148
183
|
|
|
184
|
+
// Ensure stdout is flushed immediately
|
|
149
185
|
process.stdout.write(JSON.stringify(responseData) + '\n');
|
|
186
|
+
// Flush stdout to ensure data is sent immediately
|
|
187
|
+
if (process.stdout.isTTY) {
|
|
188
|
+
process.stdout.flush();
|
|
189
|
+
}
|
|
150
190
|
} else {
|
|
151
191
|
// HTTP error status
|
|
152
192
|
const errorMessage = response.data?.error?.message ||
|
|
@@ -202,4 +242,8 @@ function sendError(id, code, message) {
|
|
|
202
242
|
};
|
|
203
243
|
|
|
204
244
|
process.stdout.write(JSON.stringify(errorResponse) + '\n');
|
|
245
|
+
// Flush stdout to ensure data is sent immediately
|
|
246
|
+
if (process.stdout.isTTY) {
|
|
247
|
+
process.stdout.flush();
|
|
248
|
+
}
|
|
205
249
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@meldocio/mcp-stdio-proxy",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "MCP stdio proxy for meldoc - connects Claude Desktop to meldoc MCP API",
|
|
5
5
|
"main": "bin/meldoc-mcp-proxy.js",
|
|
6
6
|
"bin": {
|
|
@@ -46,4 +46,4 @@
|
|
|
46
46
|
"bin/**/*.js"
|
|
47
47
|
]
|
|
48
48
|
}
|
|
49
|
-
}
|
|
49
|
+
}
|