{
  "server": "https://app.heykairon.com/mcp",
  "clusters": [
    {
      "id": "list-building",
      "title": "List building",
      "question": "Who should we talk to, and which list are they in?"
    },
    {
      "id": "campaigns",
      "title": "Campaigns",
      "question": "What motion is running against them, and how is it doing?"
    },
    {
      "id": "inbox-outreach",
      "title": "Inbox & outreach",
      "question": "What did they say, and what do we say back?"
    },
    {
      "id": "acting-as",
      "title": "Acting as someone else",
      "question": "Whose seat is this running on?"
    }
  ],
  "tools": [
    {
      "name": "filter_resolve",
      "title": "Resolve a Sales Navigator filter",
      "description": "Resolve a human-readable Sales Navigator filter value (location, industry, function) to a LinkedIn id, echoing the canonical label so a wrong match is visible. Cached globally; pass the returned urn to search_sales_navigator, or let it resolve names for you.",
      "cluster": "list-building",
      "annotations": {
        "readOnly": true,
        "destructive": false,
        "idempotent": true,
        "openWorld": true
      },
      "params": [
        {
          "name": "type",
          "type": "\"location\" | \"industry\" | \"function\" | \"current_company\" | \"past_company\" | \"company_location\" | \"school\" | \"past_role\" | \"groups\" | \"persona\" | \"technologies\" | \"account_lists\" | \"lead_lists\" | \"postal_code\"",
          "required": true
        },
        {
          "name": "query",
          "type": "string",
          "required": true
        }
      ],
      "inputSchema": {
        "$schema": "https://json-schema.org/draft/2020-12/schema",
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "location",
              "industry",
              "function",
              "current_company",
              "past_company",
              "company_location",
              "school",
              "past_role",
              "groups",
              "persona",
              "technologies",
              "account_lists",
              "lead_lists",
              "postal_code"
            ]
          },
          "query": {
            "type": "string",
            "minLength": 1,
            "maxLength": 256
          }
        },
        "required": [
          "type",
          "query"
        ]
      }
    },
    {
      "name": "icp_get",
      "title": "Get an ICP",
      "description": "Read one ICP and its latest (active) version by `icpId`.",
      "cluster": "list-building",
      "annotations": {
        "readOnly": true,
        "destructive": false,
        "idempotent": true,
        "openWorld": false
      },
      "params": [
        {
          "name": "icpId",
          "type": "string",
          "required": true
        }
      ],
      "inputSchema": {
        "$schema": "https://json-schema.org/draft/2020-12/schema",
        "type": "object",
        "properties": {
          "icpId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "icpId"
        ]
      }
    },
    {
      "name": "icp_list",
      "title": "List ICPs",
      "description": "List this org's ICPs, each with its latest (active) version's criteria and conditions.",
      "cluster": "list-building",
      "annotations": {
        "readOnly": true,
        "destructive": false,
        "idempotent": true,
        "openWorld": false
      },
      "params": [],
      "inputSchema": {
        "$schema": "https://json-schema.org/draft/2020-12/schema",
        "type": "object",
        "properties": {}
      }
    },
    {
      "name": "linkedin_fetch",
      "title": "Fetch a LinkedIn profile or company",
      "description": "Fetch a LinkedIn person OR company through the caller's connected account — whichever the target addresses. Address it with `target` — `{ type, value }` where type is url, public_identifier, or provider_id (pass whichever you have). The kind is detected from the target: a `/in/` URL or a bare slug is a person, a `/company/` URL is a company. Pass `kind: 'company'` for a company addressed by universal name or numeric id. Returns `{ kind, profile | company }`; complete data, metered + cached (`refresh: true` forces a live read).",
      "cluster": "list-building",
      "annotations": {
        "readOnly": true,
        "destructive": false,
        "idempotent": true,
        "openWorld": true
      },
      "params": [
        {
          "name": "target",
          "type": "object",
          "required": true
        },
        {
          "name": "kind",
          "type": "\"profile\" | \"company\"",
          "required": false,
          "description": "Override auto-detection. Required for a company addressed by universal name or numeric id."
        },
        {
          "name": "refresh",
          "type": "boolean",
          "required": false
        }
      ],
      "inputSchema": {
        "$schema": "https://json-schema.org/draft/2020-12/schema",
        "type": "object",
        "properties": {
          "target": {
            "oneOf": [
              {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "const": "url"
                  },
                  "value": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 512,
                    "description": "A LinkedIn profile or company URL."
                  }
                },
                "required": [
                  "type",
                  "value"
                ]
              },
              {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "const": "public_identifier"
                  },
                  "value": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 512,
                    "description": "The vanity slug (e.g. \"jane-doe\") or company universal name."
                  }
                },
                "required": [
                  "type",
                  "value"
                ]
              },
              {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "const": "provider_id"
                  },
                  "value": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 512,
                    "description": "Unipile/LinkedIn internal id (e.g. \"ACoAAB…\")."
                  }
                },
                "required": [
                  "type",
                  "value"
                ]
              }
            ]
          },
          "kind": {
            "description": "Override auto-detection. Required for a company addressed by universal name or numeric id.",
            "type": "string",
            "enum": [
              "profile",
              "company"
            ]
          },
          "refresh": {
            "type": "boolean"
          }
        },
        "required": [
          "target"
        ]
      }
    },
    {
      "name": "list_add",
      "title": "Add members to a list",
      "description": "Add members to a list (`{ asset, id, items }`, ≤500 items). Each item is `{ memberId }` (a lead or company already in the org), `{ url }` (a pasted LinkedIn /in/ or /company/ URL — INSTANT and FREE, zero provider calls: creates or converges on a bare member that can be resolved later), OR `{ snapshot }` (a search hit — pass the hit as-is, `providerId` required — which creates/dedups a born-resolved member so the saved list shows the person or company, not a bare id). Per-item results: added | already_member | invalid | not_found. Re-adding a current member converges (already_member). This is how you assemble an audience after a search: pass the result hits straight in.",
      "cluster": "list-building",
      "annotations": {
        "readOnly": false,
        "destructive": false,
        "idempotent": false,
        "openWorld": false
      },
      "params": [
        {
          "name": "asset",
          "type": "\"leads\" | \"companies\"",
          "required": true,
          "description": "Which kind of list: 'leads' (people) or 'companies'."
        },
        {
          "name": "id",
          "type": "string",
          "required": true
        },
        {
          "name": "items",
          "type": "object[]",
          "required": true
        }
      ],
      "inputSchema": {
        "$schema": "https://json-schema.org/draft/2020-12/schema",
        "type": "object",
        "properties": {
          "asset": {
            "type": "string",
            "enum": [
              "leads",
              "companies"
            ],
            "description": "Which kind of list: 'leads' (people) or 'companies'."
          },
          "id": {
            "type": "string",
            "minLength": 1
          },
          "items": {
            "minItems": 1,
            "maxItems": 500,
            "type": "array",
            "items": {
              "anyOf": [
                {
                  "type": "object",
                  "properties": {
                    "memberId": {
                      "type": "string",
                      "minLength": 1
                    }
                  },
                  "required": [
                    "memberId"
                  ]
                },
                {
                  "type": "object",
                  "properties": {
                    "url": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 2048
                    }
                  },
                  "required": [
                    "url"
                  ]
                },
                {
                  "type": "object",
                  "properties": {
                    "snapshot": {
                      "type": "object",
                      "properties": {
                        "providerId": {
                          "type": "string",
                          "minLength": 1
                        },
                        "publicIdentifier": {
                          "type": "string"
                        },
                        "profileUrl": {
                          "type": "string"
                        },
                        "name": {
                          "type": "string"
                        },
                        "headline": {
                          "type": "string"
                        },
                        "company": {
                          "type": "string"
                        },
                        "companyId": {
                          "type": "string"
                        },
                        "industry": {
                          "type": "string"
                        },
                        "location": {
                          "type": "string"
                        },
                        "avatarUrl": {
                          "type": "string"
                        },
                        "description": {
                          "type": "string"
                        },
                        "website": {
                          "type": "string"
                        },
                        "industries": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        },
                        "employeeCount": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991
                        },
                        "followerCount": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991
                        },
                        "hqCity": {
                          "type": "string"
                        },
                        "hqCountry": {
                          "type": "string"
                        },
                        "logoUrl": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "providerId"
                      ]
                    }
                  },
                  "required": [
                    "snapshot"
                  ]
                }
              ]
            }
          }
        },
        "required": [
          "asset",
          "id",
          "items"
        ]
      }
    },
    {
      "name": "list_create",
      "title": "Create a list",
      "description": "Create a named list — the campaign targeting unit. `asset: 'leads'` for a list of people, `asset: 'companies'` for a list of companies (company-first targeting: build the company set, then find people inside it — pass the finished list's id to search_sales_navigator as `companyLists` to do that second step). Names are unique per org and per asset, case-insensitive; a taken name fails with the existing list id (no silent merge). Returns the new list with a member count of 0. Build membership with list_add.",
      "cluster": "list-building",
      "annotations": {
        "readOnly": false,
        "destructive": false,
        "idempotent": false,
        "openWorld": false
      },
      "params": [
        {
          "name": "asset",
          "type": "\"leads\" | \"companies\"",
          "required": true,
          "description": "Which kind of list: 'leads' (people) or 'companies'."
        },
        {
          "name": "name",
          "type": "string",
          "required": true
        }
      ],
      "inputSchema": {
        "$schema": "https://json-schema.org/draft/2020-12/schema",
        "type": "object",
        "properties": {
          "asset": {
            "type": "string",
            "enum": [
              "leads",
              "companies"
            ],
            "description": "Which kind of list: 'leads' (people) or 'companies'."
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          }
        },
        "required": [
          "asset",
          "name"
        ]
      }
    },
    {
      "name": "list_delete",
      "title": "Delete a list",
      "description": "Soft-delete a list by `asset` + `id`: it disappears from list_list with its memberships, the member leads/companies are untouched (they stay in the org pool, in their other lists, with their qualification state intact), and the name is immediately free for reuse.",
      "cluster": "list-building",
      "annotations": {
        "readOnly": false,
        "destructive": true,
        "idempotent": true,
        "openWorld": false
      },
      "params": [
        {
          "name": "asset",
          "type": "\"leads\" | \"companies\"",
          "required": true,
          "description": "Which kind of list: 'leads' (people) or 'companies'."
        },
        {
          "name": "id",
          "type": "string",
          "required": true
        }
      ],
      "inputSchema": {
        "$schema": "https://json-schema.org/draft/2020-12/schema",
        "type": "object",
        "properties": {
          "asset": {
            "type": "string",
            "enum": [
              "leads",
              "companies"
            ],
            "description": "Which kind of list: 'leads' (people) or 'companies'."
          },
          "id": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "asset",
          "id"
        ]
      }
    },
    {
      "name": "list_get",
      "title": "Get one list",
      "description": "One list by `asset` + `id`: its name, live member count, and created date. Out-of-org or deleted ids are not found. To read who is IN it, use list_members.",
      "cluster": "list-building",
      "annotations": {
        "readOnly": true,
        "destructive": false,
        "idempotent": true,
        "openWorld": false
      },
      "params": [
        {
          "name": "asset",
          "type": "\"leads\" | \"companies\"",
          "required": true,
          "description": "Which kind of list: 'leads' (people) or 'companies'."
        },
        {
          "name": "id",
          "type": "string",
          "required": true
        }
      ],
      "inputSchema": {
        "$schema": "https://json-schema.org/draft/2020-12/schema",
        "type": "object",
        "properties": {
          "asset": {
            "type": "string",
            "enum": [
              "leads",
              "companies"
            ],
            "description": "Which kind of list: 'leads' (people) or 'companies'."
          },
          "id": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "asset",
          "id"
        ]
      }
    },
    {
      "name": "list_list",
      "title": "List lists",
      "description": "Read this org's lists of one `asset`, keyset-paginated, newest first, each with its live member count. `q` matches the list name (case-insensitive). Page with the returned `cursor`. Deleted lists never appear.",
      "cluster": "list-building",
      "annotations": {
        "readOnly": true,
        "destructive": false,
        "idempotent": true,
        "openWorld": false
      },
      "params": [
        {
          "name": "asset",
          "type": "\"leads\" | \"companies\"",
          "required": true,
          "description": "Which kind of list: 'leads' (people) or 'companies'."
        },
        {
          "name": "q",
          "type": "string",
          "required": false
        },
        {
          "name": "cursor",
          "type": "string",
          "required": false
        },
        {
          "name": "limit",
          "type": "integer",
          "required": false,
          "default": "25"
        }
      ],
      "inputSchema": {
        "$schema": "https://json-schema.org/draft/2020-12/schema",
        "type": "object",
        "properties": {
          "asset": {
            "type": "string",
            "enum": [
              "leads",
              "companies"
            ],
            "description": "Which kind of list: 'leads' (people) or 'companies'."
          },
          "q": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "cursor": {
            "type": "string",
            "maxLength": 4096
          },
          "limit": {
            "default": 25,
            "type": "integer",
            "minimum": 1,
            "maximum": 100
          }
        },
        "required": [
          "asset"
        ]
      }
    },
    {
      "name": "list_members",
      "title": "Read a list's members",
      "description": "One keyset page of a list's members (`{ asset, id, q?, cursor?, limit? }`), newest-added first. Each row is `{ id, title, subtitle, location, linkedinUrl }` — the id removes it with list_remove, the URL reads it with linkedin_fetch. `q` filters case-insensitively over the member's display fields (name, headline, company, location). Page with the returned `cursor`.",
      "cluster": "list-building",
      "annotations": {
        "readOnly": true,
        "destructive": false,
        "idempotent": true,
        "openWorld": false
      },
      "params": [
        {
          "name": "asset",
          "type": "\"leads\" | \"companies\"",
          "required": true,
          "description": "Which kind of list: 'leads' (people) or 'companies'."
        },
        {
          "name": "id",
          "type": "string",
          "required": true
        },
        {
          "name": "q",
          "type": "string",
          "required": false
        },
        {
          "name": "cursor",
          "type": "string",
          "required": false
        },
        {
          "name": "limit",
          "type": "integer",
          "required": false,
          "default": "25"
        }
      ],
      "inputSchema": {
        "$schema": "https://json-schema.org/draft/2020-12/schema",
        "type": "object",
        "properties": {
          "asset": {
            "type": "string",
            "enum": [
              "leads",
              "companies"
            ],
            "description": "Which kind of list: 'leads' (people) or 'companies'."
          },
          "id": {
            "type": "string",
            "minLength": 1
          },
          "q": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "cursor": {
            "type": "string",
            "maxLength": 4096
          },
          "limit": {
            "default": 25,
            "type": "integer",
            "minimum": 1,
            "maximum": 100
          }
        },
        "required": [
          "asset",
          "id"
        ]
      }
    },
    {
      "name": "list_remove",
      "title": "Remove members from a list",
      "description": "Remove members from a list (`{ asset, id, memberIds }`). Deletes only the membership — the leads/companies stay in the org pool and in their other lists, and can be re-added later. Returns how many memberships were removed.",
      "cluster": "list-building",
      "annotations": {
        "readOnly": false,
        "destructive": false,
        "idempotent": false,
        "openWorld": false
      },
      "params": [
        {
          "name": "asset",
          "type": "\"leads\" | \"companies\"",
          "required": true,
          "description": "Which kind of list: 'leads' (people) or 'companies'."
        },
        {
          "name": "id",
          "type": "string",
          "required": true
        },
        {
          "name": "memberIds",
          "type": "string[]",
          "required": true
        }
      ],
      "inputSchema": {
        "$schema": "https://json-schema.org/draft/2020-12/schema",
        "type": "object",
        "properties": {
          "asset": {
            "type": "string",
            "enum": [
              "leads",
              "companies"
            ],
            "description": "Which kind of list: 'leads' (people) or 'companies'."
          },
          "id": {
            "type": "string",
            "minLength": 1
          },
          "memberIds": {
            "minItems": 1,
            "maxItems": 500,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1
            }
          }
        },
        "required": [
          "asset",
          "id",
          "memberIds"
        ]
      }
    },
    {
      "name": "list_update",
      "title": "Rename a list",
      "description": "Rename a list (`{ asset, id, name }`). Same uniqueness rule as create: a name already taken by another live list of that asset fails with that list id.",
      "cluster": "list-building",
      "annotations": {
        "readOnly": false,
        "destructive": false,
        "idempotent": false,
        "openWorld": false
      },
      "params": [
        {
          "name": "asset",
          "type": "\"leads\" | \"companies\"",
          "required": true,
          "description": "Which kind of list: 'leads' (people) or 'companies'."
        },
        {
          "name": "id",
          "type": "string",
          "required": true
        },
        {
          "name": "name",
          "type": "string",
          "required": true
        }
      ],
      "inputSchema": {
        "$schema": "https://json-schema.org/draft/2020-12/schema",
        "type": "object",
        "properties": {
          "asset": {
            "type": "string",
            "enum": [
              "leads",
              "companies"
            ],
            "description": "Which kind of list: 'leads' (people) or 'companies'."
          },
          "id": {
            "type": "string",
            "minLength": 1
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          }
        },
        "required": [
          "asset",
          "id",
          "name"
        ]
      }
    },
    {
      "name": "profile_posts",
      "title": "A profile's recent posts",
      "description": "A page of a profile's recent posts (transient — not persisted). Address the person with `target` — `{ type, value }` (url, public_identifier, or provider_id). Use `cursor` to page; one page is one metered action.",
      "cluster": "list-building",
      "annotations": {
        "readOnly": true,
        "destructive": false,
        "idempotent": true,
        "openWorld": true
      },
      "params": [
        {
          "name": "target",
          "type": "object",
          "required": true
        },
        {
          "name": "cursor",
          "type": "string",
          "required": false
        }
      ],
      "inputSchema": {
        "$schema": "https://json-schema.org/draft/2020-12/schema",
        "type": "object",
        "properties": {
          "target": {
            "oneOf": [
              {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "const": "url"
                  },
                  "value": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 512,
                    "description": "A LinkedIn profile or company URL."
                  }
                },
                "required": [
                  "type",
                  "value"
                ]
              },
              {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "const": "public_identifier"
                  },
                  "value": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 512,
                    "description": "The vanity slug (e.g. \"jane-doe\") or company universal name."
                  }
                },
                "required": [
                  "type",
                  "value"
                ]
              },
              {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "const": "provider_id"
                  },
                  "value": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 512,
                    "description": "Unipile/LinkedIn internal id (e.g. \"ACoAAB…\")."
                  }
                },
                "required": [
                  "type",
                  "value"
                ]
              }
            ]
          },
          "cursor": {
            "type": "string",
            "maxLength": 4096
          }
        },
        "required": [
          "target"
        ]
      }
    },
    {
      "name": "search_people",
      "title": "Search people (classic)",
      "description": "Classic LinkedIn people search — works WITHOUT a Sales Navigator seat. Pass `keywords` and/or structured filters: id-resolved `filters` ({type,query} over location/industry/company/past_company/school/service — pass human-readable NAMES, resolved to ids server-side — a name LinkedIn does not recognize REFUSES the search with `CHANNEL_ACTION_FILTER_UNRESOLVED` naming it, rather than running without that filter and quietly returning a wider audience; re-issue with a name LinkedIn uses, or drop the filter if you meant the broader search), `networkDistance` (1|2|3), `profileLanguage` (ISO codes), `openTo`, `connectionsOf`/`followersOf` (member ids from people.suggest), `advancedKeywords` (first/last/title/company/school). Or paste a search `url` to run it verbatim. Transient hits + a cursor; one page is one metered action. To persist a hit, call profile_fetch on it.",
      "cluster": "list-building",
      "annotations": {
        "readOnly": true,
        "destructive": false,
        "idempotent": true,
        "openWorld": true
      },
      "params": [
        {
          "name": "url",
          "type": "string",
          "required": false
        },
        {
          "name": "keywords",
          "type": "string",
          "required": false
        },
        {
          "name": "cursor",
          "type": "string",
          "required": false
        },
        {
          "name": "limit",
          "type": "integer",
          "required": false,
          "description": "Page size for paging (default 10). Classic search is clamped to 50 provider-side (Sales Nav allows 100). Set by \"Load all\", not by the agent."
        },
        {
          "name": "filters",
          "type": "object[]",
          "required": false
        },
        {
          "name": "networkDistance",
          "type": "1 | 2 | 3[]",
          "required": false,
          "description": "Connection degree: 1 (1st), 2 (2nd), 3 (3rd+). LinkedIn native filter CONNECTIONS."
        },
        {
          "name": "profileLanguage",
          "type": "string[]",
          "required": false,
          "description": "Profile languages as 2-letter ISO-639-1 codes (e.g. [\"en\",\"es\"])."
        },
        {
          "name": "openTo",
          "type": "\"proBono\" | \"boardMember\"[]",
          "required": false
        },
        {
          "name": "connectionsOf",
          "type": "string[]",
          "required": false,
          "description": "Member ids whose connections to search within (from people.suggest)."
        },
        {
          "name": "followersOf",
          "type": "string[]",
          "required": false,
          "description": "Member ids whose followers to search within (from people.suggest)."
        },
        {
          "name": "advancedKeywords",
          "type": "object",
          "required": false
        }
      ],
      "inputSchema": {
        "$schema": "https://json-schema.org/draft/2020-12/schema",
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "minLength": 1,
            "maxLength": 2048
          },
          "keywords": {
            "type": "string",
            "minLength": 1,
            "maxLength": 2000
          },
          "cursor": {
            "type": "string",
            "maxLength": 4096
          },
          "limit": {
            "description": "Page size for paging (default 10). Classic search is clamped to 50 provider-side (Sales Nav allows 100). Set by \"Load all\", not by the agent.",
            "type": "integer",
            "minimum": 1,
            "maximum": 100
          },
          "filters": {
            "maxItems": 40,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "type": {
                  "type": "string",
                  "enum": [
                    "location",
                    "industry",
                    "company",
                    "past_company",
                    "school",
                    "service"
                  ],
                  "description": "Which id-resolved dimension: location, industry, company, past_company, school, service."
                },
                "query": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 256,
                  "description": "The value as a human-readable NAME (never an id). Phrase it the way LinkedIn names things — canonical industry names (\"Financial Services\", not \"fintech\"), real place names (\"United States\", \"Greater Madrid Metropolitan Area\"). The best single typeahead match is resolved and its label echoed back."
                }
              },
              "required": [
                "type",
                "query"
              ]
            }
          },
          "networkDistance": {
            "description": "Connection degree: 1 (1st), 2 (2nd), 3 (3rd+). LinkedIn native filter CONNECTIONS.",
            "minItems": 1,
            "type": "array",
            "items": {
              "anyOf": [
                {
                  "type": "number",
                  "const": 1
                },
                {
                  "type": "number",
                  "const": 2
                },
                {
                  "type": "number",
                  "const": 3
                }
              ]
            }
          },
          "profileLanguage": {
            "description": "Profile languages as 2-letter ISO-639-1 codes (e.g. [\"en\",\"es\"]).",
            "minItems": 1,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 2,
              "maxLength": 2
            }
          },
          "openTo": {
            "minItems": 1,
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "proBono",
                "boardMember"
              ]
            }
          },
          "connectionsOf": {
            "description": "Member ids whose connections to search within (from people.suggest).",
            "minItems": 1,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1
            }
          },
          "followersOf": {
            "description": "Member ids whose followers to search within (from people.suggest).",
            "minItems": 1,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1
            }
          },
          "advancedKeywords": {
            "type": "object",
            "properties": {
              "firstName": {
                "type": "string",
                "minLength": 1,
                "maxLength": 128
              },
              "lastName": {
                "type": "string",
                "minLength": 1,
                "maxLength": 128
              },
              "title": {
                "type": "string",
                "minLength": 1,
                "maxLength": 256
              },
              "company": {
                "type": "string",
                "minLength": 1,
                "maxLength": 256
              },
              "school": {
                "type": "string",
                "minLength": 1,
                "maxLength": 256
              }
            }
          }
        }
      }
    },
    {
      "name": "search_sales_navigator",
      "title": "Search (Sales Navigator)",
      "description": "Search LinkedIn Sales Navigator over people OR companies. This is the expert path: prefer it over classic keyword search whenever a structured filter fits the intent — filters are precise where keywords are noisy.\n\nHOW FILTERS WORK\n• `filters` are human-readable, id-resolved dimensions `{ type, query, mode? }`. You pass a NAME (e.g. `{ type: \"industry\", query: \"Financial Services\" }`); the server resolves it to a LinkedIn id for you — never pass ids. `mode` is \"include\" (default) or \"exclude\".\n• Phrase each `query` the way LinkedIn names things: canonical industry names (\"Financial Services\", not \"fintech\"), real place names (\"Greater Madrid Metropolitan Area\" or the country, not a neighborhood). Resolution takes the single best typeahead match.\n• Every other dimension is a typed field (seniority, role, companyHeadcount, …) — read each field's description for when to use it.\n\nCOMBINING FILTERS — this determines your results:\n• Multiple values of the SAME dimension are OR'd (industry [\"Financial Services\",\"Banking\"] = either).\n• DIFFERENT dimensions are AND'd (industry AND location AND seniority). Each dimension you add NARROWS the result set — add them one intent at a time and stop before you over-constrain to zero.\n\nEXCLUSIONS — your primary tool for removing who does NOT belong. Almost every dimension takes an exclude side, and you should reach for it whenever a broad filter sweeps in an obvious wrong segment (a positive filter alone often cannot express \"leaders but NOT recruiters\"):\n• `role.exclude` — drop unwanted current-title words: e.g. searching \"growth leaders\" but flooded with agencies/recruiters → `role:{ include:[…], exclude:[\"recruiter\",\"talent\",\"agency\",\"assistant\",\"intern\",\"student\"] }`. This is usually the highest-leverage exclusion.\n• `seniority.exclude` — drop levels you do not want (e.g. exclude [\"entry_level\",\"training\",\"unpaid\"] when you want decision-makers).\n• id-resolved `filters` with `mode:\"exclude\"` — drop a whole industry, company, or location: e.g. `{ type:\"industry\", query:\"Staffing and Recruiting\", mode:\"exclude\" }`, or exclude a competitor via `{ type:\"current_company\", query:\"Acme\", mode:\"exclude\" }`.\n• Use exclusions proactively in your FIRST search when the ask implies an obvious anti-segment, and reactively when the echoed hits show a recurring wrong type — name the exclusion in your read-back and apply it next turn.\n\nLOCATIONS — expand regions to countries:\n• A region/continent does NOT resolve as one id (\"LATAM\", \"Europe\", \"APAC\" will fail). Emit ONE location filter PER country (same dimension repeated = OR). LATAM → Argentina, Brazil, Mexico, Colombia, Chile, Peru, Ecuador, Uruguay, Costa Rica, Panama (+ more as relevant). A single named country → just that country. Never invent locations the user did not name.\n\nPEOPLE — TITLES (`role`) beat the coarse ladder. This is the highest-leverage filter; get it right:\n• `role` matches ONLY the CURRENT job-title field (title-scoped keywords, include/exclude) — NOT the whole profile. That is why it beats `keywords` for any title intent: trust it, do not fall back to `keywords` for a title. (`keywords` matches every text on the profile, so it is far noisier.)\n• For a PAST title (\"used to be a CFO\", \"previously a founder\"), use the id-resolved `past_role` filter — `filters:[{ type:\"past_role\", query:\"Chief Financial Officer\" }]` (JOB_TITLE typeahead; supports mode:\"exclude\"). `role` is current-only; `past_role` is the only way to filter on prior titles.\n• A job TITLE goes in `role` (title-keyword include/exclude). Use `seniority` (cxo, vice_president, director…) ONLY for a pure level with no title intent — for \"leaders of X\" the seniority block below recalls far better.\n• Exec / C-suite titles and founder are SINGLE-TITLE pills: one `role.include` entry per variant, standing alone — \"CEO\", \"Chief Executive Officer\", \"Founder\", \"Fundador\", \"Fundadora\", \"Cofounder\", \"Co-founder\". Never wrap these in a seniority block.\n• SENIORITY BLOCK — THE DEFAULT FOR ANY LEADERSHIP INTENT. The moment you read the ask as *the people who LEAD or DECIDE on some area* — \"heads of growth\", \"payment managers\", \"gerentes de cobranzas\", \"marketing decision-makers\", \"whoever owns billing\", \"the person in charge of ops\" — emit ONE seniority-block pill: a marker AND a parenthesized OR-list of ROLE synonyms, e.g. `<<SENIORITY_BLOCK_EN>> AND (\"payments\" OR \"billing\" OR \"collections\")`. The marker expands server-side to a broad leadership OR-block (head/VP/director/manager/chief…), so you recall the WHOLE pyramid — a hand-enumerated title list always misses the variants real people actually use. Put only role words in the OR-list (never seniority words), quote each term, AND/OR uppercase. At most ONE seniority-block pill per search.\n• Reach for the block by DEFAULT: whenever the audience is leaders/owners/decision-makers of a domain, the block belongs in the search. B2B outbound almost always targets a decision-maker, so a people search WITHOUT a seniority block should be the rare exception, and you should be able to name why. The only real exceptions: (a) the ask is exec/C-suite/founder ONLY → single-title pills instead (see above); (b) the ask names a SPECIFIC non-leadership title with no leadership intent (\"data engineer\", \"recruiter\", \"designer\") → plain title pills; (c) the ask is a PURE level with no domain (\"all VPs, any function\") → `seniority` alone. Anything that reads as \"the leaders of X\" gets the block — do not settle for a bare role keyword and do not hand-enumerate the ladder.\n• Marker by language: Spanish geo/terms (Mexico, Spain, LATAM, \"gerente\",\"jefe\") → <<SENIORITY_BLOCK_ES_EN>> with Spanish+English role synonyms; Brazil / Portuguese terms → <<SENIORITY_BLOCK_PT_EN>> with Portuguese+English; otherwise → <<SENIORITY_BLOCK_EN>> (English only).\n• Top-of-pyramid: when asking for leaders of a department, ALSO add the matching C-title as its own single-title pill — HR→CHRO, Marketing→CMO, Finance→CFO, Tech/Engineering→CTO, Operations→COO, Product→CPO.\n\nCLOSE THE LOOP — every search echoes back the filters AS RESOLVED (`query → label`, or a failure) plus a hit count. ALWAYS read it:\n• Wrong resolution (you said \"Apple\", it resolved to the wrong entity) → re-issue with a more specific query.\n• A filter that did not resolve REFUSES the whole search (`CHANNEL_ACTION_FILTER_UNRESOLVED`, naming which one) — it is never dropped, because running without it would silently widen your audience. Re-issue with a name LinkedIn uses (canonical industry name, real place name), or drop the filter yourself if you meant the broader search.\n• Targeting people at companies you already hold as a Kairon company list? Pass `companyLists: [{ id }]` (`mode:\"exclude\"` to suppress a set) — NOT `account_lists`, which is Sales Navigator's own saved lists. Never enumerate the companies as `current_company` filters when you have the list id: that costs a call per name and caps at 40.\n• Zero or too-few hits → loosen: drop the narrowest dimension, widen a range, or broaden the role OR-list.\n• Too many hits, OR the hits include a recurring wrong segment (recruiters, students, the wrong industry) → add an EXCLUSION (see EXCLUSIONS) before adding more positive filters — it removes the noise without shrinking the real audience.\n\nCOMMON TRAPS\n• \"Startup\" / \"scale-up\" is NOT a filter — approximate it by SIZE, and the size field DEPENDS ON CATEGORY. On a PEOPLE search: small `companyHeadcount` buckets ([\"1-10\",\"11-50\",\"51-200\"]), optionally `companyType: [\"privately_held\"]`. On a COMPANIES search: small `headcount` buckets ([\"1-10\",\"11-50\",\"51-200\"]) — a companies search has NO company-type facet, so do NOT send `companyType` (nor `companyHeadcount`) on it; both are people-search-only and the search will reject them.\n• Industry uses LinkedIn's canonical names in an `industry` filter (\"Financial Services\", \"Banking\" — NOT \"fintech\"); add related categories as OR values. A business model / product (\"fintech\", \"SaaS\", \"marketplace\") describes WHAT a company does → that is `keywords`, not `industry`.\n• `keywords` is a LAST resort — ONLY skills/tools/tech the user EXPLICITLY named (e.g. \"Workday\", \"Kubernetes\"). Never derive keywords from a role, title, location, or industry; each has its own filter.\n• `keywords` is a BOOLEAN query, not a phrase. Bare space-separated words are AND-ed — `fintech payments neobank` demands all three in one profile and returns ZERO. For alternatives, OR + quote each term AND wrap the whole group in parentheses: `(\"fintech\" OR \"payments\" OR \"neobank\")`. The parentheses are MANDATORY — an unparenthesized OR of 4+ terms is silently mis-parsed by LinkedIn and returns ~0 even though it looks right. Quote multi-word phrases; combine groups with AND/NOT; operators UPPERCASE. If a keyword search returns zero, suspect (a) missing parentheses around the OR group and (b) implicit-AND, and re-issue before dropping terms.\n\nWORKED EXAMPLES (natural language → filters)\n• \"Payment managers / gerentes de pagos in LATAM\" → category:people, role:{include:[\"<<SENIORITY_BLOCK_ES_EN>> AND (\\\"pagos\\\" OR \\\"payments\\\" OR \\\"medios de pago\\\" OR \\\"billing\\\" OR \\\"cobranzas\\\")\"]}, filters:[{type:\"location\",query:\"Mexico\"},{type:\"location\",query:\"Brazil\"},{type:\"location\",query:\"Colombia\"},{type:\"location\",query:\"Argentina\"}].\n• \"Marketing leaders in the US\" → category:people, role:{include:[\"CMO\",\"Chief Marketing Officer\",\"<<SENIORITY_BLOCK_EN>> AND (\\\"marketing\\\" OR \\\"branding\\\" OR \\\"growth\\\" OR \\\"demand generation\\\")\"]}, filters:[{type:\"location\",query:\"United States\"}].\n• \"CEOs and founders in Argentina\" → category:people, role:{include:[\"CEO\",\"Chief Executive Officer\",\"Founder\",\"Fundador\",\"Fundadora\",\"Cofounder\",\"Co-founder\"]}, filters:[{type:\"location\",query:\"Argentina\"}].\n• \"VP-level engineers at Berlin startups\" (pure level + a title word) → category:people, seniority:{include:[\"vice_president\"]}, role:{include:[\"Engineering\"]}, filters:[{type:\"location\",query:\"Berlin, Germany\"}], companyHeadcount:[\"1-10\",\"11-50\",\"51-200\"].\n• \"Fintech companies in LATAM, 50–200 staff\" → category:companies, filters:[{type:\"industry\",query:\"Financial Services\"},{type:\"industry\",query:\"Banking\"},{type:\"location\",query:\"Mexico\"},{type:\"location\",query:\"Brazil\"},{type:\"location\",query:\"Colombia\"}], headcount:[\"51-200\"], keywords:\"fintech\".\n\nRequires the connected account to hold a Sales Navigator seat. Transient hits + a cursor; page with the returned cursor. One page is one metered action.",
      "cluster": "list-building",
      "annotations": {
        "readOnly": true,
        "destructive": false,
        "idempotent": true,
        "openWorld": true
      },
      "params": [
        {
          "name": "category",
          "type": "\"people\" | \"companies\"",
          "required": false,
          "description": "Search people (default) or companies. Some fields are valid for only one category.",
          "default": "\"people\""
        },
        {
          "name": "keywords",
          "type": "string",
          "required": false,
          "description": "LAST resort — matches noisily across all text. Prefer a structured filter for any title/industry/geography/size intent; use keywords only for a concept no filter captures. This is a BOOLEAN query, not a phrase: bare space-separated words are AND-ed (ALL must appear), so \"fintech payments neobank\" requires all three together and usually returns ZERO. For ALTERNATIVES, OR them, quote each, and ALWAYS wrap the OR group in parentheses: `(\"fintech\" OR \"payments\" OR \"neobank\")`. The parentheses are MANDATORY — LinkedIn silently mis-parses an unparenthesized OR of 4+ terms and returns ~0. Quote multi-word phrases; combine groups with AND/NOT (e.g. `(\"fintech\" OR \"neobank\") AND \"payments\"`). Operators must be UPPERCASE."
        },
        {
          "name": "filters",
          "type": "object[]",
          "required": false,
          "description": "Id-resolved dimensions (location, industry, company, …). Same dimension repeated = OR; different dimensions = AND (each narrows the results)."
        },
        {
          "name": "cursor",
          "type": "string",
          "required": false,
          "description": "Pass the cursor from a prior result to page."
        },
        {
          "name": "limit",
          "type": "integer",
          "required": false,
          "description": "Page size (max 100 for Sales Nav; default 10). Used when paging, not by the agent."
        },
        {
          "name": "firstName",
          "type": "string",
          "required": false
        },
        {
          "name": "lastName",
          "type": "string",
          "required": false
        },
        {
          "name": "role",
          "type": "object",
          "required": false,
          "description": "Current job-TITLE keywords (include/exclude) — the primary people filter. Use it for ALL title intent, NOT `keywords` and NOT `seniority`. Each include entry is a separate Boolean title clause LinkedIn ORs. Two kinds: (1) single-title pills — exact exec titles + founder, one entry per variant (e.g. \"CEO\",\"Chief Executive Officer\",\"Founder\",\"Fundador\"); (2) ONE seniority-block pill for broad leadership roles: a marker AND a parenthesized OR-list of role synonyms, e.g. `<<SENIORITY_BLOCK_EN>> AND (\"growth\" OR \"demand generation\")`. The marker (one of <<SENIORITY_BLOCK_EN>> / <<SENIORITY_BLOCK_ES_EN>> / <<SENIORITY_BLOCK_PT_EN>>, by language) expands server-side to a broad leadership OR-block so you recall heads/VPs/directors/managers without enumerating titles. See the playbook for the full recipe."
        },
        {
          "name": "seniority",
          "type": "object",
          "required": false,
          "description": "LinkedIn's coarse seniority ladder (cxo, vice_president, director, senior, …) — NOT job titles. Use only when you mean a seniority level; pair with `role` for \"VP-level whose title contains X\"."
        },
        {
          "name": "tenure",
          "type": "object[]",
          "required": false,
          "description": "Years at the current company in their current role, as {min,max} ranges. Years MUST be LinkedIn bucket breakpoints — valid min: 0, 1, 3, 6, 10; valid max: 1, 2, 5, 10 (buckets <1, 1-2, 3-5, 6-10, 10+). Any other value (e.g. min:5 or min:2) is rejected. So \"5+ years\" → {min:6}; \"3+ years\" → {min:3}; \"3 to 5 years\" → {min:3,max:5}."
        },
        {
          "name": "tenureAtCompany",
          "type": "object[]",
          "required": false,
          "description": "Total years at the current company, as {min,max} ranges. Years MUST be LinkedIn bucket breakpoints — valid min: 0, 1, 3, 6, 10; valid max: 1, 2, 5, 10 (buckets <1, 1-2, 3-5, 6-10, 10+). Any other value (e.g. min:5 or min:2) is rejected. So \"5+ years\" → {min:6}; \"3+ years\" → {min:3}; \"3 to 5 years\" → {min:3,max:5}."
        },
        {
          "name": "tenureAtRole",
          "type": "object[]",
          "required": false,
          "description": "Years in the current role, as {min,max} ranges. Years MUST be LinkedIn bucket breakpoints — valid min: 0, 1, 3, 6, 10; valid max: 1, 2, 5, 10 (buckets <1, 1-2, 3-5, 6-10, 10+). Any other value (e.g. min:5 or min:2) is rejected. So \"5+ years\" → {min:6}; \"3+ years\" → {min:3}; \"3 to 5 years\" → {min:3,max:5}."
        },
        {
          "name": "companyHeadcount",
          "type": "\"1-10\" | \"11-50\" | \"51-200\" | \"201-500\" | \"501-1000\" | \"1001-5000\" | \"5001-10000\" | \"10001+\"[]",
          "required": false,
          "description": "Size band of the person's current employer (people search). For a company's OWN size use `headcount`. Approximate \"startup\" with small buckets ([\"1-10\",\"11-50\",\"51-200\"])."
        },
        {
          "name": "companyType",
          "type": "\"public_company\" | \"privately_held\" | \"non_profit\" | \"educational_institution\" | \"partnership\" | \"self_employed\" | \"self_owned\" | \"government_agency\"[]",
          "required": false,
          "description": "Ownership type of the person's current employer (people search; e.g. privately_held, public_company). A companies search has no company-type facet."
        },
        {
          "name": "profileLanguage",
          "type": "string[]",
          "required": false,
          "description": "Profile languages as 2-letter ISO codes (e.g. [\"en\",\"es\"])."
        },
        {
          "name": "networkDistance",
          "type": "1 | 2 | 3 | \"GROUP\"[]",
          "required": false,
          "description": "Connection degree from the seat: 1 / 2 / 3 — valid for BOTH people and companies. The \"GROUP\" value (shared group) is PEOPLE only; do not use it on a companies search."
        },
        {
          "name": "connectionsOf",
          "type": "string[]",
          "required": false,
          "description": "Member ids whose connections to search within."
        },
        {
          "name": "changedJobs",
          "type": "boolean",
          "required": false,
          "description": "Spotlight: only people who recently changed jobs."
        },
        {
          "name": "postedOnLinkedin",
          "type": "boolean",
          "required": false
        },
        {
          "name": "mentionedInNews",
          "type": "boolean",
          "required": false
        },
        {
          "name": "followingYourCompany",
          "type": "boolean",
          "required": false
        },
        {
          "name": "pastColleague",
          "type": "boolean",
          "required": false
        },
        {
          "name": "sharedExperiences",
          "type": "boolean",
          "required": false
        },
        {
          "name": "viewedYourProfileRecently",
          "type": "boolean",
          "required": false
        },
        {
          "name": "viewedProfileRecently",
          "type": "boolean",
          "required": false
        },
        {
          "name": "messagedRecently",
          "type": "boolean",
          "required": false
        },
        {
          "name": "includeSavedLeads",
          "type": "boolean",
          "required": false
        },
        {
          "name": "includeSavedAccounts",
          "type": "boolean",
          "required": false
        },
        {
          "name": "hasJobOffers",
          "type": "boolean",
          "required": false,
          "description": "Company search: only companies currently hiring."
        },
        {
          "name": "headcount",
          "type": "\"1-10\" | \"11-50\" | \"51-200\" | \"201-500\" | \"501-1000\" | \"1001-5000\" | \"5001-10000\" | \"10001+\"[]",
          "required": false,
          "description": "The company's OWN size band (companies search; the analog of people-search `companyHeadcount`). Approximate \"startup\" with small buckets ([\"1-10\",\"11-50\",\"51-200\"])."
        },
        {
          "name": "headcountGrowth",
          "type": "object",
          "required": false,
          "description": "Company headcount growth rate as a {min,max} percentage range."
        },
        {
          "name": "annualRevenue",
          "type": "object",
          "required": false,
          "description": "Company annual revenue {currency (ISO 4217), min, max} in millions. Both min AND max are required and MUST be breakpoints: 0, 0.2, 1, 2.5, 5, 10, 20, 50, 100, 500, 1000, 1001."
        },
        {
          "name": "followersCount",
          "type": "object[]",
          "required": false,
          "description": "Company follower count {min,max} ranges. Breakpoints — min: 1, 51, 101, 1001, 5001; max: 50, 100, 1000, 5000."
        },
        {
          "name": "fortune",
          "type": "object[]",
          "required": false,
          "description": "Fortune ranking {min,max} ranges (e.g. Fortune 500). Breakpoints — min: 0, 51, 101, 251; max: 50, 100, 250, 500."
        },
        {
          "name": "recentActivities",
          "type": "\"senior_leadership_changes\" | \"funding_events\"[]",
          "required": false,
          "description": "Company signals: senior_leadership_changes and/or funding_events."
        },
        {
          "name": "departmentHeadcount",
          "type": "object",
          "required": false
        },
        {
          "name": "departmentHeadcountGrowth",
          "type": "object",
          "required": false
        },
        {
          "name": "savedAccounts",
          "type": "string[]",
          "required": false
        },
        {
          "name": "savedSearchId",
          "type": "string",
          "required": false
        },
        {
          "name": "recentSearchId",
          "type": "string",
          "required": false
        },
        {
          "name": "lastViewedAt",
          "type": "number",
          "required": false
        },
        {
          "name": "withinArea",
          "type": "number",
          "required": false
        },
        {
          "name": "companyLists",
          "type": "object[]",
          "required": false,
          "description": "Scope a PEOPLE search to the companies in your own Kairon company lists (`list_list`, asset \"companies\"). The server expands each list to its companies' LinkedIn ids as a current_company filter — no per-company resolution, no 40-filter ceiling. NOT `account_lists`, which means Sales Navigator's own saved lists and will not match a Kairon list. People category only."
        }
      ],
      "inputSchema": {
        "$schema": "https://json-schema.org/draft/2020-12/schema",
        "type": "object",
        "properties": {
          "category": {
            "default": "people",
            "description": "Search people (default) or companies. Some fields are valid for only one category.",
            "type": "string",
            "enum": [
              "people",
              "companies"
            ]
          },
          "keywords": {
            "description": "LAST resort — matches noisily across all text. Prefer a structured filter for any title/industry/geography/size intent; use keywords only for a concept no filter captures. This is a BOOLEAN query, not a phrase: bare space-separated words are AND-ed (ALL must appear), so \"fintech payments neobank\" requires all three together and usually returns ZERO. For ALTERNATIVES, OR them, quote each, and ALWAYS wrap the OR group in parentheses: `(\"fintech\" OR \"payments\" OR \"neobank\")`. The parentheses are MANDATORY — LinkedIn silently mis-parses an unparenthesized OR of 4+ terms and returns ~0. Quote multi-word phrases; combine groups with AND/NOT (e.g. `(\"fintech\" OR \"neobank\") AND \"payments\"`). Operators must be UPPERCASE.",
            "type": "string",
            "minLength": 1,
            "maxLength": 2000
          },
          "filters": {
            "description": "Id-resolved dimensions (location, industry, company, …). Same dimension repeated = OR; different dimensions = AND (each narrows the results).",
            "maxItems": 40,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "type": {
                  "type": "string",
                  "enum": [
                    "location",
                    "industry",
                    "function",
                    "current_company",
                    "past_company",
                    "company_location",
                    "school",
                    "past_role",
                    "groups",
                    "persona",
                    "technologies",
                    "account_lists",
                    "lead_lists",
                    "postal_code"
                  ],
                  "description": "Which id-resolved dimension. People: location, industry, function, current_company, past_company, company_location, school, past_role, groups, persona, account_lists, lead_lists, postal_code. Companies: location, industry, technologies, company_location, account_lists, lead_lists, postal_code."
                },
                "query": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 256,
                  "description": "The value as a human-readable NAME (never an id). Phrase it the way LinkedIn names things — canonical industry names (\"Financial Services\", not \"fintech\"), real place names (\"Greater Madrid Metropolitan Area\" or the country). Resolution takes the best single typeahead match and echoes the resolved label back."
                },
                "mode": {
                  "description": "\"include\" (default) requires the value; \"exclude\" filters it out.",
                  "type": "string",
                  "enum": [
                    "include",
                    "exclude"
                  ]
                }
              },
              "required": [
                "type",
                "query"
              ]
            }
          },
          "cursor": {
            "description": "Pass the cursor from a prior result to page.",
            "type": "string",
            "maxLength": 4096
          },
          "limit": {
            "description": "Page size (max 100 for Sales Nav; default 10). Used when paging, not by the agent.",
            "type": "integer",
            "minimum": 1,
            "maximum": 100
          },
          "firstName": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128
          },
          "lastName": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128
          },
          "role": {
            "description": "Current job-TITLE keywords (include/exclude) — the primary people filter. Use it for ALL title intent, NOT `keywords` and NOT `seniority`. Each include entry is a separate Boolean title clause LinkedIn ORs. Two kinds: (1) single-title pills — exact exec titles + founder, one entry per variant (e.g. \"CEO\",\"Chief Executive Officer\",\"Founder\",\"Fundador\"); (2) ONE seniority-block pill for broad leadership roles: a marker AND a parenthesized OR-list of role synonyms, e.g. `<<SENIORITY_BLOCK_EN>> AND (\"growth\" OR \"demand generation\")`. The marker (one of <<SENIORITY_BLOCK_EN>> / <<SENIORITY_BLOCK_ES_EN>> / <<SENIORITY_BLOCK_PT_EN>>, by language) expands server-side to a broad leadership OR-block so you recall heads/VPs/directors/managers without enumerating titles. See the playbook for the full recipe.",
            "type": "object",
            "properties": {
              "include": {
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1
                }
              },
              "exclude": {
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1
                }
              }
            }
          },
          "seniority": {
            "description": "LinkedIn's coarse seniority ladder (cxo, vice_president, director, senior, …) — NOT job titles. Use only when you mean a seniority level; pair with `role` for \"VP-level whose title contains X\".",
            "type": "object",
            "properties": {
              "include": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "owner/partner",
                    "cxo",
                    "vice_president",
                    "director",
                    "experienced_manager",
                    "entry_level_manager",
                    "strategic",
                    "senior",
                    "entry_level",
                    "in_training"
                  ]
                }
              },
              "exclude": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "owner/partner",
                    "cxo",
                    "vice_president",
                    "director",
                    "experienced_manager",
                    "entry_level_manager",
                    "strategic",
                    "senior",
                    "entry_level",
                    "in_training"
                  ]
                }
              }
            }
          },
          "tenure": {
            "description": "Years at the current company in their current role, as {min,max} ranges. Years MUST be LinkedIn bucket breakpoints — valid min: 0, 1, 3, 6, 10; valid max: 1, 2, 5, 10 (buckets <1, 1-2, 3-5, 6-10, 10+). Any other value (e.g. min:5 or min:2) is rejected. So \"5+ years\" → {min:6}; \"3+ years\" → {min:3}; \"3 to 5 years\" → {min:3,max:5}.",
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "min": {
                  "type": "number"
                },
                "max": {
                  "type": "number"
                }
              }
            }
          },
          "tenureAtCompany": {
            "description": "Total years at the current company, as {min,max} ranges. Years MUST be LinkedIn bucket breakpoints — valid min: 0, 1, 3, 6, 10; valid max: 1, 2, 5, 10 (buckets <1, 1-2, 3-5, 6-10, 10+). Any other value (e.g. min:5 or min:2) is rejected. So \"5+ years\" → {min:6}; \"3+ years\" → {min:3}; \"3 to 5 years\" → {min:3,max:5}.",
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "min": {
                  "type": "number"
                },
                "max": {
                  "type": "number"
                }
              }
            }
          },
          "tenureAtRole": {
            "description": "Years in the current role, as {min,max} ranges. Years MUST be LinkedIn bucket breakpoints — valid min: 0, 1, 3, 6, 10; valid max: 1, 2, 5, 10 (buckets <1, 1-2, 3-5, 6-10, 10+). Any other value (e.g. min:5 or min:2) is rejected. So \"5+ years\" → {min:6}; \"3+ years\" → {min:3}; \"3 to 5 years\" → {min:3,max:5}.",
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "min": {
                  "type": "number"
                },
                "max": {
                  "type": "number"
                }
              }
            }
          },
          "companyHeadcount": {
            "description": "Size band of the person's current employer (people search). For a company's OWN size use `headcount`. Approximate \"startup\" with small buckets ([\"1-10\",\"11-50\",\"51-200\"]).",
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "1-10",
                "11-50",
                "51-200",
                "201-500",
                "501-1000",
                "1001-5000",
                "5001-10000",
                "10001+"
              ]
            }
          },
          "companyType": {
            "description": "Ownership type of the person's current employer (people search; e.g. privately_held, public_company). A companies search has no company-type facet.",
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "public_company",
                "privately_held",
                "non_profit",
                "educational_institution",
                "partnership",
                "self_employed",
                "self_owned",
                "government_agency"
              ]
            }
          },
          "profileLanguage": {
            "description": "Profile languages as 2-letter ISO codes (e.g. [\"en\",\"es\"]).",
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 2,
              "maxLength": 2
            }
          },
          "networkDistance": {
            "description": "Connection degree from the seat: 1 / 2 / 3 — valid for BOTH people and companies. The \"GROUP\" value (shared group) is PEOPLE only; do not use it on a companies search.",
            "type": "array",
            "items": {
              "anyOf": [
                {
                  "type": "number",
                  "const": 1
                },
                {
                  "type": "number",
                  "const": 2
                },
                {
                  "type": "number",
                  "const": 3
                },
                {
                  "type": "string",
                  "const": "GROUP"
                }
              ]
            }
          },
          "connectionsOf": {
            "description": "Member ids whose connections to search within.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "changedJobs": {
            "description": "Spotlight: only people who recently changed jobs.",
            "type": "boolean"
          },
          "postedOnLinkedin": {
            "type": "boolean"
          },
          "mentionedInNews": {
            "type": "boolean"
          },
          "followingYourCompany": {
            "type": "boolean"
          },
          "pastColleague": {
            "type": "boolean"
          },
          "sharedExperiences": {
            "type": "boolean"
          },
          "viewedYourProfileRecently": {
            "type": "boolean"
          },
          "viewedProfileRecently": {
            "type": "boolean"
          },
          "messagedRecently": {
            "type": "boolean"
          },
          "includeSavedLeads": {
            "type": "boolean"
          },
          "includeSavedAccounts": {
            "type": "boolean"
          },
          "hasJobOffers": {
            "description": "Company search: only companies currently hiring.",
            "type": "boolean"
          },
          "headcount": {
            "description": "The company's OWN size band (companies search; the analog of people-search `companyHeadcount`). Approximate \"startup\" with small buckets ([\"1-10\",\"11-50\",\"51-200\"]).",
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "1-10",
                "11-50",
                "51-200",
                "201-500",
                "501-1000",
                "1001-5000",
                "5001-10000",
                "10001+"
              ]
            }
          },
          "headcountGrowth": {
            "description": "Company headcount growth rate as a {min,max} percentage range.",
            "type": "object",
            "properties": {
              "min": {
                "type": "number"
              },
              "max": {
                "type": "number"
              }
            }
          },
          "annualRevenue": {
            "description": "Company annual revenue {currency (ISO 4217), min, max} in millions. Both min AND max are required and MUST be breakpoints: 0, 0.2, 1, 2.5, 5, 10, 20, 50, 100, 500, 1000, 1001.",
            "type": "object",
            "properties": {
              "currency": {
                "type": "string",
                "minLength": 3,
                "maxLength": 3
              },
              "min": {
                "type": "number"
              },
              "max": {
                "type": "number"
              }
            },
            "required": [
              "currency",
              "min",
              "max"
            ]
          },
          "followersCount": {
            "description": "Company follower count {min,max} ranges. Breakpoints — min: 1, 51, 101, 1001, 5001; max: 50, 100, 1000, 5000.",
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "min": {
                  "type": "number"
                },
                "max": {
                  "type": "number"
                }
              }
            }
          },
          "fortune": {
            "description": "Fortune ranking {min,max} ranges (e.g. Fortune 500). Breakpoints — min: 0, 51, 101, 251; max: 50, 100, 250, 500.",
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "min": {
                  "type": "number"
                },
                "max": {
                  "type": "number"
                }
              }
            }
          },
          "recentActivities": {
            "description": "Company signals: senior_leadership_changes and/or funding_events.",
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "senior_leadership_changes",
                "funding_events"
              ]
            }
          },
          "departmentHeadcount": {
            "type": "object",
            "properties": {
              "department": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "min": {
                "type": "number"
              },
              "max": {
                "type": "number"
              }
            },
            "required": [
              "department"
            ]
          },
          "departmentHeadcountGrowth": {
            "type": "object",
            "properties": {
              "department": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "min": {
                "type": "number"
              },
              "max": {
                "type": "number"
              }
            },
            "required": [
              "department"
            ]
          },
          "savedAccounts": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "savedSearchId": {
            "type": "string",
            "pattern": "^\\d+$"
          },
          "recentSearchId": {
            "type": "string",
            "pattern": "^\\d+$"
          },
          "lastViewedAt": {
            "type": "number"
          },
          "withinArea": {
            "type": "number"
          },
          "companyLists": {
            "description": "Scope a PEOPLE search to the companies in your own Kairon company lists (`list_list`, asset \"companies\"). The server expands each list to its companies' LinkedIn ids as a current_company filter — no per-company resolution, no 40-filter ceiling. NOT `account_lists`, which means Sales Navigator's own saved lists and will not match a Kairon list. People category only.",
            "maxItems": 20,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string",
                  "minLength": 1,
                  "description": "A Kairon company list id (from `list_list`)."
                },
                "mode": {
                  "description": "\"include\" (default) = people AT these companies; \"exclude\" = people NOT at them.",
                  "type": "string",
                  "enum": [
                    "include",
                    "exclude"
                  ]
                }
              },
              "required": [
                "id"
              ]
            }
          }
        }
      }
    },
    {
      "name": "signal_search",
      "title": "Search by behavioural signal",
      "description": "Find people by what they DID, not by what their profile says — the behavioural counterpart to search_people / search_sales_navigator. Pick a `signal`:\n• `engaged_with_profile` — who commented on or reacted to a profile's recent posts. `config: { target: { kind: \"person\"|\"company\", url } }`.\n• `engaged_with_keyword` — who engaged with posts matching a keyword. `config: { keyword, datePosted?, firstDegreeOnly? }`.\n• `posted_with_keyword` — who WROTE posts matching a keyword. Same config.\n• `recently_connected` — the seat's own newest connections. No config.\n• `viewed_my_profile` — who viewed the seat's profile. No config; needs a paid LinkedIn seat (Premium, Sales Navigator, or Recruiter).\n`keyword` is a full boolean query (OR/AND/NOT, quoted phrases, parentheses). Results are RAW: real people who really did this, with no ICP screening and no qualification — screen them yourself, or add them to a list with list_add. Page with the returned opaque `cursor`; each page is metered. For \"changed jobs\" or \"posted recently\", use search_sales_navigator (`changedJobs` / `postedOnLinkedin`) instead — those are Sales Navigator spotlights, not signals.",
      "cluster": "list-building",
      "annotations": {
        "readOnly": true,
        "destructive": false,
        "idempotent": true,
        "openWorld": true
      },
      "params": [
        {
          "name": "signal",
          "type": "\"posted_with_keyword\" | \"engaged_with_keyword\" | \"engaged_with_profile\" | \"recently_connected\" | \"viewed_my_profile\"",
          "required": true
        },
        {
          "name": "config",
          "type": "object",
          "required": false
        },
        {
          "name": "cursor",
          "type": "string",
          "required": false
        }
      ],
      "inputSchema": {
        "$schema": "https://json-schema.org/draft/2020-12/schema",
        "type": "object",
        "properties": {
          "signal": {
            "type": "string",
            "enum": [
              "posted_with_keyword",
              "engaged_with_keyword",
              "engaged_with_profile",
              "recently_connected",
              "viewed_my_profile"
            ]
          },
          "config": {
            "type": "object",
            "properties": {
              "keyword": {
                "type": "string",
                "minLength": 1,
                "maxLength": 4096
              },
              "datePosted": {
                "type": "string",
                "enum": [
                  "past-24h",
                  "past-week",
                  "past-month"
                ]
              },
              "firstDegreeOnly": {
                "type": "boolean"
              },
              "target": {
                "type": "object",
                "properties": {
                  "kind": {
                    "type": "string",
                    "enum": [
                      "person",
                      "company"
                    ]
                  },
                  "url": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 512
                  }
                },
                "required": [
                  "kind",
                  "url"
                ]
              }
            }
          },
          "cursor": {
            "type": "string",
            "maxLength": 4096
          }
        },
        "required": [
          "signal"
        ]
      }
    },
    {
      "name": "campaign_activate",
      "title": "Activate a campaign — starts sending to real people",
      "description": "THIS STARTS SENDING MESSAGES TO REAL PEOPLE ON LINKEDIN, and a message already sent cannot be un-sent. Activates a `draft` or `paused` campaign — `{ id, startNow? }`; `startNow` (default true) enrolls today's first batch immediately instead of waiting for the campaign's next scheduled send window. Rejected with the machine code `CAMPAIGN_ACTIVATION_BLOCKED` (409, `params.unmet` listing every unmet precondition as structured data an agent can branch on) unless ALL FOUR hold: `no_published_version` — a published graph exists (campaign_set_graph then campaign_publish first); `no_bound_list` — at least one lead list is bound (campaign_bind_list); `no_send_window` — the campaign has a send window configured; `sender_not_connected` — its sending seat is still connected. Calling activate on an ALREADY-active campaign is a no-op that returns the current campaign unchanged — safe to retry after a lost response. Sending itself is throttled by the org's own daily caps and send window; this tool does not need to reason about them. 404s (`COMMON_NOT_FOUND`) if the campaign is not in this org.",
      "cluster": "campaigns",
      "annotations": {
        "readOnly": false,
        "destructive": true,
        "idempotent": true,
        "openWorld": true
      },
      "params": [
        {
          "name": "startNow",
          "type": "boolean",
          "required": false,
          "default": "true"
        },
        {
          "name": "id",
          "type": "string",
          "required": true
        }
      ],
      "inputSchema": {
        "$schema": "https://json-schema.org/draft/2020-12/schema",
        "type": "object",
        "properties": {
          "startNow": {
            "default": true,
            "type": "boolean"
          },
          "id": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "id"
        ]
      }
    },
    {
      "name": "campaign_create",
      "title": "Create a draft campaign",
      "description": "Create a draft campaign: a `name`, the sending seat (`channelAccountId` — a connected LinkedIn account in this org), and optionally the ICP to gate enrollment on (`icpId`; when omitted, the org's most-used ICP is auto-selected as the default gate, if the org has one). Returns the new campaign in `draft` status, with no bound lists and no graph yet — follow with campaign_bind_list for an audience and campaign_set_graph for a sequence before campaign_publish. 404s (`COMMON_NOT_FOUND`) if `channelAccountId` is not a connected account in this org.",
      "cluster": "campaigns",
      "annotations": {
        "readOnly": false,
        "destructive": false,
        "idempotent": false,
        "openWorld": false
      },
      "params": [
        {
          "name": "name",
          "type": "string",
          "required": true
        },
        {
          "name": "channelAccountId",
          "type": "string",
          "required": true
        },
        {
          "name": "icpId",
          "type": "string",
          "required": false
        }
      ],
      "inputSchema": {
        "$schema": "https://json-schema.org/draft/2020-12/schema",
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "channelAccountId": {
            "type": "string",
            "minLength": 1
          },
          "icpId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "name",
          "channelAccountId"
        ]
      }
    },
    {
      "name": "campaign_pause",
      "title": "Pause an active campaign",
      "description": "Pause an active campaign — `{ id }`. Nothing new fires going forward; runs already in flight simply wait at their current step and resume where they left off if the campaign is reactivated later (nothing already sent is recalled). Idempotent: pausing an already-paused campaign is a no-op that returns the current campaign unchanged. Rejected (`COMMON_VALIDATION_FAILED`, 400) if the campaign is `draft` or `archived` — only an `active` campaign can be paused. 404s (`COMMON_NOT_FOUND`) if the campaign is not in this org.",
      "cluster": "campaigns",
      "annotations": {
        "readOnly": false,
        "destructive": false,
        "idempotent": true,
        "openWorld": false
      },
      "params": [
        {
          "name": "id",
          "type": "string",
          "required": true
        }
      ],
      "inputSchema": {
        "$schema": "https://json-schema.org/draft/2020-12/schema",
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "id"
        ]
      }
    },
    {
      "name": "campaign_publish",
      "title": "Validate and publish the campaign's draft graph",
      "description": "Validate and publish the campaign's current draft graph — `{ id, migrateInFlight? }`. Publish can FAIL validation: rather than stopping at the first problem, it returns `published: false` with EVERY validation error in `errors` (each `{ code, message, nodeKey?, condition?, params? }`, codes like `empty_graph`, `no_start`, `multiple_starts`, `unreachable`, `cycle`, `required_outcome_unwired`, `unknown_variable`, `template_body_required`, `ai_instruction_required`, `invalid_max_length`, `fixed_text_too_long`) so every problem can be fixed in one pass — this is a value in the RESULT BODY, never a thrown exception. On success, `published: true` and `version` carries the freshly-published graph (`version` is null while `published` is false). `migrateInFlight` (default false) additionally repoints the campaign's in-flight runs onto the freshly published version by node `key`, reporting `migration: { migrated, canceled }` — a run parked on a node the new version removed is canceled instead of migrated. 404s (`COMMON_NOT_FOUND`) if the campaign is not in this org.",
      "cluster": "campaigns",
      "annotations": {
        "readOnly": false,
        "destructive": false,
        "idempotent": false,
        "openWorld": false
      },
      "params": [
        {
          "name": "id",
          "type": "string",
          "required": true
        },
        {
          "name": "migrateInFlight",
          "type": "boolean",
          "required": false
        }
      ],
      "inputSchema": {
        "$schema": "https://json-schema.org/draft/2020-12/schema",
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "minLength": 1
          },
          "migrateInFlight": {
            "type": "boolean"
          }
        },
        "required": [
          "id"
        ]
      }
    },
    {
      "name": "campaign_run_get",
      "title": "One sequence run, step by step",
      "description": "Read ONE sequence run in full — `{ runId }` (an `id` from campaign_runs). Returns the lead, the sending seat, the run's position in the sequence, and `steps` — the node-by-node timeline with each step's status and timing. When a send is drafted or already out, `body` carries the actual text, with `reasoning` and `evidence` for an AI draft and `verification` when the send was checked. This is how you answer \"what did we actually say to this person, and what happened next\" — campaign_runs gives you the page, this gives you the story. 404s (`COMMON_NOT_FOUND`) if the run is not in this org, or belongs to another member's sending seat.",
      "cluster": "campaigns",
      "annotations": {
        "readOnly": true,
        "destructive": false,
        "idempotent": true,
        "openWorld": false
      },
      "params": [
        {
          "name": "runId",
          "type": "string",
          "required": true
        }
      ],
      "inputSchema": {
        "$schema": "https://json-schema.org/draft/2020-12/schema",
        "type": "object",
        "properties": {
          "runId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "runId"
        ]
      }
    },
    {
      "name": "campaign_runs",
      "title": "The campaign's sequence runs",
      "description": "Read the campaign's sequence runs — one per enrolled lead — keyset-paginated: `{ id, bucket?, cursor?, limit? }`. `bucket` filters to one activity tab: `waiting` (still in flight), `didnt_accept` (invite never accepted), `didnt_answer` (message sent, no reply), `replied`, `interested` (a reply classified interested — a subset of `replied`), `skipped` (an Enrollment Filter / ICP / exclusion verdict, or an operator stop), `error` (failed); omit `bucket` to list every run. Each run carries the `lead` (display card), `currentNodeKey`/`currentNodeType`/`currentNodeRunStatus` while live, `nextActionAt` for the live `waiting` bucket, `outcome` once terminal, the `errorCode` when `outcome` is `failed`, and `skip`/`replyClassification` detail where relevant. Page with the returned `cursor`. 404s (`COMMON_NOT_FOUND`) if the campaign is not in this org.",
      "cluster": "campaigns",
      "annotations": {
        "readOnly": true,
        "destructive": false,
        "idempotent": true,
        "openWorld": false
      },
      "params": [
        {
          "name": "bucket",
          "type": "\"waiting\" | \"didnt_accept\" | \"didnt_answer\" | \"replied\" | \"skipped\" | \"error\" | \"interested\"",
          "required": false
        },
        {
          "name": "cursor",
          "type": "string",
          "required": false
        },
        {
          "name": "limit",
          "type": "integer",
          "required": false,
          "default": "50"
        },
        {
          "name": "id",
          "type": "string",
          "required": true
        }
      ],
      "inputSchema": {
        "$schema": "https://json-schema.org/draft/2020-12/schema",
        "type": "object",
        "properties": {
          "bucket": {
            "type": "string",
            "enum": [
              "waiting",
              "didnt_accept",
              "didnt_answer",
              "replied",
              "skipped",
              "error",
              "interested"
            ]
          },
          "cursor": {
            "type": "string",
            "maxLength": 4096
          },
          "limit": {
            "default": 50,
            "type": "integer",
            "minimum": 1,
            "maximum": 100
          },
          "id": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "id"
        ]
      }
    },
    {
      "name": "campaign_set_graph",
      "title": "Replace the campaign's draft sequence graph",
      "description": "Replace the campaign's editable DRAFT sequence graph in full — `{ id, graph: { nodes, edges, startNodeKey } }`. This OVERWRITES the whole draft; it is not a patch. Each node is `{ key, type, config, uiPosition: { x, y } }` — `key` is a stable string you choose (referenced by edges), `type` is one of send_invite | wait_connection_accepted | delay | send_message | like_last_post | visit_profile | comment_on_post | research (wait_reply isn't supported yet), and `config` is that type's own shape (e.g. `{ note, draftMode?, instruction?, language? }` for send_invite — its length budget is computed automatically, not a config field — `{ days }` for delay, `{ timeoutDays }` for wait_connection_accepted). Edges are `{ fromKey, toKey, condition }`, referencing node `key`s by the outcome they route. The wiring rules, per node type — the legal outcome-edge conditions (flagging which MUST route onward) and the legal successor types:\n\n- send_invite: outcome edge \"sent\"; may connect to → wait_connection_accepted\n- wait_connection_accepted: outcome edge \"accepted\" (required — must route onward), \"timeout\"; may connect to → delay, send_message, like_last_post, visit_profile, comment_on_post, research\n- delay: outcome edge \"default\" (required — must route onward); may connect to → send_message, send_invite, like_last_post, visit_profile, comment_on_post, research\n- send_message: outcome edge \"sent\"; may connect to → delay, like_last_post, visit_profile, comment_on_post, research\n- like_last_post: outcome edge \"done\"; may connect to → send_invite, delay, send_message, visit_profile, comment_on_post, research\n- visit_profile: outcome edge \"done\"; may connect to → send_invite, delay, send_message, like_last_post, comment_on_post, research\n- comment_on_post: outcome edge \"commented\"; may connect to → send_invite, delay, send_message, like_last_post, visit_profile, research\n- research: outcome edge \"done\"; may connect to → send_invite, delay, send_message, like_last_post, visit_profile, comment_on_post\n\nRejected with `COMMON_VALIDATION_FAILED` (400) on a duplicate node key, a dangling edge (fromKey/toKey with no matching node), an edge condition the source node type doesn't emit, or an edge to a node type the source may not connect to — the rules above. Saving is not publishing: the graph stays invisible to any run until campaign_publish. 404s (`COMMON_NOT_FOUND`) if the campaign is not in this org.",
      "cluster": "campaigns",
      "annotations": {
        "readOnly": false,
        "destructive": false,
        "idempotent": true,
        "openWorld": false
      },
      "params": [
        {
          "name": "id",
          "type": "string",
          "required": true
        },
        {
          "name": "graph",
          "type": "object",
          "required": true
        }
      ],
      "inputSchema": {
        "$schema": "https://json-schema.org/draft/2020-12/schema",
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "minLength": 1
          },
          "graph": {
            "type": "object",
            "properties": {
              "nodes": {
                "maxItems": 100,
                "type": "array",
                "items": {
                  "oneOf": [
                    {
                      "type": "object",
                      "properties": {
                        "key": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 80
                        },
                        "type": {
                          "type": "string",
                          "const": "send_invite"
                        },
                        "config": {
                          "type": "object",
                          "properties": {
                            "note": {
                              "default": "",
                              "type": "string",
                              "maxLength": 2000
                            },
                            "draftMode": {
                              "type": "string",
                              "enum": [
                                "template",
                                "ai_instructions",
                                "ai_template"
                              ]
                            },
                            "instruction": {
                              "type": "string",
                              "maxLength": 4000
                            },
                            "language": {
                              "type": "string",
                              "enum": [
                                "auto",
                                "en",
                                "es",
                                "pt",
                                "fr",
                                "de",
                                "it",
                                "nl"
                              ]
                            },
                            "verifyBeforeSend": {
                              "type": "boolean"
                            }
                          }
                        },
                        "uiPosition": {
                          "type": "object",
                          "properties": {
                            "x": {
                              "type": "number"
                            },
                            "y": {
                              "type": "number"
                            }
                          },
                          "required": [
                            "x",
                            "y"
                          ]
                        }
                      },
                      "required": [
                        "key",
                        "type",
                        "config",
                        "uiPosition"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "key": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 80
                        },
                        "type": {
                          "type": "string",
                          "const": "wait_connection_accepted"
                        },
                        "config": {
                          "type": "object",
                          "properties": {
                            "timeoutDays": {
                              "type": "integer",
                              "minimum": 1,
                              "maximum": 90
                            }
                          },
                          "required": [
                            "timeoutDays"
                          ]
                        },
                        "uiPosition": {
                          "type": "object",
                          "properties": {
                            "x": {
                              "type": "number"
                            },
                            "y": {
                              "type": "number"
                            }
                          },
                          "required": [
                            "x",
                            "y"
                          ]
                        }
                      },
                      "required": [
                        "key",
                        "type",
                        "config",
                        "uiPosition"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "key": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 80
                        },
                        "type": {
                          "type": "string",
                          "const": "delay"
                        },
                        "config": {
                          "type": "object",
                          "properties": {
                            "days": {
                              "type": "integer",
                              "minimum": 1,
                              "maximum": 90
                            }
                          },
                          "required": [
                            "days"
                          ]
                        },
                        "uiPosition": {
                          "type": "object",
                          "properties": {
                            "x": {
                              "type": "number"
                            },
                            "y": {
                              "type": "number"
                            }
                          },
                          "required": [
                            "x",
                            "y"
                          ]
                        }
                      },
                      "required": [
                        "key",
                        "type",
                        "config",
                        "uiPosition"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "key": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 80
                        },
                        "type": {
                          "type": "string",
                          "const": "send_message"
                        },
                        "config": {
                          "type": "object",
                          "properties": {
                            "body": {
                              "default": "",
                              "type": "string",
                              "maxLength": 8000
                            },
                            "draftMode": {
                              "type": "string",
                              "enum": [
                                "template",
                                "ai_instructions",
                                "ai_template"
                              ]
                            },
                            "instruction": {
                              "type": "string",
                              "maxLength": 4000
                            },
                            "language": {
                              "type": "string",
                              "enum": [
                                "auto",
                                "en",
                                "es",
                                "pt",
                                "fr",
                                "de",
                                "it",
                                "nl"
                              ]
                            },
                            "verifyBeforeSend": {
                              "type": "boolean"
                            }
                          }
                        },
                        "uiPosition": {
                          "type": "object",
                          "properties": {
                            "x": {
                              "type": "number"
                            },
                            "y": {
                              "type": "number"
                            }
                          },
                          "required": [
                            "x",
                            "y"
                          ]
                        }
                      },
                      "required": [
                        "key",
                        "type",
                        "config",
                        "uiPosition"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "key": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 80
                        },
                        "type": {
                          "type": "string",
                          "const": "like_last_post"
                        },
                        "config": {
                          "type": "object",
                          "properties": {}
                        },
                        "uiPosition": {
                          "type": "object",
                          "properties": {
                            "x": {
                              "type": "number"
                            },
                            "y": {
                              "type": "number"
                            }
                          },
                          "required": [
                            "x",
                            "y"
                          ]
                        }
                      },
                      "required": [
                        "key",
                        "type",
                        "config",
                        "uiPosition"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "key": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 80
                        },
                        "type": {
                          "type": "string",
                          "const": "visit_profile"
                        },
                        "config": {
                          "type": "object",
                          "properties": {}
                        },
                        "uiPosition": {
                          "type": "object",
                          "properties": {
                            "x": {
                              "type": "number"
                            },
                            "y": {
                              "type": "number"
                            }
                          },
                          "required": [
                            "x",
                            "y"
                          ]
                        }
                      },
                      "required": [
                        "key",
                        "type",
                        "config",
                        "uiPosition"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "key": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 80
                        },
                        "type": {
                          "type": "string",
                          "const": "comment_on_post"
                        },
                        "config": {
                          "type": "object",
                          "properties": {
                            "instruction": {
                              "type": "string",
                              "maxLength": 4000
                            },
                            "maxLength": {
                              "type": "integer",
                              "minimum": 1,
                              "maximum": 1250
                            },
                            "language": {
                              "type": "string",
                              "enum": [
                                "auto",
                                "en",
                                "es",
                                "pt",
                                "fr",
                                "de",
                                "it",
                                "nl"
                              ]
                            },
                            "verifyBeforeSend": {
                              "type": "boolean"
                            }
                          }
                        },
                        "uiPosition": {
                          "type": "object",
                          "properties": {
                            "x": {
                              "type": "number"
                            },
                            "y": {
                              "type": "number"
                            }
                          },
                          "required": [
                            "x",
                            "y"
                          ]
                        }
                      },
                      "required": [
                        "key",
                        "type",
                        "config",
                        "uiPosition"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "key": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 80
                        },
                        "type": {
                          "type": "string",
                          "const": "research"
                        },
                        "config": {
                          "type": "object",
                          "properties": {
                            "instructions": {
                              "type": "string",
                              "minLength": 1,
                              "maxLength": 4000
                            }
                          },
                          "required": [
                            "instructions"
                          ]
                        },
                        "uiPosition": {
                          "type": "object",
                          "properties": {
                            "x": {
                              "type": "number"
                            },
                            "y": {
                              "type": "number"
                            }
                          },
                          "required": [
                            "x",
                            "y"
                          ]
                        }
                      },
                      "required": [
                        "key",
                        "type",
                        "config",
                        "uiPosition"
                      ]
                    }
                  ]
                }
              },
              "edges": {
                "maxItems": 300,
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "fromKey": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 80
                    },
                    "toKey": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 80
                    },
                    "condition": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 40
                    }
                  },
                  "required": [
                    "fromKey",
                    "toKey",
                    "condition"
                  ]
                }
              },
              "startNodeKey": {
                "anyOf": [
                  {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 80
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            },
            "required": [
              "nodes",
              "edges",
              "startNodeKey"
            ]
          }
        },
        "required": [
          "id",
          "graph"
        ]
      }
    },
    {
      "name": "campaign_stats",
      "title": "How the campaign is doing",
      "description": "Everything about how a campaign is performing, in one read — `{ id, days? }`.\n`summary` is the live execution snapshot: `{ status, audienceSize, enrolledCount, queuedCount, activeRunCount, usedToday, dailyEnrollmentLimit, sendWindow, currentVersion }` — `currentVersion` is null until campaign_publish has run, which is the thing to check before campaign_activate.\n`funnel` is the outcome funnel (enrolled → invited → accepted → messaged → replied → interested).\n`buckets` is the count per activity bucket — where everyone currently stands (`queued`, `waiting`, `didnt_accept`, `didnt_answer`, `replied`, `interested`, `skipped`, `error`) — the same vocabulary campaign_runs' `bucket` filter takes, so a non-zero count tells you which filter is worth reading.\n`activity` is the daily series, and is returned ONLY if you pass `days` (7 or 30). Its days are the campaign's own local days in its send-window timezone, not UTC. 404s (`COMMON_NOT_FOUND`) if the campaign is not in this org.",
      "cluster": "campaigns",
      "annotations": {
        "readOnly": true,
        "destructive": false,
        "idempotent": true,
        "openWorld": false
      },
      "params": [
        {
          "name": "id",
          "type": "string",
          "required": true
        },
        {
          "name": "days",
          "type": "7 | 30",
          "required": false
        }
      ],
      "inputSchema": {
        "$schema": "https://json-schema.org/draft/2020-12/schema",
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "minLength": 1
          },
          "days": {
            "anyOf": [
              {
                "type": "number",
                "const": 7
              },
              {
                "type": "number",
                "const": 30
              }
            ]
          }
        },
        "required": [
          "id"
        ]
      }
    },
    {
      "name": "campaign_update",
      "title": "Edit the campaign's configuration and audience",
      "description": "Edit a campaign's configuration — any subset of `{ id, name, sendWindow, autonomy, dailyEnrollmentLimit, enrollmentFilter, icpId, stopOnReply, leadListIds }`. Omitted fields are left unchanged. `sendWindow` is `{ days: [1..7 as Mon..Sun], startHour, endHour, timeZone }` and is REQUIRED before campaign_activate will run. `autonomy` is 'autopilot' (sends fire on schedule) or 'manual' (each send waits for approval). `icpId` gates enrollment on an ICP (null clears the gate — enroll everyone). `stopOnReply: false` measures replies without halting the run. `leadListIds` binds lead lists to the audience and is **additive**: lists already bound stay bound, and a bound list you leave out is NOT unbound — unbinding would cancel every in-flight run drawn from that list, so it is not something this tool can do by omission. Returns the updated campaign. 404s (`COMMON_NOT_FOUND`) if the campaign, a lead list, or `icpId` is not in this org.",
      "cluster": "campaigns",
      "annotations": {
        "readOnly": false,
        "destructive": false,
        "idempotent": true,
        "openWorld": false
      },
      "params": [
        {
          "name": "name",
          "type": "string",
          "required": false
        },
        {
          "name": "sendWindow",
          "type": "object",
          "required": false
        },
        {
          "name": "autonomy",
          "type": "\"manual\" | \"autopilot\"",
          "required": false
        },
        {
          "name": "dailyEnrollmentLimit",
          "type": "integer",
          "required": false
        },
        {
          "name": "enrollmentFilter",
          "type": "object",
          "required": false
        },
        {
          "name": "icpId",
          "type": "string | null",
          "required": false
        },
        {
          "name": "stopOnReply",
          "type": "boolean",
          "required": false
        },
        {
          "name": "id",
          "type": "string",
          "required": true
        },
        {
          "name": "leadListIds",
          "type": "string[]",
          "required": false
        }
      ],
      "inputSchema": {
        "$schema": "https://json-schema.org/draft/2020-12/schema",
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "sendWindow": {
            "type": "object",
            "properties": {
              "days": {
                "minItems": 1,
                "maxItems": 7,
                "type": "array",
                "items": {
                  "type": "integer",
                  "minimum": 0,
                  "maximum": 6
                }
              },
              "startHour": {
                "type": "integer",
                "minimum": 0,
                "maximum": 23
              },
              "endHour": {
                "type": "integer",
                "minimum": 0,
                "maximum": 23
              },
              "timeZone": {
                "type": "string",
                "minLength": 1,
                "maxLength": 64
              }
            },
            "required": [
              "days",
              "startHour",
              "endHour",
              "timeZone"
            ]
          },
          "autonomy": {
            "type": "string",
            "enum": [
              "manual",
              "autopilot"
            ]
          },
          "dailyEnrollmentLimit": {
            "type": "integer",
            "minimum": 1,
            "maximum": 200
          },
          "enrollmentFilter": {
            "type": "object",
            "properties": {
              "buckets": {
                "minItems": 1,
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "new",
                    "unanswered",
                    "in_conversation"
                  ]
                }
              },
              "scope": {
                "type": "string",
                "enum": [
                  "seat",
                  "org"
                ]
              }
            },
            "required": [
              "buckets",
              "scope"
            ]
          },
          "icpId": {
            "anyOf": [
              {
                "type": "string",
                "minLength": 1
              },
              {
                "type": "null"
              }
            ]
          },
          "stopOnReply": {
            "type": "boolean"
          },
          "id": {
            "type": "string",
            "minLength": 1
          },
          "leadListIds": {
            "minItems": 1,
            "maxItems": 50,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1
            }
          }
        },
        "required": [
          "id"
        ]
      }
    },
    {
      "name": "chat_list",
      "title": "List LinkedIn conversations",
      "description": "List LinkedIn conversations, newest activity first. Defaults to YOUR OWN seat — pass `scope: \"org\"` for every seat in the organization, or `seatId` for one teammate. Filter with `unread` (only chats with unread messages), `leadsOnly` (only chats linked to a lead), and `q` (case-insensitive match on the counterpart's NAME — this does not search message text). Each chat carries `id` (for chat_messages), `counterpartName`, `leadId` when linked, `unreadCount`, and `lastMessagePreview`. Page with the returned `cursor`. Reading is free: it is never metered and never counts against a sending limit.",
      "cluster": "inbox-outreach",
      "annotations": {
        "readOnly": true,
        "destructive": false,
        "idempotent": true,
        "openWorld": true
      },
      "params": [
        {
          "name": "seatId",
          "type": "string",
          "required": false,
          "description": "A teammate's seat id (from a chat's `channelAccountId`). Defaults to your own."
        },
        {
          "name": "scope",
          "type": "\"mine\" | \"org\"",
          "required": false,
          "description": "'mine' (default) is your own seat; 'org' is every seat in the organization."
        },
        {
          "name": "unread",
          "type": "boolean",
          "required": false
        },
        {
          "name": "leadsOnly",
          "type": "boolean",
          "required": false,
          "description": "Only chats already linked to a lead."
        },
        {
          "name": "q",
          "type": "string",
          "required": false,
          "description": "Case-insensitive match on the counterpart's NAME."
        },
        {
          "name": "cursor",
          "type": "string",
          "required": false
        },
        {
          "name": "limit",
          "type": "integer",
          "required": false
        }
      ],
      "inputSchema": {
        "$schema": "https://json-schema.org/draft/2020-12/schema",
        "type": "object",
        "properties": {
          "seatId": {
            "description": "A teammate's seat id (from a chat's `channelAccountId`). Defaults to your own.",
            "type": "string",
            "maxLength": 64
          },
          "scope": {
            "description": "'mine' (default) is your own seat; 'org' is every seat in the organization.",
            "type": "string",
            "enum": [
              "mine",
              "org"
            ]
          },
          "unread": {
            "type": "boolean"
          },
          "leadsOnly": {
            "description": "Only chats already linked to a lead.",
            "type": "boolean"
          },
          "q": {
            "description": "Case-insensitive match on the counterpart's NAME.",
            "type": "string",
            "maxLength": 200
          },
          "cursor": {
            "type": "string",
            "maxLength": 4096
          },
          "limit": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100
          }
        }
      }
    },
    {
      "name": "chat_messages",
      "title": "Read a conversation",
      "description": "Read one conversation's messages, **newest first**, by the `chatId` from chat_list. Each message has `direction` (\"in\" = from them, \"out\" = from you), `body`, `sentAt`, and any `attachments`; a message the counterpart deleted comes back with `deleted: true` and an empty body. Page further back in history with the returned `cursor`. Opening a thread may pull fresh messages from LinkedIn, which is not metered and does not count against any sending limit.",
      "cluster": "inbox-outreach",
      "annotations": {
        "readOnly": true,
        "destructive": false,
        "idempotent": true,
        "openWorld": true
      },
      "params": [
        {
          "name": "chatId",
          "type": "string",
          "required": true
        },
        {
          "name": "cursor",
          "type": "string",
          "required": false
        },
        {
          "name": "limit",
          "type": "integer",
          "required": false
        }
      ],
      "inputSchema": {
        "$schema": "https://json-schema.org/draft/2020-12/schema",
        "type": "object",
        "properties": {
          "chatId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64
          },
          "cursor": {
            "type": "string",
            "maxLength": 4096
          },
          "limit": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100
          }
        },
        "required": [
          "chatId"
        ]
      }
    },
    {
      "name": "inmail_send",
      "title": "Send an InMail",
      "description": "Send an InMail (optional subject). Address the recipient with `target` — `{ type, value }` (url, public_identifier, or provider_id). Requires the Sales Navigator seat and a live InMail credit; refused fast otherwise. Optionally attach files with `attachments` — each item is EITHER `{ fileName, mimeType, dataBase64 }` (the file bytes inline as base64; at most ONE such file per send, ≤3 MB — if you cannot produce base64 reliably, e.g. as a chat agent without direct file access, use url instead) OR `{ fileName, mimeType, url }` (an https url we fetch server-side; up to 5 of these, ≤15 MB each) — never both on the same item. This contacts a real person and consumes a credit — there is no human approval step.",
      "cluster": "inbox-outreach",
      "annotations": {
        "readOnly": false,
        "destructive": true,
        "idempotent": false,
        "openWorld": true
      },
      "params": [
        {
          "name": "target",
          "type": "object",
          "required": true
        },
        {
          "name": "subject",
          "type": "string",
          "required": false
        },
        {
          "name": "text",
          "type": "string",
          "required": true
        },
        {
          "name": "attachments",
          "type": "object[]",
          "required": false
        }
      ],
      "inputSchema": {
        "$schema": "https://json-schema.org/draft/2020-12/schema",
        "type": "object",
        "properties": {
          "target": {
            "oneOf": [
              {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "const": "url"
                  },
                  "value": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 512,
                    "description": "A LinkedIn profile or company URL."
                  }
                },
                "required": [
                  "type",
                  "value"
                ]
              },
              {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "const": "public_identifier"
                  },
                  "value": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 512,
                    "description": "The vanity slug (e.g. \"jane-doe\") or company universal name."
                  }
                },
                "required": [
                  "type",
                  "value"
                ]
              },
              {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "const": "provider_id"
                  },
                  "value": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 512,
                    "description": "Unipile/LinkedIn internal id (e.g. \"ACoAAB…\")."
                  }
                },
                "required": [
                  "type",
                  "value"
                ]
              }
            ]
          },
          "subject": {
            "type": "string",
            "maxLength": 200
          },
          "text": {
            "type": "string",
            "minLength": 1,
            "maxLength": 8000
          },
          "attachments": {
            "maxItems": 5,
            "type": "array",
            "items": {
              "anyOf": [
                {
                  "type": "object",
                  "properties": {
                    "fileName": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 255
                    },
                    "mimeType": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 255
                    },
                    "dataBase64": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 4194304
                    }
                  },
                  "required": [
                    "fileName",
                    "mimeType",
                    "dataBase64"
                  ],
                  "additionalProperties": false
                },
                {
                  "type": "object",
                  "properties": {
                    "fileName": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 255
                    },
                    "mimeType": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 255
                    },
                    "url": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 2048,
                      "format": "uri"
                    }
                  },
                  "required": [
                    "fileName",
                    "mimeType",
                    "url"
                  ],
                  "additionalProperties": false
                }
              ]
            }
          }
        },
        "required": [
          "target",
          "text"
        ]
      }
    },
    {
      "name": "invite_send",
      "title": "Send a connection invitation",
      "description": "Send a LinkedIn connection invitation (optional note) through the caller's account. Address the recipient with `target` — `{ type, value }` (url, public_identifier, or provider_id). Refused if already connected/invited; deduped per recipient; capped daily. This contacts a real person — there is no human approval step.",
      "cluster": "inbox-outreach",
      "annotations": {
        "readOnly": false,
        "destructive": true,
        "idempotent": false,
        "openWorld": true
      },
      "params": [
        {
          "name": "target",
          "type": "object",
          "required": true
        },
        {
          "name": "note",
          "type": "string",
          "required": false
        }
      ],
      "inputSchema": {
        "$schema": "https://json-schema.org/draft/2020-12/schema",
        "type": "object",
        "properties": {
          "target": {
            "oneOf": [
              {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "const": "url"
                  },
                  "value": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 512,
                    "description": "A LinkedIn profile or company URL."
                  }
                },
                "required": [
                  "type",
                  "value"
                ]
              },
              {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "const": "public_identifier"
                  },
                  "value": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 512,
                    "description": "The vanity slug (e.g. \"jane-doe\") or company universal name."
                  }
                },
                "required": [
                  "type",
                  "value"
                ]
              },
              {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "const": "provider_id"
                  },
                  "value": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 512,
                    "description": "Unipile/LinkedIn internal id (e.g. \"ACoAAB…\")."
                  }
                },
                "required": [
                  "type",
                  "value"
                ]
              }
            ]
          },
          "note": {
            "type": "string",
            "maxLength": 300
          }
        },
        "required": [
          "target"
        ]
      }
    },
    {
      "name": "message_delete",
      "title": "Delete (retract) a sent message",
      "description": "Retract a message YOU sent, addressed by the `chatId` and message `id` that chat_messages returns. Only outbound messages can be deleted — an inbound one is a not-found. Removes it from LinkedIn and marks it deleted in the Kairon conversation. Idempotent. Metered.",
      "cluster": "inbox-outreach",
      "annotations": {
        "readOnly": false,
        "destructive": true,
        "idempotent": true,
        "openWorld": true
      },
      "params": [
        {
          "name": "chatId",
          "type": "string",
          "required": true
        },
        {
          "name": "messageId",
          "type": "string",
          "required": true,
          "description": "The message's `id` from chat_messages."
        }
      ],
      "inputSchema": {
        "$schema": "https://json-schema.org/draft/2020-12/schema",
        "type": "object",
        "properties": {
          "chatId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64
          },
          "messageId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64,
            "description": "The message's `id` from chat_messages."
          }
        },
        "required": [
          "chatId",
          "messageId"
        ]
      }
    },
    {
      "name": "message_edit",
      "title": "Edit a sent message",
      "description": "Replace the body of a message YOU sent, addressed by the `chatId` and message `id` that chat_messages returns. Only outbound messages can be edited — an inbound one is a not-found. LinkedIn allows this on Classic messages within about an hour of sending; later attempts are refused by LinkedIn. Updates the conversation in Kairon as well as on LinkedIn. Metered.",
      "cluster": "inbox-outreach",
      "annotations": {
        "readOnly": false,
        "destructive": true,
        "idempotent": false,
        "openWorld": true
      },
      "params": [
        {
          "name": "chatId",
          "type": "string",
          "required": true
        },
        {
          "name": "messageId",
          "type": "string",
          "required": true,
          "description": "The message's `id` from chat_messages."
        },
        {
          "name": "text",
          "type": "string",
          "required": true
        }
      ],
      "inputSchema": {
        "$schema": "https://json-schema.org/draft/2020-12/schema",
        "type": "object",
        "properties": {
          "chatId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64
          },
          "messageId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64,
            "description": "The message's `id` from chat_messages."
          },
          "text": {
            "type": "string",
            "minLength": 1,
            "maxLength": 8000
          }
        },
        "required": [
          "chatId",
          "messageId",
          "text"
        ]
      }
    },
    {
      "name": "message_send",
      "title": "Send a direct message",
      "description": "Send a LinkedIn direct message. Pass EXACTLY ONE of: `chatId` — reply in an existing conversation (the `id` from chat_list), which is what you want whenever the conversation already exists; or `target` — `{ type, value }` (url, public_identifier, or provider_id) to open a NEW conversation, allowed only with a 1st-degree connection or an open profile. Optionally attach files with `attachments` — `{ fileName, mimeType, dataBase64 }`, up to 5 files, each ~3 MB. Returns `chatId` and, for a reply, the persisted `message` (with the `id` message_edit and message_delete take). This contacts a real person — there is no human approval step. Metered against the seat's daily send limit.",
      "cluster": "inbox-outreach",
      "annotations": {
        "readOnly": false,
        "destructive": true,
        "idempotent": false,
        "openWorld": true
      },
      "params": [
        {
          "name": "chatId",
          "type": "string",
          "required": false,
          "description": "Reply in this existing conversation (from chat_list). Use this, or `target`."
        },
        {
          "name": "target",
          "type": "object",
          "required": false,
          "description": "Open a NEW conversation with this person. Use this, or `chatId`."
        },
        {
          "name": "text",
          "type": "string",
          "required": true
        },
        {
          "name": "attachments",
          "type": "object[]",
          "required": false
        },
        {
          "name": "clientToken",
          "type": "string",
          "required": false
        }
      ],
      "inputSchema": {
        "$schema": "https://json-schema.org/draft/2020-12/schema",
        "type": "object",
        "properties": {
          "chatId": {
            "description": "Reply in this existing conversation (from chat_list). Use this, or `target`.",
            "type": "string",
            "minLength": 1,
            "maxLength": 64
          },
          "target": {
            "description": "Open a NEW conversation with this person. Use this, or `chatId`.",
            "oneOf": [
              {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "const": "url"
                  },
                  "value": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 512,
                    "description": "A LinkedIn profile or company URL."
                  }
                },
                "required": [
                  "type",
                  "value"
                ]
              },
              {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "const": "public_identifier"
                  },
                  "value": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 512,
                    "description": "The vanity slug (e.g. \"jane-doe\") or company universal name."
                  }
                },
                "required": [
                  "type",
                  "value"
                ]
              },
              {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "const": "provider_id"
                  },
                  "value": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 512,
                    "description": "Unipile/LinkedIn internal id (e.g. \"ACoAAB…\")."
                  }
                },
                "required": [
                  "type",
                  "value"
                ]
              }
            ]
          },
          "text": {
            "type": "string",
            "minLength": 1,
            "maxLength": 8000
          },
          "attachments": {
            "maxItems": 5,
            "type": "array",
            "items": {
              "anyOf": [
                {
                  "type": "object",
                  "properties": {
                    "fileName": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 255
                    },
                    "mimeType": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 255
                    },
                    "dataBase64": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 4194304
                    }
                  },
                  "required": [
                    "fileName",
                    "mimeType",
                    "dataBase64"
                  ],
                  "additionalProperties": false
                },
                {
                  "type": "object",
                  "properties": {
                    "fileName": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 255
                    },
                    "mimeType": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 255
                    },
                    "url": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 2048,
                      "format": "uri"
                    }
                  },
                  "required": [
                    "fileName",
                    "mimeType",
                    "url"
                  ],
                  "additionalProperties": false
                }
              ]
            }
          },
          "clientToken": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128
          }
        },
        "required": [
          "text"
        ]
      }
    },
    {
      "name": "impersonate_list",
      "title": "List who you can act as",
      "description": "The users you may act as, each with their organization and whether they have a LinkedIn account connected — you can only act as someone who does. Staff see every tenant; an org owner or admin sees the members of the organizations they govern. `search` matches name, email or organization.",
      "cluster": "acting-as",
      "annotations": {
        "readOnly": true,
        "destructive": false,
        "idempotent": true,
        "openWorld": false
      },
      "params": [
        {
          "name": "search",
          "type": "string",
          "required": false,
          "description": "Filter by name, email address or organization name."
        }
      ],
      "inputSchema": {
        "$schema": "https://json-schema.org/draft/2020-12/schema",
        "type": "object",
        "properties": {
          "search": {
            "description": "Filter by name, email address or organization name.",
            "type": "string"
          }
        }
      }
    },
    {
      "name": "impersonate_start",
      "title": "Act as another user",
      "description": "Act as another user from now on: every later call runs as them, on their LinkedIn seat and their organization. Staff may act as anyone; an org owner or admin only as a member of their own organization, never one ranking above them. `user` is an email address or a user id. Calling it again switches target. The mode belongs to this client alone and ends 60 minutes after your last call, or on `impersonate_stop`.",
      "cluster": "acting-as",
      "annotations": {
        "readOnly": false,
        "destructive": false,
        "idempotent": true,
        "openWorld": false
      },
      "params": [
        {
          "name": "user",
          "type": "string",
          "required": true,
          "description": "The email address or user id to act as."
        }
      ],
      "inputSchema": {
        "$schema": "https://json-schema.org/draft/2020-12/schema",
        "type": "object",
        "properties": {
          "user": {
            "type": "string",
            "minLength": 1,
            "description": "The email address or user id to act as."
          }
        },
        "required": [
          "user"
        ]
      }
    },
    {
      "name": "impersonate_stop",
      "title": "Stop acting as another user",
      "description": "Go back to being yourself. Succeeds whether or not you were acting as anyone, and reports which it was.",
      "cluster": "acting-as",
      "annotations": {
        "readOnly": false,
        "destructive": false,
        "idempotent": true,
        "openWorld": false
      },
      "params": [],
      "inputSchema": {
        "$schema": "https://json-schema.org/draft/2020-12/schema",
        "type": "object",
        "properties": {}
      }
    }
  ]
}
