See your agent call HubSpotwithout touching anything real.
Point your agent at a faithful mock of any MCP server — or bring your own. Watch every call, inject any failure, never touch real data.
Every tool call your agent makes, captured the moment it happens.
Drops into any MCP client you already run
Read the exact request, response and latency of every call
Every MCP tool call your agent makes — the precise request, response, status and timing — including the failures you inject and the retries that recover.
crm.notes.createCreates a note and attaches it to one or more CRM records.
From the tool catalog — what the agent read.
crm.notes.create with 2 values:bodystringrequiredText content of the note.
associationsarrayoptionalIDs of the records the note is attached to.
Exactly the data the agent sent (JSON)
{
"body": "Logged Q3 expansion deal from agent.",
"associations": ["deal_9981"]
}Rate limited — injected on purpose by the Mockd scenario „429 burst". Your agent waited 250 ms and the retry came back with 201 — from the mock, not the real tool.
{
"error": "RATE_LIMITED",
"message": "Too many requests. Injected by Mockd scenario 'burst'.",
"retryAfterMs": 250
}crm.contacts.searchquery: "acme"200142mscrm.contacts.searchok · 200started 12:04:01.221 · took 142 ms · 3 fieldsFull-text search across CRM contacts; returns matching records.
From the tool catalog — what the agent read.
Agent inputrequired 1/1 · 0 unknownI'm callingcrm.contacts.searchwith 3 values:querystringrequiredSearch term — e.g. a company name or email address.
"acme"propertiesarrayoptionalWhich contact fields to include in the result.
emailcompanylifecyclestagelimitnumberoptionalMaximum number of matches.
10Exactly the data the agent sent (JSON)
{ "query": "acme", "properties": ["email", "company", "lifecyclestage"], "limit": 10 }200 okServer responsewhat the tool returned{ "total": 2, "results": [ { "id": "5512", "company": "Acme Inc.", "email": "ops@acme.io" }, { "id": "5513", "company": "Acme Labs", "email": "hi@acmelabs.dev" } ] }crm.contacts.getid: 551220088mscrm.contacts.getok · 200started 12:04:01.402 · took 88 ms · 2 fieldsLoads a single contact by its unique ID.
From the tool catalog — what the agent read.
Agent inputrequired 1/1 · 0 unknownI'm callingcrm.contacts.getwith 2 values:contactIdstringrequiredUnique ID of the contact.
"5512"propertiesarrayoptionalWhich fields to load.
emailcompanyownerlifecyclestageExactly the data the agent sent (JSON)
{ "contactId": "5512", "properties": ["email", "company", "owner", "lifecyclestage"] }200 okServer responsewhat the tool returned{ "id": "5512", "company": "Acme Inc.", "email": "ops@acme.io", "owner": "rep_42", "lifecyclestage": "opportunity" }crm.deals.createname: "Acme – Q3 Expansion"201196mscrm.deals.createok · 201started 12:04:01.690 · took 196 ms · 4 fieldsCreates a new deal in the CRM pipeline.
From the tool catalog — what the agent read.
Agent inputrequired 1/1 · 0 unknownI'm callingcrm.deals.createwith 4 values:dealnamestringrequiredDisplay name of the deal.
"Acme – Q3 Expansion"amountnumberoptionalDeal value in the account's currency.
48000pipelinestringoptionalID of the pipeline the deal sits in.
"default"dealstagestringoptionalCurrent stage in the sales process.
"qualifiedtobuy"Exactly the data the agent sent (JSON)
{ "dealname": "Acme – Q3 Expansion", "amount": 48000, "pipeline": "default", "dealstage": "qualifiedtobuy" }201 okServer responsewhat the tool returned{ "id": "deal_9981", "dealname": "Acme – Q3 Expansion", "amount": 48000, "createdAt": "2026-06-19T12:04:01Z" }crm.associations.createdeal_9981 ↔ 551220074mscrm.associations.createok · 200started 12:04:01.871 · took 74 ms · 3 fieldsLinks two CRM records together, e.g. a deal with a contact.
From the tool catalog — what the agent read.
Agent inputrequired 3/3 · 0 unknownI'm callingcrm.associations.createwith 3 values:fromobjectrequiredRecord the association starts from — type (e.g. "deal") and id.
{object with 2 fieldstype:"deal"id:"deal_9981"}toobjectrequiredRecord being linked to — also type and id.
{object with 2 fieldstype:"contact"id:"5512"}associationTypestringrequiredType of link (e.g. deal_to_contact).
"deal_to_contact"Exactly the data the agent sent (JSON)
{ "from": { "type": "deal", "id": "deal_9981" }, "to": { "type": "contact", "id": "5512" }, "associationType": "deal_to_contact" }200 okServer responsewhat the tool returned{ "status": "ASSOCIATED", "from": "deal_9981", "to": "5512" }crm.notes.createinjectedrate limit — injected42931mscrm.notes.create429 errorinjected: 429 burststarted 12:04:02.005 · took 31 ms · 2 fieldsCreates a note and attaches it to one or more CRM records.
From the tool catalog — what the agent read.
Agent inputrequired 1/1 · 0 unknownI'm callingcrm.notes.createwith 2 values:bodystringrequiredText content of the note.
"Logged Q3 expansion deal from agent."associationsarrayoptionalIDs of the records the note is attached to.
deal_9981Exactly the data the agent sent (JSON)
{ "body": "Logged Q3 expansion deal from agent.", "associations": ["deal_9981"] }429 errorServer responsewhat the tool returnedRate limited — injected on purpose by the Mockd scenario „429 burst". Your agent waited 250 ms and the retry came back with 201 — from the mock, not the real tool.
{ "error": "RATE_LIMITED", "message": "Too many requests. Injected by Mockd scenario 'burst'.", "retryAfterMs": 250 }crm.notes.create↻ retry okretried after 250ms backoff201110mscrm.notes.createok · 201started 12:04:02.379 · took 110 ms · 2 fieldsCreates a note and attaches it to one or more CRM records.
From the tool catalog — what the agent read.
Agent inputrequired 1/1 · 0 unknownI'm callingcrm.notes.createwith 2 values:bodystringrequiredText content of the note.
"Logged Q3 expansion deal from agent."associationsarrayoptionalIDs of the records the note is attached to.
deal_9981Exactly the data the agent sent (JSON)
{ "body": "Logged Q3 expansion deal from agent.", "associations": ["deal_9981"] }201 okServer responsewhat the tool returned{ "id": "note_4471", "createdAt": "2026-06-19T12:04:02Z" }
Point your agent at Mockd, reach the whole ecosystem
Your agent connects to a single Mockd endpoint. Behind it sits a faithful mock of whatever you want to test — popular SaaS servers from the catalog, or your own custom MCP. No accounts, no keys, no data at risk.
- One mock endpoint stands in for every tool your agent calls
- Swap providers without touching a single line of agent code
- From HubSpot to your own internal server — same trace, same loop
Everything Mockd does — one click deeper
Scroll into the part you care about. Each card opens the full story.
contacts.search142msdeals.create196msnotes.create429See every tool call
From one config to a live trace — watch how your agent reads each tool.
How it worksReady-made mocks
HubSpot, Salesforce, Slack and more — faithful and ready to paste.
Browse the catalogBring your own MCP
Point Mockd at your own server — same trace viewer, your tools.
Connect a serverMock vs. real
Why mock instead of wiring up the real thing — no risk, full control.
Why MockdPaste a config. Watch the first trace.
Grab a ready-made config, drop it into your agent, and see the trace roll in — no signups for services you're only evaluating.
Start testing — free{
"mcpServers": {
"hubspot": {
"url": "mock.mock-d.com/hubspot/mcp",
"headers": { "x-mockd-key": "mk_test_8f2c…" }
}
}
}Questions, answered
Still curious? The docs go deeper on transports, scenarios and the trace API.
What exactly is a 'mock MCP server'?
It's a server that speaks the Model Context Protocol and exposes the same tools — same names, same descriptions, same schemas — as the real thing, but answers with synthetic, deterministic data instead of calling a live API. Your agent can't tell the difference; you get total control and full visibility.
Do I have to change my agent's code?
No. You paste a connection config into whatever MCP client you already use — Claude, Cursor, the OpenAI Agents SDK, LangGraph, and so on. Mockd looks like any other MCP server to your agent.
How is this different from just logging tool calls myself?
Two things: the mock (you don't need the real service or its data) and the viewer (a structured, shareable trace of every call). Together they turn 'integrate, then hope' into 'test, observe, then integrate'.
Can I test my own internal MCP server?
Yes — that's Bring Your Own MCP. Point Mockd at your server's URL and it renders the tool descriptions, proxies the calls, and records a full trace so you can tune prompts against your own tools.
Is the mocked data realistic?
Yes. Mocks return shaped, plausible records (real field names, IDs, relationships) so the model behaves the way it would in production — without any production data being involved.
Which servers can I mock today?
HubSpot is live now. Salesforce, Slack, Stripe, Notion, GitHub and more are next. Bring Your Own MCP works with anything that speaks the protocol.