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
| Name | Required | Description | Default |
|---|---|---|---|
| entity_type | Yes | Entity type: icp, pain_point, value_prop, experiment, channel, competitor, contact | |
| id | Yes | Entity ID to edit | |
| name | No | Updated name (mapped to 'framing' for value_prop, 'title' for experiment) | |
| description | No | Updated description | |
| fields | No | Additional fields to update as key-value pairs | |
| project | No | Project slug — overrides .cantrip.json. Required in environments where cantrip_connect cannot write to the filesystem. |
Implementation Reference
- src/tools.ts:507-518 (handler)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); }, }, - src/tools.ts:496-506 (schema)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, }, - src/client.ts:36-46 (helper)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.", ); } - src/client.ts:79-125 (helper)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; }