Demo CRM MCP Server
Click on "Deploy 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., "@Demo CRM MCP ServerShow me the pipeline summary by stage"
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.
Demo CRM MCP Server
A demo MCP server exposing a small CRM
(companies, contacts, deals, activities) as tools. Data is stored in
SQLite via Node's built-in node:sqlite, pre-seeded with sample records.
Reads return real data and writes persist across restarts.
Tools
Companies
list_companies— filter by name search / industryget_company— company + its contacts + its dealscreate_companyupdate_company
Contacts
list_contacts— filter by company / name+email searchget_contact— contact + company + deals + activity historycreate_contactupdate_contact
Deals
list_deals— filter by company / stageget_deal— deal + company + contact + activity historycreate_dealupdate_deal_stage— moves a deal throughlead → qualified → proposal → negotiation → won/lost
Activities
log_activity— attach a note/call/email/meeting to a company, contact, or deal
Search & reporting
search_crm— search across companies/contacts/dealsget_pipeline_summary— deal count + total value per stage, plus open/won totals
Related MCP server: Company Records
Requirements
Node.js 24+ (uses
node:sqlite)
Setup
npm install
npm run build
npm start # starts the MCP server on stdionpm run dev runs src/index.ts directly via tsx, for local iteration
without rebuilding.
Data lives in data/crm.db, created and seeded on first run. npm run reset-db wipes it back to the seed data.
Data directory
The default data directory is data/ next to the project. Override it
with DATA_DIR:
DATA_DIR=/tmp/demo-crm-data npm startThis matters on platforms that restrict which paths a process can write
to — a sandboxed agent gateway, for example, that only allows writes
under /tmp or /.cache. If DATA_DIR isn't set and the default data/
directory isn't writable, the server falls back to a directory under the
OS temp dir on its own rather than crashing on startup. Setting DATA_DIR
explicitly is still the more predictable option when you can.
Note that /tmp and similar sandboxed paths are usually wiped when the
container or pod is recreated, so data won't survive the way it does with
a real volume in Docker/Kubernetes.
Running as a remote server (for an MCP gateway)
The stdio entrypoint (npm start) is for clients that spawn the server as
a subprocess. To expose it over the network for a gateway to connect to,
run the Streamable HTTP entrypoint instead:
npm run build
MCP_API_KEY=some-long-random-secret PORT=3000 npm run start:httpThis starts an Express server implementing the MCP Streamable HTTP
transport at
POST/GET/DELETE http://localhost:3000/mcp, plus a GET /healthz check.
It's session-based, per the spec. The first initialize call returns an
Mcp-Session-Id header, and subsequent requests from that client include
it. Each session gets its own McpServer/transport pair, but all sessions
share the same SQLite file, so writes from one client show up in reads
from another.
If MCP_API_KEY is set, /mcp requests need Authorization: Bearer <key> or they get a 401. If it's unset, the server logs a warning and
runs unauthenticated — fine for localhost testing, not for anything
network-reachable.
Point a gateway at http://<host>:<port>/mcp, plus the bearer token if
one is set. If the gateway runs elsewhere and needs to reach this server,
deploy it somewhere reachable (see the Docker section) or tunnel it for
quick local testing with ngrok http 3000.
Querying it with curl
Streamable HTTP is session-based, so it takes three requests: initialize,
then the notifications/initialized notification, then whatever you
actually want, reusing the Mcp-Session-Id header from the first
response.
HOST=http://localhost:3000 # or your https:// domain
KEY=your-mcp-api-key # omit the Authorization header entirely if MCP_API_KEY is unset
SID=$(curl -s -i -X POST "$HOST/mcp" \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"curl","version":"1.0"}}}' \
| grep -i "^mcp-session-id" | tr -d '\r' | cut -d' ' -f2)
curl -s -X POST "$HOST/mcp" \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" -H "mcp-session-id: $SID" \
-d '{"jsonrpc":"2.0","method":"notifications/initialized"}' -o /dev/null
# list the tools
curl -s -X POST "$HOST/mcp" \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" -H "mcp-session-id: $SID" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}'
# call one
curl -s -X POST "$HOST/mcp" \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" -H "mcp-session-id: $SID" \
-d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"get_pipeline_summary","arguments":{}}}'Skipping straight from initialize to tools/list gets rejected — the
notifications/initialized step is required. Responses come back as
text/event-stream (event: message / data: {...}) rather than plain
JSON; the payload is the data: line.
Docker
docker build -t demo-crm-mcp-server .
docker run -d \
--name demo-crm \
-p 3000:3000 \
-e MCP_API_KEY=some-long-random-secret \
-v crm-data:/app/data \
demo-crm-mcp-serverOr with Compose, which reads MCP_API_KEY from the shell env or a .env
file:
MCP_API_KEY=some-long-random-secret docker compose up -d --buildCompose also brings up the caddy service described below, so it needs
DOMAIN set too. For a plain HTTP container with no TLS in front of it,
use docker run instead.
The image is a multi-stage build: TypeScript compiles in a builder stage,
and the runtime stage ships only production node_modules and dist.
There are no native modules to compile, so it's a plain node:24-alpine
with no build toolchain needed. It runs as a non-root user, exposes
3000, and has a HEALTHCHECK against /healthz. /app/data is a
volume — mount it, as above, or data resets every time the container is
recreated. MCP_API_KEY isn't baked into the image; pass it at run or
deploy time. The image runs the HTTP entrypoint (dist/http.js), not the
stdio one.
To deploy to a specific platform (Fly.io, Render, a plain VPS, ECS, etc.),
push the built image to that platform's registry/deploy flow and set
MCP_API_KEY (and PORT if required) as environment variables there.
Exposing it over HTTPS
docker-compose.yml includes a caddy service that terminates TLS in
front of the app and gets a certificate from Let's Encrypt automatically.
The app container no longer publishes port 3000 directly — Caddy is the
only thing on the public ports (80/443), and proxies to the app over the
internal Docker network.
You'll need a domain name with a DNS A/AAAA record pointing at the
server, and ports 80 and 443 open — 80 for the ACME HTTP-01 challenge,
443 for HTTPS itself. Then:
DOMAIN=mcp.example.com MCP_API_KEY=some-long-random-secret docker compose up -d --buildCaddy requests and renews the certificate for DOMAIN automatically and
stores it in the caddy-data volume, so it survives restarts. Point the
gateway at https://mcp.example.com/mcp.
The Caddyfile sets flush_interval -1 on the reverse proxy, disabling
response buffering — the Streamable HTTP transport's text/event-stream
responses need to reach the client as they're written, not batched up.
Alternatives to running Caddy yourself: nginx + certbot works the same
way in principle but needs more manual config, including proxy_buffering off; for the same streaming reason. Cloudflare Tunnel gets you HTTPS
without opening any inbound ports at all, useful behind NAT. And if
you're deploying to a platform like Fly.io, Render, or Cloud Run instead
of a bare server, it likely terminates HTTPS for you already — skip Caddy
and deploy the app image directly.
CI: building the image automatically
.github/workflows/docker-publish.yml builds the image and pushes it to
the GitHub Container Registry on pushes to main (tagged latest and
the commit SHA), on tags matching v*.*.* (tagged with that semver plus
major.minor), on PRs targeting main (build-only, to catch a broken
Dockerfile before merge), and manually via workflow_dispatch.
It builds for both linux/amd64 and linux/arm64, uses the GitHub
Actions cache, and authenticates to ghcr.io with the repo's built-in
GITHUB_TOKEN — no registry secrets to set up.
After the first successful run on main, the image is published at:
ghcr.io/lauramariel/demo-mcp-server:latestNew packages default to private. Change that from the repo's Packages
sidebar, or grant your deploy server access with docker login ghcr.io
using a PAT that has read:packages. If the workflow fails to push with
a permissions error, check that Settings → Actions → General → Workflow
permissions is set to "Read and write permissions".
To run the CI-built image instead of building from source on your server,
swap docker compose up -d --build for:
docker pull ghcr.io/lauramariel/demo-mcp-server:latest
docker run -d --name demo-crm -p 3000:3000 \
-e MCP_API_KEY=some-long-random-secret \
-v crm-data:/app/data \
ghcr.io/lauramariel/demo-mcp-server:latestOr add image: ghcr.io/lauramariel/demo-mcp-server:latest next to
build: . in docker-compose.yml and use docker compose pull instead
of --build.
Using it from Claude Code / Claude Desktop
Add it as a local MCP server, e.g. in Claude Code:
claude mcp add demo-crm -- node /Users/laura/dev/demo-mcp-server/dist/index.jsOr in Claude Desktop's claude_desktop_config.json:
{
"mcpServers": {
"demo-crm": {
"command": "node",
"args": ["/Users/laura/dev/demo-mcp-server/dist/index.js"]
}
}
}Sample queries
Reads (work against the seed data right away):
"What's in the pipeline right now?"
"Which companies are in the Software industry?"
"List every company in the CRM"
"Who are the contacts at Acme Robotics?"
"Find any contact with 'chen' in their email"
"What's Mei Lin Chen's title and which company is she at?"
"What's the status of the Robotics fleet monitoring rollout deal?"
"Show me every deal that's still in the 'lead' stage"
"What deals does BluePeak Analytics have open?"
"What's the largest deal currently in negotiation?"
"Which deals have we lost, and for how much?"
"What's the activity history on the Patient records integration deal?"
"Search the CRM for anything related to Chen"
"Search for 'consulting' across companies, contacts, and deals"
"What's our total open pipeline value vs. what we've already won?"
"Give me a breakdown of deal count and value by stage"
Writes:
"Create a new company called Initech, industry Manufacturing"
"Add a contact, Sarah Connor, at Cascade Health Group, title CTO"
"Create a deal for Northwind Traders called 'Loyalty program integration', stage qualified"
"Move Northwind Traders' POS system upgrade deal to negotiation"
"Log a call with Priya Nair about the pilot rollout timeline"
"Update Tom Fenwick's email to tom@fenwickito.example"
Project layout
src/db.ts— schema + seed datasrc/crm.ts— data access functions (plain functions over SQL, no MCP-specific code)src/server.ts— MCP tool registration (zod input schemas, wires tools tocrm.ts)src/index.ts— stdio entrypointsrc/http.ts— Streamable HTTP entrypoint (for remote/gateway use)
Available Tools
15 toolscreate_companyCreate companyC
Create a new company record in the CRM.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | ||
| website | No | ||
| industry | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full behavioral burden. It implies a mutation but says nothing about permissions, whether duplicate company names are rejected, what the response contains, or whether the call is idempotent — a meaningful gap for a create tool.
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?
A single front-loaded sentence with no filler or redundancy. Its brevity is efficient, though it borders on under-specification rather than true conciseness.
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 no annotations, no output schema, and 0% parameter coverage, the definition leaves out required-field expectations, validation behavior, and result semantics. It is not complete enough for an agent to call it confidently in edge cases.
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 0% across 3 parameters, and the description adds no field-level meaning beyond the bare schema types. It does not indicate that 'name' is required or explain the intended format of website/industry, so it fails to compensate for the coverage gap.
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?
States a specific verb ('Create') and resource ('company record in the CRM'), which cleanly separates it from siblings like create_contact and create_deal by resource noun. It does not, however, explicitly differentiate itself from update_company or mention interaction with list_companies, so it sits at clear-but-not-differentiating.
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?
No guidance on when to create versus update an existing company, no deduplication advice, no prerequisites or alternatives named. The agent must infer usage entirely from the tool name.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_contactCreate contactC
Create a new contact, optionally attached to a company.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | ||
| No | |||
| phone | No | ||
| title | No | ||
| companyId | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations exist, so the description carries the full behavioral burden. It reveals only that company linkage is optional; nothing about required permissions, duplicate handling, side effects, or what is returned after creation, which matters for a mutation tool with five parameters.
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?
A single efficient, front-loaded sentence with no filler. It is appropriately terse, though the brevity is also the source of its coverage gaps rather than a stylistic strength.
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 no annotations, no output schema, and 0% schema description coverage across five parameters, the description is far too thin. An agent cannot determine required fields, validation expectations, or post-creation behavior from it.
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 0%, so the description must explain the five parameters. It only implies the optionality of company attachment; email, phone, title, and the name requirement are left entirely unexplained beyond their names in 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?
States a specific verb ('Create') and resource ('contact'), plus a scope hint that the contact may be attached to a company. This distinguishes it from create_company and create_deal purely by resource, though it never names or contrasts a sibling explicitly.
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?
There is no when-to-use guidance, no prerequisites, and no mention of alternatives such as update_contact or search_crm to avoid duplicates. The only usage signal is that the company attachment is optional, which is incidental.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_dealCreate dealC
Create a new deal for a company, optionally linked to a contact.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | ||
| stage | No | Defaults to 'lead' | |
| companyId | Yes | ||
| contactId | No | ||
| amountCents | No | Deal value in cents |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full behavioral burden. It implies a write but says nothing about required permissions, what happens if companyId is invalid or a duplicate deal exists, whether contactId is validated against the company, or what the response contains.
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?
A single front-loaded sentence with no filler; the core action comes first and the optional linkage is appended as a qualifier. Nothing is redundant.
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 five-parameter mutation tool with no annotations, no output schema, and 40% schema coverage, the description is too thin: it omits required-field expectations, the stage default, the amountCents unit, and any notion of the returned deal.
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 only 40%, and the description compensates partially: it identifies companyId and the optional nature of contactId, and implies name. It says nothing about stage or amountCents, leaving two of five parameters undocumented in text.
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?
States a specific verb and resource ("Create a new deal") and adds the scoping detail that a deal belongs to a company and may optionally link a contact. It is clearly distinguishable from read siblings like get_deal/list_deals, though it never contrasts itself with the other deal mutator, update_deal_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?
The description implies you call it when you want a new deal, but gives no when-to-use/when-not guidance, no prerequisites (e.g., that the company must already exist), and never names an alternative such as update_deal_stage for existing deals.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_companyGet companyC
Get a company's details along with its contacts and deals.
| Name | Required | Description | Default |
|---|---|---|---|
| companyId | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries full burden. It only reveals that the response includes contacts and deals, but says nothing about permissions, data completeness, error behavior, or volume limits for a tool that implicitly expands into related entities.
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?
A single tight sentence with no filler, front-loading the core action. It is appropriately sized, though it could afford a bit more substance given the undocumented parameter.
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 retrieval tool with zero annotation coverage, an undocumented required ID, no output schema, and a nested return structure (contacts + deals), the description is too thin. It should explain the identifier, related-entity expansion, and any limits.
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 0% and there is no output schema, yet the description says nothing about the required companyId parameter — not its type, format, uniqueness, or where to obtain it. With one undocumented required param, the description must compensate and does not.
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?
States a specific verb (Get) and resource (company), and describes what the response contains (details, contacts, deals). Sibling get_contact and get_deal follow the same get_* pattern, but the description doesn't explicitly differentiate why this returns nested contacts/deals versus fetching them separately.
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?
No guidance on when to use this versus list_companies, get_contact, or get_deal. It implies a bulk retrieval but doesn't tell the agent to prefer it over multiple single-entity calls, nor when to avoid it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_contactGet contactC
Get a contact's details along with their company, deals, and activity history.
| Name | Required | Description | Default |
|---|---|---|---|
| contactId | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden yet only discloses the returned related entities. It says nothing about required permissions, error behavior for a missing contact, or side effects, leaving key traits undocumented.
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?
One front-loaded sentence with no filler; the payload preview is placed immediately after the core verb. It is efficient, though extremely short relative to what it omits.
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 single-param read tool with no output schema, the description adequately conveys what comes back, but the absence of annotations and any input/error context leaves real gaps for an agent to call it correctly. The return-value hint partially compensates.
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 0% and the description never mentions contactId, so neither source explains what the identifier is (CRM internal ID vs external key) or its expected form. A single-parameter tool should at least name and qualify its input.
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?
States a specific verb+resource ('Get a contact's details') and adds the useful scope of what is returned (company, deals, activity history). However, it does not distinguish itself from siblings like list_contacts or search_crm beyond the obvious singular-resource reading.
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?
There is no explicit when-to-use guidance and no mention of alternatives such as list_contacts (for enumeration) or search_crm (for lookup by other fields). The agent must infer that this is the single-record-by-id fetch.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_dealGet dealB
Get a deal's details along with its company, contact, and activity history.
| Name | Required | Description | Default |
|---|---|---|---|
| dealId | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden, and 'Get' implies a safe read. It adds genuine behavioral value by disclosing that the response aggregates company, contact, and activity history in one call, but it says nothing about permissions, error/not-found behavior, or freshness of the attached history.
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?
One tight sentence that front-loads the operation and appends the useful return payload. No filler or 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?
For a trivial one-parameter getter with no output schema, the description adequately conveys what comes back, but with no annotations and no parameter documentation it leaves the meaning of dealId and failure behavior unstated.
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 dealId parameter has 0% schema description coverage, so the description must compensate and does not: it never explains that dealId identifies which deal, its expected type, or where an agent would obtain it. 'a deal's details' is the only hint.
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?
States a specific verb and resource ('Get a deal's details') and even discloses the related entities returned (company, contact, activity history). This distinguishes it from list_deals at a glance, though it doesn't name the sibling getters (get_company, get_contact) it parallels.
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?
No guidance on when to use this versus list_deals, search_crm, or get_pipeline_summary, and no stated preconditions for retrieving a deal. Usage is only implied by the getter naming convention.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_pipeline_summaryGet pipeline summaryA
Get aggregate pipeline stats: deal count and total value per stage, plus open/won totals.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It discloses the shape of the returned aggregates, which is genuinely useful, but says nothing about read-only nature, permissions, scope (whole org vs. per-user), or time-window behavior.
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?
One tightly-packed sentence with zero filler, front-loading the aggregate nature and then the specific metrics. Nothing to trim.
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?
There is no output schema, so the description must carry the return-value burden, and it does list the aggregate fields. It falls just short of complete by not stating who/what the aggregate is scoped over, but for a parameterless summary tool this is nearly sufficient.
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 zero parameters, so the baseline is 4. There is nothing for the description to clarify beyond confirming it is a no-argument rollup.
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?
States a specific verb+resource ('Get aggregate pipeline stats') and enumerates the returned aggregates (deal count, total value per stage, open/won totals). The aggregate scope implicitly distinguishes it from list_deals, though it does not name that sibling explicitly.
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?
Usage is implied: an agent infers this is the reporting/rollup tool rather than the per-deal listing tool. However, there is no explicit when-to-use, when-not-to-use, or named alternative, so guidance remains inferential.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_companiesList companiesB
List CRM companies, optionally filtered by name search or industry.
| Name | Required | Description | Default |
|---|---|---|---|
| search | No | Case-insensitive substring match on company name | |
| industry | No | Exact industry match, e.g. 'Software' |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full behavioral burden. It does not state pagination behavior, result limits, ordering, or read-only status. For a listing tool this is a meaningful gap, leaving the agent to guess at result-set characteristics.
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?
A single front-loaded sentence with no wasted words; purpose and filtering scope are stated immediately.
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 no annotations and no output schema, the description should compensate for behavioral and result-shape gaps, but it does not. It omits read-safety, pagination, and how results relate to sibling listing tools, leaving the definition under-specified for a no-annotation 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?
Schema description coverage is 100%, so both parameters are already well documented in the schema (case-insensitive substring vs exact match). The description adds only the high-level notion of filtering and nothing beyond what the schema provides. 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?
States a specific verb (List) and resource (CRM companies), and distinguishes itself from get_company (singular single-entity) and create_company/update_company. The optional filtering scope is included. It does not, however, distinguish itself from list_contacts/list_deals or search_crm beyond the resource name.
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?
Usage is implied by the name and the 'optionally filtered' phrasing, but there is no explicit when-to-use guidance or routing to an alternative. An agent could plausibly confuse this with search_crm, and the description offers no condition to choose between them.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_contactsList contactsC
List CRM contacts, optionally filtered by company or a name/email search.
| Name | Required | Description | Default |
|---|---|---|---|
| search | No | ||
| companyId | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It doesn't mention pagination, result limits, default ordering, or what 'optionally filtered' means when both filters are omitted. For a list tool with zero annotation coverage this is a significant gap.
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?
One efficient sentence with zero waste, front-loaded with the core verb and resource. Appropriately sized for a simple two-param list 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?
No annotations, no output schema, and 0% schema coverage leave the description responsible for return format, pagination, and param meaning — none of which it supplies. Inadequate for the tool's actual needs.
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 0%, so the description must compensate. It only gestures at 'company or a name/email search' without clarifying that the name/email search maps to the 'search' param or that companyId requires an integer. Half the parameters remain unexplained.
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?
Clear verb (List) and resource (CRM contacts) with stated scope. It does distinguish loosely from siblings like get_contact (single) and search_crm, though it never names them. Solid but no explicit sibling differentiation.
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?
Implies usage via the optional filter wording, but provides no when-to-use/when-not guidance. Notably silent on when to prefer this over search_crm, a close sibling. Usage is inferable but not guided.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_dealsList dealsC
List deals in the sales pipeline, optionally filtered by company or stage.
| Name | Required | Description | Default |
|---|---|---|---|
| stage | No | ||
| companyId | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden of behavioral disclosure, and it only establishes that this is a filtered listing. It says nothing about pagination, result caps, default ordering, or what happens when no filters are supplied — all material for a list tool that returns an unbounded collection.
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?
A single front-loaded sentence with the resource first and the optional filters trailing; nothing is wasted. It is appropriately sized, though the brevity is partly under-specification rather than pure economy.
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 no annotations, no output schema, and 0% parameter coverage, the description is the only source of behavioral context and it omits return shape, pagination, ordering, and filter-combination behavior. For a pipeline-listing tool in a CRM with 15 siblings, that leaves real gaps an agent must guess around.
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 0%, so the description must compensate, and it only names the two filter concepts (company, stage) without adding format, matching semantics, or ID-type guidance. The stage enum values live in the schema, which is the one piece of parameter clarity that is actually structured.
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?
States a specific verb and resource ('List deals') plus the scope ('in the sales pipeline'), so an agent can tell it apart from get_deal or get_pipeline_summary by the plural-resource list semantics. It does not explicitly name any sibling alternative, but the single-vs-collection distinction is inferable from the name and description.
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?
'Optionally filtered by company or stage' implies the usage context (narrow the pipeline view with filters), which is better than nothing. However, it never says when to prefer this over search_crm or get_pipeline_summary, and it gives no exclusion guidance for the case where the caller already has a deal ID.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
log_activityLog activityC
Log a note, call, email, or meeting against a company, contact, or deal.
| Name | Required | Description | Default |
|---|---|---|---|
| type | Yes | ||
| content | Yes | ||
| entityId | Yes | ||
| entityType | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full behavioral burden, and it discloses almost nothing beyond the payload types. It does not say whether the activity is permanently attached to the entity timeline, whether it requires write permissions, whether existing data is affected, or what is returned (e.g., an activity ID).
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?
A single compact sentence with no filler, and the verb plus payload is front-loaded. Nothing could be removed without losing 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?
For a four-required-parameter mutation tool with zero annotations, zero schema descriptions, and no output schema, the description is too thin. It should at minimum clarify what an entityId refers to and what the caller gets back or what side effects occur on the parent entity.
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 0%, so the description must compensate. It effectively documents the two enum parameters by listing the accepted activity types and entity types, which is genuine added value. However, 'content' and 'entityId' receive no explanation of format, length, or which identifier space they draw from, leaving half the required parameters undocumented.
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 states a specific verb ('Log') and enumerates the resource subtypes (note, call, email, meeting) plus the target entities (company, contact, deal). It is clearly distinguishable from the CRUD siblings like create_contact or update_deal_stage, though it never uses the tool's own term 'activity' so the identity mapping is implicit.
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?
There is no indication of when to prefer this tool over alternatives, no prerequisites, and no mention of the sibling tools in the list. The agent must infer that this is for recording interactions rather than creating or modifying entities.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_crmSearch CRMC
Full-text-ish search across companies, contacts, and deals by name/email/title.
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries full burden. It discloses nothing about matching behavior ('full-text-ish' is vague and hedged), case sensitivity, result limits, ranking, pagination, or which fields per entity are actually matched.
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?
One efficient sentence, front-loaded with the action and scope. The hedge 'full-text-ish' is slightly wasteful and imprecise but the definition remains tight.
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 no annotations, no output schema, and 0% parameter coverage, the description should disclose matching behavior and return shape but doesn't. It is under-specified for how an agent must actually invoke and interpret the call.
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 0% and the single 'query' parameter has no schema description. The description partially compensates by implying the searchable fields (name/email/title), but leaves query syntax, matching rules, and formatting entirely undefined.
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?
States a clear verb (search) and resource scope (companies, contacts, deals) with the searchable fields (name/email/title). Distinguishes itself from sibling list_*/get_* tools, which are entity-specific rather than cross-entity search, though it doesn't name a specific alternative.
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 cross-entity nature implies usage (find something when you don't know which entity type it is), but there is no explicit when-to-use or when-not-to-use guidance, and siblings are not referenced.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_companyUpdate companyC
Update fields on an existing company. Only provided fields are changed.
| Name | Required | Description | Default |
|---|---|---|---|
| name | No | ||
| website | No | ||
| industry | No | ||
| companyId | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full behavioral burden. It discloses partial-update semantics ('only provided fields are changed'), which is genuinely useful, but says nothing about authorization requirements, whether changes are reversible, collision handling, or the response shape for a mutation tool.
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?
Two short sentences with no waste; the update scope and partial-update behavior are front-loaded.
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 no annotations, no output schema, and 0% parameter coverage, the description is far too thin. It lacks permission context, return behavior, and parameter documentation that an agent needs to call it 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 0%, so the schema documents no parameter meaning. The description only implies that fields are updatable and that omissions are left unchanged, but never identifies the parameters (name, website, industry, companyId) or their formats and constraints.
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?
States a clear verb (update) and resource (company), and the second sentence clarifies partial-update semantics. It does not explicitly differentiate from create_company or update_contact beyond the resource name, but the resource is 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?
No guidance on when to use this versus create_company or the sibling update tools, and no prerequisites such as required permissions or the need for an existing company ID.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_contactUpdate contactB
Update fields on an existing contact. Only provided fields are changed.
| Name | Required | Description | Default |
|---|---|---|---|
| name | No | ||
| No | |||
| phone | No | ||
| title | No | ||
| companyId | No | ||
| contactId | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full behavioral burden. It does disclose one genuinely non-obvious trait (PATCH-style merge rather than full replacement), but says nothing about permissions, failure when contactId is unknown, side effects of changing email, or idempotency.
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?
Two short sentences, zero filler, with the resource and the partial-update rule front-loaded. Nothing could be cut without losing meaning.
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 no annotations, no output schema, and six undocumented parameters, the description is too thin. An agent gets the merge behavior but lacks field-level semantics, error conditions, and any hint about permissions or the shape of the result.
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 0% across 6 parameters, so the description must compensate and does not. It never enumerates the updatable fields (name, email, phone, title, companyId) or clarifies the required contactId, referring only to generic 'fields'.
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?
States a specific verb and resource ('Update fields on an existing contact') and adds the partial-update qualifier, so an agent can distinguish it from create_contact or get_contact. It never names a sibling explicitly, but the resource is 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 conveys the partial-update contract ('only provided fields are changed'), which is useful for invoking it, but it gives no guidance on when to use update_contact versus create_contact, no prerequisites, and no note that contactId must reference an existing contact.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_deal_stageUpdate deal stageC
Move a deal to a new pipeline stage. Valid stages: lead, qualified, proposal, negotiation, won, lost.
| Name | Required | Description | Default |
|---|---|---|---|
| stage | Yes | ||
| dealId | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full behavioral burden. It says 'move' (a mutation) but discloses nothing about reversibility, whether stage transitions are validated or restricted, whether side effects occur (timestamps, activity logs, webhooks), or permission requirements. For an unannotated mutation tool this is a significant gap.
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?
Two short sentences, front-loaded with the action and followed by the valid values. Nothing is padded. The stage enumeration is somewhat redundant with the schema enum, which slightly dilutes the efficiency, but the structure is otherwise clean.
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 no annotations, no output schema, and 0% parameter description coverage, the description is thin. It omits error/validation behavior, side effects, required permissions, and what the caller gets back — all things an agent needs to invoke this correctly alongside siblings like get_deal or get_pipeline_summary.
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 0%, so the description must compensate for both parameters. It restates the stage enum values already present in the schema (redundant, not additive) and says nothing about dealId — no indication of format, source, or whether it must reference an existing deal. Only one of two parameters gains any description, and that one duplicates structured data.
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?
States a specific verb+resource+scope: 'Move a deal to a new pipeline stage.' An agent can immediately tell this mutates a deal's stage rather than reading or creating deals. It does not explicitly differentiate from siblings such as create_deal or log_activity, but the resource/verb pairing makes the distinction obvious.
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?
Usage is implied by the tool name and the enumerated stage list — an agent infers this is the tool for transitioning deals through the pipeline. There is no explicit when/when-not guidance, no mention of prerequisites (e.g., deal must exist, valid transitions), and no named alternative for related operations.
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.
15 tool updates
v1.0.0- First observed
create_company - First observed
create_contact - First observed
create_deal - First observed
get_company - First observed
get_contact - First observed
get_deal - First observed
get_pipeline_summary - First observed
list_companies - First observed
list_contacts - First observed
list_deals - First observed
log_activity - First observed
search_crm - First observed
update_company - First observed
update_contact - First observed
update_deal_stage
TDQS
Scored across 15 tools
Each tool targets a clear entity (company, contact, deal) and action. The 'get_' tools may include related data, but list vs get vs create/update boundaries are well-defined.
Most names follow verb_noun snake_case, but 'update_deal_stage' and 'log_activity' break the pure pattern, and 'search_crm' and 'get_pipeline_summary' deviate slightly. Still highly predictable overall.
15 tools is within the ideal 3-15 range and covers core CRM operations without redundancy.
CRUD is complete for companies and contacts, but deals lack create/update/delete beyond stage changes, and there is no delete for any entity or explicit activity retrieval. Notable gaps may force workarounds.
Maintenance
Related MCP Connectors
API-first CRM for LLMs - contacts, companies, deals and activities over a native MCP server.
A CRM powered by your agent: contacts, deals, email, ads, and reports over MCP.
CRM + visual automation builder AI agents can drive via MCP: contacts, tags, maps, email/SMS flows.
Read deals, persons, organizations, activities and pipelines; create and update CRM records.
Related MCP Servers
- FlicenseNot gradedqualityCmaintenanceEnables lightweight CRM pipeline management with email sequences, project scanning, and MCP-based interaction for AI agents.-
- FlicenseNot gradedqualityDmaintenanceExposes a fictional B2B CRM database (companies, contacts, deals) as callable MCP tools, enabling AI agents to answer natural-language questions about company records, contacts, and pipeline data.-
- AlicenseAqualityBmaintenanceEnables interaction with HubSpot CRM through MCP, providing tools to manage contacts, companies, deals, and search/associations via natural language.18263 npmMIT
- FlicenseNot gradedqualityCmaintenanceAn MCP-native CRM backend for AI agents, enabling customer, opportunity, note, follow-up, and pipeline health management through 15 MCP tools.-