CleanedWeb Docs

Model Context Protocol

MCP transport and tool guide

Connect MCP clients to CleanedWeb with release-gated tools, workspace API keys, bounded searches, structured outputs, metering, and safe error handling.

By CleanedWeb Published Updated

Transport sequence

Negotiate capabilities before calling a tool.

The MCP lifecycle and the CleanedWeb runtime gate are separate checks; both must pass.

Client/server request sequence
  1. 01InitializeProtocol version
  2. 02NegotiateTools + resources
  3. 03AuthorizeKey stays in adapter
  4. 04InvokeBounded tool input
  5. 05ReturnResult + receipt
REST and MCP responsibilities
ConcernRESTMCP
DiscoveryCapabilities endpointInitialize + tools
AuthenticationBearer headerTrusted adapter
ContractOpenAPI + JSON SchemaTool schemas
MeteringDelivery receiptReceipt in structured result

Current status

Machine access is release-gated. Read GET /v1/capabilities and require machine_access.enabled === true before using API-key authentication or MCP. When the flag is false, no public MCP or API-key surface should be assumed from this static guide.

When enabled, the Streamable HTTP endpoint is https://app.cleanedweb.com/mcp. It uses MCP protocol revision 2025-11-25, JSON-RPC 2.0, stateless JSON responses, and workspace-scoped Bearer API keys. The same key can call the HTTP property API.

Published tool mapping

The gated server publishes exactly these tools through tools/list:

MCP tool Equivalent HTTP operation Unit behavior
cleanedweb_capabilities GET /v1/capabilities No delivery charge
cleanedweb_list_markets GET /v1/markets No delivery charge
cleanedweb_count_properties POST /v1/properties/count No delivery charge
cleanedweb_search_properties POST /v1/properties/search Durable metered receipt
cleanedweb_get_property GET /v1/properties/{property_entity_id} No delivery charge
cleanedweb_list_property_changes GET /v1/properties/{property_entity_id}/changes No delivery charge

Every tool includes an outputSchema and returns the untouched API result in structuredContent. Capabilities, markets, count, one-property, and property-change tools are annotated read-only. Search is intentionally not annotated read-only because it commits a durable Unit receipt; it is annotated non-destructive, idempotent for an exact request, and closed-domain. All six tools use openWorldHint: false. Each output schema accepts the tool's success object or the stable structured error object used when isError is true, so clients can validate both outcomes.

Keep this first tool surface retrieval-only apart from the metered receipt side effect. Webhook management, account administration, saved-search mutation, and authentication endpoints should not be exposed as agent tools without separate approval and confirmation controls.

Published resources

The server declares resources with listChanged: false. resources/list publishes:

  • live runtime capabilities;
  • property-profile-v2;
  • property-profile-field-catalog-v2;
  • property-event-v1;
  • error-v1.

These JSON resources are annotated for the assistant audience with explicit priority. Clients should read capabilities and the property schema first, then the field catalog for semantics. Resource annotations are hints; schema validation and runtime gates remain the enforcement boundary.

Authentication boundary

The MCP client owns a cw_<environment>_... Bearer key and must keep it out of prompts, tool arguments, tool results, URLs, traces, and logs. Keys are scoped to one workspace, have only properties:read, are stored as hashes, and can be revoked. The full secret is returned only when the key is created.

Every connection is authenticated. If an Origin header is present, it must match https://app.cleanedweb.com. The shared per-key request limit returns HTTP 429 with Retry-After; do not defeat it by spreading retries across processes.

Tool input example

An adapter can accept the same property-search fields defined by OpenAPI:

{
  "market": "LU",
  "response_schema": "property-profile-v2",
  "deal_type": ["buy"],
  "location": "Belair",
  "location_place_id": "lux-neighbourhood-belair",
  "property_categories": ["apartment"],
  "max_price": 1000000,
  "min_bedrooms": 2,
  "limit": 100,
  "max_units": 100,
  "idempotency_key": "search-2026-08-04T10:00:00Z"
}

Validate this object against OpenAPI before sending it. Do not add free-form SQL, arbitrary URLs, acquisition controls, or a generic HTTP passthrough to the tool.

Tool output policy

Return the API response without renaming contract fields. Preserve:

  • property_entity_id for canonical identity;
  • schema_version for validation;
  • snapshot.dataUpdatedAt, projectionGenerationId, availableRecords, returned, has_more, and next_cursor for acceptance decisions;
  • sources for provenance.

For conversational use, the adapter may add a compact summary beside the untouched structured response. It must follow the cursor with the unchanged query when has_more is true, restart after snapshot_changed, and not claim freshness when the runtime timestamp is absent or outside policy.

Metering example

Call capabilities before a potentially broad search. When machine access is ready, the runtime publishes the exact delivery rates:

{
  "unit_costs": {
    "first_delivery": 1,
    "unchanged_delivery_within_7_days": 0.1,
    "listing_event_within_7_days": 0.25
  }
}

cleanedweb_search_properties requires max_units, a positive bounded limit, and an idempotency_key. Charging, the response receipt, and delivery classification commit atomically. An exact retry returns the recorded receipt without charging again. A changed request with the same key returns idempotency_conflict.

Use cleanedweb_count_properties for exact "how many" questions. It accepts the search filters but no sort, cursor, limit, spend ceiling, or idempotency key. It returns only the exact total and projection identity, and consumes no delivery Units. For "more than two bedrooms", send min_bedrooms: 3.

An empty unit_costs object still means machine charging is not ready. Do not estimate a charge or invoke the search tool in that state.

Error mapping

Map the stable API error object to a tool error without discarding its fields:

{
  "schema_version": "error-v1",
  "error": {
    "code": "invalid_request",
    "message": "Request validation failed",
    "details": {}
  }
}

The adapter may retry only transient availability failures. It should return authentication, entitlement, validation, ambiguity, and not-found errors to the calling agent for a changed plan or user decision.

Standards and further reading

Continue with the primary sources.

MCP Lifecycle and capability negotiation MCP Authorization specification