workfullcircle-mcp-local 1.4.0 → 1.4.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.
Files changed (3) hide show
  1. package/index.js +68 -22
  2. package/package.json +2 -2
  3. package/test.js +0 -98
package/index.js CHANGED
@@ -1,6 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  const fetch = require('node-fetch');
4
+ const https = require('https');
5
+ const { URL } = require('url');
4
6
 
5
7
  // Parse command line arguments
6
8
  const args = process.argv.slice(2);
@@ -39,6 +41,58 @@ function parseArgs(argv) {
39
41
 
40
42
  const { token: API_TOKEN, url: API_URL } = parseArgs(args);
41
43
 
44
+ // Create HTTPS agent with keepAlive disabled to prevent stale connections
45
+ const httpsAgent = new https.Agent({
46
+ keepAlive: false, // Force fresh connection for each request
47
+ timeout: 10000 // 10 second timeout
48
+ });
49
+
50
+ // Helper function to make HTTP requests with retry logic
51
+ async function makeRequest(url, payload, retryCount = 0) {
52
+ const controller = new AbortController();
53
+ const timeout = setTimeout(() => controller.abort(), 15000); // 15s timeout
54
+
55
+ try {
56
+ const response = await fetch(url, {
57
+ method: 'POST',
58
+ headers: {
59
+ 'Content-Type': 'application/json',
60
+ 'Authorization': `Bearer ${API_TOKEN}`,
61
+ 'Connection': 'close' // Explicitly request connection close
62
+ },
63
+ body: JSON.stringify(payload),
64
+ agent: httpsAgent,
65
+ signal: controller.signal
66
+ });
67
+
68
+ clearTimeout(timeout);
69
+
70
+ if (!response.ok) {
71
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
72
+ }
73
+
74
+ const responseText = await response.text();
75
+
76
+ // Validate response is valid JSON
77
+ try {
78
+ JSON.parse(responseText);
79
+ return responseText;
80
+ } catch (jsonError) {
81
+ throw new Error('Invalid JSON response from server');
82
+ }
83
+ } catch (error) {
84
+ clearTimeout(timeout);
85
+
86
+ // If it's a timeout or connection error, retry once
87
+ if ((error.name === 'AbortError' || error.code === 'ECONNRESET' || error.message.includes('timeout')) && retryCount === 0) {
88
+ console.error(`Request failed, retrying... (${error.message})`);
89
+ return makeRequest(url, payload, retryCount + 1);
90
+ }
91
+
92
+ throw error;
93
+ }
94
+ }
95
+
42
96
  // Forward all MCP requests directly to the server's MCP endpoint
43
97
  async function handleStdio() {
44
98
  let inputBuffer = '';
@@ -64,29 +118,21 @@ async function handleStdio() {
64
118
  }
65
119
 
66
120
  try {
67
- // Forward the MCP request directly to the server
68
- const response = await fetch(API_URL, {
69
- method: 'POST',
70
- headers: {
71
- 'Content-Type': 'application/json',
72
- 'Authorization': `Bearer ${API_TOKEN}`
73
- },
74
- body: JSON.stringify(payload)
75
- });
76
-
77
- const responseText = await response.text();
78
-
79
- if (!response.ok) {
80
- continue;
81
- }
82
-
83
- // Validate response is valid JSON before outputting
84
- try {
85
- JSON.parse(responseText);
86
- process.stdout.write(`${responseText}\n`);
87
- } catch (jsonError) {
88
- }
121
+ // Forward the MCP request directly to the server using the robust request function
122
+ const responseText = await makeRequest(API_URL, payload);
123
+ process.stdout.write(`${responseText}\n`);
89
124
  } catch (error) {
125
+ console.error(`MCP request failed: ${error.message}`);
126
+ // Send error response back to MCP client
127
+ const errorResponse = JSON.stringify({
128
+ jsonrpc: "2.0",
129
+ id: payload.id || null,
130
+ error: {
131
+ code: -32603,
132
+ message: `Request failed: ${error.message}`
133
+ }
134
+ });
135
+ process.stdout.write(`${errorResponse}\n`);
90
136
  }
91
137
  }
92
138
  });
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package",
3
3
  "name": "workfullcircle-mcp-local",
