Public tools
Reference for the Matchai MCP tools search_listings, get_listing and get_professional. Inputs, outputs, examples and the listing-card widget.
The MCP server offers three tools. All of them are read-only, need no account, and return published data only.
| Tool | Purpose |
|---|---|
search_listings | Find available listings by place, price, bedrooms, bathrooms, property type, and sale or rent. |
get_listing | Get the full public details of one listing from any of its addresses or from its id. |
get_professional | Get a broker's public profile and their available listings. |
How the tools behave
- Read-only. Every tool is annotated
readOnlyHint: true,destructiveHint: false,idempotentHint: trueandopenWorldHint: false. They only read Matchai's own published catalogue. - Three parts in every result.
contentis plain text a model can quote.structuredContentis typed data that matches the tool'soutputSchema._metais for the listing-card widget and can be ignored by other clients. - Unknown means null. A fact that the broker did not state is
null, never0. A listing with no stated price hasprice: null. - Forgiving arguments.
nullvalues and empty strings are dropped, and numbers sent as strings, such as"600000"or"$600,000", are converted before validation. - Errors a model can fix come back as a result with
isError: trueand a message. A call that names an unknown tool, or whoseargumentsis not an object, is a JSON-RPC error-32602. See errors.
The listing object
search_listings and get_professional return listing objects, and get_listing returns the same object with extra detail fields.
Field
Type
search_listings
Searches published listings that are available now. It returns up to 10, best match first.
Input
Every field is optional. With no arguments, the most recently updated listings are returned.
Field
Type
query is read with the same parser as listing search: prices, bedrooms, bathrooms, sale or rent and property type are pulled out of the sentence, in English, French or Spanish. An explicit argument always wins over what the sentence says, and the sentence fills in whatever the arguments leave out. If minPrice is higher than maxPrice, the two are swapped.
Output
Field
Type
The text in content starts with the number of listings and a statement of how they are ordered. It then lists one entry per listing with the title, price and type, the facts, the place, the listing broker and the URL.
An empty result says whether Matchai checked every listing or only the most recently updated ones. It never reports "none exist" for a search that did not reach further back. A city or a price range lets the search look further.
Example
Send this as a tools/call request:
{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "search_listings",
"arguments": { "query": "3 bedroom condo in Laval under 600k" }
}
}An abridged result. This search matched one listing, and the filters object shows how the sentence was read:
{
"content": [
{
"type": "text",
"text": "1 published listing on Matchai. Results are ordered by relevance to the request and by how recently the listing was updated. No broker can pay to change the order or to be included.\n\n1. Bright 3-bedroom condo near Montmorency metro — $585,000, condo for sale\n 3 bedrooms · 1.5 bathrooms · 1,120 sq ft · Montmorency, Laval, Québec\n Listed by Alice Tremblay (Agence Exemple)\n https://alice.matchai.co/bright-condo-montmorency"
}
],
"structuredContent": {
"kind": "listings",
"filters": {
"keywords": ["laval"],
"city": null,
"neighbourhood": null,
"transaction": null,
"propertyType": "condo",
"minPrice": null,
"maxPrice": 600000,
"minBedrooms": 3,
"minBathrooms": null
},
"count": 1,
"listings": [
{
"id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"title": "Bright 3-bedroom condo near Montmorency metro",
"url": "https://alice.matchai.co/bright-condo-montmorency",
"price": 585000,
"currency": "CAD",
"priceText": "$585,000",
"transaction": "sale",
"status": "available",
"propertyType": "condo",
"bedrooms": 3,
"bathrooms": 1.5,
"livingAreaSqft": 1120,
"neighbourhood": "Montmorency",
"city": "Laval",
"region": "Québec",
"location": "Montmorency, Laval, Québec",
"image": "https://media.example.com/listings/bright-condo-montmorency/cover.jpg",
"broker": { "name": "Alice Tremblay", "brokerage": "Agence Exemple" },
"site": { "name": "Alice Tremblay Immobilier", "url": "https://alice.matchai.co" },
"updatedAt": "2026-10-12T14:03:22.000Z"
}
]
},
"_meta": {
"ui": { "resourceUri": "ui://matchai/listing-cards.html?v=3f9a1c2b7d10" }
}
}The real _meta object has a few more keys for the widget. The names, addresses and photo host in these examples are made up.
get_listing
Returns the full public details of one published listing.
Input
Send url or id. If you send both, id is used.
Field
Type
These addresses all name the same listing, with or without a trailing slash or tracking parameters:
- the broker's Matchai Site, such as
https://alice.matchai.co/bright-condo-montmorency; - the older form with
/listing/before the slug, such ashttps://alice.matchai.co/listing/bright-condo-montmorency; - the broker's own domain, when the site has one;
- the path form on the platform, such as
https://matchai.co/site/alice/bright-condo-montmorency; - the Markdown copy of any of these, ending in
.md; - the bare listing id.
Output
Field
Type
The extra fields on listing:
Field
Type
Search returns available listings only. get_listing can also return a published listing that has since been sold or rented, so check status.
If no published listing matches, the result has isError: true and says that the listing may have been unpublished or that the address may be incomplete.
Example
{
"name": "get_listing",
"arguments": { "url": "https://alice.matchai.co/bright-condo-montmorency" }
}The structuredContent of the result, abridged:
{
"kind": "listing",
"listing": {
"id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"title": "Bright 3-bedroom condo near Montmorency metro",
"url": "https://alice.matchai.co/bright-condo-montmorency",
"price": 585000,
"currency": "CAD",
"priceText": "$585,000",
"transaction": "sale",
"status": "available",
"propertyType": "condo",
"bedrooms": 3,
"bathrooms": 1.5,
"livingAreaSqft": 1120,
"neighbourhood": "Montmorency",
"city": "Laval",
"region": "Québec",
"location": "Montmorency, Laval, Québec",
"image": "https://media.example.com/listings/bright-condo-montmorency/cover.jpg",
"broker": { "name": "Alice Tremblay", "brokerage": "Agence Exemple" },
"site": { "name": "Alice Tremblay Immobilier", "url": "https://alice.matchai.co" },
"updatedAt": "2026-10-12T14:03:22.000Z",
"description": "A bright corner unit on the fourth floor, five minutes from the metro. …",
"highlights": ["Two balconies", "Indoor parking", "Five minutes from the metro"],
"yearBuilt": 2012,
"lotSizeSqft": null,
"address": null,
"postalCode": null,
"images": [
"https://media.example.com/listings/bright-condo-montmorency/cover.jpg",
"https://media.example.com/listings/bright-condo-montmorency/living-room.jpg"
],
"datePosted": "2026-09-30"
}
}Here the broker did not publish the street address, so address and postalCode are null.
get_professional
Returns a broker's public profile with their available listings, up to 10.
Input
Send username or url. If you send both, username is used.
Field
Type
Output
Field
Type
The fields of professional:
Field
Type
A broker is returned only if they chose to be public somewhere: a published site, a published Matchai Page or an enabled business card. Otherwise the result has isError: true and says that no broker with a public Matchai profile matches.
Example
{
"name": "get_professional",
"arguments": { "username": "alice_tremblay" }
}The professional part of the result's structuredContent. The listings array next to it holds listing objects like those in search_listings.
{
"name": "Alice Tremblay",
"username": "alice_tremblay",
"jobTitle": "Real estate broker",
"brokerage": "Agence Exemple",
"licence": { "number": "123456", "body": "OACIQ" },
"photo": "https://media.example.com/avatars/alice-tremblay.jpg",
"siteUrl": "https://alice.matchai.co",
"pageUrl": "https://alice.matchai.pro",
"contact": { "email": null, "phone": null }
}The listing-card widget
When a tool returns listings, assistants that support MCP Apps can show them as cards inside the conversation. The cards come from one resource that every tool points to.
| Detail | Value |
|---|---|
| URI | ui://matchai/listing-cards.html?v=…, where v is a version that changes whenever the widget changes |
| Type | text/html;profile=mcp-app |
| Name | listing-cards (title "Listing cards") |
| Referenced from | _meta.ui.resourceUri on each tool in tools/list and on each result. ChatGPT reads the same URI from its own key in _meta. |
Read the current URI from tools/list instead of hard-coding it. resources/read also accepts the URI without v, and any older v, and answers with the current widget.
resources/list returns the one resource, including the content security policy the assistant should apply:
{
"resources": [
{
"uri": "ui://matchai/listing-cards.html?v=3f9a1c2b7d10",
"name": "listing-cards",
"title": "Listing cards",
"description": "Interactive cards for the listings a Matchai tool returned.",
"mimeType": "text/html;profile=mcp-app",
"_meta": {
"ui": {
"csp": {
"connectDomains": ["https://matchai.co"],
"resourceDomains": ["https://matchai.co", "https://media.example.com"]
},
"prefersBorder": true
}
}
}
]
}resources/read returns the widget as one self-contained HTML document in contents[0].text. It uses no framework and no external font or script.
What the widget does:
- Shows the result by type.
kind: "listings"becomes a scrolling row of cards,kind: "listing"becomes one larger card with a short description, andkind: "professional"becomes the broker's name, role and a Visit website link above a row of cards. - Follows the assistant. It uses the assistant's colour theme and language (English, French or Spanish) and opens links through the assistant.
- Handles failure. A result with
isError: true, or nostructuredContent, shows "Nothing to show". - Reports that a card was seen. When a card has been on screen long enough to be read, the widget tells Matchai which listings were visible, for how long and how much of each, and the assistant's coarse platform (web, desktop or mobile). If the result carries no token for this report, nothing is sent. It never sends conversation text or a user identifier.
An assistant that does not render MCP Apps ignores the widget. The text in content and the data in structuredContent carry the whole answer. If you build your own cards, link each one to the listing's url.