Skip to main content
Glama
growthbook

GrowthBook MCP Server

Official
by growthbook

create_feature_flag

Generate and manage feature flags using a defined schema in the GrowthBook MCP Server. Specify ID, value type, default value, and file extension to create flags for controlled feature rollouts.

Instructions

Create, add, or wrap an element with a feature flag.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
archivedNoWhether the feature flag is archived
defaultValueYesThe default value of the feature flag
descriptionNoA description of the feature flag
fileExtensionYesThe extension of the current file. If it's unclear, ask the user.
idYesA unique key name for the feature
projectNoThe project the feature flag belongs to
tagsNoTags for the feature flag
valueTypeYesThe value type the feature flag will return

Implementation Reference

  • The handler function that executes the create_feature_flag tool: fetches environments, constructs payload, posts to GrowthBook API, handles response, and returns formatted content with links and code stubs.
    async ({
      id,
      valueType,
      defaultValue,
      description,
      project,
      fileExtension,
    }) => {
      // get environments
      let environments = [];
      const defaults = await getDefaults(apiKey, baseApiUrl);
      if (defaults.environments) {
        environments = defaults.environments;
      } else {
        const envRes = await fetch(
          `${baseApiUrl}/api/v1/features/environments`,
          {
            headers: {
              Authorization: `Bearer ${apiKey}`,
              "Content-Type": "application/json",
            },
          }
        );
        await handleResNotOk(envRes);
        const envData = await envRes.json();
        environments = envData.environments.map((env: any) => env.id);
      }
    
      const payload = {
        id,
        description,
        owner: user,
        valueType,
        defaultValue,
        tags: ["mcp"],
        environments: environments.reduce(
          (acc: Record<string, any>, env: string) => {
            acc[env] = {
              enabled: false,
              rules: [],
            };
            return acc;
          },
          {}
        ),
        ...(project && { project }),
      };
    
      try {
        const res = await fetch(`${baseApiUrl}/api/v1/features`, {
          method: "POST",
          headers: {
            Authorization: `Bearer ${apiKey}`,
            "Content-Type": "application/json",
          },
          body: JSON.stringify(payload),
        });
    
        await handleResNotOk(res);
    
        const data = await res.json();
        const { docs, language, stub } = getDocsMetadata(fileExtension);
        const linkToGrowthBook = generateLinkToGrowthBook(
          appOrigin,
          "features",
          id
        );
        const text = `This is the API response: ${JSON.stringify(data, null, 2)}
    
        Additionally, here is a template of what to show to the user:
    
        **✅ Your feature flag \`my-flag-name\` is ready!**
        [View it in GrowthBook](${linkToGrowthBook})
    
        **How to use it in your code:**
        (To the LLM agent. Use the text below to properly add the feature flag to the codebase. Also, surface the relevant docs/implemenation to the user)
    
        ${stub}
    
        **Want to learn more?**
        See the [GrowthBook ${language} docs](${docs})
      `;
    
        return {
          content: [{ type: "text", text }],
        };
      } catch (error) {
        throw new Error(`Error creating feature flag: ${error}`);
      }
    }
  • Registers the create_feature_flag tool on the MCP server within registerFeatureTools, specifying name, description, input schema, hints, and handler function.
    /**
     * Tool: create_feature_flag
     */
    server.tool(
      "create_feature_flag",
      "Creates a new feature flag in GrowthBook and modifies the codebase when relevant.",
      {
        id: featureFlagSchema.id,
        valueType: featureFlagSchema.valueType,
        defaultValue: featureFlagSchema.defaultValue,
        description: featureFlagSchema.description.optional().default(""),
        project: featureFlagSchema.project.optional(),
        fileExtension: featureFlagSchema.fileExtension,
      },
      {
        readOnlyHint: false,
        destructiveHint: false,
      },
      async ({
        id,
        valueType,
        defaultValue,
        description,
        project,
        fileExtension,
      }) => {
        // get environments
        let environments = [];
        const defaults = await getDefaults(apiKey, baseApiUrl);
        if (defaults.environments) {
          environments = defaults.environments;
        } else {
          const envRes = await fetch(
            `${baseApiUrl}/api/v1/features/environments`,
            {
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Content-Type": "application/json",
              },
            }
          );
          await handleResNotOk(envRes);
          const envData = await envRes.json();
          environments = envData.environments.map((env: any) => env.id);
        }
    
        const payload = {
          id,
          description,
          owner: user,
          valueType,
          defaultValue,
          tags: ["mcp"],
          environments: environments.reduce(
            (acc: Record<string, any>, env: string) => {
              acc[env] = {
                enabled: false,
                rules: [],
              };
              return acc;
            },
            {}
          ),
          ...(project && { project }),
        };
    
        try {
          const res = await fetch(`${baseApiUrl}/api/v1/features`, {
            method: "POST",
            headers: {
              Authorization: `Bearer ${apiKey}`,
              "Content-Type": "application/json",
            },
            body: JSON.stringify(payload),
          });
    
          await handleResNotOk(res);
    
          const data = await res.json();
          const { docs, language, stub } = getDocsMetadata(fileExtension);
          const linkToGrowthBook = generateLinkToGrowthBook(
            appOrigin,
            "features",
            id
          );
          const text = `This is the API response: ${JSON.stringify(data, null, 2)}
    
          Additionally, here is a template of what to show to the user:
    
          **✅ Your feature flag \`my-flag-name\` is ready!**
          [View it in GrowthBook](${linkToGrowthBook})
    
          **How to use it in your code:**
          (To the LLM agent. Use the text below to properly add the feature flag to the codebase. Also, surface the relevant docs/implemenation to the user)
    
          ${stub}
    
          **Want to learn more?**
          See the [GrowthBook ${language} docs](${docs})
        `;
    
          return {
            content: [{ type: "text", text }],
          };
        } catch (error) {
          throw new Error(`Error creating feature flag: ${error}`);
        }
      }
    );
  • Shared Zod schema object defining input parameters for feature flag tools, including id, valueType, defaultValue, etc.
    export const featureFlagSchema = {
      id: z
        .string()
        .regex(
          /^[a-zA-Z0-9_.:|_-]+$/,
          "Feature key can only include letters, numbers, and the characters _, -, ., :, and |"
        )
        .describe("A unique key name for the feature"),
      valueType: z
        .enum(["string", "number", "boolean", "json"])
        .describe("The value type the feature flag will return"),
      defaultValue: z.string().describe("The default value of the feature flag"),
      description: z.string().describe("A brief description of the feature flag"),
      archived: z.boolean().describe("Whether the feature flag should be archived"),
      project: z
        .string()
        .describe("The ID of the project to which the feature flag belongs"),
      // Contextual info
      fileExtension: z
        .enum(SUPPORTED_FILE_EXTENSIONS)
        .describe(
          "The extension of the current file. If it's unclear, ask the user."
        ),
    } as const;
  • src/index.ts:81-87 (registration)
    Top-level call to registerFeatureTools in the main MCP server initialization, which includes the create_feature_flag tool.
    registerFeatureTools({
      server,
      baseApiUrl,
      apiKey,
      appOrigin,
      user,
    });
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden of behavioral disclosure. The description states it's for creation/adding/wrapping, implying a write operation, but doesn't specify what happens after creation (e.g., where the flag is stored, whether it's immediately active, if it requires permissions, or what the response looks like). For a tool with 8 parameters and no annotations, this leaves significant gaps in understanding the tool's behavior and effects.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, compact sentence with no wasted words. However, the use of multiple verbs ('Create, add, or wrap') slightly reduces clarity without adding value, and it could be more front-loaded with a clearer primary action. Overall, it's efficient but not perfectly structured.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (8 parameters, 4 required, no output schema, and no annotations), the description is inadequate. It doesn't explain the outcome of the creation (e.g., what is returned, where the flag is stored), doesn't differentiate from siblings, and provides minimal behavioral context. For a creation tool with significant parameters, this leaves too many gaps for effective agent use.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, meaning all parameters are documented in the schema itself (e.g., 'id' as a unique key name, 'fileExtension' with specific enum values). The description adds no additional meaning about parameters beyond what's in the schema—it doesn't explain how parameters relate to each other or provide usage context. With high schema coverage, the baseline is 3 even without param info in the description.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose3/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description 'Create, add, or wrap an element with a feature flag' uses multiple verbs (create, add, wrap) which creates ambiguity about the exact action. It mentions 'feature flag' as the resource but doesn't specify what kind of element is being wrapped or where this creation happens (e.g., in code, in a configuration system). Compared to siblings like 'create_force_rule' or 'create_sdk_connection', it's not clearly differentiated beyond the general domain of feature flags.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to use this tool versus alternatives. There are sibling tools like 'generate_flag_types', 'get_feature_flags', and 'get_single_feature_flag' that might be related, but the description doesn't indicate whether this is for initial creation versus updates, or when to use it versus other creation tools. No prerequisites or exclusions are mentioned.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Related Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/growthbook/growthbook-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server