@frontmcp/plugin-feature-flags 1.8.2 → 1.8.3

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
@@ -297,12 +297,17 @@ var StaticFeatureFlagAdapter = class {
297
297
  };
298
298
 
299
299
  // plugins/plugin-feature-flags/src/feature-flag.context.ts
300
+ import { STATELESS_SESSION_ID } from "@frontmcp/sdk";
301
+ function verifiedSessionId(ctx) {
302
+ const verified = ctx.authInfo?.sessionId ?? ctx.authInfo?.extra?.["sessionId"];
303
+ return typeof verified === "string" && verified.length > 0 && verified !== STATELESS_SESSION_ID ? verified : void 0;
304
+ }
300
305
  function buildFeatureFlagContext(ctx, config) {
301
306
  if (!ctx) return {};
302
307
  const userId = config.userIdResolver ? config.userIdResolver(ctx) : ctx.authInfo?.extra?.["sub"] ?? ctx.authInfo?.extra?.["userId"] ?? ctx.authInfo?.clientId;
303
308
  return {
304
309
  userId: userId ?? void 0,
305
- sessionId: ctx.sessionId,
310
+ sessionId: verifiedSessionId(ctx),
306
311
  attributes: config.attributesResolver ? config.attributesResolver(ctx) : {}
307
312
  };
308
313
  }
@@ -661,21 +666,23 @@ __decorateClass([
661
666
  FilterSkillsHook.Did("filterSkills", { priority: 50 })
662
667
  ], FeatureFlagPlugin.prototype, "filterSkills", 1);
663
668
  __decorateClass([
664
- ToolHook.Will("execute", { priority: 50 })
669
+ ToolHook.Will("execute", { priority: 50, appliesTo: "uncovered-apps" })
665
670
  ], FeatureFlagPlugin.prototype, "gateToolExecution", 1);
666
671
  __decorateClass([
667
- ReadResourceHook.Will("execute", { priority: 50 })
672
+ ReadResourceHook.Will("execute", { priority: 50, appliesTo: "uncovered-apps" })
668
673
  ], FeatureFlagPlugin.prototype, "gateResourceRead", 1);
669
674
  __decorateClass([
670
- GetPromptHook.Will("execute", { priority: 50 })
675
+ GetPromptHook.Will("execute", { priority: 50, appliesTo: "uncovered-apps" })
671
676
  ], FeatureFlagPlugin.prototype, "gatePromptGet", 1);
672
677
  __decorateClass([
673
- CompleteHook.Will("complete", { priority: 50 })
678
+ CompleteHook.Will("complete", { priority: 50, appliesTo: "uncovered-apps" })
674
679
  ], FeatureFlagPlugin.prototype, "gateCompletion", 1);
