cenogram-mcp-server
OfficialThis MCP server gives AI assistants access to Polish RCN real-estate transaction data and cadastral parcel context for searching, analyzing, enriching, and valuing properties.
Search 8M+ notarial real-estate transactions by location/TERYT, street/address, parcel ID, property type, price/date/area/rooms/floor, market/transaction/ownership/building type, and hazard/heritage/zoning filters; also search by radius or GeoJSON polygon with sorting and pagination.
Get market analytics: price-per-m² statistics, price histograms, database overview, and side-by-side comparison of 2–5 districts.
Resolve and search cadastral parcels by ID prefix, locality + parcel number, coordinates, bbox/radius/polygon; list parcels in an area, retrieve outlines, and generate full parcel dossiers.
Retrieve parcel/transaction context layers: flood risk, landslide risk, heritage listing, subsurface/mining/groundwater, nearby nuisances, public transport access, building permits and construction activity, general-plan zoning, agricultural land classification/eligibility, nature/forest/protected areas, and geometric road access.
Access GUS BDL demographics, economic, housing, and local statistics, plus municipal infrastructure signals such as tenders, sewerage, roads, and capital spending.
Estimate apartment and undeveloped-land values from comparable registered sales.
Break down a transaction building-by-building with footprint, storeys, estimated floor area, and construction-age estimates.
Browse location/TERYT catalogues and generate shareable map permalinks for specific transactions or areas.
Allows GitHub Copilot in VS Code to access Polish real estate transaction and parcel data by connecting to the MCP server.
Allows ChatGPT to use the server as an MCP data source for Polish real estate transactions, parcel details, and property-risk context.
This server has a remotely hosted endpoint. Open its connector listing for connection details, authentication requirements, and setup instructions:
Cenogram MCP Server
Polish Real Estate Transaction & Parcel Data for AI
MCP server for Polish real estate data. Access 8M+ real estate transactions from the national Registry of Prices and Values (Rejestr Cen Nieruchomosci, RCN) - prices from notarial deeds, not listings - directly from Claude, Cursor, ChatGPT, Grok, or any MCP-compatible AI assistant. Beyond transaction prices, the server resolves cadastral parcels and adds per-parcel context: zoning, flood and landslide risk, heritage register, building permits and construction activity, public transport access, agricultural land classification, surrounding land use, nature - nearby forest and overlapping protected areas - what lies underground (mining terrains and major groundwater reservoirs), the land-use and soil-quality classification, and road access.
Data source: Polish national RCN registry (Rejestr Cen Nieruchomosci) | Platform: cenogram.pl
Get your API key
Go to cenogram.pl/api
Enter your email
You'll receive your
cngrm_...API key by email
Manage your keys at cenogram.pl/ustawienia.
Free tier
New accounts start with 1,000 tokens and a 14-day trial of the Standard plan. After that the key keeps working on 50 tokens a week - the balance is restored to 50 every 7 days rather than accumulating - with no expiry date and no card.
A call costs 1 token for statistics, reference data, parcel identity and municipal context; 3 for a
transaction search (the list plus its summary; 1 with summaryOnly); 2 for a price histogram or a
list of the parcels in an area; 4 for one context layer of
a parcel or transaction; 5 for spatial search, parcel outlines, valuation and a multi-district
comparison; 45 for get_parcel_report, which returns every layer at once. Location catalogues are
free. Paid plans raise the allowance - see cenogram.pl/api.
Related MCP server: rcs-mcp
Installation
Pick your client. All options below use the hosted server - no local install needed (except npx/stdio).
One command - zero config files:
claude mcp add cenogram https://mcp.cenogram.pl/mcp \
-t http -H "Authorization: Bearer YOUR_API_KEY"API key. Add to ~/.codex/config.toml:
[mcp_servers.cenogram]
url = "https://mcp.cenogram.pl/mcp"
bearer_token_env_var = "CENOGRAM_API_KEY"Then export the key in the shell that starts Codex:
export CENOGRAM_API_KEY=cngrm_...OAuth. Use the same block without bearer_token_env_var, then sign in:
[mcp_servers.cenogram]
url = "https://mcp.cenogram.pl/mcp"codex mcp login cenogramWithout an API key or an OAuth login the server answers 401. Configuration keys differ between Codex versions, so check the Codex documentation for your version; this section does not guarantee that a particular version connects.
Add to .cursor/mcp.json in your project:
{
"mcpServers": {
"cenogram": {
"type": "http",
"url": "https://mcp.cenogram.pl/mcp",
"headers": {
"Authorization": "Bearer YOUR_API_KEY"
}
}
}
}Add to your config file:
macOS:
~/Library/Application Support/Claude/claude_desktop_config.jsonWindows:
%APPDATA%\Claude\claude_desktop_config.json
npx (stdio):
{
"mcpServers": {
"cenogram": {
"command": "npx",
"args": ["-y", "@cenogram/mcp-server@latest"],
"env": {
"CENOGRAM_API_KEY": "YOUR_API_KEY"
}
}
}
}Add to .vscode/mcp.json in your workspace:
{
"servers": {
"cenogram": {
"type": "http",
"url": "https://mcp.cenogram.pl/mcp",
"headers": {
"Authorization": "Bearer YOUR_API_KEY"
}
}
}
}Add to ~/.codeium/windsurf/mcp_config.json:
HTTP remote:
{
"mcpServers": {
"cenogram": {
"type": "http",
"url": "https://mcp.cenogram.pl/mcp",
"headers": {
"Authorization": "Bearer YOUR_API_KEY"
}
}
}
}If HTTP doesn't work, use the npx (stdio) option below instead.
In VS Code: Settings > Cline > MCP Servers. Add:
{
"cenogram": {
"type": "http",
"url": "https://mcp.cenogram.pl/mcp",
"headers": {
"Authorization": "Bearer YOUR_API_KEY"
}
}
}Requires Node.js >= 18. Use this if you want to run the server locally instead of connecting to the hosted one.
{
"mcpServers": {
"cenogram": {
"command": "npx",
"args": ["-y", "@cenogram/mcp-server@latest"],
"env": {
"CENOGRAM_API_KEY": "YOUR_API_KEY"
}
}
}
}Client | Config file |
Cursor |
|
Claude Code |
|
Claude Desktop |
|
Windsurf |
|
Cline | VS Code settings > Cline > MCP Servers |
Configuration
Env Variable | Required | Default | Description |
| Yes (stdio) | - | API key from cenogram.pl/api |
| No |
| API base URL |
| No |
| Set to |
| No |
| HTTP server port (HTTP mode only) |
| No | auto-generated | Persistent client identifier |
You can also use the --http CLI flag instead of MCP_TRANSPORT=http.
Tips
Model selection: For best results, use Claude Opus. It makes more sequential tool calls and produces richer analysis. You can switch the model in the dropdown at the bottom of the chat window.
Example Prompts
Polish:
"Jaka jest mediana cen mieszkan w Krakowie w 2025?"
"Pokaz transakcje z ulicy Pulawskiej 15 na Mokotowie"
"Znajdz transakcje na dzialce 126104_9.0015.201"
"Sprawdz plan miejscowy i ryzyko powodziowe dla dzialki 126104_9.0015.201"
"Znajdz transakcje gruntow w promieniu 5km od centrum Wroclawia powyzej 500 000 PLN"
"Porownaj ceny mieszkan na Mokotowie i Woli"
"Pokaz rozklad cen nieruchomosci w Polsce"
English:
"What's the median apartment price in Krakow in 2025?"
"Show transactions at Pulawska 15 in Mokotow"
"Find all transactions on parcel 126104_9.0015.201 and then search nearby"
"Check the zoning and flood risk for parcel 126104_9.0015.201"
"Find land transactions within 5km of Wroclaw center above 500,000 PLN"
"Compare apartment prices in Mokotow and Wola districts"
"Show the price distribution of real estate in Poland"
Tools
Tool | Description | Key Parameters |
| Search transactions with filters | location, street, buildingNumber, parcelId, propertyType, marketType, price/date/area range |
| Price/m2 stats by location (residential only); last 24 months by default, the answer states the period | location (optional), period ( |
| Price histogram | bins, maxPrice |
| Search transactions by geographic radius | latitude, longitude, radiusKm |
| Database overview and stats | (none) |
| List available locations | search (optional) |
| Search parcels by cadastral ID prefix | q (parcel ID prefix, min 3 chars) |
| List the cadastral parcels in an area - light list or full outlines | teryt, location, bbox, lat + lng + radiusKm, or polygon; includeGeometry, minArea/maxArea, street/buildingNumber, cursor |
| Search transactions within a GeoJSON polygon | polygon, propertyType, dateFrom/dateTo |
| Compare stats across 2-5 districts | districts (comma-separated), propertyType |
| Per-building breakdown for one transaction (footprint, storeys, est. floor area) | transaction_id (UUID from a search result) |
| Composite dossier for one parcel: core, 13 enrichment layers, transaction history, local price context (median zł/m² per property type for the county and the gmina), municipal context and a parcel-shape section (bounding rectangle, widest inscribed circle, shape class, area away from the boundaries - geometry of the outline only) | parcelId (cadastral id or UUID) |
| Resolve a parcel to its cadastral identity | parcelId, q (full cadastral id or 'locality + parcel number' - not a street address), or lat + lng |
| Population and demographic context for a location | location or teryt, year (or yearFrom/yearTo), category |
| Municipal infrastructure signals (tenders, utilities, capital spending) | location or teryt |
| Comparable-sales value estimate for an apartment | area, plus lat + lng or parcelId; rooms, market |
| Comparable-sales value estimate for undeveloped land (building plot or farmland), per m² and per hectare | lat + lng (area required) or parcelId (area from the cadastre); landType, mpzpDesignation |
| Flood risk for the property in a transaction | transaction_id (UUID from a search result) |
| Heritage-register status for the property | transaction_id |
| Landslide risk for the property | transaction_id |
| Nuisance and land-use context around the property | transaction_id |
| Public transport accessibility for the property | transaction_id |
| Building permits recorded for the property | transaction_id |
| Building permits and works notifications registered since 2016 around a point (issued decisions only), as a list plus a year × category aggregate | lat + lng; radiusKm (max 2), dateFrom, dateTo, intent, categories, excludeCategories, worksType, limit, cursor, aggregateOnly |
| Local zoning and planning status for the property | transaction_id |
| Agricultural land-use classification for the property | transaction_id |
| Nearby forest and overlapping protected natural areas for the property | transaction_id |
| Mining terrains and major groundwater reservoirs under the property | transaction_id |
| Geometric evidence of road access for the property (distances, road class, access indicator) | transaction_id |
Location naming
Most cities: use the city name directly (e.g., "Gdansk", "Lublin")
Warsaw: "Warszawa" covers all 18 districts at once; name one ("Mokotow", "Srodmiescie", "Wola") to narrow it down
Krakow and Lodz work the same way: the city name covers every sub-district, or name one ("Krakow-Podgorze")
Neighbourhood names are not administrative units - search by radius or polygon instead
Use
list_locationsto find valid names
Property types
Value | Polish | English |
| Grunt | Land plot |
| Budynek | Building |
| Grunt zabudowany | Developed land |
| Lokal | Apartment/unit |
Workflows
Results include parcel IDs and GPS coordinates, enabling multi-step research:
1. Search by address -> search_transactions(location="Mokotow", street="Pulawska", buildingNumber="15")
2. Note parcel_id and coordinates from results
3. Search nearby -> search_by_area(lat=52.19, lng=21.01, radiusKm=2, propertyType="unit")
4. Compare prices -> get_price_statistics(location="Mokotow")This mimics how a property appraiser finds comparable transactions for valuation reports.
Starting from the land rather than from a deed is a different route:
1. List the parcels -> list_parcels_in_area(location="Wawer", minArea=800)
2. Draw the ones you want -> list_parcels_in_area(bbox="21.10,52.20,21.14,52.23", includeGeometry=true)
3. Open one in full -> get_parcel_report(parcelId="146518_8.0108.27")Step 1 pages by cursor; step 2 is capped and usually truncated, so narrow the box rather than reading a truncated answer as the parcel list of the area.
Data
8M+ transactions from all of Poland (380 counties)
Date range: 2003 - present
Source: Polish national RCN registry (Rejestr Cen Nieruchomosci)
Refresh: periodic updates from RCN
Per-parcel context: zoning, flood and landslide risk, heritage register, building permits and construction activity, transit access, agricultural land use, surroundings, nature (nearby forest and protected areas), subsurface (mining terrains and major groundwater reservoirs), land-use and soil-quality classification, and road access - addressable by cadastral ID
Troubleshooting
"Error: CENOGRAM_API_KEY is required" - This only applies to stdio mode. Make sure CENOGRAM_API_KEY is set in the env block of your MCP config. For HTTP remote, the key goes in the Authorization header instead.
npx hangs or fails - Check your Node.js version with node -v. The stdio mode requires Node.js >= 18. If you're on an older version, use the HTTP remote option instead (no Node.js needed).
A location returns 0 results - The name may not be an administrative unit. Districts and neighbourhoods are two different things: "Mokotow" is a district and works, "Sluzew" is a neighbourhood inside it and does not. Use list_locations(search="...") to find valid names, or search by radius (search_by_area) for anything smaller than a district.
401 Unauthorized (HTTP mode) - The server accepts either an API key (Authorization: Bearer cngrm_..., with the Bearer prefix and the full key, not just the prefix) or an OAuth access token from a client that completed the OAuth sign-in. A missing token, or one in an unrecognised format, gets a 401 whose body links to cenogram.pl/api, where you get a key. A client with neither a key nor an OAuth login (Codex CLI, for example) gets 401 on every request - see its setup above.
402 Payment Required - The account is out of tokens. On a free account the response says the date from which the balance is back at its weekly 50; the key and the connection stay valid until then. A paid plan lifts the limit - see cenogram.pl/api.
Development
git clone https://github.com/cenogram/mcp-server.git
cd mcp-server
npm install
npm test
npm run buildLicense
MIT
Available Tools
30 toolscompare_locationsARead-onlyInspect
Compare 2-5 districts side-by-side: median price/m², average area and transaction counts. Matches names only: call list_locations(search=...) first and use names it flags as RCN districts (rcn_district) - other names (most TERYT unit names) silently return no data. Needs at least one filter besides districts (e.g. propertyType).
| Name | Required | Description | Default |
|---|---|---|---|
| floor | No | Unit floor, multi-select: integers ('0' = parter, negatives = basement), 'Nplus' ('0plus' = ground and above), 'unknown' (none recorded). Not building storeys; rows with no floor drop out unless 'unknown' is listed. | |
| rooms | No | Rooms (izby), residential units only; multi-select ('8plus' = 8 or more). Rows with no count drop out unless 'unknown' is listed. | |
| dateTo | No | End date (YYYY-MM-DD) | |
| street | No | Street name filter | |
| maxArea | No | Maximum area in m² | |
| minArea | No | Minimum area in m² | |
| dateFrom | No | Start date (YYYY-MM-DD) | |
| maxPrice | No | Maximum price in PLN | |
| minPrice | No | Minimum price in PLN | |
| districts | Yes | Comma-separated district names (2-5, unique), e.g. 'Mokotów,Wola,Ursynów' | |
| marketType | No | primary (developer) or secondary (resale); the ~55% of records with no market type drop out when this is set. | |
| buildingType | No | Building type (PKOB); 'unknown' = none recorded (NULL, ~39% of buildings), any other value excludes such rows. | |
| propertyType | No | Property type filter (recommended - API requires at least one filter) | |
| unitFunction | No | Unit function; 'unknown' = none recorded (NULL), any other value excludes such rows. Garages only via 'garage'. | |
| ownershipType | No | Legal-right type (rodzaj prawa), multi-select; perpetual_usufruct = użytkowanie wieczyste; 'unknown' = none recorded. | |
| mpzpDesignation | No | MPZP zoning designation, exact token match; comma-separated = OR; 'unknown' = none recorded. Same codes as search_transactions mpzpDesignation. | |
| transactionType | No | Multi-select. For market analysis ALWAYS set it to exclude non-market deeds (subsidized, foreclosure, public_purpose); no-type rows (~2%) drop out unless 'unknown' is listed. | |
| includeDemographics | No | Add a GUS BDL demographics block per district (county-level: density, wages, unemployment, median age, price-to-income). Districts that do not resolve to a county are omitted from it. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, so safety is covered. The description adds genuinely non-obvious behavior: silent empty results for non-RCN district names and the hidden filter requirement. It does not describe result ordering or how districts with no transactions appear, which would push it to a 5.
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?
Three sentences, front-loaded with purpose, then the naming trap, then the filter prerequisite. No filler; every clause carries an operational constraint the agent would otherwise get wrong.
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 an 18-parameter read tool with no output schema, the description covers the highest-risk gaps (name matching, mandatory second filter) and names the returned metrics. Minor gaps remain: it doesn't say how districts without sufficient data are represented or whether includeDemographics affects the shape of the response.
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 100%, so baseline is 3. The description still adds value beyond the schema for the key parameter: districts matches by name only, requires RCN-flagged names, and silently fails otherwise — semantics the schema does not convey. It also hints at propertyType as the typical second filter.
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 (compare 2-5 districts side-by-side) plus the exact output metrics (median price/m², average area, transaction counts). This is clearly distinguishable from sibling aggregators like get_price_statistics or get_market_overview, which are not district-comparison tools.
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?
Explicitly routes the agent through a prerequisite (call list_locations(search=...)) and names the condition that gates success (only names flagged as rcn_district). It also states an exclusion: TERYT unit names silently return no data, and notes the requirement of at least one filter besides districts, e.g. propertyType.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
estimate_land_valueARead-onlyInspect
[Beta] Estimate an undeveloped plot's market value from comparable registered transaction prices near a point. An orientation estimate, NOT a certified appraisal (operat szacunkowy). Address by lat + lng OR parcelId (the parcel centroid is used) - exactly one. area (m², 100–1000000) is REQUIRED with lat/lng; with parcelId it defaults to the cadastre area. landType: plot (building plot, default) or agricultural (farmland) - the caller chooses. Optional mpzpDesignation narrows the comparables; includeComps (default true) echoes them. Returns the estimate per m² and per hectare, a likely and a wide range, a confidence band, the comparable count and an as_of date (as_of lags by county: estimates are NOT comparable across areas with different as_of). Comparables are chosen by the designation recorded in the transaction register (not a local zoning plan), so this does not assert the plot is buildable. Undeveloped land only. Too few comparables, or an area that cannot be determined → no estimate. Costs 5 API tokens, refunded when no estimate is produced. It can be switched off for maintenance (a plain "temporarily unavailable" reply). Aggregates exclude fractional shares and non-market deeds.
| Name | Required | Description | Default |
|---|---|---|---|
| lat | No | Latitude of the plot (WGS84, Poland); pair with lng. Use this OR parcelId (area is then required). | |
| lng | No | Longitude of the plot (WGS84, Poland); pair with lat. Use this OR parcelId (area is then required). | |
| area | No | Plot area in m² (100–1000000). REQUIRED with lat/lng; with parcelId read from the cadastre when omitted. | |
| landType | No | Comparable segment: plot (building plot, default) or agricultural (farmland); the caller chooses. | |
| parcelId | No | Full cadastral id or internal UUID; the parcel centroid is used. Instead of lat/lng. | |
| includeComps | No | Echo the comparables weighed (default true); false = estimate only. | |
| mpzpDesignation | No | Narrow comparables to a recorded land-designation token (e.g. 'budownictwoMieszkanioweJednorodzinne'); 'unknown' = none recorded. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Despite readOnlyHint=true covering the safety profile, the description adds substantial non-obvious behavior: 5-token cost with refund when no estimate is produced, ability to be disabled for maintenance, county-varying as_of that makes estimates non-comparable, and exclusions of fractional shares and non-market deeds.
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?
Front-loaded with the core purpose and a clean beta/appraisal disclaimer, then organized into addressing, returns, and caveats. Dense but nearly every sentence carries a constraint an agent needs; a couple of clauses duplicate the schema descriptions verbatim.
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 output schema exists, yet the description enumerates the return payload (per m² and per hectare, likely and wide range, confidence band, comparable count, as_of date) and explains the no-estimate outcome. An agent knows what it will get and when it won't.
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 100%, so baseline is 3, but the description adds cross-parameter semantics the schema can't express: the exactly-one rule between lat/lng and parcelId, area's conditional requirement/defaulting, and 'unknown' = no designation recorded. Some sentences do restate schema text, preventing a 5.
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?
Specific verb + resource + scope: 'Estimate an undeveloped plot's market value from comparable registered transaction prices near a point,' plus the explicit 'Undeveloped land only' boundary and the disclaimer that this is not a certified appraisal. It doesn't name the closest ambiguous sibling (estimate_value) to route between them, so it stops short of 5.
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?
States addressing rules precisely: 'lat + lng OR parcelId ... exactly one', area REQUIRED with lat/lng and defaulted from the cadastre with parcelId, and that landType is a caller choice. It also names the failure conditions (too few comparables, undeterminable area) and the maintenance mode.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
estimate_valueARead-onlyInspect
[Beta] Estimate an apartment's market value from comparable registered transaction prices near a point. An orientation estimate, NOT a certified appraisal (operat szacunkowy): it ignores condition, finish standard and floor. Address by lat + lng OR parcelId (the parcel centroid is used) - exactly one. area (usable m², 10–250) is REQUIRED. Optional: rooms (1–10) and market (primary/secondary) narrow the comparables; includeComps (default true) echoes them. Returns the point estimate, a likely and a wide range, a confidence band, the comparable count and an as_of date; as_of lags by county, so estimates are NOT comparable across cities with different as_of. Apartments only; for a building plot or farmland use estimate_land_value. Too few comparables → no estimate. Costs 5 API tokens, refunded when no estimate is produced. Aggregates exclude fractional shares and non-market deeds.
| Name | Required | Description | Default |
|---|---|---|---|
| lat | No | Latitude of the apartment (WGS84, Poland); pair with lng. Use this OR parcelId. | |
| lng | No | Longitude of the apartment (WGS84, Poland); pair with lat. Use this OR parcelId. | |
| area | Yes | Apartment usable area in m² (REQUIRED, 10–250). | |
| rooms | No | Room count (1–10); narrows comparables to ±1 room. | |
| market | No | Restrict comparables to the primary (new-build) or secondary market. | |
| parcelId | No | Full cadastral id (slash or dash form) or internal UUID; the parcel centroid is used. Instead of lat/lng. | |
| includeComps | No | Echo the comparables weighed (default true); false = estimate only. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, and the description adds substantial context beyond that: beta status, that this is not a certified appraisal and ignores condition/finish/floor, the as_of county lag making cross-city comparison invalid, the 5-token cost with refund policy, and the exclusion of fractional shares and non-market deeds. It could go slightly further on latency or payload size, but the behavioral disclosure is unusually thorough.
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?
Front-loads the core purpose, then address rules, then return shape and caveats. Dense but every sentence carries information (ranges, as_of caveat, cost/refund, exclusions). Slightly long, but no filler sentences.
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 output schema exists, and the description fully covers the return shape: point estimate, likely and wide range, confidence band, comparable count, and as_of. With usage rules, caveats, and cost behavior all stated, an agent has everything needed 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 coverage is 100%, so parameters are already documented; the description reinforces the critical invariants (exactly one of lat/lng vs parcelId, area required at 10–250 m²) and explains what rooms/market and includeComps actually do to the result. This adds decision-relevant meaning rather than merely repeating 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 and resource ('Estimate an apartment's market value') and immediately clarifies the scope: comparable registered transactions near a point, apartments only. It explicitly distinguishes itself from the sibling estimate_land_value for plots/farmland, so the agent can choose without inspecting schemas.
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?
Gives explicit routing: apartments only, use estimate_land_value for building plots or farmland, and too few comparables yields no estimate. It also specifies the address rule (lat+lng OR parcelId, exactly one) and that area is required, covering both when to use and how to invoke.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_building_breakdownARead-onlyInspect
Building-by-building breakdown for one transaction: footprint area, storeys and estimated total floor area (footprint × storeys) of each building on the property. Use it after a search whose result has building data (searches return per-transaction building SUMS inline) - e.g. a developed-land deed covering several buildings. Each building carries a construction-age ESTIMATE with an interval, derived from building-permit records: never a registry construction date, and the records only start in 2016, so "construction year not established" is the usual honest answer. Cost: 4 tokens. Returns nothing for a transaction with no buildings.
| Name | Required | Description | Default |
|---|---|---|---|
| transactionId | No | ||
| transaction_id | No | Transaction id (UUID) from a search result that carries building data. This or transactionId is required. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint/destructiveHint, so the description carries the burden and does so richly: it discloses provenance of the construction-age ESTIMATE (permit records, never a registry date), the 2016 record horizon, the expected 'not established' outcome, and a concrete cost of 4 tokens. That is exactly the behavioral context structured fields cannot provide.
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?
Front-loaded with what is returned, then the usage trigger, then the caveat about estimate quality and cost. Three tight paragraphs with no filler; every sentence conveys a fact an agent needs (fields, provenance, empty-result behavior, price).
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 output schema and only safety annotations, the description still explains the returned fields, the semantic meaning of the estimate's interval, the empty-result case, and the token cost. Nothing an agent needs to call this correctly is missing.
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 50%: transaction_id is documented in the schema but transactionId is not, and the description never clarifies that the two are aliases for the same UUID. The description's 'for one transaction' adds orientation but no format or disambiguation guidance beyond what the schema already supplies.
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 (building-by-building breakdown for one transaction) and enumerates the returned fields: footprint area, storeys, estimated total floor area with the footprint × storeys formula. It also explicitly contrasts itself with search tools that return per-transaction building SUMS, so an agent can distinguish it from siblings without opening the schema.
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?
Gives a clear trigger: use it after a search whose result carries building data, e.g. a developed-land deed covering several buildings. It also notes the degenerate case (returns nothing for a transaction with no buildings). It doesn't name a specific sibling tool by name, but the alternative (inline search sums) is described well enough to route correctly.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_demographicsARead-onlyInspect
Local statistics for a Polish location from GUS BDL (Poland's Central Statistical Office): ~50 indicators across 11 categories (population, economy, housing, planning, infrastructure, environment, safety, education, prices) plus a few derived metrics. Address by location (city, county or gmina name; a city or county resolves to county level) OR teryt (codes from list_locations). Neighborhoods/osiedla are NOT addressable. Returns the requested level PLUS all parent levels. Optional year, or yearFrom+yearTo for a time series, and category. Cost: 1 token.
| Name | Required | Description | Default |
|---|---|---|---|
| year | No | Single year (2003-present); exclusive with yearFrom/yearTo. Omit for the latest year per indicator. | |
| teryt | No | TERYT: 2-digit voivodeship (14), 4 county (1465), 6 or 7 gmina (1465011). 7th digit: 3 = urban-rural gmina overall, 4/5 = urban/rural part only, 8 = Warszawa district (1465108 = Śródmieście). Wins over location. | |
| yearTo | No | End year for a time series (max current year + 1). | |
| category | No | Categories to return; omit for all. | |
| location | No | City, county, gmina or district name (e.g. 'Warszawa', 'Wieliczka'): city/county → county level, gmina → that gmina, a Warszawa district ('Mokotów') → that district, another city's delegatura ('Kraków-Podgórze') → its parent county. Shared name → candidates; pass one as teryt. Use this OR teryt. | |
| yearFrom | No | Start year for a time series (min 2003). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover safety (readOnly, non-destructive), but the description adds real behavioral context: the return includes the requested level PLUS all parent levels, time-series vs. single-year semantics, the data source (GUS BDL), and an explicit cost of 1 token. This is precisely the kind of non-schema information an agent needs before calling.
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?
Front-loaded with what it returns and the coverage, then addressing rules, then return shape, then cost. No filler sentences; each adds a distinct, actionable fact.
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 output schema, the description still explains the return shape (requested level plus parents), and all six optional parameters are covered by a fully documented schema. Nothing material is missing for correct invocation, including the budget cost.
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 100%, so the baseline is 3; the description goes further by explaining the location→level resolution rule and the neighborhood exclusion, which the schema only partially implies. However, precedence (teryt wins over location) and year vs. yearFrom/yearTo exclusivity are largely restated from the schema rather than adding new meaning.
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 concrete verb+resource (local GUS BDL statistics for a Polish location) with scope quantified (~50 indicators, 11 named categories). The domain, source, and granularity make it unmistakable against siblings such as get_market_overview or the get_transaction_* tools, which cover market/transaction data rather than official local statistics.
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?
Gives clear addressing rules: location by name OR teryt sourced from list_locations, with an explicit exclusion ('Neighborhoods/osiedla are NOT addressable') and resolution behavior (city/county → county level). It does not name an alternative sibling for cases where the agent wants market prices instead, so it stops short of the 5-level bar.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_infrastructure_signalsARead-onlyInspect
Signals that a Polish municipality is about to build infrastructure, from three public sources: tenders in the national procurement bulletin (rolling 12 months), membership in an agglomeration of the national urban waste-water programme, and the municipality's planned capital expenditure from its multi-year forecast. Address by location (city/county name → every municipality in the county) OR teryt (codes from list_locations; wins when both are given). State these limits when reporting: the bulletin has only contracts BELOW EU thresholds (from 2021), so the largest investments are invisible; a tender is attributed to the contracting authority's SEAT, not the works location, so the counters include municipal authorities only while the notice list shows every authority with a flag. Absence of tenders is NOT evidence that a municipality is not investing. Cost: 1 token.
| Name | Required | Description | Default |
|---|---|---|---|
| teryt | No | TERYT code: 6 or 7 digits = one municipality (e.g. 146501), 4 digits = a county aggregate (e.g. 1465). Wins over location. | |
| location | No | City, county, gmina or district name (e.g. 'Warszawa', 'Krotoszyn'): city/county → every municipality in the county, gmina → that gmina alone, a Warszawa district ('Mokotów') → that gmina, another city's delegatura ('Kraków-Podgórze') → its parent county. Shared name → candidates; pass one as teryt. Use this OR teryt. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark this as read-only and non-destructive, and the description adds substantial context beyond them: the below-EU-threshold coverage gap since 2021, tender attribution to the authority's seat rather than works location, counters vs notice-list divergence, and the explicit warning that absence of tenders is not evidence of non-investment. The 1-token cost disclosure is also useful operational context.
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?
The purpose is front-loaded in the first sentence, with addressing rules and caveats following in a logical order. The caveat block is dense but each clause prevents a specific misinterpretation, so it earns its space; the cost note is a small appendage rather than noise.
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 read-only tool with no output schema, the description covers sources, addressing, and major interpretive pitfalls well. It only lightly characterizes the return shape (counters and a notice list with a flag), which is sufficient given the absence of an output schema but not exhaustive.
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 100% and both parameters are fully documented in the schema, including the 4/6/7-digit semantics and location resolution rules. The description restates the teryt-wins precedence and the county-expansion behavior, adding little beyond the schema, so the baseline 3 applies.
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 — signals that a Polish municipality is about to build infrastructure — and enumerates the three data sources (procurement bulletin, agglomeration membership, planned capital expenditure). This is clearly distinct from siblings like get_permits_in_area or get_transaction_permits, which concern existing permits/transactions rather than forward-looking municipal investment signals.
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?
Explains the two addressing modes (location vs teryt) and states teryt wins when both are given, plus how location names resolve to municipalities. It gives clear context for invocation but does not explicitly route the agent away from related siblings such as get_permits_in_area or get_transaction_permits.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_market_overviewARead-onlyInspect
Start here for the shape of the whole Polish transaction database (not one place; for a place use get_price_statistics or search_transactions): total count, date range, breakdown by property and market type, top locations, price statistics. marketType is unknown for ~55% of records, transaction_date missing for ~1.7%.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, so safety is covered structurally. The description adds genuinely non-obvious behavioral context: coverage gaps in the underlying data (marketType unknown for ~55% of records, transaction_date missing for ~1.7%), which materially affect how an agent should interpret the breakdowns. It does not discuss response size, aggregation lag, or freshness, leaving a small 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 sentences, front-loaded with the entry-point instruction and the disambiguation before the enumeration of outputs. Every clause carries information — the negated use case, the sibling redirects, the returned fields, and the data-quality caveats — with no filler.
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 input parameters and no output schema, the description carries the burden of describing the return payload, and it does so by enumerating counts, date range, breakdowns, top locations, and price statistics. Combined with the data-quality caveats, an agent has enough to decide to call it and to interpret 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?
The tool takes zero parameters, so there is nothing for the description to disambiguate and the baseline for a parameterless tool applies. The mention of marketType refers to a returned field rather than an argument, so it neither helps nor confuses parameter semantics.
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/resource ('shape of the whole Polish transaction database') and explicitly negates the likely misreading ('not one place'), then enumerates exactly what comes back: total count, date range, breakdowns, top locations, price statistics. Sibling tools get_price_statistics and search_transactions are named as the per-place alternatives, so the agent can distinguish this from neighbors without opening a schema.
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 opening imperative 'Start here' gives an explicit entry-point rule, and the parenthetical names the alternatives (get_price_statistics, search_transactions) plus the condition that selects them (per-place queries). Both when-to-use and when-not-to-use are stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_parcel_land_classARead-onlyInspect
The official land-use and soil-quality classification of one land parcel and what it implies for taking the land out of agricultural use. Use it only for that question; for anything else about the parcel (prices, flood, zoning, buildings, permits, surroundings, transport) call get_parcel_report (one flat-price call, includes this classification). Returns the land-use categories and soil grades entered for the parcel, whether any grade is in the protected I-III range, whether the parcel is inside a city boundary (changes the rule), and a re-designation note with the date the legal state was verified. They come back as SETS: the source records no area for any of them, so the answer can never say which category prevails or give a share. Answers only where the county publishes the classification; many counties, including several large cities, do not. States: covered; covered_no_data (published, this parcel has none; billed); not_covered (county does not publish it, or we do not hold the parcel; refunded); not_computed (did not finish in time; refunded, retry). Costs 4 API tokens, refunded on not_covered and not_computed. Not legal advice, and never a statement that a parcel can or cannot be built on.
| Name | Required | Description | Default |
|---|---|---|---|
| parcelId | Yes | Full cadastral id ('142907_2.0014.342/5' or the '-' form) or internal UUID. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only say readOnly/non-destructive; the description adds substantial context beyond them: the four coverage states and their billing/refund treatment, the 4-token cost with refund conditions, the fact that results are sets with no areas so no share or dominant category can be stated, and a legal-advice disclaimer. Nothing about calling it correctly is left to inference.
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?
Front-loaded with purpose and the exclusion, then progressively deeper detail on returns, coverage states and cost — a sensible ordering. It is on the long side and the SETS/area explanation takes two clauses to land, but each sentence carries distinct 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?
With no output schema, the description fully supplies the return contract: land-use categories, soil grades, the I-III protected-range flag, the city-boundary rule, and the verification date, plus the set-valued caveat and the enumerated status values. An agent can set expectations and handle every outcome.
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?
Single parameter with 100% schema description coverage, including format examples and accepted ID forms, so the schema carries the load. The description adds no further detail on the parcelId itself (e.g. what happens with an unresolvable or non-held ID beyond the not_covered state), so the baseline 3 applies.
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 — the official land-use and soil-quality classification of one parcel — and immediately scopes it to the agricultural de-designation question. It explicitly distinguishes itself from get_parcel_report, which the agent can recognize without opening a schema.
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?
Gives an explicit when-to-use ('only for that question') and enumerates the adjacent topics that belong elsewhere (prices, flood, zoning, buildings, permits, surroundings, transport), routing them to get_parcel_report, which is noted to include this classification anyway. This is a model routing statement.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_parcel_reportARead-onlyInspect
The whole dossier for one land parcel in one call - prefer it over the per-layer parcel tools. Contains the parcel core (location, area, land use, plan designation); thirteen layers (flood, heritage, landslide, subsurface, nuisance surroundings, transit, general-plan zoning, buildings, building activity, agricultural eligibility, land-use and soil classification, nature, road access); the parcel's transactions (newest first, up to 20); local price context (county and gmina median zł/m², last 12 months); municipal context (demographics, infrastructure signals); and a parcel-shape section (outline geometry only). For a coordinate or 'locality + number' use resolve_parcel first; for a street address use list_parcels_in_area. Every section has its own state: covered; covered_no_data (checked, nothing found; billed); not_covered (outside our data; refunded); not_computed (did not finish in time; refunded - the report can be partial). Context sections use full / low_sample / suppressed / no_data (shape: full / no_data). Long lists are capped with a count of the rest. Reading it: the nearby designation signal comes from RCN deeds of neighbouring land, not from the planning register - it describes the neighbourhood, not this parcel; confirm with the local plan (MPZP) or a zoning decision. Neither it nor the shape section (geometry only) says whether a parcel can be built on or divided. Construction age is an ESTIMATE with an interval (permit records start in 2016), often "not established". Costs 45 API tokens, billed by outcome: an unresolvable parcel is refunded in full; a resolved parcel with no layer data pays only the 1-token core floor; with at least one covered layer, in full. Requests are rate-limited per API key per minute, so parallel agents sharing one key share the same limit. On a "Too many requests" response, wait the given seconds and retry sequentially.
| Name | Required | Description | Default |
|---|---|---|---|
| parcelId | Yes | Full cadastral id ('142907_2.0014.342/5' or the '-' form) or internal UUID. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Though annotations already declare readOnly/destructive=false, the description adds substantial behavior beyond them: billing (45 API tokens, refund rules per outcome), per-key per-minute rate limits with a sequential retry instruction for 'Too many requests', and the possibility of a partial report. It also flags interpretive caveats (RCN-derived neighbourhood signal, construction age as an estimate).
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?
Content is front-loaded: what it is, what's inside, then sibling routing, then state semantics, caveats, and billing. Nearly every sentence carries distinct information. It is dense and long, but the length is justified by the tool's complexity rather than padding.
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 complex aggregate tool with no output schema, the description covers the section inventory, the per-section state vocabulary (covered / covered_no_data / not_covered / not_computed plus context variants), list capping, partial results, and interpretation limits. An agent could call and correctly interpret it from this alone.
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 100% and documents the single parcelId format fully, so the baseline would be 3. The description adds real value by explaining how to obtain a valid id (resolve_parcel for coordinates, list_parcels_in_area for addresses) and by tying id validity to the refund policy for unresolvable parcels.
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 ('whole dossier for one land parcel') and enumerates the exact contents (parcel core, thirteen layers, transactions, price context, municipal context, shape). It also explicitly contrasts itself with 'the per-layer parcel tools', so an agent can distinguish it from siblings without opening any schema.
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?
Explicit routing: 'prefer it over the per-layer parcel tools', 'for a coordinate or locality + number use resolve_parcel first', and 'for a street address use list_parcels_in_area'. It names alternatives and the precise condition that selects each, leaving nothing to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_permits_in_areaARead-onlyInspect
List the building permits and works notifications registered since 2016 within a radius of a point - issued decisions only, matched through the parcel geometry we hold, which is near-complete but not the whole cadastre - to see what is being built nearby. Returns cases newest first, NOT nearest first (a permit and a notification for one investment are two cases), plus an aggregate by year and statutory object category over ALL matched cases (do not add it up across pages) with the permit/notification split and building volume. truncated = more cases than the limit: pass the returned cursor back as cursor with the same filters. Examples: apartment blocks → categories=[XIII]; drop utility-network noise (XXVI can be most of a list) → excludeCategories=[XXVI]; utility works as a sign that land is being serviced for development → categories=[XXVI]. For "how many / how much" pass aggregateOnly=true (same price). The list is ordered by date: for what is closest use a smaller radiusKm (e.g. 0.3) instead of paging; radiusKm is 0.1–2 (default 2), for a wider area make several calls for neighbouring centres. Reading it: decision outcomes (granted or refused) are not held; notifications only where accepted without objection; pending cases not at all. Matching uses the parcel's current identifier and geometry, so cases filed before a split or merge may be missed, parcels without geometry are not searched and a parcel number with a sheet segment may be matched less exactly. The answer states how many parcels we hold in the circle (0 = no data for the area) and the date of the last refresh: loaded periodically, not live. A volume marked suspect stays in the sums. A short or empty list is never a statement that nothing is being built. A query over the time limit returns an error asking for a smaller radius. Coordinates: for a parcel take them from resolve_parcel (or search_parcels); for a street use list_parcels_in_area(location, street) and the centre point of a returned row; otherwise from the user - never guess them. Cost: 5 API tokens per call, also for an empty list; each page is a separate call. It can be switched off for maintenance (a plain "temporarily unavailable" reply).
| Name | Required | Description | Default |
|---|---|---|---|
| lat | Yes | Circle centre latitude (WGS84, Poland), from resolve_parcel / list_parcels_in_area or the user; never guessed. | |
| lng | Yes | Circle centre longitude (WGS84, Poland), from resolve_parcel / list_parcels_in_area or the user; never guessed. | |
| limit | No | Cases in the list, 1–200 (default 50). The aggregate counts all matched cases. | |
| cursor | No | Cursor from the previous answer, for the next page; pass it back unchanged with the same filters. Not with aggregateOnly. | |
| dateTo | No | Window end, YYYY-MM-DD, inclusive, not before dateFrom. When older than two years, pass dateFrom as well. | |
| intent | No | multi_family = categories [XIII], single_family = [I] (incl. semi-detached and terraced), all = no filter (default). Not with categories. | |
| dateFrom | No | Window start, YYYY-MM-DD (decision date; intake date for notifications). Default two years back; earlier than 2016-01-01 counts as 2016-01-01. | |
| radiusKm | No | Radius in km, 0.1–2 (default 2). | |
| worksType | No | new_construction (default) or all (adds extensions, demolitions and other works). | |
| categories | No | Keep only these object categories (Roman numerals I–XXX). Not with intent other than all; must not overlap excludeCategories. | |
| aggregateOnly | No | true = only the aggregate (year × category counts, split, volumes), no case list. Same price; not with cursor. | |
| excludeCategories | No | Drop these object categories (cases without a category stay). Must not overlap categories. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare a safe read; the description adds far more: 5-token cost per call including empty results, per-page charging, periodic (not live) refresh, maintenance outages, an error when the query exceeds the time limit, and the aggregate covering all matched cases rather than the page. It also discloses real data gaps — no decision outcomes, only accepted notifications, no pending cases, parcels without geometry unsearched — which materially shapes interpretation.
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?
The core purpose and the 'newest first, not nearest first' caveat are front-loaded, and almost every clause carries operational value. It is nonetheless a dense wall of text without sectioning, and the cost/paging points are restated in more than one place.
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 12 parameters, no output schema and a complex data source, the description covers return ordering, the year×category aggregate with permit/notification split and volumes, the truncated/cursor protocol, refresh staleness and failure modes. Little an agent needs in order to call and interpret this correctly is missing.
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 100% so the baseline is 3; the description still adds cross-parameter meaning the schema only states tersely, e.g. that the cursor must be replayed with identical filters, that pages must not be summed, and that aggregateOnly costs the same. It does not add much beyond the schema for lat/lng/date bounds, which the schema already documents well.
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 concrete verb and resource ('List the building permits and works notifications'), plus scope (since 2016, within a radius of a point, issued decisions only) and the matching mechanism (parcel geometry held by the service). An agent knows exactly what it gets back compared with a transaction-lookup sibling.
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?
Gives explicit routing guidance: use categories=[XIII] for apartment blocks, excludeCategories=[XXVI] to drop utility noise, aggregateOnly=true for 'how many', and a smaller radiusKm instead of paging to find what is nearest. It also says where coordinates must come from (resolve_parcel / list_parcels_in_area) and forbids guessing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_price_distributionARead-onlyInspect
National histogram (all Poland) of transactions per price range - use it for the overall price structure of the market. No location filter (location/teryt are ignored); for one place use get_price_statistics or search_transactions.
| Name | Required | Description | Default |
|---|---|---|---|
| bins | No | Number of price bins (5-50, default 20) | |
| teryt | No | Ignored: histogram is national. | |
| location | No | Ignored: histogram is national. | |
| maxPrice | No | Maximum price to include (default 3,000,000 PLN) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/destructive hints, and the description adds a key behavioral quirk: location/teryt are silently ignored because the histogram is national. It does not describe the return shape or units explicitly, but for a read-only aggregation tool this is solid added context.
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 efficient sentences with the core purpose front-loaded and the exclusion/alternative guidance following immediately. Every clause earns its place.
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?
Given a read-only, no-output-schema tool with 100% param coverage, the description covers purpose, scope, and the ignored-parameter pitfall. Only the exact histogram/return representation is left implicit, which is a minor gap.
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 100% and already documents bins, maxPrice, and the ignored location/teryt fields. The description's note about ignored params largely repeats what the schema states, so 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 output form (national histogram of transactions per price range) and scope (all Poland), clearly differentiating it from location-scoped siblings. An agent can tell exactly what this returns without opening the schema.
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?
Explicitly states when to use it ('overall price structure of the market') and names the alternatives for the location-specific case ('for one place use get_price_statistics or search_transactions'), including the condition that selects them.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_price_statisticsARead-onlyInspect
Price per m² statistics for residential apartments (lokale mieszkalne) by location; for other property types use search_transactions. Default window: last 24 months (same as the search_transactions median); period="all" for full history. The response states the period used. 'Warszawa'/'Kraków'/'Łódź' auto-expand to all sub-districts; other names use partial match. Based on notarial-deed prices, not asking prices; coverage varies by county (some have data gaps of 5+ years).
| Name | Required | Description | Default |
|---|---|---|---|
| dateTo | No | Custom window end, YYYY-MM-DD, inclusive (default today). Overrides period. | |
| period | No | Window: "24m" (default) = last 24 months, "all" = full history. Ignored when dateFrom or dateTo is set. | |
| dateFrom | No | Custom window start, YYYY-MM-DD. Overrides period. | |
| location | No | Location name; 'Warszawa'/'Kraków'/'Łódź' expand to all sub-districts, other names use case-insensitive partial match (e.g. 'Wrocł' matches 'Wrocław'). Omit for all Poland. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare it as a safe read-only operation, but the description adds material context: data are based on notarial-deed prices rather than asking prices, county coverage varies with possible 5+ year gaps, and the response states the period used. These are meaningful behavioral caveats beyond the annotations.
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?
The description is compact and front-loaded: purpose and sibling exclusion come first, followed by window defaults, location matching, and data caveats. Every sentence contributes useful information without repetition.
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?
Input behavior and data caveats are well covered, but there is no output schema and the description does not explain what statistics are returned (e.g., median, average, count, breakdown). For an agent invoking a statistics tool, that return-shape gap leaves meaningful uncertainty.
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 100%, so all four parameters are already documented in the schema. The description reinforces the default window and location expansion behavior but adds little parameter semantics beyond what the schema provides, so the baseline of 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?
The description states a specific verb+resource: price per m² statistics for residential apartments by location. It also distinguishes the tool from search_transactions by naming the alternative for other property types.
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?
It clearly scopes usage to residential apartments and directs other property types to search_transactions. It also explains the default 24-month window and when to use period="all". However, it does not explicitly compare against related siblings like get_price_distribution or compare_locations.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_transaction_farmlandARead-onlyInspect
Parcel-by-parcel agricultural land-eligibility breakdown for one transaction, from official nationwide eligibility data (updated weekly): per linked parcel with a matched eligible area - the area in m², its share of the parcel (when the measured area is known) and the number of source features; also how many linked parcels carry a match and the snapshot date. Useful for due diligence on land actually eligible/maintained as agricultural, beyond the paper classification. A parcel with no match returns nothing - absence is NEVER a statement that the property is non-agricultural (small plots not actively farmed are absent, the layer has its own update cadence, older transactions can reference renumbered parcels). Cost: 4 tokens (refunded when there is no eligible area).
| Name | Required | Description | Default |
|---|---|---|---|
| transactionId | No | ||
| transaction_id | No | Transaction id (UUID) from a search result. This or transactionId is required. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnlyHint it discloses the crucial interpretive caveat: a no-match result is never proof of non-agricultural status, with three concrete reasons (small unfarmed plots absent, layer update cadence, renumbered parcels on older transactions). It also gives the data refresh cadence and an explicit cost/refund rule, which annotations do not carry.
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?
Purpose and return shape come first, then the caveat and cost. Every sentence carries unique information – no restatement of the name, no filler – despite the density required by the negative-result semantics.
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 carries return semantics itself: per-parcel area in m², share of parcel when measured area is known, source feature count, count of matched parcels, and snapshot date. Combined with the absence caveat and cost note, an agent has everything needed to call and interpret 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 coverage is 50% – only transaction_id is documented as the UUID from a search result – and the description adds nothing about the parameters. In particular it does not clarify that transactionId and transaction_id are duplicate aliases of the same UUID, an ambiguity an agent could stumble on.
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 opening states a specific verb+resource+scope: a parcel-by-parcel agricultural land-eligibility breakdown for a single transaction, drawn from nationwide official data. It is clearly separable from neighboring tools such as get_parcel_land_class (paper classification) and the other get_transaction_* environment lookups.
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?
It gives a clear usage context ('useful for due diligence on land actually eligible/maintained as agricultural, beyond the paper classification') and a cost note, which implies the alternative source. It never names a sibling tool explicitly or states when not to call it, so it stops short of a full routing rule.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_transaction_floodARead-onlyInspect
Parcel-by-parcel flood-hazard breakdown for one transaction: per linked plot in a mapped flood zone - the worst hazard category (high/medium/low, ~1-in-10-year to ~1-in-500-year), hazard type (river/coastal/infrastructure), the share of the plot inside the zone and the per-scenario list with return periods. Use it after a search whose result shows flood_risk (search_transactions and search_by_area surface it inline; search_by_polygon does not). For a parcel with no transaction, get_parcel_report lists the same scenarios. Land in no mapped zone returns nothing - absence of a zone is never asserted as "safe". Cost: 4 tokens (refunded when there is no flood data).
| Name | Required | Description | Default |
|---|---|---|---|
| transactionId | No | ||
| transaction_id | No | Transaction id (UUID) from a search result. This or transactionId is required. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, so the safety profile is covered. The description still adds genuinely useful context the annotations cannot: empty results when no mapped zone exists, an explicit warning that absence is not an assertion of safety, and a stated cost of 4 tokens refunded when no flood data. It doesn't describe ordering or the exact shape of the per-plot payload, but the behavioral cues it does give are strong.
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?
The high-value usage rule and cost/empty-result caveats are front-loaded and every sentence carries information. The opening sentence is dense with clause-heavy enumeration, but that density is payload description rather than padding.
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 output schema, the description carries the full burden of describing return values and does so field by field. Combined with the empty-result semantics, the cost note, and the sibling fallbacks, an agent has everything needed to call this correctly and interpret a null response.
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?
At 50% schema coverage and zero parametrization in the description ('for one transaction'), the baseline of 3 applies. Neither the schema nor the description resolves the real ambiguity: transactionId and transaction_id are duplicate optional aliases with required=[] and no stated either/or rule in the schema for transactionId.
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?
Names a specific verb and resource ('flood-hazard breakdown for one transaction') and enumerates exactly what comes back: hazard category, hazard type, share of plot in zone, and per-scenario return periods. That precision also distinguishes it from the sibling get_flood_risk, which is not transaction-scoped.
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?
Gives an explicit trigger ('after a search whose result shows flood_risk') and names which searches surface it inline (search_transactions, search_by_area) versus which do not (search_by_polygon). It also routes the no-transaction case to get_parcel_report, so the agent has a complete decision tree.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_transaction_heritageARead-onlyInspect
Parcel-by-parcel heritage-listing breakdown for one transaction: per linked plot with a detected listing - the status (listed = a protected monument on/at the plot; zone = within a protected urban layout or the designated surroundings of a monument), the share of the plot inside the protected area (when measurable) and the entries (category, name, function, period, entry date). Use it after a search whose result shows a heritage listing (search_transactions and search_by_area surface heritage_status inline; search_by_polygon does not). For a parcel with no transaction, get_parcel_report lists the same entries. No detected listing returns nothing - absence of a detection is never "not listed". Indicative data: the regional heritage conservator makes the binding determination. Cost: 4 tokens (refunded when there is no heritage data).
| Name | Required | Description | Default |
|---|---|---|---|
| transactionId | No | ||
| transaction_id | No | Transaction id (UUID) from a search result. This or transactionId is required. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond readOnlyHint/non-destructive annotations: it discloses the cost (4 tokens, refunded when there is no heritage data), the authoritative caveat (indicative data; the regional conservator makes the binding determination), and the critical semantic that no detected listing is not the same as 'not listed'. Those are exactly the traits an agent cannot infer from structured fields.
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?
Front-loaded with the purpose, then output shape, then usage routing, then caveats and cost — a sensible ordering with no filler. The first sentence is dense and clause-heavy, but every element carries 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?
There is no output schema, so the description must describe return values, and it does: status meanings for 'listed' vs 'zone', the measurable protected-area share, and the entry fields. Combined with usage routing, cost, and authority caveats, an agent has everything needed to call it and interpret 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?
The two schema parameters are an alias pair (transactionId / transaction_id) at 50% description coverage, and the one documented property already says 'This or transactionId is required.' The description only implies 'one transaction' without naming the parameter or noting the alias, so it adds no real meaning over the schema — adequate but not compensating 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+resource: a parcel-by-parcel heritage-listing breakdown for one transaction, enumerated down to fields (status, protected share, entries with category/name/function/period/entry date). It clearly separates itself from get_parcel_report (no-transaction case) and the search tools, so an agent can identify it without opening the schema.
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?
Explicitly says when to use it ('after a search whose result shows a heritage listing') and names the alternatives: search_transactions and search_by_area surface heritage_status inline, search_by_polygon does not, and get_parcel_report covers a parcel with no transaction. This is a complete routing statement with both positive and negative conditions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_transaction_landslideARead-onlyInspect
Parcel-by-parcel landslide-hazard breakdown for one transaction, from official landslide-hazard maps (1:10,000): per linked plot intersecting a mapped hazard area - the worst category ('landslide' = a mapped landslide area, 'threatened' = an area threatened by mass movements), the share of the plot inside the zones, and the per-zone list (with source_version_date, the source-record version date, not an observation date). At this scale an intersection means overlap with a mapped area, not that the parcel itself is a landslide. Use it after a search whose result shows landslide_risk (inline in search_transactions and search_by_area, not search_by_polygon). For a parcel with no transaction, get_parcel_report gives the share and zone kinds. Land in no mapped zone returns nothing - absence of data is never an assertion of safety. Cost: 4 tokens (refunded when there is no landslide data).
| Name | Required | Description | Default |
|---|---|---|---|
| transactionId | No | ||
| transaction_id | No | Transaction id (UUID) from a search result. This or transactionId is required. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare this is a non-destructive read; the description goes well beyond by disclosing pricing (4 tokens, refunded when no landslide data), the scale caveat (intersection means overlap with a mapped area, not that the parcel is a landslide), the meaning of source_version_date, and the crucial empty-result semantics ('absence of data is never an assertion of safety'). That last point is the kind of behavioral nuance structured fields cannot convey.
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?
Front-loads the core capability, then usage, then caveats and cost — a sensible ordering with no filler sentences. It is dense and the deeply nested parenthetical defining source_version_date forces re-reading, but every sentence carries information an agent needs.
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?
The description effectively documents the return shape (worst category, share of plot in zones, per-zone list) despite there being no output schema, and covers cost, negative results, and scale limits. The only remaining gap is guidance on the two mutually-exclusive transaction id parameters, which matters somewhat given both are optional in the schema.
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 50%: transaction_id carries a description naming it as the UUID from a search result, while transactionId is undocumented in the schema. The description establishes what the input represents ('for one transaction') but never explains the duplicated alias or that either field satisfies the requirement, leaving the agent to reconcile two near-identical parameters itself. Adequate baseline, but it does not fully 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?
The description names a specific resource and scope: parcel-by-parcel landslide-hazard breakdown for a single transaction, sourced from 1:10,000 official hazard maps. It also defines the domain vocabulary ('landslide' vs 'threatened') so the agent understands the output categories, and it is clearly separable from siblings like get_transaction_flood or get_parcel_report.
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?
Explicit trigger: call it after a search whose result shows landslide_risk, and it even names which search tools surface that field (search_transactions, search_by_area) and which do not (search_by_polygon). It also names the alternative for transactions-less parcels (get_parcel_report), which is exactly the when-to-use-another-tool guidance the dimension asks for.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_transaction_natureARead-onlyInspect
Parcel-by-parcel nature breakdown for one transaction: per linked plot with a nature signal - the nearest forest within 2 km (forest_distance_m, 0 = the plot overlaps forest, with the overlap share) and any overlapping protected areas: the sharpest form (protection_rank 1 = national park, 2 = nature reserve, 3 = Natura 2000, 4 = landscape park, 5 = protected landscape, 6 = other), building_restriction ('statutory_ban' = a ban following from the Nature Protection Act for parks and reserves, 'conditional' = depends on the establishing act), the share of the plot under protection and names. Search results carry no nature signal: call this directly on a transaction id when forest proximity or protected-area build limits matter. For a parcel with no transaction, get_parcel_report names the protected areas. It describes the SOURCE of a restriction, not a permitting outcome; not legal advice. An empty result is NEVER a statement that building is allowed (local plans and permit decisions are not covered). A buffer zone around a park or reserve is reported as 'buffer_zone' at rank 6, never as a statutory ban. An empty result says which kind it is: plots checked with no signal, or no nature data held yet - the second is never a finding of no forest or protected area. Cost: 4 tokens (refunded on any empty result).
| Name | Required | Description | Default |
|---|---|---|---|
| transactionId | No | ||
| transaction_id | No | Transaction id (UUID) from a search result. This or transactionId is required. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With only readOnlyHint and destructiveHint annotations, the description adds substantial behavioral context: cost and refund policy, empty-result semantics, buffer-zone treatment, rank meanings, building-restriction meanings, and a legal disclaimer. It also clarifies that the tool describes the source of a restriction rather than a permitting outcome.
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?
The description is front-loaded with the core purpose and then layers in caveats and semantics. It is dense and somewhat long, but most sentences earn their place by preventing misinterpretation of empty results and protected-area rankings.
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 and annotations are minimal, so the description carries most of the explanatory burden. It covers the return concepts, empty-result distinctions, buffer-zone behavior, cost, and legal scope well enough for an agent to invoke and interpret the tool 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 50%, so the description should compensate for gaps. It mentions calling on a transaction id from a search result, but it does not clarify the duplicated transactionId / transaction_id fields or their requiredness, leaving some ambiguity for the agent.
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 gives a specific verb-and-resource purpose: a parcel-by-parcel nature breakdown for one transaction, covering forest proximity and overlapping protected areas. It distinguishes itself from search tools (which carry no nature signal) and from get_parcel_report for parcels without transactions.
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?
It explicitly says to call this directly on a transaction id when forest proximity or protected-area build limits matter, and it names get_parcel_report as the alternative for parcel-only lookups. It also warns that an empty result is never a statement that building is allowed.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_transaction_permitsARead-onlyInspect
Building-permit history for one transaction's parcels, from the national registry of building permits and works notifications (records since 2016): per case - kind (permit / notification), works type, object category, authority, date, address, volume. Use it after a search to screen what was built or approved on the land. Match is by the parcel's current identifier, so splits/merges break the link. Permits are held once a decision is issued (its outcome, granted or refused, is not held); notifications only where accepted without objection; pending cases not at all. For a parcel with no transaction, get_parcel_report lists the cases in its building-activity section. For what is being built around a point, use get_permits_in_area. Three coverage states: covered (at least one registered case), covered_no_data (the transaction exists, its parcels have no case), not_covered (no transaction with this id). An empty result never confirms that nothing was planned. Cost: 4 tokens (refunded when there is no record or no such transaction).
| Name | Required | Description | Default |
|---|---|---|---|
| transactionId | No | ||
| transaction_id | No | Transaction id (UUID) from a search result. This or transactionId is required. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish a safe read operation, but the description adds substantial behavioral context: linkage is by current parcel identifier so splits/merges break it, permit outcome and pending cases are not held, notifications are included only if accepted without objection, and empty results never confirm absence. It also discloses cost and refund conditions.
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?
The purpose is front-loaded, and the remaining sentences add essential caveats, coverage-state meanings, alternatives, and cost information without filler. The length is justified by the domain complexity and absence of an output schema.
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?
Given no output schema, the description supplies the key return-shape information by listing per-case fields. It also explains coverage states, match limitations, inclusion rules, empty-result interpretation, and cost, making it complete enough for correct invocation.
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 schema covers the UUID pattern and partially describes transaction_id as the transaction id from a search result. The description reinforces that the tool operates on one transaction id, but it does not clarify the transactionId vs transaction_id alias or add further parameter-level guidance beyond 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 resource and scope: building-permit history for one transaction's parcels from the national registry, with per-case fields and coverage since 2016. It also distinguishes itself from siblings by naming get_parcel_report and get_permits_in_area for adjacent use cases.
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?
Explicitly says to use it after a search to screen what was built or approved on the land. It also routes the agent to alternatives: get_parcel_report when there is no transaction, and get_permits_in_area for nearby point-based permit activity.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_transaction_planningARead-onlyInspect
General-plan (plan ogólny, POG) zoning for one transaction's land: per linked plot, the zones covering it - symbol, name, share of the plot, the building parameters the plan sets (max height, max development intensity, max built-up coverage, min biologically active area) - plus overlay areas (infill development area / obszar uzupełnienia zabudowy, central development area). Use it for feasibility and permitted-use questions on a plot. Coverage is THREE-STATE: 'covered' returns zone data; 'covered_no_data' = the municipality has an adopted general plan but no zone data covers these plots yet; 'not_covered' = no published general-plan data for the municipality yet - NEVER a claim that it has no plan (general plans are still being adopted). Cost: 4 tokens (refunded for covered_no_data and not_covered).
| Name | Required | Description | Default |
|---|---|---|---|
| transactionId | No | ||
| transaction_id | No | Transaction id (UUID) from a search result. This or transactionId is required. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, yet the description adds substantial context beyond them: the three-state coverage model ('covered'/'covered_no_data'/'not_covered'), the explicit warning that 'not_covered' is never a claim that no plan exists, and the cost of 4 tokens with refund conditions for the two non-data states. That is exactly the kind of operational and interpretive context an agent cannot get from structured fields.
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?
The returned fields and the usage rule come first, followed by the coverage semantics and cost. The parenthetical Polish terms are domain-necessary, and no sentence is filler.
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 describe return values – it does, enumerating zone attributes and overlay areas. Combined with the coverage-state explanation, an agent knows what it will get and how to read an empty 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 only 50% – transaction_id is documented but transactionId is bare – and the description never mentions either parameter, how to obtain a transaction id, or why two aliases for the same UUID exist. With half the parameters undocumented and no compensating text, the agent is left to infer the input contract.
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: general-plan (POG) zoning for one transaction's land, enumerating the returned fields (zone symbol, name, share, max height, development intensity, built-up coverage, biologically active area) and overlay areas. This clearly separates it from the many sibling get_transaction_* hazard tools, which cover flood, heritage, nature, transit, etc.
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?
"Use it for feasibility and permitted-use questions on a plot" gives explicit when-to-use guidance, and the coverage discussion implies when results will be empty. It never names an alternative tool or states exclusions, so it stops short of the top tier.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_transaction_roadsARead-onlyInspect
Plot-by-plot road-access evidence for one transaction, to judge how its land sits relative to the road network: per linked plot, the distance in meters to the nearest public road (500 m), the nearest road of any kind (500 m) and the nearest motorway/expressway/dual-carriageway (3 km; a traffic-nuisance proxy, not access) - plus, for the nearest public road, the estimated distance to its carriageway EDGE (null when the source has no width), its management category and functional class, and whether it runs at ground level (false = viaduct or tunnel). Each plot carries access_indicator (likely / uncertain / unlikely) and its rule version. access_indicator is GEOMETRIC EVIDENCE from carriageway centrelines in reference road data. It does NOT determine legal access or say anything about easements and rights of way (land register, not published here) - a lead to verify, never a conclusion. A null distance means no such road within the radius in the reference data - NEVER a guarantee none exists; assessed=false = not evaluated yet. For a parcel with no transaction, get_parcel_report has a one-line road-access summary. Cost: 4 tokens (refunded when there is no informative data).
| Name | Required | Description | Default |
|---|---|---|---|
| transactionId | No | ||
| transaction_id | No | Transaction id (UUID) from a search result. This or transactionId is required. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint/destructiveHint, yet the description adds substantive behavior: explicit cost (4 tokens, refunded when there is no informative data), the meaning of null distances, assessed=false semantics, and the carriageway-edge null case when the source lacks width. It also bounds interpretation, stating categorically that the indicator is geometric evidence and never a legal-access conclusion.
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?
Front-loaded with purpose before the field list, and every clause carries information (radii, null meaning, legality caveat, cost). It runs long at roughly 150 words, but the dashes and parentheses keep it scannable and no sentence is filler.
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 output schema exists, yet the description fully describes the return shape per plot, including access_indicator values and rule version, plus edge cases (null, assessed=false). Cost and interpretation limits are covered. An agent has everything needed to call and read the result 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 50% — only transaction_id documents itself as 'Transaction id (UUID) from a search result. This or transactionId is required.' The description adds nothing about the two-parameter alias (transactionId vs transaction_id) or which form to prefer. With trivial UUID parameters the schema does most of the work, so baseline 3 fits.
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: plot-by-plot road-access evidence for a single transaction, and enumerates exactly what it returns (nearest public road, any road, motorway distances, carriageway-edge distance, management category, functional class, ground-level flag, access_indicator). This is clearly distinguishable from siblings like get_transaction_transit or get_transaction_surroundings without opening the schema.
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?
Gives a clear purpose statement ('to judge how its land sits relative to the road network') and names a concrete alternative for the no-transaction case: get_parcel_report's one-line road-access summary. It also warns that the motorway distance is a nuisance proxy, not an access measure. No explicit 'do not use this when' exclusion versus other transaction_* siblings, but the routing guidance is strong.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_transaction_subsurfaceARead-onlyInspect
Use it to see whether one transaction's land overlaps a mining terrain or a major groundwater reservoir: per linked plot overlapping either - the mining-terrain status ('active' | 'former') with mineral class ('subsidence' = extraction with surface deformation, the actual mining-damage risk; 'surface' = open-pit, mostly local impact; 'fluid' = borehole extraction; 'other'), the reservoir status ('documented' | 'undocumented'), the share of the plot inside each, and per-object details. A mining terrain is a legally defined zone of anticipated mining influence with an approximate mapped location: an intersection is an advisory signal to verify with the competent mining-supervision authority, not a legal determination. A reservoir's extent alone imposes NO restriction; one would come only from a protection zone, which is not published here. For a parcel with no transaction, get_parcel_report lists the same objects. Land overlapping neither layer returns nothing - absence of data is never an assertion of safety. Cost: 4 tokens (refunded when there is no subsurface data).
| Name | Required | Description | Default |
|---|---|---|---|
| transactionId | No | ||
| transaction_id | No | Transaction id (UUID) from a search result. This or transactionId is required. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the readOnly/destructive annotations: warns that a mining-terrain intersection is advisory only and must be verified with the mining authority, that a reservoir extent alone imposes no restriction, that absence of results is not an assertion of safety, and that the call costs 4 tokens with a refund on empty data. This is exactly the context an agent needs before presenting the result.
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?
The usage and cost statement is front-loaded, and each subsequent sentence carries interpretive value (status enums, legal caveats). It is dense and runs long, but almost nothing could be cut without losing a meaningful caveat.
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, yet the description enumerates the return shape (per-plot overlap, mining status, mineral class semantics, reservoir status, share inside each, per-object details) and covers the all-important negative-result semantics. An agent can call and interpret this correctly without further documentation.
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 50% — only transaction_id carries a schema description, and its purpose is obvious from the UUID pattern and the 'one transaction's land' phrasing. The description adds no format, sourcing, or fallback guidance for the two aliased ID parameters, so it neither compensates nor harms.
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: checks whether one transaction's land overlaps a mining terrain or groundwater reservoir, and enumerates the returned fields. It is clearly distinguishable from siblings like get_transaction_flood or get_transaction_landslide by naming the exact layers covered.
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?
Explicitly names the alternative for parcels without a transaction (get_parcel_report), which is the key routing decision. It does not, however, differentiate against the other transaction_* siblings (flood, heritage, nature, etc.), leaving the agent to infer that those cover different layers.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_transaction_surroundingsARead-onlyInspect
Plot-by-plot surroundings profile for one transaction, for due diligence on nearby nuisances: per linked plot, the distance in meters to the nearest cemetery (1 km radius), landfill (3 km), sewage treatment plant (2 km), industrial/storage area (1 km), large industrial plant (3 km), intensive livestock farm (3 km), high-voltage overhead power line (1 km) and extra-high-voltage overhead power line (1 km). Distances are approximate, from the plot boundary; 0 = the plot touches or overlaps. Only overhead high- and extra-high-voltage lines are covered (medium and low voltage are ubiquitous). For a parcel with no transaction, get_parcel_report lists the same distances. A null distance means no such object within the radius in the reference data - NEVER a guarantee none exists; assessed=false = not evaluated yet. Cost: 4 tokens (refunded when there is no informative data).
| Name | Required | Description | Default |
|---|---|---|---|
| transactionId | No | ||
| transaction_id | No | Transaction id (UUID) from a search result. This or transactionId is required. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish that this is a read-only, non-destructive operation, and the description adds substantial behavioral context: measurement from the plot boundary, per-nuisance radius limits, null-distance meaning, assessed=false meaning, and token cost/refund behavior. The null caveat is especially valuable and not contradicted by annotations.
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?
The purpose is front-loaded, followed by the nuisance list, measurement caveats, null semantics, and cost. The description is dense but every sentence carries useful information and there is no filler.
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 read-only tool with no output schema, the description covers what is measured, the radii, how distances are interpreted, what null and assessed=false mean, cost behavior, and the no-transaction alternative. An agent has enough context to call it correctly, with the only notable gap being parameter alias semantics.
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 50%: transaction_id has a description, but transactionId is undocumented, and the alias relationship is not explained in the tool description. The description says only 'for one transaction' and does not compensate by clarifying which parameter to use, whether both are accepted, or where the UUID comes from.
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 and resource: a plot-by-plot surroundings profile for one transaction, focused on nearby nuisances. It distinguishes itself from the sibling get_parcel_report by explaining that tool covers parcels with no transaction.
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?
It explicitly frames the use case as due diligence on nearby nuisances and names the key alternative for parcels without a transaction. That gives an agent a clear routing rule between this tool and get_parcel_report.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_transaction_transitARead-onlyInspect
Use it to check public-transport access to one transaction's land: for each linked plot, the nearest stop distance by mode (rail/metro within 3000 m, tram 1500 m, bus 1000 m) from open GTFS data, plus the nearest stop's name per mode present. No stop within its cap in any mode returns nothing - absence of a row is never "no transit access" (open feeds cover cities and national rail, not every rural area). Cost: 4 tokens (refunded when there is no transit data).
| Name | Required | Description | Default |
|---|---|---|---|
| transactionId | No | ||
| transaction_id | No | Transaction id (UUID) from a search result. This or transactionId is required. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/non-destructive, but the description adds substantial context beyond them: the exact per-mode distance caps, the GTFS data source, the cost of 4 tokens with a refund on empty results, and the critical negative-result semantics. That last point prevents the agent from misreading an empty response as 'no transit access'.
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?
Front-loaded with purpose, then thresholds, then the negative-result caveat and cost — every sentence carries information. It is dense but not padded; the parenthetical threshold list is the only spot that feels compressed rather than 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 output schema, the description still explains the return shape (distance per mode, nearest stop name per mode present), the row-per-linked-plot granularity, and what an empty result means. Combined with the cost note, an agent has everything needed to call and interpret 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 coverage is 50%: transaction_id is documented in the schema, but the alias transactionId has no description and the two-parameter/zero-required arrangement is ambiguous. The description implies a transaction identifier is needed but never explains the duplicate alias or which to supply, leaving the schema to carry that burden alone.
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: check public-transport access for one transaction's linked plots, returning nearest stop distance per mode plus stop names. This is clearly distinguishable from neighboring tools like get_transaction_roads or get_transaction_surroundings.
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?
Opens with an explicit use case ('Use it to check public-transport access to one transaction's land'), which tells the agent when to reach for it. It does not name an alternative tool or state when not to use it, so it stops short of full routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_locationsARead-onlyInspect
Resolve a place name to TERYT codes, or browse the TERYT hierarchy - the first step before search_transactions (pass the returned code as teryt=).
search (a name): looks it up across all levels (voivodeship, county, municipality, precinct); each match carries its TERYT code, parent unit and the exact follow-up calls; exact and prefix matches come first under 'Best matches'. Rows flagged rcn_district also accept the name in search_transactions(location=) and compare_locations; RCN district names with no TERYT code are listed separately. RCN district matches also show their transaction count and date range, with a warning when the label covers only part of a gmina.
parent (a code): browse children - no parent = 16 voivodeships, 2-digit = counties, 4-digit = municipalities, 6-digit = precincts. parent wins when both are given. Returns administrative units, never streets: for parcels on a street pass the name to list_parcels_in_area as street=. Prefer teryt where a name is ambiguous ('Wałcz' is both a county and a municipality).
| Name | Required | Description | Default |
|---|---|---|---|
| parent | No | TERYT parent code to browse children: 2-digit (voivodeship → counties), 4-digit (county → municipalities), 6-digit (municipality → precincts). Omit for all voivodeships. | |
| search | No | Place name, case- and diacritics-insensitive partial match (e.g. 'wejher' for Wejherowo). Returns TERYT codes plus, where applicable, RCN district names. Ignored when parent is set. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint/non-destructive, yet the description adds substantial behavioral detail: ordering ('Best matches' with exact/prefix first), RCN district flagging and separate listing of code-less districts, transaction count and date range on RCN matches, a partial-gmina warning, and the precedence rule. These are non-obvious traits not derivable from the schema or annotations.
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?
Purpose and the search_transactions follow-up are front-loaded, and every remaining clause carries operational content rather than filler. It is dense and somewhat sprawling in the dash-clause structure, but nothing is purely redundant — a minor trim would make it a 5.
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 output schema, the description must explain return shape, and it does: matches carry TERYT code, parent unit, and exact follow-up calls; RCN district matches add counts and date ranges. Combined with the two fully-documented params and read-only annotations, an agent has everything needed to call and interpret 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 coverage is 100% and already documents both params, but the description still adds meaning beyond it: the code-depth-to-hierarchy-level mapping is restated with the practical consequence, the 'parent wins when both are given' override resolves a real ambiguity the schema only hints at ('Ignored when parent is set'), and it clarifies that results are administrative units, never streets.
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 opening sentence states a specific verb and resource ('Resolve a place name to TERYT codes, or browse the TERYT hierarchy') and immediately positions the tool relative to siblings by naming search_transactions and the teryt= follow-up. The two modes (search vs parent) are explicitly enumerated so the agent can tell this apart from search_parcels/resolve_parcel.
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?
It states when to use this tool ('the first step before search_transactions'), how each mode selects behavior, precedence ('parent wins when both are given'), a disambiguation rule ('Prefer teryt where a name is ambiguous', with the Wałcz example), and an explicit exclusion routing to list_parcels_in_area for streets/parcels. Alternatives and exclusions are both covered.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_parcels_in_areaARead-onlyInspect
List cadastral parcels in an area - the land plots themselves, NOT transactions (for deeds and prices use search_by_area or search_by_polygon). For an id prefix use search_parcels; for a coordinate or 'locality + number' use resolve_parcel (a street address goes here, via street= and buildingNumber=); for everything about one parcel use get_parcel_report.
Name the area (at least one): teryt (codes from list_locations); location (county, city or gmina NAME; a name shared by several units is an error listing the candidates, never a guess); bbox; lat + lng + radiusKm (a circle; not together with a bbox); polygon (on its own).
Two answer shapes, priced differently: the default LIGHT list (parcel id, district, centre point, held street address; 2 API tokens; cursor paging) and OUTLINES, with includeGeometry=true (needs a bbox) or a polygon (GeoJSON polygon per parcel; 5 API tokens; max 100 parcels, 50 by default; no paging). An outline answer marked TRUNCATED is an arbitrary subset (not the first, nearest or largest): never report it as the area's parcel list, ask for a smaller area.
Light-list filters (not on outline calls) need a narrow scope - a bbox, a circle, a location name, or a teryt of at least 4 digits (county) - and do not count as naming the area. minArea / maxArea (m²) = the registered parcel surface.
street: whole-word, case- and accent-insensitive ('Górna' does not find 'Podgórna'; a fragment finds nothing). Not inflected: pass the NOMINATIVE ('Karmelickiej' answers empty). An empty page is free and carries close-name suggestions - read them before concluding anything.
buildingNumber (needs street): exact ('12A' does not find '12a'); RCN often records compound numbers ('84/92'), so '84' will not find '84/92'. If empty, official address points are tried (still exact); if both miss, the page is empty (free) and lists the numbers held on the street. Most rural parcels have no street: outside towns use resolve_parcel with the precinct name and parcel number; an empty street search in the countryside says nothing about the parcel. parcel_id is returned only to API-token / OAuth callers and paid or trial accounts.
Coverage has two gaps. (1) The cadastral data we hold is near-complete but not live (measured per county; fresh splits, merges or renumbering may be missing), for EVERY entrance: a short list or no truncation marker never means you have every parcel. Each answer has a corpus_coverage block (figures for teryt/location, null for bbox/circle/polygon). (2) bbox, circle and polygon miss the few held parcels whose outline is in an unreadable coordinate system; teryt/location list those with no location. A returned parcel is real; never read an empty or short answer as proof the land is not there. Limits: an area over 500 km², a radius over 12.6 km or a polygon over 500 vertices is refused.
| Name | Required | Description | Default |
|---|---|---|---|
| lat | No | Circle centre latitude (WGS84). Needs lng and radiusKm. | |
| lng | No | Circle centre longitude (WGS84). Needs lat and radiusKm. | |
| bbox | No | Bounding box "minLng,minLat,maxLng,maxLat" (WGS84), at most 500 km². Required for includeGeometry=true. | |
| limit | No | Max parcels. Light list: up to 1000, default 250. Outlines: up to 100, default 50. | |
| teryt | No | TERYT code prefix (2/4/6 digits or finer), comma-separated for several. Wins over location. | |
| cursor | No | Opaque cursor from the previous light-list answer, for the next page; pass it back unchanged. Not available on outline calls. | |
| street | No | Street name in the NOMINATIVE (min 4 letters or digits). Needs a bbox, a circle, a location name, or a teryt of at least 4 digits; not with includeGeometry or a polygon. | |
| maxArea | No | Maximum parcel surface in m². Same scope requirement as minArea. | |
| minArea | No | Minimum parcel surface in m². Needs a narrow scope; not with includeGeometry or a polygon. | |
| polygon | No | GeoJSON Polygon: [longitude, latitude] pairs, first and last point identical, max 500 vertices. Always returns outlines. Pass it instead of the other area parameters. | |
| location | No | County, city, gmina or district name, resolved to its TERYT code ('Mokotów' = that Warszawa district; 'Kraków-Podgórze' = its parent county; a gmina name answers at municipality level). | |
| radiusKm | No | Circle radius in km (max 12.6, the radius covering 500 km²). Needs lat and lng. | |
| buildingNumber | No | Building number, exact; needs street, same scope requirement. If nothing is found, drop the number and read the numbers off the street's rows. | |
| includeGeometry | No | Return full outlines instead of the light row (5 tokens instead of 2). Requires a bbox; with a polygon outlines come back anyway. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare a safe read; the description goes far beyond them with token pricing (2 vs 5 API tokens), cursor paging only on light lists, the 500 km² / 12.6 km / 500-vertex refusal limits, free empty pages, TRUNCATED outlines being an arbitrary subset, and two explicitly enumerated coverage gaps. It also discloses an account-dependent behavior (parcel_id only for token/OAuth and paid/trial callers), which no annotation covers.
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?
It is front-loaded and well-sectioned: purpose and sibling routing first, then entrance, then answer shapes, then filter rules, then coverage and limits. It is nonetheless very dense and some clauses duplicate the schema, so trimming would help, but almost every sentence carries decision-relevant 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?
There is no output schema and 14 loosely typed parameters, yet the description names both answer shapes and their fields, explains truncation, paging, token cost, coverage caveats and hard limits. An agent has everything it needs to call this correctly and to interpret a short or empty result without false conclusions.
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 already 100%, so the baseline is 3; the description still adds real semantics the schema lacks — street must be nominative and whole-word, buildingNumber must be exact and compound numbers ('84/92') will not match '84', empty pages carry close-name suggestions, and minArea/maxArea mean the registered parcel surface. Some content (radius max, teryt precedence, limit defaults) merely restates the schema, keeping it below a 5.
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 first sentence states a concrete verb and resource ('List cadastral parcels') and immediately disambiguates from transactions. It then names four sibling tools (search_parcels, resolve_parcel, search_by_area/search_by_polygon, get_parcel_report) with the condition that selects each, so an agent can route without opening any schema.
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?
Explicit when-to-use and when-not-to-use guidance is given for the sibling tools, for the entrance (street address vs precinct + number vs id prefix), and for the output mode (light list vs outlines). It also states exclusions directly, e.g. 'not together with a bbox', 'not on outline calls', and 'outside towns use resolve_parcel'.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
resolve_parcelARead-onlyInspect
Resolve a land parcel to its cadastral identity using exactly ONE of:
parcelId: a full cadastral id ('142907_2.0014.342/5' or the '-' form) or internal UUID.
q: a full id, a UUID, or 'locality name + parcel number' (e.g. 'Sabnie 342/5'): the name is a gmina or cadastral precinct (obręb), matched exactly, case-insensitively; a gmina name plus a number also works for a gmina made of several precincts (e.g. 'Ełk 461/3'). An ambiguous name returns several candidates, not a guess. NOT a street address: for a city address use list_parcels_in_area(street=, buildingNumber=).
lat & lng: a WGS84 point inside the parcel (a road parcel is flagged: the point probably fell on the street). Returns matching parcels with district, area and coordinates; 'truncated' when capped. not_covered: for a FULL id it means we could not confirm the parcel live; in the DISCOVERY modes (name + number, coordinate) only "not among the parcels we hold" (near-complete, not live) - a fresh change or an unusual spelling is likelier than a missing parcel, so never report "no such parcel". not_computed = the lookup could not finish, also not a finding. corpus_coverage says how much of the register was searched. Then feed the id to search_transactions(parcelId) for its sale history. Free.
| Name | Required | Description | Default |
|---|---|---|---|
| q | No | Full cadastral id, UUID, or 'locality name + parcel number' (e.g. 'Sabnie 342/5'); not a street address. Exclusive with parcelId and lat/lng. | |
| lat | No | Latitude WGS84; pair with lng. Exclusive with q and parcelId. | |
| lng | No | Longitude WGS84; pair with lat. Exclusive with q and parcelId. | |
| parcelId | No | Full cadastral id (slash or dash form) or internal UUID. Exclusive with q and lat/lng. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, so safety is covered. The description adds substantial behavior beyond that: ambiguous names return several candidates rather than guessing, road parcels are flagged when a point falls on a street, results can be 'truncated', and not_covered/not_computed/corpus_coverage are explained with warnings about misinterpretation. That is rich context an agent would not get from the annotations alone.
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?
The description is front-loaded with the three usage modes and is organized as bullets, which makes it easy to scan. It is dense but mostly earns its length, though the not_covered paragraph is verbose and could be tightened. It is slightly long for a four-parameter tool, but the structure prevents it from becoming unwieldy.
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 carries the full burden of explaining return values, and it does so: matching parcels include district, area and coordinates, 'truncated' indicates capping, and not_covered/not_computed/corpus_coverage are defined. It also explains the ambiguity response and next-step integration with search_transactions. Nothing essential is missing for correct invocation or interpretation.
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 100%, so the schema already documents each parameter, but the description adds real semantic value beyond it. It gives concrete examples for parcelId forms and q ('Sabnie 342/5', 'Ełk 461/3'), explains name-matching rules (exact, case-insensitive gmina or precinct), describes ambiguity behavior, and specifies that lat/lng must be a WGS84 point inside the parcel. This meaningfully improves correct parameter use.
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 opens with a specific verb and resource: 'Resolve a land parcel to its cadastral identity.' It immediately distinguishes this from nearby tools by naming the exact alternative for street addresses (list_parcels_in_area) and by pointing to search_transactions for sale history. An agent can tell exactly what this tool is for without opening the schema.
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?
It states the exclusive usage rule ('using exactly ONE of') and then explains each mode: parcelId, q, and lat/lng. It explicitly rules out street addresses and redirects to list_parcels_in_area(street=, buildingNumber=), and it describes the follow-up path to search_transactions(parcelId). This is explicit when-to-use and when-not-to-use guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_by_areaARead-onlyInspect
Find transactions within a radius of a point - the tool for neighborhoods/osiedla (not TERYT districts) and street-level searches. Returns TRANSACTIONS (deeds and prices), despite the name; for the land plots themselves in an area use list_parcels_in_area. Radius: 0.3-0.5 km for a street, 0.5-1 km for a neighborhood, 2-5 km for a city area; the area is a bounding box around the radius, so corners extend beyond radiusKm. Take coordinates from the user, never invent them. minArea/maxArea work for every propertyType. Costs 3 API tokens (1 with summaryOnly). Permalink to a result: https://cenogram.pl/ceny-transakcyjne?src=mcpstdio#v=1&lat=&lng=&z=16&tx= ( from the "id:" line, / from "Location: °N, °E"; omit &tx= for the area only).
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | Page 1-10 (50 rows). | |
| floor | No | Unit floor, multi-select: integers ('0' = parter, negatives = basement), 'Nplus' ('0plus' = ground and above), 'unknown' (none recorded). Not building storeys; rows with no floor drop out unless 'unknown' is listed. | |
| limit | No | Number of results (1-50, default 20) | |
| rooms | No | Rooms (izby), residential units only; multi-select ('8plus' = 8 or more). Rows with no count drop out unless 'unknown' is listed. | |
| dateTo | No | End date (YYYY-MM-DD) | |
| landUse | No | Land-use category, multi-select, case-sensitive (gruntyZabudowaneIZurbanizowane = built-up, gruntyRolne = agricultural, gruntyLesne = forest, terenyKomunikacyjne = transport); 'unknown' = none recorded (NULL), not 'no use'. | |
| maxArea | No | Maximum area in m² | |
| minArea | No | Minimum area in m² (usable area for units, parcel area for land) | |
| dateFrom | No | Start date (YYYY-MM-DD) | |
| latitude | Yes | Latitude (Poland range: 49-55) | |
| maxPrice | No | Maximum price in PLN | |
| minPrice | No | Minimum price in PLN | |
| radiusKm | No | Search radius in km (0.1-50, default 2). | |
| floodRisk | No | Flood-hazard zone, multi-select: high ~1-in-10-year, medium ~1-in-100, low ~1-in-500. Mapped zones only; absence of a zone is never 'safe'. | |
| longitude | Yes | Longitude (Poland range: 14-25) | |
| marketType | No | primary (developer) or secondary (resale); the ~55% of records with no market type drop out when this is set. | |
| summaryOnly | No | Return only aggregate stats (total, median price/m² with its sample size, period) and no rows. Costs only the summary call; limit/sort/page are ignored. | |
| buildingType | No | Building type (PKOB); 'unknown' = none recorded (NULL, ~39% of buildings), any other value excludes such rows. | |
| propertyType | No | Property type filter | |
| unitFunction | No | Unit function; 'unknown' = none recorded (NULL), any other value excludes such rows. Garages only via 'garage'. | |
| landslideRisk | No | Landslide hazard, multi-select: landslide = mapped landslide area; threatened = area threatened by mass movements. Mapped areas only; absence of a zone is never 'safe'. | |
| ownershipType | No | Legal-right type (rodzaj prawa), multi-select; perpetual_usufruct = użytkowanie wieczyste; 'unknown' = none recorded. | |
| heritageStatus | No | Heritage listing, multi-select: listed = protected monument on the land; zone = protected urban layout or monument surroundings. Detected listings only; absence of a detection is never 'not listed'. | |
| buildingStoreys | No | Above-ground storeys, multi-select: integers, 'Nplus' ('3plus' = 3+), 'unknown' (no count). Single-building deeds only, so 'unknown' also covers multi-building deeds. Not the unit floor; rows with no count drop out unless 'unknown' is listed. | |
| mpzpDesignation | No | MPZP zoning designation, exact token match; comma-separated = OR; 'unknown' = none recorded. Same codes as search_transactions mpzpDesignation. | |
| transactionType | No | Multi-select. For market analysis ALWAYS set it to exclude non-market deeds (subsidized, foreclosure, public_purpose); no-type rows (~2%) drop out unless 'unknown' is listed. | |
| maxFootprintArea | No | Maximum building footprint in m², summed over the transaction's buildings; measured rows only (absence = 'not measured', not 'no building'). Not usable area. | |
| minFootprintArea | No | Minimum building footprint in m², summed over the transaction's buildings; measured rows only (absence = 'not measured', not 'no building'). Not usable area. | |
| excludeFractionalShares | No | true = clean land prices: drops fractional ownership shares, whose price reflects the whole deed. Default false. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the readOnlyHint annotation: it discloses token cost (3 API tokens, 1 with summaryOnly), the bounding-box approximation that makes corners extend past radiusKm, and the exact permalink construction including which output fields to substitute. That is unusually rich context for a read-only 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?
Front-loaded purpose sentence followed by short labeled blocks (radius guidance, cost, permalink), so it scans well. Slightly dense with the permalink template, but no sentence is filler.
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 29 parameters and no output schema, it still tells the agent what comes back (deeds and prices), what the id/Location lines look like, and how to build a permalink. Minor gaps around ordering/sort behavior, but nothing that would cause a wrong 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 100%, so baseline is 3, but the description adds cross-parameter meaning the schema lacks: radius sizing per search intent, that the area is a bounding box, that minArea/maxArea apply to every propertyType, and that summaryOnly makes limit/sort/page irrelevant.
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 ('Find transactions within a radius of a point') and explicitly disambiguates from the name itself ('Returns TRANSACTIONS, despite the name'), while naming list_parcels_in_area as the alternative for parcels. An agent can pick it apart from search_transactions or search_by_polygon without opening the schema.
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?
Gives concrete when-to-use conditions (neighborhoods/osiedla rather than TERYT districts, street-level searches), names the direct alternative for a different need, and adds operational rules: radius 0.3-0.5 km for a street, 2-5 km for a city area, and 'Take coordinates from the user, never invent them.'
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_by_polygonARead-onlyInspect
Find transactions inside a GeoJSON Polygon - for precise neighborhood/osiedla boundaries; for a quick look start with search_by_area (its results can help estimate coordinates). Returns TRANSACTIONS (deeds and prices) with coordinates, despite the name; for the land plots inside a drawn shape pass the same polygon to list_parcels_in_area. Costs 5 API tokens. Permalink to a result: https://cenogram.pl/ceny-transakcyjne?src=mcpstdio#v=1&lat=&lng=&z=16&tx= ( from the "id:" line, / from "Location: °N, °E"; omit &tx= for the area only).
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | Page 1-20 (50 rows). | |
| floor | No | Unit floor, multi-select: integers ('0' = parter, negatives = basement), 'Nplus' ('0plus' = ground and above), 'unknown' (none recorded). Not building storeys; rows with no floor drop out unless 'unknown' is listed. | |
| limit | No | Max results (1-3000); 50 shown. | |
| rooms | No | Rooms (izby), residential units only; multi-select ('8plus' = 8 or more). Rows with no count drop out unless 'unknown' is listed. | |
| dateTo | No | End date (YYYY-MM-DD) | |
| street | No | Street name filter (partial match) | |
| landUse | No | Land-use category, multi-select, case-sensitive (gruntyZabudowaneIZurbanizowane = built-up, gruntyRolne = agricultural, gruntyLesne = forest, terenyKomunikacyjne = transport); 'unknown' = none recorded (NULL), not 'no use'. | |
| maxArea | No | Maximum area in m² | |
| minArea | No | Minimum area in m² | |
| polygon | Yes | GeoJSON Polygon: [longitude, latitude] pairs, first and last point identical, max 500 vertices total. | |
| dateFrom | No | Start date (YYYY-MM-DD) | |
| district | No | District name filter | |
| maxPrice | No | Maximum price in PLN | |
| minPrice | No | Minimum price in PLN | |
| marketType | No | primary (developer) or secondary (resale); the ~55% of records with no market type drop out when this is set. | |
| buildingType | No | Building type (PKOB); 'unknown' = none recorded (NULL, ~39% of buildings), any other value excludes such rows. | |
| propertyType | No | Property type filter | |
| unitFunction | No | Unit function; 'unknown' = none recorded (NULL), any other value excludes such rows. Garages only via 'garage'. | |
| ownershipType | No | Legal-right type (rodzaj prawa), multi-select; perpetual_usufruct = użytkowanie wieczyste; 'unknown' = none recorded. | |
| buildingStoreys | No | Above-ground storeys, multi-select: integers, 'Nplus' ('3plus' = 3+), 'unknown' (no count). Single-building deeds only, so 'unknown' also covers multi-building deeds. Not the unit floor; rows with no count drop out unless 'unknown' is listed. | |
| mpzpDesignation | No | MPZP zoning designation, exact token match; comma-separated = OR; 'unknown' = none recorded. Same codes as search_transactions mpzpDesignation. | |
| transactionType | No | Multi-select. For market analysis ALWAYS set it to exclude non-market deeds (subsidized, foreclosure, public_purpose); no-type rows (~2%) drop out unless 'unknown' is listed. | |
| maxFootprintArea | No | Maximum building footprint in m², summed over the transaction's buildings; measured rows only (absence = 'not measured', not 'no building'). Not usable area. | |
| minFootprintArea | No | Minimum building footprint in m², summed over the transaction's buildings; measured rows only (absence = 'not measured', not 'no building'). Not usable area. | |
| excludeFractionalShares | No | true = clean land prices: drops fractional ownership shares, whose price reflects the whole deed. Default false. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, and the description adds meaningful context beyond that: it costs 5 API tokens, returns transactions with coordinates and prices, includes a permalink construction pattern, and clarifies the naming mismatch. This is useful behavioral information that helps the agent set expectations.
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?
The description is front-loaded with the core purpose and routing guidance, then adds cost and permalink details. Every sentence earns its place by helping the agent choose and use the tool correctly.
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 complex 25-parameter read-only tool with no output schema, the description covers purpose, alternatives, token cost, return content, and permalink format. Combined with the fully documented schema, this is complete enough for correct invocation.
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 all 25 parameters are already well documented in the schema. The description only references the polygon and does not add parameter-level semantics beyond what the schema provides, so the baseline of 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?
The description states a specific verb and resource: find transactions inside a GeoJSON Polygon. It explicitly distinguishes this from search_by_area for quick looks and list_parcels_in_area for land plots, and clarifies that it returns transactions despite the tool 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?
It gives explicit routing guidance: use this for precise neighborhood/osiedla boundaries, start with search_by_area for a quick look, and use list_parcels_in_area for land plots inside the same shape. It also states the token cost, which helps the agent decide when to invoke it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_parcelsARead-onlyInspect
Autocomplete land parcels by cadastral ID PREFIX only, never by area: for the parcels in a place or shape use list_parcels_in_area; to turn a coordinate or 'locality + number' into one parcel use resolve_parcel (a street address: list_parcels_in_area). Returns matching parcels with district, area and GPS coordinates (e.g. prefix '146518_8.01'). Coverage: the cadastral register we hold is near-complete but not live, so an empty result more likely means a recent change or a mistyped prefix than that no such parcel exists - never report it as "this parcel does not exist" (resolve_parcel with the FULL id can still confirm and add one). Free: costs no API tokens.
| Name | Required | Description | Default |
|---|---|---|---|
| q | Yes | Parcel ID prefix (min 3 chars), e.g. '146518_8.01' | |
| limit | No | Max results (1-10, default 10) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, yet the description still adds real behavior: the register is near-complete but not live, empty results are ambiguous rather than proof of non-existence, and the call is token-free. The only residual friction is the muddled parenthetical 'a street address: list_parcels_in_area', which slightly clouds the routing instead of sharpening it.
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?
Front-loaded with the core constraint in the first clause, and the coverage caveat and cost note are compact, high-value lines. The nested parenthetical in the routing sentence costs a little readability but nearly every sentence carries distinct 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 two-parameter search with no output schema, it covers everything an agent needs: what comes back (district, area, GPS coordinates), how to interpret an empty result, and when to escalate to resolve_parcel with the full ID. No annotation or schema gap is left unaddressed.
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 100% and both parameters ('q' prefix with min 3 chars, 'limit' 1-10) are documented inline, so the schema already carries the load. The description's example prefix '146518_8.01' duplicates the schema example rather than extending it, so this is baseline territory.
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 ('autocomplete land parcels by cadastral ID PREFIX only') and immediately bounds the scope by naming the operations it is not ('never by area'). The routing sentence names the two siblings that handle area/shape and full-ID resolution, so an agent can distinguish it without opening any schema.
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?
Explicitly partitions the task space: prefix search here, list_parcels_in_area for a place or shape, resolve_parcel for a coordinate or 'locality + number'. It even supplies a negative rule ('never by area') that closes the most likely misuse path.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_transactionsARead-onlyInspect
Find individual Polish real-estate transactions from the national RCN registry (8M+ notarial deeds, not asking prices) by place, property type, price, area, date or street. Returns address, date, price, area, price/m² and property type. Resolve the place first: list_locations(search=...), then pass its TERYT code as teryt= (exact match). Use location= only for a name that result flags as an RCN district (rcn_district) - other names silently return zero rows. Neighborhoods (osiedla) are not TERYT districts: use search_by_area. Data notes: marketType is NULL for ~55% of records (filtering by it drops them); ~1.7% have no transaction_date. Permalink to a result: https://cenogram.pl/ceny-transakcyjne?src=mcpstdio#v=1&lat=&lng=&z=16&tx= ( from the "id:" line, / from "Location: °N, °E"; omit &tx= for the area only). Inline [...] notes flag computed values (summed or converted parcel area, inferred property type) and approximated streets; all else is as recorded in the deed.
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | Page number for pagination (default: 1) | |
| sort | No | Sort by field (default: date) | date |
| floor | No | Unit floor, multi-select: integers ('0' = parter, negatives = basement), 'Nplus' ('0plus' = ground and above), 'unknown' (none recorded). Not building storeys; rows with no floor drop out unless 'unknown' is listed. | |
| limit | No | Number of results (1-50, default 10) | |
| order | No | Sort order (default: desc) | desc |
| rooms | No | Rooms (izby), residential units only; multi-select ('8plus' = 8 or more). Rows with no count drop out unless 'unknown' is listed. | |
| teryt | No | TERYT code(s), comma-separated, max 10: 2-digit (voivodeship), 4 (county), 6 (municipality) or a precinct code (e.g. '321705_2.0054'). Find codes with list_locations. Exact - avoids name ambiguity. | |
| dateTo | No | End date (YYYY-MM-DD) | |
| street | No | Street name, matched anywhere inside the name. Give the NOMINATIVE with Polish diacritics - matching is literal ('Karmelickiej' does not find 'Karmelicka'); a miss looks exactly like 'no such transactions'. | |
| landUse | No | Land-use category, multi-select, case-sensitive (gruntyZabudowaneIZurbanizowane = built-up, gruntyRolne = agricultural, gruntyLesne = forest, terenyKomunikacyjne = transport); 'unknown' = none recorded (NULL), not 'no use'. | |
| maxArea | No | Maximum area in m² | |
| minArea | No | Minimum area in m² | |
| dateFrom | No | Start date (YYYY-MM-DD) | |
| location | No | City (e.g. 'Warszawa') or RCN district (e.g. 'Mokotów', 'Kraków-Podgórze'); 'Warszawa', 'Kraków', 'Łódź' expand to all sub-districts. Prefer teryt=; confirm a name with list_locations(search=...) (valid ones are flagged rcn_district). | |
| maxPrice | No | Maximum price in PLN | |
| minPrice | No | Minimum price in PLN | |
| parcelId | No | Exact parcel ID, copied from a search result's parcel_id field (e.g. '146518_8.0108.27'). | |
| floodRisk | No | Flood-hazard zone, multi-select: high ~1-in-10-year, medium ~1-in-100, low ~1-in-500. Mapped zones only; absence of a zone is never 'safe'. | |
| marketType | No | primary (developer) or secondary (resale); the ~55% of records with no market type drop out when this is set. | |
| summaryOnly | No | Return only aggregate stats (total, median price/m² with its sample size, period) and no rows. Costs only the summary call; limit/sort/page are ignored. | |
| buildingType | No | Building type (PKOB); 'unknown' = none recorded (NULL, ~39% of buildings), any other value excludes such rows. | |
| propertyType | No | Property type filter | |
| unitFunction | No | Unit function; 'unknown' = none recorded (NULL), any other value excludes such rows. Garages only via 'garage'. | |
| landslideRisk | No | Landslide hazard, multi-select: landslide = mapped landslide area; threatened = area threatened by mass movements. Mapped areas only; absence of a zone is never 'safe'. | |
| ownershipType | No | Legal-right type (rodzaj prawa), multi-select; perpetual_usufruct = użytkowanie wieczyste; 'unknown' = none recorded. | |
| buildingNumber | No | Building/house number (e.g. '30', '12A'). Requires location or street. | |
| heritageStatus | No | Heritage listing, multi-select: listed = protected monument on the land; zone = protected urban layout or monument surroundings. Detected listings only; absence of a detection is never 'not listed'. | |
| buildingStoreys | No | Above-ground storeys, multi-select: integers, 'Nplus' ('3plus' = 3+), 'unknown' (no count). Single-building deeds only, so 'unknown' also covers multi-building deeds. Not the unit floor; rows with no count drop out unless 'unknown' is listed. | |
| mpzpDesignation | No | MPZP zoning designation, exact token match; comma-separated = OR (e.g. 'MN,MW'). 'unknown' = none recorded (NULL), distinct from the code 'brakMPZPLubWZ' (no plan/WZ). Known codes: budownictwoMieszkanioweJednorodzinne, brakMPZPLubWZ, terenRolniczy, innyNiewymieniony, terenZabudowyUslugowej, terenDrogWewnetrznych, terenDrogPublicznych, terenZabudowyZagrodowejGospodarstwRolnych, budownictwoMieszkanioweWielorodzinne, las, terenObiektowProdukcyjnychSkladowIMagazynow, terenSportuIRekreacji, decyzjaWarunkiZabudowy, terenZieleniUrzadzonej, terenZieleniObjetyFormaOchronyPrzyrody, terenWodPowierzchniowychSrodladowych, obszarITerenGorniczy, terenObslugiProdukcjiWGospodarstwachRolnych, terenInfrastrukturyTechnicznej, terenOgrodowDzialkowych, terenRozmieszczeniaDuzcychObiektowHandlowych, cmentarz, terenKomunikacjiWodnejSzlakWodny, terenWodPowierzchniowychMorskich, MN, BP, KD, U, INN, MW, KDW, R, ZP, P, WZ, ZN, WS, UC, ZL, ZD, US, TIT. An unrecognised value is still sent, with a warning. | |
| transactionType | No | Multi-select. For market analysis ALWAYS set it to exclude non-market deeds (subsidized, foreclosure, public_purpose); no-type rows (~2%) drop out unless 'unknown' is listed. | |
| maxFootprintArea | No | Maximum building footprint in m², summed over the transaction's buildings; measured rows only (absence = 'not measured', not 'no building'). Not usable area. | |
| minFootprintArea | No | Minimum building footprint in m², summed over the transaction's buildings; measured rows only (absence = 'not measured', not 'no building'). Not usable area. | |
| excludeFractionalShares | No | true = clean land prices: drops fractional ownership shares, whose price reflects the whole deed. Default false. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the read-only safety profile, but the description adds crucial behavioral context: silent zero-row failures when location names aren't RCN districts, literal street matching where a miss looks like 'no transactions', null-rate caveats for marketType and transaction_date, and interpretation of inline [...] notes for computed values. These are non-obvious traits that materially affect correct invocation.
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?
The description is long but information-dense and front-loads the core capability before moving to workflow, data caveats, and permalink construction. There is some redundancy with the schema's own parameter descriptions (e.g., street matching, marketType nulls), which a stricter version could trim, but little is wasted.
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 33-parameter, zero-required tool with no output schema, the description is remarkably complete: it states what fields are returned, explains the mandatory location-resolution workflow, discloses major data gaps, and even gives the permalink template for linking to a result. An agent has everything needed to avoid common failure modes.
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 100% with rich per-parameter descriptions, so the baseline is 3. The description still adds value by framing teryt= as the preferred exact-match routing parameter after list_locations, and by highlighting that location= is only for rcn_district values. Some notes (street nominative form, marketType null drop) duplicate schema text, keeping this from a 5.
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 ('Find'), resource ('individual Polish real-estate transactions'), and scope (national RCN registry, 8M+ notarial deeds, not asking prices). It also lists the filterable dimensions and distinguishes the data source from asking-price sources, making it immediately clear how this differs from sibling search tools.
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?
Explicitly prescribes the prerequisite workflow: resolve place with list_locations, then pass its TERYT code as teryt=. It warns that location= only works for RCN districts and that other names silently return zero rows, and routes neighborhood searches to search_by_area. This is exactly the when/when-not/alternatives guidance an agent needs.
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.
29 tool updates
v0.18.0- Changed
compare_locations10 fields changed- changed
Input schema / properties / buildingType / descriptionPrevious value: -"Building type filter (PKOB classification). 'unknown' = no type recorded (NULL); without it such rows are excluded (~39% of buildings have no type)."New value: +"Building type (PKOB); 'unknown' = none recorded (NULL, ~39% of buildings), any other value excludes such rows." - changed
Input schema / properties / districts / descriptionPrevious value: -"Comma-separated district names to compare (2-5, must be unique). E.g. 'Mokotów,Wola,Ursynów'"New value: +"Comma-separated district names (2-5, unique), e.g. 'Mokotów,Wola,Ursynów'" - changed
Input schema / properties / floor / descriptionPrevious value: -"Floor of the unit (piętro lokalu, residential). Multi-select buckets: exact integers incl. '0' (parter) and negatives e.g. '-1' (basement), 'Nplus' e.g. '10plus' = 10 or more, '0plus' = ground and above, 'unknown' = no floor recorded (NULL). E.g. ['0','1','2'] for ground-to-2nd floor. Building storeys are a different attribute. Without 'unknown', rows with no floor are excluded."New value: +"Unit floor, multi-select: integers ('0' = parter, negatives = basement), 'Nplus' ('0plus' = ground and above), 'unknown' (none recorded). Not building storeys; rows with no floor drop out unless 'unknown' is listed." - changed
Input schema / properties / includeDemographics / descriptionPrevious value: -"Add a GUS BDL demographics block per district (county-level: population density, wages, unemployment, median age, plus a few cross-source ratios like price-to-income). Districts that don't resolve to a county are omitted from the demographics section."New value: +"Add a GUS BDL demographics block per district (county-level: density, wages, unemployment, median age, price-to-income). Districts that do not resolve to a county are omitted from it." - changed
Input schema / properties / marketType / descriptionPrevious value: -"Market type filter"New value: +"primary (developer) or secondary (resale); the ~55% of records with no market type drop out when this is set." - changed
Input schema / properties / mpzpDesignation / descriptionPrevious value: -"MPZP zoning designation prefix filter (e.g. 'terenRolniczy', 'budownictwoMieszkanioweJednorodzinne', 'budownictwoMieszkanioweWielorodzinne'). Use 'unknown' for rows with no designation recorded (NULL); distinct from the registry code 'brakMPZPLubWZ'."New value: +"MPZP zoning designation, exact token match; comma-separated = OR; 'unknown' = none recorded. Same codes as search_transactions mpzpDesignation." - changed
Input schema / properties / ownershipType / descriptionPrevious value: -"Ownership / legal-right type filter (rodzaj prawa do nieruchomości). land_ownership; perpetual_usufruct (użytkowanie wieczyste — covers both registry codes for this right); cooperative_ownership; unit_sale; ownership; unit_ownership_with_appurtenant_right; building_ownership_with_appurtenant_right. 'unknown' = no right recorded (NULL). Multi-select; e.g. ['land_ownership','perpetual_usufruct'] to compare ownership vs perpetual usufruct on undeveloped land."New value: +"Legal-right type (rodzaj prawa), multi-select; perpetual_usufruct = użytkowanie wieczyste; 'unknown' = none recorded." - changed
Input schema / properties / rooms / descriptionPrevious value: -"Number of rooms (izby) filter, residential units only. Multi-select; '8plus' means 8 or more, 'unknown' = no room count recorded (NULL). E.g. ['2','3'] for 2-3 izby flats. Without 'unknown', rows with no room count are excluded."New value: +"Rooms (izby), residential units only; multi-select ('8plus' = 8 or more). Rows with no count drop out unless 'unknown' is listed." - changed
Input schema / properties / transactionType / descriptionPrevious value: -"Transaction type filter. For market analysis, ALWAYS specify to exclude non-market transactions."New value: +"Multi-select. For market analysis ALWAYS set it to exclude non-market deeds (subsidized, foreclosure, public_purpose); no-type rows (~2%) drop out unless 'unknown' is listed." - changed
Input schema / properties / unitFunction / descriptionPrevious value: -"Unit/apartment function filter. 'unknown' = no function recorded (NULL); without it such rows are excluded. Garages appear only when 'garage' is selected, not via 'unknown'."New value: +"Unit function; 'unknown' = none recorded (NULL), any other value excludes such rows. Garages only via 'garage'."
- Added
estimate_land_value - Changed
estimate_value7 fields changed- changed
Input schema / properties / area / descriptionPrevious value: -"Apartment usable area in m² (REQUIRED, 10–250). Estimates for 300+ m² are unreliable and rejected."New value: +"Apartment usable area in m² (REQUIRED, 10–250)." - changed
Input schema / properties / includeComps / descriptionPrevious value: -"Echo the nearest comparables the estimate weighed (default true). Set false for the estimate only."New value: +"Echo the comparables weighed (default true); false = estimate only." - changed
Input schema / properties / lat / descriptionPrevious value: -"Latitude of the apartment (WGS84, Poland). Must be paired with lng. Use this OR parcelId."New value: +"Latitude of the apartment (WGS84, Poland); pair with lng. Use this OR parcelId." - changed
Input schema / properties / lng / descriptionPrevious value: -"Longitude of the apartment (WGS84, Poland). Must be paired with lat. Use this OR parcelId."New value: +"Longitude of the apartment (WGS84, Poland); pair with lat. Use this OR parcelId." - changed
Input schema / properties / market / descriptionPrevious value: -"Restrict comparables to the primary (new-build) or secondary market (optional)."New value: +"Restrict comparables to the primary (new-build) or secondary market." - changed
Input schema / properties / parcelId / descriptionPrevious value: -"Full cadastral id (slash or dash form) or internal UUID; the parcel centroid is used. Use instead of lat/lng."New value: +"Full cadastral id (slash or dash form) or internal UUID; the parcel centroid is used. Instead of lat/lng." - changed
Input schema / properties / rooms / descriptionPrevious value: -"Room count (1–10, optional) — narrows the comparables to ±1 room."New value: +"Room count (1–10); narrows comparables to ±1 room."
- Changed
get_building_breakdown3 fields changed- added
Input schema / properties / transactionIdAdded value: +{ + "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", + "type": "string" +} - changed
Input schema / properties / transaction_id / descriptionPrevious value: -"Transaction id (UUID) from a search_transactions / search_by_area / search_by_polygon result that carries building data."New value: +"Transaction id (UUID) from a search result that carries building data. This or transactionId is required." - removed
Input schema / requiredRemoved value: -[ - "transaction_id" -]
- Changed
get_demographics4 fields changed- changed
Input schema / properties / category / descriptionPrevious value: -"Filter to these categories. Omit to return all available."New value: +"Categories to return; omit for all." - changed
Input schema / properties / location / descriptionPrevious value: -"City, county, or district name (e.g. 'Warszawa', 'Kraków'). A city/county name resolves to county/powiat level; a Warszawa district name (e.g. 'Mokotów') resolves to that district, another city's delegatura (e.g. 'Kraków-Podgórze') to its parent county. Use this OR teryt. For gmina-level data on other units pass a 6/7-digit teryt instead."New value: +"City, county, gmina or district name (e.g. 'Warszawa', 'Wieliczka'): city/county → county level, gmina → that gmina, a Warszawa district ('Mokotów') → that district, another city's delegatura ('Kraków-Podgórze') → its parent county. Shared name → candidates; pass one as teryt. Use this OR teryt." - changed
Input schema / properties / teryt / descriptionPrevious value: -"TERYT code: 2-digit (voivodeship, e.g. 14), 4-digit (county, e.g. 1465), 6 or 7-digit (gmina, e.g. 1465011). The 7th digit selects the unit type: 3 = urban-rural gmina overall, 4/5 = urban/rural part only, 8 = Warszawa district (1465011 = all of Warszawa, 1465108 = Śródmieście). Wins over location. Use list_locations to find codes."New value: +"TERYT: 2-digit voivodeship (14), 4 county (1465), 6 or 7 gmina (1465011). 7th digit: 3 = urban-rural gmina overall, 4/5 = urban/rural part only, 8 = Warszawa district (1465108 = Śródmieście). Wins over location." - changed
Input schema / properties / year / descriptionPrevious value: -"Single year (2003-present). Mutually exclusive with yearFrom/yearTo. Omit for the latest available year per indicator."New value: +"Single year (2003-present); exclusive with yearFrom/yearTo. Omit for the latest year per indicator."
- Changed
get_infrastructure_signals1 field changed- changed
Input schema / properties / location / descriptionPrevious value: -"City, county, or district name (e.g. 'Warszawa', 'Krotoszyn'). A city/county name aggregates every municipality in the county; a Warszawa district name (e.g. 'Mokotów') narrows to that gmina, another city's delegatura (e.g. 'Kraków-Podgórze') resolves to its parent county. Use this OR teryt."New value: +"City, county, gmina or district name (e.g. 'Warszawa', 'Krotoszyn'): city/county → every municipality in the county, gmina → that gmina alone, a Warszawa district ('Mokotów') → that gmina, another city's delegatura ('Kraków-Podgórze') → its parent county. Shared name → candidates; pass one as teryt. Use this OR teryt."
- Changed
get_parcel_land_class1 field changed- changed
Input schema / properties / parcelId / descriptionPrevious value: -"Full cadastral id ('142907_2.0014.342/5' or the '-' form) or the internal UUID from a search/resolve result."New value: +"Full cadastral id ('142907_2.0014.342/5' or the '-' form) or internal UUID."
- Changed
get_parcel_report1 field changed- changed
Input schema / properties / parcelId / descriptionPrevious value: -"Full cadastral id ('142907_2.0014.342/5' or the '-' form) or the internal UUID from a search/resolve result."New value: +"Full cadastral id ('142907_2.0014.342/5' or the '-' form) or internal UUID."
- Added
get_permits_in_area - Changed
get_price_distribution2 fields changed- added
Input schema / properties / locationAdded value: +{ + "description": "Ignored: histogram is national.", + "type": "string" +} - added
Input schema / properties / terytAdded value: +{ + "description": "Ignored: histogram is national.", + "type": "string" +}
- Changed
get_price_statistics4 fields changed- added
Input schema / properties / dateFromAdded value: +{ + "description": "Custom window start, YYYY-MM-DD. Overrides period.", + "pattern": "^\\d{4}-\\d{2}-\\d{2}$", + "type": "string" +} - added
Input schema / properties / dateToAdded value: +{ + "description": "Custom window end, YYYY-MM-DD, inclusive (default today). Overrides period.", + "pattern": "^\\d{4}-\\d{2}-\\d{2}$", + "type": "string" +} - changed
Input schema / properties / location / descriptionPrevious value: -"Filter by location name. 'Warszawa'/'Kraków'/'Łódź' auto-expand to all sub-districts. Other names use case-insensitive partial match (e.g. 'Wrocł' matches 'Wrocław'). Omit for all Poland."New value: +"Location name; 'Warszawa'/'Kraków'/'Łódź' expand to all sub-districts, other names use case-insensitive partial match (e.g. 'Wrocł' matches 'Wrocław'). Omit for all Poland." - added
Input schema / properties / periodAdded value: +{ + "description": "Window: \"24m\" (default) = last 24 months, \"all\" = full history. Ignored when dateFrom or dateTo is set.", + "enum": [ + "24m", + "all" + ], + "type": "string" +}
- Changed
get_transaction_farmland3 fields changed- added
Input schema / properties / transactionIdAdded value: +{ + "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", + "type": "string" +} - changed
Input schema / properties / transaction_id / descriptionPrevious value: -"Transaction id (UUID) from a search_transactions / search_by_area / search_by_polygon result."New value: +"Transaction id (UUID) from a search result. This or transactionId is required." - removed
Input schema / requiredRemoved value: -[ - "transaction_id" -]
- Changed
get_transaction_flood3 fields changed- added
Input schema / properties / transactionIdAdded value: +{ + "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", + "type": "string" +} - changed
Input schema / properties / transaction_id / descriptionPrevious value: -"Transaction id (UUID) from a search_transactions / search_by_area / search_by_polygon result."New value: +"Transaction id (UUID) from a search result. This or transactionId is required." - removed
Input schema / requiredRemoved value: -[ - "transaction_id" -]
- Changed
get_transaction_heritage3 fields changed- added
Input schema / properties / transactionIdAdded value: +{ + "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", + "type": "string" +} - changed
Input schema / properties / transaction_id / descriptionPrevious value: -"Transaction id (UUID) from a search_transactions / search_by_area / search_by_polygon result."New value: +"Transaction id (UUID) from a search result. This or transactionId is required." - removed
Input schema / requiredRemoved value: -[ - "transaction_id" -]
- Changed
get_transaction_landslide3 fields changed- added
Input schema / properties / transactionIdAdded value: +{ + "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", + "type": "string" +} - changed
Input schema / properties / transaction_id / descriptionPrevious value: -"Transaction id (UUID) from a search_transactions / search_by_area / search_by_polygon result."New value: +"Transaction id (UUID) from a search result. This or transactionId is required." - removed
Input schema / requiredRemoved value: -[ - "transaction_id" -]
- Changed
get_transaction_nature3 fields changed- added
Input schema / properties / transactionIdAdded value: +{ + "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", + "type": "string" +} - changed
Input schema / properties / transaction_id / descriptionPrevious value: -"Transaction id (UUID) from a search_transactions / search_by_area / search_by_polygon result."New value: +"Transaction id (UUID) from a search result. This or transactionId is required." - removed
Input schema / requiredRemoved value: -[ - "transaction_id" -]
- Changed
get_transaction_permits3 fields changed- added
Input schema / properties / transactionIdAdded value: +{ + "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", + "type": "string" +} - changed
Input schema / properties / transaction_id / descriptionPrevious value: -"Transaction id (UUID) from a search_transactions / search_by_area / search_by_polygon result."New value: +"Transaction id (UUID) from a search result. This or transactionId is required." - removed
Input schema / requiredRemoved value: -[ - "transaction_id" -]
- Changed
get_transaction_planning3 fields changed- added
Input schema / properties / transactionIdAdded value: +{ + "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", + "type": "string" +} - changed
Input schema / properties / transaction_id / descriptionPrevious value: -"Transaction id (UUID) from a search_transactions / search_by_area / search_by_polygon result."New value: +"Transaction id (UUID) from a search result. This or transactionId is required." - removed
Input schema / requiredRemoved value: -[ - "transaction_id" -]
- Changed
get_transaction_roads3 fields changed- added
Input schema / properties / transactionIdAdded value: +{ + "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", + "type": "string" +} - changed
Input schema / properties / transaction_id / descriptionPrevious value: -"Transaction id (UUID) from a search_transactions / search_by_area / search_by_polygon result."New value: +"Transaction id (UUID) from a search result. This or transactionId is required." - removed
Input schema / requiredRemoved value: -[ - "transaction_id" -]
- Changed
get_transaction_subsurface3 fields changed- added
Input schema / properties / transactionIdAdded value: +{ + "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", + "type": "string" +} - changed
Input schema / properties / transaction_id / descriptionPrevious value: -"Transaction id (UUID) from a search_transactions / search_by_area / search_by_polygon result."New value: +"Transaction id (UUID) from a search result. This or transactionId is required." - removed
Input schema / requiredRemoved value: -[ - "transaction_id" -]
- Changed
get_transaction_surroundings3 fields changed- added
Input schema / properties / transactionIdAdded value: +{ + "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", + "type": "string" +} - changed
Input schema / properties / transaction_id / descriptionPrevious value: -"Transaction id (UUID) from a search_transactions / search_by_area / search_by_polygon result."New value: +"Transaction id (UUID) from a search result. This or transactionId is required." - removed
Input schema / requiredRemoved value: -[ - "transaction_id" -]
- Changed
get_transaction_transit3 fields changed- added
Input schema / properties / transactionIdAdded value: +{ + "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", + "type": "string" +} - changed
Input schema / properties / transaction_id / descriptionPrevious value: -"Transaction id (UUID) from a search_transactions / search_by_area / search_by_polygon result."New value: +"Transaction id (UUID) from a search result. This or transactionId is required." - removed
Input schema / requiredRemoved value: -[ - "transaction_id" -]
- Changed
list_locations2 fields changed- changed
Input schema / properties / parent / descriptionPrevious value: -"TERYT parent code to browse children. 2-digit (voivodeship → counties), 4-digit (county → municipalities), 6-digit (municipality → precincts). Omit for all voivodeships."New value: +"TERYT parent code to browse children: 2-digit (voivodeship → counties), 4-digit (county → municipalities), 6-digit (municipality → precincts). Omit for all voivodeships." - changed
Input schema / properties / search / descriptionPrevious value: -"Look up a place by name (case-insensitive, diacritics-insensitive partial match, e.g. 'wejher' for Wejherowo). Returns TERYT codes plus, where applicable, RCN district names. Ignored when parent is set."New value: +"Place name, case- and diacritics-insensitive partial match (e.g. 'wejher' for Wejherowo). Returns TERYT codes plus, where applicable, RCN district names. Ignored when parent is set."
- Changed
list_parcels_in_area13 fields changed- changed
Input schema / properties / bbox / descriptionPrevious value: -"Bounding box in WGS84 as \"minLng,minLat,maxLng,maxLat\", covering at most 500 km². Required for includeGeometry=true."New value: +"Bounding box \"minLng,minLat,maxLng,maxLat\" (WGS84), at most 500 km². Required for includeGeometry=true." - changed
Input schema / properties / buildingNumber / descriptionPrevious value: -"Building number. Against the record the match is exact ('12A' does not find '12a') and RCN numbering is often compound ('84/92'), so an exact '84' misses '84/92'. When that comes back empty, the same number is tried against official address points instead, case-insensitively ('12a' finds '12A') but still exact, matching the street by the same whole-word rule as street, not a fragment — if that also misses, drop the number and read the numbers off the street's rows. Requires street. Same scope requirement as street."New value: +"Building number, exact; needs street, same scope requirement. If nothing is found, drop the number and read the numbers off the street's rows." - changed
Input schema / properties / cursor / descriptionPrevious value: -"Opaque cursor from the previous light-list answer, to get the next page. Pass it back unchanged; it is not available on outline calls."New value: +"Opaque cursor from the previous light-list answer, for the next page; pass it back unchanged. Not available on outline calls." - changed
Input schema / properties / includeGeometry / descriptionPrevious value: -"Return each parcel's full outline instead of the light row (5 tokens instead of 2, at most 100 parcels, no paging). Requires a bbox; with a polygon the outlines come back anyway."New value: +"Return full outlines instead of the light row (5 tokens instead of 2). Requires a bbox; with a polygon outlines come back anyway." - changed
Input schema / properties / lat / descriptionPrevious value: -"Latitude of the circle centre (WGS84). Requires lng and radiusKm."New value: +"Circle centre latitude (WGS84). Needs lng and radiusKm." - changed
Input schema / properties / limit / descriptionPrevious value: -"Max parcels returned. Light list: up to 1000, default 250. Outlines: up to 100, default 50 — a larger value is clamped there."New value: +"Max parcels. Light list: up to 1000, default 250. Outlines: up to 100, default 50." - changed
Input schema / properties / lng / descriptionPrevious value: -"Longitude of the circle centre (WGS84). Requires lat and radiusKm."New value: +"Circle centre longitude (WGS84). Needs lat and radiusKm." - changed
Input schema / properties / location / descriptionPrevious value: -"County, city, or district name, resolved to its TERYT code. A Warszawa district name (e.g. 'Mokotów') narrows to that district; another city's delegatura (e.g. 'Kraków-Podgórze') resolves to its parent county. An ambiguous name is an error listing the candidates."New value: +"County, city, gmina or district name, resolved to its TERYT code ('Mokotów' = that Warszawa district; 'Kraków-Podgórze' = its parent county; a gmina name answers at municipality level)." - changed
Input schema / properties / minArea / descriptionPrevious value: -"Minimum parcel surface in m². Needs a bbox, a circle, a location name, or a teryt of at least 4 digits. Not available with includeGeometry or a polygon."New value: +"Minimum parcel surface in m². Needs a narrow scope; not with includeGeometry or a polygon." - changed
Input schema / properties / polygon / descriptionPrevious value: -"GeoJSON Polygon geometry. Coordinates: [longitude, latitude] pairs, first and last point identical, at most 500 vertices. Always returns outlines. Pass it instead of the other area parameters, not alongside them."New value: +"GeoJSON Polygon: [longitude, latitude] pairs, first and last point identical, max 500 vertices. Always returns outlines. Pass it instead of the other area parameters." - changed
Input schema / properties / radiusKm / descriptionPrevious value: -"Circle radius in km (max 12.6 — the radius covering the 500 km² ceiling). Requires lat and lng."New value: +"Circle radius in km (max 12.6, the radius covering 500 km²). Needs lat and lng." - changed
Input schema / properties / street / descriptionPrevious value: -"Street name, matched by whole words within the name, case- and accent-insensitively (min 4 letters or digits): 'Górna' finds 'ulica Górna' and 'Górna 15' but not 'Podgórna', and a fragment like 'Marsza' finds nothing. NOMINATIVE: 'Karmelickiej' does not fold to 'Karmelicka' and answers empty. Needs a bbox, a circle, a location name, or a teryt of at least 4 digits. Not available with includeGeometry or a polygon."New value: +"Street name in the NOMINATIVE (min 4 letters or digits). Needs a bbox, a circle, a location name, or a teryt of at least 4 digits; not with includeGeometry or a polygon." - changed
Input schema / properties / teryt / descriptionPrevious value: -"TERYT administrative code prefix (2/4/6 digits or finer), comma-separated for several. Wins over location when both are given."New value: +"TERYT code prefix (2/4/6 digits or finer), comma-separated for several. Wins over location."
- Changed
resolve_parcel4 fields changed- changed
Input schema / properties / lat / descriptionPrevious value: -"Latitude WGS84. Must be paired with lng. Mutually exclusive with q and parcelId."New value: +"Latitude WGS84; pair with lng. Exclusive with q and parcelId." - changed
Input schema / properties / lng / descriptionPrevious value: -"Longitude WGS84. Must be paired with lat. Mutually exclusive with q and parcelId."New value: +"Longitude WGS84; pair with lat. Exclusive with q and parcelId." - changed
Input schema / properties / parcelId / descriptionPrevious value: -"Full cadastral id (slash or dash form) or internal UUID. Mutually exclusive with q and lat/lng."New value: +"Full cadastral id (slash or dash form) or internal UUID. Exclusive with q and lat/lng." - changed
Input schema / properties / q / descriptionPrevious value: -"Full cadastral id, a UUID, or 'locality name + parcel number' (e.g. 'Sabnie 342/5') — the name may be a gmina or a cadastral precinct (obręb). NOT a street address: for a street + building number use list_parcels_in_area instead. Mutually exclusive with parcelId and lat/lng."New value: +"Full cadastral id, UUID, or 'locality name + parcel number' (e.g. 'Sabnie 342/5'); not a street address. Exclusive with parcelId and lat/lng."
- Changed
search_by_area20 fields changed- changed
Input schema / properties / buildingStoreys / descriptionPrevious value: -"Number of above-ground storeys of the building. Multi-select buckets: exact non-negative integers (e.g. '1','2'), 'Nplus' e.g. '3plus' = 3 or more, 'unknown' = no storey count recorded (NULL). Recorded ONLY for single-building transactions, so 'unknown' covers BOTH a deed with several buildings (no single storey count exists) and a single building with missing data — never read it as 'a building with no storeys'. This is NOT the floor of a unit (see floor). Without 'unknown', rows with no storey count are excluded."New value: +"Above-ground storeys, multi-select: integers, 'Nplus' ('3plus' = 3+), 'unknown' (no count). Single-building deeds only, so 'unknown' also covers multi-building deeds. Not the unit floor; rows with no count drop out unless 'unknown' is listed." - changed
Input schema / properties / buildingType / descriptionPrevious value: -"Building type filter (PKOB classification). 'unknown' = no type recorded (NULL); without it such rows are excluded (~39% of buildings have no type)."New value: +"Building type (PKOB); 'unknown' = none recorded (NULL, ~39% of buildings), any other value excludes such rows." - added
Input schema / properties / excludeFractionalSharesAdded value: +{ + "default": false, + "description": "true = clean land prices: drops fractional ownership shares, whose price reflects the whole deed. Default false.", + "type": "boolean" +} - changed
Input schema / properties / floodRisk / descriptionPrevious value: -"Flood-hazard filter. high = most frequent flooding (~1-in-10-year), medium (~1-in-100-year), low = rarest (~1-in-500-year). Selects ONLY transactions whose land sits in a mapped flood zone; absence of a zone is never asserted as 'safe'. Multi-select; e.g. ['medium','high'] = at least medium risk."New value: +"Flood-hazard zone, multi-select: high ~1-in-10-year, medium ~1-in-100, low ~1-in-500. Mapped zones only; absence of a zone is never 'safe'." - changed
Input schema / properties / floor / descriptionPrevious value: -"Floor of the unit (piętro lokalu, residential). Multi-select buckets: exact integers incl. '0' (parter) and negatives e.g. '-1' (basement), 'Nplus' e.g. '10plus' = 10 or more, '0plus' = ground and above, 'unknown' = no floor recorded (NULL). E.g. ['0','1','2'] for ground-to-2nd floor. Building storeys are a different attribute. Without 'unknown', rows with no floor are excluded."New value: +"Unit floor, multi-select: integers ('0' = parter, negatives = basement), 'Nplus' ('0plus' = ground and above), 'unknown' (none recorded). Not building storeys; rows with no floor drop out unless 'unknown' is listed." - changed
Input schema / properties / heritageStatus / descriptionPrevious value: -"Heritage-listing filter. listed = a protected monument on/at the property's land; zone = the land lies within a protected urban layout or the designated surroundings of a monument. Selects ONLY transactions where a listing was detected; absence of a detection is never asserted as 'not listed'. Multi-select; e.g. ['listed'] = individually listed properties only."New value: +"Heritage listing, multi-select: listed = protected monument on the land; zone = protected urban layout or monument surroundings. Detected listings only; absence of a detection is never 'not listed'." - changed
Input schema / properties / landUse / descriptionPrevious value: -"Recorded land-use category of the transaction's land. Multi-select from: gruntyZabudowaneIZurbanizowane (built-up and urbanised), gruntyRolne (agricultural), gruntyLesne (forest), terenyKomunikacyjne (transport), inne (other). 'unknown' = no category recorded for the land (NULL) — a legitimate bucket, never a claim that the land has no use. Values are case-sensitive. E.g. ['gruntyRolne'] for farmland, or ['gruntyZabudowaneIZurbanizowane','gruntyRolne'] to compare developed vs farmland."New value: +"Land-use category, multi-select, case-sensitive (gruntyZabudowaneIZurbanizowane = built-up, gruntyRolne = agricultural, gruntyLesne = forest, terenyKomunikacyjne = transport); 'unknown' = none recorded (NULL), not 'no use'." - changed
Input schema / properties / landslideRisk / descriptionPrevious value: -"Landslide-hazard filter, from official landslide-hazard maps (1:10,000 scale). 'landslide' = the land intersects a mapped landslide area; 'threatened' = an area threatened by mass movements. Selects ONLY transactions whose land intersects a mapped hazard area — an intersection means overlap with a mapped area, not that the parcel itself is a landslide; absence of a zone is never asserted as 'safe'. Multi-select; e.g. ['landslide','threatened'] = any mapped hazard."New value: +"Landslide hazard, multi-select: landslide = mapped landslide area; threatened = area threatened by mass movements. Mapped areas only; absence of a zone is never 'safe'." - changed
Input schema / properties / marketType / descriptionPrevious value: -"Market type: primary (developer) or secondary (resale). ~55% of records have unknown market type and will be excluded when this filter is used."New value: +"primary (developer) or secondary (resale); the ~55% of records with no market type drop out when this is set." - changed
Input schema / properties / maxFootprintArea / descriptionPrevious value: -"Maximum building footprint (ground-plan) area in m², summed over all buildings of the transaction. Distinct from maxArea, which measures usable floor area (units) or land/parcel area. Set only where every linked building has footprint data, so this bound selects only measured rows — absence means 'not measured', not 'no building'."New value: +"Maximum building footprint in m², summed over the transaction's buildings; measured rows only (absence = 'not measured', not 'no building'). Not usable area." - changed
Input schema / properties / minArea / descriptionPrevious value: -"Minimum area in m² (usable_area_m2 for units, parcel_area for land)"New value: +"Minimum area in m² (usable area for units, parcel area for land)" - changed
Input schema / properties / minFootprintArea / descriptionPrevious value: -"Minimum building footprint (ground-plan) area in m², summed over all buildings of the transaction. Distinct from minArea, which measures usable floor area (units) or land/parcel area. Set only where every linked building has footprint data, so this bound selects only measured rows — absence means 'not measured', not 'no building'."New value: +"Minimum building footprint in m², summed over the transaction's buildings; measured rows only (absence = 'not measured', not 'no building'). Not usable area." - added
Input schema / properties / mpzpDesignationAdded value: +{ + "description": "MPZP zoning designation, exact token match; comma-separated = OR; 'unknown' = none recorded. Same codes as search_transactions mpzpDesignation.", + "type": "string" +} - changed
Input schema / properties / ownershipType / descriptionPrevious value: -"Ownership / legal-right type filter (rodzaj prawa do nieruchomości). land_ownership; perpetual_usufruct (użytkowanie wieczyste — covers both registry codes for this right); cooperative_ownership; unit_sale; ownership; unit_ownership_with_appurtenant_right; building_ownership_with_appurtenant_right. 'unknown' = no right recorded (NULL). Multi-select; e.g. ['land_ownership','perpetual_usufruct'] to compare ownership vs perpetual usufruct on undeveloped land."New value: +"Legal-right type (rodzaj prawa), multi-select; perpetual_usufruct = użytkowanie wieczyste; 'unknown' = none recorded." - added
Input schema / properties / pageAdded value: +{ + "description": "Page 1-10 (50 rows).", + "maximum": 10, + "minimum": 1, + "type": "integer" +} - changed
Input schema / properties / radiusKm / descriptionPrevious value: -"Search radius in km (0.1-50, default 2). Use 0.5-1 for neighborhoods, 0.3-0.5 for streets."New value: +"Search radius in km (0.1-50, default 2)." - changed
Input schema / properties / rooms / descriptionPrevious value: -"Number of rooms (izby) filter, residential units only. Multi-select; '8plus' means 8 or more, 'unknown' = no room count recorded (NULL). E.g. ['2','3'] for 2-3 izby flats. Without 'unknown', rows with no room count are excluded."New value: +"Rooms (izby), residential units only; multi-select ('8plus' = 8 or more). Rows with no count drop out unless 'unknown' is listed." - added
Input schema / properties / summaryOnlyAdded value: +{ + "description": "Return only aggregate stats (total, median price/m² with its sample size, period) and no rows. Costs only the summary call; limit/sort/page are ignored.", + "type": "boolean" +} - changed
Input schema / properties / transactionType / descriptionPrevious value: -"Transaction type filter. For market analysis, ALWAYS specify to exclude non-market transactions."New value: +"Multi-select. For market analysis ALWAYS set it to exclude non-market deeds (subsidized, foreclosure, public_purpose); no-type rows (~2%) drop out unless 'unknown' is listed." - changed
Input schema / properties / unitFunction / descriptionPrevious value: -"Unit/apartment function filter. 'unknown' = no function recorded (NULL); without it such rows are excluded. Garages appear only when 'garage' is selected, not via 'unknown'."New value: +"Unit function; 'unknown' = none recorded (NULL), any other value excludes such rows. Garages only via 'garage'."
- Changed
search_by_polygon16 fields changed- changed
Input schema / properties / buildingStoreys / descriptionPrevious value: -"Number of above-ground storeys of the building. Multi-select buckets: exact non-negative integers (e.g. '1','2'), 'Nplus' e.g. '3plus' = 3 or more, 'unknown' = no storey count recorded (NULL). Recorded ONLY for single-building transactions, so 'unknown' covers BOTH a deed with several buildings (no single storey count exists) and a single building with missing data — never read it as 'a building with no storeys'. This is NOT the floor of a unit (see floor). Without 'unknown', rows with no storey count are excluded."New value: +"Above-ground storeys, multi-select: integers, 'Nplus' ('3plus' = 3+), 'unknown' (no count). Single-building deeds only, so 'unknown' also covers multi-building deeds. Not the unit floor; rows with no count drop out unless 'unknown' is listed." - changed
Input schema / properties / buildingType / descriptionPrevious value: -"Building type filter (PKOB classification). 'unknown' = no type recorded (NULL); without it such rows are excluded (~39% of buildings have no type)."New value: +"Building type (PKOB); 'unknown' = none recorded (NULL, ~39% of buildings), any other value excludes such rows." - added
Input schema / properties / excludeFractionalSharesAdded value: +{ + "default": false, + "description": "true = clean land prices: drops fractional ownership shares, whose price reflects the whole deed. Default false.", + "type": "boolean" +} - changed
Input schema / properties / floor / descriptionPrevious value: -"Floor of the unit (piętro lokalu, residential). Multi-select buckets: exact integers incl. '0' (parter) and negatives e.g. '-1' (basement), 'Nplus' e.g. '10plus' = 10 or more, '0plus' = ground and above, 'unknown' = no floor recorded (NULL). E.g. ['0','1','2'] for ground-to-2nd floor. Building storeys are a different attribute. Without 'unknown', rows with no floor are excluded."New value: +"Unit floor, multi-select: integers ('0' = parter, negatives = basement), 'Nplus' ('0plus' = ground and above), 'unknown' (none recorded). Not building storeys; rows with no floor drop out unless 'unknown' is listed." - changed
Input schema / properties / landUse / descriptionPrevious value: -"Recorded land-use category of the transaction's land. Multi-select from: gruntyZabudowaneIZurbanizowane (built-up and urbanised), gruntyRolne (agricultural), gruntyLesne (forest), terenyKomunikacyjne (transport), inne (other). 'unknown' = no category recorded for the land (NULL) — a legitimate bucket, never a claim that the land has no use. Values are case-sensitive. E.g. ['gruntyRolne'] for farmland, or ['gruntyZabudowaneIZurbanizowane','gruntyRolne'] to compare developed vs farmland."New value: +"Land-use category, multi-select, case-sensitive (gruntyZabudowaneIZurbanizowane = built-up, gruntyRolne = agricultural, gruntyLesne = forest, terenyKomunikacyjne = transport); 'unknown' = none recorded (NULL), not 'no use'." - changed
Input schema / properties / limit / descriptionPrevious value: -"Max results (1-3000, default 100). MCP displays up to 50 transactions."New value: +"Max results (1-3000); 50 shown." - changed
Input schema / properties / marketType / descriptionPrevious value: -"Market type filter"New value: +"primary (developer) or secondary (resale); the ~55% of records with no market type drop out when this is set." - changed
Input schema / properties / maxFootprintArea / descriptionPrevious value: -"Maximum building footprint (ground-plan) area in m², summed over all buildings of the transaction. Distinct from maxArea, which measures usable floor area (units) or land/parcel area. Set only where every linked building has footprint data, so this bound selects only measured rows — absence means 'not measured', not 'no building'."New value: +"Maximum building footprint in m², summed over the transaction's buildings; measured rows only (absence = 'not measured', not 'no building'). Not usable area." - changed
Input schema / properties / minFootprintArea / descriptionPrevious value: -"Minimum building footprint (ground-plan) area in m², summed over all buildings of the transaction. Distinct from minArea, which measures usable floor area (units) or land/parcel area. Set only where every linked building has footprint data, so this bound selects only measured rows — absence means 'not measured', not 'no building'."New value: +"Minimum building footprint in m², summed over the transaction's buildings; measured rows only (absence = 'not measured', not 'no building'). Not usable area." - changed
Input schema / properties / mpzpDesignation / descriptionPrevious value: -"MPZP zoning designation filter (exact match). Use 'unknown' for rows with no designation recorded (NULL); distinct from the registry code 'brakMPZPLubWZ'."New value: +"MPZP zoning designation, exact token match; comma-separated = OR; 'unknown' = none recorded. Same codes as search_transactions mpzpDesignation." - changed
Input schema / properties / ownershipType / descriptionPrevious value: -"Ownership / legal-right type filter (rodzaj prawa do nieruchomości). land_ownership; perpetual_usufruct (użytkowanie wieczyste — covers both registry codes for this right); cooperative_ownership; unit_sale; ownership; unit_ownership_with_appurtenant_right; building_ownership_with_appurtenant_right. 'unknown' = no right recorded (NULL). Multi-select; e.g. ['land_ownership','perpetual_usufruct'] to compare ownership vs perpetual usufruct on undeveloped land."New value: +"Legal-right type (rodzaj prawa), multi-select; perpetual_usufruct = użytkowanie wieczyste; 'unknown' = none recorded." - added
Input schema / properties / pageAdded value: +{ + "description": "Page 1-20 (50 rows).", + "maximum": 20, + "minimum": 1, + "type": "integer" +} - changed
Input schema / properties / polygon / descriptionPrevious value: -"GeoJSON Polygon geometry. Coordinates: [longitude, latitude] pairs. First and last point must be identical. Max 500 vertices total."New value: +"GeoJSON Polygon: [longitude, latitude] pairs, first and last point identical, max 500 vertices total." - changed
Input schema / properties / rooms / descriptionPrevious value: -"Number of rooms (izby) filter, residential units only. Multi-select; '8plus' means 8 or more, 'unknown' = no room count recorded (NULL). E.g. ['2','3'] for 2-3 izby flats. Without 'unknown', rows with no room count are excluded."New value: +"Rooms (izby), residential units only; multi-select ('8plus' = 8 or more). Rows with no count drop out unless 'unknown' is listed." - changed
Input schema / properties / transactionType / descriptionPrevious value: -"Transaction type filter. For market analysis, ALWAYS specify to exclude non-market transactions."New value: +"Multi-select. For market analysis ALWAYS set it to exclude non-market deeds (subsidized, foreclosure, public_purpose); no-type rows (~2%) drop out unless 'unknown' is listed." - changed
Input schema / properties / unitFunction / descriptionPrevious value: -"Unit/apartment function filter. 'unknown' = no function recorded (NULL); without it such rows are excluded. Garages appear only when 'garage' is selected, not via 'unknown'."New value: +"Unit function; 'unknown' = none recorded (NULL), any other value excludes such rows. Garages only via 'garage'."
- Changed
search_parcels1 field changed- changed
Input schema / properties / q / descriptionPrevious value: -"Parcel ID prefix to search for (min 3 chars). E.g. '146518_8.01'"New value: +"Parcel ID prefix (min 3 chars), e.g. '146518_8.01'"
- Changed
search_transactions22 fields changed- changed
Input schema / properties / buildingNumber / descriptionPrevious value: -"Building/house number (e.g. '30', '12A'). Requires location or street to be set."New value: +"Building/house number (e.g. '30', '12A'). Requires location or street." - changed
Input schema / properties / buildingStoreys / descriptionPrevious value: -"Number of above-ground storeys of the building. Multi-select buckets: exact non-negative integers (e.g. '1','2'), 'Nplus' e.g. '3plus' = 3 or more, 'unknown' = no storey count recorded (NULL). Recorded ONLY for single-building transactions, so 'unknown' covers BOTH a deed with several buildings (no single storey count exists) and a single building with missing data — never read it as 'a building with no storeys'. This is NOT the floor of a unit (see floor). Without 'unknown', rows with no storey count are excluded."New value: +"Above-ground storeys, multi-select: integers, 'Nplus' ('3plus' = 3+), 'unknown' (no count). Single-building deeds only, so 'unknown' also covers multi-building deeds. Not the unit floor; rows with no count drop out unless 'unknown' is listed." - changed
Input schema / properties / buildingType / descriptionPrevious value: -"Building type filter (PKOB classification). 'unknown' = no type recorded (NULL); without it such rows are excluded (~39% of buildings have no type)."New value: +"Building type (PKOB); 'unknown' = none recorded (NULL, ~39% of buildings), any other value excludes such rows." - added
Input schema / properties / excludeFractionalSharesAdded value: +{ + "default": false, + "description": "true = clean land prices: drops fractional ownership shares, whose price reflects the whole deed. Default false.", + "type": "boolean" +} - changed
Input schema / properties / floodRisk / descriptionPrevious value: -"Flood-hazard filter. high = most frequent flooding (~1-in-10-year), medium (~1-in-100-year), low = rarest (~1-in-500-year). Selects ONLY transactions whose land sits in a mapped flood zone; absence of a zone is never asserted as 'safe'. Multi-select; e.g. ['medium','high'] = at least medium risk."New value: +"Flood-hazard zone, multi-select: high ~1-in-10-year, medium ~1-in-100, low ~1-in-500. Mapped zones only; absence of a zone is never 'safe'." - changed
Input schema / properties / floor / descriptionPrevious value: -"Floor of the unit (piętro lokalu, residential). Multi-select buckets: exact integers incl. '0' (parter) and negatives e.g. '-1' (basement), 'Nplus' e.g. '10plus' = 10 or more, '0plus' = ground and above, 'unknown' = no floor recorded (NULL). E.g. ['0','1','2'] for ground-to-2nd floor. Building storeys are a different attribute. Without 'unknown', rows with no floor are excluded."New value: +"Unit floor, multi-select: integers ('0' = parter, negatives = basement), 'Nplus' ('0plus' = ground and above), 'unknown' (none recorded). Not building storeys; rows with no floor drop out unless 'unknown' is listed." - changed
Input schema / properties / heritageStatus / descriptionPrevious value: -"Heritage-listing filter. listed = a protected monument on/at the property's land; zone = the land lies within a protected urban layout or the designated surroundings of a monument. Selects ONLY transactions where a listing was detected; absence of a detection is never asserted as 'not listed'. Multi-select; e.g. ['listed'] = individually listed properties only."New value: +"Heritage listing, multi-select: listed = protected monument on the land; zone = protected urban layout or monument surroundings. Detected listings only; absence of a detection is never 'not listed'." - changed
Input schema / properties / landUse / descriptionPrevious value: -"Recorded land-use category of the transaction's land. Multi-select from: gruntyZabudowaneIZurbanizowane (built-up and urbanised), gruntyRolne (agricultural), gruntyLesne (forest), terenyKomunikacyjne (transport), inne (other). 'unknown' = no category recorded for the land (NULL) — a legitimate bucket, never a claim that the land has no use. Values are case-sensitive. E.g. ['gruntyRolne'] for farmland, or ['gruntyZabudowaneIZurbanizowane','gruntyRolne'] to compare developed vs farmland."New value: +"Land-use category, multi-select, case-sensitive (gruntyZabudowaneIZurbanizowane = built-up, gruntyRolne = agricultural, gruntyLesne = forest, terenyKomunikacyjne = transport); 'unknown' = none recorded (NULL), not 'no use'." - changed
Input schema / properties / landslideRisk / descriptionPrevious value: -"Landslide-hazard filter, from official landslide-hazard maps (1:10,000 scale). 'landslide' = the land intersects a mapped landslide area; 'threatened' = an area threatened by mass movements. Selects ONLY transactions whose land intersects a mapped hazard area — an intersection means overlap with a mapped area, not that the parcel itself is a landslide; absence of a zone is never asserted as 'safe'. Multi-select; e.g. ['landslide','threatened'] = any mapped hazard."New value: +"Landslide hazard, multi-select: landslide = mapped landslide area; threatened = area threatened by mass movements. Mapped areas only; absence of a zone is never 'safe'." - changed
Input schema / properties / location / descriptionPrevious value: -"Location name - city (e.g. 'Warszawa', 'Kraków', 'Gdańsk') or district (e.g. 'Mokotów', 'Kraków-Podgórze'). 'Warszawa', 'Kraków', 'Łódź' auto-expand to all sub-districts. Prefer teryt= for exact matches; call list_locations(search=...) to confirm a name is valid here — it flags valid ones as rcn_district."New value: +"City (e.g. 'Warszawa') or RCN district (e.g. 'Mokotów', 'Kraków-Podgórze'); 'Warszawa', 'Kraków', 'Łódź' expand to all sub-districts. Prefer teryt=; confirm a name with list_locations(search=...) (valid ones are flagged rcn_district)." - changed
Input schema / properties / marketType / descriptionPrevious value: -"Market type: primary (developer) or secondary (resale). ~55% of records have unknown market type and will be excluded when this filter is used."New value: +"primary (developer) or secondary (resale); the ~55% of records with no market type drop out when this is set." - changed
Input schema / properties / maxFootprintArea / descriptionPrevious value: -"Maximum building footprint (ground-plan) area in m², summed over all buildings of the transaction. Distinct from maxArea, which measures usable floor area (units) or land/parcel area. Set only where every linked building has footprint data, so this bound selects only measured rows — absence means 'not measured', not 'no building'."New value: +"Maximum building footprint in m², summed over the transaction's buildings; measured rows only (absence = 'not measured', not 'no building'). Not usable area." - changed
Input schema / properties / minFootprintArea / descriptionPrevious value: -"Minimum building footprint (ground-plan) area in m², summed over all buildings of the transaction. Distinct from minArea, which measures usable floor area (units) or land/parcel area. Set only where every linked building has footprint data, so this bound selects only measured rows — absence means 'not measured', not 'no building'."New value: +"Minimum building footprint in m², summed over the transaction's buildings; measured rows only (absence = 'not measured', not 'no building'). Not usable area." - changed
Input schema / properties / mpzpDesignation / descriptionPrevious value: -"MPZP zoning designation filter (exact match, e.g. 'budownictwoMieszkanioweWielorodzinne', 'terenObiektowProdukcyjnychSkladowIMagazynow'). Use 'unknown' for rows with no designation recorded (NULL); distinct from the registry code 'brakMPZPLubWZ' (= 'no plan/WZ' recorded as data)."New value: +"MPZP zoning designation, exact token match; comma-separated = OR (e.g. 'MN,MW'). 'unknown' = none recorded (NULL), distinct from the code 'brakMPZPLubWZ' (no plan/WZ). Known codes: budownictwoMieszkanioweJednorodzinne, brakMPZPLubWZ, terenRolniczy, innyNiewymieniony, terenZabudowyUslugowej, terenDrogWewnetrznych, terenDrogPublicznych, terenZabudowyZagrodowejGospodarstwRolnych, budownictwoMieszkanioweWielorodzinne, las, terenObiektowProdukcyjnychSkladowIMagazynow, terenSportuIRekreacji, decyzjaWarunkiZabudowy, terenZieleniUrzadzonej, terenZieleniObjetyFormaOchronyPrzyrody, terenWodPowierzchniowychSrodladowych, obszarITerenGorniczy, terenObslugiProdukcjiWGospodarstwachRolnych, terenInfrastrukturyTechnicznej, terenOgrodowDzialkowych, terenRozmieszczeniaDuzcychObiektowHandlowych, cmentarz, terenKomunikacjiWodnejSzlakWodny, terenWodPowierzchniowychMorskich, MN, BP, KD, U, INN, MW, KDW, R, ZP, P, WZ, ZN, WS, UC, ZL, ZD, US, TIT. An unrecognised value is still sent, with a warning." - changed
Input schema / properties / ownershipType / descriptionPrevious value: -"Ownership / legal-right type filter (rodzaj prawa do nieruchomości). land_ownership; perpetual_usufruct (użytkowanie wieczyste — covers both registry codes for this right); cooperative_ownership; unit_sale; ownership; unit_ownership_with_appurtenant_right; building_ownership_with_appurtenant_right. 'unknown' = no right recorded (NULL). Multi-select; e.g. ['land_ownership','perpetual_usufruct'] to compare ownership vs perpetual usufruct on undeveloped land."New value: +"Legal-right type (rodzaj prawa), multi-select; perpetual_usufruct = użytkowanie wieczyste; 'unknown' = none recorded." - changed
Input schema / properties / parcelId / descriptionPrevious value: -"Exact parcel ID as returned in search results (e.g. '146518_8.0108.27'). Must match exactly - copy from a previous search result's parcel_id field."New value: +"Exact parcel ID, copied from a search result's parcel_id field (e.g. '146518_8.0108.27')." - changed
Input schema / properties / rooms / descriptionPrevious value: -"Number of rooms (izby) filter, residential units only. Multi-select; '8plus' means 8 or more, 'unknown' = no room count recorded (NULL). E.g. ['2','3'] for 2-3 izby flats. Without 'unknown', rows with no room count are excluded."New value: +"Rooms (izby), residential units only; multi-select ('8plus' = 8 or more). Rows with no count drop out unless 'unknown' is listed." - changed
Input schema / properties / street / descriptionPrevious value: -"Street name filter, matched anywhere inside the name (e.g. 'Puławska', 'Aleja Waszyngtona'). Give it in the NOMINATIVE and with its Polish diacritics — matching is literal, so 'Karmelickiej' does not find 'Karmelicka' and 'Marszalkowska' does not find 'Marszałkowska'. Either mistake answers with nothing, which reads exactly like 'no such transactions'."New value: +"Street name, matched anywhere inside the name. Give the NOMINATIVE with Polish diacritics - matching is literal ('Karmelickiej' does not find 'Karmelicka'); a miss looks exactly like 'no such transactions'." - added
Input schema / properties / summaryOnlyAdded value: +{ + "description": "Return only aggregate stats (total, median price/m² with its sample size, period) and no rows. Costs only the summary call; limit/sort/page are ignored.", + "type": "boolean" +} - changed
Input schema / properties / teryt / descriptionPrevious value: -"TERYT administrative code(s) for precise area filtering. Comma-separated, max 10. 2-digit (voivodeship), 4-digit (county), 6-digit (municipality), or full precinct code (e.g. '321705_2.0054'). Use list_locations to find codes. More precise than 'location' - avoids name ambiguity."New value: +"TERYT code(s), comma-separated, max 10: 2-digit (voivodeship), 4 (county), 6 (municipality) or a precinct code (e.g. '321705_2.0054'). Find codes with list_locations. Exact - avoids name ambiguity." - changed
Input schema / properties / transactionType / descriptionPrevious value: -"Transaction type filter. For market analysis, ALWAYS specify transactionType to exclude non-market transactions (subsidized, foreclosure, public purpose). ~2% of transactions have unknown type (NULL) and are excluded when this filter is used unless 'unknown' is included."New value: +"Multi-select. For market analysis ALWAYS set it to exclude non-market deeds (subsidized, foreclosure, public_purpose); no-type rows (~2%) drop out unless 'unknown' is listed." - changed
Input schema / properties / unitFunction / descriptionPrevious value: -"Unit/apartment function filter. 'unknown' = no function recorded (NULL); without it such rows are excluded. Garages appear only when 'garage' is selected, not via 'unknown'."New value: +"Unit function; 'unknown' = none recorded (NULL), any other value excludes such rows. Garages only via 'garage'."
12 tool updates
v0.12.0- Changed
get_demographics2 fields changed- changed
Input schema / properties / location / descriptionPrevious value: -"City/county name, resolves to county/powiat level (e.g. 'Warszawa', 'Kraków'). Use this OR teryt. For gmina-level data pass a 6/7-digit teryt instead."New value: +"City, county, or district name (e.g. 'Warszawa', 'Kraków'). A city/county name resolves to county/powiat level; a Warszawa district name (e.g. 'Mokotów') resolves to that district, another city's delegatura (e.g. 'Kraków-Podgórze') to its parent county. Use this OR teryt. For gmina-level data on other units pass a 6/7-digit teryt instead." - changed
Input schema / properties / teryt / descriptionPrevious value: -"TERYT code: 2-digit (voivodeship, e.g. 14), 4-digit (county, e.g. 1465), 6 or 7-digit (gmina, e.g. 1465011). Wins over location. Use list_locations to find codes."New value: +"TERYT code: 2-digit (voivodeship, e.g. 14), 4-digit (county, e.g. 1465), 6 or 7-digit (gmina, e.g. 1465011). The 7th digit selects the unit type: 3 = urban-rural gmina overall, 4/5 = urban/rural part only, 8 = Warszawa district (1465011 = all of Warszawa, 1465108 = Śródmieście). Wins over location. Use list_locations to find codes."
- Changed
get_infrastructure_signals1 field changed- changed
Input schema / properties / location / descriptionPrevious value: -"City or county name (e.g. 'Warszawa', 'Krotoszyn'). Aggregates every municipality in the county. Use this OR teryt."New value: +"City, county, or district name (e.g. 'Warszawa', 'Krotoszyn'). A city/county name aggregates every municipality in the county; a Warszawa district name (e.g. 'Mokotów') narrows to that gmina, another city's delegatura (e.g. 'Kraków-Podgórze') resolves to its parent county. Use this OR teryt."
- Added
get_parcel_land_class - Added
get_transaction_nature - Added
get_transaction_roads - Added
get_transaction_subsurface - Changed
list_locations1 field changed- changed
Input schema / properties / search / descriptionPrevious value: -"Filter locations by name (case-insensitive partial match, e.g. 'Krak' for Kraków districts). Ignored when parent is set."New value: +"Look up a place by name (case-insensitive, diacritics-insensitive partial match, e.g. 'wejher' for Wejherowo). Returns TERYT codes plus, where applicable, RCN district names. Ignored when parent is set."
- Added
list_parcels_in_area - Changed
resolve_parcel1 field changed- changed
Input schema / properties / q / descriptionPrevious value: -"Full cadastral id, a UUID, or 'locality name + parcel number' (e.g. 'Sabnie 342/5'). Mutually exclusive with parcelId and lat/lng."New value: +"Full cadastral id, a UUID, or 'locality name + parcel number' (e.g. 'Sabnie 342/5') — the name may be a gmina or a cadastral precinct (obręb). NOT a street address: for a street + building number use list_parcels_in_area instead. Mutually exclusive with parcelId and lat/lng."
- Changed
search_by_area4 fields changed- added
Input schema / properties / buildingStoreysAdded value: +{ + "description": "Number of above-ground storeys of the building. Multi-select buckets: exact non-negative integers (e.g. '1','2'), 'Nplus' e.g. '3plus' = 3 or more, 'unknown' = no storey count recorded (NULL). Recorded ONLY for single-building transactions, so 'unknown' covers BOTH a deed with several buildings (no single storey count exists) and a single building with missing data — never read it as 'a building with no storeys'. This is NOT the floor of a unit (see floor). Without 'unknown', rows with no storey count are excluded.", + "items": { + "pattern": "^(\\d+|\\d+plus|unknown)$", + "type": "string" + }, + "type": "array" +} - added
Input schema / properties / landUseAdded value: +{ + "description": "Recorded land-use category of the transaction's land. Multi-select from: gruntyZabudowaneIZurbanizowane (built-up and urbanised), gruntyRolne (agricultural), gruntyLesne (forest), terenyKomunikacyjne (transport), inne (other). 'unknown' = no category recorded for the land (NULL) — a legitimate bucket, never a claim that the land has no use. Values are case-sensitive. E.g. ['gruntyRolne'] for farmland, or ['gruntyZabudowaneIZurbanizowane','gruntyRolne'] to compare developed vs farmland.", + "items": { + "enum": [ + "gruntyZabudowaneIZurbanizowane", + "gruntyRolne", + "gruntyLesne", + "terenyKomunikacyjne", + "inne", + "unknown" + ], + "type": "string" + }, + "type": "array" +} - added
Input schema / properties / maxFootprintAreaAdded value: +{ + "description": "Maximum building footprint (ground-plan) area in m², summed over all buildings of the transaction. Distinct from maxArea, which measures usable floor area (units) or land/parcel area. Set only where every linked building has footprint data, so this bound selects only measured rows — absence means 'not measured', not 'no building'.", + "type": "number" +} - added
Input schema / properties / minFootprintAreaAdded value: +{ + "description": "Minimum building footprint (ground-plan) area in m², summed over all buildings of the transaction. Distinct from minArea, which measures usable floor area (units) or land/parcel area. Set only where every linked building has footprint data, so this bound selects only measured rows — absence means 'not measured', not 'no building'.", + "type": "number" +}
- Changed
search_by_polygon4 fields changed- added
Input schema / properties / buildingStoreysAdded value: +{ + "description": "Number of above-ground storeys of the building. Multi-select buckets: exact non-negative integers (e.g. '1','2'), 'Nplus' e.g. '3plus' = 3 or more, 'unknown' = no storey count recorded (NULL). Recorded ONLY for single-building transactions, so 'unknown' covers BOTH a deed with several buildings (no single storey count exists) and a single building with missing data — never read it as 'a building with no storeys'. This is NOT the floor of a unit (see floor). Without 'unknown', rows with no storey count are excluded.", + "items": { + "pattern": "^(\\d+|\\d+plus|unknown)$", + "type": "string" + }, + "type": "array" +} - added
Input schema / properties / landUseAdded value: +{ + "description": "Recorded land-use category of the transaction's land. Multi-select from: gruntyZabudowaneIZurbanizowane (built-up and urbanised), gruntyRolne (agricultural), gruntyLesne (forest), terenyKomunikacyjne (transport), inne (other). 'unknown' = no category recorded for the land (NULL) — a legitimate bucket, never a claim that the land has no use. Values are case-sensitive. E.g. ['gruntyRolne'] for farmland, or ['gruntyZabudowaneIZurbanizowane','gruntyRolne'] to compare developed vs farmland.", + "items": { + "enum": [ + "gruntyZabudowaneIZurbanizowane", + "gruntyRolne", + "gruntyLesne", + "terenyKomunikacyjne", + "inne", + "unknown" + ], + "type": "string" + }, + "type": "array" +} - added
Input schema / properties / maxFootprintAreaAdded value: +{ + "description": "Maximum building footprint (ground-plan) area in m², summed over all buildings of the transaction. Distinct from maxArea, which measures usable floor area (units) or land/parcel area. Set only where every linked building has footprint data, so this bound selects only measured rows — absence means 'not measured', not 'no building'.", + "type": "number" +} - added
Input schema / properties / minFootprintAreaAdded value: +{ + "description": "Minimum building footprint (ground-plan) area in m², summed over all buildings of the transaction. Distinct from minArea, which measures usable floor area (units) or land/parcel area. Set only where every linked building has footprint data, so this bound selects only measured rows — absence means 'not measured', not 'no building'.", + "type": "number" +}
- Changed
search_transactions7 fields changed- changed
Input schema / properties / buildingNumber / descriptionPrevious value: -"Building/house number (e.g. '251C', '12A'). Requires location or street to be set."New value: +"Building/house number (e.g. '30', '12A'). Requires location or street to be set." - added
Input schema / properties / buildingStoreysAdded value: +{ + "description": "Number of above-ground storeys of the building. Multi-select buckets: exact non-negative integers (e.g. '1','2'), 'Nplus' e.g. '3plus' = 3 or more, 'unknown' = no storey count recorded (NULL). Recorded ONLY for single-building transactions, so 'unknown' covers BOTH a deed with several buildings (no single storey count exists) and a single building with missing data — never read it as 'a building with no storeys'. This is NOT the floor of a unit (see floor). Without 'unknown', rows with no storey count are excluded.", + "items": { + "pattern": "^(\\d+|\\d+plus|unknown)$", + "type": "string" + }, + "type": "array" +} - added
Input schema / properties / landUseAdded value: +{ + "description": "Recorded land-use category of the transaction's land. Multi-select from: gruntyZabudowaneIZurbanizowane (built-up and urbanised), gruntyRolne (agricultural), gruntyLesne (forest), terenyKomunikacyjne (transport), inne (other). 'unknown' = no category recorded for the land (NULL) — a legitimate bucket, never a claim that the land has no use. Values are case-sensitive. E.g. ['gruntyRolne'] for farmland, or ['gruntyZabudowaneIZurbanizowane','gruntyRolne'] to compare developed vs farmland.", + "items": { + "enum": [ + "gruntyZabudowaneIZurbanizowane", + "gruntyRolne", + "gruntyLesne", + "terenyKomunikacyjne", + "inne", + "unknown" + ], + "type": "string" + }, + "type": "array" +} - changed
Input schema / properties / location / descriptionPrevious value: -"Location name - city (e.g. 'Warszawa', 'Kraków', 'Gdańsk') or district (e.g. 'Mokotów', 'Kraków-Podgórze'). 'Warszawa', 'Kraków', 'Łódź' auto-expand to all sub-districts. Use list_locations to find valid names."New value: +"Location name - city (e.g. 'Warszawa', 'Kraków', 'Gdańsk') or district (e.g. 'Mokotów', 'Kraków-Podgórze'). 'Warszawa', 'Kraków', 'Łódź' auto-expand to all sub-districts. Prefer teryt= for exact matches; call list_locations(search=...) to confirm a name is valid here — it flags valid ones as rcn_district." - added
Input schema / properties / maxFootprintAreaAdded value: +{ + "description": "Maximum building footprint (ground-plan) area in m², summed over all buildings of the transaction. Distinct from maxArea, which measures usable floor area (units) or land/parcel area. Set only where every linked building has footprint data, so this bound selects only measured rows — absence means 'not measured', not 'no building'.", + "type": "number" +} - added
Input schema / properties / minFootprintAreaAdded value: +{ + "description": "Minimum building footprint (ground-plan) area in m², summed over all buildings of the transaction. Distinct from minArea, which measures usable floor area (units) or land/parcel area. Set only where every linked building has footprint data, so this bound selects only measured rows — absence means 'not measured', not 'no building'.", + "type": "number" +} - changed
Input schema / properties / street / descriptionPrevious value: -"Street name filter (partial match, e.g. 'Puławska', 'Trakt Lubelski')"New value: +"Street name filter, matched anywhere inside the name (e.g. 'Puławska', 'Aleja Waszyngtona'). Give it in the NOMINATIVE and with its Polish diacritics — matching is literal, so 'Karmelickiej' does not find 'Karmelicka' and 'Marszalkowska' does not find 'Marszałkowska'. Either mistake answers with nothing, which reads exactly like 'no such transactions'."
1 tool update
v0.6.0- Changed
search_by_polygon2 fields changed- changed
Input schema / properties / limit / descriptionPrevious value: -"Max results (1-5000, default 100). MCP displays up to 50 transactions."New value: +"Max results (1-3000, default 100). MCP displays up to 50 transactions." - changed
Input schema / properties / limit / maximumPrevious value: -5000New value: +3000
23 tool updates
v0.5.0- First observed
compare_locations - First observed
estimate_value - First observed
get_building_breakdown - First observed
get_demographics - First observed
get_infrastructure_signals - First observed
get_market_overview - First observed
get_parcel_report - First observed
get_price_distribution - First observed
get_price_statistics - First observed
get_transaction_farmland - First observed
get_transaction_flood - First observed
get_transaction_heritage - First observed
get_transaction_landslide - First observed
get_transaction_permits - First observed
get_transaction_planning - First observed
get_transaction_surroundings - First observed
get_transaction_transit - First observed
list_locations - First observed
resolve_parcel - First observed
search_by_area - First observed
search_by_polygon - First observed
search_parcels - First observed
search_transactions
TDQS
Scored across 30 tools
Descriptions actively steer callers between overlapping families (search_transactions vs search_by_area vs search_by_polygon; get_parcel_report vs per-layer get_transaction_* tools), so most boundaries are clear. However, with 30 tools and several near-neighbors (get_transaction_permits vs get_permits_in_area, estimate_value vs estimate_land_value), an agent still needs to read carefully to avoid misselection.
Nearly all tools use a predictable snake_case verb_noun pattern (search_transactions, get_price_statistics, get_transaction_flood, list_locations). The main deviations are the search_by_area/search_by_polygon forms and mixed estimate_* naming, but these remain readable and not chaotic.
The domain is broad, but 30 tools exceeds the recommended range and includes many per-layer transaction detail tools that largely duplicate what get_parcel_report returns. Several could be consolidated into a parameterized transaction-detail or parcel-report call.
The read-only surface is extensive: transaction search by place/radius/polygon, price statistics, parcel resolution and reporting, environmental layers, permits, planning, nature, farmland, valuation, demographics and infrastructure. A generic get_transaction(id) endpoint is notable by its absence, but the layer-specific and aggregate report tools cover most workflows without major dead ends.
Maintenance
Related MCP Connectors
Polish real-estate deed prices and parcel checks: zoning plan, utilities, flood risk
Polish real-estate prices from notarial deeds: area stats, plot and building reports, valuations.
Polish EGiB cadastral parcels by id_działki or coordinates, with RCN sale prices.
Polish flat prices on deweloperuch.pl: RCN sale prices (valuation, stats, rankings), asking prices.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceProvides access to Poland's largest business registry database, enabling company search, beneficiary checks, and financial document retrieval via natural language.1-
- AlicenseAqualityDmaintenanceEnables searching Polish administrative areas and retrieving real estate transaction data from the official registry via geoportal.gov.pl.31GPL 3.0
- AlicenseNot gradedqualityDmaintenanceFind, analyze, and score Polish public tenders (BZP): parsed requirements, deadlines, certificates, and bid-fit scoring against your company profile.9 npmMIT
- AlicenseNot gradedqualityCmaintenanceAccess 17M+ geocoded French property transactions (DVF), 22M+ DPE energy ratings, and 20M+ building records via MCP or REST API. Search transactions, market stats, comparables, price trends, rental yield, flip detection, and more.MIT