@cloudstreamsoftware/knowledge-mcp-client 1.0.0 → 1.0.2

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,4 +1,4 @@
1
- # @cloudstream/knowledge-mcp-client
1
+ # @cloudstreamsoftware/knowledge-mcp-client
2
2
 
3
3
  MCP client bridge for CloudStream Knowledge Server. Translates Claude Code's stdio-based MCP protocol to HTTP requests against the Cloudflare Knowledge Server.
4
4
 
@@ -26,7 +26,7 @@ Add to `~/.claude/settings.json`:
26
26
  "mcpServers": {
27
27
  "cloudstream-knowledge": {
28
28
  "command": "npx",
29
- "args": ["@cloudstream/knowledge-mcp-client"],
29
+ "args": ["@cloudstreamsoftware/knowledge-mcp-client"],
30
30
  "env": {
31
31
  "CLOUDSTREAM_LICENSE": "your-license-key",
32
32
  "CLOUDSTREAM_API": "https://cloudstream-knowledge.broken-rain-0984.workers.dev"
@@ -64,7 +64,7 @@ When the Knowledge Server is unavailable, the bridge returns helpful error messa
64
64
  Enable debug logging:
65
65
 
66
66
  ```bash
67
- CLOUDSTREAM_DEBUG=true npx @cloudstream/knowledge-mcp-client
67
+ CLOUDSTREAM_DEBUG=true npx @cloudstreamsoftware/knowledge-mcp-client
68
68
  ```
69
69
 
70
70
  Debug output goes to stderr (doesn't interfere with JSON-RPC protocol on stdout).
@@ -75,7 +75,7 @@ Debug output goes to stderr (doesn't interfere with JSON-RPC protocol on stdout)
75
75
  # Test initialize (no network required)
76
76
  echo '{"jsonrpc":"2.0","id":1,"method":"initialize"}' | \
77
77
  CLOUDSTREAM_LICENSE=test CLOUDSTREAM_API=http://localhost \
78
- npx @cloudstream/knowledge-mcp-client
78
+ npx @cloudstreamsoftware/knowledge-mcp-client
79
79
 
80
80
  # Expected response:
81
81
  # {"jsonrpc":"2.0","id":1,"result":{"protocolVersion":"2024-11-05",...}}
package/dist/bridge.d.ts CHANGED
@@ -31,7 +31,8 @@ export declare class HttpBridge {
31
31
  */
32
32
  private handleError;
33
33
  /**
34
- * Generate offline mode response with helpful message
34
+ * Generate offline mode response
35
+ * Per JSON-RPC 2.0, failures must return error, not result
35
36
  */
36
37
  private offlineModeResponse;
37
38
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAGjF;;;;;;;;GAQG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,eAAe,CAAiC;IACxD,OAAO,CAAC,SAAS,CAAsB;gBAE3B,MAAM,EAAE,YAAY;IAIhC;;OAEG;IACG,OAAO,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC;IAgBxD;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IAiBxB;;OAEG;YACW,WAAW;IAwDzB;;OAEG;IACH,OAAO,CAAC,WAAW;IAoBnB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IA0C3B;;OAEG;IACH,OAAO,CAAC,aAAa;IAYrB;;OAEG;IACH,kBAAkB,IAAI,eAAe;IAIrC;;OAEG;IACH,YAAY,IAAI,KAAK,GAAG,IAAI;CAG7B"}
1
+ {"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAGjF;;;;;;;;GAQG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,eAAe,CAAiC;IACxD,OAAO,CAAC,SAAS,CAAsB;gBAE3B,MAAM,EAAE,YAAY;IAIhC;;OAEG;IACG,OAAO,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC;IAgBxD;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IAiBxB;;OAEG;YACW,WAAW;IAwDzB;;OAEG;IACH,OAAO,CAAC,WAAW;IAoBnB;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IA8B3B;;OAEG;IACH,OAAO,CAAC,aAAa;IAYrB;;OAEG;IACH,kBAAkB,IAAI,eAAe;IAIrC;;OAEG;IACH,YAAY,IAAI,KAAK,GAAG,IAAI;CAG7B"}
package/dist/bridge.js CHANGED
@@ -115,10 +115,11 @@ class HttpBridge {
115
115
  `Bridge error: ${error.message}`);
116
116
  }
117
117
  /**
118
- * Generate offline mode response with helpful message
118
+ * Generate offline mode response
119
+ * Per JSON-RPC 2.0, failures must return error, not result
119
120
  */
120
121
  offlineModeResponse(request) {
121
- // For tools/list, return empty list with offline notice
122
+ // For tools/list, return empty list (graceful degradation)
122
123
  if (request.method === 'tools/list') {
123
124
  return {
124
125
  jsonrpc: '2.0',
@@ -128,27 +129,11 @@ class HttpBridge {
128
129
  },
129
130
  };
130
131
  }
131
- // For tool calls, return friendly error
132
+ // For tool calls, return proper JSON-RPC error
132
133
  if (request.method === 'tools/call') {
133
134
  const toolName = request.params?.name || 'unknown tool';
134
- return {
135
- jsonrpc: '2.0',
136
- id: request.id,
137
- result: {
138
- content: [
139
- {
140
- type: 'text',
141
- text: `[OFFLINE] The CloudStream Knowledge Server is currently unavailable.\n\n` +
142
- `Unable to process: ${toolName}\n\n` +
143
- `Please check:\n` +
144
- `1. Your internet connection\n` +
145
- `2. Knowledge Server status at ${this.config.apiUrl}/health\n` +
146
- `3. Your license key validity\n\n` +
147
- `Local skills and web search remain available.`,
148
- },
149
- ],
150
- },
151
- };
135
+ return this.errorResponse(request.id, -32003, `Knowledge Server unavailable. Unable to process: ${toolName}. ` +
136
+ `Check your internet connection and try again.`);
152
137
  }
153
138
  return this.errorResponse(request.id, -32003, 'Knowledge Server unavailable');
154
139
  }
package/dist/index.js CHANGED
@@ -99,56 +99,78 @@ async function main() {
99
99
  }
100
100
  // Create HTTP bridge
101
101
  const bridge = new bridge_1.HttpBridge(config);
102
+ // Track pending async operations to prevent premature exit
103
+ const pendingRequests = new Set();
104
+ let stdinClosed = false;
102
105
  // Set up readline interface for stdin
103
106
  const rl = readline.createInterface({
104
107
  input: process.stdin,
105
108
  terminal: false,
106
109
  });
107
110
  // Process JSON-RPC requests line by line
108
- rl.on('line', async (line) => {
111
+ rl.on('line', (line) => {
109
112
  debug(`Received: ${line.slice(0, 100)}...`);
110
113
  if (!line.trim()) {
111
114
  return; // Ignore empty lines
112
115
  }
113
- let request;
114
- try {
115
- request = JSON.parse(line);
116
- }
117
- catch {
118
- // Parse error
119
- sendResponse({
120
- jsonrpc: '2.0',
121
- id: null,
122
- error: {
123
- code: -32700,
124
- message: 'Parse error: Invalid JSON',
125
- },
126
- });
127
- return;
128
- }
129
- // Forward to bridge and send response
130
- try {
131
- const response = await bridge.forward(request);
132
- debug(`Response for ${request.method}: ${bridge.getConnectionState()}`);
133
- sendResponse(response);
134
- }
135
- catch (error) {
136
- // Unexpected error - should be handled by bridge
137
- debug(`Unexpected error: ${error.message}`);
138
- sendResponse({
139
- jsonrpc: '2.0',
140
- id: request.id,
141
- error: {
142
- code: -32603,
143
- message: `Internal error: ${error.message}`,
144
- },
145
- });
146
- }
116
+ // Handle request asynchronously but track the promise
117
+ const requestPromise = (async () => {
118
+ let request;
119
+ try {
120
+ request = JSON.parse(line);
121
+ }
122
+ catch {
123
+ // Parse error
124
+ sendResponse({
125
+ jsonrpc: '2.0',
126
+ id: null,
127
+ error: {
128
+ code: -32700,
129
+ message: 'Parse error: Invalid JSON',
130
+ },
131
+ });
132
+ return;
133
+ }
134
+ // Forward to bridge and send response
135
+ try {
136
+ const response = await bridge.forward(request);
137
+ debug(`Response for ${request.method}: ${bridge.getConnectionState()}`);
138
+ sendResponse(response);
139
+ }
140
+ catch (error) {
141
+ // Unexpected error - should be handled by bridge
142
+ debug(`Unexpected error: ${error.message}`);
143
+ sendResponse({
144
+ jsonrpc: '2.0',
145
+ id: request.id,
146
+ error: {
147
+ code: -32603,
148
+ message: `Internal error: ${error.message}`,
149
+ },
150
+ });
151
+ }
152
+ })();
153
+ // Track this request
154
+ pendingRequests.add(requestPromise);
155
+ requestPromise.finally(() => {
156
+ pendingRequests.delete(requestPromise);
157
+ // If stdin is closed and no pending requests, exit
158
+ if (stdinClosed && pendingRequests.size === 0) {
159
+ debug('All requests completed, exiting');
160
+ process.exit(0);
161
+ }
162
+ });
147
163
  });
148
- // Handle stdin close
149
- rl.on('close', () => {
150
- debug('stdin closed, exiting');
151
- process.exit(0);
164
+ // Handle stdin close - wait for pending requests before exiting
165
+ rl.on('close', async () => {
166
+ debug(`stdin closed, ${pendingRequests.size} pending requests`);
167
+ stdinClosed = true;
168
+ // If no pending requests, exit immediately
169
+ if (pendingRequests.size === 0) {
170
+ debug('No pending requests, exiting');
171
+ process.exit(0);
172
+ }
173
+ // Otherwise, requests will exit when they complete (see finally block above)
152
174
  });
153
175
  // Handle errors
154
176
  process.on('uncaughtException', (error) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloudstreamsoftware/knowledge-mcp-client",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "MCP client bridge for CloudStream Knowledge Server - translates stdio to HTTP",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",