Skip to main content
Glama

hypertool-mcp

activate-persona.tsโ€ข13 kB
/** * Activate Persona Tool - Activate a specific persona with optional toolset selection */ import { Tool } from "@modelcontextprotocol/sdk/types.js"; import { ToolModuleFactory, ToolModule } from "../../types.js"; import { PersonaManager } from "../../../../persona/manager.js"; import { ActivationResult } from "../../../../persona/types.js"; import { z } from "zod"; import { zodToJsonSchema } from "zod-to-json-schema"; import { discoverPersonas } from "../../../../persona/discovery.js"; import { createChildLogger } from "../../../../utils/logging.js"; const logger = createChildLogger({ module: "activate-persona-tool" }); // Define the response schema using Zod const activatePersonaResponseSchema = z.object({ success: z.boolean().describe("Whether the activation was successful"), persona: z .object({ name: z.string().describe("Activated persona name"), description: z.string().optional().describe("Persona description"), activatedToolset: z .string() .optional() .describe("Name of the activated toolset"), activationTime: z .string() .describe("ISO timestamp when the persona was activated"), metadata: z .object({ activationSource: z .enum(["manual", "automatic", "restored"]) .describe("Source of the activation"), validationPassed: z .boolean() .describe("Whether validation passed during activation"), toolsResolved: z .number() .describe("Number of tools successfully resolved"), warnings: z .array(z.string()) .describe("Any warnings during activation"), }) .describe("Activation metadata"), }) .optional() .describe("Activated persona information (only present if successful)"), toolsetInfo: z .object({ name: z.string().describe("Toolset name"), toolCount: z.number().describe("Number of tools in the toolset"), resolvedTools: z .array(z.string()) .optional() .describe("List of successfully resolved tool IDs"), }) .optional() .describe("Toolset information (only present if toolset was activated)"), warnings: z .array(z.string()) .optional() .describe("Non-fatal warnings during activation"), errors: z .array(z.string()) .optional() .describe("Error messages if activation failed"), error: z.string().optional().describe("Primary error message if failed"), suggestions: z .array(z.string()) .optional() .describe("Actionable suggestions if activation failed"), }); export const activatePersonaDefinition: Tool = { name: "activate-persona", description: "Activate a specific persona with optional toolset selection. This tool orchestrates the complete persona activation workflow including validation, toolset application, and state management. Only one persona can be active at a time - activating a new persona will automatically deactivate the current one. Returns comprehensive activation results with detailed error handling and actionable suggestions for troubleshooting.", inputSchema: { type: "object" as const, properties: { personaName: { type: "string", description: "Name of the persona to activate (must match an available persona)", }, toolsetName: { type: "string", description: "Optional specific toolset to activate. If not provided, the persona's default toolset will be used", }, force: { type: "boolean", description: "Force activation even if validation fails (default: false)", default: false, }, preserveState: { type: "boolean", description: "Whether to preserve current state for potential restoration (default: true)", default: true, }, }, required: ["personaName"], additionalProperties: false, }, outputSchema: zodToJsonSchema(activatePersonaResponseSchema) as any, annotations: { title: "Activate Persona", readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false, }, }; /** * Generate actionable suggestions based on activation failure * @param personaName Failed persona name * @param error Error message * @param availablePersonas List of available personas * @returns Array of suggestion strings */ function generateActivationSuggestions( personaName: string, error: string, availablePersonas: string[] = [] ): string[] { const suggestions: string[] = []; if (error.includes("not found") || error.includes("PERSONA_NOT_FOUND")) { suggestions.push(`Persona "${personaName}" was not found.`); if (availablePersonas.length > 0) { suggestions.push("Available personas:"); availablePersonas.slice(0, 5).forEach((name) => { suggestions.push(` - ${name}`); }); if (availablePersonas.length > 5) { suggestions.push(` ... and ${availablePersonas.length - 5} more`); } } else { suggestions.push( "No personas are currently available. Try refreshing persona discovery." ); } suggestions.push('Use "list-personas" to see all available personas.'); } else if ( error.includes("validation failed") || error.includes("VALIDATION_FAILED") ) { suggestions.push("Persona validation failed. Common issues:"); suggestions.push(" - Check YAML syntax in persona.yaml"); suggestions.push(" - Ensure all required fields are present"); suggestions.push(" - Verify toolset references are valid"); suggestions.push( 'Use "validate-persona" to see detailed validation results.' ); } else if (error.includes("toolset") && error.includes("not found")) { suggestions.push("Specified toolset was not found in the persona."); suggestions.push("Check available toolsets in the persona configuration."); suggestions.push( "Try activating without specifying a toolset to use the default." ); } else if (error.includes("tool resolution")) { suggestions.push("Tool resolution failed during activation:"); suggestions.push(" - Check that required MCP servers are running"); suggestions.push(" - Verify tool IDs match available tools"); suggestions.push( " - Consider using partial activation if some tools are unavailable" ); } else { // Generic suggestions suggestions.push("Activation failed. Try these troubleshooting steps:"); suggestions.push(' 1. Use "list-personas" to verify the persona exists'); suggestions.push( ' 2. Use "validate-persona" to check for configuration issues' ); suggestions.push(" 3. Check that required MCP servers are connected"); suggestions.push( " 4. Try activating with force=true to bypass validation" ); } return suggestions; } /** * Get list of available persona names for suggestions */ async function getAvailablePersonaNames(): Promise<string[]> { try { const discoveryResult = await discoverPersonas(); return discoveryResult.personas .filter((p) => p.isValid) .map((p) => p.name) .sort(); } catch (error) { logger.warn("Failed to get available personas for suggestions", { error }); return []; } } /** * Create detailed activation response from PersonaManager result */ function createActivationResponse( result: ActivationResult, personaManager: PersonaManager ): any { if (!result.success) { return { success: false, errors: result.errors || ["Unknown activation error"], error: result.errors?.[0] || "Activation failed", warnings: result.warnings, }; } // Get active persona state for detailed information const activeState = personaManager.getActivePersona(); const response: any = { success: true, persona: { name: result.personaName, description: activeState?.persona.config.description, activatedToolset: result.activatedToolset, activationTime: (activeState?.activatedAt || new Date()).toISOString(), metadata: { activationSource: activeState?.metadata.activationSource || "manual", validationPassed: activeState?.metadata.validationPassed || false, toolsResolved: activeState?.metadata.toolsResolved || 0, warnings: activeState?.metadata.warnings || [], }, }, warnings: result.warnings, }; // Add toolset information if available if (result.activatedToolset && activeState) { const toolset = activeState.persona.config.toolsets?.find( (t) => t.name === result.activatedToolset ); if (toolset) { response.toolsetInfo = { name: toolset.name, toolCount: toolset.toolIds.length, resolvedTools: toolset.toolIds.slice(0, 10), // Limit for response size }; } } return response; } export const createActivatePersonaModule: ToolModuleFactory = ( deps ): ToolModule => { // Create PersonaManager instance with dependencies const personaManager = new PersonaManager({ getToolDiscoveryEngine: () => deps.discoveryEngine, toolsetManager: deps.toolsetManager, validateOnActivation: true, autoDiscover: true, }); return { toolName: "activate-persona", definition: activatePersonaDefinition, handler: async (args: any) => { try { const { personaName, toolsetName, force = false, preserveState = true, } = args || {}; logger.info("Persona activation requested", { personaName, toolsetName, force, preserveState, }); // Validate required parameters if (!personaName || typeof personaName !== "string") { const errorResponse = { success: false, errors: ["personaName parameter is required and must be a string"], error: "Invalid personaName parameter", suggestions: [ "Provide a valid persona name as a string", 'Use "list-personas" to see available personas', ], }; return { content: [ { type: "text", text: JSON.stringify(errorResponse), }, ], structuredContent: errorResponse, isError: true, }; } // Initialize the persona manager await personaManager.initialize(); // Attempt persona activation const activationResult = await personaManager.activatePersona( personaName, { toolsetName, force, backupState: preserveState, silent: false, } ); logger.info("Persona activation completed", { personaName, success: activationResult.success, activatedToolset: activationResult.activatedToolset, hasErrors: !!activationResult.errors?.length, hasWarnings: !!activationResult.warnings?.length, }); // Create detailed response const response = createActivationResponse( activationResult, personaManager ); // Add suggestions if activation failed if (!activationResult.success) { const availablePersonas = await getAvailablePersonaNames(); const primaryError = activationResult.errors?.[0] || "Unknown error"; response.suggestions = generateActivationSuggestions( personaName, primaryError, availablePersonas ); } return { content: [ { type: "text", text: JSON.stringify(response), }, ], structuredContent: response, isError: !activationResult.success, }; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); logger.error("Persona activation failed with exception", { error: errorMessage, personaName: args?.personaName, }); const availablePersonas = await getAvailablePersonaNames(); const errorResponse = { success: false, errors: [`Activation failed: ${errorMessage}`], error: `Failed to activate persona: ${errorMessage}`, suggestions: generateActivationSuggestions( args?.personaName || "(unknown)", errorMessage, availablePersonas ), }; return { content: [ { type: "text", text: JSON.stringify(errorResponse), }, ], structuredContent: errorResponse, isError: true, }; } }, }; };

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