Skip to main content
Glama

install_collection_content

Install AI customization elements like personas, skills, templates, agents, or memories from the DollhouseMCP collection to your local portfolio for dynamic persona management.

Instructions

Install AI customization elements FROM the DollhouseMCP collection TO your local portfolio. Use this when users ask to download/install any element type (personas, skills, templates, agents, or memories) from the collection. Examples: 'install the creative writer persona from the collection', 'get the code review skill from collection', 'download the meeting notes template from collection', 'get the project context memory from collection'.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
pathYesThe collection path to the AI customization element. Format: 'library/[type]/[element].md' where type is personas, skills, templates, agents, or memories. Example: 'library/skills/code-review.md'.

Implementation Reference

  • Registration of the 'install_collection_content' tool, including name, detailed description, input schema requiring 'path' parameter, and handler that delegates to server.installContent(path)
    tool: { name: "install_collection_content", description: "Install AI customization elements FROM the DollhouseMCP collection TO your local portfolio. Use this when users ask to download/install any element type (personas, skills, templates, agents, or memories) from the collection. Examples: 'install the creative writer persona from the collection', 'get the code review skill from collection', 'download the meeting notes template from collection', 'get the project context memory from collection'.", inputSchema: { type: "object", properties: { path: { type: "string", description: "The collection path to the AI customization element. Format: 'library/[type]/[element].md' where type is personas, skills, templates, agents, or memories. Example: 'library/skills/code-review.md'.", }, }, required: ["path"], }, }, handler: (args: any) => server.installContent(args.path) },
  • Input schema for the tool: object with required 'path' string (collection path like 'library/personas/creative-writer.md')
    inputSchema: { type: "object", properties: { path: { type: "string", description: "The collection path to the AI customization element. Format: 'library/[type]/[element].md' where type is personas, skills, templates, agents, or memories. Example: 'library/skills/code-review.md'.", }, }, required: ["path"], }, }, handler: (args: any) => server.installContent(args.path) },
  • Handler implementation: installContent(inputPath) method in ElementInstaller class, which performs the actual installation from the given collection path. This is called by the tool's server.installContent. Includes full security validation, atomic writes, and error handling.
    async installContent(inputPath: string): Promise<{ success: boolean; message: string; metadata?: IElementMetadata; elementType?: ElementType; filename?: string; }> { return await this.installFromCollection(inputPath); } /** * Atomic file write operation with guaranteed cleanup on failure * * SECURITY FIX: This method ensures that file writes are atomic and any * failures during the write process will not leave partial or corrupted * files on the filesystem. Uses temporary file + rename for atomicity. * * @param destination - Final destination path for the file * @param content - Content to write to the file * @throws Error if write operation fails (with guaranteed cleanup) */ private async atomicWriteFile(destination: string, content: string): Promise<void> { // Generate unique temporary file name to avoid collisions const tempFile = `${destination}.tmp.${Date.now()}.${Math.random().toString(36).substring(2)}`; try { // SECURITY: Write to temporary file first // If this fails, no files are left on disk await fs.writeFile(tempFile, content, 'utf-8'); // SECURITY: Atomic rename operation // On most filesystems, rename is atomic - the file appears with complete content // or doesn't appear at all. This prevents partial file corruption. await fs.rename(tempFile, destination); } catch (error) { // SECURITY: Guaranteed cleanup of temporary file on ANY failure // This ensures no temporary files are left behind even if the // rename operation fails after successful write try { await fs.unlink(tempFile); } catch (cleanupError) { // Ignore cleanup errors - the file may not exist if writeFile failed // The original error is more important to propagate } // Re-throw the original error to maintain error handling semantics throw error; } } /** * Get ElementType from string */ private getElementTypeFromString(typeStr: string): ElementType { const typeMap: Record<string, ElementType> = { 'personas': ElementType.PERSONA, 'skills': ElementType.SKILL, 'templates': ElementType.TEMPLATE, 'agents': ElementType.AGENT }; const elementType = typeMap[typeStr]; if (!elementType) { throw new Error(`Unknown element type: ${typeStr}. Valid types: ${Object.keys(typeMap).join(', ')}`); } return elementType; } /** * Format installation success message */ formatInstallSuccess(metadata: IElementMetadata, filename: string, elementType: ElementType): string { const typeEmojis: Record<ElementType, string> = { [ElementType.PERSONA]: '🎭', [ElementType.SKILL]: '🎯', [ElementType.TEMPLATE]: '📄', [ElementType.AGENT]: '🤖', [ElementType.MEMORY]: '🧠', [ElementType.ENSEMBLE]: '🎼' }; const emoji = typeEmojis[elementType] || '📦'; const typeName = elementType.charAt(0).toUpperCase() + elementType.slice(1); return `✅ **AI Customization Element Installed Successfully!**\n\n` + `${emoji} **${metadata.name}** ${metadata.author ? `by ${metadata.author}` : ''}\n` + `📁 Type: ${typeName}\n` + `📄 Saved as: ${filename}\n\n` + `🚀 **Ready to use!**`; } }
  • Core handler logic: installFromCollection performs fetch, full security validation (size, sanitize, YAML parse, metadata), path preparation, existence check, and atomic secure write to portfolio. Called by installContent.
    private async installFromCollection(collectionPath: string): Promise<InstallResult> { // ENHANCEMENT (PR #1453): Log collection installation attempt logger.debug('Installing from collection', { collectionPath }); // SECURITY: Validate and sanitize the input path first const sanitizedPath = validatePath(collectionPath); const elementType = this.validateAndExtractElementType(sanitizedPath); // STEP 1: FETCH CONTENT INTO MEMORY (NO DISK OPERATIONS YET) const content = await this.fetchCollectionContent(sanitizedPath); // STEP 2: PERFORM ALL VALIDATION BEFORE ANY DISK OPERATIONS const { sanitizedContent, metadata } = await this.validateCollectionContent(content); // STEP 3: PREPARE FILE PATH AND CHECK EXISTENCE // FIX (SonarCloud L704): Remove unused elementDir variable const { filename, localPath } = this.prepareFilePath(sanitizedPath, elementType); // SECURITY: Check if file already exists before any write operations const existsResult = await this.checkFileExists(localPath, filename); if (existsResult) { logger.debug('Element already exists in collection', { filename, elementType }); return existsResult; } // STEP 4: ALL VALIDATION COMPLETE - NOW PERFORM ATOMIC WRITE OPERATION await this.atomicWriteFile(localPath, sanitizedContent); // ENHANCEMENT (PR #1453): Log successful installation logger.debug('Element installed successfully from collection', { elementName: metadata.name, elementType, filename, localPath }); return { success: true, message: `AI customization element installed successfully!`, metadata, filename, elementType }; }

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/DollhouseMCP/mcp-server'

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