clay-server 2.47.0-beta.3 → 2.47.0-beta.4

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.
@@ -1,359 +0,0 @@
1
- var fs = require("fs");
2
- var path = require("path");
3
- var config = require("./config");
4
-
5
- var sqlite;
6
- var _availabilityError = null;
7
- try {
8
- sqlite = require("node:sqlite");
9
- } catch (e) {
10
- sqlite = null;
11
- _availabilityError = "Mate datastores require Node 22.13.0 or newer with node:sqlite available.";
12
- }
13
-
14
- function parseNodeVersion(version) {
15
- var parts = String(version || "").split(".");
16
- return {
17
- major: parseInt(parts[0] || "0", 10) || 0,
18
- minor: parseInt(parts[1] || "0", 10) || 0,
19
- patch: parseInt(parts[2] || "0", 10) || 0,
20
- };
21
- }
22
-
23
- function assertNodeVersion() {
24
- var v = parseNodeVersion(process.versions.node);
25
- if (v.major < 22 || (v.major === 22 && v.minor < 13)) {
26
- throw new Error("Mate datastores require Node 22.13.0 or newer.");
27
- }
28
- }
29
- try {
30
- assertNodeVersion();
31
- } catch (e) {
32
- if (!_availabilityError) _availabilityError = e.message;
33
- }
34
-
35
- var DatabaseSync = sqlite ? sqlite.DatabaseSync : null;
36
-
37
- var MAX_ROWS = 200;
38
- var MAX_RESULT_BYTES = 1024 * 1024;
39
- var DB_SIZE_WARNING_BYTES = 100 * 1024 * 1024;
40
- var PRAGMA_BUSY_TIMEOUT = 5000;
41
- var CLAY_META_VERSION = "1";
42
-
43
- var _dbCache = {};
44
-
45
- function isMateDatastoreAvailable() {
46
- return !!DatabaseSync && !_availabilityError;
47
- }
48
-
49
- function getMateDatastoreAvailabilityError() {
50
- return _availabilityError || null;
51
- }
52
-
53
- function assertAvailable() {
54
- if (!isMateDatastoreAvailable()) {
55
- throw new Error(getMateDatastoreAvailabilityError() || "Mate datastore is unavailable.");
56
- }
57
- }
58
-
59
- function getMateDbPath(opts) {
60
- if (opts && opts.dbPath) return String(opts.dbPath);
61
- if (opts && opts.mateDir) return path.join(String(opts.mateDir), "store.db");
62
- var userId = opts && opts.userId ? String(opts.userId) : "default";
63
- var mateId = opts && opts.mateId ? String(opts.mateId) : null;
64
- if (!mateId) throw new Error("Mate datastore requires a mateId.");
65
- return path.join(config.CONFIG_DIR, "mates", userId, mateId, "store.db");
66
- }
67
-
68
- function ensureParentDir(filePath) {
69
- fs.mkdirSync(path.dirname(filePath), { recursive: true });
70
- }
71
-
72
- function getDbSizeBytes(dbPath) {
73
- try {
74
- return fs.statSync(dbPath).size;
75
- } catch (e) {
76
- return 0;
77
- }
78
- }
79
-
80
- function openDatabase(dbPath) {
81
- var db = new DatabaseSync(dbPath);
82
- try { db.exec("PRAGMA journal_mode = WAL"); } catch (e) {}
83
- try { db.exec("PRAGMA foreign_keys = ON"); } catch (e2) {}
84
- try { db.exec("PRAGMA busy_timeout = " + PRAGMA_BUSY_TIMEOUT); } catch (e3) {}
85
- return db;
86
- }
87
-
88
- function initClayMeta(db) {
89
- var now = new Date().toISOString();
90
- db.exec("CREATE TABLE IF NOT EXISTS clay_meta (key TEXT PRIMARY KEY, value TEXT NOT NULL)");
91
- var stmt = db.prepare("INSERT OR IGNORE INTO clay_meta (key, value) VALUES (?, ?)");
92
- stmt.run("clay_meta_version", CLAY_META_VERSION);
93
- stmt.run("created_at", now);
94
- stmt.run("last_opened_at", now);
95
- db.prepare("UPDATE clay_meta SET value = ? WHERE key = ?").run(now, "last_opened_at");
96
- }
97
-
98
- function ensureMateDatastore(opts) {
99
- assertAvailable();
100
- var dbPath = getMateDbPath(opts);
101
- if (_dbCache[dbPath] && _dbCache[dbPath].db) return _dbCache[dbPath];
102
- ensureParentDir(dbPath);
103
- var db = openDatabase(dbPath);
104
- initClayMeta(db);
105
- var wrapper = {
106
- db: db,
107
- dbPath: dbPath,
108
- sizeBytes: getDbSizeBytes(dbPath),
109
- warning: getDbSizeBytes(dbPath) > DB_SIZE_WARNING_BYTES ? "Mate datastore exceeds 100 MB soft warning threshold." : null,
110
- };
111
- _dbCache[dbPath] = wrapper;
112
- return wrapper;
113
- }
114
-
115
- function openMateDatastore(opts) {
116
- return ensureMateDatastore(opts);
117
- }
118
-
119
- function closeMateDatastore(handle) {
120
- var wrapper = unwrapHandle(handle);
121
- if (!wrapper || !wrapper.db) return;
122
- try {
123
- wrapper.db.close();
124
- } catch (e) {}
125
- if (wrapper.dbPath && _dbCache[wrapper.dbPath]) delete _dbCache[wrapper.dbPath];
126
- }
127
-
128
- function closeAllMateDatastores() {
129
- var keys = Object.keys(_dbCache);
130
- for (var i = 0; i < keys.length; i++) {
131
- closeMateDatastore(_dbCache[keys[i]]);
132
- }
133
- }
134
-
135
- function unwrapHandle(handle) {
136
- if (!handle) return null;
137
- if (handle.db && handle.dbPath) return handle;
138
- return { db: handle, dbPath: null, sizeBytes: 0, warning: null };
139
- }
140
-
141
- function normalizeSql(sql) {
142
- var text = String(sql || "");
143
- text = text.replace(/^\s*(?:--[^\n]*\n|\/\*[\s\S]*?\*\/\s*)*/g, "");
144
- return text.trim();
145
- }
146
-
147
- function getFirstKeyword(sql) {
148
- var text = normalizeSql(sql);
149
- var match = text.match(/^([A-Za-z]+)/);
150
- return match ? match[1].toUpperCase() : "";
151
- }
152
-
153
- function hasMultipleStatements(sql) {
154
- var text = normalizeSql(sql);
155
- if (text.indexOf(";") === -1) return false;
156
- return !/;\s*$/.test(text) || text.slice(0, -1).indexOf(";") !== -1;
157
- }
158
-
159
- function isForbiddenSql(sql) {
160
- var text = normalizeSql(sql).toUpperCase();
161
- var banned = [
162
- "ATTACH DATABASE",
163
- "DETACH DATABASE",
164
- "LOAD_EXTENSION",
165
- "LOAD EXTENSION",
166
- ];
167
- for (var i = 0; i < banned.length; i++) {
168
- if (text.indexOf(banned[i]) !== -1) return banned[i];
169
- }
170
- if (/PRAGMA\s+(?!table_info|table_xinfo|index_list|index_info|foreign_key_list)/i.test(text)) {
171
- return "PRAGMA";
172
- }
173
- return "";
174
- }
175
-
176
- function isReadOnlyQuery(sql) {
177
- var kw = getFirstKeyword(sql);
178
- if (kw === "SELECT" || kw === "WITH") return true;
179
- return false;
180
- }
181
-
182
- function isAllowedExec(sql) {
183
- var kw = getFirstKeyword(sql);
184
- return kw === "CREATE" || kw === "ALTER" || kw === "DROP" || kw === "INSERT" || kw === "UPDATE" || kw === "DELETE";
185
- }
186
-
187
- function bindParams(stmt, params) {
188
- if (!params) return stmt;
189
- if (!Array.isArray(params)) return stmt;
190
- return stmt.run.apply(stmt, params);
191
- }
192
-
193
- function runQuery(handle, sql, params, limits) {
194
- var wrapper = unwrapHandle(handle);
195
- if (!wrapper || !wrapper.db) {
196
- return makeError("MATE_DATASTORE_UNAVAILABLE", "Mate datastore is not available.");
197
- }
198
- var text = normalizeSql(sql);
199
- if (!text) return makeError("SQLITE_QUERY_REJECTED", "Query SQL is required.");
200
- if (hasMultipleStatements(text)) return makeError("SQLITE_QUERY_REJECTED", "Multiple statements are not allowed in query mode.");
201
- var forbidden = isForbiddenSql(text);
202
- if (forbidden) return makeError("SQLITE_FORBIDDEN", forbidden + " is not allowed in Mate datastores.");
203
- if (!isReadOnlyQuery(text)) return makeError("SQLITE_QUERY_REJECTED", "Only SELECT and WITH queries are allowed.");
204
-
205
- try {
206
- var stmt = wrapper.db.prepare(text);
207
- var rows = Array.isArray(params) ? stmt.all.apply(stmt, params) : stmt.all();
208
- rows = sanitizeValue(rows);
209
- var rowCount = rows.length;
210
- var maxRows = limits && typeof limits.maxRows === "number" ? limits.maxRows : MAX_ROWS;
211
- var truncated = false;
212
- if (rows.length > maxRows) {
213
- rows = rows.slice(0, maxRows);
214
- truncated = true;
215
- }
216
- var result = {
217
- ok: true,
218
- rows: rows,
219
- rowCount: rowCount,
220
- truncated: truncated,
221
- };
222
- if (wrapper.warning) result.warning = wrapper.warning;
223
- if (limits && limits.includeSizeInfo) {
224
- result.sizeBytes = wrapper.sizeBytes;
225
- }
226
- if (Buffer.byteLength(JSON.stringify(result), "utf8") > (limits && limits.maxBytes ? limits.maxBytes : MAX_RESULT_BYTES)) {
227
- return makeError("SQLITE_RESULT_TOO_LARGE", "Query result exceeds the 1 MB response limit.");
228
- }
229
- return result;
230
- } catch (e) {
231
- return normalizeSqliteError(e, "SQLITE_EXEC_FAILED", "Query failed.");
232
- }
233
- }
234
-
235
- function runExec(handle, sql, params, limits) {
236
- var wrapper = unwrapHandle(handle);
237
- if (!wrapper || !wrapper.db) {
238
- return makeError("MATE_DATASTORE_UNAVAILABLE", "Mate datastore is not available.");
239
- }
240
- var text = normalizeSql(sql);
241
- if (!text) return makeError("MATE_DATASTORE_BAD_INPUT", "SQL is required.");
242
- if (hasMultipleStatements(text)) return makeError("SQLITE_EXEC_FAILED", "Multiple statements are not allowed in exec mode.");
243
- var forbidden = isForbiddenSql(text);
244
- if (forbidden) return makeError("SQLITE_FORBIDDEN", forbidden + " is not allowed in Mate datastores.");
245
- if (!isAllowedExec(text)) return makeError("SQLITE_EXEC_FAILED", "Only CREATE, ALTER, DROP, INSERT, UPDATE, and DELETE are allowed in exec mode.");
246
-
247
- try {
248
- var stmt = wrapper.db.prepare(text);
249
- var runResult = Array.isArray(params) ? stmt.run.apply(stmt, params) : stmt.run();
250
- var result = {
251
- ok: true,
252
- changes: typeof runResult.changes === "number" ? runResult.changes : 0,
253
- lastInsertRowid: typeof runResult.lastInsertRowid !== "undefined" ? sanitizeValue(runResult.lastInsertRowid) : null,
254
- };
255
- if (wrapper.warning) result.warning = wrapper.warning;
256
- if (limits && limits.includeSizeInfo) {
257
- result.sizeBytes = getDbSizeBytes(wrapper.dbPath);
258
- }
259
- if (Buffer.byteLength(JSON.stringify(result), "utf8") > (limits && limits.maxBytes ? limits.maxBytes : MAX_RESULT_BYTES)) {
260
- return makeError("SQLITE_RESULT_TOO_LARGE", "Execution result exceeds the 1 MB response limit.");
261
- }
262
- wrapper.sizeBytes = getDbSizeBytes(wrapper.dbPath);
263
- if (wrapper.sizeBytes > DB_SIZE_WARNING_BYTES) {
264
- wrapper.warning = "Mate datastore exceeds 100 MB soft warning threshold.";
265
- result.warning = wrapper.warning;
266
- }
267
- return result;
268
- } catch (e) {
269
- return normalizeSqliteError(e, "SQLITE_EXEC_FAILED", "Execution failed.");
270
- }
271
- }
272
-
273
- function listSchemaObjects(handle) {
274
- var wrapper = unwrapHandle(handle);
275
- if (!wrapper || !wrapper.db) {
276
- return makeError("MATE_DATASTORE_UNAVAILABLE", "Mate datastore is not available.");
277
- }
278
- try {
279
- var rows = wrapper.db.prepare(
280
- "SELECT name, type, sql FROM sqlite_master WHERE type IN ('table', 'view', 'index') AND name NOT LIKE 'sqlite_%' AND name NOT LIKE 'clay_%' ORDER BY type, name"
281
- ).all();
282
- return { ok: true, objects: rows };
283
- } catch (e) {
284
- return normalizeSqliteError(e, "SQLITE_EXEC_FAILED", "Failed to list schema objects.");
285
- }
286
- }
287
-
288
- function describeTable(handle, tableName) {
289
- var wrapper = unwrapHandle(handle);
290
- if (!wrapper || !wrapper.db) {
291
- return makeError("MATE_DATASTORE_UNAVAILABLE", "Mate datastore is not available.");
292
- }
293
- if (!isSafeIdentifier(tableName)) {
294
- return makeError("MATE_DATASTORE_BAD_INPUT", "Table name is invalid.");
295
- }
296
- try {
297
- var info = wrapper.db.prepare("SELECT name, type, sql FROM sqlite_master WHERE name = ? AND type IN ('table', 'view')").get(tableName);
298
- if (!info) return makeError("SQLITE_TABLE_NOT_FOUND", "Table not found.");
299
- var columns = wrapper.db.prepare("PRAGMA table_info(" + quoteIdentifier(tableName) + ")").all();
300
- var indexes = wrapper.db.prepare("PRAGMA index_list(" + quoteIdentifier(tableName) + ")").all();
301
- return {
302
- ok: true,
303
- table: tableName,
304
- columns: columns,
305
- indexes: indexes,
306
- createSql: info.sql || null,
307
- };
308
- } catch (e) {
309
- return normalizeSqliteError(e, "SQLITE_EXEC_FAILED", "Failed to describe table.");
310
- }
311
- }
312
-
313
- function isSafeIdentifier(name) {
314
- return typeof name === "string" && /^[A-Za-z_][A-Za-z0-9_]*$/.test(name);
315
- }
316
-
317
- function quoteIdentifier(name) {
318
- return '"' + String(name).replace(/"/g, '""') + '"';
319
- }
320
-
321
- function makeError(code, message) {
322
- return { ok: false, code: code, message: message };
323
- }
324
-
325
- function sanitizeValue(value) {
326
- if (typeof value === "bigint") return value.toString();
327
- if (Array.isArray(value)) return value.map(sanitizeValue);
328
- if (value && typeof value === "object") {
329
- var out = {};
330
- var keys = Object.keys(value);
331
- for (var i = 0; i < keys.length; i++) {
332
- out[keys[i]] = sanitizeValue(value[keys[i]]);
333
- }
334
- return out;
335
- }
336
- return value;
337
- }
338
-
339
- function normalizeSqliteError(err, fallbackCode, fallbackMessage) {
340
- var message = err && err.message ? String(err.message) : fallbackMessage;
341
- var code = fallbackCode;
342
- if (message.indexOf("no such table") !== -1) code = "SQLITE_TABLE_NOT_FOUND";
343
- if (message.indexOf("no such column") !== -1) code = "SQLITE_QUERY_REJECTED";
344
- return { ok: false, code: code, message: message };
345
- }
346
-
347
- module.exports = {
348
- isMateDatastoreAvailable: isMateDatastoreAvailable,
349
- getMateDatastoreAvailabilityError: getMateDatastoreAvailabilityError,
350
- openMateDatastore: openMateDatastore,
351
- ensureMateDatastore: ensureMateDatastore,
352
- listSchemaObjects: listSchemaObjects,
353
- describeTable: describeTable,
354
- runQuery: runQuery,
355
- runExec: runExec,
356
- closeMateDatastore: closeMateDatastore,
357
- closeAllMateDatastores: closeAllMateDatastores,
358
- getMateDbPath: getMateDbPath,
359
- };
@@ -1,232 +0,0 @@
1
- var z = require("zod");
2
- var datastore = require("./mate-datastore");
3
- var FEATURE_ENABLED = false;
4
-
5
- function attachMateDatastore(ctx) {
6
- var cwd = ctx.cwd;
7
- var isMate = ctx.isMate;
8
- var send = ctx.send;
9
- var sendTo = ctx.sendTo;
10
-
11
- function isFeatureAvailable() {
12
- return FEATURE_ENABLED && datastore.isMateDatastoreAvailable();
13
- }
14
-
15
- function ensureProjectDatastore() {
16
- if (!FEATURE_ENABLED) {
17
- return { ok: false, code: "MATE_DATASTORE_NOT_ALLOWED", message: "Mate datastore is not enabled." };
18
- }
19
- if (!isMate) {
20
- return { ok: false, code: "MATE_DATASTORE_NOT_ALLOWED", message: "Mate datastore is only available in Mate sessions." };
21
- }
22
- try {
23
- return datastore.ensureMateDatastore({ mateDir: cwd });
24
- } catch (e) {
25
- return { ok: false, code: "MATE_DATASTORE_UNAVAILABLE", message: e.message || "Mate datastore is unavailable." };
26
- }
27
- }
28
-
29
- function getDatastoreWarning(handle) {
30
- if (!handle || !handle.warning) return null;
31
- return handle.warning;
32
- }
33
-
34
- function normalizeParams(input) {
35
- if (!input) return [];
36
- if (Array.isArray(input.params)) return input.params;
37
- return [];
38
- }
39
-
40
- function normalizeToolResult(result, requestId) {
41
- var payload = result || { ok: false, code: "MATE_DATASTORE_UNAVAILABLE", message: "Mate datastore is unavailable." };
42
- if (typeof requestId !== "undefined") payload.requestId = requestId;
43
- return payload;
44
- }
45
-
46
- function callToolInternal(toolName, input) {
47
- var handle = ensureProjectDatastore();
48
- if (!handle || handle.ok === false) {
49
- return normalizeToolResult(handle, input && input.requestId);
50
- }
51
-
52
- var warning = getDatastoreWarning(handle);
53
- var params = normalizeParams(input);
54
-
55
- if (toolName === "clay_db_query") {
56
- var queryResult = datastore.runQuery(handle, input.sql, params, { maxRows: 200, maxBytes: 1024 * 1024, includeSizeInfo: true });
57
- if (warning && queryResult.ok && !queryResult.warning) queryResult.warning = warning;
58
- return normalizeToolResult(queryResult, input && input.requestId);
59
- }
60
-
61
- if (toolName === "clay_db_exec") {
62
- var execResult = datastore.runExec(handle, input.sql, params, { maxBytes: 1024 * 1024, includeSizeInfo: true });
63
- if (warning && execResult.ok && !execResult.warning) execResult.warning = warning;
64
- if (execResult.ok) {
65
- broadcastDbChange({ tool: toolName, sql: input.sql, changes: execResult.changes || 0 });
66
- }
67
- return normalizeToolResult(execResult, input && input.requestId);
68
- }
69
-
70
- if (toolName === "clay_db_tables") {
71
- var tablesResult = datastore.listSchemaObjects(handle);
72
- if (warning && tablesResult.ok && !tablesResult.warning) tablesResult.warning = warning;
73
- return normalizeToolResult(tablesResult, input && input.requestId);
74
- }
75
-
76
- if (toolName === "clay_db_describe") {
77
- var describeResult = datastore.describeTable(handle, input.table);
78
- if (warning && describeResult.ok && !describeResult.warning) describeResult.warning = warning;
79
- return normalizeToolResult(describeResult, input && input.requestId);
80
- }
81
-
82
- return normalizeToolResult({ ok: false, code: "MATE_DATASTORE_NOT_ALLOWED", message: "Unknown datastore tool: " + toolName }, input && input.requestId);
83
- }
84
-
85
- function broadcastDbChange(details) {
86
- var payload = {
87
- type: "mate_db_change",
88
- details: details || {},
89
- };
90
- send(payload);
91
- }
92
-
93
- function handleMateDatastoreMessage(ws, msg) {
94
- if (msg.type !== "mate_db_tables" && msg.type !== "mate_db_describe" && msg.type !== "mate_db_query" && msg.type !== "mate_db_exec") {
95
- return false;
96
- }
97
-
98
- if (!FEATURE_ENABLED) {
99
- return false;
100
- }
101
-
102
- if (!isMate) {
103
- sendTo(ws, {
104
- type: "mate_db_error",
105
- requestId: msg.requestId || null,
106
- code: "MATE_DATASTORE_NOT_ALLOWED",
107
- message: "Mate datastore is only available in Mate sessions.",
108
- });
109
- return true;
110
- }
111
-
112
- if (msg.type === "mate_db_tables") {
113
- sendResult(ws, "mate_db_tables_result", callToolInternal("clay_db_tables", msg));
114
- return true;
115
- }
116
-
117
- if (msg.type === "mate_db_describe") {
118
- sendResult(ws, "mate_db_describe_result", callToolInternal("clay_db_describe", msg));
119
- return true;
120
- }
121
-
122
- if (msg.type === "mate_db_query") {
123
- sendResult(ws, "mate_db_query_result", callToolInternal("clay_db_query", msg));
124
- return true;
125
- }
126
-
127
- if (msg.type === "mate_db_exec") {
128
- sendResult(ws, "mate_db_exec_result", callToolInternal("clay_db_exec", msg));
129
- return true;
130
- }
131
-
132
- return true;
133
- }
134
-
135
- function sendResult(ws, type, result) {
136
- var payload = result || { ok: false, code: "MATE_DATASTORE_UNAVAILABLE", message: "Mate datastore is unavailable." };
137
- payload.type = type;
138
- sendTo(ws, payload);
139
- }
140
-
141
- function getToolDefinitions() {
142
- if (!isMate || !isFeatureAvailable()) return [];
143
- return [
144
- {
145
- name: "clay_db_query",
146
- description: "Execute read-only SQL against the current Mate datastore.",
147
- inputSchema: {
148
- sql: z.string().min(1).describe("SQL query"),
149
- params: z.array(z.any()).optional().describe("Positional parameters"),
150
- },
151
- handler: function (input) {
152
- return callToolInternal("clay_db_query", input || {});
153
- },
154
- },
155
- {
156
- name: "clay_db_exec",
157
- description: "Execute schema or write SQL against the current Mate datastore.",
158
- inputSchema: {
159
- sql: z.string().min(1).describe("SQL statement"),
160
- params: z.array(z.any()).optional().describe("Positional parameters"),
161
- },
162
- handler: function (input) {
163
- return callToolInternal("clay_db_exec", input || {});
164
- },
165
- },
166
- {
167
- name: "clay_db_tables",
168
- description: "List schema objects in the current Mate datastore.",
169
- inputSchema: undefined,
170
- handler: function (input) {
171
- return callToolInternal("clay_db_tables", input || {});
172
- },
173
- },
174
- {
175
- name: "clay_db_describe",
176
- description: "Describe a table or view in the current Mate datastore.",
177
- inputSchema: {
178
- table: z.string().min(1).describe("Table name"),
179
- },
180
- handler: function (input) {
181
- return callToolInternal("clay_db_describe", input || {});
182
- },
183
- },
184
- ];
185
- }
186
-
187
- function createMcpServer() {
188
- var defs = getToolDefinitions();
189
- if (!defs.length) return null;
190
- var registered = {};
191
- for (var i = 0; i < defs.length; i++) {
192
- registered[defs[i].name] = {
193
- description: defs[i].description,
194
- inputSchema: defs[i].inputSchema,
195
- handler: defs[i].handler,
196
- };
197
- }
198
- return {
199
- name: "clay-datastore",
200
- version: "1.0.0",
201
- instance: {
202
- _registeredTools: registered,
203
- },
204
- };
205
- }
206
-
207
- function getSessionToolDefinitions() {
208
- if (!isMate || !isFeatureAvailable()) return null;
209
- return getToolDefinitions();
210
- }
211
-
212
- function callMateTool(session, toolName, input) {
213
- return callToolInternal(toolName, input || {});
214
- }
215
-
216
- function closeAllDatastores() {
217
- datastore.closeAllMateDatastores();
218
- }
219
-
220
- return {
221
- isFeatureAvailable: isFeatureAvailable,
222
- handleMateDatastoreMessage: handleMateDatastoreMessage,
223
- getToolDefinitions: getToolDefinitions,
224
- createMcpServer: createMcpServer,
225
- getSessionToolDefinitions: getSessionToolDefinitions,
226
- callMateTool: callMateTool,
227
- ensureProjectDatastore: ensureProjectDatastore,
228
- closeAllDatastores: closeAllDatastores,
229
- };
230
- }
231
-
232
- module.exports = { attachMateDatastore: attachMateDatastore };