Skip to main content
Glama

build-toolset

Create and customize a personalized toolset by selecting specific tools for your workflow. Define names and include tools by their identifiers to streamline tasks and improve efficiency on the hypertool-mcp server.

Instructions

Build and save a custom toolset by selecting specific tools. Like assembling tools from a workshop - pick the exact tools you need for a specific task or workflow. You must specify which tools to include. Each tool must specify either namespacedName or refId for identification. Example: {name: 'dev-essentials', tools: [{namespacedName: 'git.status'}, {namespacedName: 'docker.ps'}], autoEquip: true} creates and immediately equips a development toolset.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
autoEquipNoAutomatically equip this toolset after creation (default: false)
descriptionNoOptional description of what this toolset is for (e.g., 'Essential tools for web development')
nameYesName for the new toolset. Use lowercase with hyphens (e.g., 'dev-essentials', 'git-workflow', 'debug-kit')
toolsYesArray of tools to include in the toolset. Each tool must specify either namespacedName or refId for identification. Use list-available-tools to see available options.

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
metaYesOperation metadata
toolsetNoToolset information (only present if successful)

Implementation Reference

  • The main handler function for the 'build-toolset' MCP tool. It receives input arguments, calls toolsetManager.buildToolset to perform the actual creation, handles auto-equip, and returns the result.
    handler: async (args: any) => {
      if (deps.discoveryEngine) {
        const result = await deps.toolsetManager.buildToolset(
          args?.name || "",
          args?.tools || [],
          {
            description: args?.description,
            autoEquip: args?.autoEquip,
          }
        );
    
        // Auto-exit to normal mode if autoEquip succeeded
        if (args?.autoEquip && result.meta?.success && onModeChangeRequest) {
          onModeChangeRequest();
        }
    
        return {
          content: [
            {
              type: "text",
              text: JSON.stringify(result),
            },
          ],
          structuredContent: result,
        };
      } else {
        return {
          content: [
            {
              type: "text",
              text: "❌ **Tool discovery not available**\n\nDiscovery engine is not initialized. Server may not be fully started.",
            },
          ],
        };
      }
  • Tool definition including input schema for validation and output schema reference. Defines the structure expected for input parameters like name, tools array, description, and autoEquip.
    export const buildToolsetDefinition: Tool = {
      name: "build-toolset",
      description:
        "Build and save a custom toolset by selecting specific tools. Like assembling tools from a workshop - pick the exact tools you need for a specific task or workflow. You must specify which tools to include. Each tool must specify either namespacedName or refId for identification. Example: {name: 'dev-essentials', tools: [{namespacedName: 'git.status'}, {namespacedName: 'docker.ps'}], autoEquip: true} creates and immediately equips a development toolset.",
      inputSchema: {
        type: "object" as const,
        properties: {
          name: {
            type: "string",
            description:
              "Name for the new toolset. Use lowercase with hyphens (e.g., 'dev-essentials', 'git-workflow', 'debug-kit')",
            pattern: "^[a-z0-9-]+$",
            minLength: 2,
            maxLength: 50,
          },
          tools: {
            type: "array",
            description:
              "Array of tools to include in the toolset. Each tool must specify either namespacedName or refId for identification. Use list-available-tools to see available options.",
            minItems: 1,
            maxItems: 100,
            items: {
              type: "object",
              properties: {
                namespacedName: {
                  type: "string",
                  description:
                    "Tool reference by namespaced name (e.g., 'git.status', 'docker.ps')",
                },
                refId: {
                  type: "string",
                  description:
                    "Tool reference by unique hash identifier (e.g., 'abc123def456...')",
                },
              },
              oneOf: [{ required: ["namespacedName"] }, { required: ["refId"] }],
              additionalProperties: false,
            },
          },
          description: {
            type: "string",
            description:
              "Optional description of what this toolset is for (e.g., 'Essential tools for web development')",
            maxLength: 200,
          },
          autoEquip: {
            type: "boolean",
            description:
              "Automatically equip this toolset after creation (default: false)",
          },
        },
        required: ["name", "tools"],
        additionalProperties: false,
      },
      outputSchema: buildToolsetResponseSchema as any,
    };
  • Zod schema and JSON schema for the build-toolset response, defining the output structure including meta (success, error) and toolset info.
    export const buildToolsetResponseZodSchema = z.object({
      meta: z
        .object({
          success: z
            .boolean()
            .describe("Whether the toolset was successfully created"),
          toolsetName: z
            .string()
            .optional()
            .describe("Name of the created toolset"),
          autoEquipped: z
            .boolean()
            .optional()
            .describe(
              "Whether the toolset was automatically equipped after creation"
            ),
          error: z
            .string()
            .optional()
            .describe("Error message if the operation failed"),
        })
        .describe("Operation metadata"),
      toolset: toolsetInfoZodSchema
        .optional()
        .describe("Toolset information (only present if successful)"),
    });
    
    /**
     * Zod schema for equip toolset response
     */
    export const equipToolsetResponseZodSchema = z.object({
      success: z
        .boolean()
        .describe("Whether the toolset was successfully equipped"),
      error: z
        .string()
        .optional()
        .describe("Error message if the operation failed"),
      toolset: toolsetInfoZodSchema
        .optional()
        .describe("Equipped toolset information (only present if successful)"),
    });
    
    /**
     * Zod schema for get active toolset response
     */
    export const getActiveToolsetResponseZodSchema = z.object({
      equipped: z.boolean().describe("Whether a toolset is currently equipped"),
      toolset: toolsetInfoZodSchema
        .optional()
        .describe("Toolset information (only present if equipped)"),
      serverStatus: z
        .object({
          totalConfigured: z
            .number()
            .describe("Total number of configured servers"),
          enabled: z.number().describe("Number of enabled servers"),
          available: z.number().describe("Number of available servers"),
          unavailable: z.number().describe("Number of unavailable servers"),
          disabled: z.number().describe("Number of disabled servers"),
        })
        .optional()
        .describe("Server status summary"),
      toolSummary: z
        .object({
          currentlyExposed: z
            .number()
            .describe("Number of tools currently exposed"),
          totalDiscovered: z.number().describe("Total number of discovered tools"),
          filteredOut: z.number().describe("Number of tools filtered out"),
        })
        .optional()
        .describe("Tool summary information"),
      exposedTools: z
        .record(z.array(toolInfoResponseZodSchema))
        .describe("Tools grouped by server with full details"),
      unavailableServers: z
        .array(z.string())
        .describe("List of unavailable server names"),
      warnings: z.array(z.string()).describe("List of warnings"),
      context: contextInfoZodSchema
        .optional()
        .describe("Context usage information for the exposed tools"),
    });
    
    /**
     * TypeScript types inferred from Zod schemas
     */
    export type ContextInfo = z.infer<typeof contextInfoZodSchema>;
    export type ToolInfoResponse = z.infer<typeof toolInfoResponseZodSchema>;
    export type ListSavedToolsetsResponse = z.infer<
      typeof listSavedToolsetsResponseZodSchema
    >;
    export type BuildToolsetResponse = z.infer<
      typeof buildToolsetResponseZodSchema
    >;
    export type EquipToolsetResponse = z.infer<
      typeof equipToolsetResponseZodSchema
    >;
    export type GetActiveToolsetResponse = z.infer<
      typeof getActiveToolsetResponseZodSchema
    >;
    
    /**
     * JSON Schemas generated from Zod schemas using zod-to-json-schema
     * Note: Using $refStrategy: 'none' to avoid $ref definitions for MCP compatibility
     */
    export const serverConfigSchema = zodToJsonSchema(serverConfigZodSchema, {
      $refStrategy: "none",
    });
    
    export const toolsetInfoSchema = zodToJsonSchema(toolsetInfoZodSchema, {
      $refStrategy: "none",
    });
    
    export const listSavedToolsetsResponseSchema = zodToJsonSchema(
      listSavedToolsetsResponseZodSchema,
      {
        $refStrategy: "none",
      }
    );
    
    export const buildToolsetResponseSchema = zodToJsonSchema(
      buildToolsetResponseZodSchema,
      {
        $refStrategy: "none",
      }
    );
  • Registration of the build-toolset tool factory in the configuration tools factories array.
    export const CONFIG_TOOL_FACTORIES: ToolModuleFactory[] = [
      createListAvailableToolsModule,
      createBuildToolsetModule,
      createListSavedToolsetsModule,
      createEquipToolsetModule,
      createDeleteToolsetModule,
      createUnequipToolsetModule,
      createGetActiveToolsetModule,
      createAddToolAnnotationModule,
      createListPersonasModule, // Persona management tool
      createExitConfigurationModeModule,
    ];
  • Core helper method in ToolsetManager that implements the toolset building logic: validates inputs, resolves tools, saves to user preferences, generates detailed info, and handles auto-equip.
    async buildToolset(
      name: string,
      tools: DynamicToolReference[],
      options: {
        description?: string;
        autoEquip?: boolean;
      } = {}
    ): Promise<BuildToolsetResponse> {
      try {
        // Validate toolset name format
        const namePattern = /^[a-z0-9-]+$/;
        if (!namePattern.test(name)) {
          return {
            meta: {
              success: false,
              error:
                "Invalid toolset name format. Use only lowercase letters, numbers, and hyphens (a-z, 0-9, -)",
            },
          };
        }
    
        if (name.length < 2 || name.length > 50) {
          return {
            meta: {
              success: false,
              error: "Toolset name must be between 2 and 50 characters",
            },
          };
        }
    
        if (!tools || tools.length === 0) {
          return {
            meta: {
              success: false,
              error: "Toolset must include at least one tool",
            },
          };
        }
    
        // Validate tool references if discovery engine is available
        if (this.discoveryEngine) {
          const validationResult = this.validateToolReferences(tools);
          if (!validationResult.valid) {
            return {
              meta: {
                success: false,
                error: `Invalid tool references: ${validationResult.invalidReferences.join(", ")}`,
              },
            };
          }
        }
    
        // Check if toolset already exists
        const preferences = await import("../../../config/preferenceStore.js");
        const loadToolsetsFromPreferences = preferences.loadStoredToolsets;
        const saveToolsetsToPreferences = preferences.saveStoredToolsets;
        const stored = await loadToolsetsFromPreferences();
    
        if (stored[name]) {
          return {
            meta: {
              success: false,
              error: `Toolset "${name}" already exists. Use a different name or delete the existing toolset first.`,
            },
          };
        }
    
        // Create toolset configuration
        const config: ToolsetConfig = {
          name,
          description: options.description,
          version: "1.0.0",
          createdAt: new Date(),
          tools,
        };
    
        // Validate configuration
        const validation = validateToolsetConfig(config);
        if (!validation.valid) {
          return {
            meta: {
              success: false,
              error: `Invalid toolset configuration: ${validation.errors.join(", ")}`,
            },
          };
        }
    
        // Save toolset
        stored[name] = config;
        await saveToolsetsToPreferences(stored);
    
        // Generate detailed toolset information
        const toolsetInfo = await this.generateToolsetInfo(config);
    
        const result = {
          meta: {
            success: true,
            toolsetName: name,
            autoEquipped: false,
          },
          toolset: toolsetInfo,
        };
    
        // Auto-equip if requested
        if (options.autoEquip) {
          const equipResult = await this.equipToolset(name);
          if (equipResult.success) {
            result.meta.autoEquipped = true;
            result.toolset.active = true;
          }
        }
    
        return result;
      } catch (error) {
        return {
          meta: {
            success: false,
            error: `Failed to create toolset: ${error instanceof Error ? error.message : String(error)}`,
          },
        };
      }
    }
Behavior3/5

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

With no annotations provided, the description carries full burden. It clearly indicates this is a creation/save operation ('Build and save'), mentions the auto-equip behavior, and provides an example. However, it doesn't disclose important behavioral aspects like whether duplicate toolset names are allowed, what happens on failure, or if there are rate limits.

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

Conciseness5/5

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

The description is efficiently structured with a clear purpose statement, helpful analogy, essential requirements, and a concrete example. Every sentence adds value without redundancy, and the example demonstrates proper usage while reinforcing key concepts.

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

Completeness4/5

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

Given the tool's complexity (creation operation with 4 parameters) and the presence of an output schema, the description provides good coverage of the core functionality. It explains the purpose, requirements, and includes a helpful example. However, with no annotations, it could better address behavioral aspects like error conditions or constraints.

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

Parameters4/5

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

With 100% schema description coverage, the baseline is 3. The description adds meaningful context beyond the schema by explaining the purpose of tool selection ('pick the exact tools you need'), providing a concrete example with specific tool names, and emphasizing the requirement to specify tools with either namespacedName or refId.

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

Purpose5/5

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

The description clearly states the specific action ('Build and save a custom toolset') and resource ('by selecting specific tools'), distinguishing it from siblings like delete-toolset or equip-toolset. The workshop analogy reinforces the core purpose of assembling tools for specific tasks.

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

Usage Guidelines4/5

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

The description provides clear context for when to use this tool ('for a specific task or workflow') and mentions using list-available-tools to see options, but doesn't explicitly state when NOT to use it or contrast it with alternatives like add-tool-annotation for modifying existing toolsets.

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/toolprint/hypertool-mcp'

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