@mcp-use/client 2.0.0-beta.9 → 2.0.1-canary.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -19
- package/dist/.tsbuildinfo +1 -1
- package/dist/auth/browser.d.ts +62 -6
- package/dist/auth/browser.d.ts.map +1 -1
- package/dist/auth/callback.d.ts.map +1 -1
- package/dist/auth/flow.d.ts.map +1 -1
- package/dist/auth/node.d.ts +115 -5
- package/dist/auth/node.d.ts.map +1 -1
- package/dist/auth/session-store.d.ts +7 -1
- package/dist/auth/session-store.d.ts.map +1 -1
- package/dist/auth/storage.d.ts +12 -3
- package/dist/auth/storage.d.ts.map +1 -1
- package/dist/code-mode/executor-e2b.d.ts.map +1 -1
- package/dist/core/base.d.ts +4 -8
- package/dist/core/base.d.ts.map +1 -1
- package/dist/core/browser.d.ts +14 -2
- package/dist/core/browser.d.ts.map +1 -1
- package/dist/core/config.d.ts +82 -20
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/node.d.ts +7 -10
- package/dist/core/node.d.ts.map +1 -1
- package/dist/core/session.d.ts +102 -25
- package/dist/core/session.d.ts.map +1 -1
- package/dist/index-browser.d.ts +1 -0
- package/dist/index-browser.d.ts.map +1 -1
- package/dist/index-browser.js +568 -163
- package/dist/index-browser.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +410 -103
- package/dist/index.js.map +1 -1
- package/dist/react/McpClientProvider.d.ts +22 -10
- package/dist/react/McpClientProvider.d.ts.map +1 -1
- package/dist/react/index.d.ts +5 -2
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +1090 -352
- package/dist/react/index.js.map +1 -1
- package/dist/react/rpc-logger.d.ts +5 -0
- package/dist/react/rpc-logger.d.ts.map +1 -1
- package/dist/react/storage.d.ts +57 -10
- package/dist/react/storage.d.ts.map +1 -1
- package/dist/react/token-expiry.d.ts +9 -0
- package/dist/react/token-expiry.d.ts.map +1 -0
- package/dist/react/types.d.ts +134 -22
- package/dist/react/types.d.ts.map +1 -1
- package/dist/react/useMcp-helpers.d.ts.map +1 -1
- package/dist/react/useMcp-operations.d.ts +24 -6
- package/dist/react/useMcp-operations.d.ts.map +1 -1
- package/dist/react/useMcp.d.ts.map +1 -1
- package/dist/react/useMcpServerQueues.d.ts +36 -9
- package/dist/react/useMcpServerQueues.d.ts.map +1 -1
- package/dist/react/view/ViewRenderer.d.ts +12 -4
- package/dist/react/view/ViewRenderer.d.ts.map +1 -1
- package/dist/react/view/ext-apps-bridge.d.ts +1 -1
- package/dist/react/view/ext-apps-bridge.d.ts.map +1 -1
- package/dist/react/view/inject-openai-file-apis.d.ts.map +1 -1
- package/dist/react/view/parse-custom-props.d.ts +8 -0
- package/dist/react/view/parse-custom-props.d.ts.map +1 -1
- package/dist/react/view/resolve-view-resource.d.ts +10 -0
- package/dist/react/view/resolve-view-resource.d.ts.map +1 -1
- package/dist/react/view/sandbox-blob-url.d.ts +2 -0
- package/dist/react/view/sandbox-blob-url.d.ts.map +1 -1
- package/dist/react/view/types.d.ts +111 -4
- package/dist/react/view/types.d.ts.map +1 -1
- package/dist/react/view/view-detection.d.ts +18 -0
- package/dist/react/view/view-detection.d.ts.map +1 -1
- package/dist/react/view/view-host-policy.d.ts +61 -0
- package/dist/react/view/view-host-policy.d.ts.map +1 -0
- package/dist/sandbox.d.ts +2 -0
- package/dist/sandbox.d.ts.map +1 -0
- package/dist/sandbox.js +283 -0
- package/dist/sandbox.js.map +1 -0
- package/dist/telemetry/events.d.ts.map +1 -1
- package/dist/telemetry/tel-fetch.d.ts.map +1 -1
- package/dist/telemetry/telemetry.d.ts +5 -1
- package/dist/telemetry/telemetry.d.ts.map +1 -1
- package/dist/transport/base.d.ts +169 -34
- package/dist/transport/base.d.ts.map +1 -1
- package/dist/transport/connection-manager.d.ts +5 -1
- package/dist/transport/connection-manager.d.ts.map +1 -1
- package/dist/transport/http.d.ts +51 -2
- package/dist/transport/http.d.ts.map +1 -1
- package/dist/transport/stdio.d.ts +29 -1
- package/dist/transport/stdio.d.ts.map +1 -1
- package/dist/utils/elicitation.d.ts +4 -2
- package/dist/utils/elicitation.d.ts.map +1 -1
- package/dist/utils/logging.d.ts +1 -0
- package/dist/utils/logging.d.ts.map +1 -1
- package/dist/utils/version.d.ts +6 -0
- package/dist/utils/version.d.ts.map +1 -1
- package/package.json +9 -3
package/dist/index.js
CHANGED
|
@@ -209,6 +209,11 @@ var init_base = __esm({
|
|
|
209
209
|
notificationHandlers = [];
|
|
210
210
|
rootsCache = [];
|
|
211
211
|
activeProgressHandlers = /* @__PURE__ */ new Set();
|
|
212
|
+
/**
|
|
213
|
+
* Creates a connector with shared SDK and callback options.
|
|
214
|
+
*
|
|
215
|
+
* @param opts - Connector initialization options.
|
|
216
|
+
*/
|
|
212
217
|
constructor(opts = {}) {
|
|
213
218
|
this.opts = opts;
|
|
214
219
|
if (opts.roots) {
|
|
@@ -391,7 +396,9 @@ var init_base = __esm({
|
|
|
391
396
|
}
|
|
392
397
|
}
|
|
393
398
|
/**
|
|
394
|
-
*
|
|
399
|
+
* Returns the roots currently advertised to the server.
|
|
400
|
+
*
|
|
401
|
+
* @returns A copy of the configured roots.
|
|
395
402
|
*/
|
|
396
403
|
getRoots() {
|
|
397
404
|
return [...this.rootsCache];
|
|
@@ -460,7 +467,11 @@ var init_base = __esm({
|
|
|
460
467
|
"setupElicitationHandler: Elicitation handler registered successfully"
|
|
461
468
|
);
|
|
462
469
|
}
|
|
463
|
-
/**
|
|
470
|
+
/**
|
|
471
|
+
* Disconnects the SDK client and releases transport resources.
|
|
472
|
+
*
|
|
473
|
+
* @returns A promise that resolves after cleanup completes.
|
|
474
|
+
*/
|
|
464
475
|
async disconnect() {
|
|
465
476
|
if (!this.connected) {
|
|
466
477
|
logger.debug("Not connected to MCP implementation");
|
|
@@ -471,7 +482,7 @@ var init_base = __esm({
|
|
|
471
482
|
this.connected = false;
|
|
472
483
|
logger.debug("Disconnected from MCP implementation");
|
|
473
484
|
}
|
|
474
|
-
/**
|
|
485
|
+
/** Whether an SDK client currently exists for this connector. */
|
|
475
486
|
get isClientConnected() {
|
|
476
487
|
return this.client != null;
|
|
477
488
|
}
|
|
@@ -481,6 +492,10 @@ var init_base = __esm({
|
|
|
481
492
|
* In the SDK, `Client.connect(transport)` automatically performs the
|
|
482
493
|
* protocol‑level `initialize` handshake, so we only need to cache the list of
|
|
483
494
|
* tools and expose some server info.
|
|
495
|
+
*
|
|
496
|
+
* @param defaultRequestOptions - Options used while fetching the initial tool list.
|
|
497
|
+
* @returns The capabilities advertised by the server.
|
|
498
|
+
* @throws When {@link BaseConnector.connect} has not completed.
|
|
484
499
|
*/
|
|
485
500
|
async initialize(defaultRequestOptions = this.opts.defaultRequestOptions ?? {}) {
|
|
486
501
|
if (!this.client) {
|
|
@@ -518,18 +533,22 @@ var init_base = __esm({
|
|
|
518
533
|
logger.debug("Server info:", serverInfo);
|
|
519
534
|
return capabilities;
|
|
520
535
|
}
|
|
521
|
-
/**
|
|
536
|
+
/**
|
|
537
|
+
* Returns the tool list cached during initialization.
|
|
538
|
+
*
|
|
539
|
+
* @throws When {@link BaseConnector.initialize} has not completed.
|
|
540
|
+
*/
|
|
522
541
|
get tools() {
|
|
523
542
|
if (!this.toolsCache) {
|
|
524
543
|
throw new Error("MCP client is not initialized; call initialize() first");
|
|
525
544
|
}
|
|
526
545
|
return this.toolsCache;
|
|
527
546
|
}
|
|
528
|
-
/**
|
|
547
|
+
/** Capabilities cached during initialization, or an empty object. */
|
|
529
548
|
get serverCapabilities() {
|
|
530
549
|
return this.capabilitiesCache || {};
|
|
531
550
|
}
|
|
532
|
-
/**
|
|
551
|
+
/** Server identity cached during initialization, or `null`. */
|
|
533
552
|
get serverInfo() {
|
|
534
553
|
return this.serverInfoCache;
|
|
535
554
|
}
|
|
@@ -550,7 +569,15 @@ var init_base = __esm({
|
|
|
550
569
|
get negotiatedProtocolVersion() {
|
|
551
570
|
return this.client?.getNegotiatedProtocolVersion?.();
|
|
552
571
|
}
|
|
553
|
-
/**
|
|
572
|
+
/**
|
|
573
|
+
* Calls a tool on the connected server.
|
|
574
|
+
*
|
|
575
|
+
* @param name - Tool name.
|
|
576
|
+
* @param args - Tool arguments.
|
|
577
|
+
* @param options - Per-request timeout, cancellation, and progress options.
|
|
578
|
+
* @returns The tool result returned by the server.
|
|
579
|
+
* @throws When the connector is not connected or the tool call fails.
|
|
580
|
+
*/
|
|
554
581
|
async callTool(name, args, options) {
|
|
555
582
|
if (!this.client) {
|
|
556
583
|
throw new Error("MCP client is not connected");
|
|
@@ -675,7 +702,13 @@ var init_base = __esm({
|
|
|
675
702
|
);
|
|
676
703
|
return result;
|
|
677
704
|
}
|
|
678
|
-
/**
|
|
705
|
+
/**
|
|
706
|
+
* Reads a resource by URI.
|
|
707
|
+
*
|
|
708
|
+
* @param uri - Resource URI to read.
|
|
709
|
+
* @param options - Per-request options.
|
|
710
|
+
* @returns The resource contents returned by the server.
|
|
711
|
+
*/
|
|
679
712
|
async readResource(uri, options) {
|
|
680
713
|
if (!this.client) {
|
|
681
714
|
throw new Error("MCP client is not connected");
|
|
@@ -710,6 +743,11 @@ var init_base = __esm({
|
|
|
710
743
|
logger.debug(`Unsubscribing from resource: ${uri}`);
|
|
711
744
|
return await this.client.unsubscribeResource({ uri }, options);
|
|
712
745
|
}
|
|
746
|
+
/**
|
|
747
|
+
* Lists prompts exposed by the server.
|
|
748
|
+
*
|
|
749
|
+
* @returns The prompt list, or an empty list when prompts are unsupported.
|
|
750
|
+
*/
|
|
713
751
|
async listPrompts() {
|
|
714
752
|
if (!this.client) {
|
|
715
753
|
throw new Error("MCP client is not connected");
|
|
@@ -730,6 +768,13 @@ var init_base = __esm({
|
|
|
730
768
|
throw err;
|
|
731
769
|
}
|
|
732
770
|
}
|
|
771
|
+
/**
|
|
772
|
+
* Gets a prompt with the supplied arguments.
|
|
773
|
+
*
|
|
774
|
+
* @param name - Prompt name.
|
|
775
|
+
* @param args - Prompt arguments.
|
|
776
|
+
* @returns The rendered prompt returned by the server.
|
|
777
|
+
*/
|
|
733
778
|
async getPrompt(name, args) {
|
|
734
779
|
if (!this.client) {
|
|
735
780
|
throw new Error("MCP client is not connected");
|
|
@@ -737,7 +782,14 @@ var init_base = __esm({
|
|
|
737
782
|
logger.debug(`Getting prompt ${name}`);
|
|
738
783
|
return await this.client.getPrompt({ name, arguments: args });
|
|
739
784
|
}
|
|
740
|
-
/**
|
|
785
|
+
/**
|
|
786
|
+
* Sends a raw, potentially non-standard request through the SDK client.
|
|
787
|
+
*
|
|
788
|
+
* @param method - JSON-RPC method name.
|
|
789
|
+
* @param params - Request parameters. Defaults to an empty object.
|
|
790
|
+
* @param options - Per-request options.
|
|
791
|
+
* @returns The unvalidated result returned by the server.
|
|
792
|
+
*/
|
|
741
793
|
async request(method, params = null, options) {
|
|
742
794
|
if (!this.client) {
|
|
743
795
|
throw new Error("MCP client is not connected");
|
|
@@ -802,6 +854,8 @@ var init_connection_manager = __esm({
|
|
|
802
854
|
_connection = null;
|
|
803
855
|
_task = null;
|
|
804
856
|
_abortController = null;
|
|
857
|
+
_startPromise = null;
|
|
858
|
+
_stopPromise = null;
|
|
805
859
|
constructor() {
|
|
806
860
|
this.reset();
|
|
807
861
|
}
|
|
@@ -811,10 +865,21 @@ var init_connection_manager = __esm({
|
|
|
811
865
|
* @returns The established connection.
|
|
812
866
|
* @throws If the connection cannot be established.
|
|
813
867
|
*/
|
|
814
|
-
|
|
868
|
+
start() {
|
|
869
|
+
if (this._stopPromise) {
|
|
870
|
+
return this._stopPromise.then(() => this.start());
|
|
871
|
+
}
|
|
872
|
+
if (this._startPromise) return this._startPromise;
|
|
815
873
|
this.reset();
|
|
816
874
|
logger.debug(`Starting ${this.constructor.name}`);
|
|
817
875
|
this._task = this.connectionTask();
|
|
876
|
+
this._startPromise = this.waitUntilReady().catch((error) => {
|
|
877
|
+
this._startPromise = null;
|
|
878
|
+
throw error;
|
|
879
|
+
});
|
|
880
|
+
return this._startPromise;
|
|
881
|
+
}
|
|
882
|
+
async waitUntilReady() {
|
|
818
883
|
await this._readyPromise;
|
|
819
884
|
if (this._exception) {
|
|
820
885
|
throw this._exception;
|
|
@@ -827,7 +892,18 @@ var init_connection_manager = __esm({
|
|
|
827
892
|
/**
|
|
828
893
|
* Stop the connection manager and close the connection.
|
|
829
894
|
*/
|
|
830
|
-
|
|
895
|
+
stop() {
|
|
896
|
+
if (this._stopPromise) return this._stopPromise;
|
|
897
|
+
if (!this._task) return Promise.resolve();
|
|
898
|
+
const trackedStop = this.stopTask().finally(() => {
|
|
899
|
+
if (this._stopPromise === trackedStop) {
|
|
900
|
+
this._stopPromise = null;
|
|
901
|
+
}
|
|
902
|
+
});
|
|
903
|
+
this._stopPromise = trackedStop;
|
|
904
|
+
return trackedStop;
|
|
905
|
+
}
|
|
906
|
+
async stopTask() {
|
|
831
907
|
if (this._task && this._abortController) {
|
|
832
908
|
logger.debug(`Cancelling ${this.constructor.name} task`);
|
|
833
909
|
this._abortController.abort();
|
|
@@ -842,6 +918,8 @@ var init_connection_manager = __esm({
|
|
|
842
918
|
}
|
|
843
919
|
}
|
|
844
920
|
await this._donePromise;
|
|
921
|
+
this._task = null;
|
|
922
|
+
this._startPromise = null;
|
|
845
923
|
logger.debug(`${this.constructor.name} task completed`);
|
|
846
924
|
}
|
|
847
925
|
/**
|
|
@@ -933,6 +1011,11 @@ var init_stdio = __esm({
|
|
|
933
1011
|
errlog;
|
|
934
1012
|
clientInfo;
|
|
935
1013
|
protocolNegotiation;
|
|
1014
|
+
/**
|
|
1015
|
+
* Creates a stdio connector.
|
|
1016
|
+
*
|
|
1017
|
+
* @param options - Process launch, client identity, and shared connector options.
|
|
1018
|
+
*/
|
|
936
1019
|
constructor({
|
|
937
1020
|
command = "npx",
|
|
938
1021
|
args = [],
|
|
@@ -952,7 +1035,11 @@ var init_stdio = __esm({
|
|
|
952
1035
|
this.cwd = rest.cwd;
|
|
953
1036
|
this.protocolNegotiation = rest.protocolNegotiation ?? "legacy";
|
|
954
1037
|
}
|
|
955
|
-
/**
|
|
1038
|
+
/**
|
|
1039
|
+
* Starts the child process and establishes an MCP connection.
|
|
1040
|
+
*
|
|
1041
|
+
* @returns A promise that resolves after protocol negotiation completes.
|
|
1042
|
+
*/
|
|
956
1043
|
async connect() {
|
|
957
1044
|
if (this.connected) {
|
|
958
1045
|
logger.debug("Already connected to MCP implementation");
|
|
@@ -960,20 +1047,12 @@ var init_stdio = __esm({
|
|
|
960
1047
|
}
|
|
961
1048
|
logger.debug(`Connecting to MCP implementation via stdio: ${this.command}`);
|
|
962
1049
|
try {
|
|
963
|
-
let mergedEnv;
|
|
964
|
-
if (this.env) {
|
|
965
|
-
mergedEnv = {};
|
|
966
|
-
for (const [key, value] of Object.entries(process2.env)) {
|
|
967
|
-
if (value !== void 0) {
|
|
968
|
-
mergedEnv[key] = value;
|
|
969
|
-
}
|
|
970
|
-
}
|
|
971
|
-
Object.assign(mergedEnv, this.env);
|
|
972
|
-
}
|
|
973
1050
|
const serverParams = {
|
|
974
1051
|
command: this.command,
|
|
975
1052
|
args: this.args,
|
|
976
|
-
|
|
1053
|
+
// The SDK layers explicit values over getDefaultEnvironment(). Passing
|
|
1054
|
+
// the configured env through avoids exposing unrelated parent secrets.
|
|
1055
|
+
env: this.env,
|
|
977
1056
|
cwd: this.cwd
|
|
978
1057
|
};
|
|
979
1058
|
this.connectionManager = new StdioConnectionManager(
|
|
@@ -1048,6 +1127,11 @@ var init_stdio = __esm({
|
|
|
1048
1127
|
throw err;
|
|
1049
1128
|
}
|
|
1050
1129
|
}
|
|
1130
|
+
/**
|
|
1131
|
+
* Returns fields identifying the launched command and arguments.
|
|
1132
|
+
*
|
|
1133
|
+
* @returns Stdio connector identity metadata.
|
|
1134
|
+
*/
|
|
1051
1135
|
get publicIdentifier() {
|
|
1052
1136
|
return {
|
|
1053
1137
|
type: "stdio",
|
|
@@ -1059,6 +1143,12 @@ var init_stdio = __esm({
|
|
|
1059
1143
|
serverParams;
|
|
1060
1144
|
errlog;
|
|
1061
1145
|
_transport = null;
|
|
1146
|
+
/**
|
|
1147
|
+
* Creates a connection manager for a local server process.
|
|
1148
|
+
*
|
|
1149
|
+
* @param serverParams - Process parameters passed to the SDK transport.
|
|
1150
|
+
* @param errlog - Destination for the child process's standard error stream.
|
|
1151
|
+
*/
|
|
1062
1152
|
constructor(serverParams, errlog = process2.stderr) {
|
|
1063
1153
|
super();
|
|
1064
1154
|
this.serverParams = serverParams;
|
|
@@ -1108,7 +1198,7 @@ init_connector_telemetry();
|
|
|
1108
1198
|
init_logging();
|
|
1109
1199
|
|
|
1110
1200
|
// src/utils/version.ts
|
|
1111
|
-
var VERSION = "2.0.
|
|
1201
|
+
var VERSION = "2.0.1-canary.0";
|
|
1112
1202
|
function getPackageVersion() {
|
|
1113
1203
|
return VERSION;
|
|
1114
1204
|
}
|
|
@@ -1128,16 +1218,13 @@ var MCPAgentExecutionEvent = class extends BaseTelemetryEvent {
|
|
|
1128
1218
|
return {
|
|
1129
1219
|
// Core execution info
|
|
1130
1220
|
execution_method: this.data.executionMethod,
|
|
1131
|
-
query: this.data.query,
|
|
1132
1221
|
query_length: this.data.query.length,
|
|
1133
1222
|
success: this.data.success,
|
|
1134
1223
|
// Agent configuration
|
|
1135
1224
|
model_provider: this.data.modelProvider,
|
|
1136
1225
|
model_name: this.data.modelName,
|
|
1137
1226
|
server_count: this.data.serverCount,
|
|
1138
|
-
server_identifiers: this.data.serverIdentifiers,
|
|
1139
1227
|
total_tools_available: this.data.totalToolsAvailable,
|
|
1140
|
-
tools_available_names: this.data.toolsAvailableNames,
|
|
1141
1228
|
max_steps_configured: this.data.maxStepsConfigured,
|
|
1142
1229
|
memory_enabled: this.data.memoryEnabled,
|
|
1143
1230
|
use_server_manager: this.data.useServerManager,
|
|
@@ -1148,8 +1235,6 @@ var MCPAgentExecutionEvent = class extends BaseTelemetryEvent {
|
|
|
1148
1235
|
// Execution results (always include, even if null)
|
|
1149
1236
|
steps_taken: this.data.stepsTaken ?? null,
|
|
1150
1237
|
tools_used_count: this.data.toolsUsedCount ?? null,
|
|
1151
|
-
tools_used_names: this.data.toolsUsedNames ?? null,
|
|
1152
|
-
response: this.data.response ?? null,
|
|
1153
1238
|
response_length: this.data.response ? this.data.response.length : null,
|
|
1154
1239
|
execution_time_ms: this.data.executionTimeMs ?? null,
|
|
1155
1240
|
error_type: this.data.errorType ?? null,
|
|
@@ -1245,21 +1330,72 @@ async function telFetch(url, init) {
|
|
|
1245
1330
|
}
|
|
1246
1331
|
var POSTHOG_HOST = "https://eu.i.posthog.com";
|
|
1247
1332
|
var POSTHOG_API_KEY = "phc_lyTtbYwvkdSbrcMQNPiKiiRWrrM1seyKIMjycSvItEI";
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1333
|
+
var CONTENT_PROPERTY = /(^|_)(arguments?|args|body|command|headers?|location|message|query|response|secret|subject|token|uri|url|user_agent)(_|$)/i;
|
|
1334
|
+
var IDENTIFYING_PROPERTY = /(^|_)(server_identifiers?|server_names?|servers|tool_names?|tools_(available|used)_names)(_|$)/i;
|
|
1335
|
+
var AGGREGATE_PROPERTY = /(_count|_length|_duration(?:_ms)?|_time_ms|(^|_)num_[a-z0-9_]+)$/i;
|
|
1336
|
+
function normalizePropertyKey(key) {
|
|
1337
|
+
return key.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^a-z0-9_$]+/gi, "_").toLowerCase();
|
|
1338
|
+
}
|
|
1339
|
+
function sanitizeValue(value, seen) {
|
|
1340
|
+
if (Array.isArray(value)) {
|
|
1341
|
+
if (seen.has(value)) {
|
|
1342
|
+
throw new TypeError("Cyclic telemetry properties are not supported");
|
|
1343
|
+
}
|
|
1344
|
+
seen.add(value);
|
|
1345
|
+
const sanitized = value.map((item) => sanitizeValue(item, seen));
|
|
1346
|
+
seen.delete(value);
|
|
1347
|
+
return sanitized;
|
|
1348
|
+
}
|
|
1349
|
+
if (value !== null && typeof value === "object" && (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null)) {
|
|
1350
|
+
if (seen.has(value)) {
|
|
1351
|
+
throw new TypeError("Cyclic telemetry properties are not supported");
|
|
1352
|
+
}
|
|
1353
|
+
seen.add(value);
|
|
1354
|
+
const sanitized = sanitizeProperties(
|
|
1355
|
+
value,
|
|
1356
|
+
seen
|
|
1357
|
+
);
|
|
1358
|
+
seen.delete(value);
|
|
1359
|
+
return sanitized;
|
|
1360
|
+
}
|
|
1361
|
+
return value;
|
|
1362
|
+
}
|
|
1363
|
+
function sanitizeProperties(properties, seen = /* @__PURE__ */ new WeakSet()) {
|
|
1364
|
+
const sanitized = {};
|
|
1365
|
+
for (const [key, value] of Object.entries(properties)) {
|
|
1366
|
+
const normalizedKey = normalizePropertyKey(key);
|
|
1367
|
+
if (AGGREGATE_PROPERTY.test(normalizedKey)) {
|
|
1368
|
+
if (value === null || typeof value === "number") {
|
|
1369
|
+
sanitized[key] = value;
|
|
1370
|
+
}
|
|
1371
|
+
continue;
|
|
1372
|
+
}
|
|
1373
|
+
if (IDENTIFYING_PROPERTY.test(normalizedKey) || CONTENT_PROPERTY.test(normalizedKey)) {
|
|
1374
|
+
continue;
|
|
1375
|
+
}
|
|
1376
|
+
sanitized[key] = sanitizeValue(value, seen);
|
|
1377
|
+
}
|
|
1378
|
+
return sanitized;
|
|
1379
|
+
}
|
|
1380
|
+
async function capturePostHog(params) {
|
|
1381
|
+
try {
|
|
1382
|
+
const host = params.host ?? POSTHOG_HOST;
|
|
1383
|
+
const apiKey = params.apiKey ?? POSTHOG_API_KEY;
|
|
1384
|
+
const body = JSON.stringify({
|
|
1256
1385
|
api_key: apiKey,
|
|
1257
1386
|
event: params.event,
|
|
1258
1387
|
distinct_id: params.distinctId,
|
|
1259
|
-
properties: params.properties,
|
|
1388
|
+
properties: sanitizeProperties(params.properties),
|
|
1260
1389
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1261
|
-
})
|
|
1262
|
-
|
|
1390
|
+
});
|
|
1391
|
+
await telFetch(`${host}/i/v0/e/`, {
|
|
1392
|
+
method: "POST",
|
|
1393
|
+
headers: { "Content-Type": "application/json" },
|
|
1394
|
+
keepalive: true,
|
|
1395
|
+
body
|
|
1396
|
+
});
|
|
1397
|
+
} catch {
|
|
1398
|
+
}
|
|
1263
1399
|
}
|
|
1264
1400
|
|
|
1265
1401
|
// src/telemetry/telemetry.ts
|
|
@@ -1789,11 +1925,12 @@ async function completeOAuthFlow(provider, serverUrl, options = {}) {
|
|
|
1789
1925
|
throw new Error(`Unexpected OAuth auth() result: ${result}`);
|
|
1790
1926
|
}
|
|
1791
1927
|
}
|
|
1792
|
-
if (typeof flowProvider.getAuthorizationCode === "function") {
|
|
1793
|
-
const
|
|
1928
|
+
if (typeof flowProvider.getAuthorizationResponse === "function" || typeof flowProvider.getAuthorizationCode === "function") {
|
|
1929
|
+
const response = typeof flowProvider.getAuthorizationResponse === "function" ? await flowProvider.getAuthorizationResponse() : { code: await flowProvider.getAuthorizationCode() };
|
|
1794
1930
|
await auth(provider, {
|
|
1795
1931
|
serverUrl,
|
|
1796
|
-
authorizationCode: code,
|
|
1932
|
+
authorizationCode: response.code,
|
|
1933
|
+
...response.iss !== void 0 ? { iss: response.iss } : {},
|
|
1797
1934
|
fetchFn
|
|
1798
1935
|
});
|
|
1799
1936
|
return;
|
|
@@ -1807,6 +1944,8 @@ async function waitForBrowserAuthComplete(provider, timeoutMs) {
|
|
|
1807
1944
|
);
|
|
1808
1945
|
}
|
|
1809
1946
|
if (provider.useRedirectFlow) {
|
|
1947
|
+
await new Promise(() => {
|
|
1948
|
+
});
|
|
1810
1949
|
return;
|
|
1811
1950
|
}
|
|
1812
1951
|
const tokensKey = provider.getKey?.("tokens");
|
|
@@ -1823,25 +1962,29 @@ async function waitForBrowserAuthComplete(provider, timeoutMs) {
|
|
|
1823
1962
|
} catch {
|
|
1824
1963
|
}
|
|
1825
1964
|
}
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1965
|
+
try {
|
|
1966
|
+
const result = await runAuthPopup({
|
|
1967
|
+
popup: null,
|
|
1968
|
+
state,
|
|
1969
|
+
tokensKey,
|
|
1970
|
+
timeoutMs
|
|
1971
|
+
});
|
|
1972
|
+
switch (result.kind) {
|
|
1973
|
+
case "success":
|
|
1974
|
+
return;
|
|
1975
|
+
case "cancelled":
|
|
1976
|
+
throw new Error("OAuth authentication was cancelled.");
|
|
1977
|
+
case "timeout":
|
|
1978
|
+
throw new Error(
|
|
1979
|
+
`OAuth callback not received within ${timeoutMs}ms. Ensure /oauth/callback calls onMcpAuthorization().`
|
|
1980
|
+
);
|
|
1981
|
+
case "error":
|
|
1982
|
+
throw new Error(result.error);
|
|
1983
|
+
default:
|
|
1984
|
+
throw new Error("Unexpected OAuth popup result");
|
|
1985
|
+
}
|
|
1986
|
+
} finally {
|
|
1987
|
+
provider.markFlowComplete?.();
|
|
1845
1988
|
}
|
|
1846
1989
|
}
|
|
1847
1990
|
|
|
@@ -2054,29 +2197,39 @@ var OAuthSessionStore = class _OAuthSessionStore {
|
|
|
2054
2197
|
if (ctx) await this.store.set(this.credentialKey("tokens"), serialized);
|
|
2055
2198
|
await this.store.remove(this.getKey("code_verifier"));
|
|
2056
2199
|
await this.store.remove(this.getKey("last_auth_url"));
|
|
2200
|
+
await this.store.remove(this.getKey("last_auth_callback_url"));
|
|
2057
2201
|
}
|
|
2058
2202
|
async clientInformation(ctx) {
|
|
2203
|
+
if (!this.allowClientSecret) {
|
|
2204
|
+
const registeredRedirectUri = await this.store.get(
|
|
2205
|
+
this.getKey("client_info_redirect_uri")
|
|
2206
|
+
);
|
|
2207
|
+
if (registeredRedirectUri !== this.redirectUrl) {
|
|
2208
|
+
await this.invalidateCredentials("registration");
|
|
2209
|
+
console.info(
|
|
2210
|
+
`[${this.storageKeyPrefix}] Re-registering browser OAuth client after its Inspector callback changed or could not be verified.`
|
|
2211
|
+
);
|
|
2212
|
+
return void 0;
|
|
2213
|
+
}
|
|
2214
|
+
}
|
|
2059
2215
|
const stored = await this.readCredential("client_info", ctx);
|
|
2060
2216
|
if (!stored) return void 0;
|
|
2061
2217
|
const { key, value: clientInfo } = stored;
|
|
2062
2218
|
try {
|
|
2063
2219
|
if (!this.allowClientSecret && clientInfo.client_secret) {
|
|
2064
|
-
await this.
|
|
2065
|
-
if (ctx) await this.store.remove(this.credentialKey("client_info"));
|
|
2220
|
+
await this.invalidateCredentials("registration");
|
|
2066
2221
|
console.warn(
|
|
2067
|
-
`[${this.storageKeyPrefix}]
|
|
2222
|
+
`[${this.storageKeyPrefix}] Recovered stale browser OAuth credentials containing a client_secret.`
|
|
2068
2223
|
);
|
|
2069
2224
|
return void 0;
|
|
2070
2225
|
}
|
|
2071
2226
|
const storedRedirectUris = Array.isArray(clientInfo.redirect_uris) ? clientInfo.redirect_uris : [];
|
|
2072
|
-
const hasMatchingRedirect = storedRedirectUris.length === 0 || storedRedirectUris.includes(this.redirectUrl);
|
|
2227
|
+
const hasMatchingRedirect = storedRedirectUris.length === 0 && this.allowClientSecret || storedRedirectUris.includes(this.redirectUrl);
|
|
2073
2228
|
if (!hasMatchingRedirect) {
|
|
2074
2229
|
console.info(
|
|
2075
|
-
`[${this.storageKeyPrefix}]
|
|
2230
|
+
`[${this.storageKeyPrefix}] Recovering cached OAuth credentials after a redirect URI change.`
|
|
2076
2231
|
);
|
|
2077
|
-
await this.
|
|
2078
|
-
await this.store.remove(this.credentialKey("tokens", ctx));
|
|
2079
|
-
await this.store.remove(this.getKey("last_auth_url"));
|
|
2232
|
+
await this.invalidateCredentials("registration");
|
|
2080
2233
|
return void 0;
|
|
2081
2234
|
}
|
|
2082
2235
|
return clientInfo;
|
|
@@ -2094,11 +2247,20 @@ var OAuthSessionStore = class _OAuthSessionStore {
|
|
|
2094
2247
|
"Browser OAuth clients must be public clients; client_secret persistence is not allowed."
|
|
2095
2248
|
);
|
|
2096
2249
|
}
|
|
2097
|
-
const
|
|
2250
|
+
const persistedClientInformation = !this.allowClientSecret && (!("redirect_uris" in clientInformation) || !Array.isArray(
|
|
2251
|
+
clientInformation.redirect_uris
|
|
2252
|
+
) || clientInformation.redirect_uris.length === 0) ? { ...clientInformation, redirect_uris: [this.redirectUrl] } : clientInformation;
|
|
2253
|
+
const serialized = JSON.stringify(persistedClientInformation);
|
|
2098
2254
|
await this.store.set(this.credentialKey("client_info", ctx), serialized);
|
|
2099
2255
|
if (ctx) {
|
|
2100
2256
|
await this.store.set(this.credentialKey("client_info"), serialized);
|
|
2101
2257
|
}
|
|
2258
|
+
if (!this.allowClientSecret) {
|
|
2259
|
+
await this.store.set(
|
|
2260
|
+
this.getKey("client_info_redirect_uri"),
|
|
2261
|
+
this.redirectUrl
|
|
2262
|
+
);
|
|
2263
|
+
}
|
|
2102
2264
|
}
|
|
2103
2265
|
async saveCodeVerifier(codeVerifier) {
|
|
2104
2266
|
await this.store.set(this.getKey("code_verifier"), codeVerifier);
|
|
@@ -2123,11 +2285,22 @@ var OAuthSessionStore = class _OAuthSessionStore {
|
|
|
2123
2285
|
}
|
|
2124
2286
|
};
|
|
2125
2287
|
switch (scope) {
|
|
2288
|
+
case "registration":
|
|
2289
|
+
await removeCredentialKeys("tokens");
|
|
2290
|
+
await removeCredentialKeys("client_info");
|
|
2291
|
+
await this.store.remove(this.getKey("code_verifier"));
|
|
2292
|
+
await this.store.remove(this.getKey("last_auth_url"));
|
|
2293
|
+
await this.store.remove(this.getKey("last_auth_callback_url"));
|
|
2294
|
+
await this.store.remove(this.getKey("client_info_redirect_uri"));
|
|
2295
|
+
await this.store.remove(this.getKey("token_endpoint"));
|
|
2296
|
+
break;
|
|
2126
2297
|
case "all":
|
|
2127
2298
|
await removeCredentialKeys("tokens");
|
|
2128
2299
|
await removeCredentialKeys("client_info");
|
|
2129
2300
|
await this.store.remove(this.getKey("code_verifier"));
|
|
2130
2301
|
await this.store.remove(this.getKey("last_auth_url"));
|
|
2302
|
+
await this.store.remove(this.getKey("last_auth_callback_url"));
|
|
2303
|
+
await this.store.remove(this.getKey("client_info_redirect_uri"));
|
|
2131
2304
|
await this.store.remove(this.getKey("discovery_state"));
|
|
2132
2305
|
await this.store.remove(this.getKey("token_endpoint"));
|
|
2133
2306
|
break;
|
|
@@ -2177,7 +2350,7 @@ var OAuthSessionStore = class _OAuthSessionStore {
|
|
|
2177
2350
|
*/
|
|
2178
2351
|
async storeAuthorizationState(authorizationUrl, opts = {}) {
|
|
2179
2352
|
const state = globalThis.crypto.randomUUID();
|
|
2180
|
-
const stateKey = `${this.storageKeyPrefix}
|
|
2353
|
+
const stateKey = `${this.storageKeyPrefix}_${this.serverUrlHash}_state_${state}`;
|
|
2181
2354
|
const stateData = {
|
|
2182
2355
|
serverUrlHash: this.serverUrlHash,
|
|
2183
2356
|
expiry: Date.now() + 1e3 * 60 * 10,
|
|
@@ -2197,6 +2370,10 @@ var OAuthSessionStore = class _OAuthSessionStore {
|
|
|
2197
2370
|
authorizationUrl.searchParams.set("state", state);
|
|
2198
2371
|
const sanitizedAuthUrl = sanitizeUrl(authorizationUrl.toString());
|
|
2199
2372
|
await this.store.set(stateKey, JSON.stringify(stateData));
|
|
2373
|
+
await this.store.set(
|
|
2374
|
+
this.getKey("last_auth_callback_url"),
|
|
2375
|
+
this.redirectUrl
|
|
2376
|
+
);
|
|
2200
2377
|
await this.store.set(this.getKey("last_auth_url"), sanitizedAuthUrl);
|
|
2201
2378
|
return sanitizedAuthUrl;
|
|
2202
2379
|
}
|
|
@@ -2222,8 +2399,16 @@ var DEFAULT_PORT = 33418;
|
|
|
2222
2399
|
var PORT_RANGE = 10;
|
|
2223
2400
|
var DEFAULT_AUTH_TIMEOUT_MS2 = 5 * 6e4;
|
|
2224
2401
|
var OAuthFlowError = class extends Error {
|
|
2402
|
+
/** OAuth or local-flow error code. */
|
|
2225
2403
|
code;
|
|
2404
|
+
/** Optional human-readable error description. */
|
|
2226
2405
|
description;
|
|
2406
|
+
/**
|
|
2407
|
+
* Creates an OAuth flow error.
|
|
2408
|
+
*
|
|
2409
|
+
* @param code - OAuth or local-flow error code.
|
|
2410
|
+
* @param description - Optional human-readable description.
|
|
2411
|
+
*/
|
|
2227
2412
|
constructor(code, description) {
|
|
2228
2413
|
super(description ? `${code}: ${description}` : code);
|
|
2229
2414
|
this.code = code;
|
|
@@ -2273,16 +2458,20 @@ h1{font-size:20px;margin:0 0 12px;color:#b00020}p{line-height:1.5}code{backgroun
|
|
|
2273
2458
|
<p><code>${escapeHtml(err)}</code>${desc ? `: ${escapeHtml(desc)}` : ""}</p>
|
|
2274
2459
|
<p>You can close this tab and return to your terminal.</p></body></html>`;
|
|
2275
2460
|
var NodeOAuthClientProvider = class _NodeOAuthClientProvider {
|
|
2461
|
+
/** Protected MCP server URL associated with this provider. */
|
|
2276
2462
|
serverUrl;
|
|
2463
|
+
/** Reserved localhost callback port. */
|
|
2277
2464
|
port;
|
|
2278
2465
|
session;
|
|
2279
2466
|
kv;
|
|
2280
2467
|
authTimeoutMs;
|
|
2281
2468
|
openBrowserOverride;
|
|
2282
2469
|
server = null;
|
|
2470
|
+
/** Provider authorization URL, exposed only through the local redirect route. */
|
|
2471
|
+
authorizationUrl = null;
|
|
2283
2472
|
/** Currently in-flight deferred — used to prevent overlapping flows. */
|
|
2284
2473
|
pending = null;
|
|
2285
|
-
/** Latest deferred (settled or in-flight)
|
|
2474
|
+
/** Latest deferred (settled or in-flight) for the loopback response. */
|
|
2286
2475
|
lastFlow = null;
|
|
2287
2476
|
pendingTimer = null;
|
|
2288
2477
|
constructor(serverUrl, port, session, kv, options) {
|
|
@@ -2293,6 +2482,13 @@ var NodeOAuthClientProvider = class _NodeOAuthClientProvider {
|
|
|
2293
2482
|
this.authTimeoutMs = options.authTimeoutMs ?? DEFAULT_AUTH_TIMEOUT_MS2;
|
|
2294
2483
|
this.openBrowserOverride = options.openBrowser;
|
|
2295
2484
|
}
|
|
2485
|
+
/**
|
|
2486
|
+
* Creates a Node OAuth provider and reserves a localhost callback port.
|
|
2487
|
+
*
|
|
2488
|
+
* @param serverUrl - Protected MCP server URL.
|
|
2489
|
+
* @param options - OAuth metadata, storage, loopback, and browser options.
|
|
2490
|
+
* @returns A provider ready to participate in the SDK OAuth flow.
|
|
2491
|
+
*/
|
|
2296
2492
|
static async create(serverUrl, options = {}) {
|
|
2297
2493
|
const serverUrlHash = OAuthSessionStore.hashString(serverUrl);
|
|
2298
2494
|
const kv = options.kvStore ?? new FileKVStore(serverUrlHash, options.baseDir);
|
|
@@ -2325,48 +2521,100 @@ var NodeOAuthClientProvider = class _NodeOAuthClientProvider {
|
|
|
2325
2521
|
return new _NodeOAuthClientProvider(serverUrl, port, session, kv, options);
|
|
2326
2522
|
}
|
|
2327
2523
|
// --- Identity passthroughs (parallel to BrowserOAuthClientProvider) ---
|
|
2524
|
+
/** Prefix used for persisted OAuth session keys. */
|
|
2328
2525
|
get storageKeyPrefix() {
|
|
2329
2526
|
return this.session.storageKeyPrefix;
|
|
2330
2527
|
}
|
|
2528
|
+
/** Stable hash of the protected server URL used to namespace storage. */
|
|
2331
2529
|
get serverUrlHash() {
|
|
2332
2530
|
return this.session.serverUrlHash;
|
|
2333
2531
|
}
|
|
2334
2532
|
// --- SDK Interface (delegated to OAuthSessionStore) ---
|
|
2533
|
+
/** Loopback redirect URL registered for this provider. */
|
|
2335
2534
|
get redirectUrl() {
|
|
2336
2535
|
return this.session.redirectUrl;
|
|
2337
2536
|
}
|
|
2537
|
+
/** OAuth client metadata presented during registration. */
|
|
2338
2538
|
get clientMetadata() {
|
|
2339
2539
|
return this.session.clientMetadata;
|
|
2340
2540
|
}
|
|
2541
|
+
/** OAuth Client ID Metadata Document URL, when configured. */
|
|
2341
2542
|
get clientMetadataUrl() {
|
|
2342
2543
|
return this.session.clientMetadataUrl;
|
|
2343
2544
|
}
|
|
2545
|
+
/**
|
|
2546
|
+
* Loads saved OAuth tokens.
|
|
2547
|
+
*
|
|
2548
|
+
* @param ctx - Optional client registration context.
|
|
2549
|
+
* @returns Saved tokens, or `undefined` when none exist.
|
|
2550
|
+
*/
|
|
2344
2551
|
tokens(ctx) {
|
|
2345
2552
|
return this.session.tokens(ctx);
|
|
2346
2553
|
}
|
|
2554
|
+
/**
|
|
2555
|
+
* Persists OAuth tokens.
|
|
2556
|
+
*
|
|
2557
|
+
* @param tokens - Tokens to save.
|
|
2558
|
+
* @param ctx - Optional client registration context.
|
|
2559
|
+
*/
|
|
2347
2560
|
saveTokens(tokens, ctx) {
|
|
2348
2561
|
return this.session.saveTokens(tokens, ctx);
|
|
2349
2562
|
}
|
|
2563
|
+
/**
|
|
2564
|
+
* Loads saved OAuth client registration information.
|
|
2565
|
+
*
|
|
2566
|
+
* @param ctx - Optional registration context.
|
|
2567
|
+
* @returns Saved registration information, or `undefined`.
|
|
2568
|
+
*/
|
|
2350
2569
|
clientInformation(ctx) {
|
|
2351
2570
|
return this.session.clientInformation(ctx);
|
|
2352
2571
|
}
|
|
2572
|
+
/**
|
|
2573
|
+
* Persists OAuth client registration information.
|
|
2574
|
+
*
|
|
2575
|
+
* @param info - Client information to save.
|
|
2576
|
+
* @param ctx - Optional registration context.
|
|
2577
|
+
*/
|
|
2353
2578
|
saveClientInformation(info, ctx) {
|
|
2354
2579
|
return this.session.saveClientInformation(info, ctx);
|
|
2355
2580
|
}
|
|
2581
|
+
/**
|
|
2582
|
+
* Loads the saved PKCE code verifier.
|
|
2583
|
+
*
|
|
2584
|
+
* @returns The saved verifier.
|
|
2585
|
+
*/
|
|
2356
2586
|
codeVerifier() {
|
|
2357
2587
|
return this.session.codeVerifier();
|
|
2358
2588
|
}
|
|
2589
|
+
/**
|
|
2590
|
+
* Persists a PKCE code verifier.
|
|
2591
|
+
*
|
|
2592
|
+
* @param codeVerifier - Verifier to save.
|
|
2593
|
+
*/
|
|
2359
2594
|
saveCodeVerifier(codeVerifier) {
|
|
2360
2595
|
return this.session.saveCodeVerifier(codeVerifier);
|
|
2361
2596
|
}
|
|
2597
|
+
/**
|
|
2598
|
+
* Invalidates selected persisted OAuth credentials.
|
|
2599
|
+
*
|
|
2600
|
+
* @param scope - Credential group to remove.
|
|
2601
|
+
*/
|
|
2362
2602
|
invalidateCredentials(scope) {
|
|
2363
2603
|
return this.session.invalidateCredentials(scope);
|
|
2364
2604
|
}
|
|
2365
|
-
/**
|
|
2605
|
+
/**
|
|
2606
|
+
* Persists OAuth discovery state.
|
|
2607
|
+
*
|
|
2608
|
+
* @param state - Discovery state to save.
|
|
2609
|
+
*/
|
|
2366
2610
|
saveDiscoveryState(state) {
|
|
2367
2611
|
return this.session.saveDiscoveryState(state);
|
|
2368
2612
|
}
|
|
2369
|
-
/**
|
|
2613
|
+
/**
|
|
2614
|
+
* Returns previously saved OAuth discovery state.
|
|
2615
|
+
*
|
|
2616
|
+
* @returns Saved discovery state, or `undefined`.
|
|
2617
|
+
*/
|
|
2370
2618
|
discoveryState() {
|
|
2371
2619
|
return this.session.discoveryState();
|
|
2372
2620
|
}
|
|
@@ -2374,6 +2622,10 @@ var NodeOAuthClientProvider = class _NodeOAuthClientProvider {
|
|
|
2374
2622
|
* Bind the loopback server, set up the pending-code deferred, and ask the
|
|
2375
2623
|
* platform to open the user's browser. Does NOT await the code; the
|
|
2376
2624
|
* orchestrator awaits via `getAuthorizationCode()`.
|
|
2625
|
+
*
|
|
2626
|
+
* @param authorizationUrl - Authorization URL generated by the SDK.
|
|
2627
|
+
* @returns A promise that resolves once the loopback listener is ready and
|
|
2628
|
+
* the browser-open attempt completes.
|
|
2377
2629
|
*/
|
|
2378
2630
|
async redirectToAuthorization(authorizationUrl) {
|
|
2379
2631
|
if (this.pending) {
|
|
@@ -2385,6 +2637,7 @@ var NodeOAuthClientProvider = class _NodeOAuthClientProvider {
|
|
|
2385
2637
|
authorizationUrl,
|
|
2386
2638
|
{ flowType: "redirect" }
|
|
2387
2639
|
);
|
|
2640
|
+
this.authorizationUrl = sanitizedUrl;
|
|
2388
2641
|
await this.startLoopback();
|
|
2389
2642
|
this.pending = createDeferred();
|
|
2390
2643
|
this.lastFlow = this.pending;
|
|
@@ -2399,8 +2652,9 @@ var NodeOAuthClientProvider = class _NodeOAuthClientProvider {
|
|
|
2399
2652
|
);
|
|
2400
2653
|
}, this.authTimeoutMs);
|
|
2401
2654
|
const opener = this.openBrowserOverride ?? defaultOpener;
|
|
2655
|
+
const launcherUrl = `http://127.0.0.1:${this.port}/authorize`;
|
|
2402
2656
|
try {
|
|
2403
|
-
await opener(
|
|
2657
|
+
await opener(launcherUrl);
|
|
2404
2658
|
} catch (err) {
|
|
2405
2659
|
console.error(
|
|
2406
2660
|
`[mcp-use] Could not open browser automatically: ${err instanceof Error ? err.message : String(err)}`
|
|
@@ -2409,15 +2663,30 @@ var NodeOAuthClientProvider = class _NodeOAuthClientProvider {
|
|
|
2409
2663
|
}
|
|
2410
2664
|
/**
|
|
2411
2665
|
* Resolves with the authorization code captured by the loopback callback.
|
|
2666
|
+
*
|
|
2667
|
+
* @remarks This compatibility method omits the RFC 9207 issuer. OAuth flow
|
|
2668
|
+
* orchestrators should use {@link getAuthorizationResponse} when available.
|
|
2412
2669
|
* Must be called after `redirectToAuthorization()`. Returns the same
|
|
2413
2670
|
* promise whether the callback has fired or not — callers may subscribe
|
|
2414
2671
|
* before or after.
|
|
2672
|
+
*
|
|
2673
|
+
* @returns The authorization code received by the loopback callback.
|
|
2415
2674
|
*/
|
|
2416
2675
|
getAuthorizationCode() {
|
|
2676
|
+
return this.getAuthorizationResponse().then((response) => response.code);
|
|
2677
|
+
}
|
|
2678
|
+
/**
|
|
2679
|
+
* Resolves with the authorization code and RFC 9207 issuer captured by the
|
|
2680
|
+
* loopback callback.
|
|
2681
|
+
*
|
|
2682
|
+
* @returns The loopback authorization response.
|
|
2683
|
+
* @throws When called before {@link NodeOAuthClientProvider.redirectToAuthorization}.
|
|
2684
|
+
*/
|
|
2685
|
+
getAuthorizationResponse() {
|
|
2417
2686
|
if (!this.lastFlow) {
|
|
2418
2687
|
return Promise.reject(
|
|
2419
2688
|
new Error(
|
|
2420
|
-
"NodeOAuthClientProvider.
|
|
2689
|
+
"NodeOAuthClientProvider.getAuthorizationResponse() called before redirectToAuthorization()"
|
|
2421
2690
|
)
|
|
2422
2691
|
);
|
|
2423
2692
|
}
|
|
@@ -2425,6 +2694,9 @@ var NodeOAuthClientProvider = class _NodeOAuthClientProvider {
|
|
|
2425
2694
|
}
|
|
2426
2695
|
/**
|
|
2427
2696
|
* Cancel an in-progress flow (timeout, SIGINT, etc.) and close the loopback.
|
|
2697
|
+
*
|
|
2698
|
+
* Pending calls to {@link NodeOAuthClientProvider.getAuthorizationResponse}
|
|
2699
|
+
* reject with an {@link OAuthFlowError} whose code is `"cancelled"`.
|
|
2428
2700
|
*/
|
|
2429
2701
|
dispose() {
|
|
2430
2702
|
if (this.pending) {
|
|
@@ -2433,7 +2705,7 @@ var NodeOAuthClientProvider = class _NodeOAuthClientProvider {
|
|
|
2433
2705
|
this.stopLoopback();
|
|
2434
2706
|
}
|
|
2435
2707
|
}
|
|
2436
|
-
/**
|
|
2708
|
+
/** Local callback port, useful for status output and tests. */
|
|
2437
2709
|
get callbackPort() {
|
|
2438
2710
|
return this.port;
|
|
2439
2711
|
}
|
|
@@ -2471,12 +2743,13 @@ var NodeOAuthClientProvider = class _NodeOAuthClientProvider {
|
|
|
2471
2743
|
this.server.close();
|
|
2472
2744
|
this.server = null;
|
|
2473
2745
|
}
|
|
2746
|
+
this.authorizationUrl = null;
|
|
2474
2747
|
}
|
|
2475
|
-
resolvePending(
|
|
2748
|
+
resolvePending(response) {
|
|
2476
2749
|
const p = this.pending;
|
|
2477
2750
|
this.pending = null;
|
|
2478
2751
|
this.stopLoopback();
|
|
2479
|
-
p?.resolve(
|
|
2752
|
+
p?.resolve(response);
|
|
2480
2753
|
}
|
|
2481
2754
|
rejectPending(err) {
|
|
2482
2755
|
const p = this.pending;
|
|
@@ -2486,6 +2759,19 @@ var NodeOAuthClientProvider = class _NodeOAuthClientProvider {
|
|
|
2486
2759
|
}
|
|
2487
2760
|
handleCallback(rawUrl, res) {
|
|
2488
2761
|
const url = new URL(rawUrl, `http://127.0.0.1:${this.port}`);
|
|
2762
|
+
if (url.pathname === "/authorize") {
|
|
2763
|
+
if (this.authorizationUrl === null || this.pending === null) {
|
|
2764
|
+
res.statusCode = 410;
|
|
2765
|
+
res.end("Authorization flow is not active");
|
|
2766
|
+
return;
|
|
2767
|
+
}
|
|
2768
|
+
res.statusCode = 302;
|
|
2769
|
+
res.setHeader("location", this.authorizationUrl);
|
|
2770
|
+
res.setHeader("cache-control", "no-store");
|
|
2771
|
+
res.setHeader("referrer-policy", "no-referrer");
|
|
2772
|
+
res.end();
|
|
2773
|
+
return;
|
|
2774
|
+
}
|
|
2489
2775
|
if (url.pathname !== "/callback") {
|
|
2490
2776
|
res.statusCode = 404;
|
|
2491
2777
|
res.end("Not Found");
|
|
@@ -2493,6 +2779,7 @@ var NodeOAuthClientProvider = class _NodeOAuthClientProvider {
|
|
|
2493
2779
|
}
|
|
2494
2780
|
const code = url.searchParams.get("code");
|
|
2495
2781
|
const state = url.searchParams.get("state");
|
|
2782
|
+
const iss = url.searchParams.get("iss") ?? void 0;
|
|
2496
2783
|
const err = url.searchParams.get("error");
|
|
2497
2784
|
const errDesc = url.searchParams.get("error_description") ?? void 0;
|
|
2498
2785
|
if (err) {
|
|
@@ -2510,7 +2797,7 @@ var NodeOAuthClientProvider = class _NodeOAuthClientProvider {
|
|
|
2510
2797
|
res.statusCode = 200;
|
|
2511
2798
|
res.setHeader("content-type", "text/html; charset=utf-8");
|
|
2512
2799
|
res.end(SUCCESS_HTML);
|
|
2513
|
-
this.resolvePending(code);
|
|
2800
|
+
this.resolvePending({ code, ...iss !== void 0 ? { iss } : {} });
|
|
2514
2801
|
}
|
|
2515
2802
|
};
|
|
2516
2803
|
async function defaultOpener(url) {
|
|
@@ -2592,6 +2879,12 @@ var HttpConnector = class extends BaseConnector {
|
|
|
2592
2879
|
reconnectionOptions;
|
|
2593
2880
|
transportType = null;
|
|
2594
2881
|
streamableTransport = null;
|
|
2882
|
+
/**
|
|
2883
|
+
* Creates an HTTP connector.
|
|
2884
|
+
*
|
|
2885
|
+
* @param baseUrl - MCP endpoint URL.
|
|
2886
|
+
* @param opts - Authentication, transport, SDK, and reconnection options.
|
|
2887
|
+
*/
|
|
2595
2888
|
constructor(baseUrl, opts = {}) {
|
|
2596
2889
|
super(opts);
|
|
2597
2890
|
const originalUrl = baseUrl.replace(/\/$/, "");
|
|
@@ -2709,7 +3002,12 @@ var HttpConnector = class extends BaseConnector {
|
|
|
2709
3002
|
}
|
|
2710
3003
|
return { fallbackReason, is401Error, httpStatusCode };
|
|
2711
3004
|
}
|
|
2712
|
-
/**
|
|
3005
|
+
/**
|
|
3006
|
+
* Establishes a streamable HTTP connection to the MCP server.
|
|
3007
|
+
*
|
|
3008
|
+
* @returns A promise that resolves after protocol negotiation completes.
|
|
3009
|
+
* @throws An error with `code: 401` when authentication is required.
|
|
3010
|
+
*/
|
|
2713
3011
|
async connect() {
|
|
2714
3012
|
if (this.connected) {
|
|
2715
3013
|
logger.debug("Already connected to MCP implementation");
|
|
@@ -2937,6 +3235,11 @@ var HttpConnector = class extends BaseConnector {
|
|
|
2937
3235
|
throw err;
|
|
2938
3236
|
}
|
|
2939
3237
|
}
|
|
3238
|
+
/**
|
|
3239
|
+
* Returns fields that identify the endpoint and negotiated transport.
|
|
3240
|
+
*
|
|
3241
|
+
* @returns HTTP connector identity metadata.
|
|
3242
|
+
*/
|
|
2940
3243
|
get publicIdentifier() {
|
|
2941
3244
|
return {
|
|
2942
3245
|
type: "http",
|
|
@@ -2945,7 +3248,11 @@ var HttpConnector = class extends BaseConnector {
|
|
|
2945
3248
|
protocolEra: this.protocolEra ?? "unknown"
|
|
2946
3249
|
};
|
|
2947
3250
|
}
|
|
2948
|
-
/**
|
|
3251
|
+
/**
|
|
3252
|
+
* Returns the active transport type.
|
|
3253
|
+
*
|
|
3254
|
+
* @returns `"streamable-http"` after connection, otherwise `null`.
|
|
3255
|
+
*/
|
|
2949
3256
|
getTransportType() {
|
|
2950
3257
|
return this.transportType;
|
|
2951
3258
|
}
|
|
@@ -3320,7 +3627,7 @@ var MCPConnection = class {
|
|
|
3320
3627
|
/**
|
|
3321
3628
|
* Normalized server metadata for this ready connection.
|
|
3322
3629
|
*
|
|
3323
|
-
* @throws
|
|
3630
|
+
* @throws When called before protocol negotiation completes.
|
|
3324
3631
|
*/
|
|
3325
3632
|
get info() {
|
|
3326
3633
|
const protocolEra = this.protocolEra;
|
|
@@ -3532,12 +3839,10 @@ function isOAuthClientProvider(provider) {
|
|
|
3532
3839
|
var BaseMCPClient = class {
|
|
3533
3840
|
/**
|
|
3534
3841
|
* Internal configuration object containing MCP server definitions.
|
|
3535
|
-
* @protected
|
|
3536
3842
|
*/
|
|
3537
3843
|
config = {};
|
|
3538
3844
|
/**
|
|
3539
3845
|
* Map of server names to their active sessions.
|
|
3540
|
-
* @protected
|
|
3541
3846
|
*/
|
|
3542
3847
|
sessions = {};
|
|
3543
3848
|
/**
|
|
@@ -3581,7 +3886,7 @@ var BaseMCPClient = class {
|
|
|
3581
3886
|
*
|
|
3582
3887
|
* @param _cfg - Configuration dictionary
|
|
3583
3888
|
* @returns Client instance
|
|
3584
|
-
* @throws
|
|
3889
|
+
* @throws If called on the base class instead of a concrete implementation
|
|
3585
3890
|
*
|
|
3586
3891
|
* @example
|
|
3587
3892
|
* ```typescript
|
|
@@ -3723,7 +4028,7 @@ var BaseMCPClient = class {
|
|
|
3723
4028
|
* @param serverName - The name of the server as defined in the client configuration
|
|
3724
4029
|
* @param autoInitialize - Whether to automatically initialize the session (default: true)
|
|
3725
4030
|
* @returns A promise that resolves to the created MCPSession instance
|
|
3726
|
-
* @throws
|
|
4031
|
+
* @throws If the server is not found in the configuration
|
|
3727
4032
|
*
|
|
3728
4033
|
* @example
|
|
3729
4034
|
* ```typescript
|
|
@@ -3893,7 +4198,7 @@ var BaseMCPClient = class {
|
|
|
3893
4198
|
*
|
|
3894
4199
|
* @param serverName - Name of the server
|
|
3895
4200
|
* @returns The session instance
|
|
3896
|
-
* @throws
|
|
4201
|
+
* @throws If the session is not found
|
|
3897
4202
|
*
|
|
3898
4203
|
* @example
|
|
3899
4204
|
* ```typescript
|
|
@@ -4277,20 +4582,24 @@ global.search_tools = async (query, detailLevel = 'full') => {
|
|
|
4277
4582
|
for (const [serverName, serverTools] of Object.entries(tools)) {
|
|
4278
4583
|
if (!serverTools || serverTools.length === 0) continue;
|
|
4279
4584
|
const safeServerName = serverName.replace(/[^a-zA-Z0-9_]/g, "_");
|
|
4585
|
+
const escapedServerName = JSON.stringify(serverName);
|
|
4586
|
+
const escapedSafeServerName = JSON.stringify(safeServerName);
|
|
4280
4587
|
shim += `
|
|
4281
|
-
global[
|
|
4588
|
+
global[${escapedServerName}] = {`;
|
|
4282
4589
|
for (const tool of serverTools) {
|
|
4590
|
+
const escapedToolName = JSON.stringify(tool.name);
|
|
4283
4591
|
shim += `
|
|
4284
|
-
|
|
4592
|
+
[${escapedToolName}]: async (args) => await global.__callMcpTool(${escapedServerName}, ${escapedToolName}, args),`;
|
|
4285
4593
|
}
|
|
4286
4594
|
shim += `
|
|
4287
4595
|
};
|
|
4288
|
-
|
|
4596
|
+
`;
|
|
4597
|
+
if (safeServerName !== serverName) {
|
|
4598
|
+
shim += `
|
|
4289
4599
|
// Also expose as safe name if different
|
|
4290
|
-
|
|
4291
|
-
global['${safeServerName}'] = global['${serverName}'];
|
|
4292
|
-
}
|
|
4600
|
+
global[${escapedSafeServerName}] = global[${escapedServerName}];
|
|
4293
4601
|
`;
|
|
4602
|
+
}
|
|
4294
4603
|
}
|
|
4295
4604
|
return shim;
|
|
4296
4605
|
}
|
|
@@ -4984,9 +5293,7 @@ var MCPClient = class _MCPClient extends BaseMCPClient {
|
|
|
4984
5293
|
* @param config - Configuration object or path to JSON config file. If omitted,
|
|
4985
5294
|
* starts with empty configuration
|
|
4986
5295
|
* @param options - Optional client behavior configuration
|
|
4987
|
-
*
|
|
4988
|
-
* @param options.onSampling - Callback for handling sampling requests from servers
|
|
4989
|
-
* @param options.onElicitation - Callback for handling elicitation requests
|
|
5296
|
+
* Options can enable code mode or provide sampling and elicitation callbacks.
|
|
4990
5297
|
*
|
|
4991
5298
|
* @example
|
|
4992
5299
|
* ```typescript
|
|
@@ -5087,7 +5394,7 @@ var MCPClient = class _MCPClient extends BaseMCPClient {
|
|
|
5087
5394
|
* });
|
|
5088
5395
|
* ```
|
|
5089
5396
|
*
|
|
5090
|
-
* @see {@link
|
|
5397
|
+
* @see {@link MCPClient} for direct instantiation
|
|
5091
5398
|
* @see {@link fromConfigFile} for loading from file
|
|
5092
5399
|
*/
|
|
5093
5400
|
static fromDict(cfg, options) {
|
|
@@ -5102,7 +5409,7 @@ var MCPClient = class _MCPClient extends BaseMCPClient {
|
|
|
5102
5409
|
* @param path - Path to the JSON configuration file
|
|
5103
5410
|
* @param options - Optional client behavior configuration
|
|
5104
5411
|
* @returns New MCPClient instance
|
|
5105
|
-
* @throws
|
|
5412
|
+
* @throws If the file cannot be read or parsed
|
|
5106
5413
|
*
|
|
5107
5414
|
* @example
|
|
5108
5415
|
* ```typescript
|
|
@@ -5118,7 +5425,7 @@ var MCPClient = class _MCPClient extends BaseMCPClient {
|
|
|
5118
5425
|
* });
|
|
5119
5426
|
* ```
|
|
5120
5427
|
*
|
|
5121
|
-
* @see {@link
|
|
5428
|
+
* @see {@link MCPClient} for direct instantiation
|
|
5122
5429
|
* @see {@link fromDict} for inline configuration
|
|
5123
5430
|
*/
|
|
5124
5431
|
static fromConfigFile(path2, options) {
|
|
@@ -5265,7 +5572,7 @@ var MCPClient = class _MCPClient extends BaseMCPClient {
|
|
|
5265
5572
|
* @param code - JavaScript/TypeScript code to execute
|
|
5266
5573
|
* @param timeout - Optional execution timeout in milliseconds
|
|
5267
5574
|
* @returns Execution result with output, errors, and return value
|
|
5268
|
-
* @throws
|
|
5575
|
+
* @throws If code mode is not enabled
|
|
5269
5576
|
*
|
|
5270
5577
|
* @example
|
|
5271
5578
|
* ```typescript
|
|
@@ -5311,7 +5618,7 @@ var MCPClient = class _MCPClient extends BaseMCPClient {
|
|
|
5311
5618
|
* @param query - Optional search query to filter tools (defaults to empty string for all tools)
|
|
5312
5619
|
* @param detailLevel - Level of detail to return: "names", "descriptions", or "full"
|
|
5313
5620
|
* @returns Tool search results with matching tools
|
|
5314
|
-
* @throws
|
|
5621
|
+
* @throws If code mode is not enabled
|
|
5315
5622
|
*
|
|
5316
5623
|
* @example
|
|
5317
5624
|
* ```typescript
|