cellium-mcp-client 1.0.3 → 1.1.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/README.md CHANGED
@@ -1,10 +1,10 @@
1
1
  # @cellium/mcp-client
2
2
 
3
- A Model Context Protocol (MCP) client for connecting to the remote Cellium processor server via Server-Sent Events (SSE).
3
+ A Model Context Protocol (MCP) server that proxies requests to remote Cellium processor servers.
4
4
 
5
5
  ## Features
6
6
 
7
- - **SSE Transport**: Connects to remote Cellium server using Server-Sent Events
7
+ - **HTTP Proxy**: Proxies MCP requests to remote Cellium servers via HTTP
8
8
  - **Authentication**: Token-based authentication with format `user:username:hash`
9
9
  - **Robust Connection Management**: Automatic reconnection with configurable retry logic
10
10
  - **MCP Protocol Compliance**: Uses official `@modelcontextprotocol/sdk`
@@ -38,7 +38,7 @@ cellium-mcp-client --token "user:your-username:your-hash"
38
38
  # With custom endpoint and verbose logging
39
39
  cellium-mcp-client \
40
40
  --token "user:your-username:your-hash" \
41
- --endpoint "https://mcp.cellium.dev/sse" \
41
+ --endpoint "https://mcp.cellium.dev/mcp" \
42
42
  --verbose \
43
43
  --retry-attempts 5 \
44
44
  --retry-delay 2000
@@ -66,7 +66,7 @@ const logger = pino();
66
66
 
