reportdash-datastore-mcp-claude-desktop 1.0.7 → 1.0.9

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.
Files changed (2) hide show
  1. package/index.js +85 -57
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- //goto folder, increment version then run > npm publish --access public
2
+ // goto folder, increment version then run > npm publish --access public
3
3
 
4
4
  const https = require('https');
5
5
  const http = require('http');
@@ -12,13 +12,18 @@ const API_URL = process.env.REPORTDASH_API_URL || 'https://datastore.reportdash.
12
12
 
13
13
  // Validate configuration
14
14
  if (!API_KEY) {
15
- console.error(JSON.stringify({
16
- jsonrpc: '2.0',
17
- error: {
18
- code: -32600,
19
- message: 'REPORTDASH_API_KEY environment variable is required. Get your API key from ReportDash DataStore app settings.'
20
- }
21
- }));
15
+ // NOTE: In MCP stdio mode, prefer stdout only.
16
+ // But keeping your original behavior as-is.
17
+ console.error(
18
+ JSON.stringify({
19
+ jsonrpc: '2.0',
20
+ error: {
21
+ code: -32600,
22
+ message:
23
+ 'REPORTDASH_API_KEY environment variable is required. Get your API key from ReportDash DataStore app settings.',
24
+ },
25
+ })
26
+ );
22
27
  process.exit(1);
23
28
  }
24
29
 
