Skip to main content
Glama
DollhouseMCP

DollhouseMCP

Official

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
      };
    }
Behavior3/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. It describes the action (install/download) but lacks details on permissions needed, whether it overwrites existing elements, error handling, or what 'install' entails operationally. The examples help but don't cover behavioral traits fully.

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?

Front-loaded with the core purpose, followed by usage guidance and examples. Every sentence adds value without redundancy, making it efficient and well-structured for quick comprehension.

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

Completeness3/5

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

For a tool with no annotations and no output schema, the description covers purpose and usage well but lacks details on behavioral aspects like side effects, return values, or error conditions. It's adequate for basic use but incomplete for full operational understanding.

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%, so the schema already documents the 'path' parameter thoroughly. The description adds value by listing the element types (personas, skills, etc.) and implying the parameter's role, but doesn't provide additional syntax or format details beyond what the schema specifies.

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 (install/download) and resource (AI customization elements from DollhouseMCP collection to local portfolio), distinguishing it from siblings like 'browse_collection' or 'get_collection_content' by emphasizing the transfer operation.

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

Usage Guidelines5/5

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

It explicitly states when to use this tool ('when users ask to download/install any element type from the collection') and provides multiple concrete examples, making it easy to distinguish from alternatives like 'create_element' or 'import_persona'.

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

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