workfullcircle-mcp-local 1.3.1 → 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 -32
  2. package/package.json +2 -2
  3. package/test.js +0 -98
package/index.js CHANGED
@@ -1,13 +1,13 @@
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);
7
9
 
8
10
  function printUsage() {
9
- process.stderr.write('Usage: workfullcircle-mcp-local --token <api-token> [--url <api-url>]\n');
10
- process.stderr.write('Environment variables: WFC_API_URL (default: https://workfullcircle.com)\n');
11
11
  process.exit(1);
12
12
  }
13
13
 
@@ -33,7 +33,6 @@ function parseArgs(argv) {
33
33
  }
34
34
 
35
35
  if (!parsed.token) {
36
- process.stderr.write('Error: --token argument or WFC_TOKEN environment variable is required\n');
37
36
  printUsage();
38
37
  }
39
38
 
@@ -42,6 +41,58 @@ function parseArgs(argv) {
42
41
 
43
42
  const { token: API_TOKEN, url: API_URL } = parseArgs(args);
44
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
+
45
96
  // Forward all MCP requests directly to the server's MCP endpoint
46
97
  async function handleStdio() {
47
98
  let inputBuffer = '';
@@ -63,46 +114,31 @@ async function handleStdio() {
63
114
  try {
64
115
  payload = JSON.parse(line);
65
116
  } catch (error) {
66
- process.stderr.write(`[WFC-Local] Invalid JSON input: ${error.message}\n`);
67
117
  continue;
68
118
  }
69
119
 
70
120
  try {
71
- // Forward the MCP request directly to the server
72
- const response = await fetch(API_URL, {
73
- method: 'POST',
74
- headers: {
75
- 'Content-Type': 'application/json',
76
- 'Authorization': `Bearer ${API_TOKEN}`
77
- },
78
- body: JSON.stringify(payload)
79
- });
80
-
81
- const responseText = await response.text();
82
-
83
- if (!response.ok) {
84
- process.stderr.write(`[WFC-Local] Remote error ${response.status}: ${responseText}\n`);
85
- continue;
86
- }
87
-
88
- // Validate response is valid JSON before outputting
89
- try {
90
- JSON.parse(responseText);
91
- process.stdout.write(`${responseText}\n`);
92
- } catch (jsonError) {
93
- process.stderr.write(`[WFC-Local] Invalid JSON response: ${jsonError.message}\n`);
94
- process.stderr.write(`[WFC-Local] Response was: ${responseText.substring(0, 200)}...\n`);
95
- }
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`);
96
124
  } catch (error) {
97
- process.stderr.write(`[WFC-Local] Request failed: ${error.message}\n`);
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`);
98
136
  }
99
137
  }
100
138
  });
101
139
  }
102
140
 
103
141
  async function main() {
104
- process.stderr.write(`[WFC-Local] Connected to MCP server at ${API_URL}\n`);
105
- process.stderr.write(`[WFC-Local] Using token: ${API_TOKEN.substring(0, 10)}...\n`);
106
142
  await handleStdio();
107
143
  }
108
144
 
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.3.1",
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);