Skip to main content
Glama

cantrip_entity_edit

Edit existing business entities like ICPs, pain points, value propositions, and experiments. Update names, descriptions, and custom fields while optionally overriding project settings.

Instructions

Edit an existing entity. Fields vary by type (same as cantrip_entity_add). Pass well-known fields directly, and any additional fields in the 'fields' object. Extra fields are stored in extensions. Pass project to override .cantrip.json — useful in cloud-hosted or multi-project contexts.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
entity_typeYesEntity type: icp, pain_point, value_prop, experiment, channel, competitor, contact
idYesEntity ID to edit
nameNoUpdated name (mapped to 'framing' for value_prop, 'title' for experiment)
descriptionNoUpdated description
fieldsNoAdditional fields to update as key-value pairs
projectNoProject slug — overrides .cantrip.json. Required in environments where cantrip_connect cannot write to the filesystem.

Implementation Reference

  • Handler function for cantrip_entity_edit tool. Collects parameters (entity_type, id, name, description, fields, project) into flags, resolves the project context, and calls client.post() to edit the entity via the Cantrip API.
    handler: async (p) => {
      const flags: Record<string, string> = {};
      if (p.name) flags.name = String(p.name);
      if (p.description) flags.description = String(p.description);
      if (p.fields && typeof p.fields === "object") {
        for (const [k, v] of Object.entries(p.fields as Record<string, string>)) {
          flags[k] = v;
        }
      }
      flags.project = resolveProject(p.project as string | undefined);
      return client.post(String(p.entity_type), ["edit", String(p.id)], flags);
    },
  • src/tools.ts:489-519 (registration)
    Tool registration for cantrip_entity_edit including name, description, input schema shape (entity_type, id, name, description, fields, project), and the handler function.
    {
      name: "cantrip_entity_edit",
      description:
        "Edit an existing entity. Fields vary by type (same as cantrip_entity_add). " +
        "Pass well-known fields directly, and any additional fields in the 'fields' object. " +
        "Extra fields are stored in extensions." +
        PROJECT_DESC_SUFFIX,
      shape: {
        entity_type: entityTypeSchema,
        id: z.string().describe("Entity ID to edit"),
        name: z.string().optional().describe("Updated name (mapped to 'framing' for value_prop, 'title' for experiment)"),
        description: z.string().optional().describe("Updated description"),
        fields: z
          .record(z.string())
          .optional()
          .describe("Additional fields to update as key-value pairs"),
        project: projectSchema,
      },
      handler: async (p) => {
        const flags: Record<string, string> = {};
        if (p.name) flags.name = String(p.name);
        if (p.description) flags.description = String(p.description);
        if (p.fields && typeof p.fields === "object") {
          for (const [k, v] of Object.entries(p.fields as Record<string, string>)) {
            flags[k] = v;
          }
        }
        flags.project = resolveProject(p.project as string | undefined);
        return client.post(String(p.entity_type), ["edit", String(p.id)], flags);
      },
    },
  • Input schema definition for cantrip_entity_edit using Zod. Defines entity_type (enum), id (required string), name and description (optional strings), fields (optional record), and project (optional string).
    shape: {
      entity_type: entityTypeSchema,
      id: z.string().describe("Entity ID to edit"),
      name: z.string().optional().describe("Updated name (mapped to 'framing' for value_prop, 'title' for experiment)"),
      description: z.string().optional().describe("Updated description"),
      fields: z
        .record(z.string())
        .optional()
        .describe("Additional fields to update as key-value pairs"),
      project: projectSchema,
    },
  • resolveProject helper function that resolves project context: prefers inline slug parameter, falls back to .cantrip.json file, throws error if neither is available.
    export function resolveProject(inlineSlug?: string): string {
      if (inlineSlug) return inlineSlug;
    
      const fromFile = readProjectContext();
      if (fromFile) return fromFile;
    
      throw new Error(
        "No project context. Either pass the 'project' slug as a parameter, " +
        "or run cantrip_connect first.",
      );
    }
  • CantripClient.post method that constructs and sends HTTP POST requests to the Cantrip API. Handles project injection, authorization, error handling, and returns CantripResponse.
    async post(
      command: string,
      args: string[] = [],
      flags: Record<string, string> = {},
    ): Promise<CantripResponse> {
      const url = `${this.apiUrl}/api/cantrip`;
    
      // Inject project from .cantrip.json if not provided
      if (!flags.project) {
        const project = readProjectContext();
        if (project) flags.project = project;
      }
    
      const body: CantripRequest = { command, args, flags };
    
      const headers: Record<string, string> = {
        "Content-Type": "application/json",
      };
      if (this.apiKey) {
        headers["Authorization"] = `Bearer ${this.apiKey}`;
      }
    
      let res: Response;
      try {
        res = await fetch(url, { method: "POST", headers, body: JSON.stringify(body) });
      } catch (err) {
        throw new Error(
          `Cannot reach Cantrip API at ${this.apiUrl}. ` +
            `Check your network connection and CANTRIP_API_KEY.\n` +
            `(${err instanceof Error ? err.message : String(err)})`,
        );
      }
    
      const json = (await res.json()) as CantripResponse;
      if ("error" in json && typeof json.error === "string") {
        let message = json.error;
        if (/insufficient credits/i.test(message)) {
          message += "\n\nPurchase credits at https://cantrip.ai";
        }
        if (/not authenticated/i.test(message) || /unauthorized/i.test(message)) {
          message +=
            "\n\nSet CANTRIP_API_KEY in your MCP server config. Get a key at https://cantrip.ai";
        }
        throw new Error(`cantrip error: ${message}`);
      }
      return json;
    }

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

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