Simulation only. Estimate, not a reservation. Demo Equipment Hire is fictional; all data is synthetic and every tool is read only. No tool creates a reservation or holds stock.
| Tool | Retrieval page | Required parameters | Optional parameters |
|---|---|---|---|
search_catalog | /read/catalog | query | category (cleaning, garden, power_tools, access, decorating, heating_and_drying), limit (1-10, default 5) |
search_knowledge | /read/knowledge | query | topic (delivery, deposits, collection, returns, cleaning, cancellation, payment, general), limit (1-10, default 5) |
check_availability | /read/availability | productId, quantity, startDate, endDate | none |
calculate_quote | /read/quote | productId, quantity, startDate, endDate, fulfillment | zoneId (required when fulfillment is delivery; not allowed for pickup) |
Search text (query) is trimmed, whitespace is normalized and it must be 1-200
characters. Product and zone identifiers are lowercase letters, digits, hyphens or underscores (at most 64 characters).
quantity is an integer 1-10. fulfillment is pickup or delivery.
One product per estimate. Unknown fields are rejected: there is no way to choose a tenant, a URL or a query.
YYYY-MM-DD and must be real calendar dates in the Europe/Warsaw business calendar. Today's business date is 2026-10-04.startDate and endDate are both required for availability and estimates. They are never assumed: leave them out and the answer is needs_input.startDate is today or later and at most 180 days ahead.[startDate, endDate): the equipment is in use on the start date and available again on the end date. endDate must be after startDate.POST https://sandbox.webcanspeak.com/api/v1/tools/{toolName} with a JSON object of the tool's fields returns the result envelope as JSON. It runs the same
validation and handlers as the retrieval pages, so the same input gives the same business result.
curl -s -X POST https://sandbox.webcanspeak.com/api/v1/tools/check_availability \
-H 'content-type: application/json' \
-d '{"productId":"carpet-cleaner","quantity":2,"startDate":"2026-10-16","endDate":"2026-10-18"}'
The envelope has schemaVersion, simulation, business, tool, status (ok, needs_input or error),
requestId, generatedAt, data, sources, warnings and error.
Four GET pages answer in UTF-8 plain text (text/plain; charset=utf-8). Parameters go in the query string; only public demonstration
values belong there. Parsing is strict and happens before any work:
tenantId, url and sql) is refused with HTTP 400.limit and quantity must be written as plain base-10 digits: no sign, spaces, decimal point, exponent or leading zeros.needs_input (HTTP 422), exactly as in the JSON API.%E9 on its own or %zz is refused with HTTP 400); + means a space.Allow header.Dynamic answers carry Cache-Control: no-store, X-Robots-Tag: noindex and Referrer-Policy: no-referrer.
wcs-read/1)Every line is label: value, split at the first colon and space. Labels are the JSON paths of the result envelope. The document always starts with
format and notice and ends with end: wcs-read/1 (a missing last line means the answer was cut off).
format, notice (the simulation notice), schemaVersion, simulation, business,
tool, transport (always read), status, httpStatus, requestId, generatedAt and, if you sent one, challenge.data.<field>, with error: null) or data: null and the error lines
(error.code, error.message, error.retryable, error.fields.count, error.fields[0], ...).sources.count and, per source, sources[0].sourceId, .title, .url (or null) and .version; then
warnings.count and warnings[0], ....count line followed by [0], [1], ... entries (for example data.products.count, data.products[0].productId,
data.products[0].tags[0], data.articles[0].excerpt, data.lineItems[0].netCents).data.products[n].specifications, data.sourceRevisions) is a list of pairs:
.count, [0].name, [0].value.data.totalCents: 14400) next to data.currency: EUR. Availability is data.available (true or false) and
data.minimumAvailableQuantity. Booleans are true and false; a missing value is null.8, and the strings "true" and "null" print like the boolean and the null. Use the JSON API when the exact JSON type of a specification value matters.\\, a line feed \n, a carriage return \r, a tab \t,
and every other control character, Unicode line or paragraph separator, bidirectional control or unpaired surrogate as \uXXXX. Text taken from data or from the request can therefore
never start a new labelled line.format, notice, status,
httpStatus, error.code, error.message, error.retryable, end.Every retrieval page accepts challenge: 16-64 ASCII letters, digits or hyphens (pattern ^[A-Za-z0-9-]{16,64}$). A valid challenge is repeated in the challenge line of the answer, which lets a
client correlate a retrieval it started. An invalid one is refused with HTTP 400. It is not authentication and not proof of freshness, it is not used to compute the result, and it is never logged or recorded.
| Result | HTTP status | Meaning | Retryable |
|---|---|---|---|
ok | 200 | The tool completed (an empty search or insufficient stock is still ok) | - |
needs_input | 422 | Required business fields are missing | no |
invalid_input | 400 | Schema or business validation failed | no |
not_found | 404 | Unknown or unpublished product or source | no |
unsupported_zone | 422 | Requested delivery zone is not served | no |
rate_limited | 429 | Request allowance exceeded | yes |
upstream_unavailable | 503 | Simulator or database could not complete the operation | yes |
upstream_timeout | 504 | Internal deadline exceeded | yes |
invalid_upstream_response | 502 | Connector response failed validation | no |
stale_data | 503 | Operational snapshot exceeded its allowed age | yes |
internal_error | 500 | Unexpected failure with no safe detailed explanation | no |
The kill switch answers HTTP 503 with upstream_unavailable while documentation and source pages stay available. The retrieval pages and the JSON API use this one status mapping.
Error messages are fixed, safe text; no stack traces, internal addresses or raw dependency errors are ever shown, and no price or availability line appears on an error.
These are produced by the same code that serves the pages, and a test compares each one with what the real service returns for the request shown. The request ID and every time stamp (generatedAt, observedAt, expiresAt) are illustrative and differ on every real answer; the revisions shown are those of the seeded demonstration data.
Status ok, HTTP 200. The amounts are integer cents; the refundable deposit is separate and not taxed.
GET https://sandbox.webcanspeak.com/read/quote?productId=carpet-cleaner&quantity=2&startDate=2026-10-16&endDate=2026-10-18&fulfillment=delivery&zoneId=central
HTTP status 200
format: wcs-read/1 notice: Simulation only. Estimate, not a reservation. schemaVersion: 1.0 simulation: true business: Demo Equipment Hire tool: calculate_quote transport: read status: ok httpStatus: 200 requestId: 00000000-0000-4000-8000-000000000000 generatedAt: 2026-10-04T09:00:00.000Z data.quoteStatus: available data.notice: Simulation only. Estimate, not a reservation. data.productId: carpet-cleaner data.quantity: 2 data.startDate: 2026-10-16 data.endDate: 2026-10-18 data.rentalDays: 2 data.fulfillment: delivery data.zoneId: central data.currency: EUR data.availability.productId: carpet-cleaner data.availability.startDate: 2026-10-16 data.availability.endDate: 2026-10-18 data.availability.requestedQuantity: 2 data.availability.minimumAvailableQuantity: 4 data.availability.available: true data.availability.observedAt: 2026-10-04T09:00:00.000Z data.availability.inventoryRevision: 1 data.lineItems.count: 2 data.lineItems[0].code: rental data.lineItems[0].description: 2 x Carpet cleaner, 2 days at EUR 25.00 net per day data.lineItems[0].netCents: 10000 data.lineItems[1].code: delivery data.lineItems[1].description: Delivery to the Central zone (fixed round-trip fee) data.lineItems[1].netCents: 2000 data.dailyNetCents: 2500 data.rentalNetCents: 10000 data.deliveryNetCents: 2000 data.subtotalNetCents: 12000 data.taxBasisPoints: 2000 data.taxCents: 2400 data.totalCents: 14400 data.depositPerUnitCents: 5000 data.refundableDepositCents: 10000 data.initialAmountIncludingDepositCents: 24400 data.expiresAt: 2026-10-04T09:15:00.000Z data.sourceRevisions.count: 3 data.sourceRevisions[0].name: inventory data.sourceRevisions[0].value: 1 data.sourceRevisions[1].name: rates data.sourceRevisions[1].value: 1 data.sourceRevisions[2].name: rules data.sourceRevisions[2].value: 1 error: null sources.count: 3 sources[0].sourceId: inventory:carpet-cleaner sources[0].title: Inventory availability sources[0].url: https://sandbox.webcanspeak.com/catalog/carpet-cleaner sources[0].version: 1 sources[1].sourceId: rates:carpet-cleaner sources[1].title: Rental rates sources[1].url: https://sandbox.webcanspeak.com/catalog/carpet-cleaner sources[1].version: 1 sources[2].sourceId: rules sources[2].title: Quote rules sources[2].url: null sources[2].version: 1 warnings.count: 1 warnings[0]: Simulation only. Estimate, not a reservation. end: wcs-read/1
Status ok, HTTP 200, quoteStatus unavailable: an explanation and the availability, but no amounts and no expiry. Never read it as a price of zero.
GET https://sandbox.webcanspeak.com/read/quote?productId=carpet-cleaner&quantity=5&startDate=2026-10-16&endDate=2026-10-18&fulfillment=delivery&zoneId=central
HTTP status 200
format: wcs-read/1 notice: Simulation only. Estimate, not a reservation. schemaVersion: 1.0 simulation: true business: Demo Equipment Hire tool: calculate_quote transport: read status: ok httpStatus: 200 requestId: 00000000-0000-4000-8000-000000000000 generatedAt: 2026-10-04T09:00:00.000Z data.quoteStatus: unavailable data.notice: Simulation only. Estimate, not a reservation. data.productId: carpet-cleaner data.quantity: 5 data.startDate: 2026-10-16 data.endDate: 2026-10-18 data.availability.productId: carpet-cleaner data.availability.startDate: 2026-10-16 data.availability.endDate: 2026-10-18 data.availability.requestedQuantity: 5 data.availability.minimumAvailableQuantity: 4 data.availability.available: false data.availability.observedAt: 2026-10-04T09:00:00.000Z data.availability.inventoryRevision: 1 data.explanation: Only 4 of Carpet cleaner are available on every day from 2026-10-16 up to 2026-10-18, but 5 were requested. error: null sources.count: 1 sources[0].sourceId: inventory:carpet-cleaner sources[0].title: Inventory availability sources[0].url: https://sandbox.webcanspeak.com/catalog/carpet-cleaner sources[0].version: 1 warnings.count: 1 warnings[0]: Simulation only. Estimate, not a reservation. end: wcs-read/1
Status needs_input, HTTP 422. error.fields names what is missing; ask the user for it. Nothing is guessed.
GET https://sandbox.webcanspeak.com/read/quote?productId=carpet-cleaner&quantity=2&fulfillment=pickup
HTTP status 422
format: wcs-read/1 notice: Simulation only. Estimate, not a reservation. schemaVersion: 1.0 simulation: true business: Demo Equipment Hire tool: calculate_quote transport: read status: needs_input httpStatus: 422 requestId: 00000000-0000-4000-8000-000000000000 generatedAt: 2026-10-04T09:00:00.000Z data: null error.code: needs_input error.message: Missing required fields (startDate: startDate is required; endDate: endDate is required) error.fields.count: 2 error.fields[0]: startDate error.fields[1]: endDate error.retryable: false sources.count: 0 warnings.count: 1 warnings[0]: Simulation only. Estimate, not a reservation. end: wcs-read/1
Status error, error.code invalid_input, HTTP 400. Here the quantity is outside 1-10.
GET https://sandbox.webcanspeak.com/read/availability?productId=carpet-cleaner&quantity=11&startDate=2026-10-16&endDate=2026-10-18
HTTP status 400
format: wcs-read/1 notice: Simulation only. Estimate, not a reservation. schemaVersion: 1.0 simulation: true business: Demo Equipment Hire tool: check_availability transport: read status: error httpStatus: 400 requestId: 00000000-0000-4000-8000-000000000000 generatedAt: 2026-10-04T09:00:00.000Z data: null error.code: invalid_input error.message: Invalid input (quantity: quantity must be an integer 1-10) error.fields.count: 1 error.fields[0]: quantity error.retryable: false sources.count: 0 warnings.count: 1 warnings[0]: Simulation only. Estimate, not a reservation. end: wcs-read/1
Status error, error.code unsupported_zone, HTTP 422. No price or availability lines appear on an error.
GET https://sandbox.webcanspeak.com/read/quote?productId=carpet-cleaner&quantity=2&startDate=2026-10-16&endDate=2026-10-18&fulfillment=delivery&zoneId=outer-region
HTTP status 422
format: wcs-read/1 notice: Simulation only. Estimate, not a reservation. schemaVersion: 1.0 simulation: true business: Demo Equipment Hire tool: calculate_quote transport: read status: error httpStatus: 422 requestId: 00000000-0000-4000-8000-000000000000 generatedAt: 2026-10-04T09:00:00.000Z data: null error.code: unsupported_zone error.message: Requested delivery zone is not served error.fields.count: 0 error.retryable: false sources.count: 0 warnings.count: 1 warnings[0]: Simulation only. Estimate, not a reservation. end: wcs-read/1
Assistants that support remote MCP servers can use the same four tools. Connecting is an explicit setup step in your assistant or MCP client: you add the server yourself, and nothing on this website installs or connects it. No authentication is needed for this public demonstration.
https://sandbox.webcanspeak.com/mcp. Transport: Streamable HTTP, in its stateless form. Each request stands alone, answers with one JSON message, and there are no sessions, streams or subscriptions.tools/list returns the four tools with descriptions, input and output schemas and read-only annotations (read only, not destructive, idempotent, closed world).
The input schema leaves every business field optional so that an assistant that has not collected a date still reaches the tool, which then asks for it.POST with Content-Type: application/json and an Accept header that lists both application/json and text/event-stream
(the official client does this). One JSON-RPC message per request; JSON-RPC batches (allowed by the 2025-03-26 revision) are deliberately refused, so that one request is at most one tool call. GET and DELETE are HTTP 405.structuredContent is the result envelope described above; the one text content item is the same envelope as JSON. isError is true for needs_input
and for every error, and false for ok (an empty search or insufficient stock is still a successful result). A missing or invalid argument is such a tool result, not a protocol error, so the assistant can read the field names and ask the user.
Only an unknown tool, malformed JSON-RPC or arguments that are not an object are JSON-RPC errors.Origin header must be on the allowlist (requests without one are accepted).
While the emergency switch is off, initialize and tools/list still work and a tool call returns the upstream_unavailable result.Example, with the official TypeScript SDK:
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
const client = new Client({ name: "my-assistant", version: "1.0.0" });
await client.connect(new StreamableHTTPClientTransport(new URL("https://sandbox.webcanspeak.com/mcp")));
const { tools } = await client.listTools();
const quote = await client.callTool({ name: "calculate_quote", arguments: { productId: "carpet-cleaner", quantity: 2, startDate: "2026-10-16", endDate: "2026-10-18", fulfillment: "pickup" } });
https://sandbox.webcanspeak.com/mcp (Streamable HTTP, no authentication; see Connecting an MCP client). Connecting MCP is an explicit client setup step in your assistant; nothing on this website connects it.https://sandbox.webcanspeak.com/catalog/{productId} and https://sandbox.webcanspeak.com/knowledge/{slug}. The source URLs in tool results point here.Demo Equipment Hire is a fictional business. Everything here is simulated.