4
- "version": "1.4.0",
5
- "description": "Local STDIO MCP server for WorkFullCircle API with Antigravity path fixes",
4
+ "version": "1.4.1",
5
+ "description": "Local STDIO MCP server for WorkFullCircle API with connection leak fixes",
6
6
  "main": "index.js",
7
7
  "bin": {
8
8
  "workfullcircle-mcp-local": "index.js"
package/test.js DELETED
@@ -1,98 +0,0 @@
1
- const { spawn } = require('child_process');
2
- const path = require('path');
3
-
4
- // Test configuration
5
- const TEST_API_KEY = process.env.TEST_API_KEY || 'uam_test_key';
6
- const TEST_API_URL = process.env.TEST_API_URL || process.env.WFC_API_URL || 'https://workfullcircle.com/api';
7
-
8
- console.log('Testing @workfullcircle/mcp-local...');
9
- console.log('API URL:', TEST_API_URL);
10
- console.log('API Key:', TEST_API_KEY.substring(0, 10) + '...');
11
-
12
- // Spawn the MCP server
13
- const mcpServer = spawn('node', [path.join(__dirname, 'index.js')], {
14
- env: {
15
- ...process.env,
16
- WFC_API_URL: TEST_API_URL,
17
- WFC_API_KEY: TEST_API_KEY
18
- },
19
- stdio: ['pipe', 'pipe', 'pipe']
20
- });
21
-
22
- let responseBuffer = '';
23
-
24
- mcpServer.stdout.on('data', (data) => {
25
- responseBuffer += data.toString();
26
-
27
- // Try to parse complete JSON responses
28
- const lines = responseBuffer.split('\n');
29
- for (let i = 0; i < lines.length - 1; i++) {
30
- const line = lines[i].trim();
31
- if (line) {
32
- try {
33
- const response = JSON.parse(line);
34
- console.log('Response:', JSON.stringify(response, null, 2));
35
- } catch (e) {
36
- console.log('Non-JSON output:', line);
37
- }
38
- }
39
- }
40
- responseBuffer = lines[lines.length - 1];
41
- });
42
-
43
- mcpServer.stderr.on('data', (data) => {
44
- console.error('Error:', data.toString());
45
- });
46
-
47
- mcpServer.on('close', (code) => {
48
- console.log('Server exited with code:', code);
49
- });
50
-
51
- // Send test requests
52
- setTimeout(() => {
53
- console.log('Sending initialize request...');
54
- mcpServer.stdin.write(JSON.stringify({
55
- jsonrpc: '2.0',
56
- id: 1,
57
- method: 'initialize',
58
- params: {
59
- protocolVersion: '2024-11-05',
60
- capabilities: {},
61
- clientInfo: {
62
- name: 'test-client',
63
- version: '1.0.0'
64
- }
65
- }
66
- }) + '\n');
67
- }, 1000);
68
-
69
- setTimeout(() => {
70
- console.log('Sending tools/list request...');
71
- mcpServer.stdin.write(JSON.stringify({
72
- jsonrpc: '2.0',
73
- id: 2,
74
- method: 'tools/list'
75
- }) + '\n');
76
- }, 2000);
77
-
78
- setTimeout(() => {
79
- console.log('Sending tools/call request...');
80
- mcpServer.stdin.write(JSON.stringify({
81
- jsonrpc: '2.0',
82
- id: 3,
83
- method: 'tools/call',
84
- params: {
85
- name: 'save_memory',
86
- arguments: {
87
- content: 'Test memory from MCP local',
88
- sector: 'Semantic',
89
- tags: ['test', 'mcp-local']
90
- }
91
- }
92
- }) + '\n');
93
- }, 3000);
94
-
95
- setTimeout(() => {
96
- console.log('Terminating...');
97
- mcpServer.kill();
98
- }, 5000);