HubSpot CRM MCP Server
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@HubSpot CRM MCP ServerShow me all deals in the pipeline 'Sales'"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
HubSpot CRM MCP Server
HubSpot CRM MCP server for Claude Desktop and any MCP client, free-tier compatible. 15 tools over contacts, deals, and pipelines, authenticated with either a HubSpot private-app token or a full OAuth app. Writes are idempotent, so a retried tool call replays its first result instead of creating a duplicate record, and every tool call is written to a PII-redacted audit trail, including the calls denied for a missing scope and the calls that errored.
Related: QuickBooks Online MCP Server · MCP Audit Gateway · What production MCP actually requires
HubSpot runs a hosted MCP server of its own, with wider object coverage than this one. It is built for self-hosting: you run the process, the source is short enough to read in a sitting, and the audit trail, the cache, and the credentials never leave your infrastructure.
The rest is what a REST wrapper usually leaves out. It prompts for the exact missing scope
instead of leaking a raw 403, retries rate limits with backoff, serves record reads from a
local cache (TTL plus write-invalidation, with a signature-verified webhook handler you can wire
to your own HTTP ingress for out-of-band changes), walks cursor pagination, and returns per-item
results when a batch partially fails.
See docs/COMPARISON.md for side-by-side transcripts of a naive
API-wrapper MCP versus this one. Every transcript is generated by running both against the
mocked test suite.
Architecture
flowchart TD
Agent["MCP client / agent"] -->|"stdio (JSON-RPC)"| Server["FastMCP server<br/>server.py"]
Server --> Service["CrmService<br/>scope checks · audit · orchestration"]
Service --> Cache["LocalCache<br/>TTL + write invalidation"]
Service --> Idem["Idempotency store"]
Service --> Audit["Audit log<br/>PII redaction"]
Service --> Client["HubSpotClient<br/>retries · pagination · error mapping"]
Client --> Auth["Token provider<br/>private-app · OAuth refresh"]
Client -->|HTTPS| HubSpot["HubSpot CRM API"]
Ingress["Your HTTP ingress<br/>(optional, host-provided)"] -->|"signed v3 payload"| Processor["WebhookProcessor<br/>verify_signature"]
Processor -->|"invalidate(object)"| CacheThe stdio server speaks JSON-RPC only; it does not listen for webhooks. WebhookProcessor and
verify_signature are shipped as a tested component you mount on your own HTTP ingress (see
Webhook cache invalidation).
Related MCP server: hubspot-mcp
Tools
Every tool carries MCP annotations (readOnlyHint, destructiveHint, idempotentHint,
openWorldHint), a described input schema, and an output schema.
Tool | What it does | Scope |
| Search contacts by free-text term, one page at a time |
|
| List contacts in id order with cursor pagination |
|
| Fetch one contact by id, served from the local cache |
|
| Create a contact, idempotent on a supplied or derived key |
|
| Overwrite the properties passed and invalidate the cache entry |
|
| Archive (soft-delete) a contact |
|
| Create up to 100 contacts and report per-row failures |
|
| Search deals by free-text term with cursor pagination |
|
| Fetch one deal by id, served from the local cache |
|
| Create a deal, idempotent on a supplied or derived key |
|
| Update deal properties, including moving it to another stage |
|
| Archive (soft-delete) a deal |
|
| List deal pipelines with stages in display order (cached) |
|
| Fetch one pipeline with its ordered stages |
|
| Export the session audit trail as JSON Lines | none |
Quickstart
Run it without installing anything permanent:
uvx mcp-hubspotOr install it:
pip install mcp-hubspot
mcp-hubspotEither form speaks MCP over stdio on stdin and stdout. Authenticate with either a private-app
token (HUBSPOT_PRIVATE_APP_TOKEN) or an OAuth app (HUBSPOT_CLIENT_ID +
HUBSPOT_CLIENT_SECRET + HUBSPOT_REFRESH_TOKEN). The server auto-detects which is present.
Credentials are resolved lazily. The server starts and answers initialize and tools/list with
nothing configured, which is what lets a directory or a sandbox introspect it; the first tool call
is where a missing credential turns into an actionable error.
Wiring into an MCP client
Add to your MCP host config (for example Claude Desktop's claude_desktop_config.json):
{
"mcpServers": {
"hubspot": {
"command": "uvx",
"args": ["mcp-hubspot"],
"env": { "HUBSPOT_PRIVATE_APP_TOKEN": "pat-na1-..." }
}
}
}Docker
docker build -t mcp-hubspot .
docker run --rm -i -e HUBSPOT_PRIVATE_APP_TOKEN=pat-na1-... mcp-hubspotFrom source
Requires Python 3.12+ and uv.
uv venv
uv pip install -e ".[dev]"
cp .env.example .env # then fill in your HubSpot credentials
uv run mcp-hubspotOAuth authorization URL
For the OAuth flow, mcp_crm.auth.build_authorization_url(...) builds the consent URL with the
scopes the tools need; exchange the returned code for a refresh token and set
HUBSPOT_REFRESH_TOKEN.
Webhook cache invalidation
The stdio server does not receive webhooks. To invalidate the cache on changes made outside this
process (edits in the HubSpot UI, other integrations), mount WebhookProcessor on your own HTTP
endpoint and verify HubSpot's v3 signature with verify_signature (using the
HUBSPOT_WEBHOOK_SECRET you configure). Point it at the same LocalCache your CrmService uses:
from mcp_crm.webhooks import WebhookProcessor, verify_signature
processor = WebhookProcessor(cache)
def handle_hubspot_webhook(request):
ok = verify_signature(
secret=webhook_signing_secret,
method="POST",
uri=request.url,
body=request.raw_body,
signature=request.headers["X-HubSpot-Signature-v3"],
timestamp=request.headers["X-HubSpot-Request-Timestamp"],
)
if not ok:
return 401
processor.process(request.json())
return 200verify_signature rejects tampered bodies, wrong secrets, and stale timestamps;
WebhookProcessor.process maps each subscription to the object it invalidates and reports what it
touched.
Design decisions
Cache scope. Only object-detail reads (
crm_get_contact,crm_get_deal) and the pipeline list are cached; list/search results are query-dependent and left uncached to avoid serving stale result sets. Writes invalidate the relevant object immediately. For out-of-band changes, a signature-verifiedWebhookProcessorships as a component you mount on your own HTTP ingress (see Webhook cache invalidation); the stdio server itself does not listen for webhooks.Idempotency is client-side. HubSpot's create endpoints are not natively idempotent, so a key (supplied or derived from the payload) is stored and replayed. This makes at-least-once tool retries safe without duplicating records. The store lives in the process, so it covers retries within a session rather than across restarts, and
crm_batch_create_contactsdeliberately does not use it; both facts are stated in the tool descriptions.Scope prompting happens twice. The service pre-checks granted scopes (via token introspection) for a fast, actionable error, and the HTTP client also maps a server-side
MISSING_SCOPES403to the same typed error (belt and suspenders).Credentials load lazily. Nothing reads a token at import or at startup. A missing credential surfaces as a typed error on the first tool call, and that failure is audited like any other, so the server is still introspectable in a sandbox with an empty environment.
Backoff and clocks are injectable. Retry sleep, RNG jitter, and time sources are constructor parameters, which is why the whole suite runs offline in well under a second.
Testing
Every external HubSpot call is served by an in-memory fake (tests/fake_hubspot.py) backed by
JSON fixtures (tests/fixtures/), wired in through httpx.MockTransport. No network, no
credentials, deterministic.
uv run pytest -qRegenerate the comparison document (CI also checks it stays in sync):
uv run python scripts/generate_comparison.pyRegistry metadata
server.json describes this package for the Model Context Protocol registry
(io.github.amin-ale/hubspot-crm-mcp, PyPI mcp-hubspot, stdio transport). .mcp.json is the
minimal client config for tools that auto-detect MCP servers from a repository root.
Scope and safety
This is a client for HubSpot data you own or are authorized to access. Point it only at HubSpot accounts you control or have written permission to operate. The audit log redacts emails and phone numbers before writing records; treat exported audit logs as sensitive regardless. Behaviour documented here is point-in-time against the included fixtures, not a guarantee about any live HubSpot account.
Hire me
I build MCP servers and API integrations that survive a senior-dev code review: auth, retries, idempotency, and audit trails included, not bolted on later. Portfolio and contact: https://amin-ale.github.io/portfolio-site · amin.ale.business@gmail.com.
Available Tools
15 toolscrm_batch_create_contactsA
Create many HubSpot contacts in one request and report the outcome of every row.
Use this for bulk loads. Use crm_create_contact instead when a retry must not risk duplicates.
Writes, additively. Needs the crm.objects.contacts.write scope. Returns 'succeeded' with the created records and 'failed' with the input index, HubSpot status code, category, message, and original row for every rejection, so a partial failure never hides the rows that did save. This path does not go through the idempotency store: running the same batch twice can create duplicates, so re-send only the rows listed in 'failed'. Cached contact reads are invalidated.
| Name | Required | Description | Default |
|---|---|---|---|
| contacts | Yes | Contacts to create, up to 100 per call. Each item is a flat property map such as {'email': 'ada@example.com', 'firstname': 'Ada'}. Keys other than email, firstname, lastname, phone, and company are sent through as custom HubSpot properties. |
Output Schema
| Name | Required | Description |
|---|---|---|
| failed | No | Rows HubSpot rejected, with the reason for each. |
| succeeded | No | Records HubSpot created, each with 'id'. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
It discloses the required write scope, the response shape with 'succeeded' and 'failed' arrays, the non-idempotent behavior, and cache invalidation — all beyond the annotations. This gives the agent a full behavioral model.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is about five sentences, each with a distinct purpose: purpose, usage, behavior, idempotency caveat, cache effect. No fluff.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a batch mutation tool, it covers permissions, partial failure semantics, retry guidance, and response structure, so the agent can invoke it safely. The output schema is not shown but the description adequately describes the return value.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema already describes the contacts array with 100% coverage, and the description adds that failures include the input index and original row, making the parameter's ordering meaningful. It also refers to 'the same batch' which contextualizes the array as a unit.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with 'Create many HubSpot contacts in one request and report the outcome of every row,' which is a specific action and resource. It also contrasts with crm_create_contact by emphasizing 'many... in one request,' making the distinction clear.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly states 'Use this for bulk loads' and advises using crm_create_contact when a retry must not risk duplicates, giving clear when-to-use and when-not-to-use guidance. No other tool needs that exclusion.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
crm_create_contactAIdempotent
Create one HubSpot contact from the properties given and return the new record.
Use this for single creates, especially ones a retry might repeat. Use crm_batch_create_contacts to load many rows at once, and crm_update_contact to change a record that already exists.
Writes, additively. Needs the crm.objects.contacts.write scope. The call is keyed by 'idempotency_key', or by a hash of the properties when none is given, and a repeat of the same key replays the stored record instead of creating a second one. That key store lives in this process, so it covers retries within a session and not restarts. Cached contact reads are invalidated. At least one property must be supplied or the call fails validation.
| Name | Required | Description | Default |
|---|---|---|---|
| No | Primary email address. HubSpot deduplicates contacts on this value. | ||
| phone | No | Phone number in any format HubSpot accepts, e.g. '+1-202-555-0101'. | |
| company | No | Company name stored on the contact. This is a text property, not an association to a company record. | |
| lastname | No | Family name. HubSpot property 'lastname'. | |
| firstname | No | Given name. HubSpot property 'firstname'. | |
| idempotency_key | No | Caller-chosen key that makes a retry replay the first result instead of creating a second record. Omit to derive one from the properties. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | HubSpot record id, stable for the life of the record. |
| archived | No | True when the record is archived (soft-deleted). |
| properties | No | Property values HubSpot returned for the requested property set. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations (readOnlyHint=false, idempotentHint=true), the description discloses the required OAuth scope, the session-scoped idempotency store, cache invalidation on writes, and the validation requirement of at least one property. No contradiction with annotations; it meaningfully enriches them.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight paragraphs: purpose, usage guidance, and behavioral details. Every sentence carries information, with no filler or repetition of the schema. Front-loaded with the core purpose.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, the description appropriately avoids re-explaining return values. It covers authentication, idempotency semantics, cache effects, and validation constraints, making it sufficient for an agent to invoke correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3. The description adds valuable semantic context beyond the schema: the 'at least one property' validation rule and the idempotency key derivation/replay behavior. This justifies a 4.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'Create one HubSpot contact from the properties given and return the new record.' It explicitly contrasts with sibling tools like crm_batch_create_contacts and crm_update_contact, making the tool's unique role unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit when-to-use guidance: 'Use this for single creates, especially ones a retry might repeat.' It also names alternatives: crm_batch_create_contacts for bulk loading and crm_update_contact for existing records, giving clear decision criteria.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
crm_create_dealAIdempotent
Create one HubSpot deal from the properties given and return the new record.
Call crm_list_pipelines first when setting 'pipeline' or 'dealstage', because HubSpot only accepts a stage id that belongs to the chosen pipeline. Use crm_update_deal to move an existing deal.
Writes, additively. Needs the crm.objects.deals.write scope. The call is keyed by 'idempotency_key', or by a hash of the properties when none is given, and a repeat of the same key replays the stored record instead of creating a second one. That key store lives in this process, so it covers retries within a session and not restarts. Cached deal reads are invalidated. At least one property must be supplied.
| Name | Required | Description | Default |
|---|---|---|---|
| amount | No | Deal value as a decimal string in the account currency, e.g. '2500.00'. | |
| dealname | No | Deal title shown on the pipeline board. | |
| pipeline | No | Pipeline id from crm_list_pipelines. HubSpot uses the account's default pipeline when this is omitted. | |
| dealstage | No | Stage id taken from the chosen pipeline's 'stages'. HubSpot rejects a stage id that belongs to a different pipeline. | |
| close_date | No | Expected close date as an ISO 8601 date or timestamp, e.g. '2026-09-30'. Maps to HubSpot's 'closedate' property. | |
| idempotency_key | No | Caller-chosen key that makes a retry replay the first result instead of creating a second record. Omit to derive one from the properties. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | HubSpot record id, stable for the life of the record. |
| archived | No | True when the record is archived (soft-deleted). |
| properties | No | Property values HubSpot returned for the requested property set. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description discloses substantial behavioral traits beyond the annotations: it states the operation is 'Writes, additively,' explains the idempotency key mechanism, the in-process key store limitation ('covers retries within a session and not restarts'), cache invalidation, and the minimum property requirement. These details go well beyond the annotations' idempotentHint and destructiveHint flags.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is effectively structured into three paragraphs: purpose, prerequisite guidance, and behavioral details. Every sentence provides necessary information with zero fluff. It is appropriately sized for the complexity of the tool.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity—6 optional parameters, external dependency on crm_list_pipelines, OAuth scope requirements, idempotency semantics, and cache invalidation—the description covers all essential context. Return values are covered by the output schema, so no further explanation is needed.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema already provides strong descriptions for all 6 parameters (100% coverage), so the baseline is 3. The description adds critical cross-parameter semantics, noting that HubSpot 'only accepts a stage id that belongs to the chosen pipeline' and explaining idempotency_key behavior ('or by a hash of the properties when none is given'). This adds meaningful meaning beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's function: 'Create one HubSpot deal from the properties given and return the new record.' It uses a specific verb and resource, and distinguishes itself from the sibling crm_update_deal by explicitly saying 'Use crm_update_deal to move an existing deal.'
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit when-to-use guidance with a prerequisite call: 'Call crm_list_pipelines first when setting pipeline or dealstage,' and directs users to an alternative tool: 'Use crm_update_deal to move an existing deal.' Also states the required OAuth scope and the condition 'At least one property must be supplied.'
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
crm_delete_contactADestructiveIdempotent
Archive (soft-delete) a HubSpot contact so it drops out of active views.
Use this instead of asking a human to delete in the UI. This server never issues a hard delete; HubSpot keeps archived records restorable from its own UI for a limited window.
Writes, and destructive from an agent's point of view. Needs the crm.objects.contacts.write scope. Archiving the same id again leaves it archived. The record is dropped from the read cache and stops appearing in list and search results. Raises a not-found error for an id that never existed.
| Name | Required | Description | Default |
|---|---|---|---|
| contact_id | Yes | HubSpot contact record id, as returned by search, list, or create. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | Id of the record that was archived. |
| archived | Yes | Always true. The record was archived, not permanently deleted. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description goes far beyond the annotations (readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: true) by disclosing the soft-delete nature, required OAuth scope ('crm.objects.contacts.write'), idempotent behavior, cache invalidation, and not-found error handling. This gives the agent a full understanding of side effects and prerequisites.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with a clear one-sentence summary, followed by usage guidance, behavioral details, permissions, and error cases. Each sentence adds unique value; there is no fluff or repetition. Despite being a bit long, it's well-organized and efficient for a destructive tool.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's simplicity (one parameter), the description covers all critical aspects: purpose, when to use, safety, permissions, idempotency, cache effects, and error behavior. The output schema exists, so return details are not needed. This is thoroughly complete for an agent to safely invoke the tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema already fully describes contact_id as 'HubSpot contact record id, as returned by search, list, or create,' achieving 100% schema description coverage. The description adds no new parameter semantics beyond noting that an unknown id raises a not-found error, which is minor.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with 'Archive (soft-delete) a HubSpot contact so it drops out of active views,' which precisely states the action (archive/soft-delete), resource (HubSpot contact), and effect. It clearly distinguishes from sibling tools like crm_get_contact or crm_update_contact by focusing on deletion behavior.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly says 'Use this instead of asking a human to delete in the UI,' giving a clear when-to-use directive. It also notes the tool 'never issues a hard delete' and that records are restorable for a limited window, which helps the agent decide if this is appropriate for the task.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
crm_delete_dealADestructiveIdempotent
Archive (soft-delete) a HubSpot deal so it drops off the pipeline board.
Prefer moving a lost deal to a closed-lost stage with crm_update_deal, which keeps it in reporting. Archive only when the record should not have existed.
Writes, and destructive from an agent's point of view. Needs the crm.objects.deals.write scope. Archiving the same id again leaves it archived. The record is dropped from the read cache and stops appearing in searches. Raises a not-found error for an id that never existed.
| Name | Required | Description | Default |
|---|---|---|---|
| deal_id | Yes | HubSpot deal record id, as returned by search or create. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | Id of the record that was archived. |
| archived | Yes | Always true. The record was archived, not permanently deleted. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations, the description exposes key behaviors: soft-delete semantics, dropping from the read cache and search results, idempotency (archiving again leaves it archived), and not-found errors for never-existing IDs. It also reinforces the destructive nature from the agent's perspective while aligning with the destructiveHint and idempotentHint annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is structured with the core action first, then usage guidance, then behavioral details. Every sentence earns its place; the length is justified for a destructive operation with important caveats.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's destructive nature, annotations, and full schema coverage, the description covers all essential context: scope requirements, error behavior, idempotency, and cache/search effects. The presence of an output schema means returning the archive confirmation is already handled, so no return-value explanation is needed.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The single parameter is fully documented in the schema (100% coverage), so the description doesn't need to add parameter syntax. It does add useful context by explaining repeated calls with the same id are idempotent, but the schema already provides the essential meaning.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool archives (soft-deletes) a HubSpot deal so it disappears from the pipeline board. It distinguishes itself from the sibling crm_update_deal by explicitly contrasting archiving with moving to a closed-lost stage.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit guidance: prefer crm_update_deal for moving to closed-lost, and only archive when the record should not have existed. It also notes the required OAuth scope, providing clear when-to-use and when-not-to-use context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
crm_export_audit_logARead-onlyIdempotent
Export this session's audit trail as JSON Lines, one record per line.
Use this to hand a reviewer evidence of what the agent did, or to attach the trail to a ticket or change record.
Read-only and entirely local: it reads an in-memory buffer, makes no HubSpot call, and needs no scope. Every other tool call in the session is present, including calls denied for a missing scope and calls that raised an error, each with an id, timestamp, actor, tool name, outcome, the arguments, a short result summary, and the idempotency key where one applied. Email addresses and phone numbers are redacted before a record is stored. The buffer is not persisted, so it starts empty every time the server starts and an export after a restart covers only the new session.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description goes far beyond the annotations. It discloses that the tool is entirely local and reads an in-memory buffer, makes no HubSpot call, requires no scope, includes even denied/error calls, redacts email/phone, and explains the buffer is not persisted across restarts. These details fully characterize behavior, aligning with and expanding upon the read-only and idempotent hints.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured and efficient. The first sentence states the core function, the second provides use cases, and the remaining sentences deliver behavioral details without redundancy. Every sentence earns its place, making it concise despite being detailed.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Even with no parameters and an output schema present, the description covers all necessary context: purpose, use cases, input (none), output format and content, behavioral traits, redaction, and session-scope limitations. It is fully self-contained and leaves no significant gaps for the agent.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With zero parameters, the baseline is 4. The description doesn't need to explain parameter semantics; it adds value by describing the output format and content, which is appropriate for a no-input tool.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool exports the session's audit trail as JSON Lines with one record per line. The verb 'export' and resource 'audit trail' are specific, and the format 'JSON Lines' adds clarity. This is distinct from sibling CRM tools that focus on contacts, deals, and pipelines.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit when-to-use guidance: 'Use this to hand a reviewer evidence... or to attach the trail to a ticket or change record.' It does not mention exclusions or alternative tools, though no alternatives likely exist in the given sibling set, so the absence is not a significant gap.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
crm_get_contactARead-onlyIdempotent
Fetch one HubSpot contact by record id with its email, name, phone, and company.
Use this once an id is known. Use crm_search_contacts to find the id first.
Read-only. Needs the crm.objects.contacts.read scope. Served from an in-process cache with a 300 second default TTL; writes made through this server invalidate the entry immediately, and a cache hit is recorded in the audit log as a cache hit rather than a live read. Raises a not-found error for an unknown or archived id.
| Name | Required | Description | Default |
|---|---|---|---|
| contact_id | Yes | HubSpot contact record id, as returned by search, list, or create. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | HubSpot record id, stable for the life of the record. |
| archived | No | True when the record is archived (soft-deleted). |
| properties | No | Property values HubSpot returned for the requested property set. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations (readOnly, idempotent, not destructive), the description adds crucial operational context: required OAuth scope, in-process cache with 300s TTL, write-invalidation behavior, audit log implications, and the not-found error for unknown/archived ids. No contradiction with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the core action, then adds usage guidance and operational details. Every sentence contributes essential information—retrieval, prerequisite usage, permissions, caching, invalidation, and error behavior—with no redundancy or fluff.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the simple one-parameter schema, available output schema, and strong annotations, the description covers all necessary operational nuances: when to use, required scope, caching behavior, and error handling. The agent has complete guidance without needing to infer undefined behavior.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema already fully describes the single parameter (contact_id) with its type and source ('as returned by search, list, or create'). The description's phrase 'by record id' adds no additional meaning beyond the schema, so a baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool fetches one HubSpot contact by record id, specifying the returned fields (email, name, phone, company). It distinguishes itself from sibling tools like search, list, create, and delete by focusing on retrieval of a known id.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly instructs to use the tool only after an id is known and names the alternative (crm_search_contacts) to find the id first. This provides clear sequencing and differentiates from the search tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
crm_get_dealARead-onlyIdempotent
Fetch one HubSpot deal by record id with its name, amount, pipeline, and stage.
Use this once an id is known; use crm_search_deals to find the id first.
Read-only. Needs the crm.objects.deals.read scope. Served from an in-process cache with a 300 second default TTL, and writes made through this server invalidate the entry immediately. Raises a not-found error for an unknown or archived id.
| Name | Required | Description | Default |
|---|---|---|---|
| deal_id | Yes | HubSpot deal record id, as returned by search or create. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | HubSpot record id, stable for the life of the record. |
| archived | No | True when the record is archived (soft-deleted). |
| properties | No | Property values HubSpot returned for the requested property set. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations (readOnlyHint, idempotentHint, destructiveHint), the description adds important context: required OAuth scope, in-process caching with 300s TTL, cache invalidation on writes, and not-found behavior for unknown/archived ids. These details significantly exceed annotation coverage.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise and well-structured, using short paragraphs to separate purpose, usage guidance, and operational details. Every sentence adds value, with no redundancy or filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple one-parameter read tool with a rich output schema, the description covers all essential context: purpose, usage, auth requirements, caching behavior, and error conditions. Nothing important is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With only one parameter and 100% schema description coverage, the schema already fully documents deal_id. The description adds no further semantic detail beyond what is in the schema, so the baseline score of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('Fetch') and resource ('one HubSpot deal by record id'), and explicitly lists the fields returned (name, amount, pipeline, stage). It clearly distinguishes from crm_search_deals by stating this tool is used once an id is known.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly states when to use the tool ('once an id is known') and directs users to use crm_search_deals to find the id first, naming the alternative. This is clear and actionable guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
crm_get_pipelineARead-onlyIdempotent
Fetch one deal pipeline by id with its stages sorted by display order.
Use this when the pipeline id is already known and only its stages are needed. Use crm_list_pipelines to discover ids.
Read-only. Needs the crm.schemas.deals.read scope. Unlike the pipeline list, this call is not cached and always reaches HubSpot. Raises a not-found error for an unknown id.
| Name | Required | Description | Default |
|---|---|---|---|
| pipeline_id | Yes | Deal pipeline id, as returned by crm_list_pipelines. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | Pipeline id, the value to pass as a deal's 'pipeline'. |
| label | Yes | Pipeline name as shown in the HubSpot UI. |
| stages | No | Stages sorted by display order, first to last. |
| display_order | Yes | Position of the pipeline in the account. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint/idempotentHint, but the description adds valuable context beyond that: requires 'crm.schemas.deals.read' scope, is 'not cached and always reaches HubSpot' (unlike the pipeline list), and 'Raises a not-found error for an unknown id.' These are meaningful behavioral traits not present in annotations. No contradiction.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise and front-loaded with the core purpose. Each sentence adds value: purpose, usage guidance, discovery alternative, and behavioral caveats. No filler or redundancy. Despite several sentences, all are necessary for correct tool use.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple one-parameter tool with an output schema and strong annotations, the description covers purpose, when to use, auth scope, caching/network behavior, and error handling. It is fully complete for the task context; nothing critical is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema has 100% coverage for the single parameter with description 'Deal pipeline id, as returned by crm_list_pipelines.' The tool description repeats this context ('pipeline id is already known', 'by id') but adds little beyond the schema. With high schema coverage, baseline is 3; description offers no extra semantics.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description starts with 'Fetch one deal pipeline by id with its stages sorted by display order,' a specific verb+resource combination that clearly states the tool's function. It also distinguishes from sibling tool crm_list_pipelines by focusing on fetching a single pipeline by ID, not listing all pipelines.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit when-to-use guidance: 'Use this when the pipeline id is already known and only its stages are needed.' Also names the alternative: 'Use crm_list_pipelines to discover ids.' This directly addresses tool selection and differentiates from the list sibling.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
crm_list_contactsARead-onlyIdempotent
List HubSpot contacts in record-id order, one page at a time.
Use this to walk the whole contact set. Prefer crm_search_contacts when there is a term to match on, since listing everything is slower and burns rate limit.
Read-only. Needs the crm.objects.contacts.read scope; a missing scope is denied locally and recorded in the audit log. Not cached. Pass the returned 'after' cursor back for the next page and stop when it comes back null. Archived contacts are excluded.
| Name | Required | Description | Default |
|---|---|---|---|
| after | No | Cursor copied from the previous response's 'after' field. Omit for the first page. | |
| limit | No | How many records this page may contain, 1 to 100. HubSpot caps it at 100. |
Output Schema
| Name | Required | Description |
|---|---|---|
| after | No | Cursor for the next page, or null when this is the last page. |
| results | Yes | Records in this page, each with 'id' and 'properties'. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations (readOnlyHint, idempotentHint, openWorldHint, destructiveHint false), it adds meaningful behavioral context: required OAuth scope, local denial with audit logging, no caching, archived contacts excluded, and cursor-based pagination termination. This goes well beyond the structured metadata.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact and front-loaded, with each sentence earning its place. It mixes usage guidance, auth requirements, caching behavior, and pagination instructions without redundancy or filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Despite having an output schema (so return values are covered), the description covers all operational essentials: iteration pattern, auth, rate-limit trade-off, archived-contact filtering, and pagination. This is complete for a paged list tool of moderate complexity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description adds value by explaining how the 'after' cursor is used across pages and when to stop ('stop when it comes back null'), which complements the schema. It does not add much for 'limit', but the schema already documents its range and default.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'List HubSpot contacts in record-id order, one page at a time.' It clearly identifies the operation and distinguishes itself from crm_search_contacts by explicitly framing this as the paged walk-all tool.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description says exactly when to use it ('to walk the whole contact set') and when not to: 'Prefer crm_search_contacts when there is a term to match on, since listing everything is slower and burns rate limit.' It names the alternative and gives the reason.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
crm_list_pipelinesARead-onlyIdempotent
List every deal pipeline in the account with its stages in display order.
Call this before creating or moving a deal: it is the source of the 'pipeline' and 'dealstage' ids those tools need, and HubSpot rejects a stage id from the wrong pipeline.
Read-only. Needs the crm.schemas.deals.read scope. Served from an in-process cache with a 300 second default TTL, since pipeline definitions rarely change. Returns an empty list only if the account genuinely has no deal pipelines.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnlyHint annotation, the description adds valuable context: required OAuth scope, in-process cache with 300-second TTL, and empty-list semantics. It also explicitly says 'Read-only' reinforcing the safe nature of the call.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact yet information-dense. The first sentence states the purpose, the second gives usage guidance, and the third covers behavioral details. Each sentence earns its place with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple zero-parameter tool, the description fully covers what the tool returns, when to use it, auth requirements, caching behavior, and edge cases. The existence of an output schema covers return format details, so nothing critical is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes no parameters, so schema coverage is trivially 100%. The description adds no parameter details because none exist, but the baseline of 4 is appropriate for a zero-parameter tool.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'List every deal pipeline in the account with its stages in display order.' It clearly distinguishes from sibling tools like crm_get_pipeline by indicating it covers all pipelines and includes stage ordering.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly states when to use this tool ('Call this before creating or moving a deal') and explains the necessity for pipeline and dealstage ids. It doesn't explicitly mention alternatives (e.g., crm_get_pipeline for a single pipeline), but the use case is clearly defined, making it a strong 4.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
crm_search_contactsARead-onlyIdempotent
Search HubSpot contacts by free-text term and return one page of matches.
Use this to find contacts by name, email, company, or any other indexed property. Prefer crm_list_contacts when there is no term to match on, and crm_get_contact when the record id is already known.
Read-only. Needs the crm.objects.contacts.read scope; without it the call is denied before any CRM data request is made and the denial is written to the audit log. Search results are never cached, so every call reaches HubSpot. Pass the returned 'after' cursor back to walk further pages; a null 'after' means this was the last page. Archived contacts are excluded.
| Name | Required | Description | Default |
|---|---|---|---|
| after | No | Cursor copied from the previous response's 'after' field. Omit for the first page. | |
| limit | No | How many records this page may contain, 1 to 100. HubSpot caps it at 100. | |
| query | No | Free-text term matched against the record's indexed properties. Omit to match every record. |
Output Schema
| Name | Required | Description |
|---|---|---|
| after | No | Cursor for the next page, or null when this is the last page. |
| results | Yes | Records in this page, each with 'id' and 'properties'. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnly/idempotent annotations, the description discloses the required OAuth scope, denial/audit behavior, lack of caching, pagination cursor semantics, and archived contact exclusion. No contradictions with annotations; the description adds substantial behavioral context.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact and front-loaded: the first sentence states the core purpose, the second gives usage context, the third covers auth and caching, and the fourth explains pagination. Every sentence earns its place with no redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With rich schema annotations, output schema present, and the description covering auth, safety, pagination, and filtering behavior, the agent has everything needed to select and invoke the tool correctly. No critical gaps identified.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema already describes all three parameters fully (100% coverage), including defaults and meanings. The description reinforces free-text search and 'after' cursor usage but does not add new semantics beyond the schema, so a baseline of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a clear verb+resource+scope: 'Search HubSpot contacts by free-text term and return one page of matches.' It explicitly contrasts with sibling tools in the usage guidance, distinguishing it from crm_list_contacts (no term) and crm_get_contact (known ID).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit when-to-use guidance: 'Use this to find contacts by name, email, company, or any other indexed property.' It names alternatives: 'Prefer crm_list_contacts when there is no term to match on, and crm_get_contact when the record id is already known.' Also includes operational guidance on pagination and caching.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
crm_search_dealsARead-onlyIdempotent
Search HubSpot deals by free-text term and return one page of matches.
Use this to find deals by name, amount, or stage text. Use crm_get_deal when the record id is already known, and crm_list_pipelines to translate the returned pipeline and stage ids into readable labels.
Read-only. Needs the crm.objects.deals.read scope; a missing scope is denied locally and recorded in the audit log. Not cached. Pass the returned 'after' cursor back for the next page and stop when it is null. Archived deals are excluded.
| Name | Required | Description | Default |
|---|---|---|---|
| after | No | Cursor copied from the previous response's 'after' field. Omit for the first page. | |
| limit | No | How many records this page may contain, 1 to 100. HubSpot caps it at 100. | |
| query | No | Free-text term matched against the record's indexed properties. Omit to match every record. |
Output Schema
| Name | Required | Description |
|---|---|---|
| after | No | Cursor for the next page, or null when this is the last page. |
| results | Yes | Records in this page, each with 'id' and 'properties'. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description adds significant behavioral context beyond the annotations: required OAuth scope ('crm.objects.deals.read'), failure behavior ('denied locally and recorded in the audit log'), caching behavior ('Not cached'), pagination mechanism ('Pass the returned after cursor back for the next page and stop when it is null'), and filtering ('Archived deals are excluded'). No contradiction with the readOnlyHint annotation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is four sentences, each serving a clear purpose: main capability, usage guidance, permission/pagination/filtering details. There is no fluff; it is front-loaded with the core purpose and tightly packed with actionable information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's moderate complexity, the description covers all necessary context: it explains pagination, permission requirements, exclusions, and the distinction from sibling tools. An output schema exists, so not detailing return values is acceptable. This is a complete description for an AI agent to select and invoke the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description goes beyond the schema by explaining what 'query' matches ('name, amount, or stage text') and how to use the 'after' cursor for pagination. This extra context justifies a 4, though the schema already documents the parameters well.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The first sentence states a specific action: 'Search HubSpot deals by free-text term and return one page of matches,' clearly distinguishing this from siblings by specifying the resource (deals) and method (free-text search). It also explicitly contrasts with crm_get_deal and crm_list_pipelines, making the tool's unique role unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit guidance: 'Use this to find deals by name, amount, or stage text' and then names alternatives: 'Use crm_get_deal when the record id is already known, and crm_list_pipelines to translate the returned pipeline and stage ids into readable labels.' This clearly answers when to use this tool versus others.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
crm_update_contactADestructiveIdempotent
Update properties on an existing HubSpot contact and return the updated record.
Use this to change a known record. Use crm_create_contact for records that do not exist yet.
Writes. Only the properties passed are sent, and each one overwrites the value HubSpot held before, so the previous value is lost; properties left out are untouched. Applying the same values again produces the same record, which makes a retry safe. Needs the crm.objects.contacts.write scope. Invalidates this contact's cache entry. Raises a not-found error for an unknown or archived id, and a validation error when no property is supplied.
| Name | Required | Description | Default |
|---|---|---|---|
| No | Primary email address. HubSpot deduplicates contacts on this value. | ||
| phone | No | Phone number in any format HubSpot accepts, e.g. '+1-202-555-0101'. | |
| company | No | Company name stored on the contact. This is a text property, not an association to a company record. | |
| lastname | No | Family name. HubSpot property 'lastname'. | |
| firstname | No | Given name. HubSpot property 'firstname'. | |
| contact_id | Yes | HubSpot contact record id, as returned by search, list, or create. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | HubSpot record id, stable for the life of the record. |
| archived | No | True when the record is archived (soft-deleted). |
| properties | No | Property values HubSpot returned for the requested property set. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds significant detail beyond annotations: states it's a write operation, only passed properties are sent, previous values are lost, omitted properties are untouched, retries are safe, requires the write scope, invalidates cache, and raises specific errors. Consistent with annotations; no contradiction.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact yet comprehensive, covering purpose, usage, behavior, scope, cache, and errors in a logical order without redundancy. Every sentence adds value.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a mutation tool with 6 parameters and an output schema, the description is complete. It addresses when to use, how it behaves, required permissions, error cases, and side effects. The output schema covers return details, so no need to elaborate on that.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so descriptions already exist per parameter. The tool description adds general semantics about partial updates and overwrite behavior, which enriches understanding of how all parameters behave.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states 'Update properties on an existing HubSpot contact and return the updated record,' with a specific verb and resource. It also distinguishes from the sibling create tool, saying 'Use crm_create_contact for records that do not exist yet.'
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly says 'Use this to change a known record' and directs to crm_create_contact for new records. Error cases (unknown/archived id, no property supplied) provide additional context on when the tool is appropriate.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
crm_update_dealADestructiveIdempotent
Update properties on an existing HubSpot deal, including moving it to a new stage.
Use this to advance a deal through its pipeline. The deal's pipeline itself is not changeable here; create the deal in the right pipeline instead.
Writes. Only the properties passed are sent, and each one overwrites the value HubSpot held before; properties left out are untouched. Applying the same values again produces the same record, which makes a retry safe. Needs the crm.objects.deals.write scope. Invalidates this deal's cache entry. Raises a not-found error for an unknown or archived id, and a validation error when no property is supplied.
| Name | Required | Description | Default |
|---|---|---|---|
| amount | No | Deal value as a decimal string in the account currency, e.g. '2500.00'. | |
| deal_id | Yes | HubSpot deal record id, as returned by search or create. | |
| dealname | No | Deal title shown on the pipeline board. | |
| dealstage | No | Stage id taken from the chosen pipeline's 'stages'. HubSpot rejects a stage id that belongs to a different pipeline. | |
| close_date | No | Expected close date as an ISO 8601 date or timestamp, e.g. '2026-09-30'. Maps to HubSpot's 'closedate' property. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | HubSpot record id, stable for the life of the record. |
| archived | No | True when the record is archived (soft-deleted). |
| properties | No | Property values HubSpot returned for the requested property set. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond annotations (readOnlyHint=false, destructiveHint=true, idempotentHint=true), the description adds rich behavior: 'Writes' status, partial overwrite semantics, retry safety, required OAuth scope 'crm.objects.deals.write', cache invalidation, and specific error conditions (not-found for unknown/archived id, validation for no property). This fully complements and expands on structured hints without contradicting them.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is appropriately dense, starting with a clear one-sentence purpose, followed by usage guidance, then a concise paragraph on behavior. Every sentence adds distinct value—no repetition of schema or annotation data, no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, return values need not be described. The description covers auth requirements, cache effects, error scenarios, idempotency, and partial-update behavior, making it fully sufficient for an agent to invoke the tool correctly. The tool's complexity is moderate, and all relevant context is provided.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema covers 100% of parameters, so the baseline is 3. The description adds meaningful context beyond schemas: dealstage must come from the chosen pipeline and HubSpot rejects mismatched stages, and close_date maps to HubSpot's 'closedate' property. This extra information elevates the score.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states 'Update properties on an existing HubSpot deal' with a specific verb and resource, and explicitly distinguishes from other operations by noting the pipeline cannot be changed here and to 'create the deal in the right pipeline instead'. This separates it from create, delete, get, and search siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit guidance: 'Use this to advance a deal through its pipeline' and warns that changing the pipeline itself requires creating a new deal. Also explains partial-update semantics (only passed properties are sent, omitted ones untouched), which helps the agent decide when to use this tool. Does not explicitly list all alternatives but covers the main use case.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.
15 tool updates
v0.1.0- First observed
crm_batch_create_contacts - First observed
crm_create_contact - First observed
crm_create_deal - First observed
crm_delete_contact - First observed
crm_delete_deal - First observed
crm_export_audit_log - First observed
crm_get_contact - First observed
crm_get_deal - First observed
crm_get_pipeline - First observed
crm_list_contacts - First observed
crm_list_pipelines - First observed
crm_search_contacts - First observed
crm_search_deals - First observed
crm_update_contact - First observed
crm_update_deal
TDQS
Each tool targets a distinct resource and action: contacts, deals, pipelines, or audit log. Overlapping search/get/list tools are clearly separated with explicit guidance on when to prefer each.
All tools follow a consistent crm_verb_noun pattern with snake_case throughout. The compound verb 'batch_create' fits the convention as cleanly as simple verbs like 'search' or 'list'.
15 tools is right at the upper bound of the ideal 3-15 range. The count matches the server's stated CRM scope: two primary objects (contacts, deals) plus supporting pipelines and audit coverage.
Contacts have full search/list/get/create/update/delete/batch-create coverage. Deals lack a list-all-deals counterpart to crm_list_contacts, though search can approximate it. Pipeline and audit support are adequate. Minor gap only.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
The HubSpot MCP Server acts as a bridge that enables AI assistants and Large Language Models to securely interact with HubSpot CRM data through natural conversation, without requiring users to understand complex API structures. It provides read-only access to standard CRM objects (contacts, companies, deals, tickets, products, invoices, and more) and their associations, secured via OAuth 2.0, allowing AI agents to perform tasks like summarizing deals, fetching company updates, and looking up record changes.
MCP server for the HubSpot Integrations Center HubDB: search and retrieve integration data.
API-first CRM for LLMs - contacts, companies, deals and activities over a native MCP server.
CRM + visual automation builder AI agents can drive via MCP: contacts, tags, maps, email/SMS flows.
Related MCP Servers
- AlicenseBqualityFmaintenanceEnables AI models to interact with HubSpot CRM data and operations through a standardized interface, supporting contact and company management.16128MIT
- AlicenseAqualityCmaintenanceA read-only MCP server that exposes HubSpot CRM data (contacts, deals, companies, quotes) to AI agents, enabling natural language queries.9MIT
- AlicenseAqualityBmaintenanceEnables interaction with HubSpot CRM through MCP, providing tools to manage contacts, companies, deals, and search/associations via natural language.18527MIT
- AlicenseNot gradedqualityDmaintenanceA Model Context Protocol (MCP) server that provides AI assistants with full access to HubSpot CRM. Manage contacts, companies, deals, pipelines, and associations directly from Claude, Cursor, or any MCP-compatible client.15MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/amin-ale/hubspot-mcp-server'
If you have feedback or need assistance with the MCP directory API, please join our Discord server