@mastra/mcp 1.0.0-beta.0 → 1.0.0-beta.10
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/CHANGELOG.md +303 -0
- package/README.md +250 -24
- package/dist/__fixtures__/tools.d.ts +8 -5
- package/dist/__fixtures__/tools.d.ts.map +1 -1
- package/dist/client/{elicitationActions.d.ts → actions/elicitation.d.ts} +2 -2
- package/dist/client/actions/elicitation.d.ts.map +1 -0
- package/dist/client/actions/progress.d.ts +23 -0
- package/dist/client/actions/progress.d.ts.map +1 -0
- package/dist/client/{promptActions.d.ts → actions/prompt.d.ts} +2 -2
- package/dist/client/actions/prompt.d.ts.map +1 -0
- package/dist/client/{resourceActions.d.ts → actions/resource.d.ts} +2 -2
- package/dist/client/actions/resource.d.ts.map +1 -0
- package/dist/client/client.d.ts +79 -132
- package/dist/client/client.d.ts.map +1 -1
- package/dist/client/configuration.d.ts +23 -1
- package/dist/client/configuration.d.ts.map +1 -1
- package/dist/client/index.d.ts +3 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/oauth-provider.d.ts +230 -0
- package/dist/client/oauth-provider.d.ts.map +1 -0
- package/dist/client/types.d.ts +237 -0
- package/dist/client/types.d.ts.map +1 -0
- package/dist/docs/README.md +33 -0
- package/dist/docs/SKILL.md +46 -0
- package/dist/docs/SOURCE_MAP.json +59 -0
- package/dist/docs/mcp/01-overview.md +372 -0
- package/dist/docs/mcp/02-publishing-mcp-server.md +111 -0
- package/dist/docs/tools/01-reference.md +2306 -0
- package/dist/docs/tools-mcp/01-mcp-overview.md +384 -0
- package/dist/index.cjs +851 -107
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +774 -92
- package/dist/index.js.map +1 -1
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/oauth-middleware.d.ts +142 -0
- package/dist/server/oauth-middleware.d.ts.map +1 -0
- package/dist/server/server.d.ts +20 -4
- package/dist/server/server.d.ts.map +1 -1
- package/dist/server/types.d.ts +11 -4
- package/dist/server/types.d.ts.map +1 -1
- package/dist/shared/index.d.ts +2 -0
- package/dist/shared/index.d.ts.map +1 -0
- package/dist/shared/oauth-types.d.ts +137 -0
- package/dist/shared/oauth-types.d.ts.map +1 -0
- package/package.json +17 -14
- package/dist/client/elicitationActions.d.ts.map +0 -1
- package/dist/client/promptActions.d.ts.map +0 -1
- package/dist/client/resourceActions.d.ts.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -1,38 +1,39 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var $RefParser = require('@apidevtools/json-schema-ref-parser');
|
|
3
4
|
var base = require('@mastra/core/base');
|
|
4
5
|
var error = require('@mastra/core/error');
|
|
5
|
-
var protocol_js = require('@modelcontextprotocol/sdk/shared/protocol.js');
|
|
6
|
-
var equal = require('fast-deep-equal');
|
|
7
|
-
var uuid = require('uuid');
|
|
8
|
-
var $RefParser = require('@apidevtools/json-schema-ref-parser');
|
|
9
6
|
var tools = require('@mastra/core/tools');
|
|
10
7
|
var utils = require('@mastra/core/utils');
|
|
11
|
-
var index_js
|
|
12
|
-
var sse_js
|
|
13
|
-
var stdio_js
|
|
14
|
-
var streamableHttp_js
|
|
8
|
+
var index_js = require('@modelcontextprotocol/sdk/client/index.js');
|
|
9
|
+
var sse_js = require('@modelcontextprotocol/sdk/client/sse.js');
|
|
10
|
+
var stdio_js = require('@modelcontextprotocol/sdk/client/stdio.js');
|
|
11
|
+
var streamableHttp_js = require('@modelcontextprotocol/sdk/client/streamableHttp.js');
|
|
12
|
+
var protocol_js = require('@modelcontextprotocol/sdk/shared/protocol.js');
|
|
15
13
|
var types_js = require('@modelcontextprotocol/sdk/types.js');
|
|
16
14
|
var exitHook = require('exit-hook');
|
|
17
15
|
var zod = require('zod');
|
|
18
16
|
var zodFromJsonSchema = require('zod-from-json-schema');
|
|
19
17
|
var zodFromJsonSchemaV3 = require('zod-from-json-schema-v3');
|
|
18
|
+
var equal = require('fast-deep-equal');
|
|
19
|
+
var uuid = require('uuid');
|
|
20
20
|
var crypto$1 = require('crypto');
|
|
21
21
|
var mcp = require('@mastra/core/mcp');
|
|
22
22
|
var requestContext = require('@mastra/core/request-context');
|
|
23
|
-
var index_js = require('@modelcontextprotocol/sdk/server/index.js');
|
|
24
|
-
var sse_js = require('@modelcontextprotocol/sdk/server/sse.js');
|
|
25
|
-
var stdio_js = require('@modelcontextprotocol/sdk/server/stdio.js');
|
|
26
|
-
var streamableHttp_js = require('@modelcontextprotocol/sdk/server/streamableHttp.js');
|
|
23
|
+
var index_js$1 = require('@modelcontextprotocol/sdk/server/index.js');
|
|
24
|
+
var sse_js$1 = require('@modelcontextprotocol/sdk/server/sse.js');
|
|
25
|
+
var stdio_js$1 = require('@modelcontextprotocol/sdk/server/stdio.js');
|
|
26
|
+
var streamableHttp_js$1 = require('@modelcontextprotocol/sdk/server/streamableHttp.js');
|
|
27
|
+
var auth_js = require('@modelcontextprotocol/sdk/client/auth.js');
|
|
27
28
|
|
|
28
29
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
29
30
|
|
|
30
|
-
var equal__default = /*#__PURE__*/_interopDefault(equal);
|
|
31
31
|
var $RefParser__default = /*#__PURE__*/_interopDefault($RefParser);
|
|
32
|
+
var equal__default = /*#__PURE__*/_interopDefault(equal);
|
|
32
33
|
|
|
33
|
-
// src/client/
|
|
34
|
+
// src/client/client.ts
|
|
34
35
|
|
|
35
|
-
// src/client/
|
|
36
|
+
// src/client/actions/elicitation.ts
|
|
36
37
|
var ElicitationClientActions = class {
|
|
37
38
|
client;
|
|
38
39
|
logger;
|
|
@@ -85,6 +86,23 @@ var ElicitationClientActions = class {
|
|
|
85
86
|
this.client.setElicitationRequestHandler(handler);
|
|
86
87
|
}
|
|
87
88
|
};
|
|
89
|
+
|
|
90
|
+
// src/client/actions/progress.ts
|
|
91
|
+
var ProgressClientActions = class {
|
|
92
|
+
client;
|
|
93
|
+
logger;
|
|
94
|
+
constructor({ client, logger }) {
|
|
95
|
+
this.client = client;
|
|
96
|
+
this.logger = logger;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Set a notification handler for progress updates.
|
|
100
|
+
* @param handler The callback function to handle progress notifications.
|
|
101
|
+
*/
|
|
102
|
+
onUpdate(handler) {
|
|
103
|
+
this.client.setProgressNotificationHandler(handler);
|
|
104
|
+
}
|
|
105
|
+
};
|
|
88
106
|
var PromptClientActions = class {
|
|
89
107
|
client;
|
|
90
108
|
logger;
|
|
@@ -373,6 +391,8 @@ var ResourceClientActions = class {
|
|
|
373
391
|
};
|
|
374
392
|
|
|
375
393
|
// src/client/client.ts
|
|
394
|
+
var DEFAULT_SERVER_CONNECT_TIMEOUT_MSEC = 3e3;
|
|
395
|
+
var SSE_FALLBACK_STATUS_CODES = [400, 404, 405];
|
|
376
396
|
function convertLogLevelToLoggerMethod(level) {
|
|
377
397
|
switch (level) {
|
|
378
398
|
case "debug":
|
|
@@ -397,15 +417,21 @@ var InternalMastraMCPClient = class extends base.MastraBase {
|
|
|
397
417
|
timeout;
|
|
398
418
|
logHandler;
|
|
399
419
|
enableServerLogs;
|
|
420
|
+
enableProgressTracking;
|
|
400
421
|
serverConfig;
|
|
401
422
|
transport;
|
|
402
423
|
currentOperationContext = null;
|
|
424
|
+
exitHookUnsubscribe;
|
|
425
|
+
sigTermHandler;
|
|
426
|
+
_roots;
|
|
403
427
|
/** Provides access to resource operations (list, read, subscribe, etc.) */
|
|
404
428
|
resources;
|
|
405
429
|
/** Provides access to prompt operations (list, get, notifications) */
|
|
406
430
|
prompts;
|
|
407
431
|
/** Provides access to elicitation operations (request handling) */
|
|
408
432
|
elicitation;
|
|
433
|
+
/** Provides access to progress operations (notifications) */
|
|
434
|
+
progress;
|
|
409
435
|
/**
|
|
410
436
|
* @internal
|
|
411
437
|
*/
|
|
@@ -422,8 +448,16 @@ var InternalMastraMCPClient = class extends base.MastraBase {
|
|
|
422
448
|
this.logHandler = server.logger;
|
|
423
449
|
this.enableServerLogs = server.enableServerLogs ?? true;
|
|
424
450
|
this.serverConfig = server;
|
|
425
|
-
|
|
426
|
-
this.
|
|
451
|
+
this.enableProgressTracking = !!server.enableProgressTracking;
|
|
452
|
+
this._roots = server.roots ?? [];
|
|
453
|
+
const hasRoots = this._roots.length > 0 || !!capabilities.roots;
|
|
454
|
+
const clientCapabilities = {
|
|
455
|
+
...capabilities,
|
|
456
|
+
elicitation: {},
|
|
457
|
+
// Auto-enable roots capability if roots are provided
|
|
458
|
+
...hasRoots ? { roots: { listChanged: true, ...capabilities.roots ?? {} } } : {}
|
|
459
|
+
};
|
|
460
|
+
this.client = new index_js.Client(
|
|
427
461
|
{
|
|
428
462
|
name,
|
|
429
463
|
version
|
|
@@ -433,9 +467,13 @@ var InternalMastraMCPClient = class extends base.MastraBase {
|
|
|
433
467
|
}
|
|
434
468
|
);
|
|
435
469
|
this.setupLogging();
|
|
470
|
+
if (hasRoots) {
|
|
471
|
+
this.setupRootsHandler();
|
|
472
|
+
}
|
|
436
473
|
this.resources = new ResourceClientActions({ client: this, logger: this.logger });
|
|
437
474
|
this.prompts = new PromptClientActions({ client: this, logger: this.logger });
|
|
438
475
|
this.elicitation = new ElicitationClientActions({ client: this, logger: this.logger });
|
|
476
|
+
this.progress = new ProgressClientActions({ client: this, logger: this.logger });
|
|
439
477
|
}
|
|
440
478
|
/**
|
|
441
479
|
* Log a message at the specified level
|
|
@@ -474,13 +512,70 @@ var InternalMastraMCPClient = class extends base.MastraBase {
|
|
|
474
512
|
);
|
|
475
513
|
}
|
|
476
514
|
}
|
|
515
|
+
/**
|
|
516
|
+
* Set up handler for roots/list requests from the server.
|
|
517
|
+
*
|
|
518
|
+
* Per MCP spec (https://modelcontextprotocol.io/specification/2025-11-25/client/roots):
|
|
519
|
+
* When a server sends a roots/list request, the client responds with the configured roots.
|
|
520
|
+
*/
|
|
521
|
+
setupRootsHandler() {
|
|
522
|
+
this.log("debug", "Setting up roots/list request handler");
|
|
523
|
+
this.client.setRequestHandler(types_js.ListRootsRequestSchema, async () => {
|
|
524
|
+
this.log("debug", `Responding to roots/list request with ${this._roots.length} roots`);
|
|
525
|
+
return { roots: this._roots };
|
|
526
|
+
});
|
|
527
|
+
}
|
|
528
|
+
/**
|
|
529
|
+
* Get the currently configured roots.
|
|
530
|
+
*
|
|
531
|
+
* @returns Array of configured filesystem roots
|
|
532
|
+
*/
|
|
533
|
+
get roots() {
|
|
534
|
+
return [...this._roots];
|
|
535
|
+
}
|
|
536
|
+
/**
|
|
537
|
+
* Update the list of filesystem roots and notify the server.
|
|
538
|
+
*
|
|
539
|
+
* Per MCP spec, when roots change, the client sends a `notifications/roots/list_changed`
|
|
540
|
+
* notification to inform the server that it should re-fetch the roots list.
|
|
541
|
+
*
|
|
542
|
+
* @param roots - New list of filesystem roots
|
|
543
|
+
*
|
|
544
|
+
* @example
|
|
545
|
+
* ```typescript
|
|
546
|
+
* await client.setRoots([
|
|
547
|
+
* { uri: 'file:///home/user/projects', name: 'Projects' },
|
|
548
|
+
* { uri: 'file:///tmp', name: 'Temp' }
|
|
549
|
+
* ]);
|
|
550
|
+
* ```
|
|
551
|
+
*/
|
|
552
|
+
async setRoots(roots) {
|
|
553
|
+
this.log("debug", `Updating roots to ${roots.length} entries`);
|
|
554
|
+
this._roots = [...roots];
|
|
555
|
+
await this.sendRootsListChanged();
|
|
556
|
+
}
|
|
557
|
+
/**
|
|
558
|
+
* Send a roots/list_changed notification to the server.
|
|
559
|
+
*
|
|
560
|
+
* Per MCP spec, clients that support `listChanged` MUST send this notification
|
|
561
|
+
* when the list of roots changes. The server will then call roots/list to get
|
|
562
|
+
* the updated list.
|
|
563
|
+
*/
|
|
564
|
+
async sendRootsListChanged() {
|
|
565
|
+
if (!this.transport) {
|
|
566
|
+
this.log("debug", "Cannot send roots/list_changed: not connected");
|
|
567
|
+
return;
|
|
568
|
+
}
|
|
569
|
+
this.log("debug", "Sending notifications/roots/list_changed");
|
|
570
|
+
await this.client.notification({ method: "notifications/roots/list_changed" });
|
|
571
|
+
}
|
|
477
572
|
async connectStdio(command) {
|
|
478
573
|
this.log("debug", `Using Stdio transport for command: ${command}`);
|
|
479
574
|
try {
|
|
480
|
-
this.transport = new stdio_js
|
|
575
|
+
this.transport = new stdio_js.StdioClientTransport({
|
|
481
576
|
command,
|
|
482
577
|
args: this.serverConfig.args,
|
|
483
|
-
env: { ...stdio_js
|
|
578
|
+
env: { ...stdio_js.getDefaultEnvironment(), ...this.serverConfig.env || {} }
|
|
484
579
|
});
|
|
485
580
|
await this.client.connect(this.transport, { timeout: this.serverConfig.timeout ?? this.timeout });
|
|
486
581
|
this.log("debug", `Successfully connected to MCP server via Stdio`);
|
|
@@ -490,34 +585,42 @@ var InternalMastraMCPClient = class extends base.MastraBase {
|
|
|
490
585
|
}
|
|
491
586
|
}
|
|
492
587
|
async connectHttp(url) {
|
|
493
|
-
const { requestInit, eventSourceInit, authProvider } = this.serverConfig;
|
|
588
|
+
const { requestInit, eventSourceInit, authProvider, connectTimeout, fetch: fetch2 } = this.serverConfig;
|
|
494
589
|
this.log("debug", `Attempting to connect to URL: ${url}`);
|
|
495
590
|
let shouldTrySSE = url.pathname.endsWith(`/sse`);
|
|
496
591
|
if (!shouldTrySSE) {
|
|
497
592
|
try {
|
|
498
593
|
this.log("debug", "Trying Streamable HTTP transport...");
|
|
499
|
-
const streamableTransport = new streamableHttp_js
|
|
594
|
+
const streamableTransport = new streamableHttp_js.StreamableHTTPClientTransport(url, {
|
|
500
595
|
requestInit,
|
|
501
596
|
reconnectionOptions: this.serverConfig.reconnectionOptions,
|
|
502
|
-
authProvider
|
|
597
|
+
authProvider,
|
|
598
|
+
fetch: fetch2
|
|
503
599
|
});
|
|
504
600
|
await this.client.connect(streamableTransport, {
|
|
505
|
-
timeout:
|
|
506
|
-
// this is hardcoded to 3s because the long default timeout would be extremely slow for sse backwards compat (60s)
|
|
507
|
-
3e3
|
|
508
|
-
)
|
|
601
|
+
timeout: connectTimeout ?? DEFAULT_SERVER_CONNECT_TIMEOUT_MSEC
|
|
509
602
|
});
|
|
510
603
|
this.transport = streamableTransport;
|
|
511
604
|
this.log("debug", "Successfully connected using Streamable HTTP transport.");
|
|
512
605
|
} catch (error) {
|
|
513
606
|
this.log("debug", `Streamable HTTP transport failed: ${error}`);
|
|
607
|
+
const status = error?.code;
|
|
608
|
+
if (status !== void 0 && !SSE_FALLBACK_STATUS_CODES.includes(status)) {
|
|
609
|
+
throw error;
|
|
610
|
+
}
|
|
514
611
|
shouldTrySSE = true;
|
|
515
612
|
}
|
|
516
613
|
}
|
|
517
614
|
if (shouldTrySSE) {
|
|
518
615
|
this.log("debug", "Falling back to deprecated HTTP+SSE transport...");
|
|
519
616
|
try {
|
|
520
|
-
const
|
|
617
|
+
const sseEventSourceInit = fetch2 ? { ...eventSourceInit, fetch: fetch2 } : eventSourceInit;
|
|
618
|
+
const sseTransport = new sse_js.SSEClientTransport(url, {
|
|
619
|
+
requestInit,
|
|
620
|
+
eventSourceInit: sseEventSourceInit,
|
|
621
|
+
authProvider,
|
|
622
|
+
fetch: fetch2
|
|
623
|
+
});
|
|
521
624
|
await this.client.connect(sseTransport, { timeout: this.serverConfig.timeout ?? this.timeout });
|
|
522
625
|
this.transport = sseTransport;
|
|
523
626
|
this.log("debug", "Successfully connected using deprecated HTTP+SSE transport.");
|
|
@@ -570,14 +673,19 @@ var InternalMastraMCPClient = class extends base.MastraBase {
|
|
|
570
673
|
reject(e);
|
|
571
674
|
}
|
|
572
675
|
});
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
676
|
+
if (!this.exitHookUnsubscribe) {
|
|
677
|
+
this.exitHookUnsubscribe = exitHook.asyncExitHook(
|
|
678
|
+
async () => {
|
|
679
|
+
this.log("debug", `Disconnecting MCP server during exit`);
|
|
680
|
+
await this.disconnect();
|
|
681
|
+
},
|
|
682
|
+
{ wait: 5e3 }
|
|
683
|
+
);
|
|
684
|
+
}
|
|
685
|
+
if (!this.sigTermHandler) {
|
|
686
|
+
this.sigTermHandler = () => exitHook.gracefulExit();
|
|
687
|
+
process.on("SIGTERM", this.sigTermHandler);
|
|
688
|
+
}
|
|
581
689
|
this.log("debug", `Successfully connected to MCP server`);
|
|
582
690
|
return this.isConnected;
|
|
583
691
|
}
|
|
@@ -591,7 +699,7 @@ var InternalMastraMCPClient = class extends base.MastraBase {
|
|
|
591
699
|
* @internal
|
|
592
700
|
*/
|
|
593
701
|
get sessionId() {
|
|
594
|
-
if (this.transport instanceof streamableHttp_js
|
|
702
|
+
if (this.transport instanceof streamableHttp_js.StreamableHTTPClientTransport) {
|
|
595
703
|
return this.transport.sessionId;
|
|
596
704
|
}
|
|
597
705
|
return void 0;
|
|
@@ -612,8 +720,64 @@ var InternalMastraMCPClient = class extends base.MastraBase {
|
|
|
612
720
|
throw e;
|
|
613
721
|
} finally {
|
|
614
722
|
this.transport = void 0;
|
|
615
|
-
this.isConnected =
|
|
723
|
+
this.isConnected = null;
|
|
724
|
+
if (this.exitHookUnsubscribe) {
|
|
725
|
+
this.exitHookUnsubscribe();
|
|
726
|
+
this.exitHookUnsubscribe = void 0;
|
|
727
|
+
}
|
|
728
|
+
if (this.sigTermHandler) {
|
|
729
|
+
process.off("SIGTERM", this.sigTermHandler);
|
|
730
|
+
this.sigTermHandler = void 0;
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
/**
|
|
735
|
+
* Checks if an error indicates a session invalidation that requires reconnection.
|
|
736
|
+
*
|
|
737
|
+
* Common session-related errors include:
|
|
738
|
+
* - "No valid session ID provided" (HTTP 400)
|
|
739
|
+
* - "Server not initialized" (HTTP 400)
|
|
740
|
+
* - "Not connected" (protocol state error)
|
|
741
|
+
* - Connection refused errors
|
|
742
|
+
*
|
|
743
|
+
* @param error - The error to check
|
|
744
|
+
* @returns true if the error indicates a session problem requiring reconnection
|
|
745
|
+
*
|
|
746
|
+
* @internal
|
|
747
|
+
*/
|
|
748
|
+
isSessionError(error) {
|
|
749
|
+
if (!(error instanceof Error)) {
|
|
750
|
+
return false;
|
|
616
751
|
}
|
|
752
|
+
const errorMessage = error.message.toLowerCase();
|
|
753
|
+
return errorMessage.includes("no valid session") || errorMessage.includes("session") || errorMessage.includes("server not initialized") || errorMessage.includes("not connected") || errorMessage.includes("http 400") || errorMessage.includes("http 401") || errorMessage.includes("http 403") || errorMessage.includes("econnrefused") || errorMessage.includes("fetch failed") || errorMessage.includes("connection refused");
|
|
754
|
+
}
|
|
755
|
+
/**
|
|
756
|
+
* Forces a reconnection to the MCP server by disconnecting and reconnecting.
|
|
757
|
+
*
|
|
758
|
+
* This is useful when the session becomes invalid (e.g., after server restart)
|
|
759
|
+
* and the client needs to establish a fresh connection.
|
|
760
|
+
*
|
|
761
|
+
* @returns Promise resolving when reconnection is complete
|
|
762
|
+
* @throws {Error} If reconnection fails
|
|
763
|
+
*
|
|
764
|
+
* @internal
|
|
765
|
+
*/
|
|
766
|
+
async forceReconnect() {
|
|
767
|
+
this.log("debug", "Forcing reconnection to MCP server...");
|
|
768
|
+
try {
|
|
769
|
+
if (this.transport) {
|
|
770
|
+
await this.transport.close();
|
|
771
|
+
}
|
|
772
|
+
} catch (e) {
|
|
773
|
+
this.log("debug", "Error during force disconnect (ignored)", {
|
|
774
|
+
error: e instanceof Error ? e.message : String(e)
|
|
775
|
+
});
|
|
776
|
+
}
|
|
777
|
+
this.transport = void 0;
|
|
778
|
+
this.isConnected = null;
|
|
779
|
+
await this.connect();
|
|
780
|
+
this.log("debug", "Successfully reconnected to MCP server");
|
|
617
781
|
}
|
|
618
782
|
async listResources() {
|
|
619
783
|
this.log("debug", `Requesting resources from MCP server`);
|
|
@@ -701,6 +865,12 @@ var InternalMastraMCPClient = class extends base.MastraBase {
|
|
|
701
865
|
return handler(request.params);
|
|
702
866
|
});
|
|
703
867
|
}
|
|
868
|
+
setProgressNotificationHandler(handler) {
|
|
869
|
+
this.log("debug", "Setting progress notification handler");
|
|
870
|
+
this.client.setNotificationHandler(types_js.ProgressNotificationSchema, (notification) => {
|
|
871
|
+
handler(notification.params);
|
|
872
|
+
});
|
|
873
|
+
}
|
|
704
874
|
async convertInputSchema(inputSchema) {
|
|
705
875
|
if (utils.isZodType(inputSchema)) {
|
|
706
876
|
return inputSchema;
|
|
@@ -774,7 +944,7 @@ var InternalMastraMCPClient = class extends base.MastraBase {
|
|
|
774
944
|
}
|
|
775
945
|
async tools() {
|
|
776
946
|
this.log("debug", `Requesting tools from MCP server`);
|
|
777
|
-
const { tools: tools$1 } = await this.client.listTools({ timeout: this.timeout });
|
|
947
|
+
const { tools: tools$1 } = await this.client.listTools({}, { timeout: this.timeout });
|
|
778
948
|
const toolsRes = {};
|
|
779
949
|
for (const tool of tools$1) {
|
|
780
950
|
this.log("debug", `Processing tool: ${tool.name}`);
|
|
@@ -787,12 +957,14 @@ var InternalMastraMCPClient = class extends base.MastraBase {
|
|
|
787
957
|
execute: async (input, context) => {
|
|
788
958
|
const previousContext = this.currentOperationContext;
|
|
789
959
|
this.currentOperationContext = context?.requestContext || null;
|
|
790
|
-
|
|
791
|
-
this.log("debug", `Executing tool: ${tool.name}`, { toolArgs: input });
|
|
960
|
+
const executeToolCall = async () => {
|
|
961
|
+
this.log("debug", `Executing tool: ${tool.name}`, { toolArgs: input, runId: context?.runId });
|
|
792
962
|
const res = await this.client.callTool(
|
|
793
963
|
{
|
|
794
964
|
name: tool.name,
|
|
795
|
-
arguments: input
|
|
965
|
+
arguments: input,
|
|
966
|
+
// Use runId as progress token if available, otherwise generate a random UUID
|
|
967
|
+
...this.enableProgressTracking ? { _meta: { progressToken: context?.runId || crypto.randomUUID() } } : {}
|
|
796
968
|
},
|
|
797
969
|
types_js.CallToolResultSchema,
|
|
798
970
|
{
|
|
@@ -800,8 +972,31 @@ var InternalMastraMCPClient = class extends base.MastraBase {
|
|
|
800
972
|
}
|
|
801
973
|
);
|
|
802
974
|
this.log("debug", `Tool executed successfully: ${tool.name}`);
|
|
975
|
+
if (res.structuredContent !== void 0) {
|
|
976
|
+
return res.structuredContent;
|
|
977
|
+
}
|
|
803
978
|
return res;
|
|
979
|
+
};
|
|
980
|
+
try {
|
|
981
|
+
return await executeToolCall();
|
|
804
982
|
} catch (e) {
|
|
983
|
+
if (this.isSessionError(e)) {
|
|
984
|
+
this.log("debug", `Session error detected for tool ${tool.name}, attempting reconnection...`, {
|
|
985
|
+
error: e instanceof Error ? e.message : String(e)
|
|
986
|
+
});
|
|
987
|
+
try {
|
|
988
|
+
await this.forceReconnect();
|
|
989
|
+
this.log("debug", `Retrying tool ${tool.name} after reconnection...`);
|
|
990
|
+
return await executeToolCall();
|
|
991
|
+
} catch (reconnectError) {
|
|
992
|
+
this.log("error", `Reconnection or retry failed for tool ${tool.name}`, {
|
|
993
|
+
originalError: e instanceof Error ? e.message : String(e),
|
|
994
|
+
reconnectError: reconnectError instanceof Error ? reconnectError.stack : String(reconnectError),
|
|
995
|
+
toolArgs: input
|
|
996
|
+
});
|
|
997
|
+
throw e;
|
|
998
|
+
}
|
|
999
|
+
}
|
|
805
1000
|
this.log("error", `Error calling tool: ${tool.name}`, {
|
|
806
1001
|
error: e instanceof Error ? e.stack : JSON.stringify(e, null, 2),
|
|
807
1002
|
toolArgs: input
|
|
@@ -825,8 +1020,6 @@ var InternalMastraMCPClient = class extends base.MastraBase {
|
|
|
825
1020
|
return toolsRes;
|
|
826
1021
|
}
|
|
827
1022
|
};
|
|
828
|
-
|
|
829
|
-
// src/client/configuration.ts
|
|
830
1023
|
var mcpClientInstances = /* @__PURE__ */ new Map();
|
|
831
1024
|
var MCPClient = class extends base.MastraBase {
|
|
832
1025
|
serverConfigs = {};
|
|
@@ -899,6 +1092,48 @@ To fix this you have three different options:
|
|
|
899
1092
|
this.addToInstanceCache();
|
|
900
1093
|
return this;
|
|
901
1094
|
}
|
|
1095
|
+
/**
|
|
1096
|
+
* Provides access to progress-related operations for tracking long-running operations.
|
|
1097
|
+
*
|
|
1098
|
+
* Progress tracking allows MCP servers to send updates about the status of ongoing operations,
|
|
1099
|
+
* providing real-time feedback to users about task completion and current state.
|
|
1100
|
+
*
|
|
1101
|
+
* @example
|
|
1102
|
+
* ```typescript
|
|
1103
|
+
* // Set up handler for progress updates from a server
|
|
1104
|
+
* await mcp.progress.onUpdate('serverName', (params) => {
|
|
1105
|
+
* console.log(`Progress: ${params.progress}%`);
|
|
1106
|
+
* console.log(`Status: ${params.message}`);
|
|
1107
|
+
*
|
|
1108
|
+
* if (params.total) {
|
|
1109
|
+
* console.log(`Completed ${params.progress} of ${params.total} items`);
|
|
1110
|
+
* }
|
|
1111
|
+
* });
|
|
1112
|
+
* ```
|
|
1113
|
+
*/
|
|
1114
|
+
get progress() {
|
|
1115
|
+
this.addToInstanceCache();
|
|
1116
|
+
return {
|
|
1117
|
+
onUpdate: async (serverName, handler) => {
|
|
1118
|
+
try {
|
|
1119
|
+
const internalClient = await this.getConnectedClientForServer(serverName);
|
|
1120
|
+
return internalClient.progress.onUpdate(handler);
|
|
1121
|
+
} catch (err) {
|
|
1122
|
+
throw new error.MastraError(
|
|
1123
|
+
{
|
|
1124
|
+
id: "MCP_CLIENT_ON_UPDATE_PROGRESS_FAILED",
|
|
1125
|
+
domain: error.ErrorDomain.MCP,
|
|
1126
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1127
|
+
details: {
|
|
1128
|
+
serverName
|
|
1129
|
+
}
|
|
1130
|
+
},
|
|
1131
|
+
err
|
|
1132
|
+
);
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
};
|
|
1136
|
+
}
|
|
902
1137
|
/**
|
|
903
1138
|
* Provides access to elicitation-related operations for interactive user input collection.
|
|
904
1139
|
*
|
|
@@ -1587,14 +1822,204 @@ To fix this you have three different options:
|
|
|
1587
1822
|
}
|
|
1588
1823
|
};
|
|
1589
1824
|
|
|
1590
|
-
//
|
|
1825
|
+
// src/client/oauth-provider.ts
|
|
1826
|
+
var InMemoryOAuthStorage = class {
|
|
1827
|
+
data = /* @__PURE__ */ new Map();
|
|
1828
|
+
set(key, value) {
|
|
1829
|
+
this.data.set(key, value);
|
|
1830
|
+
}
|
|
1831
|
+
get(key) {
|
|
1832
|
+
return this.data.get(key);
|
|
1833
|
+
}
|
|
1834
|
+
delete(key) {
|
|
1835
|
+
this.data.delete(key);
|
|
1836
|
+
}
|
|
1837
|
+
clear() {
|
|
1838
|
+
this.data.clear();
|
|
1839
|
+
}
|
|
1840
|
+
};
|
|
1841
|
+
var MCPOAuthClientProvider = class {
|
|
1842
|
+
_redirectUrl;
|
|
1843
|
+
_clientMetadata;
|
|
1844
|
+
storage;
|
|
1845
|
+
onRedirect;
|
|
1846
|
+
generateState;
|
|
1847
|
+
_clientInfo;
|
|
1848
|
+
constructor(options) {
|
|
1849
|
+
this._redirectUrl = options.redirectUrl;
|
|
1850
|
+
this._clientMetadata = options.clientMetadata;
|
|
1851
|
+
this._clientInfo = options.clientInformation;
|
|
1852
|
+
this.storage = options.storage ?? new InMemoryOAuthStorage();
|
|
1853
|
+
this.onRedirect = options.onRedirectToAuthorization;
|
|
1854
|
+
this.generateState = options.stateGenerator ?? (() => crypto.randomUUID());
|
|
1855
|
+
}
|
|
1856
|
+
/**
|
|
1857
|
+
* The URL to redirect the user agent to after authorization.
|
|
1858
|
+
*/
|
|
1859
|
+
get redirectUrl() {
|
|
1860
|
+
return this._redirectUrl;
|
|
1861
|
+
}
|
|
1862
|
+
/**
|
|
1863
|
+
* Metadata about this OAuth client.
|
|
1864
|
+
*/
|
|
1865
|
+
get clientMetadata() {
|
|
1866
|
+
return this._clientMetadata;
|
|
1867
|
+
}
|
|
1868
|
+
/**
|
|
1869
|
+
* Returns a OAuth2 state parameter.
|
|
1870
|
+
*/
|
|
1871
|
+
async state() {
|
|
1872
|
+
return this.generateState();
|
|
1873
|
+
}
|
|
1874
|
+
/**
|
|
1875
|
+
* Loads information about this OAuth client.
|
|
1876
|
+
*/
|
|
1877
|
+
async clientInformation() {
|
|
1878
|
+
if (this._clientInfo) {
|
|
1879
|
+
return this._clientInfo;
|
|
1880
|
+
}
|
|
1881
|
+
const stored = await this.storage.get("client_info");
|
|
1882
|
+
if (stored) {
|
|
1883
|
+
try {
|
|
1884
|
+
return JSON.parse(stored);
|
|
1885
|
+
} catch {
|
|
1886
|
+
}
|
|
1887
|
+
}
|
|
1888
|
+
return void 0;
|
|
1889
|
+
}
|
|
1890
|
+
/**
|
|
1891
|
+
* Saves dynamically registered client information.
|
|
1892
|
+
*/
|
|
1893
|
+
async saveClientInformation(clientInformation) {
|
|
1894
|
+
this._clientInfo = clientInformation;
|
|
1895
|
+
await this.storage.set("client_info", JSON.stringify(clientInformation));
|
|
1896
|
+
}
|
|
1897
|
+
/**
|
|
1898
|
+
* Loads existing OAuth tokens.
|
|
1899
|
+
*/
|
|
1900
|
+
async tokens() {
|
|
1901
|
+
const stored = await this.storage.get("tokens");
|
|
1902
|
+
if (stored) {
|
|
1903
|
+
try {
|
|
1904
|
+
return JSON.parse(stored);
|
|
1905
|
+
} catch {
|
|
1906
|
+
}
|
|
1907
|
+
}
|
|
1908
|
+
return void 0;
|
|
1909
|
+
}
|
|
1910
|
+
/**
|
|
1911
|
+
* Stores new OAuth tokens after successful authorization.
|
|
1912
|
+
*/
|
|
1913
|
+
async saveTokens(tokens) {
|
|
1914
|
+
await this.storage.set("tokens", JSON.stringify(tokens));
|
|
1915
|
+
}
|
|
1916
|
+
/**
|
|
1917
|
+
* Invoked to redirect the user agent to the authorization URL.
|
|
1918
|
+
*/
|
|
1919
|
+
async redirectToAuthorization(authorizationUrl) {
|
|
1920
|
+
if (this.onRedirect) {
|
|
1921
|
+
await this.onRedirect(authorizationUrl);
|
|
1922
|
+
} else {
|
|
1923
|
+
console.info(`Authorization required. Please visit: ${authorizationUrl.toString()}`);
|
|
1924
|
+
}
|
|
1925
|
+
}
|
|
1926
|
+
/**
|
|
1927
|
+
* Saves a PKCE code verifier before redirecting to authorization.
|
|
1928
|
+
*/
|
|
1929
|
+
async saveCodeVerifier(codeVerifier) {
|
|
1930
|
+
await this.storage.set("code_verifier", codeVerifier);
|
|
1931
|
+
}
|
|
1932
|
+
/**
|
|
1933
|
+
* Loads the PKCE code verifier for validating authorization result.
|
|
1934
|
+
*/
|
|
1935
|
+
async codeVerifier() {
|
|
1936
|
+
const verifier = await this.storage.get("code_verifier");
|
|
1937
|
+
if (!verifier) {
|
|
1938
|
+
throw new Error("No code verifier found. Authorization flow may not have started properly.");
|
|
1939
|
+
}
|
|
1940
|
+
return verifier;
|
|
1941
|
+
}
|
|
1942
|
+
/**
|
|
1943
|
+
* Optional: Custom client authentication for token requests.
|
|
1944
|
+
* Uses default behavior if not implemented.
|
|
1945
|
+
*/
|
|
1946
|
+
async addClientAuthentication(_headers, _params, _url, _metadata) {
|
|
1947
|
+
}
|
|
1948
|
+
/**
|
|
1949
|
+
* Invalidate credentials when server indicates they're no longer valid.
|
|
1950
|
+
*/
|
|
1951
|
+
async invalidateCredentials(scope) {
|
|
1952
|
+
switch (scope) {
|
|
1953
|
+
case "all":
|
|
1954
|
+
await this.storage.delete("tokens");
|
|
1955
|
+
await this.storage.delete("client_info");
|
|
1956
|
+
await this.storage.delete("code_verifier");
|
|
1957
|
+
this._clientInfo = void 0;
|
|
1958
|
+
break;
|
|
1959
|
+
case "client":
|
|
1960
|
+
await this.storage.delete("client_info");
|
|
1961
|
+
this._clientInfo = void 0;
|
|
1962
|
+
break;
|
|
1963
|
+
case "tokens":
|
|
1964
|
+
await this.storage.delete("tokens");
|
|
1965
|
+
break;
|
|
1966
|
+
case "verifier":
|
|
1967
|
+
await this.storage.delete("code_verifier");
|
|
1968
|
+
break;
|
|
1969
|
+
}
|
|
1970
|
+
}
|
|
1971
|
+
/**
|
|
1972
|
+
* Clear all stored OAuth data.
|
|
1973
|
+
* Useful for logging out or resetting state.
|
|
1974
|
+
*/
|
|
1975
|
+
async clear() {
|
|
1976
|
+
await this.invalidateCredentials("all");
|
|
1977
|
+
}
|
|
1978
|
+
/**
|
|
1979
|
+
* Check if the provider has valid (non-expired) tokens.
|
|
1980
|
+
*/
|
|
1981
|
+
async hasValidTokens() {
|
|
1982
|
+
const currentTokens = await this.tokens();
|
|
1983
|
+
if (!currentTokens) return false;
|
|
1984
|
+
if (!currentTokens.access_token) return false;
|
|
1985
|
+
return true;
|
|
1986
|
+
}
|
|
1987
|
+
};
|
|
1988
|
+
function createSimpleTokenProvider(accessToken, options) {
|
|
1989
|
+
const tokens = {
|
|
1990
|
+
access_token: accessToken,
|
|
1991
|
+
token_type: options.tokenType ?? "Bearer",
|
|
1992
|
+
refresh_token: options.refreshToken,
|
|
1993
|
+
expires_in: options.expiresIn,
|
|
1994
|
+
scope: options.scope
|
|
1995
|
+
};
|
|
1996
|
+
const storage = new InMemoryOAuthStorage();
|
|
1997
|
+
storage.set("tokens", JSON.stringify(tokens));
|
|
1998
|
+
if (options.clientInformation) {
|
|
1999
|
+
storage.set("client_info", JSON.stringify(options.clientInformation));
|
|
2000
|
+
}
|
|
2001
|
+
return new MCPOAuthClientProvider({
|
|
2002
|
+
redirectUrl: options.redirectUrl,
|
|
2003
|
+
clientMetadata: options.clientMetadata,
|
|
2004
|
+
clientInformation: options.clientInformation,
|
|
2005
|
+
storage
|
|
2006
|
+
});
|
|
2007
|
+
}
|
|
2008
|
+
|
|
2009
|
+
// ../../node_modules/.pnpm/hono@4.11.3/node_modules/hono/dist/utils/stream.js
|
|
1591
2010
|
var StreamingApi = class {
|
|
1592
2011
|
writer;
|
|
1593
2012
|
encoder;
|
|
1594
2013
|
writable;
|
|
1595
2014
|
abortSubscribers = [];
|
|
1596
2015
|
responseReadable;
|
|
2016
|
+
/**
|
|
2017
|
+
* Whether the stream has been aborted.
|
|
2018
|
+
*/
|
|
1597
2019
|
aborted = false;
|
|
2020
|
+
/**
|
|
2021
|
+
* Whether the stream has been closed normally.
|
|
2022
|
+
*/
|
|
1598
2023
|
closed = false;
|
|
1599
2024
|
constructor(writable, _readable) {
|
|
1600
2025
|
this.writable = writable;
|
|
@@ -1646,6 +2071,10 @@ var StreamingApi = class {
|
|
|
1646
2071
|
onAbort(listener) {
|
|
1647
2072
|
this.abortSubscribers.push(listener);
|
|
1648
2073
|
}
|
|
2074
|
+
/**
|
|
2075
|
+
* Abort the stream.
|
|
2076
|
+
* You can call this method when stream is aborted by external event.
|
|
2077
|
+
*/
|
|
1649
2078
|
abort() {
|
|
1650
2079
|
if (!this.aborted) {
|
|
1651
2080
|
this.aborted = true;
|
|
@@ -1654,7 +2083,7 @@ var StreamingApi = class {
|
|
|
1654
2083
|
}
|
|
1655
2084
|
};
|
|
1656
2085
|
|
|
1657
|
-
// ../../node_modules/.pnpm/hono@4.
|
|
2086
|
+
// ../../node_modules/.pnpm/hono@4.11.3/node_modules/hono/dist/helper/streaming/utils.js
|
|
1658
2087
|
var isOldBunVersion = () => {
|
|
1659
2088
|
const version = typeof Bun !== "undefined" ? Bun.version : void 0;
|
|
1660
2089
|
if (version === void 0) {
|
|
@@ -1665,7 +2094,7 @@ var isOldBunVersion = () => {
|
|
|
1665
2094
|
return result;
|
|
1666
2095
|
};
|
|
1667
2096
|
|
|
1668
|
-
// ../../node_modules/.pnpm/hono@4.
|
|
2097
|
+
// ../../node_modules/.pnpm/hono@4.11.3/node_modules/hono/dist/utils/html.js
|
|
1669
2098
|
var HtmlEscapedCallbackPhase = {
|
|
1670
2099
|
Stringify: 1};
|
|
1671
2100
|
var resolveCallback = async (str, phase, preserveCallbacks, context, buffer) => {
|
|
@@ -1696,7 +2125,7 @@ var resolveCallback = async (str, phase, preserveCallbacks, context, buffer) =>
|
|
|
1696
2125
|
}
|
|
1697
2126
|
};
|
|
1698
2127
|
|
|
1699
|
-
// ../../node_modules/.pnpm/hono@4.
|
|
2128
|
+
// ../../node_modules/.pnpm/hono@4.11.3/node_modules/hono/dist/helper/streaming/sse.js
|
|
1700
2129
|
var SSEStreamingApi = class extends StreamingApi {
|
|
1701
2130
|
constructor(writable, readable) {
|
|
1702
2131
|
super(writable, readable);
|
|
@@ -2144,7 +2573,16 @@ var MCPServer = class extends mcp.MCPServerBase {
|
|
|
2144
2573
|
if (opts.prompts) {
|
|
2145
2574
|
capabilities.prompts = { listChanged: true };
|
|
2146
2575
|
}
|
|
2147
|
-
this.server = new index_js.Server(
|
|
2576
|
+
this.server = new index_js$1.Server(
|
|
2577
|
+
{
|
|
2578
|
+
name: this.name,
|
|
2579
|
+
version: this.version
|
|
2580
|
+
},
|
|
2581
|
+
{
|
|
2582
|
+
capabilities,
|
|
2583
|
+
...this.instructions ? { instructions: this.instructions } : {}
|
|
2584
|
+
}
|
|
2585
|
+
);
|
|
2148
2586
|
this.logger.info(
|
|
2149
2587
|
`Initialized MCPServer '${this.name}' v${this.version} (ID: ${this.id}) with tools: ${Object.keys(this.convertedTools).join(", ")} and resources. Capabilities: ${JSON.stringify(capabilities)}`
|
|
2150
2588
|
);
|
|
@@ -2169,8 +2607,8 @@ var MCPServer = class extends mcp.MCPServerBase {
|
|
|
2169
2607
|
}
|
|
2170
2608
|
});
|
|
2171
2609
|
this.elicitation = {
|
|
2172
|
-
sendRequest: async (request) => {
|
|
2173
|
-
return this.handleElicitationRequest(request);
|
|
2610
|
+
sendRequest: async (request, options) => {
|
|
2611
|
+
return this.handleElicitationRequest(request, void 0, options);
|
|
2174
2612
|
}
|
|
2175
2613
|
};
|
|
2176
2614
|
}
|
|
@@ -2180,15 +2618,51 @@ var MCPServer = class extends mcp.MCPServerBase {
|
|
|
2180
2618
|
*
|
|
2181
2619
|
* @param request - The elicitation request containing message and schema
|
|
2182
2620
|
* @param serverInstance - Optional server instance to use; defaults to main server for backward compatibility
|
|
2621
|
+
* @param options - Optional request options (timeout, signal, etc.)
|
|
2183
2622
|
* @returns Promise that resolves to the client's response
|
|
2184
2623
|
*/
|
|
2185
|
-
async handleElicitationRequest(request, serverInstance) {
|
|
2624
|
+
async handleElicitationRequest(request, serverInstance, options) {
|
|
2186
2625
|
this.logger.debug(`Sending elicitation request: ${request.message}`);
|
|
2187
2626
|
const server = serverInstance || this.server;
|
|
2188
|
-
const response = await server.elicitInput(request);
|
|
2627
|
+
const response = await server.elicitInput(request, options);
|
|
2189
2628
|
this.logger.debug(`Received elicitation response: ${JSON.stringify(response)}`);
|
|
2190
2629
|
return response;
|
|
2191
2630
|
}
|
|
2631
|
+
/**
|
|
2632
|
+
* Reads and parses the JSON body from an HTTP request.
|
|
2633
|
+
* If the request body was already parsed by middleware (e.g., express.json()),
|
|
2634
|
+
* it uses the pre-parsed body from req.body. Otherwise, it reads from the stream.
|
|
2635
|
+
*
|
|
2636
|
+
* This allows the MCP server to work with Express apps that use express.json()
|
|
2637
|
+
* globally without requiring special route exclusions.
|
|
2638
|
+
*
|
|
2639
|
+
* @param req - The incoming HTTP request
|
|
2640
|
+
* @param options - Optional configuration
|
|
2641
|
+
* @param options.preParsedOnly - If true, only return pre-parsed body from middleware,
|
|
2642
|
+
* returning undefined if not available. This allows the caller to fall back to
|
|
2643
|
+
* their own body reading logic (e.g., SDK's getRawBody with size limits).
|
|
2644
|
+
*/
|
|
2645
|
+
async readJsonBody(req, options) {
|
|
2646
|
+
const reqWithBody = req;
|
|
2647
|
+
if (reqWithBody.body !== void 0) {
|
|
2648
|
+
return reqWithBody.body;
|
|
2649
|
+
}
|
|
2650
|
+
if (options?.preParsedOnly) {
|
|
2651
|
+
return void 0;
|
|
2652
|
+
}
|
|
2653
|
+
return new Promise((resolve, reject) => {
|
|
2654
|
+
let data = "";
|
|
2655
|
+
req.on("data", (chunk) => data += chunk);
|
|
2656
|
+
req.on("end", () => {
|
|
2657
|
+
try {
|
|
2658
|
+
resolve(JSON.parse(data));
|
|
2659
|
+
} catch (e) {
|
|
2660
|
+
reject(e);
|
|
2661
|
+
}
|
|
2662
|
+
});
|
|
2663
|
+
req.on("error", reject);
|
|
2664
|
+
});
|
|
2665
|
+
}
|
|
2192
2666
|
/**
|
|
2193
2667
|
* Creates a new Server instance configured with all handlers for HTTP sessions.
|
|
2194
2668
|
* Each HTTP client connection gets its own Server instance to avoid routing conflicts.
|
|
@@ -2205,7 +2679,16 @@ var MCPServer = class extends mcp.MCPServerBase {
|
|
|
2205
2679
|
if (this.promptOptions) {
|
|
2206
2680
|
capabilities.prompts = { listChanged: true };
|
|
2207
2681
|
}
|
|
2208
|
-
const serverInstance = new index_js.Server(
|
|
2682
|
+
const serverInstance = new index_js$1.Server(
|
|
2683
|
+
{
|
|
2684
|
+
name: this.name,
|
|
2685
|
+
version: this.version
|
|
2686
|
+
},
|
|
2687
|
+
{
|
|
2688
|
+
capabilities,
|
|
2689
|
+
...this.instructions ? { instructions: this.instructions } : {}
|
|
2690
|
+
}
|
|
2691
|
+
);
|
|
2209
2692
|
this.registerHandlersOnServer(serverInstance);
|
|
2210
2693
|
return serverInstance;
|
|
2211
2694
|
}
|
|
@@ -2226,6 +2709,12 @@ var MCPServer = class extends mcp.MCPServerBase {
|
|
|
2226
2709
|
if (tool.outputSchema) {
|
|
2227
2710
|
toolSpec.outputSchema = tool.outputSchema.jsonSchema;
|
|
2228
2711
|
}
|
|
2712
|
+
if (tool.mcp?.annotations) {
|
|
2713
|
+
toolSpec.annotations = tool.mcp.annotations;
|
|
2714
|
+
}
|
|
2715
|
+
if (tool.mcp?._meta) {
|
|
2716
|
+
toolSpec._meta = tool.mcp._meta;
|
|
2717
|
+
}
|
|
2229
2718
|
return toolSpec;
|
|
2230
2719
|
})
|
|
2231
2720
|
};
|
|
@@ -2274,8 +2763,8 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
2274
2763
|
};
|
|
2275
2764
|
}
|
|
2276
2765
|
const sessionElicitation = {
|
|
2277
|
-
sendRequest: async (request2) => {
|
|
2278
|
-
return this.handleElicitationRequest(request2, serverInstance);
|
|
2766
|
+
sendRequest: async (request2, options) => {
|
|
2767
|
+
return this.handleElicitationRequest(request2, serverInstance, options);
|
|
2279
2768
|
}
|
|
2280
2769
|
};
|
|
2281
2770
|
const mcpOptions = {
|
|
@@ -2575,7 +3064,16 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
2575
3064
|
`Executing agent tool '${agentToolName}' for agent '${agent.name}' with message: "${inputData.message}"`
|
|
2576
3065
|
);
|
|
2577
3066
|
try {
|
|
2578
|
-
const
|
|
3067
|
+
const proxiedContext = context?.requestContext || new requestContext.RequestContext();
|
|
3068
|
+
if (context?.mcp?.extra) {
|
|
3069
|
+
Object.entries(context.mcp.extra).forEach(([key, value]) => {
|
|
3070
|
+
proxiedContext.set(key, value);
|
|
3071
|
+
});
|
|
3072
|
+
}
|
|
3073
|
+
const response = await agent.generate(inputData.message, {
|
|
3074
|
+
...context ?? {},
|
|
3075
|
+
requestContext: proxiedContext
|
|
3076
|
+
});
|
|
2579
3077
|
return response;
|
|
2580
3078
|
} catch (error) {
|
|
2581
3079
|
this.logger.error(`Error executing agent tool '${agentToolName}' for agent '${agent.name}':`, error);
|
|
@@ -2639,10 +3137,16 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
2639
3137
|
inputData
|
|
2640
3138
|
);
|
|
2641
3139
|
try {
|
|
2642
|
-
const
|
|
3140
|
+
const proxiedContext = context?.requestContext || new requestContext.RequestContext();
|
|
3141
|
+
if (context?.mcp?.extra) {
|
|
3142
|
+
Object.entries(context.mcp.extra).forEach(([key, value]) => {
|
|
3143
|
+
proxiedContext.set(key, value);
|
|
3144
|
+
});
|
|
3145
|
+
}
|
|
3146
|
+
const run2 = await workflow.createRun({ runId: proxiedContext?.get("runId") });
|
|
2643
3147
|
const response = await run2.start({
|
|
2644
3148
|
inputData,
|
|
2645
|
-
requestContext:
|
|
3149
|
+
requestContext: proxiedContext,
|
|
2646
3150
|
tracingContext: context?.tracingContext
|
|
2647
3151
|
});
|
|
2648
3152
|
return response;
|
|
@@ -2761,7 +3265,7 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
2761
3265
|
* ```
|
|
2762
3266
|
*/
|
|
2763
3267
|
async startStdio() {
|
|
2764
|
-
this.stdioTransport = new stdio_js.StdioServerTransport();
|
|
3268
|
+
this.stdioTransport = new stdio_js$1.StdioServerTransport();
|
|
2765
3269
|
try {
|
|
2766
3270
|
await this.server.connect(this.stdioTransport);
|
|
2767
3271
|
} catch (error$1) {
|
|
@@ -2798,7 +3302,7 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
2798
3302
|
*
|
|
2799
3303
|
* @example
|
|
2800
3304
|
* ```typescript
|
|
2801
|
-
* import http from 'http';
|
|
3305
|
+
* import http from 'node:http';
|
|
2802
3306
|
*
|
|
2803
3307
|
* const httpServer = http.createServer(async (req, res) => {
|
|
2804
3308
|
* await server.startSSE({
|
|
@@ -2829,7 +3333,8 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
2829
3333
|
res.end("SSE connection not established");
|
|
2830
3334
|
return;
|
|
2831
3335
|
}
|
|
2832
|
-
await this.
|
|
3336
|
+
const parsedBody = await this.readJsonBody(req, { preParsedOnly: true });
|
|
3337
|
+
await this.sseTransport.handlePostMessage(req, res, parsedBody);
|
|
2833
3338
|
} else {
|
|
2834
3339
|
this.logger.debug("Unknown path:", { path: url.pathname });
|
|
2835
3340
|
res.writeHead(404);
|
|
@@ -2956,8 +3461,8 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
2956
3461
|
*
|
|
2957
3462
|
* @example
|
|
2958
3463
|
* ```typescript
|
|
2959
|
-
* import http from 'http';
|
|
2960
|
-
* import { randomUUID } from 'crypto';
|
|
3464
|
+
* import http from 'node:http';
|
|
3465
|
+
* import { randomUUID } from 'node:crypto';
|
|
2961
3466
|
*
|
|
2962
3467
|
* const httpServer = http.createServer(async (req, res) => {
|
|
2963
3468
|
* await server.startHTTP({
|
|
@@ -3001,7 +3506,7 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
3001
3506
|
httpPath,
|
|
3002
3507
|
req,
|
|
3003
3508
|
res,
|
|
3004
|
-
options
|
|
3509
|
+
options
|
|
3005
3510
|
}) {
|
|
3006
3511
|
this.logger.debug(`startHTTP: Received ${req.method} request to ${url.pathname}`);
|
|
3007
3512
|
if (url.pathname !== httpPath) {
|
|
@@ -3010,11 +3515,18 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
3010
3515
|
res.end();
|
|
3011
3516
|
return;
|
|
3012
3517
|
}
|
|
3013
|
-
|
|
3014
|
-
|
|
3518
|
+
const isStatelessMode = options?.serverless || options && "sessionIdGenerator" in options && options.sessionIdGenerator === void 0;
|
|
3519
|
+
if (isStatelessMode) {
|
|
3520
|
+
this.logger.debug("startHTTP: Running in stateless mode (serverless or sessionIdGenerator: undefined)");
|
|
3015
3521
|
await this.handleServerlessRequest(req, res);
|
|
3016
3522
|
return;
|
|
3017
3523
|
}
|
|
3524
|
+
const mergedOptions = {
|
|
3525
|
+
sessionIdGenerator: () => crypto$1.randomUUID(),
|
|
3526
|
+
// default: enabled
|
|
3527
|
+
...options
|
|
3528
|
+
// user-provided overrides default
|
|
3529
|
+
};
|
|
3018
3530
|
const sessionId = req.headers["mcp-session-id"];
|
|
3019
3531
|
let transport;
|
|
3020
3532
|
this.logger.debug(
|
|
@@ -3029,40 +3541,18 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
3029
3541
|
`startHTTP: Handling GET request for existing session ${sessionId}. Calling transport.handleRequest.`
|
|
3030
3542
|
);
|
|
3031
3543
|
}
|
|
3032
|
-
const body = req.method === "POST" ? await
|
|
3033
|
-
let data = "";
|
|
3034
|
-
req.on("data", (chunk) => data += chunk);
|
|
3035
|
-
req.on("end", () => {
|
|
3036
|
-
try {
|
|
3037
|
-
resolve(JSON.parse(data));
|
|
3038
|
-
} catch (e) {
|
|
3039
|
-
reject(e);
|
|
3040
|
-
}
|
|
3041
|
-
});
|
|
3042
|
-
req.on("error", reject);
|
|
3043
|
-
}) : void 0;
|
|
3544
|
+
const body = req.method === "POST" ? await this.readJsonBody(req) : void 0;
|
|
3044
3545
|
await transport.handleRequest(req, res, body);
|
|
3045
3546
|
} else {
|
|
3046
3547
|
this.logger.debug(`startHTTP: No existing Streamable HTTP session ID found. ${req.method}`);
|
|
3047
3548
|
if (req.method === "POST") {
|
|
3048
|
-
const body = await
|
|
3049
|
-
let data = "";
|
|
3050
|
-
req.on("data", (chunk) => data += chunk);
|
|
3051
|
-
req.on("end", () => {
|
|
3052
|
-
try {
|
|
3053
|
-
resolve(JSON.parse(data));
|
|
3054
|
-
} catch (e) {
|
|
3055
|
-
reject(e);
|
|
3056
|
-
}
|
|
3057
|
-
});
|
|
3058
|
-
req.on("error", reject);
|
|
3059
|
-
});
|
|
3549
|
+
const body = await this.readJsonBody(req);
|
|
3060
3550
|
const { isInitializeRequest } = await import('@modelcontextprotocol/sdk/types.js');
|
|
3061
3551
|
if (isInitializeRequest(body)) {
|
|
3062
3552
|
this.logger.debug("startHTTP: Received Streamable HTTP initialize request, creating new transport.");
|
|
3063
|
-
transport = new streamableHttp_js.StreamableHTTPServerTransport({
|
|
3064
|
-
...
|
|
3065
|
-
sessionIdGenerator:
|
|
3553
|
+
transport = new streamableHttp_js$1.StreamableHTTPServerTransport({
|
|
3554
|
+
...mergedOptions,
|
|
3555
|
+
sessionIdGenerator: mergedOptions.sessionIdGenerator,
|
|
3066
3556
|
onsessioninitialized: (id) => {
|
|
3067
3557
|
this.streamableHTTPTransports.set(id, transport);
|
|
3068
3558
|
}
|
|
@@ -3166,24 +3656,13 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
3166
3656
|
async handleServerlessRequest(req, res) {
|
|
3167
3657
|
try {
|
|
3168
3658
|
this.logger.debug(`handleServerlessRequest: Received ${req.method} request`);
|
|
3169
|
-
const body = req.method === "POST" ? await
|
|
3170
|
-
let data = "";
|
|
3171
|
-
req.on("data", (chunk) => data += chunk);
|
|
3172
|
-
req.on("end", () => {
|
|
3173
|
-
try {
|
|
3174
|
-
resolve(JSON.parse(data));
|
|
3175
|
-
} catch (e) {
|
|
3176
|
-
reject(new Error(`Invalid JSON in request body: ${e instanceof Error ? e.message : String(e)}`));
|
|
3177
|
-
}
|
|
3178
|
-
});
|
|
3179
|
-
req.on("error", reject);
|
|
3180
|
-
}) : void 0;
|
|
3659
|
+
const body = req.method === "POST" ? await this.readJsonBody(req) : void 0;
|
|
3181
3660
|
this.logger.debug(`handleServerlessRequest: Processing ${req.method} request`, {
|
|
3182
3661
|
method: body?.method,
|
|
3183
3662
|
id: body?.id
|
|
3184
3663
|
});
|
|
3185
3664
|
const transientServer = this.createServerInstance();
|
|
3186
|
-
const tempTransport = new streamableHttp_js.StreamableHTTPServerTransport({
|
|
3665
|
+
const tempTransport = new streamableHttp_js$1.StreamableHTTPServerTransport({
|
|
3187
3666
|
sessionIdGenerator: void 0,
|
|
3188
3667
|
enableJsonResponse: true
|
|
3189
3668
|
});
|
|
@@ -3245,7 +3724,7 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
3245
3724
|
}) {
|
|
3246
3725
|
try {
|
|
3247
3726
|
this.logger.debug("Received SSE connection");
|
|
3248
|
-
this.sseTransport = new sse_js.SSEServerTransport(messagePath, res);
|
|
3727
|
+
this.sseTransport = new sse_js$1.SSEServerTransport(messagePath, res);
|
|
3249
3728
|
await this.server.connect(this.sseTransport);
|
|
3250
3729
|
this.server.onclose = async () => {
|
|
3251
3730
|
this.sseTransport = void 0;
|
|
@@ -3607,8 +4086,273 @@ Provided arguments: ${JSON.stringify(args, null, 2)}`,
|
|
|
3607
4086
|
}
|
|
3608
4087
|
}
|
|
3609
4088
|
};
|
|
4089
|
+
function escapeHeaderValue(value) {
|
|
4090
|
+
return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
4091
|
+
}
|
|
4092
|
+
function generateWWWAuthenticateHeader(options = {}) {
|
|
4093
|
+
const params = [];
|
|
4094
|
+
if (options.resourceMetadataUrl) {
|
|
4095
|
+
params.push(`resource_metadata="${escapeHeaderValue(options.resourceMetadataUrl)}"`);
|
|
4096
|
+
}
|
|
4097
|
+
if (options.additionalParams) {
|
|
4098
|
+
for (const [key, value] of Object.entries(options.additionalParams)) {
|
|
4099
|
+
params.push(`${key}="${escapeHeaderValue(value)}"`);
|
|
4100
|
+
}
|
|
4101
|
+
}
|
|
4102
|
+
if (params.length === 0) {
|
|
4103
|
+
return "Bearer";
|
|
4104
|
+
}
|
|
4105
|
+
return `Bearer ${params.join(", ")}`;
|
|
4106
|
+
}
|
|
4107
|
+
function generateProtectedResourceMetadata(config) {
|
|
4108
|
+
return {
|
|
4109
|
+
resource: config.resource,
|
|
4110
|
+
authorization_servers: config.authorizationServers,
|
|
4111
|
+
scopes_supported: config.scopesSupported ?? ["mcp:read", "mcp:write"],
|
|
4112
|
+
bearer_methods_supported: ["header"],
|
|
4113
|
+
...config.resourceName && { resource_name: config.resourceName },
|
|
4114
|
+
...config.resourceDocumentation && {
|
|
4115
|
+
resource_documentation: config.resourceDocumentation
|
|
4116
|
+
}
|
|
4117
|
+
};
|
|
4118
|
+
}
|
|
4119
|
+
function extractBearerToken(authHeader) {
|
|
4120
|
+
if (!authHeader) return void 0;
|
|
4121
|
+
const prefix = "bearer ";
|
|
4122
|
+
if (authHeader.length <= prefix.length) return void 0;
|
|
4123
|
+
if (authHeader.slice(0, prefix.length).toLowerCase() !== prefix) return void 0;
|
|
4124
|
+
const token = authHeader.slice(prefix.length).trim();
|
|
4125
|
+
return token || void 0;
|
|
4126
|
+
}
|
|
4127
|
+
|
|
4128
|
+
// src/server/oauth-middleware.ts
|
|
4129
|
+
function createOAuthMiddleware(options) {
|
|
4130
|
+
const { oauth, mcpPath = "/mcp", logger } = options;
|
|
4131
|
+
const protectedResourceMetadata = generateProtectedResourceMetadata(oauth);
|
|
4132
|
+
const wellKnownPath = "/.well-known/oauth-protected-resource";
|
|
4133
|
+
const resourceMetadataUrl = new URL(wellKnownPath, oauth.resource).toString();
|
|
4134
|
+
return async function oauthMiddleware(req, res, url) {
|
|
4135
|
+
logger?.debug?.(`OAuth middleware: ${req.method} ${url.pathname}`);
|
|
4136
|
+
if (url.pathname === wellKnownPath && req.method === "GET") {
|
|
4137
|
+
logger?.debug?.("OAuth middleware: Serving Protected Resource Metadata");
|
|
4138
|
+
res.writeHead(200, {
|
|
4139
|
+
"Content-Type": "application/json",
|
|
4140
|
+
"Cache-Control": "max-age=3600",
|
|
4141
|
+
"Access-Control-Allow-Origin": "*"
|
|
4142
|
+
});
|
|
4143
|
+
res.end(JSON.stringify(protectedResourceMetadata));
|
|
4144
|
+
return { proceed: false, handled: true };
|
|
4145
|
+
}
|
|
4146
|
+
if (url.pathname === wellKnownPath && req.method === "OPTIONS") {
|
|
4147
|
+
res.writeHead(204, {
|
|
4148
|
+
"Access-Control-Allow-Origin": "*",
|
|
4149
|
+
"Access-Control-Allow-Methods": "GET, OPTIONS",
|
|
4150
|
+
"Access-Control-Allow-Headers": "Content-Type",
|
|
4151
|
+
"Access-Control-Max-Age": "86400"
|
|
4152
|
+
});
|
|
4153
|
+
res.end();
|
|
4154
|
+
return { proceed: false, handled: true };
|
|
4155
|
+
}
|
|
4156
|
+
if (!url.pathname.startsWith(mcpPath)) {
|
|
4157
|
+
return { proceed: true, handled: false };
|
|
4158
|
+
}
|
|
4159
|
+
const authHeader = req.headers["authorization"];
|
|
4160
|
+
const token = extractBearerToken(authHeader);
|
|
4161
|
+
if (!token) {
|
|
4162
|
+
logger?.debug?.("OAuth middleware: No bearer token provided");
|
|
4163
|
+
res.writeHead(401, {
|
|
4164
|
+
"Content-Type": "application/json",
|
|
4165
|
+
"WWW-Authenticate": generateWWWAuthenticateHeader({ resourceMetadataUrl })
|
|
4166
|
+
});
|
|
4167
|
+
res.end(
|
|
4168
|
+
JSON.stringify({
|
|
4169
|
+
error: "unauthorized",
|
|
4170
|
+
error_description: "Bearer token required"
|
|
4171
|
+
})
|
|
4172
|
+
);
|
|
4173
|
+
return { proceed: false, handled: true };
|
|
4174
|
+
}
|
|
4175
|
+
if (oauth.validateToken) {
|
|
4176
|
+
logger?.debug?.("OAuth middleware: Validating token");
|
|
4177
|
+
const validationResult = await oauth.validateToken(token, oauth.resource);
|
|
4178
|
+
if (!validationResult.valid) {
|
|
4179
|
+
logger?.debug?.(`OAuth middleware: Token validation failed: ${validationResult.error}`);
|
|
4180
|
+
res.writeHead(401, {
|
|
4181
|
+
"Content-Type": "application/json",
|
|
4182
|
+
"WWW-Authenticate": generateWWWAuthenticateHeader({
|
|
4183
|
+
resourceMetadataUrl,
|
|
4184
|
+
additionalParams: {
|
|
4185
|
+
error: validationResult.error || "invalid_token",
|
|
4186
|
+
...validationResult.errorDescription && {
|
|
4187
|
+
error_description: validationResult.errorDescription
|
|
4188
|
+
}
|
|
4189
|
+
}
|
|
4190
|
+
})
|
|
4191
|
+
});
|
|
4192
|
+
res.end(
|
|
4193
|
+
JSON.stringify({
|
|
4194
|
+
error: validationResult.error || "invalid_token",
|
|
4195
|
+
error_description: validationResult.errorDescription || "Token validation failed"
|
|
4196
|
+
})
|
|
4197
|
+
);
|
|
4198
|
+
return { proceed: false, handled: true, tokenValidation: validationResult };
|
|
4199
|
+
}
|
|
4200
|
+
logger?.debug?.("OAuth middleware: Token validated successfully");
|
|
4201
|
+
return { proceed: true, handled: false, tokenValidation: validationResult };
|
|
4202
|
+
}
|
|
4203
|
+
logger?.debug?.("OAuth middleware: No token validation configured, accepting token");
|
|
4204
|
+
return {
|
|
4205
|
+
proceed: true,
|
|
4206
|
+
handled: false,
|
|
4207
|
+
tokenValidation: { valid: true }
|
|
4208
|
+
};
|
|
4209
|
+
};
|
|
4210
|
+
}
|
|
4211
|
+
function createStaticTokenValidator(validTokens) {
|
|
4212
|
+
const tokenSet = new Set(validTokens);
|
|
4213
|
+
return async (token) => {
|
|
4214
|
+
if (tokenSet.has(token)) {
|
|
4215
|
+
return { valid: true, scopes: ["mcp:read", "mcp:write"] };
|
|
4216
|
+
}
|
|
4217
|
+
return {
|
|
4218
|
+
valid: false,
|
|
4219
|
+
error: "invalid_token",
|
|
4220
|
+
errorDescription: "Token not recognized"
|
|
4221
|
+
};
|
|
4222
|
+
};
|
|
4223
|
+
}
|
|
4224
|
+
function createIntrospectionValidator(introspectionEndpoint, clientCredentials) {
|
|
4225
|
+
return async (token, resource) => {
|
|
4226
|
+
try {
|
|
4227
|
+
const headers = {
|
|
4228
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
4229
|
+
};
|
|
4230
|
+
if (clientCredentials) {
|
|
4231
|
+
if (clientCredentials.clientId.includes(":")) {
|
|
4232
|
+
return {
|
|
4233
|
+
valid: false,
|
|
4234
|
+
error: "invalid_request",
|
|
4235
|
+
errorDescription: "clientId cannot contain a colon character per RFC 7617"
|
|
4236
|
+
};
|
|
4237
|
+
}
|
|
4238
|
+
const credentials = Buffer.from(`${clientCredentials.clientId}:${clientCredentials.clientSecret}`).toString(
|
|
4239
|
+
"base64"
|
|
4240
|
+
);
|
|
4241
|
+
headers["Authorization"] = `Basic ${credentials}`;
|
|
4242
|
+
}
|
|
4243
|
+
const response = await fetch(introspectionEndpoint, {
|
|
4244
|
+
method: "POST",
|
|
4245
|
+
headers,
|
|
4246
|
+
body: new URLSearchParams({
|
|
4247
|
+
token,
|
|
4248
|
+
token_type_hint: "access_token"
|
|
4249
|
+
})
|
|
4250
|
+
});
|
|
4251
|
+
if (!response.ok) {
|
|
4252
|
+
return {
|
|
4253
|
+
valid: false,
|
|
4254
|
+
error: "server_error",
|
|
4255
|
+
errorDescription: `Introspection failed: ${response.status}`
|
|
4256
|
+
};
|
|
4257
|
+
}
|
|
4258
|
+
const data = await response.json();
|
|
4259
|
+
if (!data.active) {
|
|
4260
|
+
return {
|
|
4261
|
+
valid: false,
|
|
4262
|
+
error: "invalid_token",
|
|
4263
|
+
errorDescription: "Token is not active"
|
|
4264
|
+
};
|
|
4265
|
+
}
|
|
4266
|
+
if (data.aud) {
|
|
4267
|
+
const audiences = Array.isArray(data.aud) ? data.aud : [data.aud];
|
|
4268
|
+
if (!audiences.includes(resource)) {
|
|
4269
|
+
return {
|
|
4270
|
+
valid: false,
|
|
4271
|
+
error: "invalid_token",
|
|
4272
|
+
errorDescription: "Token audience does not match this resource"
|
|
4273
|
+
};
|
|
4274
|
+
}
|
|
4275
|
+
}
|
|
4276
|
+
return {
|
|
4277
|
+
valid: true,
|
|
4278
|
+
scopes: data.scope?.trim().split(" ").filter((s) => s !== "") || [],
|
|
4279
|
+
subject: data.sub,
|
|
4280
|
+
expiresAt: data.exp,
|
|
4281
|
+
claims: data
|
|
4282
|
+
};
|
|
4283
|
+
} catch (error) {
|
|
4284
|
+
return {
|
|
4285
|
+
valid: false,
|
|
4286
|
+
error: "server_error",
|
|
4287
|
+
errorDescription: error instanceof Error ? error.message : "Introspection failed"
|
|
4288
|
+
};
|
|
4289
|
+
}
|
|
4290
|
+
};
|
|
4291
|
+
}
|
|
3610
4292
|
|
|
4293
|
+
Object.defineProperty(exports, "UnauthorizedError", {
|
|
4294
|
+
enumerable: true,
|
|
4295
|
+
get: function () { return auth_js.UnauthorizedError; }
|
|
4296
|
+
});
|
|
4297
|
+
Object.defineProperty(exports, "auth", {
|
|
4298
|
+
enumerable: true,
|
|
4299
|
+
get: function () { return auth_js.auth; }
|
|
4300
|
+
});
|
|
4301
|
+
Object.defineProperty(exports, "buildDiscoveryUrls", {
|
|
4302
|
+
enumerable: true,
|
|
4303
|
+
get: function () { return auth_js.buildDiscoveryUrls; }
|
|
4304
|
+
});
|
|
4305
|
+
Object.defineProperty(exports, "discoverAuthorizationServerMetadata", {
|
|
4306
|
+
enumerable: true,
|
|
4307
|
+
get: function () { return auth_js.discoverAuthorizationServerMetadata; }
|
|
4308
|
+
});
|
|
4309
|
+
Object.defineProperty(exports, "discoverOAuthMetadata", {
|
|
4310
|
+
enumerable: true,
|
|
4311
|
+
get: function () { return auth_js.discoverOAuthMetadata; }
|
|
4312
|
+
});
|
|
4313
|
+
Object.defineProperty(exports, "discoverOAuthProtectedResourceMetadata", {
|
|
4314
|
+
enumerable: true,
|
|
4315
|
+
get: function () { return auth_js.discoverOAuthProtectedResourceMetadata; }
|
|
4316
|
+
});
|
|
4317
|
+
Object.defineProperty(exports, "exchangeAuthorization", {
|
|
4318
|
+
enumerable: true,
|
|
4319
|
+
get: function () { return auth_js.exchangeAuthorization; }
|
|
4320
|
+
});
|
|
4321
|
+
Object.defineProperty(exports, "extractResourceMetadataUrl", {
|
|
4322
|
+
enumerable: true,
|
|
4323
|
+
get: function () { return auth_js.extractResourceMetadataUrl; }
|
|
4324
|
+
});
|
|
4325
|
+
Object.defineProperty(exports, "parseErrorResponse", {
|
|
4326
|
+
enumerable: true,
|
|
4327
|
+
get: function () { return auth_js.parseErrorResponse; }
|
|
4328
|
+
});
|
|
4329
|
+
Object.defineProperty(exports, "refreshAuthorization", {
|
|
4330
|
+
enumerable: true,
|
|
4331
|
+
get: function () { return auth_js.refreshAuthorization; }
|
|
4332
|
+
});
|
|
4333
|
+
Object.defineProperty(exports, "registerClient", {
|
|
4334
|
+
enumerable: true,
|
|
4335
|
+
get: function () { return auth_js.registerClient; }
|
|
4336
|
+
});
|
|
4337
|
+
Object.defineProperty(exports, "selectResourceURL", {
|
|
4338
|
+
enumerable: true,
|
|
4339
|
+
get: function () { return auth_js.selectResourceURL; }
|
|
4340
|
+
});
|
|
4341
|
+
Object.defineProperty(exports, "startAuthorization", {
|
|
4342
|
+
enumerable: true,
|
|
4343
|
+
get: function () { return auth_js.startAuthorization; }
|
|
4344
|
+
});
|
|
4345
|
+
exports.InMemoryOAuthStorage = InMemoryOAuthStorage;
|
|
4346
|
+
exports.InternalMastraMCPClient = InternalMastraMCPClient;
|
|
3611
4347
|
exports.MCPClient = MCPClient;
|
|
4348
|
+
exports.MCPOAuthClientProvider = MCPOAuthClientProvider;
|
|
3612
4349
|
exports.MCPServer = MCPServer;
|
|
4350
|
+
exports.createIntrospectionValidator = createIntrospectionValidator;
|
|
4351
|
+
exports.createOAuthMiddleware = createOAuthMiddleware;
|
|
4352
|
+
exports.createSimpleTokenProvider = createSimpleTokenProvider;
|
|
4353
|
+
exports.createStaticTokenValidator = createStaticTokenValidator;
|
|
4354
|
+
exports.extractBearerToken = extractBearerToken;
|
|
4355
|
+
exports.generateProtectedResourceMetadata = generateProtectedResourceMetadata;
|
|
4356
|
+
exports.generateWWWAuthenticateHeader = generateWWWAuthenticateHeader;
|
|
3613
4357
|
//# sourceMappingURL=index.cjs.map
|
|
3614
4358
|
//# sourceMappingURL=index.cjs.map
|