workfullcircle-mcp-local 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/index.js +221 -0
- package/package.json +34 -0
- package/test.js +98 -0
package/index.js
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fetch = require('node-fetch');
|
|
4
|
+
|
|
5
|
+
// Configuration from environment
|
|
6
|
+
const API_URL = process.env.WFC_API_URL || 'https://workfullcircle.com/api';
|
|
7
|
+
const API_KEY = process.env.WFC_API_KEY;
|
|
8
|
+
|
|
9
|
+
if (!API_KEY) {
|
|
10
|
+
console.error('Error: WFC_API_KEY environment variable is required');
|
|
11
|
+
process.exit(1);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// MCP Server implementation
|
|
15
|
+
class WorkFullCircleMCPServer {
|
|
16
|
+
constructor() {
|
|
17
|
+
this.tools = [
|
|
18
|
+
{
|
|
19
|
+
name: 'save_memory',
|
|
20
|
+
description: 'Save a memory to WorkFullCircle',
|
|
21
|
+
inputSchema: {
|
|
22
|
+
type: 'object',
|
|
23
|
+
properties: {
|
|
24
|
+
content: { type: 'string', description: 'Memory content to save' },
|
|
25
|
+
sector: { type: 'string', description: 'Memory sector (Semantic, Episodic, Procedural, Emotional, Reflective)' },
|
|
26
|
+
tags: { type: 'array', items: { type: 'string' }, description: 'Tags for the memory' }
|
|
27
|
+
},
|
|
28
|
+
required: ['content']
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
name: 'get_memory',
|
|
33
|
+
description: 'Retrieve memories from WorkFullCircle',
|
|
34
|
+
inputSchema: {
|
|
35
|
+
type: 'object',
|
|
36
|
+
properties: {
|
|
37
|
+
query: { type: 'string', description: 'Search query' },
|
|
38
|
+
limit: { type: 'number', description: 'Maximum number of results' },
|
|
39
|
+
sector: { type: 'string', description: 'Filter by sector' }
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
name: 'delete_memory',
|
|
45
|
+
description: 'Delete a memory from WorkFullCircle',
|
|
46
|
+
inputSchema: {
|
|
47
|
+
type: 'object',
|
|
48
|
+
properties: {
|
|
49
|
+
id: { type: 'string', description: 'Memory ID to delete' }
|
|
50
|
+
},
|
|
51
|
+
required: ['id']
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
name: 'update_memory',
|
|
56
|
+
description: 'Update a memory in WorkFullCircle',
|
|
57
|
+
inputSchema: {
|
|
58
|
+
type: 'object',
|
|
59
|
+
properties: {
|
|
60
|
+
id: { type: 'string', description: 'Memory ID to update' },
|
|
61
|
+
content: { type: 'string', description: 'Updated memory content' },
|
|
62
|
+
sector: { type: 'string', description: 'Updated memory sector' },
|
|
63
|
+
tags: { type: 'array', items: { type: 'string' }, description: 'Updated tags' }
|
|
64
|
+
},
|
|
65
|
+
required: ['id']
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
name: 'list_all_memories',
|
|
70
|
+
description: 'List all memories in WorkFullCircle',
|
|
71
|
+
inputSchema: {
|
|
72
|
+
type: 'object',
|
|
73
|
+
properties: {
|
|
74
|
+
limit: { type: 'number', description: 'Maximum number of results' },
|
|
75
|
+
offset: { type: 'number', description: 'Number of results to skip' }
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
];
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Handle MCP initialize request
|
|
83
|
+
handleInitialize(request) {
|
|
84
|
+
return {
|
|
85
|
+
jsonrpc: '2.0',
|
|
86
|
+
id: request.id,
|
|
87
|
+
result: {
|
|
88
|
+
protocolVersion: '2024-11-05',
|
|
89
|
+
capabilities: {
|
|
90
|
+
tools: {}
|
|
91
|
+
},
|
|
92
|
+
serverInfo: {
|
|
93
|
+
name: 'workfullcircle-mcp-local',
|
|
94
|
+
version: '1.0.0'
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Handle tools/list request
|
|
101
|
+
handleToolsList(request) {
|
|
102
|
+
return {
|
|
103
|
+
jsonrpc: '2.0',
|
|
104
|
+
id: request.id,
|
|
105
|
+
result: {
|
|
106
|
+
tools: this.tools
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Handle tools/call request
|
|
112
|
+
async handleToolsCall(request) {
|
|
113
|
+
const { name, arguments: args } = request.params;
|
|
114
|
+
|
|
115
|
+
try {
|
|
116
|
+
const result = await this.callAPI(name, args);
|
|
117
|
+
|
|
118
|
+
return {
|
|
119
|
+
jsonrpc: '2.0',
|
|
120
|
+
id: request.id,
|
|
121
|
+
result: {
|
|
122
|
+
content: [
|
|
123
|
+
{
|
|
124
|
+
type: 'text',
|
|
125
|
+
text: JSON.stringify(result, null, 2)
|
|
126
|
+
}
|
|
127
|
+
]
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
} catch (error) {
|
|
131
|
+
return {
|
|
132
|
+
jsonrpc: '2.0',
|
|
133
|
+
id: request.id,
|
|
134
|
+
error: {
|
|
135
|
+
code: -32603,
|
|
136
|
+
message: error.message
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Forward call to WorkFullCircle API
|
|
143
|
+
async callAPI(toolName, args) {
|
|
144
|
+
const endpoint = `${API_URL}/mcp/${toolName}`;
|
|
145
|
+
|
|
146
|
+
const response = await fetch(endpoint, {
|
|
147
|
+
method: 'POST',
|
|
148
|
+
headers: {
|
|
149
|
+
'Content-Type': 'application/json',
|
|
150
|
+
'Authorization': `Bearer ${API_KEY}`
|
|
151
|
+
},
|
|
152
|
+
body: JSON.stringify(args)
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
if (!response.ok) {
|
|
156
|
+
const errorText = await response.text();
|
|
157
|
+
throw new Error(`API Error ${response.status}: ${errorText}`);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return await response.json();
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Main request handler
|
|
164
|
+
async handleRequest(request) {
|
|
165
|
+
switch (request.method) {
|
|
166
|
+
case 'initialize':
|
|
167
|
+
return this.handleInitialize(request);
|
|
168
|
+
case 'tools/list':
|
|
169
|
+
return this.handleToolsList(request);
|
|
170
|
+
case 'tools/call':
|
|
171
|
+
return await this.handleToolsCall(request);
|
|
172
|
+
default:
|
|
173
|
+
return {
|
|
174
|
+
jsonrpc: '2.0',
|
|
175
|
+
id: request.id,
|
|
176
|
+
error: {
|
|
177
|
+
code: -32601,
|
|
178
|
+
message: 'Method not found'
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// STDIO communication
|
|
186
|
+
async function main() {
|
|
187
|
+
const server = new WorkFullCircleMCPServer();
|
|
188
|
+
|
|
189
|
+
process.stdin.setEncoding('utf8');
|
|
190
|
+
|
|
191
|
+
process.stdin.on('data', async (chunk) => {
|
|
192
|
+
const lines = chunk.split('\n');
|
|
193
|
+
|
|
194
|
+
for (const line of lines) {
|
|
195
|
+
if (!line.trim()) continue;
|
|
196
|
+
|
|
197
|
+
try {
|
|
198
|
+
const request = JSON.parse(line);
|
|
199
|
+
const response = await server.handleRequest(request);
|
|
200
|
+
process.stdout.write(JSON.stringify(response) + '\n');
|
|
201
|
+
} catch (error) {
|
|
202
|
+
console.error('Error processing request:', error.message);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
// Handle process termination
|
|
208
|
+
process.on('SIGINT', () => {
|
|
209
|
+
process.exit(0);
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
process.on('SIGTERM', () => {
|
|
213
|
+
process.exit(0);
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Start the server
|
|
218
|
+
main().catch(error => {
|
|
219
|
+
console.error('Fatal error:', error);
|
|
220
|
+
process.exit(1);
|
|
221
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "workfullcircle-mcp-local",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Local STDIO MCP server for WorkFullCircle API",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"workfullcircle-mcp-local": "index.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"start": "node index.js",
|
|
11
|
+
"test": "node test.js"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"mcp",
|
|
15
|
+
"stdio",
|
|
16
|
+
"workfullcircle",
|
|
17
|
+
"ai",
|
|
18
|
+
"memory",
|
|
19
|
+
"windsurf",
|
|
20
|
+
"antigravity"
|
|
21
|
+
],
|
|
22
|
+
"author": "Afreensiyad",
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"node-fetch": "^2.7.0"
|
|
26
|
+
},
|
|
27
|
+
"engines": {
|
|
28
|
+
"node": ">=16.0.0"
|
|
29
|
+
},
|
|
30
|
+
"publishConfig": {
|
|
31
|
+
"access": "public"
|
|
32
|
+
},
|
|
33
|
+
"homepage": "https://workfullcircle.com"
|
|
34
|
+
}
|
package/test.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
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 || '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);
|