@cloudstreamsoftware/knowledge-mcp-client 1.0.0
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 +86 -0
- package/bin/knowledge-mcp-client.js +2 -0
- package/dist/bridge.d.ts +50 -0
- package/dist/bridge.d.ts.map +1 -0
- package/dist/bridge.js +178 -0
- package/dist/errors.d.ts +27 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +47 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +168 -0
- package/dist/types.d.ts +38 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/package.json +44 -0
package/README.md
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# @cloudstream/knowledge-mcp-client
|
|
2
|
+
|
|
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
|
+
|
|
5
|
+
## Architecture
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
Claude Code ──stdio──► MCP Client Bridge ──HTTPS──► Knowledge Server
|
|
9
|
+
(Parent) JSON-RPC (Child Process) JSON-RPC (Cloudflare)
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
This package is automatically configured when you run the CloudStream setup wizard:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npx @cloudstreamsoftware/claude-tools setup
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Manual Configuration
|
|
21
|
+
|
|
22
|
+
Add to `~/.claude/settings.json`:
|
|
23
|
+
|
|
24
|
+
```json
|
|
25
|
+
{
|
|
26
|
+
"mcpServers": {
|
|
27
|
+
"cloudstream-knowledge": {
|
|
28
|
+
"command": "npx",
|
|
29
|
+
"args": ["@cloudstream/knowledge-mcp-client"],
|
|
30
|
+
"env": {
|
|
31
|
+
"CLOUDSTREAM_LICENSE": "your-license-key",
|
|
32
|
+
"CLOUDSTREAM_API": "https://cloudstream-knowledge.broken-rain-0984.workers.dev"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Environment Variables
|
|
40
|
+
|
|
41
|
+
| Variable | Required | Description |
|
|
42
|
+
|----------|----------|-------------|
|
|
43
|
+
| `CLOUDSTREAM_LICENSE` | Yes | Your CloudStream license key |
|
|
44
|
+
| `CLOUDSTREAM_API` | Yes | Knowledge Server URL |
|
|
45
|
+
| `CLOUDSTREAM_TIMEOUT` | No | Request timeout in ms (default: 30000) |
|
|
46
|
+
| `CLOUDSTREAM_DEBUG` | No | Set to "true" for debug logging |
|
|
47
|
+
|
|
48
|
+
## How It Works
|
|
49
|
+
|
|
50
|
+
1. Claude Code spawns this package as a child process
|
|
51
|
+
2. Claude Code sends JSON-RPC 2.0 requests via stdin
|
|
52
|
+
3. This bridge forwards requests to the Knowledge Server via HTTPS
|
|
53
|
+
4. Responses are returned to Claude Code via stdout
|
|
54
|
+
|
|
55
|
+
### Offline Mode
|
|
56
|
+
|
|
57
|
+
When the Knowledge Server is unavailable, the bridge returns helpful error messages instead of crashing:
|
|
58
|
+
|
|
59
|
+
- `tools/list` returns an empty list
|
|
60
|
+
- `tools/call` returns a friendly message with troubleshooting steps
|
|
61
|
+
|
|
62
|
+
## Debugging
|
|
63
|
+
|
|
64
|
+
Enable debug logging:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
CLOUDSTREAM_DEBUG=true npx @cloudstream/knowledge-mcp-client
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Debug output goes to stderr (doesn't interfere with JSON-RPC protocol on stdout).
|
|
71
|
+
|
|
72
|
+
## Testing
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
# Test initialize (no network required)
|
|
76
|
+
echo '{"jsonrpc":"2.0","id":1,"method":"initialize"}' | \
|
|
77
|
+
CLOUDSTREAM_LICENSE=test CLOUDSTREAM_API=http://localhost \
|
|
78
|
+
npx @cloudstream/knowledge-mcp-client
|
|
79
|
+
|
|
80
|
+
# Expected response:
|
|
81
|
+
# {"jsonrpc":"2.0","id":1,"result":{"protocolVersion":"2024-11-05",...}}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## License
|
|
85
|
+
|
|
86
|
+
MIT - CloudStream Software LLC
|
package/dist/bridge.d.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { McpRequest, McpResponse, BridgeConfig, ConnectionState } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* HTTP Bridge to Knowledge Server
|
|
4
|
+
*
|
|
5
|
+
* Responsibilities:
|
|
6
|
+
* - Forward JSON-RPC requests to HTTP endpoint
|
|
7
|
+
* - Add authentication headers
|
|
8
|
+
* - Handle timeouts and retries
|
|
9
|
+
* - Graceful degradation when server unavailable
|
|
10
|
+
*/
|
|
11
|
+
export declare class HttpBridge {
|
|
12
|
+
private config;
|
|
13
|
+
private connectionState;
|
|
14
|
+
private lastError;
|
|
15
|
+
constructor(config: BridgeConfig);
|
|
16
|
+
/**
|
|
17
|
+
* Forward MCP request to Knowledge Server
|
|
18
|
+
*/
|
|
19
|
+
forward(request: McpRequest): Promise<McpResponse>;
|
|
20
|
+
/**
|
|
21
|
+
* Handle initialize request locally
|
|
22
|
+
* This allows the bridge to respond immediately without network roundtrip
|
|
23
|
+
*/
|
|
24
|
+
private handleInitialize;
|
|
25
|
+
/**
|
|
26
|
+
* Send HTTP request to Knowledge Server
|
|
27
|
+
*/
|
|
28
|
+
private sendRequest;
|
|
29
|
+
/**
|
|
30
|
+
* Handle errors with graceful degradation
|
|
31
|
+
*/
|
|
32
|
+
private handleError;
|
|
33
|
+
/**
|
|
34
|
+
* Generate offline mode response with helpful message
|
|
35
|
+
*/
|
|
36
|
+
private offlineModeResponse;
|
|
37
|
+
/**
|
|
38
|
+
* Create JSON-RPC error response
|
|
39
|
+
*/
|
|
40
|
+
private errorResponse;
|
|
41
|
+
/**
|
|
42
|
+
* Get current connection state
|
|
43
|
+
*/
|
|
44
|
+
getConnectionState(): ConnectionState;
|
|
45
|
+
/**
|
|
46
|
+
* Get last error (for diagnostics)
|
|
47
|
+
*/
|
|
48
|
+
getLastError(): Error | null;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=bridge.d.ts.map
|
|
@@ -0,0 +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"}
|
package/dist/bridge.js
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.HttpBridge = void 0;
|
|
4
|
+
const errors_1 = require("./errors");
|
|
5
|
+
/**
|
|
6
|
+
* HTTP Bridge to Knowledge Server
|
|
7
|
+
*
|
|
8
|
+
* Responsibilities:
|
|
9
|
+
* - Forward JSON-RPC requests to HTTP endpoint
|
|
10
|
+
* - Add authentication headers
|
|
11
|
+
* - Handle timeouts and retries
|
|
12
|
+
* - Graceful degradation when server unavailable
|
|
13
|
+
*/
|
|
14
|
+
class HttpBridge {
|
|
15
|
+
config;
|
|
16
|
+
connectionState = 'connecting';
|
|
17
|
+
lastError = null;
|
|
18
|
+
constructor(config) {
|
|
19
|
+
this.config = config;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Forward MCP request to Knowledge Server
|
|
23
|
+
*/
|
|
24
|
+
async forward(request) {
|
|
25
|
+
// Handle initialize locally for faster response
|
|
26
|
+
if (request.method === 'initialize') {
|
|
27
|
+
return this.handleInitialize(request);
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
const response = await this.sendRequest(request);
|
|
31
|
+
this.connectionState = 'connected';
|
|
32
|
+
this.lastError = null;
|
|
33
|
+
return response;
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
return this.handleError(request, error);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Handle initialize request locally
|
|
41
|
+
* This allows the bridge to respond immediately without network roundtrip
|
|
42
|
+
*/
|
|
43
|
+
handleInitialize(request) {
|
|
44
|
+
return {
|
|
45
|
+
jsonrpc: '2.0',
|
|
46
|
+
id: request.id,
|
|
47
|
+
result: {
|
|
48
|
+
protocolVersion: '2024-11-05',
|
|
49
|
+
serverInfo: {
|
|
50
|
+
name: 'cloudstream-knowledge',
|
|
51
|
+
version: '1.0.0',
|
|
52
|
+
},
|
|
53
|
+
capabilities: {
|
|
54
|
+
tools: {},
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Send HTTP request to Knowledge Server
|
|
61
|
+
*/
|
|
62
|
+
async sendRequest(request) {
|
|
63
|
+
const url = `${this.config.apiUrl}/api/v1/mcp`;
|
|
64
|
+
const controller = new AbortController();
|
|
65
|
+
const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
|
|
66
|
+
try {
|
|
67
|
+
const response = await fetch(url, {
|
|
68
|
+
method: 'POST',
|
|
69
|
+
headers: {
|
|
70
|
+
'Content-Type': 'application/json',
|
|
71
|
+
'Authorization': `Bearer ${this.config.licenseKey}`,
|
|
72
|
+
'User-Agent': 'cloudstream-knowledge-mcp-client/1.0.0',
|
|
73
|
+
},
|
|
74
|
+
body: JSON.stringify(request),
|
|
75
|
+
signal: controller.signal,
|
|
76
|
+
});
|
|
77
|
+
clearTimeout(timeoutId);
|
|
78
|
+
if (response.status === 401) {
|
|
79
|
+
throw new errors_1.AuthenticationError();
|
|
80
|
+
}
|
|
81
|
+
if (response.status === 429) {
|
|
82
|
+
throw new errors_1.BridgeError('Rate limit exceeded', -32005, true);
|
|
83
|
+
}
|
|
84
|
+
if (!response.ok) {
|
|
85
|
+
throw new errors_1.ServerUnavailableError(`Server returned ${response.status}: ${response.statusText}`);
|
|
86
|
+
}
|
|
87
|
+
return await response.json();
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
clearTimeout(timeoutId);
|
|
91
|
+
if (error instanceof errors_1.BridgeError) {
|
|
92
|
+
throw error;
|
|
93
|
+
}
|
|
94
|
+
// Network errors
|
|
95
|
+
if (error.name === 'AbortError') {
|
|
96
|
+
throw new errors_1.ServerUnavailableError('Request timed out');
|
|
97
|
+
}
|
|
98
|
+
throw new errors_1.ServerUnavailableError(`Network error: ${error.message}`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Handle errors with graceful degradation
|
|
103
|
+
*/
|
|
104
|
+
handleError(request, error) {
|
|
105
|
+
this.lastError = error;
|
|
106
|
+
if (error instanceof errors_1.AuthenticationError) {
|
|
107
|
+
this.connectionState = 'disconnected';
|
|
108
|
+
return this.errorResponse(request.id, error.code, error.message);
|
|
109
|
+
}
|
|
110
|
+
if (error instanceof errors_1.ServerUnavailableError) {
|
|
111
|
+
this.connectionState = 'offline';
|
|
112
|
+
return this.offlineModeResponse(request);
|
|
113
|
+
}
|
|
114
|
+
return this.errorResponse(request.id, -32603, // Internal error
|
|
115
|
+
`Bridge error: ${error.message}`);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Generate offline mode response with helpful message
|
|
119
|
+
*/
|
|
120
|
+
offlineModeResponse(request) {
|
|
121
|
+
// For tools/list, return empty list with offline notice
|
|
122
|
+
if (request.method === 'tools/list') {
|
|
123
|
+
return {
|
|
124
|
+
jsonrpc: '2.0',
|
|
125
|
+
id: request.id,
|
|
126
|
+
result: {
|
|
127
|
+
tools: [],
|
|
128
|
+
},
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
// For tool calls, return friendly error
|
|
132
|
+
if (request.method === 'tools/call') {
|
|
133
|
+
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
|
+
};
|
|
152
|
+
}
|
|
153
|
+
return this.errorResponse(request.id, -32003, 'Knowledge Server unavailable');
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Create JSON-RPC error response
|
|
157
|
+
*/
|
|
158
|
+
errorResponse(id, code, message) {
|
|
159
|
+
return {
|
|
160
|
+
jsonrpc: '2.0',
|
|
161
|
+
id,
|
|
162
|
+
error: { code, message },
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Get current connection state
|
|
167
|
+
*/
|
|
168
|
+
getConnectionState() {
|
|
169
|
+
return this.connectionState;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Get last error (for diagnostics)
|
|
173
|
+
*/
|
|
174
|
+
getLastError() {
|
|
175
|
+
return this.lastError;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
exports.HttpBridge = HttpBridge;
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base error for bridge operations
|
|
3
|
+
*/
|
|
4
|
+
export declare class BridgeError extends Error {
|
|
5
|
+
readonly code: number;
|
|
6
|
+
readonly retryable: boolean;
|
|
7
|
+
constructor(message: string, code: number, retryable?: boolean);
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Configuration error (missing env vars)
|
|
11
|
+
*/
|
|
12
|
+
export declare class ConfigurationError extends BridgeError {
|
|
13
|
+
constructor(message: string);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Network/server unavailable error
|
|
17
|
+
*/
|
|
18
|
+
export declare class ServerUnavailableError extends BridgeError {
|
|
19
|
+
constructor(message: string);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Authentication error
|
|
23
|
+
*/
|
|
24
|
+
export declare class AuthenticationError extends BridgeError {
|
|
25
|
+
constructor(message?: string);
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,WAAY,SAAQ,KAAK;aAGlB,IAAI,EAAE,MAAM;aACZ,SAAS,EAAE,OAAO;gBAFlC,OAAO,EAAE,MAAM,EACC,IAAI,EAAE,MAAM,EACZ,SAAS,GAAE,OAAe;CAK7C;AAED;;GAEG;AACH,qBAAa,kBAAmB,SAAQ,WAAW;gBACrC,OAAO,EAAE,MAAM;CAI5B;AAED;;GAEG;AACH,qBAAa,sBAAuB,SAAQ,WAAW;gBACzC,OAAO,EAAE,MAAM;CAI5B;AAED;;GAEG;AACH,qBAAa,mBAAoB,SAAQ,WAAW;gBACtC,OAAO,GAAE,MAAyC;CAI/D"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AuthenticationError = exports.ServerUnavailableError = exports.ConfigurationError = exports.BridgeError = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Base error for bridge operations
|
|
6
|
+
*/
|
|
7
|
+
class BridgeError extends Error {
|
|
8
|
+
code;
|
|
9
|
+
retryable;
|
|
10
|
+
constructor(message, code, retryable = false) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.code = code;
|
|
13
|
+
this.retryable = retryable;
|
|
14
|
+
this.name = 'BridgeError';
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
exports.BridgeError = BridgeError;
|
|
18
|
+
/**
|
|
19
|
+
* Configuration error (missing env vars)
|
|
20
|
+
*/
|
|
21
|
+
class ConfigurationError extends BridgeError {
|
|
22
|
+
constructor(message) {
|
|
23
|
+
super(message, -32600, false); // Invalid Request
|
|
24
|
+
this.name = 'ConfigurationError';
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
exports.ConfigurationError = ConfigurationError;
|
|
28
|
+
/**
|
|
29
|
+
* Network/server unavailable error
|
|
30
|
+
*/
|
|
31
|
+
class ServerUnavailableError extends BridgeError {
|
|
32
|
+
constructor(message) {
|
|
33
|
+
super(message, -32003, true); // Custom code for server unavailable
|
|
34
|
+
this.name = 'ServerUnavailableError';
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
exports.ServerUnavailableError = ServerUnavailableError;
|
|
38
|
+
/**
|
|
39
|
+
* Authentication error
|
|
40
|
+
*/
|
|
41
|
+
class AuthenticationError extends BridgeError {
|
|
42
|
+
constructor(message = 'Invalid or expired license key') {
|
|
43
|
+
super(message, -32001, false); // Custom code for auth
|
|
44
|
+
this.name = 'AuthenticationError';
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
exports.AuthenticationError = AuthenticationError;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
const bridge_1 = require("./bridge");
|
|
37
|
+
const errors_1 = require("./errors");
|
|
38
|
+
const readline = __importStar(require("readline"));
|
|
39
|
+
/**
|
|
40
|
+
* CloudStream Knowledge MCP Client
|
|
41
|
+
*
|
|
42
|
+
* Bridges stdio (Claude Code) <-> HTTP (Knowledge Server)
|
|
43
|
+
*
|
|
44
|
+
* Protocol: JSON-RPC 2.0 over stdio
|
|
45
|
+
* - Reads JSON-RPC requests from stdin (one per line)
|
|
46
|
+
* - Writes JSON-RPC responses to stdout (one per line)
|
|
47
|
+
* - Logs debug info to stderr (doesn't interfere with protocol)
|
|
48
|
+
*/
|
|
49
|
+
/**
|
|
50
|
+
* Load configuration from environment variables
|
|
51
|
+
*/
|
|
52
|
+
function loadConfig() {
|
|
53
|
+
const licenseKey = process.env.CLOUDSTREAM_LICENSE;
|
|
54
|
+
const apiUrl = process.env.CLOUDSTREAM_API;
|
|
55
|
+
if (!licenseKey) {
|
|
56
|
+
throw new errors_1.ConfigurationError('CLOUDSTREAM_LICENSE environment variable is required. ' +
|
|
57
|
+
'Run "npx cloudstream-setup" to configure.');
|
|
58
|
+
}
|
|
59
|
+
if (!apiUrl) {
|
|
60
|
+
throw new errors_1.ConfigurationError('CLOUDSTREAM_API environment variable is required. ' +
|
|
61
|
+
'Run "npx cloudstream-setup" to configure.');
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
licenseKey,
|
|
65
|
+
apiUrl,
|
|
66
|
+
timeout: parseInt(process.env.CLOUDSTREAM_TIMEOUT || '30000', 10),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Debug logging to stderr (doesn't interfere with JSON-RPC on stdout)
|
|
71
|
+
*/
|
|
72
|
+
function debug(message) {
|
|
73
|
+
if (process.env.CLOUDSTREAM_DEBUG === 'true') {
|
|
74
|
+
process.stderr.write(`[mcp-client] ${message}\n`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Send JSON-RPC response to stdout
|
|
79
|
+
*/
|
|
80
|
+
function sendResponse(response) {
|
|
81
|
+
process.stdout.write(JSON.stringify(response) + '\n');
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Main entry point
|
|
85
|
+
*/
|
|
86
|
+
async function main() {
|
|
87
|
+
debug('Starting CloudStream Knowledge MCP Client');
|
|
88
|
+
// Load configuration
|
|
89
|
+
let config;
|
|
90
|
+
try {
|
|
91
|
+
config = loadConfig();
|
|
92
|
+
debug(`API URL: ${config.apiUrl}`);
|
|
93
|
+
debug(`Timeout: ${config.timeout}ms`);
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
// Configuration error - send error response and exit
|
|
97
|
+
process.stderr.write(`Configuration error: ${error.message}\n`);
|
|
98
|
+
process.exit(1);
|
|
99
|
+
}
|
|
100
|
+
// Create HTTP bridge
|
|
101
|
+
const bridge = new bridge_1.HttpBridge(config);
|
|
102
|
+
// Set up readline interface for stdin
|
|
103
|
+
const rl = readline.createInterface({
|
|
104
|
+
input: process.stdin,
|
|
105
|
+
terminal: false,
|
|
106
|
+
});
|
|
107
|
+
// Process JSON-RPC requests line by line
|
|
108
|
+
rl.on('line', async (line) => {
|
|
109
|
+
debug(`Received: ${line.slice(0, 100)}...`);
|
|
110
|
+
if (!line.trim()) {
|
|
111
|
+
return; // Ignore empty lines
|
|
112
|
+
}
|
|
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
|
+
}
|
|
147
|
+
});
|
|
148
|
+
// Handle stdin close
|
|
149
|
+
rl.on('close', () => {
|
|
150
|
+
debug('stdin closed, exiting');
|
|
151
|
+
process.exit(0);
|
|
152
|
+
});
|
|
153
|
+
// Handle errors
|
|
154
|
+
process.on('uncaughtException', (error) => {
|
|
155
|
+
process.stderr.write(`Uncaught exception: ${error.message}\n`);
|
|
156
|
+
process.exit(1);
|
|
157
|
+
});
|
|
158
|
+
process.on('unhandledRejection', (reason) => {
|
|
159
|
+
process.stderr.write(`Unhandled rejection: ${reason}\n`);
|
|
160
|
+
process.exit(1);
|
|
161
|
+
});
|
|
162
|
+
debug('Ready for requests');
|
|
163
|
+
}
|
|
164
|
+
// Run
|
|
165
|
+
main().catch((error) => {
|
|
166
|
+
process.stderr.write(`Fatal error: ${error.message}\n`);
|
|
167
|
+
process.exit(1);
|
|
168
|
+
});
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON-RPC 2.0 Request
|
|
3
|
+
*/
|
|
4
|
+
export interface McpRequest {
|
|
5
|
+
jsonrpc: '2.0';
|
|
6
|
+
id: string | number;
|
|
7
|
+
method: string;
|
|
8
|
+
params?: {
|
|
9
|
+
name?: string;
|
|
10
|
+
arguments?: Record<string, unknown>;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* JSON-RPC 2.0 Response
|
|
15
|
+
*/
|
|
16
|
+
export interface McpResponse {
|
|
17
|
+
jsonrpc: '2.0';
|
|
18
|
+
id: string | number | null;
|
|
19
|
+
result?: unknown;
|
|
20
|
+
error?: {
|
|
21
|
+
code: number;
|
|
22
|
+
message: string;
|
|
23
|
+
data?: unknown;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Configuration from environment variables
|
|
28
|
+
*/
|
|
29
|
+
export interface BridgeConfig {
|
|
30
|
+
licenseKey: string;
|
|
31
|
+
apiUrl: string;
|
|
32
|
+
timeout: number;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Connection state for graceful degradation
|
|
36
|
+
*/
|
|
37
|
+
export type ConnectionState = 'connected' | 'connecting' | 'disconnected' | 'offline';
|
|
38
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,KAAK,CAAC;IACf,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE;QACP,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACrC,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,KAAK,CAAC;IACf,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE;QACN,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,CAAC,EAAE,OAAO,CAAC;KAChB,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,MAAM,eAAe,GACvB,WAAW,GACX,YAAY,GACZ,cAAc,GACd,SAAS,CAAC"}
|
package/dist/types.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@cloudstreamsoftware/knowledge-mcp-client",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "MCP client bridge for CloudStream Knowledge Server - translates stdio to HTTP",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"bin": {
|
|
8
|
+
"knowledge-mcp-client": "./bin/knowledge-mcp-client.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"clean": "rm -rf dist",
|
|
13
|
+
"prepublishOnly": "npm run build"
|
|
14
|
+
},
|
|
15
|
+
"engines": {
|
|
16
|
+
"node": ">=18.0.0"
|
|
17
|
+
},
|
|
18
|
+
"keywords": [
|
|
19
|
+
"mcp",
|
|
20
|
+
"model-context-protocol",
|
|
21
|
+
"cloudstream",
|
|
22
|
+
"zoho",
|
|
23
|
+
"deluge",
|
|
24
|
+
"claude-code"
|
|
25
|
+
],
|
|
26
|
+
"author": "CloudStream Software LLC",
|
|
27
|
+
"license": "MIT",
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "https://github.com/cloudstream-dev/flowstate.git",
|
|
31
|
+
"directory": "packages/knowledge-mcp-client"
|
|
32
|
+
},
|
|
33
|
+
"publishConfig": {
|
|
34
|
+
"access": "public"
|
|
35
|
+
},
|
|
36
|
+
"files": [
|
|
37
|
+
"dist/",
|
|
38
|
+
"bin/"
|
|
39
|
+
],
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@types/node": "^20.0.0",
|
|
42
|
+
"typescript": "^5.3.0"
|
|
43
|
+
}
|
|
44
|
+
}
|