MCP 服务器

GrowthKit Revenue Intelligence

tools.growthkit/revenue-intelligence

此 MCP 可以做什么

Supports B2B revenue operations with lead campaigns, ICP and company enrichment, CRM records and activities, outreach drafting, tasks, reminders, and sales intelligence.

addCampaignLeads
Campaign: Add Leads
Add one or more leads to a campaign. Standard fields (company_name, contact_email, etc.) go to typed columns. ANY OTHER FIELD you pass automatically gets stored in the metadata jsonb column — no schema migration needed for new fields. Examples of custom fields: booth_number, source_event, scanned_at, follow_up_priority, notes_from_call. Call getCampaignLeadFields first to discover what custom fields are already used in this campaign.
输入模式
{'type': 'object', 'required': ['campaign_id', 'leads'], 'properties': {'leads': {'type': 'array', 'items': {'type': 'object', 'properties': {'company_name': {'type': 'string'}, 'contact_name': {'type': 'string'}, 'contact_role': {'type': 'string'}, 'contact_email': {'type': 'string'}, 'company_domain': {'type': 'string'}, 'company_country': {'type': 'string'}, 'company_industry': {'type': 'string'}, 'contact_linkedin': {'type': 'string'}, 'company_employees': {'type': 'integer'}, 'contact_seniority': {'type': 'string'}}, 'additionalProperties': True}, 'description': 'Array of lead objects. Standard fields go to columns; unknown keys go to metadata jsonb. Max 100 per call.'}, 'source': {'enum': ['manual', 'apollo', 'hunter', 'enrichment', 'mcp', 'csv_upload'], 'type': 'string', 'description': "Default 'mcp'."}, 'campaign_id': {'type': 'string', 'description': 'ID of the campaign (from listCampaigns).'}}}
cancelReminder
Cancel Reminder
Cancel a pending reminder by ID.
可能执行破坏性操作
输入模式
{'type': 'object', 'required': ['reminder_id'], 'properties': {'reminder_id': {'type': 'string', 'description': 'ID of the pending reminder to cancel (from listReminders).'}}}
checkNotifications
Check Notifications
Check for unread notifications (direct messages and broadcasts).
只读
输入模式
{'type': 'object', 'properties': {}}
clearMemories
Clear All Memories
Delete ALL memories. Irreversible. Always ask for explicit confirmation. You MUST provide a change_reason.
可能执行破坏性操作
输入模式
{'type': 'object', 'required': ['change_reason'], 'properties': {'change_reason': {'type': 'string', 'description': 'REQUIRED: Why all memories should be cleared. Stored in audit log.'}}}
countMemories
Count Memories
Return only counts, not content — use for overview/sizing (e.g. 'how many competitor memories exist?') before deciding whether to list or search. Optionally filter by chapter via metadata_filter.chapter. For a per-chapter breakdown in one call, prefer getChapterOverview.
只读
输入模式
{'type': 'object', 'properties': {'metadata_filter': {'type': 'object', 'description': 'Optional metadata filters. Use chapter to count within a specific chapter.', 'additionalProperties': {'type': 'string'}}}}
输出模式
{'type': 'object', 'required': ['count'], 'properties': {'count': {'type': 'integer', 'description': 'Number of matching memories.'}, 'chapter': {'type': 'string', 'description': 'Chapter the count was filtered to, if any.'}}}
createCampaign
Campaign: Create Briefing
Create a new campaign briefing. Use after collecting the 7 required fields via the campaign-briefing-playbook (search 'campaign-briefing-playbook' in playbook chapter to load the methodology). Sets status='draft'. Returns the created campaign id. NEVER call this without first running the playbook conversation — every campaign needs a complete briefing.
输入模式
{'type': 'object', 'required': ['name', 'icp_snapshot', 'persona_snapshot', 'offer', 'pain_hypothesis', 'messaging_angle', 'channels', 'start_date', 'success_metric'], 'properties': {'name': {'type': 'string', 'description': "Short campaign label, 3-200 chars. Include strategic axis (e.g. 'Q2-DACH-Maschinenbau-EU-AI-Act')."}, 'notes': {'type': 'string', 'description': 'Optional internal notes about the campaign.'}, 'offer': {'type': 'string', 'description': "The concrete CTA, NOT the product name. E.g. 'Free 30-day pilot', not 'Buy GrowthKit'."}, 'channels': {'type': 'array', 'items': {'enum': ['email', 'linkedin', 'event', 'paid', 'cold_call', 'referral', 'webinar'], 'type': 'string'}, 'description': 'Outreach channels for this campaign: email | linkedin | event | paid | cold_call | referral | webinar.'}, 'end_date': {'type': 'string', 'description': 'Optional ISO date YYYY-MM-DD. Null = open-ended.'}, 'start_date': {'type': 'string', 'description': 'ISO date YYYY-MM-DD.'}, 'description': {'type': 'string', 'description': 'Optional free-text summary of the campaign.'}, 'icp_snapshot': {'type': 'object', 'description': "Frozen ICP at creation time. May be a NARROWED variant of the user's global ICP."}, 'success_metric': {'type': 'object', 'description': "{ type: 'replies'|'demos'|'sqls'|'pipeline_eur', target: number }"}, 'briefing_source': {'enum': ['wizard', 'upload', 'manual'], 'type': 'string', 'description': "Default 'wizard'."}, 'messaging_angle': {'type': 'string', 'description': 'The hook in the first email/message. The news/trend/insight that earns the read.'}, 'pain_hypothesis': {'type': 'string', 'description': 'ONE sentence stating the specific pain this campaign assumes the persona has.'}, 'persona_snapshot': {'type': 'object', 'description': 'Frozen target persona for this campaign.'}, 'product_snapshot': {'type': 'object', 'description': 'Frozen product info at creation time. Schema: { name, description, value_props[], differentiators[], pricing_hint }.'}, 'source_document_id': {'type': 'string', 'description': 'Optional documents.id if briefing was parsed from upload.'}}}
createReminder
Create Reminder
Schedule a reminder. Convert relative times to ISO 8601.
输入模式
{'type': 'object', 'required': ['title', 'remind_at'], 'properties': {'title': {'type': 'string', 'description': 'Short reminder title.'}, 'repeat': {'enum': ['none', 'daily', 'weekly', 'monthly'], 'type': 'string', 'description': 'Repeat interval: none | daily | weekly | monthly. Default: none.'}, 'channel': {'enum': ['email', 'slack', 'webhook'], 'type': 'string', 'description': 'Delivery channel: email | slack | webhook.'}, 'task_id': {'type': 'string', 'description': 'Optional: link this reminder to a task (task UUID). Linked reminders are auto-cancelled when the task is marked done/dropped.'}, 'remind_at': {'type': 'string', 'description': 'When to remind, ISO 8601 (convert relative times first).'}, 'description': {'type': 'string', 'description': 'Optional reminder details.'}, 'channel_target': {'type': 'string', 'description': 'Optional channel target, e.g. email address or webhook URL.'}}}
createTask
Create Task
Create a prioritized task. Provide the four ICE inputs (impact, confidence, effort_constraint, effort_nonconstraint); the DB computes ice_score. Show the inputs to the user for confirmation before calling.
输入模式
{'type': 'object', 'required': ['title'], 'properties': {'owner': {'type': 'string', 'description': 'Assignee (free text)'}, 'steps': {'type': 'array', 'items': {'type': 'object', 'required': ['text'], 'properties': {'done': {'type': 'boolean'}, 'text': {'type': 'string'}}}, 'description': 'Optional checklist of sub-steps.'}, 'title': {'type': 'string', 'description': 'Short task title.'}, 'bucket': {'enum': ['now', 'next', 'later', 'follow-up'], 'type': 'string', 'description': 'Time horizon: now | next | later | follow-up.'}, 'detail': {'type': 'string', 'description': 'Optional longer description of the task.'}, 'impact': {'type': 'integer', 'maximum': 10, 'minimum': 1, 'description': 'ICE impact, 1-10 (higher = more impact).'}, 'confidence': {'type': 'number', 'maximum': 1, 'minimum': 0, 'description': 'ICE confidence, 0-1 (probability the impact materializes).'}, 'effort_constraint': {'type': 'integer', 'maximum': 10, 'minimum': 1, 'description': 'Effort on the bottleneck lane (see workspace label_constraint)'}, 'related_memory_id': {'type': 'string', 'description': 'Optional ID of a related memory to link.'}, 'effort_nonconstraint': {'type': 'integer', 'maximum': 10, 'minimum': 1, 'description': 'Effort on the non-bottleneck lane'}}}
crmAddNote
CRM: Add Note
Add a note to a CRM record — a deal, company, or contact. Provide content (HTML supported) and at least one target id (deal_id, company_id, or contact_id). Use to log call summaries, context, or decisions against the record.
可访问外部资源
输入模式
{'type': 'object', 'required': ['content'], 'properties': {'content': {'type': 'string', 'description': 'Note text — supports HTML.'}, 'deal_id': {'type': 'string', 'description': 'Optional deal ID to attach the note to.'}, 'company_id': {'type': 'string', 'description': 'Optional company ID to attach the note to.'}, 'contact_id': {'type': 'string', 'description': 'Optional contact ID to attach the note to.'}}}
crmCheckConnection
CRM: Check Connection
Check if CRM is connected and which provider is active.
只读 可访问外部资源
输入模式
{'type': 'object', 'properties': {}}
输出模式
{'type': 'object', 'required': ['connected'], 'properties': {'provider': {'type': ['string', 'null'], 'description': 'Active CRM provider, if connected.'}, 'connected': {'type': 'boolean', 'description': 'Whether a CRM provider is connected.'}}}
crmCreateActivity
CRM: Create Activity
Create a follow-up activity on a CRM record. Provide a subject and set type (call | meeting | task | email | deadline; default task). Optionally link it to a deal, company, or contact and set a due_date (YYYY-MM-DD). Use to schedule next steps after an interaction.
可访问外部资源
输入模式
{'type': 'object', 'required': ['subject'], 'properties': {'note': {'type': 'string', 'description': 'Optional note/body for the activity.'}, 'type': {'enum': ['call', 'meeting', 'task', 'email', 'deadline'], 'type': 'string', 'description': 'Activity type. Default: task.'}, 'deal_id': {'type': 'string', 'description': 'Optional deal ID to link the activity to.'}, 'subject': {'type': 'string', 'description': 'Activity subject.'}, 'due_date': {'type': 'string', 'description': 'Due date YYYY-MM-DD.'}, 'company_id': {'type': 'string', 'description': 'Optional company ID to link the activity to.'}, 'contact_id': {'type': 'string', 'description': 'Optional contact ID to link the activity to.'}}}
crmCreateCompany
CRM: Create Company
Create a new company. ALWAYS search first to avoid duplicates.
可访问外部资源
输入模式
{'type': 'object', 'required': ['name'], 'properties': {'name': {'type': 'string', 'description': 'Company name.'}, 'address': {'type': 'string', 'description': 'Company address.'}}}
crmCreateContact
CRM: Create Contact
Create a new contact. ALWAYS pass company_id when the company exists.
可访问外部资源
输入模式
{'type': 'object', 'required': ['name'], 'properties': {'name': {'type': 'string', 'description': 'Full name.'}, 'email': {'type': 'string', 'description': 'Email address.'}, 'phone': {'type': 'string', 'description': 'Phone number.'}, 'company_id': {'type': 'string', 'description': 'Company ID. REQUIRED when company exists.'}}}
crmCreateDeal
CRM: Create Deal
Create a new deal. Requires title + stage_id. MUST call crmGetPipelines first.
可访问外部资源
输入模式
{'type': 'object', 'required': ['title', 'stage_id'], 'properties': {'title': {'type': 'string', 'description': 'Deal title.'}, 'value': {'type': 'number', 'description': 'Deal value.'}, 'currency': {'type': 'string', 'description': 'Currency code. Default: EUR.'}, 'stage_id': {'type': 'string', 'description': 'Stage ID from crmGetPipelines.'}, 'company_id': {'type': 'string', 'description': 'Company ID.'}, 'contact_id': {'type': 'string', 'description': 'Contact ID.'}}}
crmGetCompany
CRM: Get Company
Get full company details by ID. Returns name, domain, industry, employees, address, CRM link.
只读 可访问外部资源
输入模式
{'type': 'object', 'required': ['id'], 'properties': {'id': {'type': 'string', 'description': 'Company ID from CRM.'}}}
crmGetCompanyContacts
CRM: Get Company Contacts
Get all contacts linked to a company, by company ID. Use to find who to reach at a known company.
只读 可访问外部资源
输入模式
{'type': 'object', 'required': ['id'], 'properties': {'id': {'type': 'string', 'description': 'Company ID.'}}}
crmGetCompanyDeals
CRM: Get Company Deals
Get all deals linked to a company, by company ID. Use after crmSearchCompany or crmGetCompany to review that company's pipeline.
只读 可访问外部资源
输入模式
{'type': 'object', 'required': ['id'], 'properties': {'id': {'type': 'string', 'description': 'Company ID.'}}}
crmGetContact
CRM: Get Contact
Get full contact details by ID.
只读 可访问外部资源
输入模式
{'type': 'object', 'required': ['id'], 'properties': {'id': {'type': 'string', 'description': 'Contact ID.'}}}
crmGetDeal
CRM: Get Deal
Get the full record for one deal by ID. Use after a search or list returns a deal id when you need its complete details.
只读 可访问外部资源
输入模式
{'type': 'object', 'required': ['id'], 'properties': {'id': {'type': 'string', 'description': 'Deal ID.'}}}
crmGetPipelines
CRM: Get Pipelines
Get all pipelines with stages. ALWAYS call before creating deals to get valid stage_id.
只读 可访问外部资源
输入模式
{'type': 'object', 'properties': {}}
crmListCompanies
CRM: List Companies
List companies from CRM with structured filters. Use for segment queries like 'all pharma companies with 50-200 employees in DACH'. All filter fields optional. Returns companies with id, name, industry, employees, country, and pagination info. Unlike crmSearchCompany (which does fuzzy name search), this does precise structured filtering.
只读 可访问外部资源
输入模式
{'type': 'object', 'properties': {'filter': {'type': 'object', 'properties': {'city': {'type': 'object', 'properties': {'in': {'type': 'array', 'items': {'type': 'string'}}}}, 'name': {'type': 'object', 'properties': {'contains': {'type': 'string'}}}, 'limit': {'type': 'integer', 'description': 'Max results (1-200). Default: 50'}, 'offset': {'type': 'integer', 'description': 'Pagination offset. Default: 0'}, 'country': {'type': 'object', 'properties': {'in': {'type': 'array', 'items': {'type': 'string'}, 'description': "ISO country codes, e.g. ['DE','AT','CH']"}}}, 'industry': {'type': 'object', 'properties': {'in': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Exact match on any value in list'}, 'contains': {'type': 'string', 'description': 'Substring match (case-insensitive)'}}}, 'order_by': {'enum': ['name', 'employees', 'created_at', 'updated_at'], 'type': 'string'}, 'employees': {'type': 'object', 'properties': {'max': {'type': 'integer', 'description': 'Maximum employee count (inclusive)'}, 'min': {'type': 'integer', 'description': 'Minimum employee count (inclusive)'}}}, 'has_deals': {'type': 'boolean'}, 'order_dir': {'enum': ['asc', 'desc'], 'type': 'string'}}, 'description': 'Filter object. All fields optional.'}}}
crmListPeople
CRM: List People
List people/contacts from CRM with structured filters. Use for segment queries like 'all CEOs in pipeline companies'. All filter fields optional. Unlike crmSearchContact (fuzzy lookup of one person by name), this does precise structured filtering across the contact base. Returns contacts with id, name, title, company, and pagination info.
只读 可访问外部资源
输入模式
{'type': 'object', 'properties': {'filter': {'type': 'object', 'properties': {'limit': {'type': 'integer'}, 'offset': {'type': 'integer'}, 'country': {'type': 'object', 'properties': {'in': {'type': 'array', 'items': {'type': 'string'}}}}, 'order_by': {'enum': ['name', 'created_at', 'updated_at'], 'type': 'string'}, 'has_email': {'type': 'boolean'}, 'job_title': {'type': 'object', 'properties': {'in': {'type': 'array', 'items': {'type': 'string'}}, 'contains': {'type': 'string'}}}, 'order_dir': {'enum': ['asc', 'desc'], 'type': 'string'}, 'seniority': {'type': 'object', 'properties': {'in': {'type': 'array', 'items': {'enum': ['executive', 'director', 'manager', 'senior', 'individual'], 'type': 'string'}}}}, 'company_id': {'type': 'string', 'description': 'Filter to contacts of a specific company'}, 'department': {'type': 'object', 'properties': {'in': {'type': 'array', 'items': {'type': 'string'}}}}}, 'description': 'Filter object. All fields optional.'}}}
crmSearchCompany
CRM: Search Company
Search CRM for a company by name. ALWAYS search before creating to avoid duplicates.
只读 可访问外部资源
输入模式
{'type': 'object', 'required': ['term'], 'properties': {'term': {'type': 'string', 'description': 'Company name or keyword to search for.'}, 'limit': {'type': 'integer', 'description': 'Max results. Default: 10.'}}}
crmSearchContact
CRM: Search Contact
Search CRM for a contact by name or keyword (fuzzy match); returns the top matches. Use to look up one known person. For structured segment queries across the contact base (e.g. 'all CEOs in pipeline companies'), use crmListPeople instead.
只读 可访问外部资源
输入模式
{'type': 'object', 'required': ['term'], 'properties': {'term': {'type': 'string', 'description': 'Contact name or keyword.'}, 'limit': {'type': 'integer', 'description': 'Max results. Default: 10.'}}}
crmUpdateDeal
CRM: Update Deal
Update a deal. Use generic names: company_id, contact_id, expected_close.
可能执行破坏性操作 可访问外部资源
输入模式
{'type': 'object', 'required': ['id'], 'properties': {'id': {'type': 'string', 'description': 'Deal ID.'}, 'title': {'type': 'string', 'description': 'Optional new deal title.'}, 'value': {'type': 'number', 'description': 'Optional new deal value.'}, 'stage_id': {'type': 'string', 'description': 'Optional new stage ID (from crmGetPipelines).'}, 'expected_close': {'type': 'string', 'description': 'Expected close date YYYY-MM-DD.'}}}
deleteDocument
Delete Document
Delete a document and its associated insights. Irreversible — always confirm with the user first.
可能执行破坏性操作
输入模式
{'type': 'object', 'required': ['document_id'], 'properties': {'document_id': {'type': 'string', 'description': 'ID of the document to delete (from listDocuments).'}}}
deleteLeadSignal
Campaign: Delete Lead Signal
Permanently delete ONE why-now signal, e.g. one recorded on the wrong company. Always confirm with the user first: name the company, the signal sentence and its source, and wait for an explicit yes. There is no undo and no version history. signal_id is the `id` of a signal from listLeadSignals (active_only=false also lists expired ones). Only this signal is removed — the lead's other signals stay untouched. If the signal is right and only a detail is wrong, use updateLeadSignal instead. 404 signal_not_found means the id is unknown or not in this workspace.
可能执行破坏性操作
输入模式
{'type': 'object', 'required': ['signal_id'], 'properties': {'signal_id': {'type': 'string', 'description': 'UUID of the signal — the `id` field of a signal in listLeadSignals.'}}}
deleteMemories
Delete Memories
Delete memories by IDs. Always confirm with user first. You MUST provide a change_reason explaining WHY these memories should be deleted. The reason is stored in the version history audit log.
可能执行破坏性操作
输入模式
{'type': 'object', 'required': ['embedding_ids', 'change_reason'], 'properties': {'change_reason': {'type': 'string', 'description': "REQUIRED: Why these memories are being deleted, e.g. 'Outdated', 'Duplicate', 'User requested cleanup'. Stored in audit log."}, 'embedding_ids': {'type': 'array', 'items': {'type': 'string'}, 'description': 'IDs of the memories to delete (from searchMemory/listMemories).'}}}
discoverSimilar
Discover Similar Companies
Find lookalike companies for a seed and re-rank them by fit. mode='account' (seed={domain}) finds companies similar to that domain via Hunter similar_to; mode='icp' (no seed) discovers companies matching your saved ICP; mode='won_deals' is not yet implemented. Each candidate comes back with similarity_to_seed (0–100 firmographic closeness to the seed), canonical_icp_score (0–100 vs your global ICP; null if not on the Pro plan), divergence + divergence_flag (≥25 = seed diverges from ICP — a product signal), classification, and already_in_crm. Read-only — it never writes and never reveals emails/phones (do that per-lead separately). To control cost, only the top `shortlist_size` pre-ranked candidates are fully enriched + scored; the rest come back with enriched:false and null scores (candidates with enriched:false were NOT evaluated — null is 'not scored', not a low score). NOTE: mode='account' uses Hunter `similar_to`, which requires a Hunter Premium/Data-Platform key; without it, discovery automatically falls back to query/industry filters and says so in `warnings`.
只读 可访问外部资源
输入模式
{'type': 'object', 'properties': {'mode': {'enum': ['account', 'icp', 'won_deals'], 'type': 'string', 'description': 'account = similar to a seed domain (default); icp = match your saved ICP; won_deals = not yet implemented (returns not_implemented).'}, 'seed': {'type': 'object', 'properties': {'domain': {'type': 'string', 'description': 'Seed company domain.'}}, 'description': "Seed for mode='account', e.g. { domain: 'intertours.de' }. Leave empty for icp/won_deals."}, 'limit': {'type': 'integer', 'description': 'Max candidates to return (hard-capped at 25). Default 25.'}, 'score': {'type': 'boolean', 'description': 'Re-rank with canonical ICP scoring (calculate-alignment). Default true. similarity_to_seed is always returned regardless of this flag.'}, 'filters': {'type': 'object', 'description': "Optional Hunter Discover filter overrides, passed straight through. Use Hunter's exact sub-shapes — a wrong shape is silently dropped (or 400s). headquarters_location: { include:[{ country:'DE' }], exclude:[...] } — country is ISO-3166 alpha-2; continent / business_region / state / city are also supported inside those objects (NOT { countries:[...] }). keywords: { include:[...], exclude:[...], match:'any'|'all' } (NOT a flat array — flat → HTTP 400 invalid_keywords). industry: { include:[...], exclude:[...] }. headcount: array of enum buckets ('1-10','11-50','51-200','201-500','501-1000','1001-5000','5001-10000','10001+')."}, 'shortlist_size': {'type': 'integer', 'description': 'How many top pre-ranked candidates get fully enriched + scored (default 10). Pre-ranking uses the free discover fields (geo, size, emails_count). Lower = cheaper (fewer enrichment credits); the rest are returned unevaluated (enriched:false, null scores).'}}}
email_compose
Compose or Draft an Email
Compose an email via the user's connected email provider (currently Gmail; Microsoft 365 coming in Phase B). DEFAULT mode is 'draft' — creates a real draft in Gmail that the user can review before sending. Only use mode='send' when the user explicitly confirms sending with keywords like 'sende', 'schick raus', 'verschicken', 'send it', 'raus damit'. On 'draft' success, response includes draft_url the user can click to open the draft in Gmail. On 'send' success, response includes a tracking_id (1×1 pixel auto-injected for open-tracking). The From address is resolved server-side (5-level precedence: explicit from > user-token integration > user-token default > account default > account email) — do NOT fabricate a From address. Optional crm_deal_id links the message to a deal for future activity writeback. Requires active email provider OAuth connection.
可能执行破坏性操作 可访问外部资源
输入模式
{'type': 'object', 'required': ['mode', 'to', 'subject'], 'properties': {'to': {'type': 'string', 'description': 'Recipient email address.'}, 'from': {'type': 'string', 'description': 'Optional From address override. Must be an address the user has authorized.'}, 'mode': {'enum': ['draft', 'send'], 'type': 'string', 'description': "Default: 'draft'. Use 'send' only on explicit user confirmation."}, 'subject': {'type': 'string', 'description': 'Email subject line.'}, 'provider': {'enum': ['auto', 'google', 'microsoft'], 'type': 'string', 'description': "Default: 'auto'. Backend resolves from user's active integration."}, 'body_html': {'type': 'string', 'description': 'HTML email body with <p>, <br>, <strong>, <a href> tags as needed. For send mode, an open-tracking pixel is auto-injected.'}, 'body_text': {'type': 'string', 'description': 'Optional plain-text fallback. If only one of body_html/body_text is provided, the other is auto-generated.'}, 'thread_id': {'type': 'string', 'description': 'Optional Gmail thread ID for replies in-thread.'}, 'crm_deal_id': {'type': 'string', 'description': 'Optional CRM deal UUID if this email relates to a specific deal.'}, 'in_reply_to': {'type': 'string', 'description': 'Optional Message-ID of the message being replied to.'}}}
embedMemory
Save Memory
Store knowledge into long-term memory. Supports single items and batch embedding (max 50). IMPORTANT — Chapter System: Every memory MUST be classified into exactly one chapter via metadata.chapter. Available chapters: icp, strategy, campaigns, analytics, brand, competitors, learnings, general, pipeline, signals, playbook. Always analyze the content and pick the most specific chapter. Use general only as a last resort. BEFORE STORING: Search target chapter first to check for duplicates. QUALITY: 50-300 words, specific and factual, one concept per memory. AUTO-TAGGING: Before saving ANY memory, search the playbook chapter for 'tag-taxonomy' to load the current tag taxonomy. Then add 3-7 relevant tags as a comma-separated string in metadata.tags (e.g. metadata: { chapter: 'campaigns', tags: 'saas,series-a,dach,linkedin,demand-gen' }). Pick the most specific tags from the taxonomy. You may add 1-2 free-form tags if needed. For batch embeds, tag each item individually. PLAYBOOK SYSTEM: Available playbooks: icp-workshop, onboarding, campaign-brief, weekly-review, competitor-analysis, content-brief. When the user asks to do any of these tasks, use prompts/get to load the full playbook and follow its steps.
输入模式
{'type': 'object', 'properties': {'items': {'type': 'array', 'items': {'type': 'object', 'required': ['content'], 'properties': {'content': {'type': 'string'}, 'metadata': {'type': 'object', 'additionalProperties': {'type': 'string'}}}}, 'description': 'Batch embed: array of {content, metadata}. Max 50. Each MUST include metadata.chapter.'}, 'content': {'type': 'string', 'description': 'Text content to store (for single embed).'}, 'metadata': {'type': 'object', 'description': 'REQUIRED: Must include chapter key.', 'additionalProperties': {'type': 'string'}}}}
enrichCompany
Enrich Company
Get company info by domain or name. Returns industry, employees, revenue, location, technologies. Prefer `domain` — it is unambiguous; a name matches whatever the provider thinks it means. `domain_unresolved` is not a provider failure — no provider was called and no credit was spent. The reply carries `candidates` (up to five domains with titles): offer them to the user, or pass `country` / `industry` as hints and try again.
只读 可访问外部资源
输入模式
{'type': 'object', 'properties': {'name': {'type': 'string', 'description': "Company name (if the domain is unknown), e.g. 'Seeburger AG'."}, 'domain': {'type': 'string', 'description': 'Company domain e.g. seeburger.de'}, 'country': {'type': 'string', 'description': "Optional hint for resolving the domain from the name: country name or ISO code, e.g. 'CH'. Only used when `domain` is absent."}, 'industry': {'type': 'string', 'description': "Optional hint for resolving the domain from the name, e.g. 'ERP software'. Only used when `domain` is absent."}, 'company_name': {'type': 'string', 'description': 'DEPRECATED — use `name`. Accepted as an alias for one more release so cached tool lists keep working; if both are given, `name` wins.'}, 'campaign_lead_id': {'type': 'string', 'description': "Optional. The `id` of a lead from listCampaignLeads (that is campaign_leads.id). Pass it whenever you enrich a lead that is already in a campaign: the result is then written back onto that lead. Contact fields are only filled where they are empty — a hand-curated e-mail is never overwritten, the rival candidate is kept in enrichment_data — while provider, timestamp and a short raw extract are always recorded, so `enriched_at` afterwards means 'this lead was enriched' instead of being a guess. Without it nothing is stored and you only get the result back, which is the right thing for a company that is not a lead yet. ⚠ This is NOT the `lead_id` from pipelineStatus' top_10 or listLeadSignals: that one names the company row, and the write fails with lead_not_found. The reply carries `enrichment_write` with what happened."}}}
enrichPerson
Enrich Person
Get person profile from email or LinkedIn URL.
只读 可访问外部资源
输入模式
{'type': 'object', 'properties': {'email': {'type': 'string', 'description': "Person's email address."}, 'linkedin_url': {'type': 'string', 'description': 'Full LinkedIn profile URL.'}, 'linkedin_handle': {'type': 'string', 'description': 'LinkedIn handle/slug (without the full URL).'}, 'campaign_lead_id': {'type': 'string', 'description': "Optional. The `id` of a lead from listCampaignLeads (that is campaign_leads.id). Pass it whenever you enrich a lead that is already in a campaign: the result is then written back onto that lead. Contact fields are only filled where they are empty — a hand-curated e-mail is never overwritten, the rival candidate is kept in enrichment_data — while provider, timestamp and a short raw extract are always recorded, so `enriched_at` afterwards means 'this lead was enriched' instead of being a guess. Without it nothing is stored and you only get the result back, which is the right thing for a company that is not a lead yet. ⚠ This is NOT the `lead_id` from pipelineStatus' top_10 or listLeadSignals: that one names the company row, and the write fails with lead_not_found. The reply carries `enrichment_write` with what happened."}}}
findContacts
Find Contacts
Find contacts at a company. Filter by seniority or department.
只读 可访问外部资源
输入模式
{'type': 'object', 'properties': {'limit': {'type': 'integer', 'description': 'Max results. Default: 10.'}, 'domain': {'type': 'string', 'description': 'Company domain to find contacts at.'}, 'company': {'type': 'string', 'description': 'Company name (if domain unknown).'}, 'seniority': {'type': 'string', 'description': 'junior, senior, or executive.'}, 'department': {'type': 'string', 'description': 'sales, marketing, it, etc.'}, 'campaign_lead_id': {'type': 'string', 'description': "Optional. The `id` of a lead from listCampaignLeads (that is campaign_leads.id). Pass it whenever you enrich a lead that is already in a campaign: the result is then written back onto that lead. Contact fields are only filled where they are empty — a hand-curated e-mail is never overwritten, the rival candidate is kept in enrichment_data — while provider, timestamp and a short raw extract are always recorded, so `enriched_at` afterwards means 'this lead was enriched' instead of being a guess. Without it nothing is stored and you only get the result back, which is the right thing for a company that is not a lead yet. ⚠ This is NOT the `lead_id` from pipelineStatus' top_10 or listLeadSignals: that one names the company row, and the write fails with lead_not_found. The reply carries `enrichment_write` with what happened."}}}
findEmail
Find Email
Find one person's email by name + domain.
只读 可访问外部资源
输入模式
{'type': 'object', 'properties': {'domain': {'type': 'string', 'description': 'Company domain to search the email at.'}, 'company': {'type': 'string', 'description': 'Company name (if domain unknown).'}, 'full_name': {'type': 'string', 'description': 'Full name (alternative to first_name + last_name).'}, 'last_name': {'type': 'string', 'description': "Person's last name."}, 'first_name': {'type': 'string', 'description': "Person's first name."}, 'campaign_lead_id': {'type': 'string', 'description': "Optional. The `id` of a lead from listCampaignLeads (that is campaign_leads.id). Pass it whenever you enrich a lead that is already in a campaign: the result is then written back onto that lead. Contact fields are only filled where they are empty — a hand-curated e-mail is never overwritten, the rival candidate is kept in enrichment_data — while provider, timestamp and a short raw extract are always recorded, so `enriched_at` afterwards means 'this lead was enriched' instead of being a guess. Without it nothing is stored and you only get the result back, which is the right thing for a company that is not a lead yet. ⚠ This is NOT the `lead_id` from pipelineStatus' top_10 or listLeadSignals: that one names the company row, and the write fails with lead_not_found. The reply carries `enrichment_write` with what happened."}}}
getAeoReport
AEO Report History
Read the weekly AEO report history — how this workspace's brand shows up in AI answer engines. Per ISO week (field: period) and domain: visibility, share_of_voice and own_cited (all ratios 0..1, multiply by 100 to display a percentage), avg_position (1 = best; null = never mentioned that week, NOT zero), plus prompts_scored and attempted_but_no_data. Each series point also carries per_engine: one entry per answer engine with engine, prompts_scored, attempted_but_no_data, visibility, share_of_voice and avg_position. In per_engine, visibility/share_of_voice/avg_position are null (not 0) when that engine produced no data, and there is deliberately NO own_cited — that one exists only at the week level. Weeks before 2026-08-29 have their per_engine rebuilt from the stored by-engine metrics, so the per-engine trend has no gap. Returns { domains: { <domain-slug>: { series: [...], latest_card } } }. Omit domain to get every tracked domain. Use when the user asks about AI-search visibility, share of voice in LLM answers, or how often the brand gets cited.
只读
输入模式
{'type': 'object', 'required': [], 'properties': {'weeks': {'type': 'integer', 'maximum': 52, 'minimum': 1, 'description': 'Optional. Number of most recent weeks. Default 12.'}, 'domain': {'type': 'string', 'examples': ['growthkit-tools', 'growthkit-consulting'], 'description': "Optional. Domain SLUG, not the bare hostname — dots become hyphens, e.g. 'growthkit-tools' or 'growthkit-consulting'. Omit to return all domains. An unknown slug yields an empty result, not an error."}}}
getCampaign
Campaign: Get
Get a single campaign with full briefing details and lead-stage counts.
只读
输入模式
{'type': 'object', 'required': ['campaign_id'], 'properties': {'campaign_id': {'type': 'string', 'description': 'ID of the campaign (from listCampaigns).'}}}
getCampaignLead
Campaign: Get Lead
One campaign lead with everything stored about it: contact, company, score, lifecycle_stage, metadata and the complete enrichment_data. That is where you answer why a contact was chosen and who else was found: enrichment_data.persona holds the trail (persona_naehe, persona_treffer, gewaehlt, alternativen, getauscht), enrichment_data.kandidaten_liste the people the enrichment found, and metadata.vorheriger_kontakt the contact this one replaced. Read-only, spends no credits. ⚠ campaign_lead_id is the `id` of a row from listCampaignLeads (campaign_leads.id). It is NOT the `lead_id` from pipelineStatus' top_10 or listLeadSignals: that one names the company row and answers lead_not_found — exactly as a lead from another workspace does.
只读
输入模式
{'type': 'object', 'required': ['campaign_lead_id'], 'properties': {'campaign_lead_id': {'type': 'string', 'description': 'The `id` of a row from listCampaignLeads (campaign_leads.id).'}}}
getCampaignLeadFields
Campaign: Discover Lead Fields
Discover which fields are actually used in a campaign's leads. Returns standard columns with non-null values PLUS all metadata (custom) keys with usage counts and sample values. ALWAYS call this BEFORE asking the user about lead structure or before adding new custom fields — it tells you what's already established for this list.
只读
输入模式
{'type': 'object', 'required': ['campaign_id'], 'properties': {'campaign_id': {'type': 'string', 'description': 'ID of the campaign (from listCampaigns).'}}}
getChapterOverview
Chapter Overview
Get memory count per chapter. Use as FIRST STEP in new conversations or reviews.
只读
输入模式
{'type': 'object', 'properties': {}}
输出模式
{'type': 'object', 'required': ['chapters'], 'properties': {'total': {'type': 'integer', 'description': 'Total memory count across readable chapters.'}, 'chapters': {'type': 'array', 'items': {'type': 'object', 'required': ['chapter', 'count'], 'properties': {'count': {'type': 'integer'}, 'chapter': {'type': 'string'}}}, 'description': 'Per-chapter memory counts (readable chapters only).'}}}
getDocument
Get Document
Get a specific document with fresh download URL and linked insights.
只读
输入模式
{'type': 'object', 'required': ['document_id'], 'properties': {'document_id': {'type': 'string', 'description': 'ID of the document (from listDocuments).'}}}
getHistory
Memory Version History
Get the version history of a specific memory. Shows all previous versions with timestamps and who made changes.
只读
输入模式
{'type': 'object', 'required': ['embedding_id'], 'properties': {'embedding_id': {'type': 'string', 'description': 'ID of the memory to get history for.'}}}
getOpenTasks
Get Open Tasks
Return the workspace's open/in-progress tasks ranked by ICE (highest priority first) plus the total open count. Call this at the START of any planning, prioritization, or 'what should I work on next' discussion to ground the conversation in current open tasks before advising.
只读
输入模式
{'type': 'object', 'properties': {'limit': {'type': 'integer', 'description': 'Max tasks to return. Default: 20.'}}}
输出模式
{'type': 'object', 'required': ['tasks'], 'properties': {'tasks': {'type': 'array', 'items': {'type': 'object', 'required': ['id', 'title', 'status'], 'properties': {'id': {'type': ['string', 'number']}, 'owner': {'type': ['string', 'null']}, 'title': {'type': 'string'}, 'bucket': {'type': ['string', 'null'], 'description': 'now | next | later | follow-up.'}, 'detail': {'type': ['string', 'null']}, 'impact': {'type': ['integer', 'null']}, 'status': {'type': 'string', 'description': 'open | in_progress | done | dropped.'}, 'ice_score': {'type': ['number', 'null'], 'description': 'Computed ICE score (GENERATED column).'}, 'confidence': {'type': ['number', 'null']}, 'effort_constraint': {'type': ['integer', 'null']}, 'effort_nonconstraint': {'type': ['integer', 'null']}}}, 'description': 'Tasks ranked by ICE (highest first).'}}}
getSeoReport
SEO Report History
Read the weekly SEO report history for this workspace's domains: Google Search Console clicks and impressions, average position, AI-referral sessions and content-brief counts — one data point per ISO week, oldest first. Returns { domains: { <domain-slug>: { series: [...], latest_card } } }. IMPORTANT: avg_position is null for a week with no data — null is NOT zero and must never be charted or averaged as zero. Omit domain to get every domain the workspace tracks. Use when the user asks how SEO, organic search or Search Console performance developed over time.
只读
输入模式
{'type': 'object', 'required': [], 'properties': {'weeks': {'type': 'integer', 'maximum': 52, 'minimum': 1, 'description': 'Optional. Number of most recent weeks. Default 12.'}, 'domain': {'type': 'string', 'examples': ['growthkit-tools', 'growthkit-consulting'], 'description': "Optional. Domain SLUG, not the bare hostname — dots become hyphens, e.g. 'growthkit-tools' or 'growthkit-consulting'. Omit to return all domains. An unknown slug yields an empty result, not an error."}}}
getTopLeads
Lead Scoring: Top Leads
Retrieve the highest-scoring leads from the CRM, ranked by ICP fit. Returns company details, contact (if any), 4-dimension score breakdown, and qualitative reasons like 'Industry X — strong match to ICP'. By default filters out leads with <50% data completeness to avoid false-positives from data-sparse ICP matches (e.g. leads where only the contact's seniority matched but industry/employees/country are unknown). Override via filters.min_completeness if you want incomplete leads too. Requires scoreLeads to have been run at least once. Requires Pro plan. Read-only — does not trigger new scoring. Call scoreLeads first if your CRM has new companies or ICP has changed (check icp_version_hash in the response to detect staleness). The fit gate decides on `score_fit` against `fit_gate_min` (default 60), never on `score`: `score` is the composite that ranks leads INSIDE the gate and is structurally low for cold leads, so comparing it with the threshold is always wrong.
只读
输入模式
{'type': 'object', 'properties': {'limit': {'type': 'integer', 'maximum': 100, 'minimum': 1, 'description': 'Number of leads to return. Default 10, max 100.'}, 'filters': {'type': 'object', 'properties': {'min_completeness': {'type': 'number', 'maximum': 1, 'minimum': 0, 'description': 'Minimum data completeness 0-1. Default 0.5 (filters ghost leads). Set to 0 to include data-sparse matches.'}, 'enrichment_recommended': {'type': 'boolean', 'description': 'If true, return only leads flagged for enrichment. If false, only leads with sufficient data. Omit for both.'}}, 'description': 'Optional result filters.'}, 'min_score': {'type': 'integer', 'maximum': 100, 'minimum': 0, 'description': 'Minimum score 0-100 to include. Default 60.'}}}
getWorkingMemory
Working Memory: Get
Retrieve the current state for a (kind, key) in the current session. Returns null if not set. Use this when you need to merge into existing state or verify what's stored. NOTE: Active working memory entries are ALSO automatically injected into the system prompt by Build Messages — you usually don't need to call this manually. Only call when you need a specific record's full state on-demand.
只读
输入模式
{'type': 'object', 'required': ['session_id', 'kind', 'key'], 'properties': {'key': {'type': 'string', 'description': 'Logical identifier within the kind (same key used in setWorkingMemory).'}, 'kind': {'enum': ['wizard', 'working_set', 'pinned_entity'], 'type': 'string', 'description': 'Which kind of state to retrieve: wizard | working_set | pinned_entity.'}, 'session_id': {'type': 'string', 'description': 'The current chat session_id. REQUIRED.'}}}
listCampaignLeads
Campaign: List Leads
List leads in a campaign, optionally filtered by lifecycle_stage or enrichment_status. Returns up to 100 per call. Compact rows by default — id, company name, domain, score, fit_gate, strong_signals, has_email, has_phone, lifecycle_stage — which is what you need to rank and to decide. The compact rows carry no contact. fields=full adds the contact (contact_name, contact_role, contact_email, contact_phone), enrichment_provider, enriched_at and enrichment_persona: why the enrichment picked this contact — persona_naehe (closeness of the contact's role to the campaign persona, 0 to 1), persona_treffer, gewaehlt, the alternativen it passed over, and getauscht when it replaced a contact who was already there; that previous contact is kept in metadata.vorheriger_kontakt. enrichment_persona is null when the lead was never enriched with a persona. For one lead's complete record — including kandidaten_liste, everyone the enrichment found — call getCampaignLead with the row's id. The fit gate decides on `score_fit` against `fit_gate_min` (default 60), never on `score`: `score` is the composite that ranks leads INSIDE the gate and is structurally low for cold leads, so comparing it with the threshold is always wrong.
只读
输入模式
{'type': 'object', 'required': ['campaign_id'], 'properties': {'limit': {'type': 'integer', 'description': 'Default 50, max 100.'}, 'fields': {'enum': ['compact', 'full'], 'type': 'string', 'description': 'compact for lists and ranking; full when you need contacts or the enrichment trail across the list. For a single lead prefer getCampaignLead. Default compact.'}, 'campaign_id': {'type': 'string', 'description': 'ID of the campaign (from listCampaigns).'}, 'lifecycle_stage': {'enum': ['imported', 'enriched', 'scored', 'crm_ready', 'crm_synced', 'rejected', 'bounced'], 'type': 'string', 'description': 'Optional: filter by lifecycle stage.'}, 'enrichment_status': {'enum': ['pending', 'enriched', 'failed', 'skipped'], 'type': 'string', 'description': 'Optional: filter by enrichment status.'}}}
listCampaigns
Campaign: List
List campaigns for the current user, optionally filtered by status. Returns campaign metadata plus per-stage lead counts.
只读
输入模式
{'type': 'object', 'properties': {'limit': {'type': 'integer', 'description': 'Default 25, max 100.'}, 'status': {'enum': ['draft', 'active', 'paused', 'completed', 'archived'], 'type': 'string', 'description': 'Optional: filter by status: draft | active | paused | completed | archived.'}}}
listDeleted
List Deleted Memories
List recently deleted memories that can be restored. Shows content preview and deletion info.
只读
输入模式
{'type': 'object', 'properties': {'limit': {'type': 'integer', 'description': 'Max results. Default: 20.'}}}
listDocuments
List Documents
List stored documents with optional filtering by category or chapter.
只读
输入模式
{'type': 'object', 'properties': {'limit': {'type': 'integer', 'description': 'Max results. Default: 50.'}, 'offset': {'type': 'integer', 'description': 'Pagination offset. Default: 0.'}, 'chapter': {'type': 'string', 'description': 'Optional: filter by associated memory chapter.'}, 'category': {'type': 'string', 'description': 'Optional: filter by storage category.'}}}
listLeadSignals
Campaign: List Lead Signals
List the stored why-now signals for one lead or for a whole campaign: `id` (the signal_id that updateLeadSignal and deleteLeadSignal take), type (funding, hiring, job_change, leadership, acquisition, expansion, tech_change, regulatory, event, inbound, other), the one-sentence signal, its source URL, the observed date, a confidence, and `cite`. Read-only. When you use a signal in outreach, use `cite` VERBATIM as the source line — it is already formatted for the reader ("ad-hoc-news, 27. August 2026"). Never write "observed", "observed_at" or "as observed on": those are field names from our data model, not words a prospect should read. Never present a signal without its source and date.
只读
输入模式
{'type': 'object', 'properties': {'lang': {'enum': ['de', 'en'], 'type': 'string', 'description': 'Language of the `cite` line. Default de.'}, 'limit': {'type': 'integer', 'description': 'Default 50, max 200.'}, 'lead_id': {'type': 'string', 'description': 'UUID of the LEAD (leads.id), e.g. from pipelineStatus top_10. Either this, campaign_lead_id or campaign_id. Mixing the two lead UUIDs up is no longer a trap: whichever you pass is resolved to the right entity, and an unknown UUID returns 404 with an explanation instead of an empty list.'}, 'active_only': {'type': 'boolean', 'description': 'Only signals inside their TTL. Default true — an expired signal is not a reason to call.'}, 'campaign_id': {'type': 'string', 'description': 'All signals of a campaign (from listCampaigns). Either this or one of the lead UUIDs.'}, 'campaign_lead_id': {'type': 'string', 'description': 'UUID of the CAMPAIGN MEMBERSHIP (campaign_leads.id) — the id from listCampaignLeads or from the pipelineRun candidate list. Resolves to the same signals as lead_id.'}}}
listMemories
List Memories
List stored memories in stored order with pagination. Unlike searchMemory (semantic relevance ranking), use this to browse, enumerate, or audit a chapter — not to find the most relevant memory for a question. Filter by chapter via metadata_filter.chapter.
只读
输入模式
{'type': 'object', 'properties': {'limit': {'type': 'integer', 'description': 'Max results. Default: 50.'}, 'offset': {'type': 'integer', 'description': 'Pagination offset. Default: 0.'}, 'metadata_filter': {'type': 'object', 'description': 'Optional metadata filters. Use chapter to list within a specific chapter.', 'additionalProperties': {'type': 'string'}}}}
listReminders
List Reminders
List reminders, ordered by remind_at ascending. By default returns only pending reminders; pass status=sent|cancelled|all to widen. Optionally scope to one task via task_id. Returns each reminder's id, title, remind_at, and status.
只读
输入模式
{'type': 'object', 'properties': {'limit': {'type': 'integer', 'description': 'Max results. Default: 50.'}, 'status': {'enum': ['pending', 'sent', 'cancelled', 'all'], 'type': 'string', 'description': 'Filter by status: pending | sent | cancelled | all. Default: pending.'}, 'task_id': {'type': 'string', 'description': 'Optional: only reminders linked to this task.'}}}
输出模式
{'type': 'object', 'required': ['reminders'], 'properties': {'reminders': {'type': 'array', 'items': {'type': 'object', 'required': ['id', 'title', 'remind_at', 'status'], 'properties': {'id': {'type': ['string', 'number']}, 'title': {'type': 'string'}, 'status': {'type': 'string', 'description': 'pending | sent | cancelled.'}, 'remind_at': {'type': 'string', 'description': 'ISO 8601 timestamp.'}}}, 'description': 'Matching reminders, ordered by remind_at ascending.'}}}
listTasks
List Tasks
List tasks in the workspace, ranked by ICE (highest first). Optional filters.
只读
输入模式
{'type': 'object', 'properties': {'limit': {'type': 'integer', 'description': 'Max results. Default: 50.'}, 'owner': {'type': 'string', 'description': 'Optional: filter by assignee.'}, 'bucket': {'enum': ['now', 'next', 'later', 'follow-up'], 'type': 'string', 'description': 'Optional: filter by bucket: now | next | later | follow-up.'}, 'status': {'enum': ['open', 'in_progress', 'done', 'dropped'], 'type': 'string', 'description': 'Optional: filter by status: open | in_progress | done | dropped.'}}}
输出模式
{'type': 'object', 'required': ['tasks'], 'properties': {'tasks': {'type': 'array', 'items': {'type': 'object', 'required': ['id', 'title', 'status'], 'properties': {'id': {'type': ['string', 'number']}, 'owner': {'type': ['string', 'null']}, 'title': {'type': 'string'}, 'bucket': {'type': ['string', 'null'], 'description': 'now | next | later | follow-up.'}, 'detail': {'type': ['string', 'null']}, 'impact': {'type': ['integer', 'null']}, 'status': {'type': 'string', 'description': 'open | in_progress | done | dropped.'}, 'ice_score': {'type': ['number', 'null'], 'description': 'Computed ICE score (GENERATED column).'}, 'confidence': {'type': ['number', 'null']}, 'effort_constraint': {'type': ['integer', 'null']}, 'effort_nonconstraint': {'type': ['integer', 'null']}}}, 'description': 'Tasks ranked by ICE (highest first).'}}}
listTeam
List Team Members
List all team members (token holders) for your account. Shows display names, roles, and identifies which token is yours.
只读
输入模式
{'type': 'object', 'properties': {}}
pipelineRun
Pipeline: Run Stage
Run ONE stage of the qualification chain for the next N candidates. Stages in order: resolve → score → signals → reveal → rescore; rerank follows reveal and re-judges the contacts that are already there. ALWAYS call with dry_run=true first and show the user the candidate count and estimated_credits; only after explicit confirmation call again with dry_run=false and confirm_credits set to the number you showed. reveal spends 3 credits per lead (13 with with_phone) and resolve spends 1 per lead; score, signals and rescore spend none — so resolve needs confirm_credits too, not just reveal. rerank calls no provider at all: it reads the stored candidate lists, and the only credit it can spend is one per contact it actually swaps (the new address is verified). That number is not knowable before the run, so its estimate is 0 — use rerank instead of a second reveal whenever the contacts are there but the wrong people. A stage with 0 candidates is not an error — it means the previous stage has to run first, and the reply then carries `why_zero` with per-condition `counts` and a finished sentence in `de` and `en`: report that reason, never invent one. `why_zero` is absent whenever there are candidates. Never run this against a demo campaign; it is refused with 403. The response ends with `next`: pending counts per stage (label_de/label_en, why_zero at 0) — base every next-step suggestion on it, never on chat history. The fit gate decides on `score_fit` against `fit_gate_min` (default 60), never on `score`: `score` is the composite that ranks leads INSIDE the gate and is structurally low for cold leads, so comparing it with the threshold is always wrong.
可能执行破坏性操作 可访问外部资源
输入模式
{'type': 'object', 'required': ['campaign_id', 'stage'], 'properties': {'lang': {'enum': ['de', 'en'], 'type': 'string', 'description': 'Language for the signal sentences written by the `signals` stage. Default de. Other stages ignore it.'}, 'limit': {'type': 'integer', 'description': 'How many candidates to process. Default 10, max 25.'}, 'stage': {'enum': ['resolve', 'score', 'signals', 'reveal', 'rescore', 'rerank'], 'type': 'string', 'description': 'resolve = find domain and firmographics. score = ICP fit. signals = why-now scan. reveal = persona, email and optionally phone (SPENDS CREDITS). rescore = second pass once seniority is known. rerank = re-check the contacts you already have against the persona, from the candidate lists reveal stored (0 credits, 1 per contact it actually swaps). Map user language: Firmendaten vervollstaendigen/ergaenzen/anreichern or complete company data = resolve; bewerten/priorisieren/einordnen or score/rank = score, use rescore if the campaign was scored before; Anlaesse/Signale/Trigger/Why-now suchen or find triggers = signals; Ansprechpartner/Kontakte finden, E-Mail/Telefon ermitteln or find contacts = reveal; Kontakte neu bewerten/Ansprechpartner neu pruefen/passt der Kontakt noch or re-check the contacts = rerank'}, 'dry_run': {'type': 'boolean', 'description': 'true = report candidates and estimated_credits, change nothing. Always do this first.'}, 'lead_ids': {'type': 'array', 'items': {'type': 'string'}, 'description': "Optional: run only on these leads instead of letting the stage choose. Use it when the user names specific companies, for a first careful run on one lead, or to pick up after an aborted run. These are `leads.id` — the `lead_id` from this tool's own dry-run candidates, from pipelineStatus top_10 or from listLeadSignals. It is NOT the `id` from listCampaignLeads: that is the campaign membership (campaign_leads.id), and passing it is not refused — it simply matches nothing, and 0 candidates reads like 'nothing left to do'. Naming leads only NARROWS: whoever the gate excludes stays excluded. One exception, and it is the point of a second attempt: in the resolve stage a named lead is taken up again even inside the two retry windows."}, 'min_score': {'type': 'integer', 'description': 'Fit threshold for signals and reveal. Default 60.'}, 'with_phone': {'type': 'boolean', 'description': 'reveal only: also reveal a mobile number. Default false. A phone costs 10 credits per lead on top of the 3 for the email.'}, 'campaign_id': {'type': 'string', 'description': 'ID of the campaign (from listCampaigns).'}, 'require_signal': {'type': 'boolean', 'description': 'reveal only: require an active why-now signal. Default true. Setting this to false widens who gets contacted — ask the user before you do it.'}, 'confirm_credits': {'type': 'integer', 'description': 'Required for a paid stage when dry_run is false — reveal and resolve: the exact estimated_credits from the dry run. A mismatch is refused with 409 and a fresh number — the candidate set changed, so show the user the new figure instead of retrying with the old one. rerank is estimated at 0 and therefore runs without a confirmation, although a swap costs one credit; do the dry run anyway and tell the user how many contacts it would re-judge.'}}}
pipelineStatus
Pipeline: Status
Show where a campaign's leads stand in the qualification chain. Returns the funnel (how many leads have a domain, firmographics, a score, a signal, an email, a phone), how many candidates each stage currently has, and the top 10 leads by priority. Read-only, spends no credits. Call this FIRST whenever the user asks what to do with a campaign — the pending counts tell you which stage to run next. The gate_column field says which signal column the reveal gate uses; if it reads 'active_signals' the gate is softer than specified and weak signals still count. The reply carries `stages` — one entry per stage with its pending count and `label_de`/`label_en`. Use those labels when you name a stage to the user; the internal ids (resolve, reveal) are not words a user knows. `contacts` counts three states, not two: `passend`, `andere_rolle`, `fehlt` — the middle one is the common case that "has an e-mail" hides, a contact who is there but in the wrong role. The fit gate decides on `score_fit` against `fit_gate_min` (default 60), never on `score`: `score` is the composite that ranks leads INSIDE the gate and is structurally low for cold leads, so comparing it with the threshold is always wrong.
只读
输入模式
{'type': 'object', 'required': ['campaign_id'], 'properties': {'campaign_id': {'type': 'string', 'description': 'ID of the campaign (from listCampaigns).'}}}
place_call
Place Call (app-private)
APP-PRIVATE: initiates a click-to-call to one lead from the user's own verified caller ID. Not model-callable (hidden via _meta.ui.visibility:["app"]). Invoked only by the lead-call-card iframe when the human clicks ☎ Anrufen. The gk_ session token is taken server-side; the app passes campaign_lead_id only.
可能执行破坏性操作 可访问外部资源
输入模式
{'type': 'object', 'required': ['campaign_lead_id'], 'properties': {'campaign_lead_id': {'type': 'string', 'description': "ID of the campaign lead to call (campaign_lead_id from show_callable_leads' structuredContent)."}}}
restoreVersion
Restore Memory Version
Restore a memory to a previous version. Works for both existing and deleted memories. Use version_id from getHistory or listDeleted results.
可能执行破坏性操作
输入模式
{'type': 'object', 'required': ['version_id'], 'properties': {'version_id': {'type': 'string', 'description': 'The version ID (restore_id) to restore to. Get this from getHistory or listDeleted.'}}}
save_call_outcome
Save Call Outcome (app-private)
APP-PRIVATE: saves the post-call disposition / note / next action for one call. Not model-callable (hidden via _meta.ui.visibility:["app"]). Invoked only by the lead-call-card iframe after a call. The gk_ session token is taken server-side; the app passes call_log_id (from place_call) plus optional disposition / notes / next_action.
可能执行破坏性操作
输入模式
{'type': 'object', 'required': ['call_log_id'], 'properties': {'notes': {'type': 'string', 'description': 'Optional free-text note about the call.'}, 'call_log_id': {'type': 'string', 'description': 'call_log_id returned by place_call in its structuredContent.'}, 'disposition': {'enum': ['interested', 'no_need', 'callback', 'voicemail', 'wrong_number', 'dnc'], 'type': 'string', 'description': 'Optional call disposition.'}, 'next_action': {'type': 'object', 'required': ['remind_at'], 'properties': {'title': {'type': 'string', 'description': 'Optional reminder title.'}, 'remind_at': {'type': 'string', 'description': 'ISO timestamp for the reminder.'}}, 'description': 'Optional follow-up reminder (typically for a callback disposition).'}}}
scoreLeads
Lead Scoring: Run
Trigger ICP lead scoring. Two independent modes — choose by WHERE the leads live, they do not overlap. (1) CAMPAIGN MODE — mode='campaign' plus campaign_id: scores the leads of one campaign (campaign_leads). Use this whenever the request is about a campaign, an imported/uploaded lead list, or leads that are not in a CRM. Needs no CRM connection and no Pro plan. Scores are written back onto the campaign's leads; read them via listCampaignLeads (score / completeness per lead). (2) CRM MODE — mode='full' | 'delta' | 'company_ids': scores this user's connected CRM companies. 'full' = every company (slow for >1k), 'delta' = only those new or changed since the last run (recommended for routine updates), 'company_ids' = a specific list. Persists to the lead_scores table; read results via getTopLeads. Requires a connected CRM and a Pro plan (active or trialing). If the user has no CRM or no Pro plan, campaign mode is the only mode that will work. Both modes score on the same 4 dimensions (industry 35%, employees 25%, geo 20%, seniority 20%) with missing-data renormalization and return counts plus a per-user summary. Write-operation — it persists scores.
输入模式
{'type': 'object', 'required': ['mode'], 'properties': {'mode': {'enum': ['campaign', 'full', 'delta', 'company_ids'], 'type': 'string', 'description': "Which leads to score. 'campaign' scores the leads of one campaign and REQUIRES campaign_id — no CRM and no Pro plan needed. The other three target the connected CRM and require Pro: 'full' scores all CRM companies (slow for >1k), 'delta' only those updated since the last run or not yet scored (recommended for routine updates), 'company_ids' a specific list (requires company_ids)."}, 'campaign_id': {'type': 'string', 'description': "UUID of the campaign whose leads to score. REQUIRED when mode='campaign'; ignored in the CRM modes. Get it from listCampaigns."}, 'company_ids': {'type': 'array', 'items': {'type': 'string'}, 'description': "CRM company IDs to score. Required and only used when mode='company_ids'. Max 100 recommended per call."}}}
searchMemory
Search Memory
Search long-term memory using semantic similarity. ALWAYS SEARCH BEFORE ANSWERING marketing/strategy questions. Use short, specific keywords as queries. Available chapters: icp, strategy, campaigns, analytics, brand, competitors, learnings, general, pipeline, signals, playbook. TAG FILTERING: Memories are auto-tagged. Use metadata_filter with tags key to filter (e.g. metadata_filter: { chapter: 'campaigns', tags: 'linkedin' }).
只读
输入模式
{'type': 'object', 'required': ['query'], 'properties': {'limit': {'type': 'integer', 'description': 'Max results. Default: 10.'}, 'query': {'type': 'string', 'description': 'Search keywords — short and specific.'}, 'match_threshold': {'type': 'number', 'description': 'Min similarity (0-1). Default: 0.5.'}, 'metadata_filter': {'type': 'object', 'description': 'Filter by metadata. Use chapter to search within a specific chapter.', 'additionalProperties': {'type': 'string'}}}}
sendNotification
Send Notification
Send a notification to a team member. First use listTeam to find the recipient. For 2-person teams, the recipient is auto-resolved.
输入模式
{'type': 'object', 'required': ['message'], 'properties': {'context': {'type': 'object', 'description': "Optional context, e.g. {chapter: 'icp'}.", 'additionalProperties': {'type': 'string'}}, 'message': {'type': 'string', 'description': 'The notification message to send.'}, 'broadcast': {'type': 'boolean', 'description': 'If true, sends to ALL team members. Default: false.'}, 'to_prefix': {'type': 'string', 'description': "Recipient's token_prefix or display_name from listTeam."}}}
setTaskWeights
Set Task Weights
Set the workspace effort weights (constraint vs non-constraint lane) and optional display labels. Re-stamps open tasks so their ICE re-ranks.
输入模式
{'type': 'object', 'required': ['w_constraint', 'w_nonconstraint'], 'properties': {'w_constraint': {'type': 'number', 'minimum': 0, 'description': 'Weight for the constraint (bottleneck) effort lane in the ICE score.'}, 'w_nonconstraint': {'type': 'number', 'minimum': 0, 'description': 'Weight for the non-constraint effort lane in the ICE score.'}, 'label_constraint': {'type': 'string', 'description': "Optional display label for the constraint lane (e.g. 'Engineering')."}, 'label_nonconstraint': {'type': 'string', 'description': "Optional display label for the non-constraint lane (e.g. 'Design')."}}}
setWorkingMemory
Working Memory: Set
Store structured state for the current chat session. Use this to persist data that must survive history compression — wizard fields, suggestion lists, active entities. Three kinds: 'wizard' (multi-turn field collection), 'working_set' (ephemeral suggestion lists with TTL), 'pinned_entity' (durable context). Call this AFTER the user confirms a value, BEFORE moving to the next step. The state object replaces (not merges) — fetch first if you need to merge.
可能执行破坏性操作
输入模式
{'type': 'object', 'required': ['session_id', 'kind', 'key', 'state'], 'properties': {'key': {'type': 'string', 'description': "Logical identifier within a kind. Examples: 'campaign_briefing', 'lead_candidates', 'active_campaign'. Use snake_case."}, 'kind': {'enum': ['wizard', 'working_set', 'pinned_entity'], 'type': 'string', 'description': 'wizard = multi-turn field collection. working_set = ephemeral suggestion lists with TTL. pinned_entity = durable context across turns.'}, 'state': {'type': 'object', 'description': 'The full state object to store. Replaces any previous state for this (kind, key). Schema is free-form but conventions: wizard = { fields, required, collected, current_step }; working_set = { items, context }; pinned_entity = { id, name, summary, ... }.'}, 'status': {'enum': ['active', 'completed', 'abandoned'], 'type': 'string', 'description': "Default 'active'. Set to 'completed' when a wizard finishes successfully (triggers completed_at timestamp)."}, 'ttl_turns': {'type': 'integer', 'description': 'Optional TTL in user-turns. After this many turns, the record auto-expires. NULL/omit = permanent (typical for wizard and pinned_entity). Use 5 for working_set / suggestion lists.'}, 'session_id': {'type': 'string', 'description': 'The current chat session_id. REQUIRED. Comes from the conversation context.'}}}
show_callable_leads
☎ Show Callable Leads
Render an interactive call card of leads that have a phone number, each with a ☎ Anrufen button. The HUMAN user clicks a button to place a click-to-call from their own verified caller ID. This tool ONLY displays the card — it never places a call itself, and there is no model-callable call tool (UWG § 7: calls are human-initiated only). Optionally scope to one campaign_id; omit it to aggregate all callable leads across the user's campaigns. Use when the user asks to see or call leads (e.g. "zeig mir anrufbare Leads", "welche Leads kann ich anrufen"). The fit gate decides on `score_fit` against `fit_gate_min` (default 60), never on `score`: `score` is the composite that ranks leads INSIDE the gate and is structurally low for cold leads, so comparing it with the threshold is always wrong.
只读
输入模式
{'type': 'object', 'properties': {'limit': {'type': 'integer', 'description': 'Max leads to render. Default 50, max 100.'}, 'campaign_id': {'type': 'string', 'description': 'Optional campaign UUID (from listCampaigns). Omit to aggregate callable leads across all campaigns.'}}}
toggleStep
Toggle Step
Check off or re-open a single step in a task's checklist. Provide the task `id` and the `step_id` of the step to toggle. Omit `done` to flip the step's current state; set done=true/false to force a specific state (idempotent). Use when the user completes or reopens a checklist item on a task that has steps.
输入模式
{'type': 'object', 'required': ['id', 'step_id'], 'properties': {'id': {'type': 'string', 'description': 'Task UUID.'}, 'done': {'type': 'boolean', 'description': 'Omit to flip the current state.'}, 'step_id': {'type': 'string', 'description': "ID of the step to toggle (from the task's steps)."}}}
updateCampaign
Campaign: Update
Update fields on an existing campaign. Pass only the fields to change. Use `scoring` to give THIS campaign its own lead-scoring profile — without it the campaign is scored against the user's global ICP, which is wrong whenever the campaign targets a different market. A campaign with its own profile also re-scores automatically when the profile changes.
可能执行破坏性操作
输入模式
{'type': 'object', 'required': ['campaign_id'], 'properties': {'name': {'type': 'string', 'description': 'Short campaign label, 3-200 chars.'}, 'notes': {'type': 'string', 'description': 'Optional internal notes about the campaign.'}, 'offer': {'type': 'string', 'description': "The concrete CTA, NOT the product name. E.g. 'Free 30-day pilot'."}, 'status': {'enum': ['draft', 'active', 'paused', 'completed', 'archived'], 'type': 'string', 'description': 'Campaign status: draft | active | paused | completed | archived.'}, 'scoring': {'type': ['object', 'null'], 'properties': {'geo': {'type': ['array', 'object'], 'items': {'type': 'string'}, 'description': "ISO-3166-1 alpha-2 country codes. Two forms, both accepted: the plain list ['DE','AT','CH'], which is descriptive only, or { list: ['DE','AT'], gate: true } when a company outside the list should be penalised — same meaning as employees.gate. A plain list means gate=false."}, 'weights': {'type': 'object', 'properties': {'geo': {'type': 'integer'}, 'industry': {'type': 'integer'}, 'employees': {'type': 'integer'}, 'seniority': {'type': 'integer'}}, 'description': 'Optional {industry, employees, geo, seniority} overriding the default 35/25/20/20. A weight of 0 still counts toward completeness — use employees.gate=false to drop a dimension entirely.'}, 'employees': {'type': 'object', 'properties': {'max': {'type': 'integer'}, 'min': {'type': 'integer'}, 'gate': {'type': 'boolean'}}, 'description': '{ min, max, gate }. gate=true means a company outside the range is penalised; gate=false means the range is descriptive only.'}, 'seniority': {'type': 'object', 'properties': {'roles': {'type': 'array', 'items': {'type': 'string'}}}, 'description': '{ roles: [string] } — job titles as the user names them, in their language. Common leadership synonyms (GF, CEO, Inhaber, Managing Director, …) are matched anyway and need not be listed.'}, 'industries': {'type': 'array', 'items': {'type': 'string'}, 'description': "Target industries, free text in the user's own words."}}, 'description': "Lead-scoring profile for THIS campaign, merged into icp_snapshot.scoring (the rest of icp_snapshot is left alone). Fill it only from what the user told you — never from general knowledge or another campaign; a wrong profile scores every lead wrongly and the numbers look plausible either way. Set employees.gate=false when company size is context rather than a criterion ('no hard cut-off', 'roughly', 'kein Gate'): the dimension then counts neither toward the score nor toward completeness. Pass null to remove the profile and fall back to the global ICP. Rejected with scoring_invalid if it names none of industries/employees/geo/seniority.roles."}, 'channels': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Outreach channels for this campaign.'}, 'end_date': {'type': 'string', 'description': 'Optional ISO date YYYY-MM-DD. Null = open-ended.'}, 'start_date': {'type': 'string', 'description': 'ISO date YYYY-MM-DD.'}, 'campaign_id': {'type': 'string', 'description': 'ID of the campaign to update (from listCampaigns).'}, 'icp_snapshot': {'type': 'object', 'description': 'Frozen ICP for this campaign. May be a narrowed variant of the global ICP.'}, 'success_metric': {'type': 'object', 'description': "{ type: 'replies'|'demos'|'sqls'|'pipeline_eur', target: number }"}, 'messaging_angle': {'type': 'string', 'description': 'The hook in the first email/message — the news/trend/insight that earns the read.'}, 'pain_hypothesis': {'type': 'string', 'description': 'ONE sentence stating the specific pain this campaign assumes the persona has.'}, 'persona_snapshot': {'type': 'object', 'description': 'Frozen target persona for this campaign.'}, 'product_snapshot': {'type': 'object', 'description': 'Frozen product info. Schema: { name, description, value_props[], differentiators[], pricing_hint }.'}, 'fit_gate_min_score': {'type': ['integer', 'null'], 'description': 'Fit-gate threshold on score_fit for THIS campaign, 0 to 100. Default is 60 when unset — only change it when the user asks. Lower it when a documented signal decides suitability rather than the score: reveal then stops dropping leads that sit just below the default, which is the case this exists for. Pass null to put the campaign back on the default.'}}}
updateCampaignLead
Campaign: Update Lead
Update fields on an existing campaign lead. Pass lead_id (UUID from listCampaignLeads) and an updates object with only the fields to change. Use this to mark leads as rejected, manually correct enrichment data, or attach custom metadata. Setting lifecycle_stage='rejected' REQUIRES rejected_reason in the same call. The metadata field is shallow-merged into existing metadata jsonb — existing keys are preserved unless overwritten by the same key. Score/dim_*/icp_version_hash are NOT writable here (those come from scoreLeads). crm_external_id/crm_synced_at are NOT writable either (CRM-Sync owns those).
可能执行破坏性操作
输入模式
{'type': 'object', 'required': ['lead_id', 'updates'], 'properties': {'lead_id': {'type': 'string', 'description': 'UUID of the campaign_lead to update'}, 'updates': {'type': 'object', 'properties': {'metadata': {'type': 'object', 'description': 'Shallow-merged into existing metadata. Pass {} to clear all keys.'}, 'company_name': {'type': 'string'}, 'contact_name': {'type': 'string'}, 'contact_role': {'type': 'string'}, 'contact_email': {'type': 'string'}, 'contact_phone': {'type': 'string'}, 'company_domain': {'type': 'string'}, 'company_country': {'type': 'string'}, 'lifecycle_stage': {'enum': ['imported', 'enriched', 'scored', 'crm_ready', 'crm_synced', 'rejected', 'bounced'], 'type': 'string'}, 'rejected_reason': {'type': 'string', 'description': "REQUIRED when lifecycle_stage='rejected'"}, 'company_industry': {'type': 'string'}, 'company_linkedin': {'type': 'string'}, 'contact_linkedin': {'type': 'string'}, 'company_employees': {'type': 'integer'}, 'contact_seniority': {'type': 'string'}, 'enrichment_status': {'enum': ['pending', 'enriched', 'failed', 'skipped'], 'type': 'string'}}, 'description': 'Object with fields to change. metadata is shallow-merged.'}}}
updateLeadSignal
Campaign: Update Lead Signal
Correct ONE stored why-now signal in place. signal_id is the `id` of a signal from listLeadSignals — call that with active_only=false to also see expired signals. updates carries only the fields to change: type, signal, source_url, source_label, observed_at, last_confirmed_at. Anything else is ignored and named in `ignored_fields`. The signal stays on its lead: lead_id is not writable, so a signal recorded on the wrong company is removed with deleteLeadSignal, not moved. Changing type, observed_at or last_confirmed_at makes the database recompute expires_at — the reply says so in `expires_at_neu_berechnet`; expires_at itself cannot be set. Setting last_confirmed_at to the date you re-checked the source revives a signal whose expiry has passed — for signals that describe an ongoing state (e.g. tech_change: the system is still in use). Event types (funding, hiring, …) keep counting from observed_at, so for them last_confirmed_at extends nothing; check `signal.expires_at` in the reply. Errors: 404 signal_not_found (unknown id, or not in this workspace), 409 duplicate_source_url (this lead already has another signal with that URL — delete that one first or use a different source), 400 with code signal_too_short, signal_too_long, invalid_type or source_required.
可能执行破坏性操作
输入模式
{'type': 'object', 'required': ['signal_id', 'updates'], 'properties': {'updates': {'type': 'object', 'properties': {'type': {'enum': ['funding', 'acquisition', 'hiring', 'job_change', 'tech_change', 'expansion', 'leadership', 'regulatory', 'event', 'inbound', 'other'], 'type': 'string'}, 'signal': {'type': 'string', 'description': 'The one-sentence signal, 10 to 1000 characters.'}, 'source_url': {'type': 'string', 'description': 'Source URL, must start with http:// or https://. Unique per lead.'}, 'observed_at': {'type': 'string', 'description': 'YYYY-MM-DD — date of the source or event, not the date we saw it.'}, 'source_label': {'type': 'string', 'description': "Readable source name. It takes precedence over the URL host in `cite`, which goes verbatim into outreach — so a publication or site name, never a colleague's name."}, 'last_confirmed_at': {'type': 'string', 'description': 'YYYY-MM-DD — when the fact was last re-checked.'}}, 'description': 'Only the fields to change. At least one of them.'}, 'signal_id': {'type': 'string', 'description': 'UUID of the signal — the `id` field of a signal in listLeadSignals.'}}}
updateMemory
Update Memory
Update content or metadata of a stored memory. Use to enrich, fix, or reclassify. You MUST provide a change_reason explaining WHAT changed and WHY. The reason is stored in the version history audit log.
可能执行破坏性操作
输入模式
{'type': 'object', 'required': ['embedding_id', 'change_reason'], 'properties': {'new_content': {'type': 'string', 'description': 'Updated text content.'}, 'embedding_id': {'type': 'string', 'description': 'ID of the memory to update.'}, 'new_metadata': {'type': 'object', 'description': 'Optional metadata to replace, e.g. chapter or tags.', 'additionalProperties': {'type': 'string'}}, 'change_reason': {'type': 'string', 'description': "REQUIRED: Why this memory is being updated, e.g. 'Added Q2 metrics', 'Fixed company name', 'User requested update'. Stored in audit log."}}}
updateTask
Update Task
Update fields of a task. Partial update; status='done' sets done_at automatically. ice_score recomputes when impact/confidence/effort change.
可能执行破坏性操作
输入模式
{'type': 'object', 'required': ['id'], 'properties': {'id': {'type': 'string', 'description': 'ID of the task to update (from listTasks).'}, 'owner': {'type': 'string', 'description': 'Assignee (free text).'}, 'steps': {'type': 'array', 'items': {'type': 'object', 'required': ['text'], 'properties': {'id': {'type': 'string'}, 'done': {'type': 'boolean'}, 'text': {'type': 'string'}}}, 'description': "Replace the task's checklist. Omit to leave unchanged."}, 'title': {'type': 'string', 'description': 'Optional new task title.'}, 'bucket': {'enum': ['now', 'next', 'later', 'follow-up'], 'type': 'string', 'description': 'Time horizon: now | next | later | follow-up.'}, 'detail': {'type': 'string', 'description': 'Optional longer description of the task.'}, 'impact': {'type': 'integer', 'maximum': 10, 'minimum': 1, 'description': 'ICE impact, 1-10 (higher = more impact).'}, 'status': {'enum': ['open', 'in_progress', 'done', 'dropped'], 'type': 'string', 'description': 'New status: open | in_progress | done | dropped.'}, 'confidence': {'type': 'number', 'maximum': 1, 'minimum': 0, 'description': 'ICE confidence, 0-1 (probability the impact materializes).'}, 'effort_constraint': {'type': 'integer', 'maximum': 10, 'minimum': 1, 'description': 'Effort on the bottleneck lane (see workspace label_constraint).'}, 'effort_nonconstraint': {'type': 'integer', 'maximum': 10, 'minimum': 1, 'description': 'Effort on the non-bottleneck lane.'}}}
uploadDocument
Upload Document
Upload a file to GrowthKit document storage. Optionally extracts text and embeds insights.
输入模式
{'type': 'object', 'required': ['file_base64', 'filename', 'mime_type'], 'properties': {'title': {'type': 'string', 'description': 'Optional document title. Defaults to the filename.'}, 'chapter': {'type': 'string', 'description': 'Optional memory chapter to associate extracted insights with.'}, 'category': {'enum': ['battlecards', 'reports', 'uploads', 'exports', 'templates', 'presentations'], 'type': 'string', 'description': 'Optional storage category.'}, 'filename': {'type': 'string', 'description': 'Filename with extension.'}, 'mime_type': {'type': 'string', 'description': 'MIME type.'}, 'description': {'type': 'string', 'description': 'Optional short description of the document.'}, 'file_base64': {'type': 'string', 'description': 'Base64-encoded file content.'}, 'extract_insights': {'type': 'boolean', 'description': 'If true, extract text and embed insights into memory. Default: false.'}}}
verifyEmail
Verify Email
Check if an email is deliverable. Use before outreach.
只读 可访问外部资源
输入模式
{'type': 'object', 'required': ['email'], 'properties': {'email': {'type': 'string', 'description': 'Email address to verify for deliverability.'}}}
已更改
pipelineRun
2026年9月25日 02:59
已添加
getCampaignLead
2026年9月25日 02:59
已更改
listCampaignLeads
2026年9月25日 02:59
已更改
show_callable_leads
2026年9月23日 02:51
已更改
pipelineRun
2026年9月23日 02:51
已更改
pipelineStatus
2026年9月23日 02:51
已更改
listCampaignLeads
2026年9月23日 02:51
已更改
updateCampaign
2026年9月23日 02:51
已更改
getTopLeads
2026年9月23日 02:51
已更改
findEmail
2026年9月23日 02:51
已更改
findContacts
2026年9月23日 02:51
已更改
enrichPerson
2026年9月23日 02:51
已更改
enrichCompany
2026年9月23日 02:51
已添加
deleteLeadSignal
2026年9月21日 02:57
已添加
updateLeadSignal
2026年9月21日 02:57
已更改
listLeadSignals
2026年9月21日 02:57
已添加
getAeoReport
2026年9月17日 12:55
已添加
getSeoReport
2026年9月17日 12:55
已添加
toggleStep
2026年9月17日 12:55
已添加
setTaskWeights
2026年9月17日 12:55
已添加
updateTask
2026年9月17日 12:55
已添加
getOpenTasks
2026年9月17日 12:55
已添加
listTasks
2026年9月17日 12:55
已添加
createTask
2026年9月17日 12:55
已添加
getWorkingMemory
2026年9月17日 12:55
已添加
setWorkingMemory
2026年9月17日 12:55
已添加
save_call_outcome
2026年9月17日 12:55
已添加
place_call
2026年9月17日 12:55
已添加
show_callable_leads
2026年9月17日 12:55
已添加
listLeadSignals
2026年9月17日 12:55