Skip to main content
Glama

install_utility

Fetches and writes a CustomClaw utility payload to a specified directory. For paid utilities, requires a Stripe session ID from the buyer's receipt. Returns written files and npm dependencies but does not run install.

Instructions

Fetch a CustomClaw utility payload and write its files into target_dir. For paid utilities, pass session_id (the Stripe checkout session_id from the buyer's receipt email). Returns the list of files written and any npm dependencies the caller should install — this tool does NOT run npm install itself; the host agent decides when to install deps.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
slugYesThe utility slug to install.
target_dirYesDirectory to write files into. Absolute path preferred; relative paths are resolved against the server process cwd.
session_idNoOptional. Stripe checkout session_id for paid utilities. Found as session_id=... in the CustomClaw receipt email download URL.

Implementation Reference

  • The main handler function for the install_utility tool. Fetches payload from the registry API, validates inputs, writes files to target_dir (with path traversal protection), and returns files_written, dependencies, and a message.
    async function installUtility({ slug, target_dir, session_id }) {
      if (!slug || typeof slug !== 'string') {
        throw new Error('slug is required (string)');
      }
      if (!target_dir || typeof target_dir !== 'string') {
        throw new Error('target_dir is required (string, absolute or relative directory)');
      }
    
      const url = new URL(`${SITE_BASE}/api/cli`);
      url.searchParams.set('slug', slug);
      if (session_id) url.searchParams.set('session_id', session_id);
    
      const res = await fetch(url.toString());
    
      if (res.status === 401) {
        throw new Error(
          `This utility is paid and requires proof of purchase. ` +
          `Pass session_id (the Stripe checkout session_id) — you'll find session_id=... ` +
          `in the download URL from your CustomClaw receipt email. ` +
          `Then call install_utility again with { slug: "${slug}", target_dir, session_id: "cs_..." }.`
        );
      }
      if (res.status === 404) {
        throw new Error(`No utility with slug "${slug}". Use list_utilities or search_utilities to find valid slugs.`);
      }
      if (!res.ok) {
        let msg = `HTTP ${res.status}`;
        try {
          const body = await res.json();
          if (body && body.error) msg = body.error;
        } catch {
          // body wasn't JSON, keep generic message
        }
        throw new Error(`Registry error: ${msg}`);
      }
    
      const payload = await res.json();
      const { files = [], dependencies = [], message } = payload;
    
      // Resolve target_dir against cwd if relative.
      const resolvedDir = path.isAbsolute(target_dir)
        ? target_dir
        : path.resolve(process.cwd(), target_dir);
    
      const written = [];
      for (const file of files) {
        if (!file || typeof file.path !== 'string' || typeof file.content !== 'string') {
          continue;
        }
        // Join and ensure the final path stays inside resolvedDir (defence against "../").
        const destPath = path.resolve(resolvedDir, file.path);
        const rel = path.relative(resolvedDir, destPath);
        if (rel.startsWith('..') || path.isAbsolute(rel)) {
          throw new Error(`Refusing to write outside target_dir: ${file.path}`);
        }
        fs.mkdirSync(path.dirname(destPath), { recursive: true });
        fs.writeFileSync(destPath, file.content);
        written.push(destPath);
      }
    
      return {
        slug,
        target_dir: resolvedDir,
        files_written: written,
        dependencies,
        dependencies_install_hint:
          dependencies.length > 0
            ? `Run one of: npm install ${dependencies.join(' ')}  |  yarn add ${dependencies.join(' ')}  |  pnpm add ${dependencies.join(' ')}`
            : 'No dependencies required.',
        message: message || 'Utility successfully written.',
      };
    }
  • Input schema definition registered for install_utility. Defines required string parameters: slug, target_dir, and optional session_id (for paid utilities).
    {
      name: 'install_utility',
      description:
        'Fetch a CustomClaw utility payload and write its files into target_dir. ' +
        'For paid utilities, pass session_id (the Stripe checkout session_id from the buyer\'s receipt email). ' +
        'Returns the list of files written and any npm dependencies the caller should install — ' +
        'this tool does NOT run npm install itself; the host agent decides when to install deps.',
      inputSchema: {
        type: 'object',
        properties: {
          slug: {
            type: 'string',
            description: 'The utility slug to install.',
          },
          target_dir: {
            type: 'string',
            description:
              'Directory to write files into. Absolute path preferred; relative paths are resolved against the server process cwd.',
          },
          session_id: {
            type: 'string',
            description:
              'Optional. Stripe checkout session_id for paid utilities. Found as session_id=... in the CustomClaw receipt email download URL.',
          },
        },
        required: ['slug', 'target_dir'],
        additionalProperties: false,
      },
    },
  • index.js:234-263 (registration)
    The tool registration entry within the TOOLS array, including name, description, and inputSchema.
      {
        name: 'install_utility',
        description:
          'Fetch a CustomClaw utility payload and write its files into target_dir. ' +
          'For paid utilities, pass session_id (the Stripe checkout session_id from the buyer\'s receipt email). ' +
          'Returns the list of files written and any npm dependencies the caller should install — ' +
          'this tool does NOT run npm install itself; the host agent decides when to install deps.',
        inputSchema: {
          type: 'object',
          properties: {
            slug: {
              type: 'string',
              description: 'The utility slug to install.',
            },
            target_dir: {
              type: 'string',
              description:
                'Directory to write files into. Absolute path preferred; relative paths are resolved against the server process cwd.',
            },
            session_id: {
              type: 'string',
              description:
                'Optional. Stripe checkout session_id for paid utilities. Found as session_id=... in the CustomClaw receipt email download URL.',
            },
          },
          required: ['slug', 'target_dir'],
          additionalProperties: false,
        },
      },
    ];
  • The case branch in the CallToolRequestSchema handler that dispatches install_utility calls to the installUtility function.
    case 'install_utility': {
      const result = await installUtility({
        slug: args.slug,
        target_dir: args.target_dir,
        session_id: args.session_id,
      });
      return jsonResult(result);
    }
Behavior4/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 discloses that it writes files, returns a list of files and npm dependencies, and refrains from running npm install. However, it does not mention potential side effects like overwriting existing files or required permissions.

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?

Two sentences, efficiently structured. The first sentence states the main action, the second provides critical usage details (session_id and npm install behavior). No unnecessary words.

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

Completeness5/5

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

No output schema but the description fully explains return value (list of files and npm dependencies) and what the tool does not do (npm install). For a tool with 3 parameters and no nested objects, this is complete.

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

Parameters5/5

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

Schema coverage is 100%, and the description adds context beyond the schema: slug is clarified as 'utility slug', target_dir includes guidance on absolute vs relative paths, and session_id explains where to find it (Stripe checkout session_id from receipt email).

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 'Fetch a CustomClaw utility payload and write its files into target_dir', which is a specific verb and resource. It distinguishes from sibling tools (get_utility_info, list_utilities, search_utilities) which are all informational while this is an installation tool.

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?

Provides explicit guidance on when to pass session_id (for paid utilities) and clarifies that the tool does NOT run npm install itself, leaving that decision to the host agent. This helps the agent understand when and how to use it.

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/onlythebestswfl-ops/customclaw-mcp'

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