Skip to main content
Glama

cantrip_entity_add

Add new entities like customers, pain points, or experiments to Cantrip's GoToMarket platform to organize and track business development data.

Instructions

Create a new entity. Automatically marked as 'accepted'. Fields vary by type:

  • icp: name, description, demographics, jobs_to_be_done, willingness_to_pay, current_alternatives, priority, is_beachhead

  • pain_point: description, severity (low|medium|high|critical), frequency (rare|occasional|frequent|constant), evidence

  • value_prop: framing (required — use instead of 'name'; 'description' is stored in extensions), tagline, evidence

  • channel: name, channel_type, lifecycle_stage (exploring|testing|scaling|maintaining|killed), cac, estimated_reach, conversion_rate (note: 'description' maps to 'notes' column)

  • experiment: title (required — use instead of 'name'), hypothesis, description, status (proposed|designed|active|completed|analyzed|abandoned), success_metrics, outcome_notes, value_prop_id, channel_id

  • competitor: name, description, url, positioning, strengths, weaknesses, pricing_model

  • contact: name, email, phone, company, role, source, url, notes Extra fields (any field not in the schema above) are stored in extensions. After adding entities, pause and confirm with the user before adding more. 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
nameNoEntity name (mapped to 'framing' for value_prop, 'title' for experiment)
descriptionNoEntity description
fieldsNoAdditional fields as key-value pairs (e.g. {severity: 'high', frequency: 'constant'})
projectNoProject slug — overrides .cantrip.json. Required in environments where cantrip_connect cannot write to the filesystem.

Implementation Reference

  • Handler function for cantrip_entity_add tool. Builds flags from name, description, and fields parameters, resolves the project context, and calls client.post to create the entity via the 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), ["add"], flags);
    },
  • src/tools.ts:451-488 (registration)
    Tool registration in createTools function. Defines the tool name, description (including detailed field documentation for each entity type), input schema shape, and handler function.
    {
      name: "cantrip_entity_add",
      description:
        "Create a new entity. Automatically marked as 'accepted'. " +
        "Fields vary by type:\n" +
        "- icp: name, description, demographics, jobs_to_be_done, willingness_to_pay, current_alternatives, priority, is_beachhead\n" +
        "- pain_point: description, severity (low|medium|high|critical), frequency (rare|occasional|frequent|constant), evidence\n" +
        "- value_prop: framing (required — use instead of 'name'; 'description' is stored in extensions), tagline, evidence\n" +
        "- channel: name, channel_type, lifecycle_stage (exploring|testing|scaling|maintaining|killed), cac, estimated_reach, conversion_rate (note: 'description' maps to 'notes' column)\n" +
        "- experiment: title (required — use instead of 'name'), hypothesis, description, status (proposed|designed|active|completed|analyzed|abandoned), success_metrics, outcome_notes, value_prop_id, channel_id\n" +
        "- competitor: name, description, url, positioning, strengths, weaknesses, pricing_model\n" +
        "- contact: name, email, phone, company, role, source, url, notes\n" +
        "Extra fields (any field not in the schema above) are stored in extensions. " +
        "After adding entities, pause and confirm with the user before adding more." +
        PROJECT_DESC_SUFFIX,
      shape: {
        entity_type: entityTypeSchema,
        name: z.string().optional().describe("Entity name (mapped to 'framing' for value_prop, 'title' for experiment)"),
        description: z.string().optional().describe("Entity description"),
        fields: z
          .record(z.string())
          .optional()
          .describe("Additional fields as key-value pairs (e.g. {severity: 'high', frequency: 'constant'})"),
        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), ["add"], flags);
      },
    },
  • Input schema definition using Zod. Defines entity_type (required), name (optional), description (optional), fields (optional record for additional fields), and project (optional) parameters.
    shape: {
      entity_type: entityTypeSchema,
      name: z.string().optional().describe("Entity name (mapped to 'framing' for value_prop, 'title' for experiment)"),
      description: z.string().optional().describe("Entity description"),
      fields: z
        .record(z.string())
        .optional()
        .describe("Additional fields as key-value pairs (e.g. {severity: 'high', frequency: 'constant'})"),
      project: projectSchema,
    },
  • buildFlags helper function that converts parameters to a flags object, filtering out undefined, null, and empty string values. Used by the handler to prepare API request parameters.
    function buildFlags(params: Record<string, unknown>): Record<string, string> {
      const flags: Record<string, string> = {};
      for (const [k, v] of Object.entries(params)) {
        if (v !== undefined && v !== null && v !== "") {
          flags[k] = String(v);
        }
      }
      return flags;
    }
  • CantripClient.post method that executes the API call. Constructs the request envelope with command, args, and flags, injects project context, adds authentication headers, and handles the HTTP response with error handling.
    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