@frontmcp/plugin-feature-flags 1.8.1 → 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 +12 -5
- package/esm/package.json +2 -2
- package/feature-flag.context.d.ts +1 -1
- package/feature-flag.context.d.ts.map +1 -1
- package/feature-flag.plugin.d.ts.map +1 -1
- package/index.js +29 -22
- package/package.json +2 -2
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
|
|
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.
|
|
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.
|
|
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
|
|
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,
|
|
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;
|
|
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
|
|
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
|
|
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
|
|
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,
|
|
395
|
+
(0, import_sdk2.Provider)({
|
|
391
396
|
name: "provider:feature-flags:accessor",
|
|
392
397
|
description: "Context-scoped accessor for feature flag evaluation",
|
|
393
|
-
scope:
|
|
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,
|
|
402
|
-
var ReadResourceHook = (0,
|
|
403
|
-
var GetPromptHook = (0,
|
|
404
|
-
var CompleteHook = (0,
|
|
405
|
-
var FilterSkillsHook = (0,
|
|
406
|
-
var FeatureFlagPlugin = class extends
|
|
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(
|
|
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:
|
|
645
|
-
inject: () => [FeatureFlagAdapterToken,
|
|
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
|
-
|
|
656
|
+
import_sdk3.ListToolsHook.Did("findTools", { priority: 50 })
|
|
652
657
|
], FeatureFlagPlugin.prototype, "filterListTools", 1);
|
|
653
658
|
__decorateClass([
|
|
654
|
-
|
|
659
|
+
import_sdk3.ListResourcesHook.Did("findResources", { priority: 50 })
|
|
655
660
|
], FeatureFlagPlugin.prototype, "filterListResources", 1);
|
|
656
661
|
__decorateClass([
|
|
657
|
-
|
|
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
|
-
|
|
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,
|
|
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.
|
|
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.
|
|
52
|
+
"@frontmcp/sdk": "1.8.3"
|
|
53
53
|
},
|
|
54
54
|
"peerDependencies": {
|
|
55
55
|
"@launchdarkly/node-server-sdk": "^9.0.0 || ^10.0.0",
|