@frontmcp/plugin-skilled-openapi 1.2.1 → 1.4.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/esm/index.mjs CHANGED
@@ -372,9 +372,10 @@ var BundleSyncService = class {
372
372
  if (this.options.exposeOperationsAsInternalTools && this.operationToolFactory) {
373
373
  try {
374
374
  this.operationToolFactory.unregisterAll();
375
+ const pathsWithGet = collectPathsWithGet(this.hiddenOps.values());
375
376
  for (const entry of this.hiddenOps.values()) {
376
377
  try {
377
- this.operationToolFactory.register(entry);
378
+ this.operationToolFactory.register(entry, { pathsWithGet });
378
379
  } catch (regErr) {
379
380
  this.logger.warn(
380
381
  `[bundle-sync] internal-tool register failed for ${entry.bundleId}.${entry.op.operationId}: ${regErr.message}`
@@ -401,9 +402,10 @@ var BundleSyncService = class {
401
402
  if (this.options.exposeOperationsAsInternalTools && this.operationToolFactory) {
402
403
  try {
403
404
  this.operationToolFactory.unregisterAll();
405
+ const pathsWithGet = collectPathsWithGet(snapshotEntries);
404
406
  for (const entry of snapshotEntries) {
405
407
  try {
406
- this.operationToolFactory.register(entry);
408
+ this.operationToolFactory.register(entry, { pathsWithGet });
407
409
  } catch {
408
410
  }
409
411
  }
@@ -500,6 +502,15 @@ var BundleSyncService = class {
500
502
  }
501
503
  }
502
504
  };
505
+ function collectPathsWithGet(entries) {
506
+ const set = /* @__PURE__ */ new Set();
507
+ for (const entry of entries) {
508
+ if (typeof entry.op.httpMethod === "string" && entry.op.httpMethod.toUpperCase() === "GET") {
509
+ set.add(entry.op.pathTemplate);
510
+ }
511
+ }
512
+ return set;
513
+ }
503
514
 
504
515
  // plugins/plugin-skilled-openapi/src/tools/execute-action.tool.ts
505
516
  import { BundleStore, SkillAuditWriterToken } from "@frontmcp/adapters/skills";
@@ -1137,6 +1148,7 @@ LoadSkillTool = __decorateClass([
1137
1148
  ], LoadSkillTool);
1138
1149
 
1139
1150
  // plugins/plugin-skilled-openapi/src/tools/operation-tool.factory.ts
1151
+ import { classifyOne } from "@frontmcp/adapters/skills";
1140
1152
  import {
1141
1153
  ToolInstance,
1142
1154
  ToolKind
@@ -1179,12 +1191,21 @@ var OperationToolFactory = class {
1179
1191
  }
1180
1192
  /** Map (bundleId|opId) → the executor function that doubles as registry token. */
1181
1193
  registered = /* @__PURE__ */ new Map();
1194
+ /** Tool names this factory has pushed into the classification registry. */
1195
+ classificationKeys = /* @__PURE__ */ new Set();
1182
1196
  /**
1183
1197
  * Register one operation as an internal tool. Idempotent — calling twice
1184
1198
  * with the same `(bundleId, operationId)` is a no-op (the existing
1185
1199
  * registration is left in place).
1200
+ *
1201
+ * When the factory was constructed with a `classificationRegistry` AND
1202
+ * the caller supplies `ctx.pathsWithGet`, the factory also classifies the
1203
+ * operation (per HTTP semantics) and pushes the result into the
1204
+ * classification registry. A downstream `tools/call` hook can then look
1205
+ * up the classification by tool name and auto-emit
1206
+ * `notifications/resources/*` on success.
1186
1207
  */
1187
- register(entry) {
1208
+ register(entry, ctx) {
1188
1209
  const key2 = `${entry.bundleId}|${entry.op.operationId}`;
1189
1210
  if (this.registered.has(key2)) return;
1190
1211
  const executor = this.makeExecutor(entry);
@@ -1197,10 +1218,31 @@ var OperationToolFactory = class {
1197
1218
  const instance = new ToolInstance(record, this.deps.providers, OPERATION_TOOL_OWNER);
1198
1219
  this.deps.toolRegistry.registerToolInstance(instance);
1199
1220
  this.registered.set(key2, executor);
1221
+ if (this.deps.classificationRegistry && ctx?.pathsWithGet) {
1222
+ try {
1223
+ const classification = classifyOne(
1224
+ entry.bundleId,
1225
+ {
1226
+ operationId: entry.op.operationId,
1227
+ method: entry.op.httpMethod,
1228
+ path: entry.op.pathTemplate
1229
+ },
1230
+ ctx.pathsWithGet
1231
+ );
1232
+ const toolName = metadata.name;
1233
+ this.deps.classificationRegistry.register(toolName, classification);
1234
+ this.classificationKeys.add(toolName);
1235
+ } catch (e) {
1236
+ this.deps.logger.warn(
1237
+ `[operation-tool-factory] classification failed for ${entry.bundleId}.${entry.op.operationId}: ${e.message}`
1238
+ );
1239
+ }
1240
+ }
1200
1241
  }
1201
1242
  /**
1202
1243
  * Unregister every tool this factory has registered. Used on bundle swap
1203
- * before re-registering the new bundle's operations.
1244
+ * before re-registering the new bundle's operations. Also clears the
1245
+ * classification entries this factory pushed.
1204
1246
  */
1205
1247
  unregisterAll() {
1206
1248
  for (const executor of this.registered.values()) {
@@ -1211,6 +1253,12 @@ var OperationToolFactory = class {
1211
1253
  }
1212
1254
  }
1213
1255
  this.registered.clear();
1256
+ if (this.deps.classificationRegistry && this.classificationKeys.size > 0) {
1257
+ for (const toolName of this.classificationKeys) {
1258
+ this.deps.classificationRegistry.unregister(toolName);
1259
+ }
1260
+ this.classificationKeys.clear();
1261
+ }
1214
1262
  }
1215
1263
  /** Number of currently-registered internal operation tools (test/audit hook). */
1216
1264
  get size() {
package/esm/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@frontmcp/plugin-skilled-openapi",
3
- "version": "1.2.1",
3
+ "version": "1.4.0",
4
4
  "description": "FrontMCP plugin: serve a customer's OpenAPI spec as skill bundles (signed, OpenAPI-Overlay-based) with hidden per-operation tools mediated by three meta-tools (search_skill / load_skill / execute_action).",
5
5
  "author": "AgentFront <info@agentfront.dev>",
6
6
  "license": "Apache-2.0",
@@ -45,14 +45,14 @@
45
45
  }
46
46
  },
47
47
  "dependencies": {
48
- "@frontmcp/adapters": "1.2.1",
49
- "@frontmcp/auth": "1.2.1",
50
- "@frontmcp/protocol": "1.2.1",
51
- "@frontmcp/sdk": "1.2.1",
52
- "@frontmcp/utils": "1.2.1"
48
+ "@frontmcp/adapters": "1.4.0",
49
+ "@frontmcp/auth": "1.4.0",
50
+ "@frontmcp/protocol": "1.4.0",
51
+ "@frontmcp/sdk": "1.4.0",
52
+ "@frontmcp/utils": "1.4.0"
53
53
  },
54
54
  "peerDependencies": {
55
- "@frontmcp/lazy-zod": "1.2.1"
55
+ "@frontmcp/lazy-zod": "1.4.0"
56
56
  },
57
57
  "devDependencies": {
58
58
  "reflect-metadata": "^0.2.2"
package/index.js CHANGED
@@ -37,7 +37,7 @@ __export(index_exports, {
37
37
  module.exports = __toCommonJS(index_exports);
38
38
 
39
39
  // plugins/plugin-skilled-openapi/src/skilled-openapi.plugin.ts
40
- var import_skills5 = require("@frontmcp/adapters/skills");
40
+ var import_skills6 = require("@frontmcp/adapters/skills");
41
41
  var import_sdk5 = require("@frontmcp/sdk");
42
42
 
43
43
  // plugins/plugin-skilled-openapi/src/executor/credential-resolver.ts
@@ -366,9 +366,10 @@ var BundleSyncService = class {
366
366
  if (this.options.exposeOperationsAsInternalTools && this.operationToolFactory) {
367
367
  try {
368
368
  this.operationToolFactory.unregisterAll();
369
+ const pathsWithGet = collectPathsWithGet(this.hiddenOps.values());
369
370
  for (const entry of this.hiddenOps.values()) {
370
371
  try {
371
- this.operationToolFactory.register(entry);
372
+ this.operationToolFactory.register(entry, { pathsWithGet });
372
373
  } catch (regErr) {
373
374
  this.logger.warn(
374
375
  `[bundle-sync] internal-tool register failed for ${entry.bundleId}.${entry.op.operationId}: ${regErr.message}`
@@ -395,9 +396,10 @@ var BundleSyncService = class {
395
396
  if (this.options.exposeOperationsAsInternalTools && this.operationToolFactory) {
396
397
  try {
397
398
  this.operationToolFactory.unregisterAll();
399
+ const pathsWithGet = collectPathsWithGet(snapshotEntries);
398
400
  for (const entry of snapshotEntries) {
399
401
  try {
400
- this.operationToolFactory.register(entry);
402
+ this.operationToolFactory.register(entry, { pathsWithGet });
401
403
  } catch {
402
404
  }
403
405
  }
@@ -494,6 +496,15 @@ var BundleSyncService = class {
494
496
  }
495
497
  }
496
498
  };
499
+ function collectPathsWithGet(entries) {
500
+ const set = /* @__PURE__ */ new Set();
501
+ for (const entry of entries) {
502
+ if (typeof entry.op.httpMethod === "string" && entry.op.httpMethod.toUpperCase() === "GET") {
503
+ set.add(entry.op.pathTemplate);
504
+ }
505
+ }
506
+ return set;
507
+ }
497
508
 
498
509
  // plugins/plugin-skilled-openapi/src/tools/execute-action.tool.ts
499
510
  var import_skills4 = require("@frontmcp/adapters/skills");
@@ -1128,6 +1139,7 @@ LoadSkillTool = __decorateClass([
1128
1139
  ], LoadSkillTool);
1129
1140
 
1130
1141
  // plugins/plugin-skilled-openapi/src/tools/operation-tool.factory.ts
1142
+ var import_skills5 = require("@frontmcp/adapters/skills");
1131
1143
  var import_sdk3 = require("@frontmcp/sdk");
1132
1144
  var OPERATION_TOOL_OWNER_TOKEN = /* @__PURE__ */ Symbol.for("skilled-openapi:operation-tool-owner");
1133
1145
  var OPERATION_TOOL_OWNER = {
@@ -1167,12 +1179,21 @@ var OperationToolFactory = class {
1167
1179
  }
1168
1180
  /** Map (bundleId|opId) → the executor function that doubles as registry token. */
1169
1181
  registered = /* @__PURE__ */ new Map();
1182
+ /** Tool names this factory has pushed into the classification registry. */
1183
+ classificationKeys = /* @__PURE__ */ new Set();
1170
1184
  /**
1171
1185
  * Register one operation as an internal tool. Idempotent — calling twice
1172
1186
  * with the same `(bundleId, operationId)` is a no-op (the existing
1173
1187
  * registration is left in place).
1188
+ *
1189
+ * When the factory was constructed with a `classificationRegistry` AND
1190
+ * the caller supplies `ctx.pathsWithGet`, the factory also classifies the
1191
+ * operation (per HTTP semantics) and pushes the result into the
1192
+ * classification registry. A downstream `tools/call` hook can then look
1193
+ * up the classification by tool name and auto-emit
1194
+ * `notifications/resources/*` on success.
1174
1195
  */
1175
- register(entry) {
1196
+ register(entry, ctx) {
1176
1197
  const key2 = `${entry.bundleId}|${entry.op.operationId}`;
1177
1198
  if (this.registered.has(key2)) return;
1178
1199
  const executor = this.makeExecutor(entry);
@@ -1185,10 +1206,31 @@ var OperationToolFactory = class {
1185
1206
  const instance = new import_sdk3.ToolInstance(record, this.deps.providers, OPERATION_TOOL_OWNER);
1186
1207
  this.deps.toolRegistry.registerToolInstance(instance);
1187
1208
  this.registered.set(key2, executor);
1209
+ if (this.deps.classificationRegistry && ctx?.pathsWithGet) {
1210
+ try {
1211
+ const classification = (0, import_skills5.classifyOne)(
1212
+ entry.bundleId,
1213
+ {
1214
+ operationId: entry.op.operationId,
1215
+ method: entry.op.httpMethod,
1216
+ path: entry.op.pathTemplate
1217
+ },
1218
+ ctx.pathsWithGet
1219
+ );
1220
+ const toolName = metadata.name;
1221
+ this.deps.classificationRegistry.register(toolName, classification);
1222
+ this.classificationKeys.add(toolName);
1223
+ } catch (e) {
1224
+ this.deps.logger.warn(
1225
+ `[operation-tool-factory] classification failed for ${entry.bundleId}.${entry.op.operationId}: ${e.message}`
1226
+ );
1227
+ }
1228
+ }
1188
1229
  }
1189
1230
  /**
1190
1231
  * Unregister every tool this factory has registered. Used on bundle swap
1191
- * before re-registering the new bundle's operations.
1232
+ * before re-registering the new bundle's operations. Also clears the
1233
+ * classification entries this factory pushed.
1192
1234
  */
1193
1235
  unregisterAll() {
1194
1236
  for (const executor of this.registered.values()) {
@@ -1199,6 +1241,12 @@ var OperationToolFactory = class {
1199
1241
  }
1200
1242
  }
1201
1243
  this.registered.clear();
1244
+ if (this.deps.classificationRegistry && this.classificationKeys.size > 0) {
1245
+ for (const toolName of this.classificationKeys) {
1246
+ this.deps.classificationRegistry.unregister(toolName);
1247
+ }
1248
+ this.classificationKeys.clear();
1249
+ }
1202
1250
  }
1203
1251
  /** Number of currently-registered internal operation tools (test/audit hook). */
1204
1252
  get size() {
@@ -1397,7 +1445,7 @@ var SkilledOpenApiPlugin = class extends import_sdk5.DynamicPlugin {
1397
1445
  { name: "skilled-openapi:hidden-ops", provide: HiddenOpRegistry, useValue: new HiddenOpRegistry() },
1398
1446
  {
1399
1447
  name: "skilled-openapi:bundle-store",
1400
- provide: import_skills5.BundleStore,
1448
+ provide: import_skills6.BundleStore,
1401
1449
  // Resolve TelemetryAccessor from the scope's provider registry so the
1402
1450
  // bundle-pulls counter and `skill.bundle.swap` span actually export.
1403
1451
  // The accessor is structurally compatible with `BundleStoreTelemetry`.
@@ -1405,7 +1453,7 @@ var SkilledOpenApiPlugin = class extends import_sdk5.DynamicPlugin {
1405
1453
  // we resolve `undefined` and the BundleStore falls through its zero-cost
1406
1454
  // no-telemetry path.
1407
1455
  inject: () => [import_sdk5.ScopeEntry],
1408
- useFactory: (scope) => new import_skills5.BundleStore({ telemetry: resolveBundleTelemetry(scope) })
1456
+ useFactory: (scope) => new import_skills6.BundleStore({ telemetry: resolveBundleTelemetry(scope) })
1409
1457
  },
1410
1458
  {
1411
1459
  name: "skilled-openapi:credential-resolver",
@@ -1421,7 +1469,7 @@ var SkilledOpenApiPlugin = class extends import_sdk5.DynamicPlugin {
1421
1469
  {
1422
1470
  name: "skilled-openapi:bundle-sync",
1423
1471
  provide: BundleSyncService,
1424
- inject: () => [import_sdk5.ScopeEntry, HiddenOpRegistry, import_skills5.BundleStore],
1472
+ inject: () => [import_sdk5.ScopeEntry, HiddenOpRegistry, import_skills6.BundleStore],
1425
1473
  useFactory: async (scope, hiddenOps, bundleStore) => {
1426
1474
  const logger = scope.logger.child("skilled-openapi:sync");
1427
1475
  const lazySkillRegistry = new Proxy({}, {
@@ -1478,7 +1526,7 @@ var SkilledOpenApiPlugin = class extends import_sdk5.DynamicPlugin {
1478
1526
  );
1479
1527
  let source;
1480
1528
  try {
1481
- source = (0, import_skills5.createBundleSource)(parsed.source, parsed.bundleCacheDir, logger);
1529
+ source = (0, import_skills6.createBundleSource)(parsed.source, parsed.bundleCacheDir, logger);
1482
1530
  } catch (e) {
1483
1531
  logger.error(`failed to construct bundle source: ${e.message}`);
1484
1532
  return sync;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@frontmcp/plugin-skilled-openapi",
3
- "version": "1.2.1",
3
+ "version": "1.4.0",
4
4
  "description": "FrontMCP plugin: serve a customer's OpenAPI spec as skill bundles (signed, OpenAPI-Overlay-based) with hidden per-operation tools mediated by three meta-tools (search_skill / load_skill / execute_action).",
5
5
  "author": "AgentFront <info@agentfront.dev>",
6
6
  "license": "Apache-2.0",
@@ -45,14 +45,14 @@
45
45
  }
46
46
  },
47
47
  "dependencies": {
48
- "@frontmcp/adapters": "1.2.1",
49
- "@frontmcp/auth": "1.2.1",
50
- "@frontmcp/protocol": "1.2.1",
51
- "@frontmcp/sdk": "1.2.1",
52
- "@frontmcp/utils": "1.2.1"
48
+ "@frontmcp/adapters": "1.4.0",
49
+ "@frontmcp/auth": "1.4.0",
50
+ "@frontmcp/protocol": "1.4.0",
51
+ "@frontmcp/sdk": "1.4.0",
52
+ "@frontmcp/utils": "1.4.0"
53
53
  },
54
54
  "peerDependencies": {
55
- "@frontmcp/lazy-zod": "1.2.1"
55
+ "@frontmcp/lazy-zod": "1.4.0"
56
56
  },
57
57
  "devDependencies": {
58
58
  "reflect-metadata": "^0.2.2"
@@ -1 +1 @@
1
- {"version":3,"file":"bundle-sync.service.d.ts","sourceRoot":"","sources":["../../src/sync/bundle-sync.service.ts"],"names":[],"mappings":"AAEA,OAAO,EASL,KAAK,UAAU,EACf,KAAK,WAAW,EAEhB,KAAK,cAAc,EAEnB,KAAK,wBAAwB,EAC9B,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,KAAK,cAAc,EAAqB,KAAK,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAEpG,OAAO,EAAsB,KAAK,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAC3F,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,KAAK,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAE5E,MAAM,WAAW,iBAAiB;IAChC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,WAAW,EAAE,YAAY,EAAE,CAAC;IAC5B;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,wBAAwB,CAAC;IACrC;;;;;;;;OAQG;IACH,+BAA+B,EAAE,OAAO,CAAC;CAC1C;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,UAAU,CAAC;CACnB;AAED;;;;;;;;;;;;GAYG;AACH,qBAAa,iBAAiB;IAI1B,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB;;;;;;OAMG;IACH,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAC;IAfxC,OAAO,CAAC,yBAAyB,CAA0C;gBAGxD,aAAa,EAAE,sBAAsB,EACrC,SAAS,EAAE,gBAAgB,EAC3B,WAAW,EAAE,WAAW,EACxB,OAAO,EAAE,iBAAiB,EAC1B,MAAM,EAAE,cAAc;IACvC;;;;;;OAMG;IACc,oBAAoB,CAAC,EAAE,oBAAoB,YAAA;IAG9D;;;;OAIG;IACG,KAAK,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAoO/D;;;;OAIG;IACH,OAAO,CAAC,cAAc;IAatB,OAAO,CAAC,gBAAgB;CAmCzB"}
1
+ {"version":3,"file":"bundle-sync.service.d.ts","sourceRoot":"","sources":["../../src/sync/bundle-sync.service.ts"],"names":[],"mappings":"AAEA,OAAO,EASL,KAAK,UAAU,EACf,KAAK,WAAW,EAEhB,KAAK,cAAc,EAEnB,KAAK,wBAAwB,EAC9B,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,KAAK,cAAc,EAAqB,KAAK,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAEpG,OAAO,EAAsB,KAAK,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAC3F,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,KAAK,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAE5E,MAAM,WAAW,iBAAiB;IAChC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,WAAW,EAAE,YAAY,EAAE,CAAC;IAC5B;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,wBAAwB,CAAC;IACrC;;;;;;;;OAQG;IACH,+BAA+B,EAAE,OAAO,CAAC;CAC1C;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,UAAU,CAAC;CACnB;AAED;;;;;;;;;;;;GAYG;AACH,qBAAa,iBAAiB;IAI1B,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB;;;;;;OAMG;IACH,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAC;IAfxC,OAAO,CAAC,yBAAyB,CAA0C;gBAGxD,aAAa,EAAE,sBAAsB,EACrC,SAAS,EAAE,gBAAgB,EAC3B,WAAW,EAAE,WAAW,EACxB,OAAO,EAAE,iBAAiB,EAC1B,MAAM,EAAE,cAAc;IACvC;;;;;;OAMG;IACc,oBAAoB,CAAC,EAAE,oBAAoB,YAAA;IAG9D;;;;OAIG;IACG,KAAK,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,iBAAiB,CAAC;IA0O/D;;;;OAIG;IACH,OAAO,CAAC,cAAc;IAatB,OAAO,CAAC,gBAAgB;CAmCzB"}
@@ -1,3 +1,4 @@
1
+ import { type ClassificationRegistry } from '@frontmcp/adapters/skills';
1
2
  import { type FrontMcpLogger, type ProviderRegistry, type ToolRegistry } from '@frontmcp/sdk';
2
3
  import { type HiddenOpEntry } from '../registry/hidden-op.registry';
3
4
  /**
@@ -13,6 +14,25 @@ export interface OperationToolFactoryDeps {
13
14
  providers: ProviderRegistry;
14
15
  /** Logger for diagnostics. */
15
16
  logger: FrontMcpLogger;
17
+ /**
18
+ * Optional classification registry. When set together with `pathsWithGet`
19
+ * on each `register()` call, the factory also records the OpenAPI -> MCP
20
+ * classification for the operation so a runtime dispatcher hook can
21
+ * auto-emit `notifications/resources/updated` / `…/list_changed` on
22
+ * successful tool calls. Unregistering via `unregisterAll()` clears the
23
+ * matching classification entries.
24
+ */
25
+ classificationRegistry?: ClassificationRegistry;
26
+ }
27
+ /**
28
+ * Optional context passed per `register()` call so the factory can classify
29
+ * the operation against the rest of the bundle. Callers (typically the
30
+ * bundle-sync service) precompute `pathsWithGet` once over the bundle's
31
+ * full operation list before iterating.
32
+ */
33
+ export interface OperationRegisterContext {
34
+ /** Set of path templates that have a GET op in the same bundle. */
35
+ pathsWithGet: ReadonlySet<string>;
16
36
  }
17
37
  /**
18
38
  * Stable result envelope produced by every operation executor. Mirrors the
@@ -35,16 +55,26 @@ export declare class OperationToolFactory {
35
55
  private readonly deps;
36
56
  /** Map (bundleId|opId) → the executor function that doubles as registry token. */
37
57
  private registered;
58
+ /** Tool names this factory has pushed into the classification registry. */
59
+ private classificationKeys;
38
60
  constructor(deps: OperationToolFactoryDeps);
39
61
  /**
40
62
  * Register one operation as an internal tool. Idempotent — calling twice
41
63
  * with the same `(bundleId, operationId)` is a no-op (the existing
42
64
  * registration is left in place).
65
+ *
66
+ * When the factory was constructed with a `classificationRegistry` AND
67
+ * the caller supplies `ctx.pathsWithGet`, the factory also classifies the
68
+ * operation (per HTTP semantics) and pushes the result into the
69
+ * classification registry. A downstream `tools/call` hook can then look
70
+ * up the classification by tool name and auto-emit
71
+ * `notifications/resources/*` on success.
43
72
  */
44
- register(entry: HiddenOpEntry): void;
73
+ register(entry: HiddenOpEntry, ctx?: OperationRegisterContext): void;
45
74
  /**
46
75
  * Unregister every tool this factory has registered. Used on bundle swap
47
- * before re-registering the new bundle's operations.
76
+ * before re-registering the new bundle's operations. Also clears the
77
+ * classification entries this factory pushed.
48
78
  */
49
79
  unregisterAll(): void;
50
80
  /** Number of currently-registered internal operation tools (test/audit hook). */
@@ -1 +1 @@
1
- {"version":3,"file":"operation-tool.factory.d.ts","sourceRoot":"","sources":["../../src/tools/operation-tool.factory.ts"],"names":[],"mappings":"AAcA,OAAO,EAIL,KAAK,cAAc,EACnB,KAAK,gBAAgB,EAGrB,KAAK,YAAY,EAClB,MAAM,eAAe,CAAC;AAIvB,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAWpE;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAS/E;AA2BD,MAAM,WAAW,wBAAwB;IACvC,sEAAsE;IACtE,YAAY,EAAE,YAAY,CAAC;IAC3B,8DAA8D;IAC9D,SAAS,EAAE,gBAAgB,CAAC;IAC5B,8BAA8B;IAC9B,MAAM,EAAE,cAAc,CAAC;CACxB;AAED;;;;;GAKG;AACH,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAUD;;;GAGG;AACH,qBAAa,oBAAoB;IAInB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAHjC,kFAAkF;IAClF,OAAO,CAAC,UAAU,CAAwC;gBAE7B,IAAI,EAAE,wBAAwB;IAE3D;;;;OAIG;IACH,QAAQ,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI;IAiBpC;;;OAGG;IACH,aAAa,IAAI,IAAI;IAYrB,iFAAiF;IACjF,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED;;;;;OAKG;IACH,OAAO,CAAC,YAAY;CA4ErB"}
1
+ {"version":3,"file":"operation-tool.factory.d.ts","sourceRoot":"","sources":["../../src/tools/operation-tool.factory.ts"],"names":[],"mappings":"AAaA,OAAO,EAAe,KAAK,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AAErF,OAAO,EAIL,KAAK,cAAc,EACnB,KAAK,gBAAgB,EAGrB,KAAK,YAAY,EAClB,MAAM,eAAe,CAAC;AAIvB,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAWpE;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAS/E;AA2BD,MAAM,WAAW,wBAAwB;IACvC,sEAAsE;IACtE,YAAY,EAAE,YAAY,CAAC;IAC3B,8DAA8D;IAC9D,SAAS,EAAE,gBAAgB,CAAC;IAC5B,8BAA8B;IAC9B,MAAM,EAAE,cAAc,CAAC;IACvB;;;;;;;OAOG;IACH,sBAAsB,CAAC,EAAE,sBAAsB,CAAC;CACjD;AAED;;;;;GAKG;AACH,MAAM,WAAW,wBAAwB;IACvC,mEAAmE;IACnE,YAAY,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CACnC;AAED;;;;;GAKG;AACH,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAUD;;;GAGG;AACH,qBAAa,oBAAoB;IAMnB,OAAO,CAAC,QAAQ,CAAC,IAAI;IALjC,kFAAkF;IAClF,OAAO,CAAC,UAAU,CAAwC;IAC1D,2EAA2E;IAC3E,OAAO,CAAC,kBAAkB,CAAqB;gBAElB,IAAI,EAAE,wBAAwB;IAE3D;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,KAAK,EAAE,aAAa,EAAE,GAAG,CAAC,EAAE,wBAAwB,GAAG,IAAI;IA2CpE;;;;OAIG;IACH,aAAa,IAAI,IAAI;IAqBrB,iFAAiF;IACjF,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED;;;;;OAKG;IACH,OAAO,CAAC,YAAY;CA4ErB"}