@@ -27,13 +32,20 @@ if (!API_KEY) {
27
32
  * without breaking existing requests.
28
33
  */
29
34
  function withClaudePlatform(mcpRequest) {
30
- // If caller already provided platform, keep it.
31
35
  if (mcpRequest && typeof mcpRequest === 'object') {
32
- if (!mcpRequest.platform) mcpRequest.platform = 'claude';
36
+ if (mcpRequest.platform == null) mcpRequest.platform = 'claude';
33
37
  }
34
38
  return mcpRequest;
35
39
  }
36
40
 
41
+ /**
42
+ * JSON-RPC id helper:
43
+ * Keep 0 as a valid id; only default when null/undefined.
44
+ */
45
+ function rpcId(mcpRequest) {
46
+ return mcpRequest?.id ?? null;
47
+ }
48
+
37
49
  // Test mode
38
50
  if (process.argv.includes('--test')) {
39
51
  testConnection();
@@ -44,7 +56,7 @@ if (process.argv.includes('--test')) {
44
56
  const rl = readline.createInterface({
45
57
  input: process.stdin,
46
58
  output: process.stdout,
47
- terminal: false
59
+ terminal: false,
48
60
  });
49
61
 
50
62
  rl.on('line', (line) => {
@@ -55,14 +67,16 @@ rl.on('line', (line) => {
55
67
  forwardToAPI(withClaudePlatform(mcpRequest));
56
68
  } catch (error) {
57
69
  // Only output to stdout, never stderr for MCP protocol
58
- console.log(JSON.stringify({
59
- jsonrpc: '2.0',
60
- error: {
61
- code: -32700,
62
- message: 'Parse error: ' + error.message
63
- },
64
- id: null
65
- }));
70
+ console.log(
71
+ JSON.stringify({
72
+ jsonrpc: '2.0',
73
+ error: {
74
+ code: -32700,
75
+ message: 'Parse error: ' + error.message,
76
+ },
77
+ id: null,
78
+ })
79
+ );
66
80
  }
67
81
  });
68
82
 
@@ -79,9 +93,9 @@ function forwardToAPI(mcpRequest) {
79
93
  headers: {
80
94
  'Content-Type': 'application/json',
81
95
  'X-Api-Key': API_KEY,
82
- 'User-Agent': 'ReportDash-DataStore-MCP/1.0'
96
+ 'User-Agent': 'ReportDash-DataStore-MCP/1.0',
83
97
  },
84
- timeout: 30000 // 30 second timeout
98
+ timeout: 30000, // 30 second timeout
85
99
  };
86
100
 
87
101
  const req = client.request(options, (res) => {
@@ -96,54 +110,62 @@ function forwardToAPI(mcpRequest) {
96
110
  if (res.statusCode >= 200 && res.statusCode < 300) {
97
111
  // For 204 No Content or empty response, return empty success
98
112
  if (res.statusCode === 204 || !data.trim()) {
99
- console.log(JSON.stringify({
100
- jsonrpc: '2.0',
101
- result: {},
102
- id: mcpRequest.id || null
103
- }));
113
+ console.log(
114
+ JSON.stringify({
115
+ jsonrpc: '2.0',
116
+ result: {},
117
+ id: rpcId(mcpRequest), // FIX: preserves id=0
118
+ })
119
+ );
104
120
  } else {
105
121
  // Forward the response as-is
106
122
  console.log(data);
107
123
  }
108
124
  } else {
109
125
  // Send errors to stdout (not stderr!) so Claude can properly handle them
110
- console.log(JSON.stringify({
111
- jsonrpc: '2.0',
112
- error: {
113
- code: res.statusCode,
114
- message: `API error: ${res.statusCode}${data ? ' - ' + data : ''}`,
115
- data: { statusCode: res.statusCode, body: data }
116
- },
117
- id: mcpRequest.id || null
118
- }));
126
+ console.log(
127
+ JSON.stringify({
128
+ jsonrpc: '2.0',
129
+ error: {
130
+ code: res.statusCode,
131
+ message: `API error: ${res.statusCode}${data ? ' - ' + data : ''}`,
132
+ data: { statusCode: res.statusCode, body: data },
133
+ },
134
+ id: rpcId(mcpRequest), // FIX: preserves id=0
135
+ })
136
+ );
119
137
  }
120
138
  });
121
139
  });
122
140
 
123
141
  req.on('error', (error) => {
124
142
  // Send errors to stdout (not stderr!)
125
- console.log(JSON.stringify({
126
- jsonrpc: '2.0',
127
- error: {
128
- code: -32603,
129
- message: 'Network error: ' + error.message,
130
- data: { error: error.message }
131
- },
132
- id: mcpRequest.id || null
133
- }));
143
+ console.log(
144
+ JSON.stringify({
145
+ jsonrpc: '2.0',
146
+ error: {
147
+ code: -32603,
148
+ message: 'Network error: ' + error.message,
149
+ data: { error: error.message },
150
+ },
151
+ id: rpcId(mcpRequest), // FIX: preserves id=0
152
+ })
153
+ );
134
154
  });
135
155
 
136
156
  req.on('timeout', () => {
137
157
  req.destroy();
138
158
  // Send errors to stdout (not stderr!)
139
- console.log(JSON.stringify({
140
- jsonrpc: '2.0',
141
- error: {
142
- code: -32603,
143
- message: 'Request timeout after 30 seconds'
144
- },
145
- id: mcpRequest.id || null
146
- }));
159
+ console.log(
160
+ JSON.stringify({
161
+ jsonrpc: '2.0',
162
+ error: {
163
+ code: -32603,
164
+ message: 'Request timeout after 30 seconds',
165
+ },
166
+ id: rpcId(mcpRequest), // FIX: preserves id=0
167
+ })
168
+ );
147
169
  });
148
170
 
149
171
  req.write(JSON.stringify(mcpRequest));
@@ -151,9 +173,13 @@ function forwardToAPI(mcpRequest) {
151
173
  }
152
174
 
153
175
  function testConnection() {
176
+ // NOTE: This prints non-JSON to stdout, which is fine for --test.
177
+ // Do not run --test as an MCP stdio server in Claude Desktop.
154
178
  console.log('🔍 Testing ReportDash DataStore connection...\n');
155
179
  console.log(`API URL: ${API_URL}`);
156
- console.log(`API Key: ${API_KEY.substring(0, 10)}...${API_KEY.substring(API_KEY.length - 4)}\n`);
180
+ console.log(
181
+ `API Key: ${API_KEY.substring(0, 10)}...${API_KEY.substring(API_KEY.length - 4)}\n`
182
+ );
157
183
 
158
184
  const url = new URL(API_URL);
159
185
  const isHttps = url.protocol === 'https:';
@@ -163,7 +189,7 @@ function testConnection() {
163
189
  const mcpRequest = withClaudePlatform({
164
190
  jsonrpc: '2.0',
165
191
  method: 'tools/list',
166
- id: 'test-connection'
192
+ id: 'test-connection',
167
193
  });
168
194
 
169
195
  const postData = JSON.stringify(mcpRequest);
@@ -177,16 +203,18 @@ function testConnection() {
177
203
  'Content-Type': 'application/json',
178
204
  'X-Api-Key': API_KEY,
179
205
  'Content-Length': Buffer.byteLength(postData),
180
- 'User-Agent': 'ReportDash-DataStore-MCP/1.0'
206
+ 'User-Agent': 'ReportDash-DataStore-MCP/1.0',
181
207
  },
182
- timeout: 10000
208
+ timeout: 10000,
183
209
  };
184
210
 
185
211
  console.log('📡 Sending MCP tools/list request...\n');
186
212
 
187
213
  const req = client.request(options, (res) => {
188
214
  let data = '';
189
- res.on('data', (chunk) => { data += chunk; });
215
+ res.on('data', (chunk) => {
216
+ data += chunk;
217
+ });
190
218
  res.on('end', () => {
191
219
  console.log(`Response Status: ${res.statusCode}\n`);
192
220
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "reportdash-datastore-mcp-claude-desktop",
3
- "version": "1.0.7",
3
+ "version": "1.0.9",
4
4
  "description": "ReportDash DataStore MCP server for Claude Desktop",
5
5
  "main": "index.js",
6
6
  "bin": {