@aris-mcp/server 1.0.2 → 2.1.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/dist/index.js +243 -643
- package/package.json +1 -2
package/dist/index.js
CHANGED
|
@@ -5,500 +5,14 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
5
5
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
6
|
import { z as z2 } from "zod";
|
|
7
7
|
|
|
8
|
-
// ../core/dist/redact.js
|
|
9
|
-
var SENSITIVE_KEYS = /* @__PURE__ */ new Set([
|
|
10
|
-
"ssn",
|
|
11
|
-
"password",
|
|
12
|
-
"api_key",
|
|
13
|
-
"email",
|
|
14
|
-
"credit",
|
|
15
|
-
"secret",
|
|
16
|
-
"token",
|
|
17
|
-
"authorization"
|
|
18
|
-
]);
|
|
19
|
-
var EMAIL_REGEX = /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g;
|
|
20
|
-
var SSN_REGEX = /\b\d{3}-\d{2}-\d{4}\b/g;
|
|
21
|
-
var PHONE_REGEX = /\b(\+?1[-.\s]?)?\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}\b/g;
|
|
22
|
-
function isSensitiveKey(key) {
|
|
23
|
-
const lower = key.toLowerCase();
|
|
24
|
-
for (const sensitive of SENSITIVE_KEYS) {
|
|
25
|
-
if (lower.includes(sensitive)) {
|
|
26
|
-
return true;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
return false;
|
|
30
|
-
}
|
|
31
|
-
function redactStringValue(value) {
|
|
32
|
-
let result = value;
|
|
33
|
-
result = result.replace(EMAIL_REGEX, "[REDACTED_EMAIL]");
|
|
34
|
-
result = result.replace(SSN_REGEX, "[REDACTED_SSN]");
|
|
35
|
-
result = result.replace(PHONE_REGEX, "[REDACTED_PHONE]");
|
|
36
|
-
return result;
|
|
37
|
-
}
|
|
38
|
-
function walkAndRedact(obj) {
|
|
39
|
-
if (obj === null || obj === void 0) {
|
|
40
|
-
return obj;
|
|
41
|
-
}
|
|
42
|
-
if (Array.isArray(obj)) {
|
|
43
|
-
return obj.map((item) => walkAndRedact(item));
|
|
44
|
-
}
|
|
45
|
-
if (typeof obj === "object") {
|
|
46
|
-
const result = {};
|
|
47
|
-
for (const [key, value] of Object.entries(obj)) {
|
|
48
|
-
if (isSensitiveKey(key)) {
|
|
49
|
-
result[key] = "[REDACTED]";
|
|
50
|
-
} else if (typeof value === "string") {
|
|
51
|
-
result[key] = redactStringValue(value);
|
|
52
|
-
} else {
|
|
53
|
-
result[key] = walkAndRedact(value);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
return result;
|
|
57
|
-
}
|
|
58
|
-
if (typeof obj === "string") {
|
|
59
|
-
return redactStringValue(obj);
|
|
60
|
-
}
|
|
61
|
-
return obj;
|
|
62
|
-
}
|
|
63
|
-
function redactPII(input) {
|
|
64
|
-
try {
|
|
65
|
-
const parsed = JSON.parse(input);
|
|
66
|
-
const redacted = walkAndRedact(parsed);
|
|
67
|
-
return JSON.stringify(redacted);
|
|
68
|
-
} catch {
|
|
69
|
-
return input;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// ../core/dist/compress.js
|
|
74
|
-
var STOP_WORDS = /* @__PURE__ */ new Set([
|
|
75
|
-
"the",
|
|
76
|
-
"is",
|
|
77
|
-
"at",
|
|
78
|
-
"of",
|
|
79
|
-
"on",
|
|
80
|
-
"and",
|
|
81
|
-
"a",
|
|
82
|
-
"to",
|
|
83
|
-
"in",
|
|
84
|
-
"for",
|
|
85
|
-
"it",
|
|
86
|
-
"this",
|
|
87
|
-
"that",
|
|
88
|
-
"with",
|
|
89
|
-
"from",
|
|
90
|
-
"by",
|
|
91
|
-
"an",
|
|
92
|
-
"be",
|
|
93
|
-
"as",
|
|
94
|
-
"are",
|
|
95
|
-
"was",
|
|
96
|
-
"were",
|
|
97
|
-
"been",
|
|
98
|
-
"has",
|
|
99
|
-
"have",
|
|
100
|
-
"had",
|
|
101
|
-
"do",
|
|
102
|
-
"does",
|
|
103
|
-
"did",
|
|
104
|
-
"will",
|
|
105
|
-
"would",
|
|
106
|
-
"could",
|
|
107
|
-
"should",
|
|
108
|
-
"can",
|
|
109
|
-
"may",
|
|
110
|
-
"might"
|
|
111
|
-
]);
|
|
112
|
-
function estimateTokens(text) {
|
|
113
|
-
return Math.ceil(text.length / 4);
|
|
114
|
-
}
|
|
115
|
-
function extractKeywords(query) {
|
|
116
|
-
const words = query.toLowerCase().replace(/[^\w\s]/g, "").split(/\s+/).filter((w) => w.length > 0 && !STOP_WORDS.has(w));
|
|
117
|
-
return new Set(words);
|
|
118
|
-
}
|
|
119
|
-
function splitSentences(text) {
|
|
120
|
-
return text.split(/(?<=[.?!])\s+/).map((s) => s.trim()).filter((s) => s.length > 0);
|
|
121
|
-
}
|
|
122
|
-
function scoreSentence(sentence, keywords) {
|
|
123
|
-
const words = sentence.toLowerCase().replace(/[^\w\s]/g, "").split(/\s+/);
|
|
124
|
-
let score = 0;
|
|
125
|
-
for (const word of words) {
|
|
126
|
-
if (keywords.has(word)) {
|
|
127
|
-
score++;
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
return score;
|
|
131
|
-
}
|
|
132
|
-
function compressContext(query, context) {
|
|
133
|
-
const originalTokens = estimateTokens(context);
|
|
134
|
-
const keywords = extractKeywords(query);
|
|
135
|
-
let compressed;
|
|
136
|
-
if (keywords.size === 0) {
|
|
137
|
-
compressed = context.length > 500 ? context.slice(0, 500) + "..." : context;
|
|
138
|
-
} else {
|
|
139
|
-
const sentences = splitSentences(context);
|
|
140
|
-
const relevant = sentences.filter((sentence) => scoreSentence(sentence, keywords) > 0);
|
|
141
|
-
if (relevant.length === 0) {
|
|
142
|
-
compressed = context.length > 500 ? context.slice(0, 500) + "..." : context;
|
|
143
|
-
} else {
|
|
144
|
-
compressed = relevant.join(" ");
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
const compressedTokens = estimateTokens(compressed);
|
|
148
|
-
const savedTokens = originalTokens - compressedTokens;
|
|
149
|
-
const savingsPercent = originalTokens > 0 ? Math.round(savedTokens / originalTokens * 100) : 0;
|
|
150
|
-
return {
|
|
151
|
-
original: context,
|
|
152
|
-
compressed,
|
|
153
|
-
originalTokens,
|
|
154
|
-
compressedTokens,
|
|
155
|
-
savedTokens,
|
|
156
|
-
savingsPercent
|
|
157
|
-
};
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
// ../core/dist/pipeline.js
|
|
161
|
-
var MAX_PROMPT_LENGTH = 1e5;
|
|
162
|
-
var MAX_CONTEXT_LENGTH = 5e5;
|
|
163
|
-
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
164
|
-
function sanitizeContext(context) {
|
|
165
|
-
let sanitized = context.replace(/<[^>]*>/g, "");
|
|
166
|
-
const injectionPatterns = [
|
|
167
|
-
/\[SYSTEM\]/gi,
|
|
168
|
-
/\[INST\]/gi,
|
|
169
|
-
/\[\/INST\]/gi,
|
|
170
|
-
/<<SYS>>/gi,
|
|
171
|
-
/<\/SYS>/gi,
|
|
172
|
-
/\[IMPORTANT\]/gi,
|
|
173
|
-
/\{system\}/gi,
|
|
174
|
-
/###\s*(?:system|instruction|admin)\s*:/gi,
|
|
175
|
-
/(?:^|\n)system\s*:\s*/gi,
|
|
176
|
-
/BEGIN SYSTEM PROMPT/gi,
|
|
177
|
-
/END SYSTEM PROMPT/gi,
|
|
178
|
-
/IGNORE PREVIOUS INSTRUCTIONS/gi,
|
|
179
|
-
/IGNORE ALL PREVIOUS/gi,
|
|
180
|
-
/YOU ARE NOW/gi,
|
|
181
|
-
/NEW INSTRUCTIONS:/gi,
|
|
182
|
-
/OVERRIDE:/gi
|
|
183
|
-
];
|
|
184
|
-
for (const pattern of injectionPatterns) {
|
|
185
|
-
sanitized = sanitized.replace(pattern, "");
|
|
186
|
-
}
|
|
187
|
-
return sanitized;
|
|
188
|
-
}
|
|
189
|
-
var ArisPipeline = class {
|
|
190
|
-
llm;
|
|
191
|
-
cache;
|
|
192
|
-
enableRedaction;
|
|
193
|
-
enableCompression;
|
|
194
|
-
debug;
|
|
195
|
-
constructor(config) {
|
|
196
|
-
this.llm = config.llmProvider;
|
|
197
|
-
this.cache = config.cache;
|
|
198
|
-
this.enableRedaction = config.enableRedaction ?? true;
|
|
199
|
-
this.enableCompression = config.enableCompression ?? true;
|
|
200
|
-
this.debug = config.debug ?? false;
|
|
201
|
-
}
|
|
202
|
-
async process(query, context, options) {
|
|
203
|
-
if (query.length > MAX_PROMPT_LENGTH) {
|
|
204
|
-
throw new Error(`Prompt exceeds maximum length of ${MAX_PROMPT_LENGTH} characters (got ${query.length})`);
|
|
205
|
-
}
|
|
206
|
-
if (context && context.length > MAX_CONTEXT_LENGTH) {
|
|
207
|
-
throw new Error(`Context exceeds maximum length of ${MAX_CONTEXT_LENGTH} characters (got ${context.length})`);
|
|
208
|
-
}
|
|
209
|
-
const sanitizedContext = context ? sanitizeContext(context) : "";
|
|
210
|
-
const originalTokens = estimateTokens(query + sanitizedContext);
|
|
211
|
-
const externalSignal = options?.signal;
|
|
212
|
-
const timeoutController = new AbortController();
|
|
213
|
-
let timeoutId;
|
|
214
|
-
if (!externalSignal) {
|
|
215
|
-
timeoutId = setTimeout(() => timeoutController.abort(), DEFAULT_TIMEOUT_MS);
|
|
216
|
-
}
|
|
217
|
-
const signal = externalSignal ?? timeoutController.signal;
|
|
218
|
-
try {
|
|
219
|
-
if (signal.aborted) {
|
|
220
|
-
throw new Error("Operation aborted");
|
|
221
|
-
}
|
|
222
|
-
const cacheKey = this.cache ? `aris:pipeline:${this.cache.hashRequest(query + sanitizedContext)}` : "";
|
|
223
|
-
if (this.cache && cacheKey) {
|
|
224
|
-
const cached = await this.cache.get(cacheKey);
|
|
225
|
-
if (cached) {
|
|
226
|
-
try {
|
|
227
|
-
const parsed = JSON.parse(cached);
|
|
228
|
-
this.log("Cache hit");
|
|
229
|
-
return { ...parsed, cached: true };
|
|
230
|
-
} catch {
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
let processedQuery = query;
|
|
235
|
-
let processedContext = sanitizedContext;
|
|
236
|
-
let redacted = false;
|
|
237
|
-
if (this.enableRedaction) {
|
|
238
|
-
processedQuery = redactPII(processedQuery);
|
|
239
|
-
if (processedContext) {
|
|
240
|
-
processedContext = redactPII(processedContext);
|
|
241
|
-
}
|
|
242
|
-
redacted = true;
|
|
243
|
-
this.log("PII redaction applied");
|
|
244
|
-
}
|
|
245
|
-
let compressed = false;
|
|
246
|
-
if (this.enableCompression && processedContext) {
|
|
247
|
-
const compression = compressContext(processedQuery, processedContext);
|
|
248
|
-
processedContext = compression.compressed;
|
|
249
|
-
compressed = true;
|
|
250
|
-
this.log(`Compression: ${compression.savedTokens} tokens saved (${compression.savingsPercent}%)`);
|
|
251
|
-
}
|
|
252
|
-
const prompt = processedContext ? `Context:
|
|
253
|
-
${processedContext}
|
|
254
|
-
|
|
255
|
-
Query: ${processedQuery}` : processedQuery;
|
|
256
|
-
const processedTokens = estimateTokens(prompt);
|
|
257
|
-
if (signal.aborted) {
|
|
258
|
-
throw new Error("Operation aborted");
|
|
259
|
-
}
|
|
260
|
-
this.log(`Sending to ${this.llm.name}`);
|
|
261
|
-
const llmResponse = await this.llm.send(prompt, { signal });
|
|
262
|
-
const savedTokens = originalTokens - processedTokens;
|
|
263
|
-
const savingsPercent = originalTokens > 0 ? Math.round(savedTokens / originalTokens * 100) : 0;
|
|
264
|
-
const result = {
|
|
265
|
-
response: llmResponse.content,
|
|
266
|
-
model: llmResponse.model,
|
|
267
|
-
originalTokens,
|
|
268
|
-
processedTokens,
|
|
269
|
-
savedTokens,
|
|
270
|
-
savingsPercent,
|
|
271
|
-
cached: false,
|
|
272
|
-
redacted,
|
|
273
|
-
compressed,
|
|
274
|
-
usage: llmResponse.usage
|
|
275
|
-
};
|
|
276
|
-
if (this.cache && cacheKey) {
|
|
277
|
-
await this.cache.set(cacheKey, JSON.stringify(result));
|
|
278
|
-
this.log("Response cached");
|
|
279
|
-
}
|
|
280
|
-
return result;
|
|
281
|
-
} finally {
|
|
282
|
-
if (timeoutId !== void 0) {
|
|
283
|
-
clearTimeout(timeoutId);
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
log(message) {
|
|
288
|
-
if (this.debug) {
|
|
289
|
-
process.stderr.write(`[aris:pipeline] ${message}
|
|
290
|
-
`);
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
};
|
|
294
|
-
|
|
295
|
-
// ../core/dist/providers/openrouter.js
|
|
296
|
-
var DEFAULT_MODEL = "minimax/minimax-m2.5";
|
|
297
|
-
var DEFAULT_BASE_URL = "https://openrouter.ai/api/v1";
|
|
298
|
-
var OpenRouterProvider = class {
|
|
299
|
-
name = "openrouter";
|
|
300
|
-
apiKey;
|
|
301
|
-
model;
|
|
302
|
-
baseUrl;
|
|
303
|
-
constructor(config) {
|
|
304
|
-
this.apiKey = config.apiKey;
|
|
305
|
-
this.model = config.model ?? DEFAULT_MODEL;
|
|
306
|
-
this.baseUrl = config.baseUrl ?? DEFAULT_BASE_URL;
|
|
307
|
-
}
|
|
308
|
-
async send(prompt, options) {
|
|
309
|
-
const model = options?.model ?? this.model;
|
|
310
|
-
const response = await fetch(`${this.baseUrl}/chat/completions`, {
|
|
311
|
-
method: "POST",
|
|
312
|
-
headers: {
|
|
313
|
-
Authorization: `Bearer ${this.apiKey}`,
|
|
314
|
-
"Content-Type": "application/json",
|
|
315
|
-
"HTTP-Referer": "https://aris.dev",
|
|
316
|
-
"X-Title": "Aris MCP"
|
|
317
|
-
},
|
|
318
|
-
body: JSON.stringify({
|
|
319
|
-
model,
|
|
320
|
-
messages: [{ role: "user", content: prompt }],
|
|
321
|
-
max_tokens: options?.maxTokens ?? 4096,
|
|
322
|
-
temperature: options?.temperature ?? 0.7
|
|
323
|
-
}),
|
|
324
|
-
signal: options?.signal
|
|
325
|
-
});
|
|
326
|
-
if (!response.ok) {
|
|
327
|
-
const errorText = await response.text();
|
|
328
|
-
throw new Error(`OpenRouter API error (${response.status}): ${errorText}`);
|
|
329
|
-
}
|
|
330
|
-
const data = await response.json();
|
|
331
|
-
const content = data.choices?.[0]?.message?.content ?? "";
|
|
332
|
-
return {
|
|
333
|
-
content,
|
|
334
|
-
model: data.model ?? model,
|
|
335
|
-
usage: data.usage ? {
|
|
336
|
-
promptTokens: data.usage.prompt_tokens,
|
|
337
|
-
completionTokens: data.usage.completion_tokens,
|
|
338
|
-
totalTokens: data.usage.total_tokens
|
|
339
|
-
} : void 0
|
|
340
|
-
};
|
|
341
|
-
}
|
|
342
|
-
async healthCheck() {
|
|
343
|
-
try {
|
|
344
|
-
const response = await fetch(`${this.baseUrl}/models`, {
|
|
345
|
-
headers: { Authorization: `Bearer ${this.apiKey}` }
|
|
346
|
-
});
|
|
347
|
-
return response.ok;
|
|
348
|
-
} catch {
|
|
349
|
-
return false;
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
};
|
|
353
|
-
|
|
354
|
-
// ../core/dist/providers/ollama.js
|
|
355
|
-
var DEFAULT_MODEL2 = "llama3";
|
|
356
|
-
var DEFAULT_BASE_URL2 = "http://localhost:11434";
|
|
357
|
-
var OllamaProvider = class {
|
|
358
|
-
name = "ollama";
|
|
359
|
-
model;
|
|
360
|
-
baseUrl;
|
|
361
|
-
constructor(config = {}) {
|
|
362
|
-
this.model = config.model ?? DEFAULT_MODEL2;
|
|
363
|
-
this.baseUrl = config.baseUrl ?? DEFAULT_BASE_URL2;
|
|
364
|
-
}
|
|
365
|
-
async send(prompt, options) {
|
|
366
|
-
const model = options?.model ?? this.model;
|
|
367
|
-
const response = await fetch(`${this.baseUrl}/api/chat`, {
|
|
368
|
-
method: "POST",
|
|
369
|
-
headers: { "Content-Type": "application/json" },
|
|
370
|
-
body: JSON.stringify({
|
|
371
|
-
model,
|
|
372
|
-
messages: [{ role: "user", content: prompt }],
|
|
373
|
-
stream: false,
|
|
374
|
-
options: {
|
|
375
|
-
num_predict: options?.maxTokens ?? 4096,
|
|
376
|
-
temperature: options?.temperature ?? 0.7
|
|
377
|
-
}
|
|
378
|
-
}),
|
|
379
|
-
signal: options?.signal
|
|
380
|
-
});
|
|
381
|
-
if (!response.ok) {
|
|
382
|
-
const errorText = await response.text();
|
|
383
|
-
throw new Error(`Ollama API error (${response.status}): ${errorText}`);
|
|
384
|
-
}
|
|
385
|
-
const data = await response.json();
|
|
386
|
-
const promptTokens = data.prompt_eval_count ?? 0;
|
|
387
|
-
const completionTokens = data.eval_count ?? 0;
|
|
388
|
-
return {
|
|
389
|
-
content: data.message?.content ?? "",
|
|
390
|
-
model: data.model ?? model,
|
|
391
|
-
usage: {
|
|
392
|
-
promptTokens,
|
|
393
|
-
completionTokens,
|
|
394
|
-
totalTokens: promptTokens + completionTokens
|
|
395
|
-
}
|
|
396
|
-
};
|
|
397
|
-
}
|
|
398
|
-
async healthCheck() {
|
|
399
|
-
try {
|
|
400
|
-
const response = await fetch(`${this.baseUrl}/api/tags`);
|
|
401
|
-
return response.ok;
|
|
402
|
-
} catch {
|
|
403
|
-
return false;
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
};
|
|
407
|
-
|
|
408
|
-
// ../core/dist/cache.js
|
|
409
|
-
import { createHash } from "crypto";
|
|
410
|
-
import { Redis } from "ioredis";
|
|
411
|
-
var ArisCache = class {
|
|
412
|
-
redis;
|
|
413
|
-
constructor(redisUrl) {
|
|
414
|
-
this.redis = new Redis(redisUrl ?? "redis://localhost:6379", {
|
|
415
|
-
lazyConnect: true,
|
|
416
|
-
retryStrategy: (times) => {
|
|
417
|
-
if (times > 3)
|
|
418
|
-
return null;
|
|
419
|
-
return Math.min(times * 200, 2e3);
|
|
420
|
-
}
|
|
421
|
-
});
|
|
422
|
-
this.redis.on("error", (err) => {
|
|
423
|
-
process.stderr.write(`[ArisCache] Redis connection error: ${err.message}
|
|
424
|
-
`);
|
|
425
|
-
});
|
|
426
|
-
this.redis.connect().catch((err) => {
|
|
427
|
-
process.stderr.write(`[ArisCache] Failed to connect to Redis: ${err.message}
|
|
428
|
-
`);
|
|
429
|
-
});
|
|
430
|
-
}
|
|
431
|
-
async get(key) {
|
|
432
|
-
try {
|
|
433
|
-
return await this.redis.get(key);
|
|
434
|
-
} catch (err) {
|
|
435
|
-
console.warn(`[ArisCache] get failed: ${err.message}`);
|
|
436
|
-
return null;
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
async set(key, value, ttlSeconds = 600) {
|
|
440
|
-
try {
|
|
441
|
-
await this.redis.set(key, value, "EX", ttlSeconds);
|
|
442
|
-
} catch (err) {
|
|
443
|
-
console.warn(`[ArisCache] set failed: ${err.message}`);
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
hashRequest(body) {
|
|
447
|
-
return createHash("sha256").update(body).digest("hex");
|
|
448
|
-
}
|
|
449
|
-
async ping() {
|
|
450
|
-
try {
|
|
451
|
-
const result = await this.redis.ping();
|
|
452
|
-
return result === "PONG";
|
|
453
|
-
} catch {
|
|
454
|
-
return false;
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
async checkThrottle(maxJoules = 5e3) {
|
|
458
|
-
try {
|
|
459
|
-
const value = await this.redis.get("aris_system_joules");
|
|
460
|
-
if (value === null)
|
|
461
|
-
return false;
|
|
462
|
-
const joules = parseFloat(value);
|
|
463
|
-
return joules > maxJoules;
|
|
464
|
-
} catch (err) {
|
|
465
|
-
console.warn(`[ArisCache] checkThrottle failed: ${err.message}`);
|
|
466
|
-
return false;
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
async disconnect() {
|
|
470
|
-
try {
|
|
471
|
-
await this.redis.quit();
|
|
472
|
-
} catch {
|
|
473
|
-
}
|
|
474
|
-
}
|
|
475
|
-
};
|
|
476
|
-
|
|
477
8
|
// src/config.ts
|
|
478
|
-
function envBool(value, defaultValue) {
|
|
479
|
-
if (value === void 0) return defaultValue;
|
|
480
|
-
return value.toLowerCase() === "true";
|
|
481
|
-
}
|
|
482
9
|
function loadConfig() {
|
|
483
|
-
const
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
if (llmProvider === "openrouter" && !llmApiKey) {
|
|
487
|
-
throw new Error(
|
|
488
|
-
"ARIS_API_KEY is required when ARIS_LLM_PROVIDER is 'openrouter'"
|
|
489
|
-
);
|
|
10
|
+
const apiKey = process.env.ARIS_API_KEY;
|
|
11
|
+
if (!apiKey) {
|
|
12
|
+
throw new Error("ARIS_API_KEY is required");
|
|
490
13
|
}
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
llmProvider,
|
|
494
|
-
llmApiKey,
|
|
495
|
-
llmModel: process.env.ARIS_LLM_MODEL,
|
|
496
|
-
ollamaUrl,
|
|
497
|
-
redisUrl: process.env.ARIS_REDIS_URL,
|
|
498
|
-
enableRedaction: envBool(process.env.ARIS_ENABLE_REDACTION, true),
|
|
499
|
-
enableCompression: envBool(process.env.ARIS_ENABLE_COMPRESSION, true),
|
|
500
|
-
debug: envBool(process.env.ARIS_DEBUG, false)
|
|
501
|
-
};
|
|
14
|
+
const apiUrl = process.env.ARIS_API_URL ?? "https://energetic-light-production.up.railway.app";
|
|
15
|
+
return { apiKey, apiUrl };
|
|
502
16
|
}
|
|
503
17
|
|
|
504
18
|
// src/tools.ts
|
|
@@ -581,24 +95,183 @@ var TOOL_DEFINITIONS = [
|
|
|
581
95
|
}
|
|
582
96
|
];
|
|
583
97
|
|
|
98
|
+
// src/setup.ts
|
|
99
|
+
import { createInterface } from "readline/promises";
|
|
100
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
|
|
101
|
+
import { join } from "path";
|
|
102
|
+
import { homedir } from "os";
|
|
103
|
+
var BOLD = "\x1B[1m";
|
|
104
|
+
var DIM = "\x1B[2m";
|
|
105
|
+
var GREEN = "\x1B[32m";
|
|
106
|
+
var CYAN = "\x1B[36m";
|
|
107
|
+
var YELLOW = "\x1B[33m";
|
|
108
|
+
var RED = "\x1B[31m";
|
|
109
|
+
var RESET = "\x1B[0m";
|
|
110
|
+
var MCP_CONFIG = (apiKey) => ({
|
|
111
|
+
aris: {
|
|
112
|
+
command: "npx",
|
|
113
|
+
args: ["-y", "@aris-mcp/server"],
|
|
114
|
+
env: {
|
|
115
|
+
ARIS_API_KEY: apiKey
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
function getIdeTargets() {
|
|
120
|
+
const home = homedir();
|
|
121
|
+
return [
|
|
122
|
+
{
|
|
123
|
+
name: "Claude Code",
|
|
124
|
+
configPath: join(home, ".claude", "settings.json"),
|
|
125
|
+
configKey: "mcpServers"
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
name: "Cursor",
|
|
129
|
+
configPath: join(home, ".cursor", "mcp.json"),
|
|
130
|
+
configKey: "mcpServers"
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
name: "VS Code",
|
|
134
|
+
configPath: join(home, ".vscode", "mcp.json"),
|
|
135
|
+
configKey: "servers"
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
name: "Windsurf",
|
|
139
|
+
configPath: join(home, ".codeium", "windsurf", "mcp_config.json"),
|
|
140
|
+
configKey: "mcpServers"
|
|
141
|
+
}
|
|
142
|
+
];
|
|
143
|
+
}
|
|
144
|
+
function detectInstalledIdes() {
|
|
145
|
+
const targets = getIdeTargets();
|
|
146
|
+
const home = homedir();
|
|
147
|
+
return targets.filter((ide) => {
|
|
148
|
+
if (existsSync(ide.configPath)) return true;
|
|
149
|
+
const dir = ide.configPath.substring(0, ide.configPath.lastIndexOf("/"));
|
|
150
|
+
if (existsSync(dir)) return true;
|
|
151
|
+
if (process.platform === "darwin") {
|
|
152
|
+
const appNames = {
|
|
153
|
+
"Claude Code": [],
|
|
154
|
+
// CLI-based, check for .claude dir
|
|
155
|
+
"Cursor": ["/Applications/Cursor.app"],
|
|
156
|
+
"VS Code": ["/Applications/Visual Studio Code.app"],
|
|
157
|
+
"Windsurf": ["/Applications/Windsurf.app"]
|
|
158
|
+
};
|
|
159
|
+
const paths = appNames[ide.name] ?? [];
|
|
160
|
+
return paths.some((p) => existsSync(p));
|
|
161
|
+
}
|
|
162
|
+
return false;
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
function readJsonFile(path) {
|
|
166
|
+
try {
|
|
167
|
+
const content = readFileSync(path, "utf-8");
|
|
168
|
+
return JSON.parse(content);
|
|
169
|
+
} catch {
|
|
170
|
+
return {};
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
function writeJsonFile(path, data) {
|
|
174
|
+
const dir = path.substring(0, path.lastIndexOf("/"));
|
|
175
|
+
mkdirSync(dir, { recursive: true });
|
|
176
|
+
writeFileSync(path, JSON.stringify(data, null, 2) + "\n", "utf-8");
|
|
177
|
+
}
|
|
178
|
+
function configureIde(ide, apiKey) {
|
|
179
|
+
try {
|
|
180
|
+
const config = readJsonFile(ide.configPath);
|
|
181
|
+
const servers = config[ide.configKey] ?? {};
|
|
182
|
+
if (servers.aris) {
|
|
183
|
+
const existing = servers.aris;
|
|
184
|
+
const env = existing.env ?? {};
|
|
185
|
+
env.ARIS_API_KEY = apiKey;
|
|
186
|
+
existing.env = env;
|
|
187
|
+
} else {
|
|
188
|
+
servers.aris = MCP_CONFIG(apiKey).aris;
|
|
189
|
+
}
|
|
190
|
+
config[ide.configKey] = servers;
|
|
191
|
+
writeJsonFile(ide.configPath, config);
|
|
192
|
+
return true;
|
|
193
|
+
} catch {
|
|
194
|
+
return false;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
async function runSetup() {
|
|
198
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
199
|
+
console.log("");
|
|
200
|
+
console.log(` ${BOLD}Aris MCP Server${RESET} ${DIM}v2.0.0${RESET}`);
|
|
201
|
+
console.log(` ${DIM}Optimize every LLM call${RESET}`);
|
|
202
|
+
console.log("");
|
|
203
|
+
console.log(` ${CYAN}Step 1${RESET} ${DIM}/${RESET} API Key`);
|
|
204
|
+
console.log(` ${DIM}Get yours at https://aris.dev${RESET}`);
|
|
205
|
+
console.log("");
|
|
206
|
+
const apiKey = await rl.question(` ${BOLD}ARIS_API_KEY:${RESET} `);
|
|
207
|
+
if (!apiKey.trim()) {
|
|
208
|
+
console.log(`
|
|
209
|
+
${RED}No API key provided. Exiting.${RESET}
|
|
210
|
+
`);
|
|
211
|
+
rl.close();
|
|
212
|
+
process.exit(1);
|
|
213
|
+
}
|
|
214
|
+
console.log("");
|
|
215
|
+
console.log(` ${CYAN}Step 2${RESET} ${DIM}/${RESET} Detecting IDEs...`);
|
|
216
|
+
console.log("");
|
|
217
|
+
const detected = detectInstalledIdes();
|
|
218
|
+
if (detected.length === 0) {
|
|
219
|
+
console.log(` ${YELLOW}No supported IDEs detected.${RESET}`);
|
|
220
|
+
console.log("");
|
|
221
|
+
console.log(` ${DIM}Manually add to your MCP config:${RESET}`);
|
|
222
|
+
console.log("");
|
|
223
|
+
console.log(` ${DIM}${JSON.stringify({ mcpServers: MCP_CONFIG(apiKey.trim()) }, null, 2).split("\n").join("\n ")}${RESET}`);
|
|
224
|
+
console.log("");
|
|
225
|
+
rl.close();
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
for (const ide of detected) {
|
|
229
|
+
console.log(` ${GREEN}found${RESET} ${ide.name} ${DIM}${ide.configPath}${RESET}`);
|
|
230
|
+
}
|
|
231
|
+
console.log("");
|
|
232
|
+
const answer = await rl.question(` ${BOLD}Configure ${detected.length} IDE${detected.length > 1 ? "s" : ""}? [Y/n]${RESET} `);
|
|
233
|
+
if (answer.trim().toLowerCase() === "n") {
|
|
234
|
+
console.log(`
|
|
235
|
+
${DIM}Skipped. Add ARIS_API_KEY to your MCP config manually.${RESET}
|
|
236
|
+
`);
|
|
237
|
+
rl.close();
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
console.log("");
|
|
241
|
+
let configured = 0;
|
|
242
|
+
for (const ide of detected) {
|
|
243
|
+
const ok = configureIde(ide, apiKey.trim());
|
|
244
|
+
if (ok) {
|
|
245
|
+
console.log(` ${GREEN}done${RESET} ${ide.name}`);
|
|
246
|
+
configured++;
|
|
247
|
+
} else {
|
|
248
|
+
console.log(` ${RED}fail${RESET} ${ide.name} ${DIM}(check permissions)${RESET}`);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
console.log("");
|
|
252
|
+
if (configured > 0) {
|
|
253
|
+
console.log(` ${GREEN}${BOLD}Aris configured in ${configured} IDE${configured > 1 ? "s" : ""}.${RESET}`);
|
|
254
|
+
console.log(` ${DIM}Restart your IDE to activate.${RESET}`);
|
|
255
|
+
console.log("");
|
|
256
|
+
console.log(` ${DIM}Tools available:${RESET}`);
|
|
257
|
+
console.log(` ${CYAN}aris_optimize${RESET} ${DIM}Full pipeline: redact + compress + LLM${RESET}`);
|
|
258
|
+
console.log(` ${CYAN}aris_compress${RESET} ${DIM}Context compression only${RESET}`);
|
|
259
|
+
console.log(` ${CYAN}aris_health${RESET} ${DIM}Check pipeline status${RESET}`);
|
|
260
|
+
}
|
|
261
|
+
console.log("");
|
|
262
|
+
rl.close();
|
|
263
|
+
}
|
|
264
|
+
|
|
584
265
|
// src/index.ts
|
|
585
266
|
function log(message) {
|
|
586
267
|
process.stderr.write(`[aris-mcp] ${message}
|
|
587
268
|
`);
|
|
588
269
|
}
|
|
589
|
-
function createLLMProvider(config) {
|
|
590
|
-
if (config.llmProvider === "ollama") {
|
|
591
|
-
return new OllamaProvider({
|
|
592
|
-
baseUrl: config.ollamaUrl,
|
|
593
|
-
model: config.llmModel
|
|
594
|
-
});
|
|
595
|
-
}
|
|
596
|
-
return new OpenRouterProvider({
|
|
597
|
-
apiKey: config.llmApiKey,
|
|
598
|
-
model: config.llmModel
|
|
599
|
-
});
|
|
600
|
-
}
|
|
601
270
|
async function main() {
|
|
271
|
+
if (!process.env.ARIS_API_KEY && process.stdin.isTTY) {
|
|
272
|
+
await runSetup();
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
602
275
|
let config;
|
|
603
276
|
try {
|
|
604
277
|
config = loadConfig();
|
|
@@ -606,111 +279,67 @@ async function main() {
|
|
|
606
279
|
log(`Configuration error: ${err.message}`);
|
|
607
280
|
process.exit(1);
|
|
608
281
|
}
|
|
609
|
-
log(`
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
282
|
+
log(`API: ${config.apiUrl}`);
|
|
283
|
+
async function apiCall(path, body) {
|
|
284
|
+
const res = await fetch(`${config.apiUrl}${path}`, {
|
|
285
|
+
method: body ? "POST" : "GET",
|
|
286
|
+
headers: {
|
|
287
|
+
Authorization: `Bearer ${config.apiKey}`,
|
|
288
|
+
"Content-Type": "application/json"
|
|
289
|
+
},
|
|
290
|
+
body: body ? JSON.stringify(body) : void 0,
|
|
291
|
+
signal: AbortSignal.timeout(35e3)
|
|
292
|
+
});
|
|
293
|
+
const data = await res.json();
|
|
294
|
+
return { status: res.status, data };
|
|
618
295
|
}
|
|
619
|
-
const pipeline = new ArisPipeline({
|
|
620
|
-
llmProvider,
|
|
621
|
-
cache,
|
|
622
|
-
enableRedaction: config.enableRedaction,
|
|
623
|
-
enableCompression: config.enableCompression,
|
|
624
|
-
debug: config.debug
|
|
625
|
-
});
|
|
626
296
|
const server = new McpServer(
|
|
627
|
-
{
|
|
628
|
-
|
|
629
|
-
version: "1.0.0"
|
|
630
|
-
},
|
|
631
|
-
{
|
|
632
|
-
capabilities: {
|
|
633
|
-
tools: {}
|
|
634
|
-
}
|
|
635
|
-
}
|
|
297
|
+
{ name: "aris-mcp", version: "2.0.0" },
|
|
298
|
+
{ capabilities: { tools: {} } }
|
|
636
299
|
);
|
|
637
300
|
server.tool(
|
|
638
301
|
ToolName.OPTIMIZE,
|
|
639
302
|
TOOL_DESCRIPTIONS[ToolName.OPTIMIZE],
|
|
640
303
|
{
|
|
641
|
-
prompt: z2.string().min(1
|
|
642
|
-
"The user prompt to optimize and send through the Aris pipeline.
|
|
304
|
+
prompt: z2.string().min(1).max(1e5).describe(
|
|
305
|
+
"The user prompt to optimize and send through the Aris pipeline."
|
|
643
306
|
),
|
|
644
|
-
context: z2.string().max(5e5
|
|
645
|
-
"Optional background context to compress before including with the prompt.
|
|
307
|
+
context: z2.string().max(5e5).optional().describe(
|
|
308
|
+
"Optional background context to compress before including with the prompt."
|
|
646
309
|
)
|
|
647
310
|
},
|
|
648
|
-
async ({ prompt, context }
|
|
311
|
+
async ({ prompt, context }) => {
|
|
649
312
|
try {
|
|
650
|
-
await
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
message: "Starting Aris optimization pipeline..."
|
|
657
|
-
}
|
|
658
|
-
});
|
|
659
|
-
await sendNotification({
|
|
660
|
-
method: "notifications/progress",
|
|
661
|
-
params: {
|
|
662
|
-
progressToken: "aris_optimize",
|
|
663
|
-
progress: 20,
|
|
664
|
-
total: 100,
|
|
665
|
-
message: "Applying PII redaction and context compression..."
|
|
666
|
-
}
|
|
667
|
-
});
|
|
668
|
-
const controller = new AbortController();
|
|
669
|
-
const timeout = setTimeout(() => controller.abort(), 3e4);
|
|
670
|
-
let result;
|
|
671
|
-
try {
|
|
672
|
-
result = await pipeline.process(prompt, context, {
|
|
673
|
-
signal: controller.signal
|
|
674
|
-
});
|
|
675
|
-
} finally {
|
|
676
|
-
clearTimeout(timeout);
|
|
313
|
+
const { status, data } = await apiCall("/optimize", { prompt, context });
|
|
314
|
+
if (status !== 200) {
|
|
315
|
+
return {
|
|
316
|
+
content: [{ type: "text", text: `Pipeline error: ${data.error ?? "Unknown error"}` }],
|
|
317
|
+
isError: true
|
|
318
|
+
};
|
|
677
319
|
}
|
|
678
|
-
await sendNotification({
|
|
679
|
-
method: "notifications/progress",
|
|
680
|
-
params: {
|
|
681
|
-
progressToken: "aris_optimize",
|
|
682
|
-
progress: 100,
|
|
683
|
-
total: 100,
|
|
684
|
-
message: "Pipeline complete."
|
|
685
|
-
}
|
|
686
|
-
});
|
|
687
320
|
const summary = [
|
|
688
|
-
|
|
321
|
+
data.response,
|
|
689
322
|
"",
|
|
690
323
|
"--- Aris Pipeline Stats ---",
|
|
691
|
-
`Model: ${
|
|
692
|
-
`Original tokens: ${
|
|
693
|
-
`Processed tokens: ${
|
|
694
|
-
`Tokens saved: ${
|
|
695
|
-
`Cached: ${
|
|
696
|
-
`Redacted: ${
|
|
697
|
-
`Compressed: ${
|
|
324
|
+
`Model: ${data.model}`,
|
|
325
|
+
`Original tokens: ${data.originalTokens}`,
|
|
326
|
+
`Processed tokens: ${data.processedTokens}`,
|
|
327
|
+
`Tokens saved: ${data.savedTokens} (${data.savingsPercent}%)`,
|
|
328
|
+
`Cached: ${data.cached}`,
|
|
329
|
+
`Redacted: ${data.redacted}`,
|
|
330
|
+
`Compressed: ${data.compressed}`
|
|
698
331
|
];
|
|
699
|
-
|
|
332
|
+
const usage = data.usage;
|
|
333
|
+
if (usage) {
|
|
700
334
|
summary.push(
|
|
701
|
-
`LLM usage - prompt: ${
|
|
335
|
+
`LLM usage - prompt: ${usage.promptTokens}, completion: ${usage.completionTokens}, total: ${usage.totalTokens}`
|
|
702
336
|
);
|
|
703
337
|
}
|
|
704
|
-
return {
|
|
705
|
-
content: [{ type: "text", text: summary.join("\n") }]
|
|
706
|
-
};
|
|
338
|
+
return { content: [{ type: "text", text: summary.join("\n") }] };
|
|
707
339
|
} catch (err) {
|
|
708
340
|
const message = err instanceof Error ? err.message : String(err);
|
|
709
|
-
const errorText = message.includes("aborted") ? "Pipeline timed out
|
|
710
|
-
return {
|
|
711
|
-
content: [{ type: "text", text: errorText }],
|
|
712
|
-
isError: true
|
|
713
|
-
};
|
|
341
|
+
const errorText = message.includes("TimeoutError") || message.includes("aborted") ? "Pipeline timed out" : message.includes("fetch") ? "Aris API unavailable" : `Pipeline error: ${message}`;
|
|
342
|
+
return { content: [{ type: "text", text: errorText }], isError: true };
|
|
714
343
|
}
|
|
715
344
|
}
|
|
716
345
|
);
|
|
@@ -720,42 +349,18 @@ async function main() {
|
|
|
720
349
|
{},
|
|
721
350
|
async () => {
|
|
722
351
|
try {
|
|
723
|
-
const
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
cache: {
|
|
732
|
-
enabled: !!cache,
|
|
733
|
-
healthy: cacheHealthy,
|
|
734
|
-
url: config.redisUrl ? "(configured)" : "(not configured)"
|
|
735
|
-
},
|
|
736
|
-
features: {
|
|
737
|
-
redaction: config.enableRedaction,
|
|
738
|
-
compression: config.enableCompression
|
|
739
|
-
},
|
|
740
|
-
debug: config.debug
|
|
741
|
-
};
|
|
742
|
-
return {
|
|
743
|
-
content: [
|
|
744
|
-
{
|
|
745
|
-
type: "text",
|
|
746
|
-
text: JSON.stringify(status, null, 2)
|
|
747
|
-
}
|
|
748
|
-
]
|
|
749
|
-
};
|
|
352
|
+
const { status, data } = await apiCall("/health");
|
|
353
|
+
if (status !== 200) {
|
|
354
|
+
return {
|
|
355
|
+
content: [{ type: "text", text: `Health check error: ${data.error ?? "Unknown error"}` }],
|
|
356
|
+
isError: true
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
750
360
|
} catch (err) {
|
|
751
361
|
const message = err instanceof Error ? err.message : String(err);
|
|
752
362
|
return {
|
|
753
|
-
content: [
|
|
754
|
-
{
|
|
755
|
-
type: "text",
|
|
756
|
-
text: `Health check error: ${message}`
|
|
757
|
-
}
|
|
758
|
-
],
|
|
363
|
+
content: [{ type: "text", text: `Health check error: ${message}` }],
|
|
759
364
|
isError: true
|
|
760
365
|
};
|
|
761
366
|
}
|
|
@@ -765,37 +370,36 @@ async function main() {
|
|
|
765
370
|
ToolName.COMPRESS,
|
|
766
371
|
TOOL_DESCRIPTIONS[ToolName.COMPRESS],
|
|
767
372
|
{
|
|
768
|
-
query: z2.string().min(1
|
|
769
|
-
"The query used to determine which sentences in the context are relevant.
|
|
373
|
+
query: z2.string().min(1).max(1e5).describe(
|
|
374
|
+
"The query used to determine which sentences in the context are relevant."
|
|
770
375
|
),
|
|
771
|
-
context: z2.string().min(1
|
|
772
|
-
"The context text to compress.
|
|
376
|
+
context: z2.string().min(1).max(5e5).describe(
|
|
377
|
+
"The context text to compress."
|
|
773
378
|
)
|
|
774
379
|
},
|
|
775
380
|
async ({ query, context }) => {
|
|
776
381
|
try {
|
|
777
|
-
const
|
|
382
|
+
const { status, data } = await apiCall("/compress", { query, context });
|
|
383
|
+
if (status !== 200) {
|
|
384
|
+
return {
|
|
385
|
+
content: [{ type: "text", text: `Compression error: ${data.error ?? "Unknown error"}` }],
|
|
386
|
+
isError: true
|
|
387
|
+
};
|
|
388
|
+
}
|
|
778
389
|
const summary = [
|
|
779
390
|
"Compressed context:",
|
|
780
|
-
|
|
391
|
+
data.compressed,
|
|
781
392
|
"",
|
|
782
393
|
"--- Compression Stats ---",
|
|
783
|
-
`Original tokens: ${
|
|
784
|
-
`Compressed tokens: ${
|
|
785
|
-
`Tokens saved: ${
|
|
394
|
+
`Original tokens: ${data.originalTokens}`,
|
|
395
|
+
`Compressed tokens: ${data.compressedTokens}`,
|
|
396
|
+
`Tokens saved: ${data.savedTokens} (${data.savingsPercent}%)`
|
|
786
397
|
];
|
|
787
|
-
return {
|
|
788
|
-
content: [{ type: "text", text: summary.join("\n") }]
|
|
789
|
-
};
|
|
398
|
+
return { content: [{ type: "text", text: summary.join("\n") }] };
|
|
790
399
|
} catch (err) {
|
|
791
400
|
const message = err instanceof Error ? err.message : String(err);
|
|
792
401
|
return {
|
|
793
|
-
content: [
|
|
794
|
-
{
|
|
795
|
-
type: "text",
|
|
796
|
-
text: `Compression error: ${message}`
|
|
797
|
-
}
|
|
798
|
-
],
|
|
402
|
+
content: [{ type: "text", text: `Compression error: ${message}` }],
|
|
799
403
|
isError: true
|
|
800
404
|
};
|
|
801
405
|
}
|
|
@@ -807,12 +411,8 @@ async function main() {
|
|
|
807
411
|
const shutdown = async () => {
|
|
808
412
|
log("Shutting down...");
|
|
809
413
|
try {
|
|
810
|
-
if (cache) {
|
|
811
|
-
await cache.disconnect();
|
|
812
|
-
}
|
|
813
414
|
await server.close();
|
|
814
|
-
} catch
|
|
815
|
-
log(`Error during shutdown: ${err.message}`);
|
|
415
|
+
} catch {
|
|
816
416
|
}
|
|
817
417
|
process.exit(0);
|
|
818
418
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aris-mcp/server",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"aris-mcp": "dist/index.js"
|
|
@@ -31,7 +31,6 @@
|
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
34
|
-
"ioredis": "^5.6.1",
|
|
35
34
|
"zod": "^3.24.4"
|
|
36
35
|
},
|
|
37
36
|
"devDependencies": {
|