@torqon/mcp 0.2.0 → 0.2.2
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/dist/index.js +56 -44
- package/dist/install.js +8 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -11,6 +11,10 @@ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
|
|
|
11
11
|
import { z } from 'zod';
|
|
12
12
|
const API_URL = process.env.TORQON_API_URL ?? 'https://torqon-production.up.railway.app';
|
|
13
13
|
const API_KEY = process.env.TORQON_API_KEY ?? '';
|
|
14
|
+
if (!API_KEY) {
|
|
15
|
+
process.stderr.write('[Torqon] TORQON_API_KEY is not set. All memory operations will fail.\n');
|
|
16
|
+
process.stderr.write('[Torqon] Run: npx -y @torqon/mcp@latest add <client> --api-key <your-key>\n');
|
|
17
|
+
}
|
|
14
18
|
// Stable session ID — shared across all tool calls in this Claude Desktop session.
|
|
15
19
|
// No user intervention needed. Resets when Claude Desktop restarts.
|
|
16
20
|
const SESSION_ID = `mcp-${new Date().toISOString().slice(0, 10)}-${Math.random().toString(36).slice(2, 7)}`;
|
|
@@ -18,6 +22,24 @@ const headers = {
|
|
|
18
22
|
'Content-Type': 'application/json',
|
|
19
23
|
...(API_KEY ? { 'X-Api-Key': API_KEY } : {}),
|
|
20
24
|
};
|
|
25
|
+
async function apiPost(path, body) {
|
|
26
|
+
try {
|
|
27
|
+
const res = await fetch(`${API_URL}${path}`, {
|
|
28
|
+
method: 'POST',
|
|
29
|
+
headers,
|
|
30
|
+
body: JSON.stringify(body),
|
|
31
|
+
});
|
|
32
|
+
let data = {};
|
|
33
|
+
try {
|
|
34
|
+
data = await res.json();
|
|
35
|
+
}
|
|
36
|
+
catch { /* non-JSON body */ }
|
|
37
|
+
return { ok: res.ok, status: res.status, data };
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
return { ok: false, status: 0, data: { error: err.message ?? 'Network error' } };
|
|
41
|
+
}
|
|
42
|
+
}
|
|
21
43
|
// ── Gibberish filter ─────────────────────────────────────────────────────────
|
|
22
44
|
// Strips noise from power-user prompts before sending to Torqon.
|
|
23
45
|
// Removes: random symbols, excessive punctuation, repeated chars,
|
|
@@ -100,31 +122,21 @@ server.tool('auto_process', 'CALL THIS FIRST on every user message. Stores new f
|
|
|
100
122
|
content: [{ type: 'text', text: 'Message too short or noisy — no memory operation needed.' }],
|
|
101
123
|
};
|
|
102
124
|
}
|
|
125
|
+
if (!API_KEY) {
|
|
126
|
+
return { content: [{ type: 'text', text: '[Torqon] No API key configured. Run: npx -y @torqon/mcp@latest add <client> --api-key <your-key>' }] };
|
|
127
|
+
}
|
|
103
128
|
// Fire store and retrieve in parallel
|
|
104
|
-
const [,
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
headers,
|
|
108
|
-
body: JSON.stringify({
|
|
109
|
-
conversationId: SESSION_ID,
|
|
110
|
-
message: cleaned,
|
|
111
|
-
storeOnly: true,
|
|
112
|
-
apiKey: API_KEY,
|
|
113
|
-
}),
|
|
114
|
-
}),
|
|
115
|
-
fetch(`${API_URL}/chat`, {
|
|
116
|
-
method: 'POST',
|
|
117
|
-
headers,
|
|
118
|
-
body: JSON.stringify({
|
|
119
|
-
conversationId: SESSION_ID,
|
|
120
|
-
message: cleaned,
|
|
121
|
-
rawFacts: true,
|
|
122
|
-
apiKey: API_KEY,
|
|
123
|
-
}),
|
|
124
|
-
}),
|
|
129
|
+
const [, retrieve] = await Promise.all([
|
|
130
|
+
apiPost('/chat', { conversationId: SESSION_ID, message: cleaned, storeOnly: true }),
|
|
131
|
+
apiPost('/chat', { conversationId: SESSION_ID, message: cleaned, rawFacts: true }),
|
|
125
132
|
]);
|
|
126
|
-
|
|
127
|
-
|
|
133
|
+
if (!retrieve.ok) {
|
|
134
|
+
const msg = retrieve.status === 401
|
|
135
|
+
? '[Torqon] Invalid API key. Check your TORQON_API_KEY.'
|
|
136
|
+
: `[Torqon] API error ${retrieve.status}: ${retrieve.data?.error ?? 'unknown'}`;
|
|
137
|
+
return { content: [{ type: 'text', text: msg }] };
|
|
138
|
+
}
|
|
139
|
+
const context = retrieve.data?.response?.content ?? '';
|
|
128
140
|
return {
|
|
129
141
|
content: [{
|
|
130
142
|
type: 'text',
|
|
@@ -141,21 +153,21 @@ server.tool('store_memory', 'Explicitly stores an important fact or decision int
|
|
|
141
153
|
message: z.string().describe('The fact or decision to store'),
|
|
142
154
|
}, async ({ message }) => {
|
|
143
155
|
const cleaned = cleanMessage(message);
|
|
156
|
+
if (!API_KEY) {
|
|
157
|
+
return { content: [{ type: 'text', text: '[Torqon] No API key configured. Run: npx -y @torqon/mcp@latest add <client> --api-key <your-key>' }] };
|
|
158
|
+
}
|
|
144
159
|
if (!hasSignal(cleaned)) {
|
|
145
160
|
return {
|
|
146
161
|
content: [{ type: 'text', text: 'Nothing meaningful to store.' }],
|
|
147
162
|
};
|
|
148
163
|
}
|
|
149
|
-
await
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
apiKey: API_KEY,
|
|
157
|
-
}),
|
|
158
|
-
});
|
|
164
|
+
const result = await apiPost('/chat', { conversationId: SESSION_ID, message: cleaned, storeOnly: true });
|
|
165
|
+
if (!result.ok) {
|
|
166
|
+
const msg = result.status === 401
|
|
167
|
+
? '[Torqon] Invalid API key. Check your TORQON_API_KEY.'
|
|
168
|
+
: `[Torqon] Store failed (${result.status}): ${result.data?.error ?? 'unknown error'}`;
|
|
169
|
+
return { content: [{ type: 'text', text: msg }] };
|
|
170
|
+
}
|
|
159
171
|
return {
|
|
160
172
|
content: [{ type: 'text', text: `Stored in Torqon memory.` }],
|
|
161
173
|
};
|
|
@@ -166,19 +178,19 @@ server.tool('store_memory', 'Explicitly stores an important fact or decision int
|
|
|
166
178
|
server.tool('retrieve_context', 'Retrieves relevant facts from Torqon memory for a specific question. Use when you need to look up something specific.', {
|
|
167
179
|
query: z.string().describe('The question or topic to look up in memory'),
|
|
168
180
|
}, async ({ query }) => {
|
|
181
|
+
if (!API_KEY) {
|
|
182
|
+
return { content: [{ type: 'text', text: '[Torqon] No API key configured. Run: npx -y @torqon/mcp@latest add <client> --api-key <your-key>' }] };
|
|
183
|
+
}
|
|
169
184
|
const cleaned = cleanMessage(query);
|
|
170
|
-
const
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
}),
|
|
178
|
-
});
|
|
179
|
-
const data = await response.json();
|
|
185
|
+
const result = await apiPost('/chat', { conversationId: SESSION_ID, message: cleaned });
|
|
186
|
+
if (!result.ok) {
|
|
187
|
+
const msg = result.status === 401
|
|
188
|
+
? '[Torqon] Invalid API key. Check your TORQON_API_KEY.'
|
|
189
|
+
: `[Torqon] Retrieval failed (${result.status}): ${result.data?.error ?? 'unknown error'}`;
|
|
190
|
+
return { content: [{ type: 'text', text: msg }] };
|
|
191
|
+
}
|
|
180
192
|
return {
|
|
181
|
-
content: [{ type: 'text', text: data
|
|
193
|
+
content: [{ type: 'text', text: result.data?.response?.content ?? '[Torqon] No context found.' }],
|
|
182
194
|
};
|
|
183
195
|
});
|
|
184
196
|
// ── optimize_context ─────────────────────────────────────────────────────────
|
package/dist/install.js
CHANGED
|
@@ -49,7 +49,14 @@ function getConfigPath(client) {
|
|
|
49
49
|
return { path: join(home, 'Library/Application Support/Zed/settings.json'), format: 'json' };
|
|
50
50
|
return { path: join(home, '.config/zed/settings.json'), format: 'json' };
|
|
51
51
|
}
|
|
52
|
-
|
|
52
|
+
if (client === 'vscode') {
|
|
53
|
+
if (os === 'win32')
|
|
54
|
+
return { path: `${process.env.APPDATA}\\Code\\User\\globalStorage\\saoudrizwan.claude-dev\\settings\\cline_mcp_settings.json`, format: 'json' };
|
|
55
|
+
if (os === 'darwin')
|
|
56
|
+
return { path: join(home, 'Library/Application Support/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json'), format: 'json' };
|
|
57
|
+
return { path: join(home, '.config/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json'), format: 'json' };
|
|
58
|
+
}
|
|
59
|
+
throw new Error(`Unknown client: ${client}. Supported: claude, cursor, windsurf, codex, zed, vscode`);
|
|
53
60
|
}
|
|
54
61
|
function installJson(client, configPath, apiKey, apiUrl) {
|
|
55
62
|
const configDir = configPath.substring(0, Math.max(configPath.lastIndexOf('\\'), configPath.lastIndexOf('/')));
|