{"service":"Portal Signal","source":"https://mcp.hubspot.com","cadence":"hourly","state":"changed","lastScanAt":"2026-10-13T16:00:12.994Z","logicalHour":"2026-10-13T16:00:00.000Z","toolCount":27,"currentHash":"f05bd167961aaa1423f852669e07783b969d10b5faa04f934cad88118ac8e446","latestChange":{"detectedAt":"2026-10-13T16:00:12.994Z","kind":"behavioral","summary":"0 added, 0 removed, 1 modified.","previousHash":"2659a45c161847aa27e01d34176b36eb0bac2c3c9d4e044024b1c8f8ea6d22f8","currentHash":"f05bd167961aaa1423f852669e07783b969d10b5faa04f934cad88118ac8e446","added":[],"removed":[],"modified":[{"name":"manage_landing_page","severity":"behavioral","fields":["input schema","description"],"summary":"manage_landing_page: input schema, description changed"}]},"tools":[{"name":"discover_hubspot_schema","description":"Discovers HubSpot data types, pipelines, and stages. <capabilities> - Searches across all HubSpot data types available to the current user - Returns type names that can be used as input to other tools - Shows read/write access status for each type based on the current user's permissions - Returns pipelines and their stages (including open/closed status) for a data type </capabilities> <usage_guidance> - Use this tool FIRST when you need to identify which data types exist before querying data - Use SEARCH_OBJECT_TYPES when you don't know the exact type name - Use GET_OBJECT_TYPES when you already know the type names (e.g. CONTACT, DEAL), or with an empty typeNameFilter list to retrieve all available types - Use GET_PIPELINES to list the pipelines and stages for a type (e.g. deal or ticket stages) - GET_PIPELINES stage metadata: `probability` (DEAL only) is the likelihood (0-1) the deal closes successfully. `state` (all other types) is OPEN or CLOSED, except for LEAD where the values are NEW, IN_PROGRESS, QUALIFIED, or UNQUALIFIED — QUALIFIED and UNQUALIFIED are the closed/terminal states, NEW and IN_PROGRESS are open - Check readAccess/writeAccess before attempting operations on a type </usage_guidance> <examples> <example> <user_input>How many support requests did we get last month?</user_input> <tool_call>{\"query\": {\"_queryType\": \"SEARCH_OBJECT_TYPES\", \"searchTerms\": \"support requests tickets\"}}</tool_call> </example> <example> <user_input>How many products do we have?</user_input> <thoughts>\"products\" is ambiguous — it may be HubSpot's standard Products object or a custom object like p12345_product_models, and semantic search tends to rank the standard one first, so I won't just take the top hit. I'll review all candidates and, if more than one plausibly matches, ask the user to clarify before querying.</thoughts> <tool_call>{\"query\": {\"_queryType\": \"SEARCH_OBJECT_TYPES\", \"searchTerms\": \"products\"}}</tool_call> </example> <example> <user_input>What fields are on contacts and deals?</user_input> <tool_call>{\"query\": {\"_queryType\": \"GET_OBJECT_TYPES\", \"typeNameFilter\": [\"CONTACT\", \"DEAL\"]}}</tool_call> </example> <example> <user_input>What types of data does HubSpot have?</user_input> <tool_call>{\"query\": {\"_queryType\": \"GET_OBJECT_TYPES\"}}</tool_call> </example> <example> <user_input>What are the deal pipeline stages?</user_input> <tool_call>{\"query\": {\"_queryType\": \"GET_PIPELINES\", \"objectType\": \"DEAL\"}}</tool_call> </example> </examples>"},{"name":"get_aeo_metrics","description":"Portal-level AEO analytics: brand visibility, mentions, citations, competitor share-of-voice, and per-assistant breakdowns for a date window. Select the sections you need with `include`, a JSON array of section names, e.g. [\"SUMMARY\", \"PROMPTS\"] (SUMMARY, PROMPTS, CITATIONS, CITATION_ANALYSIS, COMPETITORS, ASSISTANT_BREAKDOWN, RUN_STATUS, ICPS_AND_PRODUCTS, BUSINESS_UNITS, LIMITS); defaults to {SUMMARY, RUN_STATUS}. businessUnitId is optional: omit it to use the portal's business unit automatically, or call once with include=[\"BUSINESS_UNITS\"] first to choose one when the portal has several. CITATION_ANALYSIS additionally requires a citationUrl. Dates are ISO-8601 (YYYY-MM-DD); default to the last 30 days. Call tool_guidance (mcpToolInstructions) for the full section catalog, setup-status semantics, and field-level details."},{"name":"get_campaign_attribution_reports","description":"REQUIRED FIRST STEP: before your first call, invoke tool_guidance for \"get_campaign_attribution_reports\" and follow it. The dimension names, filter syntax, date-range semantics, grouping rules, and query patterns live in tool_guidance, not in this description; calling this tool without them produces wrong or failed queries. If you skip tool_guidance, submit your first call with hasReadToolInstructions=false (the default); the tool will return status=READ_TOOL_INSTRUCTION_REQUIRED with the full instructions in toolInstructions — read them, then retry with hasReadToolInstructions=true. Revenue ranking: dimensions=[CAMPAIGN], metrics=[REVENUE], sortByMetric=REVENUE. Attribution data tool: all metrics (revenue, deal amounts, deal counts, contact counts) are scoped to the closed-won deal attribution pipeline. Use for revenue, attributed deal, and attributed contact questions. CONTACT_COUNT = contacts whose interactions influenced closed-won deals; this is NOT a \"new contacts generated\" metric. For non-attribution contact queries (new contacts, influenced contacts, sessions), use read_campaign_data with GET_ANALYTICS. TOP/BEST PERFORMING ASSET: use dimension=ASSET_TITLE; set sortByMetric to the metric the question asks about (REVENUE when unspecified, DEAL_COUNT for \"most deals\", DEAL_AMOUNT for \"highest deal value\", CONTACT_COUNT for \"most contacts\", ATTRIBUTION_COUNT for \"most interactions\"). Attribution metrics share a common unit across all asset types. Do NOT rank by calling getCampaignAssetMetrics per type — those engagement metrics (views vs. open rate) are not cross-type comparable. Scope note: this data covers closed-won / attributed deals only. For deals at any stage (open, opportunity, qualifiedtobuy, and so on), use read_campaign_data with operation=GET_ASSET_METRICS and assetType=DEAL (returns name, stage, amount, close date for all associated deals) or search_crm_objects with a campaign association filter. For long-running queries, this returns a PROCESSING status with a taskId to poll for results."},{"name":"get_content_analytics_report","description":"Run a content analytics report across landing pages, website pages, and blog posts in the portal. Returns: TOTALS: ranked rows of contentId, contentTitle, and the requested metric value. TIME_SERIES: per-contentId series of {timestamp, value} points for the requested metric and period. SUMMARY: aggregated per-period points (one value per bucket) for the requested metric. PEOPLE: list of contacts/visitors (contactId or session identifier, plus available identity fields) who viewed the specified contentIds. Pick mode by intent: TOTALS to rank, TIME_SERIES to chart trends per page, SUMMARY for a single aggregated trend, PEOPLE for who-viewed lookups. TIME_SERIES/PEOPLE require contentIds. Examples: mode=TOTALS metric=VIEWS limit=10 -> top 10 pages by views. mode=TIME_SERIES contentIds=[123] metric=SUBMISSIONS period=LAST_30_DAYS -> daily submissions for page 123. Requires 'Read analytics related to pages, blogs and other content assets' permission and a Pro or Enterprise portal."},{"name":"get_conversation_channel_metadata","description":"List inboxes, channels, and channel instances in this portal. Call before filtering search_conversations by channel/inbox/instance — do not guess IDs. Use channelId for a channel-type filter and channelInstanceId for a specific configured instance."},{"name":"get_crm_objects","description":"Fetches multiple CRM objects of the same object type in a single request. <returns> A list of CRM objects with their properties, identified by their unique IDs, containing: - id: Unique identifier for the CRM object - properties: Key-value pairs of property names and their values - createdAt: Timestamp when the object was created - updatedAt: Timestamp when the object was last updated - url: URL to view the object in HubSpot </returns> <usage_guidance> - Use the `search_crm_objects` tool to list a few objects first without a filter criteria - Then use the `get_crm_objects` tool to retrieve those objects by their IDs without any properties in the tool input to understand the data model - This will help you understand the structure of the objects and their properties </usage_guidance>"},{"name":"get_marketing_email_analytics","description":"Provides analytics data for marketing emails based on sends in the given date range. To find emails created or published within certain date ranges, use search_crm_objects instead. The request takes a single field, analysisRequest, which is an OBJECT — never a bare string. It carries a \"_type\" discriminator plus the section settings for that type. Available analysisRequest types (set as analysisRequest._type): - \"OVERVIEW\" — portal-level aggregate statistics (sends, deliveries, opens, clicks, bounces, unsubscribes) over a date range, optionally scoped to specific emails or broken down by time interval. Uses statisticsSection. - \"HEALTH\" — portal email health diagnostics. Four sections: mxGroupStatisticsSection (delivery performance statistics by the destination domains with the most deliveries, over a date range); healthScoresSection (monthly 0–100 health scores with per-metric breakdown for click, open, hard bounce, spam report, unsubscribe, and click-to-open — up to 6 months, GLOBAL or INDUSTRY benchmark); sourceHealthScoresSection (same per-metric breakdown per contact source, i.e. where contacts were imported from, past ~30 days); bounceReasonsSection (breakdown of bounces by reason category over a date range, split into hard and soft bounces, optionally scoped to a single MX group). - \"RECIPIENTS\" — delivery outcome and engagement summary for a specific contact recipient, with an optional ordered event timeline (sent, opened, clicked, bounced, etc.). Uses recipientDetailsSection. No operation returns a collection of all recipients for an email; only individual recipient information is available. - \"UNSUBSCRIBE_SURVEY\" — breakdown of unsubscribe survey responses by reason code (NO_LONGER_INTERESTED, DID_NOT_SIGN_UP, TOO_MANY_EMAILS, IRRELEVANT_CONTENT, OTHER) over a date range. Optionally scoped to a specific email by emailContentId. Use this to understand WHY contacts unsubscribed and improve future emails."},{"name":"get_organization_details","description":"Get organization-wide teams, job titles (roles), seats, and account info (timezone, currency, account type, portal name). Use the include parameter (TEAMS, SEATS, JOB_TITLES, ACCOUNT_INFORMATION) to fetch only what you need. Returns only the included sections (or all if include is omitted): - TEAMS: teams with name and member owner IDs (org-wide, not personal). - SEATS: available seat type NAMES only, not user counts. - JOB_TITLES: roles/job titles present in the org. - ACCOUNT_INFORMATION: timezone, currency, account type, UI domain, account ID, portal name, create date. - guidance (optional): if present, read it carefully; it may hold a user-facing message (e.g. missing permissions to relay) or an internal hint (e.g. name disambiguation). Routing: - First-person personal context (\"my team\", \"my role\", \"my manager\", \"my direct reports\") -> use get_user_details instead. - EXCEPTION: plural \"my teams\" / \"which teams am I on\" -> use THIS tool (get_user_details returns only one primaryTeam). - Org-wide references (\"our sales team\", \"the marketing team\", \"all managers\") -> use this tool. Follow-ups (this tool alone does not count or list users/deals): - Count users by seat or role: get seat type names / job titles here, then filter search_crm_objects on the USER objectType by each. SEATS gives names only, so you MUST follow up with search_crm_objects for per-seat counts. - A team's data (\"our sales team's deals\"): include=[TEAMS] to resolve members to owner IDs, then pass those IDs as filters to search_crm_objects. - Which teams a user is on: include=[TEAMS], then match the user's ownerId against team member ownerIds; match on ownerId ONLY, never on member name."},{"name":"get_properties","description":"Fetches property definitions including data types and enumeration values. <capabilities> - Particularly useful for discovering valid options in enumeration-type properties - To search for actual data, use search_crm_objects </capabilities> <returns> List of property definition objects containing: - name: Property identifier - label: Display label - description: Property description - type: Data type (string, enumeration, number, etc.) - options: For enumeration types, list of valid values with labels </returns> <usage_guidance> - Property details can be unexpectedly large. Consider fetching in batches - It's not advised to pass an objects full list of properties into this tool </usage_guidance>"},{"name":"get_user_details","description":"Returns user, team and hub info; CRM/marketing object and tool availability. Call this before other HubSpot operations to establish the current user's identity, permissions, and which object types and tools are available. Returns info for the current user only — to find other users/owners, search the \"users\" objectType with search_crm_objects. <usage_guidance> - Object availability drives which objectType values other tools accept. Each object type has TWO statuses: `read` (view/search) and `write` (create/update) — check the one matching your operation. - Also reports availability of the other MCP tools; trust this over a tool's own listing, especially when a tool is not AVAILABLE. - Any non-AVAILABLE object or tool needs user action to resolve (some issues the user alone cannot fix) — surface it only if the task requires that object/tool. - `include` selects sections: omitted/empty returns USER_INFORMATION + TOOL_INFORMATION; TEAMS_AND_ROLES must be requested explicitly. - TEAMS_AND_ROLES is personal context only (the user's primary team with member owner IDs, job title, seats, direct report owner IDs). For org-wide teams/roles, \"my teams\", or account settings (timezone, currency, account type), use get_organization_details. - directReports are NOT team members. If the user asks about direct reports and directReports is empty, tell them none are configured and ask before substituting team members — never substitute automatically. </usage_guidance> Availability statuses: - AVAILABLE: usable - REQUIRES_REAUTHORIZATION: disconnect and reconnect the connector - REQUIRES_PERMISSION_MODIFICATION: user lacks a HubSpot permission - REQUIRES_ACCOUNT_MODIFICATION: account needs an upgrade - BLOCKED_FOR_PORTALS_WITH_SENSITIVE_DATA: sensitive data, unresolvable - NOT_AVAILABLE: no user action can enable it Returns: - userId and hubId (accountId) - `guidance` (if present): relay its message to the user - `onboarded` (if present): false = portal has not completed initial setup"},{"name":"manage_aeo_prompts","description":"Read AI responses to tracked prompts, or create and run new tracked prompts. Provide exactly one `operation`, a JSON object (not a string) with an `_operationType` field set to DETAIL (a single prompt's per-run AI response text, citations, and mentions for an assistant and date window) or CREATE (start tracking new prompts and run them immediately). CREATE requires a confirmed=false preview before confirmed=true. Call get_aeo_metrics with include=[\"BUSINESS_UNITS\"] then include=[\"ICPS_AND_PRODUCTS\"] to get the businessUnitId, icpIds, and productIds that CREATE needs. Call tool_guidance (mcpToolInstructions) for the confirmation workflow and per-operation details."},{"name":"manage_aeo_recommendations","description":"List and inspect AI-search brand recommendations for a business unit. Provide exactly one `operation`, a JSON object (not a string) with an `_operationType` field set to LIST (recommendations for a business unit, filterable by status/prompt and paginated via cursor/hasMore/nextCursor), DETAIL (one recommendation enriched with action-status fields and its full citation list), or START_ACTION. Call get_aeo_metrics with include=[\"BUSINESS_UNITS\"] first to get the businessUnitId. Starting a recommendation's action isn't available through the assistant yet — START_ACTION returns a message directing the user to complete it in HubSpot AEO. Call tool_guidance (mcpToolInstructions) for per-operation details."},{"name":"manage_campaign_objects","description":"REQUIRED FIRST STEP: before your first call, invoke tool_guidance for \"manage_campaign_objects\". Creates or updates campaigns, assigns campaign owners, and manages asset associations. <prerequisites> Use CRM tools to retrieve the campaign's campaignCrmObjectId before using CAMPAIGN_UPDATE or CAMPAIGN_ASSET operations. </prerequisites> <mandatory_confirmation_process> Always show proposed changes in a table and get explicit user approval before creating or updating campaigns or modifying asset associations. This step is CRITICAL. <confirmation_rules> - **First confirmation only**: Add this line after the approval prompt: \"Want to skip confirmations for this chat? Just ask.\" - **After 1 confirmation**: Stop offering the skip option, but keep confirming - **If user opts out**: Skip confirmations for remainder of session </confirmation_rules> <confirmation_format> Proposed Changes: | operationType | Field | Value | |-----------------|-------------|-------------------| | CAMPAIGN_CREATE | displayName | Q3 Brand Campaign | Approve? [✅ Yes / ❌ No] Want to skip confirmations for this chat? Just ask. </confirmation_format> </mandatory_confirmation_process> <operations> The `operationType` field is required on every request: - CAMPAIGN_CREATE: set `createRequest` with required `displayName`, optional `startDate`, `endDate`, `goal`, `audience`, `notes`, `customProperties`. - CAMPAIGN_UPDATE: set `updateRequest` with required `campaignCrmObjectId`, optional `displayName`, `startDate`, `endDate`, `goal`, `audience`, `notes`, `customProperties`. - CAMPAIGN_ASSET: set `assetRequest` with required `campaignCrmObjectId`, `assetOperations` (non-empty list of `{action, assetObjectType, crmObjectIds}`). Each entry has its own ADD|REMOVE action. Check `assetOperationFailures` in the response — if non-empty, those operations failed; succeeded ones are already applied. Call CAMPAIGN_ASSET_TYPES_LIST first. - CAMPAIGN_ASSET_TYPES_LIST: no additional fields required. </operations>"},{"name":"manage_crm_objects","description":"Creates or updates CRM objects and their associations. Use createRequest to create objects; use updateRequest to update existing objects or associate two existing objects. For any association or association-label work, first call the `tool_guidance` tool for `manage_crm_objects` — detailed association steps live there. <required_first_step> BEFORE proposing or making any change, call get_user_details and check write availability for the target objectType. If write is not AVAILABLE (e.g. REQUIRES_PERMISSION_MODIFICATION), do NOT show a confirmation table and do NOT call this tool — explain the limitation to the user and stop. </required_first_step> <mandatory_confirmation> Before every create or update, show the proposed changes in a table (columns: Object Type | ID | Property | Current Value | New Value) and get explicit user approval. This is CRITICAL. - Use human-friendly property labels (\"Deal Stage\", not \"dealstage\") and enum display labels (\"Closed Won\", not \"closedwon\"); if you lack label info from a prior call, fetch it with search_properties first. - End with an approval prompt, e.g. \"Approve? [✅ Yes / ❌ No]\". - On the FIRST confirmation only, also add: \"Want to skip confirmations for this chat? Just ask.\" Then stop offering it but keep confirming. If the user opts out, skip confirmations for the session. </mandatory_confirmation> <guidance> - Limit to a MAXIMUM of 10 objects per request (upserts and associations). - Not all properties are editable. Use search_properties to list properties, or search_crm_objects to sample data, before changes. - hubspot_owner_id defaults to the current user when omitted; set it to empty string to leave unowned. - For concept nouns (\"lead\", \"appointment\", \"account\"), ALWAYS call discover_hubspot_schema first for the exact typeName — never infer from training data; schemas are portal-specific (e.g. \"lead\" may be LEAD or a CONTACT lifecycle stage), and creating the wrong object type cannot be undone. </guidance>"},{"name":"manage_landing_page","description":"Create, edit, style, publish, clone, and inspect HubSpot landing pages. One action per call. Reads: MODULES, MODULE_TYPES, MODULE_DEF, MODULE_STYLES, MODULE_GUIDE, REVISIONS, TEMPLATES, FORMS, BRAND_KIT, LIST_CUSTOM_MODULES. Writes: CREATE_FROM_TEMPLATE, CREATE_CUSTOM_TEMPLATE, UPDATE_CUSTOM_TEMPLATE, CREATE_MODULE, UPDATE_MODULE, SET_MODULE_FIELDS, SET_MODULE_STYLES, SET_SECTION_STYLES, INSERT, REMOVE, REMOVE_SECTION, MOVE, SET_METADATA, PUBLISH, CLONE, RESTORE_REVISION. Read before write: MODULES before any edit; MODULE_TYPES before INSERT; MODULE_DEF before unfamiliar fields; MODULE_STYLES before SET_MODULE_STYLES. Writes mutate one shared draft — never concurrently. CREATE_MODULE authors a reusable custom module TYPE (not on any page — check LIST_CUSTOM_MODULES first, then INSERT the returned modulePath). BATCH IS THE DEFAULT for compound edits: group SET_MODULE_FIELDS/STYLES/SECTION_STYLES/METADATA/REMOVE/MOVE into one action=BATCH call (operationsJson, sequential server-side, returns batchResults). Max 10 operations per batch; at most one REMOVE/REMOVE_SECTION/MOVE per batch. NOT batchable (always separate): INSERT/CREATE_*/UPDATE_*/CLONE/PUBLISH/RESTORE_REVISION. If BATCH returns \"not currently supported\", fall back to sequential calls. CREATE_FROM_TEMPLATE requires explicit user confirmation IN CHAT — choosing a template is NOT confirmation. Confirm before PUBLISH/RESTORE_REVISION/UPDATE_CUSTOM_TEMPLATE. Never renders a card — after your LAST edit or PUBLISH, call the render tool. Examples: action=MODULES contentId=123 -> modulesJson. action=CREATE_FROM_TEMPLATE pageName=\"Spring Promo\" templatePath=\"...\" -> {status,contentId,editorUrl}. action=SET_MODULE_FIELDS contentId=456 moduleId=\"hero_1\" fieldOverridesJson={headline:\"Hi\"} -> verifiedFieldsJson. action=SET_SECTION_STYLES contentId=456 moduleId=\"hero_1\" stylesJson={backgroundColor:{r:255,g:238,b:0,a:1}} -> verifiedStylesJson. Scopes: reads need landingpages-read or -write; writes need landingpages-write; PUBLISH additionally needs landingpages-publish."},{"name":"manage_marketing_email","description":"Manages a marketing email's settings and content. Call tool_guidance for guidance. Settings sub-operations (_type): - \"LIST_SUBSCRIPTION_TYPES\" — list subscription types; call before CREATE to get a valid subscriptionTypeId - \"LIST_FROM_ADDRESSES\" — list verified from addresses; call before CREATE to choose a replyToEmail; if address not listed, list options and stop - \"CREATE\" — create a new email (required: name, subject, fromName, replyToEmail, subscriptionTypeId; permanent fields — ask the user BEFORE calling CREATE: templatePath: ask template or blank? call LIST_TEMPLATES to show options; brandId; emailType: BATCH by default, AUTOMATED for workflow emails) - \"POLL_EMAIL_CREATION\" — poll for CRM object; takes marketingEmailId - \"UPDATE\" — update email settings; template/brandId cannot be changed after creation - \"CLONE\" — clone into a new draft - \"GET_EMAIL_DETAILS\" — retrieve current settings - \"GET_TEMPLATE\" — retrieve a template by path - \"LIST_TEMPLATES\" — search/browse templates by kind (CODED or DND) and filename Content sub-operations (marketingEmailObjectId): - \"GET_CONTENT\" — returns the editable layout - \"EDIT_CONTENT\" — always call tool_guidance; resubmit full layout; preserve all styling, only change text/links/images - \"PREVIEW_CONTENT\" — renders the email; returns subjectLine, renderedText, (optional) renderedHtml - \"AB_TEST_EMAIL\" — set up an A/B test on a draft email by adding Version B; use this whenever the user asks to test two versions, create a version B, split test, or try two subject lines — they often don't say \"A/B\" explicitly Only draft emails can be edited. Always show proposed changes and get explicit user confirmation before creating, updating, or editing."},{"name":"manage_onboarding","description":"<purpose>Check whether the user's HubSpot is connected and working. Use it when they ask if it's connected or working, are testing the connection, have just connected, or ask if their CRM is empty or has any data. Also assesses CRM onboarding status and guides the next step.</purpose><usage_guidance>For those connection checks, call this tool right away, without asking first, whatever get_user_details returned for onboarded. Otherwise, call it when get_user_details returns onboarded: false, after answering the user's question and offering to help them get started; do not call it when onboarded: true. Use action to control behavior: leave empty (the default) to just check status. SET_GOAL — records the user's primary goal; requires goal to be set to one of organizeAndTrackContacts, automateMarketing, generateLeads, manageSalesPipeline, customerSupport, billsAndCollectPayment, buildWebsite, createMarketingContent, or stillExploring — map the user's own words to the closest matching value. Only one goal can be stored; setting a new goal replaces any previous one.</usage_guidance><returns>goalStatus: NOT_STARTED or COMPLETE — whether the user has set an onboarding goal; goal: the user's stored goal (present once set); taskGroup: the goal's remaining onboarding tasks (omitted until a goal is set, or when nothing is left to do) — a group with a name, nested childGroups, and tasks, each with a name, description, and link; completed or skipped tasks are excluded; guidance: instructions for you, the agent — when present, follow it and present the returned tasks as options for the user to choose from; do not collapse them into a single step</returns><response_rendering>Render every returned task, including those nested in child groups, as a markdown link [task name](task link) with its description. List all of them (guidance says how many); do not omit or limit. Always render: See all onboarding tasks in your [start guide](guideLink).</response_rendering>"},{"name":"manage_segment","description":"Create a segment, edit an existing one, or add/remove CRM records from one. Set operation.type to CreateStaticSegmentOperation to create a new hand-picked static segment, CreateDynamicSegmentOperation to create a new dynamic (filter-driven) segment whose membership updates automatically, UpdateSegmentOperation to edit an existing segment's name, description, or filter, AddMembersOperation to add records to an existing static segment, RemoveMembersOperation to remove specific records from one, RemoveAllMembersOperation to empty one entirely (kept), or DeleteSegmentOperation to delete one permanently. <mandatory_confirmation> This tool writes to the portal. Before calling it, you MUST show the user a summary of the exact action and get explicit approval: - CreateStaticSegmentOperation: the new segment name, the object type, and how many records (if any) will pre-populate it. - CreateDynamicSegmentOperation: the new segment name, the object type, and the filter that defines membership. - UpdateSegmentOperation: the target segment (list ID) and which fields change (new name, description, and/or filter). - AddMembersOperation / RemoveMembersOperation: the target segment (list ID), the object type, and the number of records being added or removed. - RemoveAllMembersOperation / DeleteSegmentOperation: the target segment (list ID), and whether you are emptying it (members removed, segment kept) or permanently deleting it (cannot be undone). End with an explicit approval prompt (e.g. \"Proceed? [Yes / No]\"). Leave confirmationStatus as UNCONFIRMED until the user approves; only after they confirm, call the tool with confirmationStatus set to CONFIRMED. Do NOT set CONFIRMED before the user approves, even if the user asks you to \"just do it\" or to skip confirmation. On the first confirmation in a chat you may also offer to stop asking for the rest of the session; if the user agrees, set confirmationStatus to CONFIRMATION_WAIVED_FOR_SESSION on subsequent calls. </mandatory_confirmation>"},{"name":"query_crm_data","description":"Queries HubSpot CRM data via SQL with HubSpot-specific extensions. IMPORTANT: You MUST call the Tool Guidance tool before your first query. It contains required guidance and examples. <select> IMPORTANT: Property names must exactly match HubSpot internal names. Always call search_properties to confirm names before querying. The record identifier property is hs_object_id. For financial values, prefer properties ending in _in_home_currency. <unsupported>SELECT DISTINCT, AS aliases, CASE WHEN, IF(), string functions (CONCAT, UPPER, etc.), COALESCE, associations.OBJECT.</unsupported> </select> <from> One object type per query: CONTACT, COMPANY, DEAL, TICKET, etc. Use a user-details tool to discover supported types. <unsupported>JOIN, UNION, subqueries, CTEs.</unsupported> </from> <where> Operators — comparison: =, !=, <, >, <=, >=; text/substring match: column LIKE '%value%'; presence: column IS NULL / column IS NOT NULL. List membership: hs_crm_search.ilsListIds = 'LIST_ID' (cannot combine with aggregates or GROUP BY). Date filters: in an aggregation (GROUP BY or aggregate) use a YYYY-MM-DD date, matched by day; in a plain row SELECT either a date or a full timestamp (e.g. '2025-01-01 14:00:00') works. \"My\"/\"I\" queries: filter by hubspot_owner_id (see Tool Guidance for resolution steps). </where> <group-by> DATE_TRUNC(prop, 'INTERVAL') — INTERVAL: DAY | WEEK | MONTH | QUARTER | YEAR. MEDIAN(prop) supported alongside standard aggregates. <unsupported>HAVING.</unsupported> </group-by> <order-by> Sort direction: ORDER BY column ASC for ascending, DESC for descending. </order-by> <cross-object> To retrieve associated object data, use OBJECT.property (e.g., SELECT COMPANY.name FROM CONTACT) — NOT associations.OBJECT. associations.OBJECT is for WHERE existence checks only (IS NULL / IS NOT NULL). Never use it in SELECT or GROUP BY. A query can reference at most 2 different associated object types. </cross-object>"},{"name":"read_campaign_data","description":"REQUIRED FIRST STEP: before your first call, invoke tool_guidance for \"read_campaign_data\" and follow it; it contains the required parameter details and examples for each operation. Reads campaign data using one of four operations selected by the `operation` field. GET_ANALYTICS: engagement metrics (sessions, new contacts, influenced contacts) for one or more campaigns. GET_ASSET_METRICS: performance metrics for assets of one type associated with a campaign. Metrics are type-specific and NOT comparable across types — do NOT use this for cross-type \"top/best performing asset\" questions; use getCampaignAttributionReports with dimension=ASSET_TITLE for that (its attribution metrics share a common unit across all asset types; set sortByMetric to the metric the question asks about — REVENUE when no metric is specified). GET_CONTACTS: paginated contact IDs attributed to a campaign, filtered by attribution type (NEW_CONTACTS_FIRST_TOUCH, NEW_CONTACTS_LAST_TOUCH, INFLUENCED_CONTACTS). GET_CAMPAIGN_ASSET_TYPES: returns the portal-enabled campaign asset types with human-readable aliases (e.g. AUTOMATION_PLATFORM_FLOW → workflows). No additional request parameters needed."},{"name":"search_conversations","description":"Search or analyze conversation threads, ticket transcripts, and support case messages from HubSpot inboxes. For conversation content tied to a CONTACT, TICKET, DEAL, or COMPANY, including when summarizing or describing a ticket, use this tool, not search_crm_objects/get_crm_objects, which return only record properties, not the message thread. You may use search_crm_objects first to resolve the CRM record ID, then pass it here as objectType + objectId (e.g. objectType=TICKET) to retrieve the thread. Searching NOTE, EMAIL, or CALL engagement objects does not retrieve inbox conversation transcripts. Internal notes and team comments left on a conversation or case live inside the conversation thread, not in NOTE engagements. Retrieve them here with includeAllDialogue=true. Pick one mode per call, or omit all to get the most recent conversations (newest first), with inbox/channel/status filters still applied. Modes: CRM object (objectType + objectId), time range (startTime/endTime), text search (query, with searchMethod=KEYWORD default or SEMANTIC), or aggregation (aggregationDimensions). Text search with either method may combine with time range; no other cross-mode combinations allowed. Aggregation always counts conversations started in the requested window (hs_started_at). Non-aggregation time-range search counts conversations active in the window (hs_lastmodifieddate) — a conversation started before the window but updated within it will appear in time-range results but not in aggregation counts. <usage_guidance> - [Important] For queries like \"my conversations\" or \"our chats\" that imply owner/assignee filtering: use the assignedAgentId request filter to narrow to a specific agent's conversations (pass the HubSpot user id, i.e. the <userId> in actor id \"A-<userId>\"). Each result also includes assignedAgentId for grouping. For wide owner scans, combine with includeMessages=false to scan cheaply - [Important] Attribute agent/rep names by identity, never from message text (signatures are free text and often wrong). Prefer the resolved names this tool already returns: assignedAgentName for a conversation's assignee and, with messageDetail=FULL, senderName on each agent message. Only when a name is absent, fall back to the id (assignedAgentId, or the <userId> in a sender's \"A-<userId>\" actorId) and resolve it with search_crm_objects on USER by hs_internal_user_id (or search_owners when owner id == user id) — not get_crm_objects by object id, which is a different id. actorType=AGENT alone does not prove a human sender - [Important] When a name matches multiple CRM object types (e.g. \"Alex Chen\" matches both a CONTACT and a COMPANY), you MUST call search_conversations for EACH matching object type — do not stop after the first match. Present results from all matches and tell the user which object types you found - For channel filters, call get_conversation_channel_metadata first. Use conversationChannelId for a channel type such as EMAIL, and channelInstanceId for a specific configured address, number, or form. To label CHANNEL aggregation buckets, read the channelName already on each bucket instead of calling get_conversation_channel_metadata - For time-range searches, state the exact dates you used - For a plain \"last N days\" or recency search (not aggregation, which requires both time bounds), set startTime only and omit endTime; pinning endTime to the current moment can drop a conversation modified moments earlier - When choosing between CRM-object lookup and text search, briefly say which you picked and why - For text search, KEYWORD is the default. Pick the method by whether the request's distinctive terms would plausibly appear VERBATIM in the messages, not by how conversational the request sounds: a loosely-phrased question about a specific thing (\"any recent updates on the SAML setup problems?\") is still KEYWORD, because \"SAML\" is what the messages say. Use KEYWORD for product names, error codes, field names, and jargon; use searchMethod=SEMANTIC when there is no such term to match on, for paraphrase, cross-language, or a described situation (\"customer frustrated about being locked out\"). If SEMANTIC plus one KEYWORD fallback both return nothing relevant, report no matching conversation found (it may just be not recently indexed) rather than re-searching - [Important] One focused search is almost always enough: if the first search_conversations call returns relevant conversations, summarize them. Do not re-run reworded or synonym queries, and never fire parallel queries for variations of one request. Only broaden to an alternate phrasing when the first returns nothing or clearly misses - When you already know you need message content, set includeMessages=true on the first call rather than scanning with includeMessages=false and then re-running the same query for messages. Use includeMessages=false only for wide queries where you need to count or filter across many conversations before deciding which ones to read - Use the minimal messageDetail for the task: the default WITH_ROLE fits most summaries; use TEXT_ONLY when speaker roles are irrelevant; request FULL only when you actually need full per-message metadata, not as a default - Paginate by passing a response's nextPageAfter back as the after parameter. When a response has no nextPageAfter, you have the last page, so stop; do not invent, increment, or guess a cursor to fetch more - For partial results, list which objects had conversations and which didn't - When summarizing, include the number of messages returned; note this may be capped by messageLimit (default 100) and may not reflect the full conversation - For \"how many conversations mention X\", use text search and read totalConversations. Name an inbox to get a distinct-conversation count for that inbox/time scope (approximate only for very large match counts); it counts ALL keyword matches and can exceed the page returned. Without an inbox, totalConversations reflects only the returned page, not a portal-wide total. The count reflects the keyword match only, so treat it as approximate whenever conversationChannelId, channelInstanceId, or conversationStatus is set (those filters and blocked-channel exclusions are applied client-side after the count is computed). It can also be positive even when no conversations are returned (matches scored below the relevance floor). Set maxConversations low (and includeMessages=false) for a cheap count - [Important] For \"why are customers contacting us / common reasons / support themes\" questions, use conversations, not tickets alone (chat and email may never become a ticket). There is no topic/reason dimension: summarize themes from a small time-range sample (includeMessages=true) and say the result is a sample; aggregation (CHANNEL, STATUS, STARTED_AT_DAY/WEEK) gives volume and trend, not topics </usage_guidance>"},{"name":"search_crm_objects","description":"Searches and retrieves CRM records from HubSpot by filters, associations, and criteria. Returns actual records, not field definitions (use search_properties to discover fields, discover_hubspot_schema to discover object types). Returns: id, requested properties, urlTemplate, total (match count for analytics/pagination), offset. Rules: - objectType MUST be an exact type identifier. Standard types (CONTACT, DEAL) work directly; for any concept noun (\"lead\", \"appointment\", \"account\"), ALWAYS call discover_hubspot_schema for its typeName — never infer from training data, as schemas are portal-specific (e.g. \"lead\" may be a LEAD or a CONTACT lifecycle stage). Re-resolve if results are empty/unexpected. - To learn a type's data model or recover from 0 results, sample via get_crm_objects (no properties) and confirm values with search_properties before refining filters. - Max 5 filterGroups, up to 6 filters each, 18 total. - Always check total; never substitute sample/partial data for actual data. - Prefer this tool for record retrieval; for complex analysis, refine requirements with the user and segment large datasets. - You MUST return a clickable URL (from urlTemplate, with UTM params) for every record. - Use associatedWith to filter/list objects by association; use search_owners to list users/owners. - First-person queries (\"my deals\", \"contacts I own\") MUST filter hubspot_owner_id = {ownerId} from get_user_details; fetching ownerId without applying it returns all records, not the user's. - Currency: when returning a currency amount (DEAL.amount, LINE_ITEM.price, QUOTE.hs_quote_amount, INVOICE.hs_amount_billed, CART/ORDER.hs_total_price, SUBSCRIPTION.hs_mrr, COMMERCE_PAYMENT.hs_initial_amount) also request its currency-code property (DEAL: deal_currency_code; LINE_ITEM: hs_line_item_currency_code; QUOTE/INVOICE: hs_currency; else hs_currency_code). For DEAL aggregation use amount_in_home_currency (never pair with deal_currency_code); never sum raw amount across differing currencies."},{"name":"search_intent_signals","description":"Buyer-intent signals for companies and contacts. SEARCH returns signal records, LIST returns the portal's signal types, AGGREGATE returns counts grouped by company/companies. Can narrow aggregates by a signal type. Set `query` to one shape and always set `_queryType`. Put known names in one SEARCH for aliases and suggestions; LIST does not need to be called but can be used for broad catalog discovery. An unknown field is dropped, not rejected, so check the response matches the filters you asked for."},{"name":"search_owners","description":"Lists and searches for owners who can be assigned to CRM records. <capabilities> - Supports searching by name/email or batch lookup by owner IDs - HubSpot owner ids and user IDs are distinct, lookups only work when owner ids are provided specifically </capabilities> <returns> List of owner objects containing: - ownerId: The ID to use for hubspot_owner_id assignments - name: Display name of the owner - isActive: Whether the owner is currently active </returns> <examples> <example> <description>Search by name</description> <query>{\"searchQuery\": \"John Smith\"}</query> </example> <example> <description>Lookup specific IDs</description> <query>{\"ownerIds\": [12345, 67890]}</query> </example> <example> <description>Paginate results</description> <query>{\"limit\": 50, \"offset\": 50}</query> </example> </examples>"},{"name":"search_properties","description":"Finds the most relevant CRM property definitions using keyword-based search. <capabilities> - Lists all property definitions for an object type when no search terms are provided - To search for actual record data, use search_crm_objects </capabilities> <returns> A filtered list of matching properties, each with: - name: Property identifier - label: Display label - description: Property description - matchScore: Relevance score for the query (absent when no query is provided) </returns> <usage_guidance> - Prefer the keywords field to pass multiple property-name guesses in a SINGLE request (best performance); use the query field for a single guess (backward compatibility) - Keywords must be property-name guesses (e.g. \"assignee\", \"zip_code\"), NOT natural-language phrases - MAXIMUM 5 keywords per request; exceeding this returns a validation error - Omit search terms to return ALL properties for the object type (useful for discovery) </usage_guidance> <examples> - \"open tickets grouped by urgency\" -> {\"objectType\": \"TICKET\", \"keywords\": [\"urgency\"]} - \"calls assigned to me\" -> {\"objectType\": \"CALL\", \"keywords\": [\"assignee\", \"assigned_to\", \"call_owner\", \"owned_by\"]} - \"companies by name, employee count, zip, last contact\" -> {\"objectType\": \"COMPANY\", \"keywords\": [\"name\", \"employees\", \"zip_code\", \"last_contact\"]} - \"analyze all tickets (property discovery)\" -> {\"objectType\": \"TICKET\"} </examples>"},{"name":"submit_feedback","description":"Collects and submits user feedback about the HubSpot connector to HubSpot. Only after the user explicitly confirms the exact feedback to send. <scope> EXCLUSIVELY for feedback about HubSpot connector tools (search_crm_objects, manage_crm_objects, get_properties, etc.). Do NOT use for: - Non-HubSpot tools (Slack, Microsoft 365, Notion, iMessage, Intercom, etc.) - General AI/LLM quality (wrong answers, hallucinations, formatting) - HubSpot product/UI issues unrelated to the connector If the issue is not about a HubSpot connector tool, do NOT initiate feedback - tell the user this channel is for HubSpot connector issues only. </scope> <when_to_invoke> Agent-detected: user corrects HubSpot connector behavior, reports it returned wrong data/errors, or is dissatisfied with a HubSpot connector tool. User-initiated: explicit requests (\"I want to give feedback\"), or intent to reach HubSpot (\"HubSpot should know...\", \"Tell HubSpot...\"). </when_to_invoke> <flow> 1. Agent-detected only: finish your answer first, then after a divider (---) note the connector issue and OFFER feedback; if declined, continue and never ask again this session. 2. Ask the user to describe the issue in their own words; WAIT. 3. Preview \"Here's what I'll send to HubSpot: [their exact words]. Should I go ahead?\" and WAIT for confirmation. 4. Only call this tool once the user confirms. </flow> <critical_requirements> - NEVER call without explicit user confirmation of the feedback to send. - The feedback field MUST be the user's own words - never auto-generate or paraphrase. - Claude/ChatGPT thumbs up/down send feedback to Anthropic/OpenAI, NOT HubSpot; only this tool sends to HubSpot. - NEVER submit feedback about non-HubSpot tools or connectors. </critical_requirements>"},{"name":"tool_guidance","description":"<purpose> Retrieves guidance and usage instructions for a set of HubSpot tools. </purpose> <when_to_use> - If a tool's description isn't enough to commit to using it - To find if a tool's inputs or outputs have further semantic meaning - To learn understand if and how certain tools can work together </when_to_use> <how_to_call> Pass the names of the tools you want guidance for in `toolNames` (e.g. [\"manage_crm_objects\"]). Provide at least one tool name. </how_to_call>"}]}