@danainnovations/cortex-mcp 1.0.39 → 1.0.40
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/cli.js +45 -29
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +117 -2
- package/dist/index.js +208 -27
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -141,7 +141,7 @@ declare const AVAILABLE_MCPS: readonly [{
|
|
|
141
141
|
}, {
|
|
142
142
|
readonly name: "m365";
|
|
143
143
|
readonly displayName: "Microsoft 365";
|
|
144
|
-
readonly description: "Email, calendar, OneDrive, Teams, meetings, contacts, tasks, notes (
|
|
144
|
+
readonly description: "Email, calendar, OneDrive, Teams, meetings, contacts, tasks, notes (33 tools)";
|
|
145
145
|
readonly serverName: "cortex-m365";
|
|
146
146
|
readonly authMode: "personal";
|
|
147
147
|
}, {
|
|
@@ -189,4 +189,119 @@ declare function readCredentials(): CortexCredentials | null;
|
|
|
189
189
|
*/
|
|
190
190
|
declare function getEffectiveApiKey(): string;
|
|
191
191
|
|
|
192
|
-
|
|
192
|
+
/** Metadata for a single MCP tool */
|
|
193
|
+
interface ToolInfo {
|
|
194
|
+
name: string;
|
|
195
|
+
description: string;
|
|
196
|
+
inputSchema: Record<string, unknown>;
|
|
197
|
+
}
|
|
198
|
+
/** Base error class for all Cortex SDK errors */
|
|
199
|
+
declare class CortexError extends Error {
|
|
200
|
+
readonly mcpName?: string | undefined;
|
|
201
|
+
constructor(message: string, mcpName?: string | undefined);
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Thrown when a tool executes but returns isError: true
|
|
205
|
+
* (e.g., bad SOQL query, missing OAuth connection, invalid record ID).
|
|
206
|
+
*/
|
|
207
|
+
declare class CortexToolError extends CortexError {
|
|
208
|
+
readonly mcpName: string;
|
|
209
|
+
readonly toolName: string;
|
|
210
|
+
constructor(message: string, mcpName: string, toolName: string);
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Thrown on transport/auth failures — the tool never executed
|
|
214
|
+
* (e.g., invalid API key, network error, server down).
|
|
215
|
+
*/
|
|
216
|
+
declare class CortexNetworkError extends CortexError {
|
|
217
|
+
readonly code?: number | undefined;
|
|
218
|
+
constructor(message: string, code?: number | undefined, mcpName?: string);
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Provides a call interface for a single Cortex MCP.
|
|
222
|
+
* Lazily initializes the underlying HTTP session on first use.
|
|
223
|
+
*/
|
|
224
|
+
declare class MCPNamespace {
|
|
225
|
+
readonly mcpName: string;
|
|
226
|
+
private readonly client;
|
|
227
|
+
private initPromise;
|
|
228
|
+
constructor(mcpName: string, serverUrl: string, apiKey: string);
|
|
229
|
+
private ensureInitialized;
|
|
230
|
+
private doInit;
|
|
231
|
+
/**
|
|
232
|
+
* Call a tool on this MCP. Returns the parsed result.
|
|
233
|
+
*
|
|
234
|
+
* @example
|
|
235
|
+
* const ns = new MCPNamespace('salesforce', serverUrl, apiKey);
|
|
236
|
+
* const result = await ns.call('run_soql_query', {
|
|
237
|
+
* query: 'SELECT Id, Name FROM Account LIMIT 10'
|
|
238
|
+
* });
|
|
239
|
+
*/
|
|
240
|
+
call(toolName: string, args?: Record<string, unknown>): Promise<unknown>;
|
|
241
|
+
/** List all tools available on this MCP. */
|
|
242
|
+
listTools(): Promise<ToolInfo[]>;
|
|
243
|
+
/** Release the session. The next call() will re-initialize. */
|
|
244
|
+
close(): void;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
interface CortexClientOptions {
|
|
248
|
+
/** API key. Defaults to auto-resolved key (env > credentials > config > shared). */
|
|
249
|
+
apiKey?: string;
|
|
250
|
+
/** Cortex server URL. Defaults to https://cortex-bice.vercel.app */
|
|
251
|
+
serverUrl?: string;
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* High-level SDK client for calling Cortex MCP tools from custom apps.
|
|
255
|
+
* Auto-resolves credentials and lazily initializes per-MCP sessions.
|
|
256
|
+
*
|
|
257
|
+
* @example
|
|
258
|
+
* ```typescript
|
|
259
|
+
* import { CortexClient } from '@danainnovations/cortex-mcp';
|
|
260
|
+
*
|
|
261
|
+
* const cortex = new CortexClient();
|
|
262
|
+
*
|
|
263
|
+
* // Salesforce — no Connected App needed
|
|
264
|
+
* const accounts = await cortex.salesforce.call('run_soql_query', {
|
|
265
|
+
* query: 'SELECT Id, Name FROM Account LIMIT 10'
|
|
266
|
+
* });
|
|
267
|
+
*
|
|
268
|
+
* // Microsoft 365
|
|
269
|
+
* const emails = await cortex.m365.call('list_emails', { count: 5 });
|
|
270
|
+
*
|
|
271
|
+
* // GitHub
|
|
272
|
+
* const repos = await cortex.github.call('list_repositories', { per_page: 5 });
|
|
273
|
+
*
|
|
274
|
+
* // Cleanup when done
|
|
275
|
+
* cortex.close();
|
|
276
|
+
* ```
|
|
277
|
+
*/
|
|
278
|
+
declare class CortexClient {
|
|
279
|
+
private readonly apiKey;
|
|
280
|
+
private readonly serverUrl;
|
|
281
|
+
private readonly namespaces;
|
|
282
|
+
constructor(options?: CortexClientOptions);
|
|
283
|
+
get asana(): MCPNamespace;
|
|
284
|
+
get github(): MCPNamespace;
|
|
285
|
+
get vercel(): MCPNamespace;
|
|
286
|
+
get supabase(): MCPNamespace;
|
|
287
|
+
get m365(): MCPNamespace;
|
|
288
|
+
get salesforce(): MCPNamespace;
|
|
289
|
+
get monday(): MCPNamespace;
|
|
290
|
+
get slack(): MCPNamespace;
|
|
291
|
+
get bestbuy(): MCPNamespace;
|
|
292
|
+
/**
|
|
293
|
+
* Call any MCP tool when the MCP name is determined at runtime.
|
|
294
|
+
*
|
|
295
|
+
* @example
|
|
296
|
+
* const result = await cortex.call('github', 'list_repositories', { per_page: 5 });
|
|
297
|
+
*/
|
|
298
|
+
call(mcpName: string, toolName: string, args?: Record<string, unknown>): Promise<unknown>;
|
|
299
|
+
/**
|
|
300
|
+
* Release all sessions. Safe to call multiple times.
|
|
301
|
+
* The next call after close() will re-initialize automatically.
|
|
302
|
+
*/
|
|
303
|
+
close(): void;
|
|
304
|
+
private getNamespace;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
export { AVAILABLE_MCPS, type ClientType, CortexClient, type CortexClientOptions, type CortexCredentials, CortexError, CortexHttpClient, type CortexMcpConfig, CortexNetworkError, CortexToolError, DEFAULT_API_KEY, DEFAULT_SERVER_URL, type DetectedClient, MCPNamespace, MCP_NAMES, type ToolInfo, configureClaudeCode, configureClaudeDesktop, configureClient, configureCursor, createConfig, detectClients, generateStdioSnippet, getEffectiveApiKey, isValidApiKey, readConfig, readCredentials, startStdioServer, validateApiKeyRemote, writeConfig };
|
package/dist/index.js
CHANGED
|
@@ -33,7 +33,7 @@ var AVAILABLE_MCPS = [
|
|
|
33
33
|
{
|
|
34
34
|
name: "m365",
|
|
35
35
|
displayName: "Microsoft 365",
|
|
36
|
-
description: "Email, calendar, OneDrive, Teams, meetings, contacts, tasks, notes (
|
|
36
|
+
description: "Email, calendar, OneDrive, Teams, meetings, contacts, tasks, notes (33 tools)",
|
|
37
37
|
serverName: "cortex-m365",
|
|
38
38
|
authMode: "personal"
|
|
39
39
|
},
|
|
@@ -107,7 +107,8 @@ var CortexHttpClient = class {
|
|
|
107
107
|
const headers = {
|
|
108
108
|
"Content-Type": "application/json",
|
|
109
109
|
"x-api-key": this.apiKey,
|
|
110
|
-
"mcp-protocol-version": PROTOCOL_VERSION
|
|
110
|
+
"mcp-protocol-version": PROTOCOL_VERSION,
|
|
111
|
+
"x-cortex-client": "cortex-mcp-stdio"
|
|
111
112
|
};
|
|
112
113
|
if (this.sessionId) {
|
|
113
114
|
headers["mcp-session-id"] = this.sessionId;
|
|
@@ -117,7 +118,7 @@ var CortexHttpClient = class {
|
|
|
117
118
|
method: "POST",
|
|
118
119
|
headers,
|
|
119
120
|
body: JSON.stringify(body),
|
|
120
|
-
signal: AbortSignal.timeout(
|
|
121
|
+
signal: AbortSignal.timeout(6e4)
|
|
121
122
|
});
|
|
122
123
|
const newSessionId = response.headers.get("mcp-session-id");
|
|
123
124
|
if (newSessionId) {
|
|
@@ -142,7 +143,8 @@ var CortexHttpClient = class {
|
|
|
142
143
|
const headers = {
|
|
143
144
|
"Content-Type": "application/json",
|
|
144
145
|
"x-api-key": this.apiKey,
|
|
145
|
-
"mcp-protocol-version": PROTOCOL_VERSION
|
|
146
|
+
"mcp-protocol-version": PROTOCOL_VERSION,
|
|
147
|
+
"x-cortex-client": "cortex-mcp-stdio"
|
|
146
148
|
};
|
|
147
149
|
if (this.sessionId) {
|
|
148
150
|
headers["mcp-session-id"] = this.sessionId;
|
|
@@ -184,7 +186,7 @@ import {
|
|
|
184
186
|
ListToolsRequestSchema
|
|
185
187
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
186
188
|
var UPLOAD_TOOLS = /* @__PURE__ */ new Set(["upload_file", "upload_file_to_sharepoint"]);
|
|
187
|
-
var INLINE_UPLOAD_MAX = 3
|
|
189
|
+
var INLINE_UPLOAD_MAX = 3 * 1024 * 1024;
|
|
188
190
|
function overrideUploadToolSchema(tool) {
|
|
189
191
|
const name = tool.name;
|
|
190
192
|
const baseName = name.includes("__") ? name.split("__").pop() : name;
|
|
@@ -310,48 +312,57 @@ async function handleLocalFileUpload(cortex, toolName, args) {
|
|
|
310
312
|
};
|
|
311
313
|
}
|
|
312
314
|
const fileBuffer = readFileSync(filePath);
|
|
313
|
-
const chunkSize =
|
|
315
|
+
const chunkSize = 2.5 * 1024 * 1024;
|
|
314
316
|
const total = fileBuffer.length;
|
|
315
|
-
let
|
|
317
|
+
let driveItem = {};
|
|
316
318
|
for (let start = 0; start < total; start += chunkSize) {
|
|
317
319
|
const end = Math.min(start + chunkSize, total);
|
|
318
320
|
const chunk = fileBuffer.subarray(start, end);
|
|
321
|
+
const chunkBase64 = Buffer.from(chunk).toString("base64");
|
|
319
322
|
console.error(
|
|
320
|
-
`[cortex-mcp] Uploading chunk ${start}-${end - 1}/${total}`
|
|
323
|
+
`[cortex-mcp] Uploading chunk ${start}-${end - 1}/${total} via backend relay`
|
|
321
324
|
);
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
body: chunk,
|
|
329
|
-
signal: AbortSignal.timeout(12e4)
|
|
330
|
-
// 2 min per chunk
|
|
325
|
+
const chunkResponse = await cortex.callTool(`${prefix}upload_file_chunk`, {
|
|
326
|
+
upload_url: uploadUrl,
|
|
327
|
+
chunk: chunkBase64,
|
|
328
|
+
range_start: start,
|
|
329
|
+
range_end: end - 1,
|
|
330
|
+
total_size: total
|
|
331
331
|
});
|
|
332
|
-
if (
|
|
333
|
-
|
|
332
|
+
if (chunkResponse.error) {
|
|
333
|
+
return {
|
|
334
|
+
content: [{ type: "text", text: chunkResponse.error.message }],
|
|
335
|
+
isError: true
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
const chunkResult = chunkResponse.result;
|
|
339
|
+
let chunkData;
|
|
340
|
+
try {
|
|
341
|
+
chunkData = JSON.parse(chunkResult.content[0].text);
|
|
342
|
+
} catch {
|
|
334
343
|
return {
|
|
335
344
|
content: [{ type: "text", text: JSON.stringify({
|
|
336
345
|
success: false,
|
|
337
|
-
error:
|
|
346
|
+
error: "Failed to parse chunk upload response from backend"
|
|
338
347
|
}) }],
|
|
339
348
|
isError: true
|
|
340
349
|
};
|
|
341
350
|
}
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
}
|
|
351
|
+
if (!chunkData.success) {
|
|
352
|
+
return {
|
|
353
|
+
content: [{ type: "text", text: JSON.stringify(chunkData) }],
|
|
354
|
+
isError: true
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
if (chunkData.status === 200 || chunkData.status === 201) {
|
|
358
|
+
driveItem = chunkData.data ?? {};
|
|
348
359
|
}
|
|
349
360
|
}
|
|
350
361
|
return {
|
|
351
362
|
content: [{ type: "text", text: JSON.stringify({
|
|
352
363
|
success: true,
|
|
353
364
|
file: driveItem,
|
|
354
|
-
message: `Uploaded '${args.path}' (${(fileSize / 1024).toFixed(1)}
|
|
365
|
+
message: `Uploaded '${args.path}' (${(fileSize / 1024 / 1024).toFixed(1)}MB) via upload session`
|
|
355
366
|
}) }],
|
|
356
367
|
isError: false
|
|
357
368
|
};
|
|
@@ -694,11 +705,181 @@ function getEffectiveApiKey() {
|
|
|
694
705
|
if (config?.apiKey) return config.apiKey;
|
|
695
706
|
return DEFAULT_API_KEY;
|
|
696
707
|
}
|
|
708
|
+
|
|
709
|
+
// src/client/mcp-namespace.ts
|
|
710
|
+
var CortexError = class extends Error {
|
|
711
|
+
constructor(message, mcpName) {
|
|
712
|
+
super(message);
|
|
713
|
+
this.mcpName = mcpName;
|
|
714
|
+
this.name = "CortexError";
|
|
715
|
+
}
|
|
716
|
+
};
|
|
717
|
+
var CortexToolError = class extends CortexError {
|
|
718
|
+
constructor(message, mcpName, toolName) {
|
|
719
|
+
super(message, mcpName);
|
|
720
|
+
this.mcpName = mcpName;
|
|
721
|
+
this.toolName = toolName;
|
|
722
|
+
this.name = "CortexToolError";
|
|
723
|
+
}
|
|
724
|
+
};
|
|
725
|
+
var CortexNetworkError = class extends CortexError {
|
|
726
|
+
constructor(message, code, mcpName) {
|
|
727
|
+
super(message, mcpName);
|
|
728
|
+
this.code = code;
|
|
729
|
+
this.name = "CortexNetworkError";
|
|
730
|
+
}
|
|
731
|
+
};
|
|
732
|
+
var MCPNamespace = class {
|
|
733
|
+
constructor(mcpName, serverUrl, apiKey) {
|
|
734
|
+
this.mcpName = mcpName;
|
|
735
|
+
this.client = new CortexHttpClient(serverUrl, apiKey, mcpName);
|
|
736
|
+
}
|
|
737
|
+
client;
|
|
738
|
+
initPromise = null;
|
|
739
|
+
async ensureInitialized() {
|
|
740
|
+
if (this.initPromise !== null) return this.initPromise;
|
|
741
|
+
this.initPromise = this.doInit();
|
|
742
|
+
return this.initPromise;
|
|
743
|
+
}
|
|
744
|
+
async doInit() {
|
|
745
|
+
const response = await this.client.initialize();
|
|
746
|
+
if (response.error) {
|
|
747
|
+
this.initPromise = null;
|
|
748
|
+
throw new CortexNetworkError(
|
|
749
|
+
response.error.message,
|
|
750
|
+
response.error.code,
|
|
751
|
+
this.mcpName
|
|
752
|
+
);
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
/**
|
|
756
|
+
* Call a tool on this MCP. Returns the parsed result.
|
|
757
|
+
*
|
|
758
|
+
* @example
|
|
759
|
+
* const ns = new MCPNamespace('salesforce', serverUrl, apiKey);
|
|
760
|
+
* const result = await ns.call('run_soql_query', {
|
|
761
|
+
* query: 'SELECT Id, Name FROM Account LIMIT 10'
|
|
762
|
+
* });
|
|
763
|
+
*/
|
|
764
|
+
async call(toolName, args = {}) {
|
|
765
|
+
await this.ensureInitialized();
|
|
766
|
+
const response = await this.client.callTool(toolName, args);
|
|
767
|
+
if (response.error) {
|
|
768
|
+
throw new CortexNetworkError(
|
|
769
|
+
response.error.message,
|
|
770
|
+
response.error.code,
|
|
771
|
+
this.mcpName
|
|
772
|
+
);
|
|
773
|
+
}
|
|
774
|
+
const result = response.result;
|
|
775
|
+
const text = result?.content?.[0]?.text ?? "";
|
|
776
|
+
if (result?.isError) {
|
|
777
|
+
throw new CortexToolError(text, this.mcpName, toolName);
|
|
778
|
+
}
|
|
779
|
+
return parseText(text);
|
|
780
|
+
}
|
|
781
|
+
/** List all tools available on this MCP. */
|
|
782
|
+
async listTools() {
|
|
783
|
+
await this.ensureInitialized();
|
|
784
|
+
const response = await this.client.listTools();
|
|
785
|
+
if (response.error) {
|
|
786
|
+
throw new CortexNetworkError(
|
|
787
|
+
response.error.message,
|
|
788
|
+
response.error.code,
|
|
789
|
+
this.mcpName
|
|
790
|
+
);
|
|
791
|
+
}
|
|
792
|
+
const result = response.result;
|
|
793
|
+
return result?.tools ?? [];
|
|
794
|
+
}
|
|
795
|
+
/** Release the session. The next call() will re-initialize. */
|
|
796
|
+
close() {
|
|
797
|
+
this.initPromise = null;
|
|
798
|
+
}
|
|
799
|
+
};
|
|
800
|
+
function parseText(text) {
|
|
801
|
+
if (!text) return text;
|
|
802
|
+
try {
|
|
803
|
+
return JSON.parse(text);
|
|
804
|
+
} catch {
|
|
805
|
+
return text;
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
// src/client/cortex-client.ts
|
|
810
|
+
var CortexClient = class {
|
|
811
|
+
apiKey;
|
|
812
|
+
serverUrl;
|
|
813
|
+
namespaces = /* @__PURE__ */ new Map();
|
|
814
|
+
constructor(options = {}) {
|
|
815
|
+
this.apiKey = options.apiKey ?? getEffectiveApiKey();
|
|
816
|
+
this.serverUrl = options.serverUrl ?? DEFAULT_SERVER_URL;
|
|
817
|
+
}
|
|
818
|
+
get asana() {
|
|
819
|
+
return this.getNamespace("asana");
|
|
820
|
+
}
|
|
821
|
+
get github() {
|
|
822
|
+
return this.getNamespace("github");
|
|
823
|
+
}
|
|
824
|
+
get vercel() {
|
|
825
|
+
return this.getNamespace("vercel");
|
|
826
|
+
}
|
|
827
|
+
get supabase() {
|
|
828
|
+
return this.getNamespace("supabase");
|
|
829
|
+
}
|
|
830
|
+
get m365() {
|
|
831
|
+
return this.getNamespace("m365");
|
|
832
|
+
}
|
|
833
|
+
get salesforce() {
|
|
834
|
+
return this.getNamespace("salesforce");
|
|
835
|
+
}
|
|
836
|
+
get monday() {
|
|
837
|
+
return this.getNamespace("monday");
|
|
838
|
+
}
|
|
839
|
+
get slack() {
|
|
840
|
+
return this.getNamespace("slack");
|
|
841
|
+
}
|
|
842
|
+
get bestbuy() {
|
|
843
|
+
return this.getNamespace("bestbuy");
|
|
844
|
+
}
|
|
845
|
+
/**
|
|
846
|
+
* Call any MCP tool when the MCP name is determined at runtime.
|
|
847
|
+
*
|
|
848
|
+
* @example
|
|
849
|
+
* const result = await cortex.call('github', 'list_repositories', { per_page: 5 });
|
|
850
|
+
*/
|
|
851
|
+
async call(mcpName, toolName, args = {}) {
|
|
852
|
+
return this.getNamespace(mcpName).call(toolName, args);
|
|
853
|
+
}
|
|
854
|
+
/**
|
|
855
|
+
* Release all sessions. Safe to call multiple times.
|
|
856
|
+
* The next call after close() will re-initialize automatically.
|
|
857
|
+
*/
|
|
858
|
+
close() {
|
|
859
|
+
for (const ns of this.namespaces.values()) {
|
|
860
|
+
ns.close();
|
|
861
|
+
}
|
|
862
|
+
this.namespaces.clear();
|
|
863
|
+
}
|
|
864
|
+
getNamespace(name) {
|
|
865
|
+
let ns = this.namespaces.get(name);
|
|
866
|
+
if (!ns) {
|
|
867
|
+
ns = new MCPNamespace(name, this.serverUrl, this.apiKey);
|
|
868
|
+
this.namespaces.set(name, ns);
|
|
869
|
+
}
|
|
870
|
+
return ns;
|
|
871
|
+
}
|
|
872
|
+
};
|
|
697
873
|
export {
|
|
698
874
|
AVAILABLE_MCPS,
|
|
875
|
+
CortexClient,
|
|
876
|
+
CortexError,
|
|
699
877
|
CortexHttpClient,
|
|
878
|
+
CortexNetworkError,
|
|
879
|
+
CortexToolError,
|
|
700
880
|
DEFAULT_API_KEY,
|
|
701
881
|
DEFAULT_SERVER_URL,
|
|
882
|
+
MCPNamespace,
|
|
702
883
|
MCP_NAMES,
|
|
703
884
|
configureClaudeCode,
|
|
704
885
|
configureClaudeDesktop,
|