Skip to main content
Glama

fork_app

Create a full copy of a published app as a new project, including database, functions, and site, with optional subdomain claiming.

Instructions

Fork a published app into a new project. Creates a full copy including database, functions, site, and optionally claims a subdomain.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
version_idYesThe app version ID to fork (from browse_apps)
nameYesName for the new forked project
tierNoDatabase tier: prototype ($0.10/7d), hobby ($5/30d), team ($20/30d)prototype
subdomainNoOptional subdomain to claim for the forked app

Implementation Reference

  • The handleForkApp async function is the main handler that executes the fork_app tool logic. It makes an API request to fork an app, handles payment requirements (x402), saves credentials to the local keystore, and returns formatted results with project details.
    export async function handleForkApp(args: {
      version_id: string;
      name: string;
      tier?: string;
      subdomain?: string;
    }): Promise<{ content: Array<{ type: "text"; text: string }>; isError?: boolean }> {
      const tier = args.tier || "prototype";
    
      const res = await apiRequest(`/v1/fork/${tier}`, {
        method: "POST",
        body: {
          version_id: args.version_id,
          name: args.name,
          subdomain: args.subdomain,
        },
      });
    
      if (res.is402) {
        const body = res.body as Record<string, unknown>;
        const lines = [
          `## Payment Required`,
          ``,
          `To fork this app (tier: **${tier}**), an x402 payment is needed.`,
          ``,
        ];
        if (body.x402) {
          lines.push(`**Payment details:**`);
          lines.push("```json");
          lines.push(JSON.stringify(body.x402, null, 2));
          lines.push("```");
        } else {
          lines.push(`**Server response:**`);
          lines.push("```json");
          lines.push(JSON.stringify(body, null, 2));
          lines.push("```");
        }
        lines.push(``);
        lines.push(
          `The user's wallet or payment agent must send the required amount. ` +
          `Once payment is confirmed, retry this tool call.`,
        );
        return { content: [{ type: "text", text: lines.join("\n") }] };
      }
    
      if (!res.ok) return formatApiError(res, "forking app");
    
      const body = res.body as {
        project_id: string;
        anon_key: string;
        service_key: string;
        schema_slot: string;
        tier: string;
        lease_expires_at: string;
        site_url?: string;
        subdomain_url?: string;
        functions?: Array<{ name: string; url: string }>;
      };
    
      // Save credentials to local key store
      saveProject(body.project_id, {
        anon_key: body.anon_key,
        service_key: body.service_key,
        tier: body.tier,
        expires_at: body.lease_expires_at,
      });
    
      const lines = [
        `## App Forked: ${args.name}`,
        ``,
        `| Field | Value |`,
        `|-------|-------|`,
        `| project_id | \`${body.project_id}\` |`,
        `| tier | ${body.tier} |`,
        `| schema | ${body.schema_slot} |`,
        `| expires | ${body.lease_expires_at} |`,
      ];
    
      if (body.site_url) {
        lines.push(`| site | ${body.site_url} |`);
      }
      if (body.subdomain_url) {
        lines.push(`| subdomain | ${body.subdomain_url} |`);
      }
    
      lines.push(``);
      lines.push(`Keys saved to local key store.`);
    
      return { content: [{ type: "text", text: lines.join("\n") }] };
    }
  • The forkAppSchema defines the input validation schema for the fork_app tool using Zod. It specifies version_id (required), name (required), tier (optional with default 'prototype'), and subdomain (optional) parameters.
    export const forkAppSchema = {
      version_id: z.string().describe("The app version ID to fork (from browse_apps)"),
      name: z.string().describe("Name for the new forked project"),
      tier: z
        .enum(["prototype", "hobby", "team"])
        .default("prototype")
        .describe("Database tier: prototype ($0.10/7d), hobby ($5/30d), team ($20/30d)"),
      subdomain: z
        .string()
        .optional()
        .describe("Optional subdomain to claim for the forked app"),
    };
  • src/index.ts:27-27 (registration)
    Import statement that brings in the forkAppSchema and handleForkApp from the tools/fork-app module, making them available for tool registration.
    import { forkAppSchema, handleForkApp } from "./tools/fork-app.js";
  • src/index.ts:243-248 (registration)
    The fork_app tool is registered with the MCP server using server.tool(). It specifies the tool name, description, input schema, and the handler function that processes requests.
    server.tool(
      "fork_app",
      "Fork a published app into a new project. Creates a full copy including database, functions, site, and optionally claims a subdomain.",
      forkAppSchema,
      async (args) => handleForkApp(args),
    );

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/kychee-com/run402'

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