@mcpc-tech/core 0.3.36 → 0.3.38

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/index.cjs CHANGED
@@ -13969,6 +13969,147 @@ var ExperimentalServerTasks = class {
13969
13969
  requestStream(request, resultSchema, options) {
13970
13970
  return this._server.requestStream(request, resultSchema, options);
13971
13971
  }
13972
+ /**
13973
+ * Sends a sampling request and returns an AsyncGenerator that yields response messages.
13974
+ * The generator is guaranteed to end with either a 'result' or 'error' message.
13975
+ *
13976
+ * For task-augmented requests, yields 'taskCreated' and 'taskStatus' messages
13977
+ * before the final result.
13978
+ *
13979
+ * @example
13980
+ * ```typescript
13981
+ * const stream = server.experimental.tasks.createMessageStream({
13982
+ * messages: [{ role: 'user', content: { type: 'text', text: 'Hello' } }],
13983
+ * maxTokens: 100
13984
+ * }, {
13985
+ * onprogress: (progress) => {
13986
+ * // Handle streaming tokens via progress notifications
13987
+ * console.log('Progress:', progress.message);
13988
+ * }
13989
+ * });
13990
+ *
13991
+ * for await (const message of stream) {
13992
+ * switch (message.type) {
13993
+ * case 'taskCreated':
13994
+ * console.log('Task created:', message.task.taskId);
13995
+ * break;
13996
+ * case 'taskStatus':
13997
+ * console.log('Task status:', message.task.status);
13998
+ * break;
13999
+ * case 'result':
14000
+ * console.log('Final result:', message.result);
14001
+ * break;
14002
+ * case 'error':
14003
+ * console.error('Error:', message.error);
14004
+ * break;
14005
+ * }
14006
+ * }
14007
+ * ```
14008
+ *
14009
+ * @param params - The sampling request parameters
14010
+ * @param options - Optional request options (timeout, signal, task creation params, onprogress, etc.)
14011
+ * @returns AsyncGenerator that yields ResponseMessage objects
14012
+ *
14013
+ * @experimental
14014
+ */
14015
+ createMessageStream(params, options) {
14016
+ const clientCapabilities = this._server.getClientCapabilities();
14017
+ if ((params.tools || params.toolChoice) && !clientCapabilities?.sampling?.tools) {
14018
+ throw new Error("Client does not support sampling tools capability.");
14019
+ }
14020
+ if (params.messages.length > 0) {
14021
+ const lastMessage = params.messages[params.messages.length - 1];
14022
+ const lastContent = Array.isArray(lastMessage.content) ? lastMessage.content : [lastMessage.content];
14023
+ const hasToolResults = lastContent.some((c) => c.type === "tool_result");
14024
+ const previousMessage = params.messages.length > 1 ? params.messages[params.messages.length - 2] : void 0;
14025
+ const previousContent = previousMessage ? Array.isArray(previousMessage.content) ? previousMessage.content : [previousMessage.content] : [];
14026
+ const hasPreviousToolUse = previousContent.some((c) => c.type === "tool_use");
14027
+ if (hasToolResults) {
14028
+ if (lastContent.some((c) => c.type !== "tool_result")) {
14029
+ throw new Error("The last message must contain only tool_result content if any is present");
14030
+ }
14031
+ if (!hasPreviousToolUse) {
14032
+ throw new Error("tool_result blocks are not matching any tool_use from the previous message");
14033
+ }
14034
+ }
14035
+ if (hasPreviousToolUse) {
14036
+ const toolUseIds = new Set(previousContent.filter((c) => c.type === "tool_use").map((c) => c.id));
14037
+ const toolResultIds = new Set(lastContent.filter((c) => c.type === "tool_result").map((c) => c.toolUseId));
14038
+ if (toolUseIds.size !== toolResultIds.size || ![...toolUseIds].every((id) => toolResultIds.has(id))) {
14039
+ throw new Error("ids of tool_result blocks and tool_use blocks from previous message do not match");
14040
+ }
14041
+ }
14042
+ }
14043
+ return this.requestStream({
14044
+ method: "sampling/createMessage",
14045
+ params
14046
+ }, CreateMessageResultSchema, options);
14047
+ }
14048
+ /**
14049
+ * Sends an elicitation request and returns an AsyncGenerator that yields response messages.
14050
+ * The generator is guaranteed to end with either a 'result' or 'error' message.
14051
+ *
14052
+ * For task-augmented requests (especially URL-based elicitation), yields 'taskCreated'
14053
+ * and 'taskStatus' messages before the final result.
14054
+ *
14055
+ * @example
14056
+ * ```typescript
14057
+ * const stream = server.experimental.tasks.elicitInputStream({
14058
+ * mode: 'url',
14059
+ * message: 'Please authenticate',
14060
+ * elicitationId: 'auth-123',
14061
+ * url: 'https://example.com/auth'
14062
+ * }, {
14063
+ * task: { ttl: 300000 } // Task-augmented for long-running auth flow
14064
+ * });
14065
+ *
14066
+ * for await (const message of stream) {
14067
+ * switch (message.type) {
14068
+ * case 'taskCreated':
14069
+ * console.log('Task created:', message.task.taskId);
14070
+ * break;
14071
+ * case 'taskStatus':
14072
+ * console.log('Task status:', message.task.status);
14073
+ * break;
14074
+ * case 'result':
14075
+ * console.log('User action:', message.result.action);
14076
+ * break;
14077
+ * case 'error':
14078
+ * console.error('Error:', message.error);
14079
+ * break;
14080
+ * }
14081
+ * }
14082
+ * ```
14083
+ *
14084
+ * @param params - The elicitation request parameters
14085
+ * @param options - Optional request options (timeout, signal, task creation params, etc.)
14086
+ * @returns AsyncGenerator that yields ResponseMessage objects
14087
+ *
14088
+ * @experimental
14089
+ */
14090
+ elicitInputStream(params, options) {
14091
+ const clientCapabilities = this._server.getClientCapabilities();
14092
+ const mode = params.mode ?? "form";
14093
+ switch (mode) {
14094
+ case "url": {
14095
+ if (!clientCapabilities?.elicitation?.url) {
14096
+ throw new Error("Client does not support url elicitation.");
14097
+ }
14098
+ break;
14099
+ }
14100
+ case "form": {
14101
+ if (!clientCapabilities?.elicitation?.form) {
14102
+ throw new Error("Client does not support form elicitation.");
14103
+ }
14104
+ break;
14105
+ }
14106
+ }
14107
+ const normalizedParams = mode === "form" && params.mode === void 0 ? { ...params, mode: "form" } : params;
14108
+ return this.requestStream({
14109
+ method: "elicitation/create",
14110
+ params: normalizedParams
14111
+ }, ElicitResultSchema, options);
14112
+ }
13972
14113
  /**
13973
14114
  * Gets the current status of a task.
13974
14115
  *
@@ -16224,22 +16365,45 @@ async function auth(provider, options) {
16224
16365
  }
16225
16366
  }
16226
16367
  async function authInternal(provider, { serverUrl, authorizationCode, scope, resourceMetadataUrl, fetchFn }) {
16368
+ const cachedState = await provider.discoveryState?.();
16227
16369
  let resourceMetadata;
16228
16370
  let authorizationServerUrl;
16229
- try {
16230
- resourceMetadata = await discoverOAuthProtectedResourceMetadata(serverUrl, { resourceMetadataUrl }, fetchFn);
16231
- if (resourceMetadata.authorization_servers && resourceMetadata.authorization_servers.length > 0) {
16232
- authorizationServerUrl = resourceMetadata.authorization_servers[0];
16371
+ let metadata;
16372
+ let effectiveResourceMetadataUrl = resourceMetadataUrl;
16373
+ if (!effectiveResourceMetadataUrl && cachedState?.resourceMetadataUrl) {
16374
+ effectiveResourceMetadataUrl = new URL(cachedState.resourceMetadataUrl);
16375
+ }
16376
+ if (cachedState?.authorizationServerUrl) {
16377
+ authorizationServerUrl = cachedState.authorizationServerUrl;
16378
+ resourceMetadata = cachedState.resourceMetadata;
16379
+ metadata = cachedState.authorizationServerMetadata ?? await discoverAuthorizationServerMetadata(authorizationServerUrl, { fetchFn });
16380
+ if (!resourceMetadata) {
16381
+ try {
16382
+ resourceMetadata = await discoverOAuthProtectedResourceMetadata(serverUrl, { resourceMetadataUrl: effectiveResourceMetadataUrl }, fetchFn);
16383
+ } catch {
16384
+ }
16233
16385
  }
16234
- } catch {
16235
- }
16236
- if (!authorizationServerUrl) {
16237
- authorizationServerUrl = new URL("/", serverUrl);
16386
+ if (metadata !== cachedState.authorizationServerMetadata || resourceMetadata !== cachedState.resourceMetadata) {
16387
+ await provider.saveDiscoveryState?.({
16388
+ authorizationServerUrl: String(authorizationServerUrl),
16389
+ resourceMetadataUrl: effectiveResourceMetadataUrl?.toString(),
16390
+ resourceMetadata,
16391
+ authorizationServerMetadata: metadata
16392
+ });
16393
+ }
16394
+ } else {
16395
+ const serverInfo = await discoverOAuthServerInfo(serverUrl, { resourceMetadataUrl: effectiveResourceMetadataUrl, fetchFn });
16396
+ authorizationServerUrl = serverInfo.authorizationServerUrl;
16397
+ metadata = serverInfo.authorizationServerMetadata;
16398
+ resourceMetadata = serverInfo.resourceMetadata;
16399
+ await provider.saveDiscoveryState?.({
16400
+ authorizationServerUrl: String(authorizationServerUrl),
16401
+ resourceMetadataUrl: effectiveResourceMetadataUrl?.toString(),
16402
+ resourceMetadata,
16403
+ authorizationServerMetadata: metadata
16404
+ });
16238
16405
  }
16239
16406
  const resource = await selectResourceURL(serverUrl, provider, resourceMetadata);
16240
- const metadata = await discoverAuthorizationServerMetadata(authorizationServerUrl, {
16241
- fetchFn
16242
- });
16243
16407
  let clientInformation = await Promise.resolve(provider.clientInformation());
16244
16408
  if (!clientInformation) {
16245
16409
  if (authorizationCode !== void 0) {
@@ -16494,6 +16658,26 @@ async function discoverAuthorizationServerMetadata(authorizationServerUrl, { fet
16494
16658
  }
16495
16659
  return void 0;
16496
16660
  }
16661
+ async function discoverOAuthServerInfo(serverUrl, opts) {
16662
+ let resourceMetadata;
16663
+ let authorizationServerUrl;
16664
+ try {
16665
+ resourceMetadata = await discoverOAuthProtectedResourceMetadata(serverUrl, { resourceMetadataUrl: opts?.resourceMetadataUrl }, opts?.fetchFn);
16666
+ if (resourceMetadata.authorization_servers && resourceMetadata.authorization_servers.length > 0) {
16667
+ authorizationServerUrl = resourceMetadata.authorization_servers[0];
16668
+ }
16669
+ } catch {
16670
+ }
16671
+ if (!authorizationServerUrl) {
16672
+ authorizationServerUrl = String(new URL("/", serverUrl));
16673
+ }
16674
+ const authorizationServerMetadata = await discoverAuthorizationServerMetadata(authorizationServerUrl, { fetchFn: opts?.fetchFn });
16675
+ return {
16676
+ authorizationServerUrl,
16677
+ authorizationServerMetadata,
16678
+ resourceMetadata
16679
+ };
16680
+ }
16497
16681
  async function startAuthorization(authorizationServerUrl, { metadata, clientInformation, redirectUrl, scope, state, resource }) {
16498
16682
  let authorizationUrl;
16499
16683
  if (metadata) {
@@ -17391,18 +17575,6 @@ var cleanToolSchema = (schema) => {
17391
17575
  var import_node_process3 = require("node:process");
17392
17576
  var import_node_process4 = __toESM(require("node:process"), 1);
17393
17577
  var import_node_crypto = require("node:crypto");
17394
- var mcpClientPool = /* @__PURE__ */ new Map();
17395
- var mcpClientConnecting = /* @__PURE__ */ new Map();
17396
- var shortHash = (s) => (0, import_node_crypto.createHash)("sha256").update(s).digest("hex").slice(0, 8);
17397
- function defSignature(def) {
17398
- const defCopy = {
17399
- ...def
17400
- };
17401
- if (defCopy.transportType === "memory" || defCopy.transport) {
17402
- return `memory:${Date.now()}:${Math.random()}`;
17403
- }
17404
- return JSON.stringify(defCopy);
17405
- }
17406
17578
  function createTransport(def) {
17407
17579
  const defAny = def;
17408
17580
  const explicitType = defAny.transportType || defAny.type;
@@ -17450,90 +17622,43 @@ function createTransport(def) {
17450
17622
  }
17451
17623
  throw new Error(`Unsupported transport configuration: ${JSON.stringify(def)}`);
17452
17624
  }
17453
- async function getOrCreateMcpClient(defKey, def) {
17454
- const pooled = mcpClientPool.get(defKey);
17455
- if (pooled) {
17456
- pooled.refCount += 1;
17457
- return pooled.client;
17458
- }
17459
- const existingConnecting = mcpClientConnecting.get(defKey);
17460
- if (existingConnecting) {
17461
- const client = await existingConnecting;
17462
- const entry = mcpClientPool.get(defKey);
17463
- if (entry) entry.refCount += 1;
17464
- return client;
17465
- }
17466
- const transport = createTransport(def);
17467
- const connecting = (async () => {
17468
- const client = new Client({
17469
- name: `mcp_${shortHash(defSignature(def))}`,
17470
- version: "1.0.0"
17471
- });
17472
- await client.connect(transport, {
17473
- timeout: 6e4 * 10
17474
- });
17475
- return client;
17476
- })();
17477
- mcpClientConnecting.set(defKey, connecting);
17478
- try {
17479
- const client = await connecting;
17480
- mcpClientPool.set(defKey, {
17481
- client,
17482
- refCount: 1
17483
- });
17484
- return client;
17485
- } finally {
17486
- mcpClientConnecting.delete(defKey);
17625
+ function defSignature(def) {
17626
+ const defCopy = {
17627
+ ...def
17628
+ };
17629
+ if (defCopy.transportType === "memory" || defCopy.transport) {
17630
+ return `memory:${Date.now()}:${Math.random()}`;
17487
17631
  }
17632
+ return JSON.stringify(defCopy);
17488
17633
  }
17489
- async function releaseMcpClient(defKey) {
17490
- const entry = mcpClientPool.get(defKey);
17491
- if (!entry) return;
17492
- entry.refCount -= 1;
17493
- if (entry.refCount <= 0) {
17494
- mcpClientPool.delete(defKey);
17495
- try {
17496
- await entry.client.close();
17497
- } catch (err) {
17498
- console.error("Error closing MCP client:", err);
17499
- }
17500
- }
17634
+ var shortHash = (s) => (0, import_node_crypto.createHash)("sha256").update(s).digest("hex").slice(0, 8);
17635
+ async function createMcpClient(def) {
17636
+ const transport = createTransport(def);
17637
+ const client = new Client({
17638
+ name: `mcp_${shortHash(defSignature(def))}`,
17639
+ version: "1.0.0"
17640
+ });
17641
+ await client.connect(transport, {
17642
+ timeout: 6e4 * 10
17643
+ });
17644
+ return client;
17501
17645
  }
17502
- var cleanupAllPooledClients = async () => {
17503
- const entries = Array.from(mcpClientPool.entries());
17504
- mcpClientPool.clear();
17505
- await Promise.all(entries.map(async ([, { client }]) => {
17506
- try {
17507
- await client.close();
17508
- } catch (err) {
17509
- console.error("Error closing MCP client:", err);
17510
- }
17511
- }));
17512
- };
17513
- import_node_process4.default.once?.("exit", () => {
17514
- cleanupAllPooledClients();
17515
- });
17516
- import_node_process4.default.once?.("SIGINT", () => {
17517
- cleanupAllPooledClients().finally(() => import_node_process4.default.exit(0));
17518
- });
17519
17646
  async function composeMcpDepTools(mcpConfig, filterIn) {
17520
17647
  const allTools = {};
17521
17648
  const allClients = {};
17522
- const acquiredKeys = [];
17649
+ const clientsToClose = [];
17523
17650
  for (const [name, definition] of Object.entries(mcpConfig.mcpServers)) {
17524
17651
  const def = definition;
17525
17652
  if (def.disabled) continue;
17526
- const defKey = shortHash(defSignature(def));
17527
- const serverId = name;
17528
17653
  try {
17529
- const client = await getOrCreateMcpClient(defKey, def);
17530
- acquiredKeys.push(defKey);
17531
- allClients[serverId] = client;
17654
+ const client = await createMcpClient(def);
17655
+ clientsToClose.push(client);
17656
+ allClients[name] = client;
17532
17657
  const { tools } = await client.listTools();
17533
17658
  tools.forEach((tool2) => {
17534
17659
  const toolNameWithScope = `${name}.${tool2.name}`;
17535
17660
  const internalToolName = tool2.name;
17536
- const rawToolId = `${serverId}_${internalToolName}`;
17661
+ const rawToolId = `${name}_${internalToolName}`;
17537
17662
  const toolId = sanitizePropertyKey(rawToolId);
17538
17663
  if (filterIn && !filterIn({
17539
17664
  action: internalToolName,
@@ -17545,7 +17670,7 @@ async function composeMcpDepTools(mcpConfig, filterIn) {
17545
17670
  })) {
17546
17671
  return;
17547
17672
  }
17548
- const execute = (args) => allClients[serverId].callTool({
17673
+ const execute = (args) => allClients[name].callTool({
17549
17674
  name: internalToolName,
17550
17675
  arguments: args
17551
17676
  }, void 0, {
@@ -17562,10 +17687,12 @@ async function composeMcpDepTools(mcpConfig, filterIn) {
17562
17687
  }
17563
17688
  }
17564
17689
  const cleanupClients = async () => {
17565
- await Promise.all(acquiredKeys.map((k) => releaseMcpClient(k)));
17566
- acquiredKeys.length = 0;
17567
- Object.keys(allTools).forEach((key) => delete allTools[key]);
17568
- Object.keys(allClients).forEach((key) => delete allClients[key]);
17690
+ await Promise.all(clientsToClose.map((client) => {
17691
+ try {
17692
+ return client.close();
17693
+ } catch {
17694
+ }
17695
+ }));
17569
17696
  };
17570
17697
  return {
17571
17698
  tools: allTools,
package/index.mjs CHANGED
@@ -1,3 +1,5 @@
1
+ import { createRequire } from 'node:module';
2
+ const require = createRequire(import.meta.url);
1
3
  var __create = Object.create;
2
4
  var __defProp = Object.defineProperty;
3
5
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -13955,6 +13957,147 @@ var ExperimentalServerTasks = class {
13955
13957
  requestStream(request, resultSchema, options) {
13956
13958
  return this._server.requestStream(request, resultSchema, options);
13957
13959
  }
13960
+ /**
13961
+ * Sends a sampling request and returns an AsyncGenerator that yields response messages.
13962
+ * The generator is guaranteed to end with either a 'result' or 'error' message.
13963
+ *
13964
+ * For task-augmented requests, yields 'taskCreated' and 'taskStatus' messages
13965
+ * before the final result.
13966
+ *
13967
+ * @example
13968
+ * ```typescript
13969
+ * const stream = server.experimental.tasks.createMessageStream({
13970
+ * messages: [{ role: 'user', content: { type: 'text', text: 'Hello' } }],
13971
+ * maxTokens: 100
13972
+ * }, {
13973
+ * onprogress: (progress) => {
13974
+ * // Handle streaming tokens via progress notifications
13975
+ * console.log('Progress:', progress.message);
13976
+ * }
13977
+ * });
13978
+ *
13979
+ * for await (const message of stream) {
13980
+ * switch (message.type) {
13981
+ * case 'taskCreated':
13982
+ * console.log('Task created:', message.task.taskId);
13983
+ * break;
13984
+ * case 'taskStatus':
13985
+ * console.log('Task status:', message.task.status);
13986
+ * break;
13987
+ * case 'result':
13988
+ * console.log('Final result:', message.result);
13989
+ * break;
13990
+ * case 'error':
13991
+ * console.error('Error:', message.error);
13992
+ * break;
13993
+ * }
13994
+ * }
13995
+ * ```
13996
+ *
13997
+ * @param params - The sampling request parameters
13998
+ * @param options - Optional request options (timeout, signal, task creation params, onprogress, etc.)
13999
+ * @returns AsyncGenerator that yields ResponseMessage objects
14000
+ *
14001
+ * @experimental
14002
+ */
14003
+ createMessageStream(params, options) {
14004
+ const clientCapabilities = this._server.getClientCapabilities();
14005
+ if ((params.tools || params.toolChoice) && !clientCapabilities?.sampling?.tools) {
14006
+ throw new Error("Client does not support sampling tools capability.");
14007
+ }
14008
+ if (params.messages.length > 0) {
14009
+ const lastMessage = params.messages[params.messages.length - 1];
14010
+ const lastContent = Array.isArray(lastMessage.content) ? lastMessage.content : [lastMessage.content];
14011
+ const hasToolResults = lastContent.some((c) => c.type === "tool_result");
14012
+ const previousMessage = params.messages.length > 1 ? params.messages[params.messages.length - 2] : void 0;
14013
+ const previousContent = previousMessage ? Array.isArray(previousMessage.content) ? previousMessage.content : [previousMessage.content] : [];
14014
+ const hasPreviousToolUse = previousContent.some((c) => c.type === "tool_use");
14015
+ if (hasToolResults) {
14016
+ if (lastContent.some((c) => c.type !== "tool_result")) {
14017
+ throw new Error("The last message must contain only tool_result content if any is present");
14018
+ }
14019
+ if (!hasPreviousToolUse) {
14020
+ throw new Error("tool_result blocks are not matching any tool_use from the previous message");
14021
+ }
14022
+ }
14023
+ if (hasPreviousToolUse) {
14024
+ const toolUseIds = new Set(previousContent.filter((c) => c.type === "tool_use").map((c) => c.id));
14025
+ const toolResultIds = new Set(lastContent.filter((c) => c.type === "tool_result").map((c) => c.toolUseId));
14026
+ if (toolUseIds.size !== toolResultIds.size || ![...toolUseIds].every((id) => toolResultIds.has(id))) {
14027
+ throw new Error("ids of tool_result blocks and tool_use blocks from previous message do not match");
14028
+ }
14029
+ }
14030
+ }
14031
+ return this.requestStream({
14032
+ method: "sampling/createMessage",
14033
+ params
14034
+ }, CreateMessageResultSchema, options);
14035
+ }
14036
+ /**
14037
+ * Sends an elicitation request and returns an AsyncGenerator that yields response messages.
14038
+ * The generator is guaranteed to end with either a 'result' or 'error' message.
14039
+ *
14040
+ * For task-augmented requests (especially URL-based elicitation), yields 'taskCreated'
14041
+ * and 'taskStatus' messages before the final result.
14042
+ *
14043
+ * @example
14044
+ * ```typescript
14045
+ * const stream = server.experimental.tasks.elicitInputStream({
14046
+ * mode: 'url',
14047
+ * message: 'Please authenticate',
14048
+ * elicitationId: 'auth-123',
14049
+ * url: 'https://example.com/auth'
14050
+ * }, {
14051
+ * task: { ttl: 300000 } // Task-augmented for long-running auth flow
14052
+ * });
14053
+ *
14054
+ * for await (const message of stream) {
14055
+ * switch (message.type) {
14056
+ * case 'taskCreated':
14057
+ * console.log('Task created:', message.task.taskId);
14058
+ * break;
14059
+ * case 'taskStatus':
14060
+ * console.log('Task status:', message.task.status);
14061
+ * break;
14062
+ * case 'result':
14063
+ * console.log('User action:', message.result.action);
14064
+ * break;
14065
+ * case 'error':
14066
+ * console.error('Error:', message.error);
14067
+ * break;
14068
+ * }
14069
+ * }
14070
+ * ```
14071
+ *
14072
+ * @param params - The elicitation request parameters
14073
+ * @param options - Optional request options (timeout, signal, task creation params, etc.)
14074
+ * @returns AsyncGenerator that yields ResponseMessage objects
14075
+ *
14076
+ * @experimental
14077
+ */
14078
+ elicitInputStream(params, options) {
14079
+ const clientCapabilities = this._server.getClientCapabilities();
14080
+ const mode = params.mode ?? "form";
14081
+ switch (mode) {
14082
+ case "url": {
14083
+ if (!clientCapabilities?.elicitation?.url) {
14084
+ throw new Error("Client does not support url elicitation.");
14085
+ }
14086
+ break;
14087
+ }
14088
+ case "form": {
14089
+ if (!clientCapabilities?.elicitation?.form) {
14090
+ throw new Error("Client does not support form elicitation.");
14091
+ }
14092
+ break;
14093
+ }
14094
+ }
14095
+ const normalizedParams = mode === "form" && params.mode === void 0 ? { ...params, mode: "form" } : params;
14096
+ return this.requestStream({
14097
+ method: "elicitation/create",
14098
+ params: normalizedParams
14099
+ }, ElicitResultSchema, options);
14100
+ }
13958
14101
  /**
13959
14102
  * Gets the current status of a task.
13960
14103
  *
@@ -16210,22 +16353,45 @@ async function auth(provider, options) {
16210
16353
  }
16211
16354
  }
16212
16355
  async function authInternal(provider, { serverUrl, authorizationCode, scope, resourceMetadataUrl, fetchFn }) {
16356
+ const cachedState = await provider.discoveryState?.();
16213
16357
  let resourceMetadata;
16214
16358
  let authorizationServerUrl;
16215
- try {
16216
- resourceMetadata = await discoverOAuthProtectedResourceMetadata(serverUrl, { resourceMetadataUrl }, fetchFn);
16217
- if (resourceMetadata.authorization_servers && resourceMetadata.authorization_servers.length > 0) {
16218
- authorizationServerUrl = resourceMetadata.authorization_servers[0];
16359
+ let metadata;
16360
+ let effectiveResourceMetadataUrl = resourceMetadataUrl;
16361
+ if (!effectiveResourceMetadataUrl && cachedState?.resourceMetadataUrl) {
16362
+ effectiveResourceMetadataUrl = new URL(cachedState.resourceMetadataUrl);
16363
+ }
16364
+ if (cachedState?.authorizationServerUrl) {
16365
+ authorizationServerUrl = cachedState.authorizationServerUrl;
16366
+ resourceMetadata = cachedState.resourceMetadata;
16367
+ metadata = cachedState.authorizationServerMetadata ?? await discoverAuthorizationServerMetadata(authorizationServerUrl, { fetchFn });
16368
+ if (!resourceMetadata) {
16369
+ try {
16370
+ resourceMetadata = await discoverOAuthProtectedResourceMetadata(serverUrl, { resourceMetadataUrl: effectiveResourceMetadataUrl }, fetchFn);
16371
+ } catch {
16372
+ }
16219
16373
  }
16220
- } catch {
16221
- }
16222
- if (!authorizationServerUrl) {
16223
- authorizationServerUrl = new URL("/", serverUrl);
16374
+ if (metadata !== cachedState.authorizationServerMetadata || resourceMetadata !== cachedState.resourceMetadata) {
16375
+ await provider.saveDiscoveryState?.({
16376
+ authorizationServerUrl: String(authorizationServerUrl),
16377
+ resourceMetadataUrl: effectiveResourceMetadataUrl?.toString(),
16378
+ resourceMetadata,
16379
+ authorizationServerMetadata: metadata
16380
+ });
16381
+ }
16382
+ } else {
16383
+ const serverInfo = await discoverOAuthServerInfo(serverUrl, { resourceMetadataUrl: effectiveResourceMetadataUrl, fetchFn });
16384
+ authorizationServerUrl = serverInfo.authorizationServerUrl;
16385
+ metadata = serverInfo.authorizationServerMetadata;
16386
+ resourceMetadata = serverInfo.resourceMetadata;
16387
+ await provider.saveDiscoveryState?.({
16388
+ authorizationServerUrl: String(authorizationServerUrl),
16389
+ resourceMetadataUrl: effectiveResourceMetadataUrl?.toString(),
16390
+ resourceMetadata,
16391
+ authorizationServerMetadata: metadata
16392
+ });
16224
16393
  }
16225
16394
  const resource = await selectResourceURL(serverUrl, provider, resourceMetadata);
16226
- const metadata = await discoverAuthorizationServerMetadata(authorizationServerUrl, {
16227
- fetchFn
16228
- });
16229
16395
  let clientInformation = await Promise.resolve(provider.clientInformation());
16230
16396
  if (!clientInformation) {
16231
16397
  if (authorizationCode !== void 0) {
@@ -16480,6 +16646,26 @@ async function discoverAuthorizationServerMetadata(authorizationServerUrl, { fet
16480
16646
  }
16481
16647
  return void 0;
16482
16648
  }
16649
+ async function discoverOAuthServerInfo(serverUrl, opts) {
16650
+ let resourceMetadata;
16651
+ let authorizationServerUrl;
16652
+ try {
16653
+ resourceMetadata = await discoverOAuthProtectedResourceMetadata(serverUrl, { resourceMetadataUrl: opts?.resourceMetadataUrl }, opts?.fetchFn);
16654
+ if (resourceMetadata.authorization_servers && resourceMetadata.authorization_servers.length > 0) {
16655
+ authorizationServerUrl = resourceMetadata.authorization_servers[0];
16656
+ }
16657
+ } catch {
16658
+ }
16659
+ if (!authorizationServerUrl) {
16660
+ authorizationServerUrl = String(new URL("/", serverUrl));
16661
+ }
16662
+ const authorizationServerMetadata = await discoverAuthorizationServerMetadata(authorizationServerUrl, { fetchFn: opts?.fetchFn });
16663
+ return {
16664
+ authorizationServerUrl,
16665
+ authorizationServerMetadata,
16666
+ resourceMetadata
16667
+ };
16668
+ }
16483
16669
  async function startAuthorization(authorizationServerUrl, { metadata, clientInformation, redirectUrl, scope, state, resource }) {
16484
16670
  let authorizationUrl;
16485
16671
  if (metadata) {
@@ -17377,18 +17563,6 @@ var cleanToolSchema = (schema) => {
17377
17563
  import { cwd } from "node:process";
17378
17564
  import process5 from "node:process";
17379
17565
  import { createHash } from "node:crypto";
17380
- var mcpClientPool = /* @__PURE__ */ new Map();
17381
- var mcpClientConnecting = /* @__PURE__ */ new Map();
17382
- var shortHash = (s) => createHash("sha256").update(s).digest("hex").slice(0, 8);
17383
- function defSignature(def) {
17384
- const defCopy = {
17385
- ...def
17386
- };
17387
- if (defCopy.transportType === "memory" || defCopy.transport) {
17388
- return `memory:${Date.now()}:${Math.random()}`;
17389
- }
17390
- return JSON.stringify(defCopy);
17391
- }
17392
17566
  function createTransport(def) {
17393
17567
  const defAny = def;
17394
17568
  const explicitType = defAny.transportType || defAny.type;
@@ -17436,90 +17610,43 @@ function createTransport(def) {
17436
17610
  }
17437
17611
  throw new Error(`Unsupported transport configuration: ${JSON.stringify(def)}`);
17438
17612
  }
17439
- async function getOrCreateMcpClient(defKey, def) {
17440
- const pooled = mcpClientPool.get(defKey);
17441
- if (pooled) {
17442
- pooled.refCount += 1;
17443
- return pooled.client;
17444
- }
17445
- const existingConnecting = mcpClientConnecting.get(defKey);
17446
- if (existingConnecting) {
17447
- const client = await existingConnecting;
17448
- const entry = mcpClientPool.get(defKey);
17449
- if (entry) entry.refCount += 1;
17450
- return client;
17451
- }
17452
- const transport = createTransport(def);
17453
- const connecting = (async () => {
17454
- const client = new Client({
17455
- name: `mcp_${shortHash(defSignature(def))}`,
17456
- version: "1.0.0"
17457
- });
17458
- await client.connect(transport, {
17459
- timeout: 6e4 * 10
17460
- });
17461
- return client;
17462
- })();
17463
- mcpClientConnecting.set(defKey, connecting);
17464
- try {
17465
- const client = await connecting;
17466
- mcpClientPool.set(defKey, {
17467
- client,
17468
- refCount: 1
17469
- });
17470
- return client;
17471
- } finally {
17472
- mcpClientConnecting.delete(defKey);
17613
+ function defSignature(def) {
17614
+ const defCopy = {
17615
+ ...def
17616
+ };
17617
+ if (defCopy.transportType === "memory" || defCopy.transport) {
17618
+ return `memory:${Date.now()}:${Math.random()}`;
17473
17619
  }
17620
+ return JSON.stringify(defCopy);
17474
17621
  }
17475
- async function releaseMcpClient(defKey) {
17476
- const entry = mcpClientPool.get(defKey);
17477
- if (!entry) return;
17478
- entry.refCount -= 1;
17479
- if (entry.refCount <= 0) {
17480
- mcpClientPool.delete(defKey);
17481
- try {
17482
- await entry.client.close();
17483
- } catch (err) {
17484
- console.error("Error closing MCP client:", err);
17485
- }
17486
- }
17622
+ var shortHash = (s) => createHash("sha256").update(s).digest("hex").slice(0, 8);
17623
+ async function createMcpClient(def) {
17624
+ const transport = createTransport(def);
17625
+ const client = new Client({
17626
+ name: `mcp_${shortHash(defSignature(def))}`,
17627
+ version: "1.0.0"
17628
+ });
17629
+ await client.connect(transport, {
17630
+ timeout: 6e4 * 10
17631
+ });
17632
+ return client;
17487
17633
  }
17488
- var cleanupAllPooledClients = async () => {
17489
- const entries = Array.from(mcpClientPool.entries());
17490
- mcpClientPool.clear();
17491
- await Promise.all(entries.map(async ([, { client }]) => {
17492
- try {
17493
- await client.close();
17494
- } catch (err) {
17495
- console.error("Error closing MCP client:", err);
17496
- }
17497
- }));
17498
- };
17499
- process5.once?.("exit", () => {
17500
- cleanupAllPooledClients();
17501
- });
17502
- process5.once?.("SIGINT", () => {
17503
- cleanupAllPooledClients().finally(() => process5.exit(0));
17504
- });
17505
17634
  async function composeMcpDepTools(mcpConfig, filterIn) {
17506
17635
  const allTools = {};
17507
17636
  const allClients = {};
17508
- const acquiredKeys = [];
17637
+ const clientsToClose = [];
17509
17638
  for (const [name, definition] of Object.entries(mcpConfig.mcpServers)) {
17510
17639
  const def = definition;
17511
17640
  if (def.disabled) continue;
17512
- const defKey = shortHash(defSignature(def));
17513
- const serverId = name;
17514
17641
  try {
17515
- const client = await getOrCreateMcpClient(defKey, def);
17516
- acquiredKeys.push(defKey);
17517
- allClients[serverId] = client;
17642
+ const client = await createMcpClient(def);
17643
+ clientsToClose.push(client);
17644
+ allClients[name] = client;
17518
17645
  const { tools } = await client.listTools();
17519
17646
  tools.forEach((tool2) => {
17520
17647
  const toolNameWithScope = `${name}.${tool2.name}`;
17521
17648
  const internalToolName = tool2.name;
17522
- const rawToolId = `${serverId}_${internalToolName}`;
17649
+ const rawToolId = `${name}_${internalToolName}`;
17523
17650
  const toolId = sanitizePropertyKey(rawToolId);
17524
17651
  if (filterIn && !filterIn({
17525
17652
  action: internalToolName,
@@ -17531,7 +17658,7 @@ async function composeMcpDepTools(mcpConfig, filterIn) {
17531
17658
  })) {
17532
17659
  return;
17533
17660
  }
17534
- const execute = (args) => allClients[serverId].callTool({
17661
+ const execute = (args) => allClients[name].callTool({
17535
17662
  name: internalToolName,
17536
17663
  arguments: args
17537
17664
  }, void 0, {
@@ -17548,10 +17675,12 @@ async function composeMcpDepTools(mcpConfig, filterIn) {
17548
17675
  }
17549
17676
  }
17550
17677
  const cleanupClients = async () => {
17551
- await Promise.all(acquiredKeys.map((k) => releaseMcpClient(k)));
17552
- acquiredKeys.length = 0;
17553
- Object.keys(allTools).forEach((key) => delete allTools[key]);
17554
- Object.keys(allClients).forEach((key) => delete allClients[key]);
17678
+ await Promise.all(clientsToClose.map((client) => {
17679
+ try {
17680
+ return client.close();
17681
+ } catch {
17682
+ }
17683
+ }));
17555
17684
  };
17556
17685
  return {
17557
17686
  tools: allTools,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mcpc-tech/core",
3
- "version": "0.3.36",
3
+ "version": "0.3.38",
4
4
  "homepage": "https://jsr.io/@mcpc/core",
5
5
  "dependencies": {
6
6
  "@ai-sdk/provider": "^2.0.0",
@@ -1,3 +1,6 @@
1
+ import { createRequire } from 'node:module';
2
+ const require = createRequire(import.meta.url);
3
+
1
4
  // __mcpc__core_latest/node_modules/@mcpc/core/src/plugins/large-result.ts
2
5
  import { mkdtemp, writeFile } from "node:fs/promises";
3
6
  import { join } from "node:path";
@@ -1,3 +1,6 @@
1
+ import { createRequire } from 'node:module';
2
+ const require = createRequire(import.meta.url);
3
+
1
4
  // __mcpc__core_latest/node_modules/@mcpc/core/src/plugins/search-tool.ts
2
5
  import rg from "@mcpc-tech/ripgrep-napi";
3
6
  import { tmpdir } from "node:os";
@@ -1,3 +1,6 @@
1
+ import { createRequire } from 'node:module';
2
+ const require = createRequire(import.meta.url);
3
+
1
4
  // __mcpc__core_latest/node_modules/@mcpc/core/src/plugins/skills.ts
2
5
  import { readdir, readFile } from "node:fs/promises";
3
6
  import { join, relative, resolve } from "node:path";
package/plugins.mjs CHANGED
@@ -1,3 +1,6 @@
1
+ import { createRequire } from 'node:module';
2
+ const require = createRequire(import.meta.url);
3
+
1
4
  // __mcpc__core_latest/node_modules/@mcpc/core/src/plugins/search-tool.js
2
5
  import rg from "@mcpc-tech/ripgrep-napi";
3
6
  import { tmpdir } from "node:os";
@@ -1 +1 @@
1
- {"version":3,"file":"mcp.d.ts","sources":["../../../../src/utils/common/mcp.ts"],"names":[],"mappings":"AAKA,cAA+B,UAAU,iCAAiC;AAwL1E,OAAO,iBAAe,mBACpB,WAAW,UAAU,EACrB,YAAY;EACV,QAAQ,MAAM;EACd,MAAM,GAAG;EACT,SAAS,MAAM;EACf,mBAAmB,MAAM;EACzB,kBAAkB,MAAM;EACxB,QAAQ,MAAM;MACV,OAAO,GACZ,QAAQ,OAAO,MAAM,EAAE,GAAG"}
1
+ {"version":3,"file":"mcp.d.ts","sources":["../../../../src/utils/common/mcp.ts"],"names":[],"mappings":"AAKA,cAA+B,UAAU,iCAAiC;AAiG1E,OAAO,iBAAe,mBACpB,WAAW,UAAU,EACrB,YAAY;EACV,QAAQ,MAAM;EACd,MAAM,GAAG;EACT,SAAS,MAAM;EACf,mBAAmB,MAAM;EACzB,kBAAkB,MAAM;EACxB,QAAQ,MAAM;MACV,OAAO,GACZ,QAAQ,OAAO,MAAM,EAAE,GAAG"}