@frontmcp/plugin-feature-flags 0.0.1

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.
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Context Extension Types for FeatureFlagPlugin
3
+ *
4
+ * Declares TypeScript types for `this.featureFlags` property
5
+ * on ExecutionContextBase (ToolContext, AgentContext, etc.).
6
+ *
7
+ * The SDK handles the runtime installation via `contextExtensions` in plugin metadata.
8
+ * This file only provides TypeScript type augmentation.
9
+ */
10
+ import type { FeatureFlagAccessor } from './providers/feature-flag-accessor.provider';
11
+ declare module '@frontmcp/sdk' {
12
+ interface ExecutionContextBase {
13
+ /**
14
+ * Access the feature flag accessor for evaluating flags.
15
+ * Only available when FeatureFlagPlugin is installed.
16
+ *
17
+ * @throws Error if FeatureFlagPlugin is not installed
18
+ */
19
+ readonly featureFlags: FeatureFlagAccessor;
20
+ }
21
+ interface PromptContext {
22
+ /**
23
+ * Access the feature flag accessor for evaluating flags.
24
+ * Only available when FeatureFlagPlugin is installed.
25
+ */
26
+ readonly featureFlags: FeatureFlagAccessor;
27
+ }
28
+ }
29
+ /**
30
+ * Get the FeatureFlagAccessor from an execution context.
31
+ * Alternative to `this.featureFlags` for explicit function-style access.
32
+ *
33
+ * @throws Error if FeatureFlagPlugin is not installed
34
+ */
35
+ export declare function getFeatureFlags<T extends {
36
+ get: (token: unknown) => unknown;
37
+ }>(ctx: T): FeatureFlagAccessor;
38
+ /**
39
+ * Try to get the FeatureFlagAccessor, returning undefined if not available.
40
+ * Use this for graceful degradation when the plugin might not be installed.
41
+ */
42
+ export declare function tryGetFeatureFlags<T extends {
43
+ tryGet?: (token: unknown) => unknown;
44
+ }>(ctx: T): FeatureFlagAccessor | undefined;
45
+ //# sourceMappingURL=feature-flag.context-extension.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feature-flag.context-extension.d.ts","sourceRoot":"","sources":["../src/feature-flag.context-extension.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,4CAA4C,CAAC;AAOtF,OAAO,QAAQ,eAAe,CAAC;IAC7B,UAAU,oBAAoB;QAC5B;;;;;WAKG;QACH,QAAQ,CAAC,YAAY,EAAE,mBAAmB,CAAC;KAC5C;IAGD,UAAU,aAAa;QACrB;;;WAGG;QACH,QAAQ,CAAC,YAAY,EAAE,mBAAmB,CAAC;KAC5C;CACF;AAMD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS;IAAE,GAAG,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAA;CAAE,EAAE,GAAG,EAAE,CAAC,GAAG,mBAAmB,CAE3G;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS;IAAE,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAA;CAAE,EACnF,GAAG,EAAE,CAAC,GACL,mBAAmB,GAAG,SAAS,CAKjC"}
@@ -0,0 +1,67 @@
1
+ import { DynamicPlugin, FlowCtxOf, ProviderType } from '@frontmcp/sdk';
2
+ import type { FeatureFlagPluginOptions, FeatureFlagPluginOptionsInput } from './feature-flag.types';
3
+ /**
4
+ * FeatureFlagPlugin - Dynamic capability gating for FrontMCP.
5
+ *
6
+ * Filters tools, resources, prompts, and skills based on feature flag evaluation.
7
+ * Supports static flags, Split.io, LaunchDarkly, Unleash, and custom adapters.
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * @FrontMcp({
12
+ * plugins: [
13
+ * FeatureFlagPlugin.init({
14
+ * adapter: 'static',
15
+ * flags: { 'beta-tools': true, 'experimental-agent': false },
16
+ * }),
17
+ * ],
18
+ * })
19
+ * class MyServer {}
20
+ * ```
21
+ */
22
+ export default class FeatureFlagPlugin extends DynamicPlugin<FeatureFlagPluginOptions, FeatureFlagPluginOptionsInput> {
23
+ options: FeatureFlagPluginOptions;
24
+ constructor(options: FeatureFlagPluginOptionsInput);
25
+ /**
26
+ * Dynamic providers based on plugin options.
27
+ */
28
+ static dynamicProviders: (options: FeatureFlagPluginOptionsInput) => ProviderType[];
29
+ /**
30
+ * Filter tools from list_tools based on feature flags.
31
+ * Runs after findTools but before resolveConflicts for fewer conflicts.
32
+ */
33
+ filterListTools(flowCtx: FlowCtxOf<'tools:list-tools'>): Promise<void>;
34
+ /**
35
+ * Filter resources from list_resources based on feature flags.
36
+ */
37
+ filterListResources(flowCtx: FlowCtxOf<'resources:list-resources'>): Promise<void>;
38
+ /**
39
+ * Filter prompts from list_prompts based on feature flags.
40
+ */
41
+ filterListPrompts(flowCtx: any): Promise<void>;
42
+ /**
43
+ * Filter skills from skills:search based on feature flags.
44
+ * Hooks after search stage, before finalize converts to output.
45
+ */
46
+ filterSearchSkills(flowCtx: any): Promise<void>;
47
+ /**
48
+ * Execution gate: block direct tool/call when the tool's feature flag is off.
49
+ * This prevents bypassing the list filter via direct tool invocation.
50
+ */
51
+ gateToolExecution(flowCtx: FlowCtxOf<'tools:call-tool'>): Promise<void>;
52
+ /**
53
+ * Collect unique flag keys from items that have a featureFlag metadata.
54
+ */
55
+ private collectFlagRefs;
56
+ /**
57
+ * Batch evaluate all collected flag refs via the adapter.
58
+ */
59
+ private batchEvaluateRefs;
60
+ /**
61
+ * Determine if a feature flag ref is enabled given adapter results.
62
+ * For object-style refs, `defaultValue` acts as a fallback when the adapter
63
+ * returns false (i.e., the flag is unknown to the adapter).
64
+ */
65
+ private isRefEnabled;
66
+ }
67
+ //# sourceMappingURL=feature-flag.plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feature-flag.plugin.d.ts","sourceRoot":"","sources":["../src/feature-flag.plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,SAAS,EAOT,YAAY,EAEb,MAAM,eAAe,CAAC;AAEvB,OAAO,KAAK,EAAE,wBAAwB,EAAE,6BAA6B,EAAkB,MAAM,sBAAsB,CAAC;AAYpH;;;;;;;;;;;;;;;;;;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;;OAEG;IAEG,iBAAiB,CAAC,OAAO,EAAE,GAAG;IAmBpC;;;OAGG;IAEG,kBAAkB,CAAC,OAAO,EAAE,GAAG;IAmBrC;;;OAGG;IAEG,iBAAiB,CAAC,OAAO,EAAE,SAAS,CAAC,iBAAiB,CAAC;IA2B7D;;OAEG;IACH,OAAO,CAAC,eAAe;IAcvB;;OAEG;YACW,iBAAiB;IAQ/B;;;;OAIG;IACH,OAAO,CAAC,YAAY;CAOrB"}
@@ -0,0 +1,17 @@
1
+ import { Reference } from '@frontmcp/sdk';
2
+ import type { FeatureFlagAdapter } from './adapters/feature-flag-adapter.interface';
3
+ import type { FeatureFlagAccessor } from './providers/feature-flag-accessor.provider';
4
+ import type { FeatureFlagPluginOptions } from './feature-flag.types';
5
+ /**
6
+ * DI token for the feature flag adapter.
7
+ */
8
+ export declare const FeatureFlagAdapterToken: Reference<FeatureFlagAdapter>;
9
+ /**
10
+ * DI token for the plugin configuration.
11
+ */
12
+ export declare const FeatureFlagConfigToken: Reference<FeatureFlagPluginOptions>;
13
+ /**
14
+ * DI token for the context-scoped FeatureFlagAccessor.
15
+ */
16
+ export declare const FeatureFlagAccessorToken: Reference<FeatureFlagAccessor>;
17
+ //# sourceMappingURL=feature-flag.symbols.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feature-flag.symbols.d.ts","sourceRoot":"","sources":["../src/feature-flag.symbols.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2CAA2C,CAAC;AACpF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,4CAA4C,CAAC;AACtF,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAErE;;GAEG;AACH,eAAO,MAAM,uBAAuB,EAAE,SAAS,CAAC,kBAAkB,CAEhC,CAAC;AAEnC;;GAEG;AACH,eAAO,MAAM,sBAAsB,EAAE,SAAS,CAAC,wBAAwB,CAE/B,CAAC;AAEzC;;GAEG;AACH,eAAO,MAAM,wBAAwB,EAAE,SAAS,CAAC,mBAAmB,CAEjC,CAAC"}
@@ -0,0 +1,88 @@
1
+ import type { FrontMcpContext } from '@frontmcp/sdk';
2
+ /** Context passed to feature flag adapters for per-user/session evaluation. */
3
+ export interface FeatureFlagContext {
4
+ userId?: string;
5
+ sessionId?: string;
6
+ attributes?: Record<string, unknown>;
7
+ }
8
+ /** Variant result from multi-variate feature flags. */
9
+ export interface FeatureFlagVariant {
10
+ name: string;
11
+ value: unknown;
12
+ enabled: boolean;
13
+ }
14
+ /**
15
+ * Metadata field type for annotating tools/resources/prompts/skills.
16
+ * Can be a simple flag key string or an object with default value.
17
+ */
18
+ export type FeatureFlagRef = string | {
19
+ key: string;
20
+ defaultValue?: boolean;
21
+ };
22
+ /** Cache strategy for feature flag evaluations. */
23
+ export type FeatureFlagCacheStrategy = 'session' | 'request' | 'none';
24
+ /** Resolver function for extracting user ID from context. */
25
+ export type UserIdResolver = (ctx: FrontMcpContext) => string | undefined;
26
+ /** Resolver function for extracting attributes from context. */
27
+ export type AttributesResolver = (ctx: FrontMcpContext) => Record<string, unknown>;
28
+ /** Shared base options for all adapter configurations. */
29
+ interface FeatureFlagBaseOptions {
30
+ defaultValue?: boolean;
31
+ cacheStrategy?: FeatureFlagCacheStrategy;
32
+ cacheTtlMs?: number;
33
+ userIdResolver?: UserIdResolver;
34
+ attributesResolver?: AttributesResolver;
35
+ }
36
+ /** Static/in-memory flags (no external dependency). */
37
+ export interface StaticFeatureFlagPluginOptions extends FeatureFlagBaseOptions {
38
+ adapter: 'static';
39
+ flags: Record<string, boolean | FeatureFlagVariant>;
40
+ }
41
+ /** Split.io adapter options. */
42
+ export interface SplitioFeatureFlagPluginOptions extends FeatureFlagBaseOptions {
43
+ adapter: 'splitio';
44
+ config: {
45
+ apiKey: string;
46
+ };
47
+ }
48
+ /** LaunchDarkly adapter options. */
49
+ export interface LaunchDarklyFeatureFlagPluginOptions extends FeatureFlagBaseOptions {
50
+ adapter: 'launchdarkly';
51
+ config: {
52
+ sdkKey: string;
53
+ };
54
+ }
55
+ /** Unleash adapter options. */
56
+ export interface UnleashFeatureFlagPluginOptions extends FeatureFlagBaseOptions {
57
+ adapter: 'unleash';
58
+ config: {
59
+ url: string;
60
+ appName: string;
61
+ apiKey?: string;
62
+ };
63
+ }
64
+ /** Custom adapter (user provides their own implementation). */
65
+ export interface CustomFeatureFlagPluginOptions extends FeatureFlagBaseOptions {
66
+ adapter: 'custom';
67
+ adapterInstance: import('./adapters/feature-flag-adapter.interface').FeatureFlagAdapter;
68
+ }
69
+ /** Union of all plugin option types. */
70
+ export type FeatureFlagPluginOptions = StaticFeatureFlagPluginOptions | SplitioFeatureFlagPluginOptions | LaunchDarklyFeatureFlagPluginOptions | UnleashFeatureFlagPluginOptions | CustomFeatureFlagPluginOptions;
71
+ /** Input type (same as options for this plugin). */
72
+ export type FeatureFlagPluginOptionsInput = FeatureFlagPluginOptions;
73
+ declare global {
74
+ interface ExtendFrontMcpToolMetadata {
75
+ featureFlag?: FeatureFlagRef;
76
+ }
77
+ interface ExtendFrontMcpResourceMetadata {
78
+ featureFlag?: FeatureFlagRef;
79
+ }
80
+ interface ExtendFrontMcpPromptMetadata {
81
+ featureFlag?: FeatureFlagRef;
82
+ }
83
+ interface ExtendFrontMcpSkillMetadata {
84
+ featureFlag?: FeatureFlagRef;
85
+ }
86
+ }
87
+ export {};
88
+ //# sourceMappingURL=feature-flag.types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feature-flag.types.d.ts","sourceRoot":"","sources":["../src/feature-flag.types.ts"],"names":[],"mappings":"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"}
package/index.d.ts ADDED
@@ -0,0 +1,34 @@
1
+ /**
2
+ * FeatureFlagPlugin - Dynamic capability gating for FrontMCP
3
+ *
4
+ * Filters tools, resources, prompts, and skills based on feature flag evaluation.
5
+ * Supports static flags, Split.io, LaunchDarkly, Unleash, and custom adapters.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import { FeatureFlagPlugin } from '@frontmcp/plugin-feature-flags';
10
+ *
11
+ * @FrontMcp({
12
+ * plugins: [
13
+ * FeatureFlagPlugin.init({
14
+ * adapter: 'static',
15
+ * flags: { 'beta-tools': true, 'experimental-agent': false },
16
+ * }),
17
+ * ],
18
+ * })
19
+ * class MyServer {}
20
+ * ```
21
+ *
22
+ * @packageDocumentation
23
+ */
24
+ export { default, default as FeatureFlagPlugin } from './feature-flag.plugin';
25
+ export { FeatureFlagAdapterToken, FeatureFlagConfigToken, FeatureFlagAccessorToken } from './feature-flag.symbols';
26
+ export type { FeatureFlagContext, FeatureFlagVariant, FeatureFlagRef, FeatureFlagCacheStrategy, UserIdResolver, AttributesResolver, FeatureFlagPluginOptions, FeatureFlagPluginOptionsInput, StaticFeatureFlagPluginOptions, SplitioFeatureFlagPluginOptions, LaunchDarklyFeatureFlagPluginOptions, UnleashFeatureFlagPluginOptions, CustomFeatureFlagPluginOptions, } from './feature-flag.types';
27
+ export type { FeatureFlagAdapter } from './adapters';
28
+ export { StaticFeatureFlagAdapter } from './adapters/static.adapter';
29
+ export { SplitioFeatureFlagAdapter } from './adapters/splitio.adapter';
30
+ export { LaunchDarklyFeatureFlagAdapter } from './adapters/launchdarkly.adapter';
31
+ export { UnleashFeatureFlagAdapter } from './adapters/unleash.adapter';
32
+ export { FeatureFlagAccessor } from './providers/feature-flag-accessor.provider';
33
+ export { getFeatureFlags, tryGetFeatureFlags } from './feature-flag.context-extension';
34
+ //# sourceMappingURL=index.d.ts.map
package/index.d.ts.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAGH,OAAO,EAAE,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAG9E,OAAO,EAAE,uBAAuB,EAAE,sBAAsB,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAGnH,YAAY,EACV,kBAAkB,EAClB,kBAAkB,EAClB,cAAc,EACd,wBAAwB,EACxB,cAAc,EACd,kBAAkB,EAClB,wBAAwB,EACxB,6BAA6B,EAC7B,8BAA8B,EAC9B,+BAA+B,EAC/B,oCAAoC,EACpC,+BAA+B,EAC/B,8BAA8B,GAC/B,MAAM,sBAAsB,CAAC;AAG9B,YAAY,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AACrE,OAAO,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AACvE,OAAO,EAAE,8BAA8B,EAAE,MAAM,iCAAiC,CAAC;AACjF,OAAO,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AAGvE,OAAO,EAAE,mBAAmB,EAAE,MAAM,4CAA4C,CAAC;AAKjF,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC"}