675
680
  FeatureFlagPlugin = __decorateClass([
676
681
  Plugin({
677
682
  name: "feature-flags",
678
683
  description: "Feature flag-based capability filtering for MCP",
684
+ // A server where an entry declares `featureFlag` and none of these gates reaches it refuses to start.
685
+ enforcesMetadata: ["featureFlag"],
679
686
  providers: [],
680
687
  contextExtensions: [
681
688
  {
package/esm/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@frontmcp/plugin-feature-flags",
3
- "version": "1.8.2",
3
+ "version": "1.8.3",
4
4
  "description": "Feature flag plugin for FrontMCP - dynamically gate MCP capabilities behind feature flags",
5
5
  "author": "AgentFront <info@agentfront.dev>",
6
6
  "license": "Apache-2.0",
@@ -49,7 +49,7 @@
49
49
  }
50
50
  },
51
51
  "dependencies": {
52
- "@frontmcp/sdk": "1.8.2"
52
+ "@frontmcp/sdk": "1.8.3"
53
53
  },
54
54
  "peerDependencies": {
55
55
  "@launchdarkly/node-server-sdk": "^9.0.0 || ^10.0.0",
@@ -1,4 +1,4 @@
1
- import type { FrontMcpContext } from '@frontmcp/sdk';
1
+ import { type FrontMcpContext } from '@frontmcp/sdk';
2
2
  import type { FeatureFlagContext, FeatureFlagPluginOptions } from './feature-flag.types';
3
3
  /**
4
4
  * Build the adapter evaluation context for the current caller.
@@ -1 +1 @@
1
- {"version":3,"file":"feature-flag.context.d.ts","sourceRoot":"","sources":["../src/feature-flag.context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAErD,OAAO,KAAK,EAAE,kBAAkB,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAEzF;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CACrC,GAAG,EAAE,eAAe,GAAG,SAAS,EAChC,MAAM,EAAE,IAAI,CAAC,wBAAwB,EAAE,gBAAgB,GAAG,oBAAoB,CAAC,GAC9E,kBAAkB,CAcpB"}
1
+ {"version":3,"file":"feature-flag.context.d.ts","sourceRoot":"","sources":["../src/feature-flag.context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AAE3E,OAAO,KAAK,EAAE,kBAAkB,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAkBzF;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CACrC,GAAG,EAAE,eAAe,GAAG,SAAS,EAChC,MAAM,EAAE,IAAI,CAAC,wBAAwB,EAAE,gBAAgB,GAAG,oBAAoB,CAAC,GAC9E,kBAAkB,CAcpB"}
@@ -1 +1 @@
1
- {"version":3,"file":"feature-flag.plugin.d.ts","sourceRoot":"","sources":["../src/feature-flag.plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EAUb,KAAK,SAAS,EACd,KAAK,YAAY,EAClB,MAAM,eAAe,CAAC;AAMvB,OAAO,KAAK,EAEV,wBAAwB,EACxB,6BAA6B,EAE9B,MAAM,sBAAsB,CAAC;AAa9B;;;;;;;;;;;;;;;;;;GAkBG;AAaH,MAAM,CAAC,OAAO,OAAO,iBAAkB,SAAQ,aAAa,CAAC,wBAAwB,EAAE,6BAA6B,CAAC;IACnH,OAAO,EAAE,wBAAwB,CAAC;gBAEtB,OAAO,EAAE,6BAA6B;IAKlD;;OAEG;IACH,OAAgB,gBAAgB,GAAI,SAAS,6BAA6B,KAAG,YAAY,EAAE,CA0FzF;IAMF;;;OAGG;IAEG,eAAe,CAAC,OAAO,EAAE,SAAS,CAAC,kBAAkB,CAAC;IAmB5D;;OAEG;IAEG,mBAAmB,CAAC,OAAO,EAAE,SAAS,CAAC,0BAA0B,CAAC;IAmBxE;;;;OAIG;IAEG,2BAA2B,CAAC,OAAO,EAAE,SAAS,CAAC,mCAAmC,CAAC;IAmBzF;;OAEG;IAEG,iBAAiB,CAAC,OAAO,EAAE,GAAG;IAmBpC;;;;;;;;OAQG;IAEG,YAAY,CAAC,OAAO,EAAE,SAAS,CAAC,eAAe,CAAC;IAmBtD;;;OAGG;IAEG,iBAAiB,CAAC,OAAO,EAAE,SAAS,CAAC,iBAAiB,CAAC;IAI7D;;;;;;OAMG;IAEG,gBAAgB,CAAC,OAAO,EAAE,GAAG;IAInC;;;;;OAKG;IAEG,aAAa,CAAC,OAAO,EAAE,GAAG;IAIhC;;;;;OAKG;IAEG,cAAc,CAAC,OAAO,EAAE,GAAG;IAMjC;;;;;OAKG;YACW,kBAAkB;IA+BhC;;OAEG;IACH,OAAO,CAAC,eAAe;IAcvB;;OAEG;YACW,iBAAiB;IAQ/B;;;;;;;OAOG;IACH,OAAO,CAAC,kBAAkB;IAW1B;;;;OAIG;IACH,OAAO,CAAC,YAAY;CAWrB"}
1
+ {"version":3,"file":"feature-flag.plugin.d.ts","sourceRoot":"","sources":["../src/feature-flag.plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EAUb,KAAK,SAAS,EACd,KAAK,YAAY,EAClB,MAAM,eAAe,CAAC;AAMvB,OAAO,KAAK,EAEV,wBAAwB,EACxB,6BAA6B,EAE9B,MAAM,sBAAsB,CAAC;AAa9B;;;;;;;;;;;;;;;;;;GAkBG;AAeH,MAAM,CAAC,OAAO,OAAO,iBAAkB,SAAQ,aAAa,CAAC,wBAAwB,EAAE,6BAA6B,CAAC;IACnH,OAAO,EAAE,wBAAwB,CAAC;gBAEtB,OAAO,EAAE,6BAA6B;IAKlD;;OAEG;IACH,OAAgB,gBAAgB,GAAI,SAAS,6BAA6B,KAAG,YAAY,EAAE,CA0FzF;IAMF;;;OAGG;IAEG,eAAe,CAAC,OAAO,EAAE,SAAS,CAAC,kBAAkB,CAAC;IAmB5D;;OAEG;IAEG,mBAAmB,CAAC,OAAO,EAAE,SAAS,CAAC,0BAA0B,CAAC;IAmBxE;;;;OAIG;IAEG,2BAA2B,CAAC,OAAO,EAAE,SAAS,CAAC,mCAAmC,CAAC;IAmBzF;;OAEG;IAEG,iBAAiB,CAAC,OAAO,EAAE,GAAG;IAmBpC;;;;;;;;OAQG;IAEG,YAAY,CAAC,OAAO,EAAE,SAAS,CAAC,eAAe,CAAC;IAmBtD;;;OAGG;IAEG,iBAAiB,CAAC,OAAO,EAAE,SAAS,CAAC,iBAAiB,CAAC;IAI7D;;;;;;OAMG;IAEG,gBAAgB,CAAC,OAAO,EAAE,GAAG;IAInC;;;;;OAKG;IAEG,aAAa,CAAC,OAAO,EAAE,GAAG;IAIhC;;;;;OAKG;IAEG,cAAc,CAAC,OAAO,EAAE,GAAG;IAMjC;;;;;OAKG;YACW,kBAAkB;IA+BhC;;OAEG;IACH,OAAO,CAAC,eAAe;IAcvB;;OAEG;YACW,iBAAiB;IAQ/B;;;;;;;OAOG;IACH,OAAO,CAAC,kBAAkB;IAW1B;;;;OAIG;IACH,OAAO,CAAC,YAAY;CAWrB"}
package/index.js CHANGED
@@ -255,7 +255,7 @@ __export(index_exports, {
255
255
  module.exports = __toCommonJS(index_exports);
256
256
 
257
257
  // plugins/plugin-feature-flags/src/feature-flag.plugin.ts
258
- var import_sdk2 = require("@frontmcp/sdk");
258
+ var import_sdk3 = require("@frontmcp/sdk");
259
259
 
260
260
  // plugins/plugin-feature-flags/src/adapters/static.adapter.ts
261
261
  var StaticFeatureFlagAdapter = class {
@@ -299,12 +299,17 @@ var StaticFeatureFlagAdapter = class {
299
299
  };
300
300
 
301
301
  // plugins/plugin-feature-flags/src/feature-flag.context.ts
302
+ var import_sdk = require("@frontmcp/sdk");
303
+ function verifiedSessionId(ctx) {
304
+ const verified = ctx.authInfo?.sessionId ?? ctx.authInfo?.extra?.["sessionId"];
305
+ return typeof verified === "string" && verified.length > 0 && verified !== import_sdk.STATELESS_SESSION_ID ? verified : void 0;
306
+ }
302
307
  function buildFeatureFlagContext(ctx, config) {
303
308
  if (!ctx) return {};
304
309
  const userId = config.userIdResolver ? config.userIdResolver(ctx) : ctx.authInfo?.extra?.["sub"] ?? ctx.authInfo?.extra?.["userId"] ?? ctx.authInfo?.clientId;
305
310
  return {
306
311
  userId: userId ?? void 0,
307
- sessionId: ctx.sessionId,
312
+ sessionId: verifiedSessionId(ctx),
308
313
  attributes: config.attributesResolver ? config.attributesResolver(ctx) : {}
309
314
  };
310
315
  }
@@ -321,7 +326,7 @@ var FeatureFlagAccessorToken = /* @__PURE__ */ Symbol(
321
326
  );
322
327
 
323
328
  // plugins/plugin-feature-flags/src/providers/feature-flag-accessor.provider.ts
324
- var import_sdk = require("@frontmcp/sdk");
329
+ var import_sdk2 = require("@frontmcp/sdk");
325
330
  var FeatureFlagAccessor = class {
326
331
  adapter;
327
332
  ctx;
@@ -387,10 +392,10 @@ var FeatureFlagAccessor = class {
387
392
  }
388
393
  };
389
394
  FeatureFlagAccessor = __decorateClass([
390
- (0, import_sdk.Provider)({
395
+ (0, import_sdk2.Provider)({
391
396
  name: "provider:feature-flags:accessor",
392
397
  description: "Context-scoped accessor for feature flag evaluation",
393
- scope: import_sdk.ProviderScope.CONTEXT
398
+ scope: import_sdk2.ProviderScope.CONTEXT
394
399
  })
395
400
  ], FeatureFlagAccessor);
396
401
  function createFeatureFlagAccessor(adapter, ctx, config) {
@@ -398,12 +403,12 @@ function createFeatureFlagAccessor(adapter, ctx, config) {
398
403
  }
399
404
 
400
405
  // plugins/plugin-feature-flags/src/feature-flag.plugin.ts
401
- var ListPromptsHook = (0, import_sdk2.FlowHooksOf)("prompts:list-prompts");
402
- var ReadResourceHook = (0, import_sdk2.FlowHooksOf)("resources:read-resource");
403
- var GetPromptHook = (0, import_sdk2.FlowHooksOf)("prompts:get-prompt");
404
- var CompleteHook = (0, import_sdk2.FlowHooksOf)("completion:complete");
405
- var FilterSkillsHook = (0, import_sdk2.FlowHooksOf)("skills:filter");
406
- var FeatureFlagPlugin = class extends import_sdk2.DynamicPlugin {
406
+ var ListPromptsHook = (0, import_sdk3.FlowHooksOf)("prompts:list-prompts");
407
+ var ReadResourceHook = (0, import_sdk3.FlowHooksOf)("resources:read-resource");
408
+ var GetPromptHook = (0, import_sdk3.FlowHooksOf)("prompts:get-prompt");
409
+ var CompleteHook = (0, import_sdk3.FlowHooksOf)("completion:complete");
410
+ var FilterSkillsHook = (0, import_sdk3.FlowHooksOf)("skills:filter");
411
+ var FeatureFlagPlugin = class extends import_sdk3.DynamicPlugin {
407
412
  options;
408
413
  constructor(options) {
409
414
  super();
@@ -554,7 +559,7 @@ var FeatureFlagPlugin = class extends import_sdk2.DynamicPlugin {
554
559
  */
555
560
  currentFlagContext() {
556
561
  try {
557
- const ctx = this.get(import_sdk2.FrontMcpContextStorage)?.getStore();
562
+ const ctx = this.get(import_sdk3.FrontMcpContextStorage)?.getStore();
558
563
  if (!ctx) return {};
559
564
  return buildFeatureFlagContext(ctx, this.options);
560
565
  } catch {
@@ -641,20 +646,20 @@ __publicField(FeatureFlagPlugin, "dynamicProviders", (options) => {
641
646
  providers.push({
642
647
  name: "feature-flags:accessor",
643
648
  provide: FeatureFlagAccessorToken,
644
- scope: import_sdk2.ProviderScope.CONTEXT,
645
- inject: () => [FeatureFlagAdapterToken, import_sdk2.FRONTMCP_CONTEXT, FeatureFlagConfigToken],
649
+ scope: import_sdk3.ProviderScope.CONTEXT,
650
+ inject: () => [FeatureFlagAdapterToken, import_sdk3.FRONTMCP_CONTEXT, FeatureFlagConfigToken],
646
651
  useFactory: (adapter, ctx, cfg) => createFeatureFlagAccessor(adapter, ctx, cfg)
647
652
  });
648
653
  return providers;
649
654
  });
650
655
  __decorateClass([
651
- import_sdk2.ListToolsHook.Did("findTools", { priority: 50 })
656
+ import_sdk3.ListToolsHook.Did("findTools", { priority: 50 })
652
657
  ], FeatureFlagPlugin.prototype, "filterListTools", 1);
653
658
  __decorateClass([
654
- import_sdk2.ListResourcesHook.Did("findResources", { priority: 50 })
659
+ import_sdk3.ListResourcesHook.Did("findResources", { priority: 50 })
655
660
  ], FeatureFlagPlugin.prototype, "filterListResources", 1);
656
661
  __decorateClass([
657
- import_sdk2.ListResourceTemplatesHook.Did("findTemplates", { priority: 50 })
662
+ import_sdk3.ListResourceTemplatesHook.Did("findTemplates", { priority: 50 })
658
663
  ], FeatureFlagPlugin.prototype, "filterListResourceTemplates", 1);
659
664
  __decorateClass([
660
665
  ListPromptsHook.Did("findPrompts", { priority: 50 })
@@ -663,21 +668,23 @@ __decorateClass([
663
668
  FilterSkillsHook.Did("filterSkills", { priority: 50 })
664
669
  ], FeatureFlagPlugin.prototype, "filterSkills", 1);
665
670
  __decorateClass([
666
- import_sdk2.ToolHook.Will("execute", { priority: 50 })
671
+ import_sdk3.ToolHook.Will("execute", { priority: 50, appliesTo: "uncovered-apps" })
667
672
  ], FeatureFlagPlugin.prototype, "gateToolExecution", 1);
668
673
  __decorateClass([
669
- ReadResourceHook.Will("execute", { priority: 50 })
674
+ ReadResourceHook.Will("execute", { priority: 50, appliesTo: "uncovered-apps" })
670
675
  ], FeatureFlagPlugin.prototype, "gateResourceRead", 1);
671
676
  __decorateClass([
672
- GetPromptHook.Will("execute", { priority: 50 })
677
+ GetPromptHook.Will("execute", { priority: 50, appliesTo: "uncovered-apps" })
673
678
  ], FeatureFlagPlugin.prototype, "gatePromptGet", 1);
674
679
  __decorateClass([
675
- CompleteHook.Will("complete", { priority: 50 })
680
+ CompleteHook.Will("complete", { priority: 50, appliesTo: "uncovered-apps" })
676
681
  ], FeatureFlagPlugin.prototype, "gateCompletion", 1);
677
682
  FeatureFlagPlugin = __decorateClass([
678
- (0, import_sdk2.Plugin)({
683
+ (0, import_sdk3.Plugin)({
679
684
  name: "feature-flags",
680
685
  description: "Feature flag-based capability filtering for MCP",
686
+ // A server where an entry declares `featureFlag` and none of these gates reaches it refuses to start.
687
+ enforcesMetadata: ["featureFlag"],
681
688
  providers: [],
682
689
  contextExtensions: [
683
690
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@frontmcp/plugin-feature-flags",
3
- "version": "1.8.2",
3
+ "version": "1.8.3",
4
4
  "description": "Feature flag plugin for FrontMCP - dynamically gate MCP capabilities behind feature flags",
5
5
  "author": "AgentFront <info@agentfront.dev>",
6
6
  "license": "Apache-2.0",
@@ -49,7 +49,7 @@
49
49
  }
50
50
  },
51
51
  "dependencies": {
52
- "@frontmcp/sdk": "1.8.2"
52
+ "@frontmcp/sdk": "1.8.3"
53
53
  },
54
54
  "peerDependencies": {
55
55
  "@launchdarkly/node-server-sdk": "^9.0.0 || ^10.0.0",