tools/call over
POST /hubspot/mcp. The connector is connected through OAuth (HubSpot login; see
Forbind HubSpot CMS).
Endpoint:
https://mcp.consile.ai/hubspot/mcp. HubSpot CMS is its own named
connector with only its own tools.Write safety: guardrail model
The nine write tools split into two tiers based on reversibility:- Draft operations run freely. Creating a page, editing a blog post draft, or upserting a HubDB row all target the unpublished draft buffer. Nothing reaches the live site and the change can be discarded. No confirmation required.
- Publishing and destructive actions require
confirm: true. These are: pushing a page draft live (publish_page), publishing a blog post draft (publish_blog_post), publishing a HubDB table draft to live pages (publish_hubdb_table), and discarding a HubDB draft (reset_hubdb_draft). Withoutconfirm: true, the tool returns aWritePreviewdry-run and calls no HubSpot API.
WritePreview shape
When a write action requires confirmation butconfirm is omitted or false, the tool
returns this shape instead of calling HubSpot:
confirm: true added.
Draft-first default on create
New pages and blog posts are always created withstate: "DRAFT". The connector
enforces this regardless of what the caller sends, so nothing is accidentally published
on first create.
Portal tier requirement
The OAuth scopes this connector requests (content, hubdb, business-intelligence)
require the connected HubSpot portal to be on one of:
- CMS Hub or Content Hub
- Marketing Hub Professional or Enterprise
Authentication
HubSpot CMS uses the standard OAuth authorization-code flow with refresh token. Each tenant authorizes Consile’s HubSpot app and theirrefresh_token is vaulted under
(tenantId, "hubspot"). Access tokens expire after roughly 30 minutes and are
renewed silently by the platform’s refreshing vault. The AI never sees the token.
OAuth scopes: content, hubdb, business-intelligence, oauth (the last is
auto-injected by HubSpot on every grant and is not a functional scope).
Revoking access. There is no upstream revoke in the portal in v1. To pull access
back from HubSpot, uninstall the Consile app in HubSpot’s connected apps settings.
Disconnecting in the Consile portal deletes the vaulted token immediately.
Shared parameters
Paging
List tools use cursor-based paging. Passafter from paging.next.after in the
previous response to retrieve the next page.
integer
default:"20"
Max items to return in this page (1-100).
string
Cursor from a previous response’s
paging.next.after.Page type
string
default:"site"
Which page tree:
"site" (website pages) or "landing" (landing pages).HubDB table reference
string
required
HubDB table numeric id (preferred) or unique table name.
Read tools: pages (4 tools)
list_pages
List website or landing pages with paging. Passarchived: true to list archived
pages instead of live ones.
string
default:"site"
integer
default:"20"
string
boolean
List archived pages instead of live ones.
{ results, paging } where each result includes id, name, slug,
state, htmlTitle, metaDescription, publishDate, archivedAt, createdAt,
updatedAt.
get_page
Retrieve a single site or landing page (the live/published version) by id.string
default:"site"
string
required
The page id.
get_page_draft
Read the unpublished draft buffer of a page to inspect pending edits before publishing.string
default:"site"
string
required
The page id.
get_page but reflects staged edits).
list_page_revisions
List prior published revisions of a page for review or rollback planning.string
default:"site"
string
required
The page id.
integer
default:"20"
string
{ results, paging } where each revision includes id, createdAt,
createdBy.
Read tools: blog (4 tools)
list_blog_posts
List blog posts with paging. Passarchived: true to list archived posts.
integer
default:"20"
string
boolean
List archived posts instead of live ones.
{ results, paging } where each result includes id, name, slug,
state, contentGroupId, htmlTitle, metaDescription, publishDate, tagIds,
authorName, createdAt, updatedAt.
get_blog_post
Get a single blog post by id. Setdraft: true to read the draft buffer instead of
the live version.
string
required
The blog post id.
boolean
Read the draft buffer instead of the live version.
postBody (HTML content).
list_blog_tags
List blog tags with paging.integer
default:"20"
string
{ results, paging } where each tag includes id, name, slug,
createdAt, updatedAt.
list_blog_authors
List blog authors with paging. Authors are referenced by posts; this is a read-through of the author registry.integer
default:"20"
string
{ results, paging } where each author includes id, displayName,
email, slug, avatar.
Read tools: HubDB (5 tools)
list_hubdb_tables
List the account’s HubDB tables with id, name, label, column metadata, row count, and publish state.integer
default:"20"
string
{ results, paging } where each table includes id, name, label,
columns (array with type, name, label, options), rowCount, publishedAt.
get_hubdb_table
Get a single HubDB table’s full definition including column schema: types, options, andforeignTableId/foreignColumnId for FOREIGN_ID columns. Call this before
writing rows to understand the expected value types.
string
required
columns array.
list_hubdb_rows
List rows of a published HubDB table with paging. Returns each row’s cell values per column.string
required
integer
default:"20"
string
{ results, paging } where each row includes id, values (map of
column name to cell value).
get_hubdb_row
Get a single published HubDB row by rowId.string
required
string
required
The row id.
{ id, values }.
export_hubdb_table
Export a HubDB table’s data as a CSV or Excel file. Returns the raw file content.string
required
string
default:"CSV"
Export format:
"CSV" or "EXCEL".{ tableIdOrName, format, data } where data is the raw file content
as a string.
Read tools: analytics (1 tool)
get_traffic_analytics
Read traffic and page-view analytics over a date range. Optionally broken down by content, source, geolocation, or UTM campaign.Requires Marketing Hub Professional/Enterprise on the connected portal. The
business-intelligence scope gates this endpoint.string
default:"totals"
How to break the traffic down. One of:
totals, sessions, sources,
geolocation, pages, landing-pages, utm-campaigns.string
default:"total"
Aggregation period. One of:
total, daily, weekly, monthly,
summarize/daily, summarize/weekly, summarize/monthly.string
required
Start date in
YYYYMMDD format (inclusive).string
required
End date in
YYYYMMDD format (inclusive).integer
Max breakdown rows to return (up to 1000).
Write tools (9 guardrailed)
create_page_draft
Create a new site or landing page as an unpublished draft. State is forced toDRAFT
regardless of what you pass; nothing goes live on create. Publish later with
publish_page.
Does not require confirmation (reversible draft operation).
string
default:"site"
string
required
Internal page name.
string
Path to the template/theme file the page uses.
string
URL slug (path) for the page.
string
SEO
<title> for the page.string
SEO meta description.
update_page_draft
Edit a page’s draft buffer (name, slug, SEO title, SEO description) without touching the live page. Publish the change later withpublish_page.
Does not require confirmation (draft buffer only, live page untouched).
string
default:"site"
string
required
The page id.
string
string
string
string
publish_page
Push a page’s unpublished draft changes live to the public website. This is a push-live of the draft: it updates an already-published page, not a first-time publish of a brand-new page. Requiresconfirm: true. Without it, returns a WritePreview dry-run describing
exactly what would be published.
string
default:"site"
string
required
The page id.
boolean
Set
true to apply. Omit or false to receive a WritePreview.WritePreview if not confirmed.
create_blog_post_draft
Create a new blog post as an unpublished draft. State is forced toDRAFT. Requires
the target blog’s contentGroupId (read it from an existing post via list_blog_posts
or find it in the HubSpot UI). Publish later with publish_blog_post.
Does not require confirmation (reversible draft operation).
string
required
The blog (content group) id this post belongs to.
string
required
Post title / internal name.
string
URL slug for the post.
string
Post body HTML.
string
SEO
<title>.string
SEO meta description.
update_blog_post_draft
Edit a blog post’s draft buffer (title, slug, body, SEO) without touching the live post. Publish later withpublish_blog_post.
Does not require confirmation (draft buffer only, live post untouched).
string
required
The blog post id.
string
string
string
Post body HTML.
string
string
publish_blog_post
Push a blog post’s draft changes live to the public site. Requiresconfirm: true. Without it, returns a WritePreview dry-run.
string
required
The blog post id.
boolean
Set
true to apply. Omit or false to receive a WritePreview.WritePreview if not confirmed.
upsert_hubdb_row_draft
Create a new row (omitrowId) or update an existing one (pass rowId) in a
HubDB table’s draft. Changes are staged and invisible on live pages until
publish_hubdb_table is called.
Call get_hubdb_table first to inspect column types. Cell values must match each
column’s type (for example: FOREIGN_ID columns expect arrays, select columns expect
option objects, date columns expect epoch milliseconds).
Does not require confirmation (staged in draft, nothing live until publish).
string
required
string
Existing row id to update. Omit to create a new row.
object
required
Map of
columnName to cell value, typed per the column schema.publish_hubdb_table
Publish a HubDB table’s draft (schema and rows) so the changes appear on live pages. Any prior HubDB row write is invisible until this is called. Requiresconfirm: true. Without it, returns a WritePreview dry-run.
string
required
boolean
Set
true to apply. Omit or false to receive a WritePreview.WritePreview if not
confirmed.
reset_hubdb_draft
Discard all unpublished draft changes on a HubDB table, reverting the draft to the current live/published version. Destructive: all staged row and schema edits are lost. Requiresconfirm: true. Without it, returns a WritePreview dry-run.
string
required
boolean
Set
true to apply. Omit or false to receive a WritePreview.WritePreview if not
confirmed.
Code examples
Tool names are namespaced
hubspot__<tool> in Claude/ChatGPT (the AI invokes
these automatically). The bare names (e.g. list_pages) are used here for
readability.An expired or revoked access token returns
AccessTokenExpiredError. Because
HubSpot uses a refresh_token flow, silent renewal normally prevents this. If
it does surface, reconnect via the portal to issue a fresh token pair. See
Errors & limits.HubSpot’s public-app rate limit is 110 requests per 10 seconds per connected
account. On a
429, the client retries up to 3 times with backoff (honoring
Retry-After when present), so a chatty session self-heals. Per-request timeout
is 20s. get_traffic_analytics uses HubSpot’s legacy v2 analytics API with dates
in YYYYMMDD format. A 403 almost always means the connected portal’s plan or
granted scopes do not cover that surface. See
Errors & limits.This connector is multi-instance: a tenant can connect several HubSpot portals,
each as its own connector instance with a separately vaulted
refresh_token.