67
67
  const client = new CelliumMCPClient({
68
68
  token: 'user:your-username:your-hash',
69
- endpoint: 'https://mcp.cellium.dev/sse',
69
+ endpoint: 'https://mcp.cellium.dev/mcp',
70
70
  logger,
71
71
  retryAttempts: 3,
72
72
  retryDelay: 1000
@@ -87,7 +87,7 @@ process.on('SIGINT', async () => {
87
87
  | Option | Environment Variable | Description | Default |
88
88
  |--------|---------------------|-------------|---------|
89
89
  | `--token` | `CELLIUM_MCP_TOKEN` | Authentication token (required) | - |
90
- | `--endpoint` | - | Server endpoint URL | `https://mcp.cellium.dev/sse` |
90
+ | `--endpoint` | - | Server endpoint URL | `https://mcp.cellium.dev/mcp` |
91
91
  | `--verbose` | - | Enable verbose logging | `false` |
92
92
  | `--retry-attempts` | - | Number of retry attempts | `3` |
93
93
  | `--retry-delay` | - | Delay between retries (ms) | `1000` |
@@ -106,29 +106,20 @@ Example: `user:john-doe:a1b2c3d4e5f6...`
106
106
  ## Architecture
107
107
 
108
108
  ```
109
- ┌─────────────────┐ SSE ┌─────────────────┐
110
- │ │◄──────────►│ │
111
- MCP Client HTTPS │ Cellium Server │
112
- │ (This Package) │ (Remote) │
113
- │ │ │ │
114
- └─────────────────┘ └─────────────────┘
115
- ▲ │
116
- │ stdio │
117
- │ MCP Protocol │
118
- ▼ │
119
- ┌─────────────────┐ │
120
- │ │ │
121
- │ Code Editor / │ │
122
- │ AI Assistant │ │
123
- │ (Cody, etc.) │ │
124
- └─────────────────┘ │
109
+ ┌─────────────────┐ stdio ┌─────────────────┐ HTTPS ┌─────────────────┐
110
+ │ │◄──────────►│ │◄──────────►│
111
+ Code Editor / │ MCP cellium-mcp-HTTP │ Cellium Server │
112
+ AI Assistant │ Protocol │ client (Proxy) │ Requests │ (Remote) │
113
+ (Cody, etc.) │ │ │ │ │
114
+ └─────────────────┘ └─────────────────┘ └─────────────────┘
125
115
  ```
126
116
 
127
- The client acts as a bridge between local MCP clients (like Cody) and the remote Cellium processor server, handling:
128
- - Authentication and connection management
129
- - Protocol translation between stdio MCP and SSE
130
- - Error handling and reconnection logic
131
- - Request/response proxying
117
+ The client acts as an **MCP server proxy** between local MCP clients (like Cody) and the remote Cellium processor server, handling:
118
+ - **MCP Protocol**: Full stdio-based MCP server implementation
119
+ - **Authentication**: Token-based authentication with remote server
120
+ - **Request Proxying**: Converts MCP requests to HTTP requests to remote server
121
+ - **Error Handling**: Graceful handling of connection failures
122
+ - **Connection Management**: Automatic retry and reconnection logic
132
123
 
133
124
  ## Development
134
125
 
@@ -153,7 +144,7 @@ npm run dev
153
144
  ### Connection Issues
154
145
 
155
146
  1. **Invalid token format**: Ensure your token follows the `user:username:hash` format
156
- 2. **Network connectivity**: Check if `https://mcp.cellium.dev/sse` is accessible
147
+ 2. **Network connectivity**: Check if `https://mcp.cellium.dev/mcp` is accessible
157
148
  3. **Authentication failed**: Verify your token is valid and not expired
158
149
 
159
150
  ### Verbose Logging
package/dist/cli.js CHANGED
@@ -11,7 +11,7 @@ const program = new commander_1.Command();
11
11
  program
12
12
  .name('cellium-mcp-client')
13
13
  .description('MCP client for connecting to remote Cellium processor server')
14
- .version('1.0.3')
14
+ .version('1.1.1')
15
15
  .option('-t, --token <token>', 'Authentication token (format: user:username:hash)')
16
16
  .option('-e, --endpoint <url>', 'Server endpoint URL', 'http://localhost:3000/mcp')
17
17
  .option('-v, --verbose', 'Enable verbose logging')
package/dist/client.d.ts CHANGED
@@ -11,14 +11,12 @@ export declare class CelliumMCPClient {
11
11
  private localServer;
12
12
  private isConnected;
13
13
  private reconnectTimer?;
14
- private currentRetryCount;
15
14
  constructor(config: CelliumMCPClientConfig);
16
15
  private setupServer;
17
16
  private makeHttpRequest;
18
17
  connect(): Promise<void>;
18
+ private testConnectionInBackground;
19
19
  serve(): Promise<void>;
20
20
  private testConnection;
21
- private handleConnectionError;
22
- private reconnect;
23
21
  disconnect(): Promise<void>;
24
22
  }
package/dist/client.js CHANGED
@@ -30,12 +30,22 @@ const PingSchema = zod_1.z.object({
30
30
  method: zod_1.z.literal('ping'),
31
31
  params: zod_1.z.object({}).optional()
32
32
  });
33
+ const InitializeSchema = zod_1.z.object({
34
+ method: zod_1.z.literal('initialize'),
35
+ params: zod_1.z.object({
36
+ protocolVersion: zod_1.z.string(),
37
+ capabilities: zod_1.z.object({}).passthrough()
38
+ })
39
+ });
40
+ const InitializedNotificationSchema = zod_1.z.object({
41
+ method: zod_1.z.literal('notifications/initialized'),
42
+ params: zod_1.z.object({}).optional()
43
+ });
33
44
  class CelliumMCPClient {
34
45
  config;
35
46
  localServer;
36
47
  isConnected = false;
37
48
  reconnectTimer;
38
- currentRetryCount = 0;
39
49
  constructor(config) {
40
50
  this.config = {
41
51
  retryAttempts: 3,
@@ -55,57 +65,67 @@ class CelliumMCPClient {
55
65
  this.setupServer();
56
66
  }
57
67
  setupServer() {
58
- // Register a dynamic tool handler that forwards all tool calls to remote server
59
- this.localServer.registerTool('cellium-proxy-tool', {
60
- description: 'Proxy tool for Cellium server - handles all tool calls dynamically'
61
- }, async (_args) => {
62
- // This won't actually be called since we override the request handlers directly
63
- return { content: [{ type: 'text', text: 'Proxy tool' }] };
68
+ // Handle MCP initialization
69
+ this.localServer.server.setRequestHandler(InitializeSchema, async (_request) => {
70
+ this.config.logger.debug('Received initialize request');
71
+ return {
72
+ protocolVersion: '2024-11-05',
73
+ capabilities: {
74
+ tools: {},
75
+ resources: {}
76
+ },
77
+ serverInfo: {
78
+ name: 'cellium-mcp-client',
79
+ version: '1.1.1'
80
+ }
81
+ };
64
82
  });
65
83
  // Override the underlying server's tool request handlers to proxy to remote
66
84
  this.localServer.server.setRequestHandler(ToolsListSchema, async () => {
67
85
  this.config.logger.debug('Proxying tools/list to remote server');
68
- if (!this.isConnected) {
69
- throw new Error('Not connected to remote server');
70
- }
71
86
  const result = await this.makeHttpRequest('tools/list', {});
72
87
  return result;
73
88
  });
74
89
  this.localServer.server.setRequestHandler(ToolsCallSchema, async (request) => {
75
90
  this.config.logger.debug({ toolName: request.params?.name }, 'Proxying tool call to remote server');
76
- if (!this.isConnected) {
77
- throw new Error('Not connected to remote server');
78
- }
79
91
  const result = await this.makeHttpRequest('tools/call', request.params);
80
92
  return result;
81
93
  });
82
94
  // Handle resources as well
83
95
  this.localServer.server.setRequestHandler(ResourcesListSchema, async () => {
84
96
  this.config.logger.debug('Proxying resources/list to remote server');
85
- if (!this.isConnected) {
86
- throw new Error('Not connected to remote server');
87
- }
88
97
  const result = await this.makeHttpRequest('resources/list', {});
89
98
  return result;
90
99
  });
91
100
  this.localServer.server.setRequestHandler(ResourcesReadSchema, async (request) => {
92
101
  this.config.logger.debug({ uri: request.params?.uri }, 'Proxying resources/read to remote server');
93
- if (!this.isConnected) {
94
- throw new Error('Not connected to remote server');
95
- }
96
102
  const result = await this.makeHttpRequest('resources/read', request.params);
97
103
  return result;
98
104
  });
99
105
  // Handle ping
100
106
  this.localServer.server.setRequestHandler(PingSchema, async () => {
101
- if (!this.isConnected) {
102
- throw new Error('Not connected to remote server');
103
- }
104
107
  const result = await this.makeHttpRequest('ping', {});
105
108
  return result;
106
109
  });
110
+ // Handle other common MCP methods
111
+ this.localServer.server.setNotificationHandler(InitializedNotificationSchema, async () => {
112
+ this.config.logger.debug('Received initialized notification');
113
+ // No response needed for notifications
114
+ });
107
115
  }
108
116
  async makeHttpRequest(method, params) {
117
+ // If not connected, try to connect first
118
+ if (!this.isConnected) {
119
+ try {
120
+ await this.testConnection();
121
+ this.isConnected = true;
122
+ this.config.logger.info('Connected to remote Cellium server');
123
+ }
124
+ catch (error) {
125
+ this.config.logger.error({ error }, 'Failed to connect to remote server');
126
+ throw new Error('Cannot connect to remote Cellium server');
127
+ }
128
+ }
109
129
  const mcpEndpoint = this.config.endpoint.replace('/sse', '/mcp');
110
130
  const requestBody = {
111
131
  jsonrpc: '2.0',
@@ -134,31 +154,38 @@ class CelliumMCPClient {
134
154
  }
135
155
  catch (error) {
136
156
  this.config.logger.error({ error, method }, 'HTTP request to remote server failed');
157
+ this.isConnected = false; // Mark as disconnected on error
137
158
  throw error;
138
159
  }
139
160
  }
140
161
  async connect() {
141
162
  try {
142
- this.config.logger.info({ endpoint: this.config.endpoint }, 'Connecting to Cellium MCP Server');
143
- // Test connection with a ping
163
+ this.config.logger.info({ endpoint: this.config.endpoint }, 'Starting Cellium MCP Server');
164
+ // Set up the stdio transport for local MCP server immediately
165
+ const stdioTransport = new stdio_js_1.StdioServerTransport();
166
+ await this.localServer.connect(stdioTransport);
167
+ this.config.logger.info('MCP Server connected and ready');
168
+ // Test connection to remote server in background, but don't block startup
169
+ this.testConnectionInBackground();
170
+ }
171
+ catch (error) {
172
+ this.config.logger.error({ error }, 'Failed to start MCP server');
173
+ throw error;
174
+ }
175
+ }
176
+ async testConnectionInBackground() {
177
+ try {
144
178
  await this.testConnection();
145
179
  this.isConnected = true;
146
- this.currentRetryCount = 0;
180
+ this.config.logger.info('Connected to remote Cellium server');
147
181
  if (this.reconnectTimer) {
148
182
  clearTimeout(this.reconnectTimer);
149
183
  this.reconnectTimer = undefined;
150
184
  }
151
- this.config.logger.info('Connected to remote Cellium server');
152
- // Set up the stdio transport for local MCP server
153
- const stdioTransport = new stdio_js_1.StdioServerTransport();
154
- await this.localServer.connect(stdioTransport);
155
- this.config.logger.info('MCP Client connected and ready');
156
185
  }
157
186
  catch (error) {
158
- this.config.logger.error({ error }, 'Failed to connect');
187
+ this.config.logger.warn({ error }, 'Failed to connect to remote server, will retry on first request');
159
188
  this.isConnected = false;
160
- this.handleConnectionError();
161
- throw error;
162
189
  }
163
190
  }
164
191
  async serve() {
@@ -192,28 +219,6 @@ class CelliumMCPClient {
192
219
  }
193
220
  this.config.logger.debug('Connection test successful');
194
221
  }
195
- handleConnectionError() {
196
- if (this.currentRetryCount < this.config.retryAttempts) {
197
- this.currentRetryCount++;
198
- this.config.logger.warn(`Connection failed, retrying in ${this.config.retryDelay}ms (attempt ${this.currentRetryCount}/${this.config.retryAttempts})`);
199
- this.reconnectTimer = setTimeout(() => {
200
- this.reconnect();
201
- }, this.config.retryDelay);
202
- }
203
- else {
204
- this.config.logger.error('Max retry attempts reached, giving up');
205
- process.exit(1);
206
- }
207
- }
208
- async reconnect() {
209
- try {
210
- await this.connect();
211
- }
212
- catch (error) {
213
- this.config.logger.error({ error }, 'Reconnection failed');
214
- this.handleConnectionError();
215
- }
216
- }
217
222
  async disconnect() {
218
223
  this.config.logger.info('Disconnecting from Cellium MCP Server');
219
224
  this.isConnected = false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cellium-mcp-client",
3
- "version": "1.0.3",
3
+ "version": "1.1.1",
4
4
  "description": "MCP client for connecting to remote Cellium processor server",
5
5
  "main": "dist/index.js",
6
6
  "bin": {