korter-mcp
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@korter-mcpWhat's the price history for Tsavkisi Park?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
korter-mcp
Event-sourced korter.ge proxy exposed as MCP tools. Tbilisi new-builds, with price history — korter shows you a price, this shows you how it moved.
Built on @lambda-house/teob-ts.
Personal research tool. Not a product, not a data service.
Registering in Claude Code
Local stdio server (fetches korter itself, keeps its own history):
pnpm install && pnpm run build
claude mcp add --transport stdio korter -- node /path/to/korter-mcp/dist/main.js stdioProject-scoped: this repo ships .mcp.json, so a Claude Code
session opened in this directory has the server automatically.
Remote (a deployed serve instance does the fetching; one shared history, no
duplicate load on korter):
# MCP over Streamable HTTP (put an OAuth-capable gateway in front — see Modes):
claude mcp add --transport http korter https://<your-host>/mcp
# or the stdio facade over the deployed read API:
KORTER_MODE=remote \
KORTER_REMOTE_URL=https://<your-host> \
KORTER_REMOTE_TOKEN=<api token> \
claude mcp add --transport stdio korter -- node /path/to/korter-mcp/dist/main.js stdioOnce connected, call the get_skill tool (apartment-search,
criteria-coverage, freshness-and-history, operating-limits) — the server
ships its own usage guidance.
Related MCP server: Geo Home MCP
Tools
Reads (served from projections and the journal — never from a live fetch):
search_projects, get_project, list_districts, price_history,
diff_report.
Commands: refresh (fetch a source now — refreshing is an action, not a
force flag on reads), track / untrack / list_tracked (the weekly sweep
set, journaled).
Source ids are project:<slug> or listing:<slug>, e.g.
project:tsavkisi-park-tbilisi, listing:new-projects-in-avlabari.
Every result carries the envelope: source_url, fetched_at,
prices_as_of (korter's own "prices up to date as of" date — null when korter
shows none), observed_at, staleness_days. All timestamps come from journal
events, never from the clock at serialization time; staleness_days is the
one field allowed to consult the clock, because "how stale is this now" is a
question about now.
Why event sourcing for a scraper
Two reasons, and if either stopped being true a sqlite3 + httpx script would
be the better tool:
Price history is an event log.
PriceObservedon aProjectentity is the history — noprice_historytable, no INSERT-if-changed rule. Dedup is a puredecidefunction returningdone().The same code runs two ways — a local stdio MCP server on a laptop, and a long-lived prod service whose history keeps accruing whether or not the laptop is on.
Design
Three aggregates:
Aggregate | Per | Holds |
| korter slug | attributes and the price history |
| fetched URL | fetch lifecycle, listing membership |
| singleton | the tracked set and the sweep schedule |
Raw HTML is not event-sourced — it lives in a plain 24h page_cache table,
with sourceHash on the events tying an observation back to its bytes. The
same goes for korter's district taxonomy: reference data in a plain table,
refreshed by listing fetches, not history.
Recon findings and the extraction map: docs/schema-notes.md.
Storage
SQLite everywhere, including a deployed instance (on a persistent volume). teob-ts's whole read model — projection store, live category tails, journal reader — is SQLite-native, and this corpus is a handful of entities with weekly writes. Postgres would be an unused dependency.
Fixtures
fixtures/ holds saved korter pages for parser-compatibility tests. They are
korter's content and are not distributed — absent (as in the public
snapshot), those tests skip and the suite still passes against the invented
pages in test/synthetic.ts. See fixtures/README.md.
Modes
node dist/main.js stdio # MCP over stdin/stdout (default; stdout carries frames, logs go to stderr)
node dist/main.js serve # long-lived service: /api + /mcp on :8080, probes on :9095
node dist/main.js sweep # one-shot sweep of the tracked set, prints the diff report, exits
pnpm run smoke # 2 live requests against korter, excluded from CIserve refuses to start without KORTER_API_TOKEN and
KORTER_POMERIUM_TOKEN — the endpoints must be authenticated, or a personal
research tool becomes a public scraper fronting someone else's site.
Development
pnpm install
pnpm test # zero network — everything runs against fixtures/
pnpm run typecheck
pnpm run buildHow it behaves toward korter
1 request/second, globally, across every caller. Cache-first, 24h TTL. Weekly sweeps of a short tracked list.
Honest User-Agent:
korter-mcp/0.1 (personal research tool).403 or 429 stops the tool. The breaker opens and stays open. Nothing rotates, nothing retries behind your back, nothing gets bypassed.
Listing and project pages only — no secondary market, no user listings.
No republication, no resale, no bulk export.
robots.txtis checked before fetching (and korter's disallows their own hydration API — so only the HTML pages are read, never/api/).
These constraints live in src/config.ts and are asserted by the test suite.
Known limitations
korter's own data goes stale. Cards dated June 2025 were still displayed in August 2026 (the smoke run on 2026-08-30 found a live card 39 days stale). Read
prices_as_ofandstaleness_days.The parser is the fragile part. One pure function,
src/parse/extract.ts, readingwindow.INITIAL_STATE; fully fixture-tested. It will break when korter redesigns, and everything else is deliberately independent of it.Districts are korter's taxonomy. Their "Vake district" swallows Bagebi, Lisi and the Nutsubidze plateau. No mapping to colloquial neighbourhoods is invented.
Prices come in the page currency (
/en/serves USD). GEL and USD are independent series, never converted.A page's currency history starts when this tool first observes it — there is no backfill; korter shows no history to backfill from. That asymmetry is the reason this tool exists.
korter's ToS likely prohibits automated extraction. The operator accepts that risk knowingly and keeps volume trivial in exchange. If you run this yourself, that trade-off — and the structural limits that keep it honest — becomes yours.
License
Available Tools
15 toolsconsentA
Record or change YOUR consent (authenticated users). Two separate consents: accept_terms — required to use the tools (notice: get_skill 'privacy'); marketing_offers — OPTIONAL opt-in to receive real-estate suggestions matching your searches, never required. Omit a field to leave it unchanged; false revokes.
| Name | Required | Description | Default |
|---|---|---|---|
| accept_terms | No | ||
| marketing_offers | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the burden and does well: it discloses that omitted fields are left unchanged, that false revokes, that accept_terms gates tool usage, and that marketing_offers is never required. It omits return/response behavior and any idempotency or permission nuance, which keeps it from 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?
Front-loaded with the core action and then the two consent semantics; dense but every clause adds information. Minor awkwardness in 'notice: get_skill "privacy"' and the mid-sentence parenthetical slightly disrupt flow.
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 zero-required-parameter, two-boolean tool with no output schema, the description covers what each field does and the gating/revocation rules. It lacks only the result/confirmation behavior of the call, which is a small 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 0%, so the description must compensate — and it does, explaining what each boolean means, that accept_terms is required for tool use, and the edge-case semantics of omission and false. That is meaning well beyond the bare boolean types.
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 set (record or change) and resource (YOUR consent, authenticated users), and enumerates the two distinct consent types by name. It's unmistakably different from siblings like track/untrack or my_data.
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?
Clearly frames when to call: to record or modify your own consent, with accept_terms being required to use the tools and marketing_offers optional. It points to get_skill 'privacy' for the notice, but doesn't name an alternative tool or state when this is not the right choice.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
diff_reportA
What changed across all observed projects since a timestamp: price moves (old → new), newly discovered projects, delistings, and listing membership changes.
| Name | Required | Description | Default |
|---|---|---|---|
| since | Yes | ISO date or datetime, e.g. 2026-08-01 |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It usefully discloses the report's contents (old → new price moves, delistings, membership changes), which is meaningful behavioral context, but it omits access requirements, cost/latency, size limits, and pagination behavior for what is potentially a large multi-project report.
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?
A single front-loaded sentence that puts the verb ('What changed') first and then lists the four change categories. No filler, no repetition of the tool name, and the column-style enumeration keeps the return content scannable.
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 correctly takes on the job of explaining return content and does so by enumerating the four change types. It is nearly complete for a read-only diff tool; the only real gap is that 'observed projects' (tracked vs. all indexed) is never defined.
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?
Only one parameter and schema description coverage is 100%, so the baseline is 3. The phrase 'since a timestamp' and 'old → new' echo the schema's ISO date/datetime semantics but add no format, timezone, or boundary-inclusivity detail beyond what the schema already states.
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 ('what changed'), a clear resource scope ('all observed projects since a timestamp'), and enumerates the exact change categories (price moves, new projects, delistings, membership changes). That scope distinguishes it from siblings like price_history (single-project history) or secondary_trends without opening their 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?
There is no 'when to use this' guidance, no exclusions, and no named alternative. An agent can infer it is a reporting/diff tool from the verb, but nothing tells it whether to prefer this over price_history, refresh, or list_tracked when investigating changes.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_projectA
Full card for one project by korter slug: attributes, latest price per currency, coordinates, history summary. Check staleness_days — korter itself displays months-old prices.
| Name | Required | Description | Default |
|---|---|---|---|
| slug | Yes | korter slug, e.g. 'tsavkisi-park-tbilisi' |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It does disclose a genuinely non-obvious behavioral quirk: korter itself may display months-old prices, so the agent should inspect staleness_days. It doesn't cover auth/permission needs or read-only nature explicitly, but the freshness warning is real value beyond structured data.
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 tight sentences, front-loaded with the return contents and ending with the operational caveat. Every clause earns its place; nothing is redundant.
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 compensates by enumerating returned fields (attributes, prices per currency, coordinates, history summary) and flagging the staleness signal. It is nearly complete for a single-record read tool; only auth/error behavior is 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?
Only one parameter, and schema description coverage is 100% — the schema already documents the slug with a concrete example. The description reinforces that slug is a 'korter slug', adding no syntax or format detail the schema lacks.
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 ('full card for one project by korter slug') and enumerates exactly what the card contains: attributes, latest price per currency, coordinates, history summary. This cleanly separates it from sibling list/search tools like search_projects and price_history.
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?
Usage is implied by 'by korter slug' — you fetch one known project — and the staleness_days pointer hints at a freshness-checking use case. However, it never names an alternative (e.g., search_projects to obtain a slug, or price_history for deeper trend work) or states when not to use it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_skillA
Fetch usage guidance for this server before composing non-trivial queries. Skills: apartment-search — Map a buyer's criteria onto the search tools; the coarse-to-fine flow; criteria-coverage — What korter exposes vs what this server models — the gap map by buyer persona; freshness-and-history — Reading the staleness envelope; using price_history and diff_report; operating-limits — Rate limits, the breaker, and what this tool refuses to do; privacy — The privacy notice shown to authenticated users (current version). Call with the skill name; call 'apartment-search' before any multi-criteria search.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations the description must carry behavioral load, and it does disclose substantive content: the skill catalog, including that 'operating-limits' covers rate limits, the breaker, and what the tool refuses to do, and that 'privacy' carries a versioned notice. It omits call-side traits such as return format (prose vs structured) and any caching/cost behavior, leaving a modest 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?
Purpose and the routing rule are front-loaded in the first and last sentences. The middle is a dense run-on of semicolon/em-dash fragments that is information-rich but harder to parse than a bulleted list would be; nothing is purely wasteful.
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?
A one-parameter enumeration tool with no output schema does not need return-value documentation, and all five skill names are accounted for. What remains thin is the mapping from user scenario to the three skills besides apartment-search, so an agent still has to guess which of the others to fetch.
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 0%, so the description must compensate, and it does by explaining the meaning of every enum value rather than merely listing them — e.g. criteria-coverage is 'the gap map by buyer persona', freshness-and-history covers 'using price_history and diff_report'. It reinforces the invocation form ('Call with the skill name') but adds no format detail beyond the enum itself.
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 ('Fetch usage guidance for this server') and immediately distinguishes itself from the search/tracking siblings by enumerating the five concrete skills it serves. An agent can tell this is the meta-documentation tool and not a data tool 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?
Gives a clear trigger ('before composing non-trivial queries') and an explicit rule for one skill ('call apartment-search before any multi-criteria search'). It stops short of stating when not to call it (e.g., trivial/single-tool queries) or which skill to pick for the other four scenarios, so it is strong context without full exclusion logic.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_districtsA
korter's own district/microdistrict taxonomy for Tbilisi with their average price per m². Names are korter's, as-is — their 'Vake district' swallows Bagebi, Lisi and the Nutsubidze plateau.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries full behavioral burden. It discloses a critical behavioral trait: the names are korter's own, not standard administrative districts, and gives a concrete example of geographic scope. This is valuable but only covers naming/scope; it says nothing about read-only nature, rate limits, caching, or response format. For a zero-param list tool, the biggest behavioral risk — 'these aren't the districts you think they are' — is addressed, earning a 3.
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 core purpose (taxonomy + average price), followed by the naming caveat. No wasted words. The dash construction is slightly informal but information-dense and easy to parse.
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 simple zero-param list tool with no output schema, the description covers purpose and a key caveat about naming. However, with no output schema, it does not describe what the returned list looks like (district names + price fields? hierarchies?) nor does it indicate if this is a static reference or computed fresh. Adequate but incomplete for an agent needing to interpret results.
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?
Zero parameters, so baseline is 4. The description correctly adds no parameter semantics because there are none to describe, and it wisely uses the space for scope clarification instead.
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 (list) and resource (districts/microdistricts) and adds the crucial scope — it's the platform's own proprietary taxonomy plus average price per m². This distinguishes it clearly from the sibling 'secondary_trends' or 'search_secondary', which handle market data differently.
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 description implies this is the canonical source for district-level price averages, and the caveat about 'Vake district' swallowing Bagebi etc. implicitly guides interpretation. However, it does not explicitly state when to use this tool vs. alternatives like price_history or secondary_trends — the agent must infer that this is for static taxonomy lookups.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_trackedC
The sources in the weekly sweep, and when the last sweep ran.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden, yet it never states that this is a safe read-only operation, nor anything about side effects, permissions, or pagination. It only asserts what information is present, not how the tool behaves when called.
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?
A single short sentence with no filler, front-loading the returned content. It is efficient, though the sentence is grammatically a fragment and slightly cryptic in its shorthand.
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 should describe the return shape, and it does name two returned elements (the tracked sources and the last sweep time). However, terms like 'weekly sweep' and 'sources' are never defined, so it is adequate but leaves the agent guessing at specifics.
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 no parameter meaning to convey and the baseline of 4 applies. Nothing in the schema needs additional elaboration from the description.
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 reads as a noun phrase ('The sources in the weekly sweep...') rather than a clear verb+resource statement, though it does convey the domain concept of listing tracked sources. It does not distinguish this tool from siblings like track/untrack or clarify that it is the read-side counterpart. The purpose is inferable but not sharply stated.
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?
There is no statement of when to use this tool versus the obvious siblings such as track, untrack, or refresh. An agent must infer from the name alone that this lists currently tracked sources, with no guidance on prerequisites or when an alternative is preferable.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_usersC
Operator only: registered users, their consents and interest profiles (the opted-in list is the offers feed).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden of behavioral disclosure. It states 'Operator only' but doesn't explain what that means (e.g., role-based access), nor does it describe the return format, pagination, or side effects. The parenthetical about the opted-in list adds a bit of context but is insufficient.
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 a single, concise sentence that is front-loaded with the key permission constraint. It efficiently conveys the main points without unnecessary words.
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 no-parameter tool with no annotations and no output schema, the description should do more to clarify the return data and usage. It mentions users, consents, and interest profiles, but lacks details on structure, operator context, and how it relates to siblings. The brief parenthetical is not enough.
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?
There are zero parameters, so the baseline score is 4. The description doesn't need to explain parameters, and it correctly focuses on the output instead.
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 uses a noun phrase rather than a clear verb+resource, but the tool name 'list_users' carries the verb. It mentions registered users, consents, and interest profiles, giving some sense of what data is returned. However, it doesn't clarify if this is purely a list operation or includes nested data, and it doesn't differentiate from siblings like 'my_data' or 'consent'.
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 only guidance is 'Operator only', which indicates a permission requirement but not when or why to use this tool. There's no mention of alternatives or context for invocation, leaving the agent to infer usage.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
my_dataA
Everything this server holds about YOU (authenticated users): profile, consent log, recorded search interests. Your right to know — and the map for what consent(false) erases from use.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the behavior burden. It names the returned contents (profile, consent log, search interests) and mentions the consent(false) interaction, but does not confirm read-only semantics, auth requirements beyond 'authenticated users', or whether calling it has any side effects.
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 compact sentences with the subject ('everything about YOU') front-loaded. The second sentence is somewhat cryptic and em-dash-heavy but still earns its place by linking the tool to the consent feature.
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 no annotations, the description enumerates what is returned, which is the key missing information. It is adequate for a zero-param read tool, though it could state the read-only nature more plainly.
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?
There are zero parameters and schema coverage is 100%, so the baseline is 4. The description correctly requires no argument detail, consistent with the empty object 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 with concrete contents — profile, consent log, recorded search interests — scoped to the authenticated user, which distinguishes it from sibling list_users/get_project. The verb is only implied ('everything this server holds'), but the resource and scope are unambiguous.
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?
Implies usage via 'your right to know' and positions the tool as the map for what consent(false) erases, which hints at a relationship with the consent sibling. However it never states explicitly when to call this versus consent, list_users, or other retrieval tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
price_historyC
The accrued price history for one project — every price change and re-dating this tool has observed, from the journal. This is the value korter does not show: how the price moved.
| Name | Required | Description | Default |
|---|---|---|---|
| slug | Yes | ||
| currency | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden. It usefully discloses provenance ('from the journal') and observational limits ('this tool has observed'), implying coverage may be incomplete, but says nothing about read-only safety, auth/permissions, result size, pagination, or ordering.
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 tight sentences with the resource and its scope front-loaded. The second sentence is partly rhetorical ('the value korter does not show') but does add differentiation, so waste is minimal.
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, no annotations, and undocumented parameters mean the description should have covered return shape, scope/limits, and parameter meanings. It gives a good conceptual framing but leaves the operational essentials 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 description coverage is 0% for two parameters, and the description does not compensate: 'one project' only loosely implies the slug identifies the project, and the currency enum (USD/GEL) is never explained or referenced. The agent must infer both from the schema 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?
The description states a concrete resource and its scope: the accrued price history for one project, covering 'every price change and re-dating this tool has observed.' An agent understands it retrieves a time series of price movements, though no verb is used and no sibling (e.g. get_project, diff_report) is named to sharpen the boundary.
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?
There is no explicit when-to-use guidance, no prerequisites (e.g. must the project be tracked?), and no alternatives named among the many siblings. Usage is only inferable from the resource name itself.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
refreshA
Fetch one source from korter now (cache-first, 24h TTL; globally paced at 1 req/s; honest UA). source_id is 'project:' or 'listing:'. If korter answers 403/429 the circuit breaker opens and stays open — by design this tool stops instead of evading.
| Name | Required | Description | Default |
|---|---|---|---|
| force | No | bypass the 24h page cache | |
| source_id | Yes | e.g. project:tsavkisi-park-tbilisi |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden and does so convincingly: cache-first with a 24h TTL, global pacing at 1 req/s, an honest user agent, and a circuit breaker that stays open on 403/429 by design. These are non-obvious operational traits an agent could not infer from the schema, and they define the failure mode explicitly.
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 dense sentences with zero filler; the core action is front-loaded, followed by the id format and then the failure policy. Every clause 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 fetch tool with no annotations and no output schema, the description covers caching, rate limiting, id format, and error behavior well. It does not state what the tool returns or whether a fetch persists data anywhere, which is a minor but real gap given no output schema exists to fill 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 already 100%, which sets a baseline of 3, and the description goes beyond it by defining the two valid source_id namespaces ('project:<slug>' and 'listing:<slug>') rather than just giving one example as the schema does. The force parameter's effect (bypassing the 24h cache) is only explained in the schema, not reinforced in prose, 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 and resource: fetch one source from korter now, scoped to a single source_id. It is distinguishable from read siblings like get_project because it forces a network fetch rather than a local read. It stops short of explicitly naming an alternative tool or contrasting with 'track' (which presumably refreshes recurring sources), so sibling differentiation is implied rather than stated.
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 description conveys context through caching and pacing details (cache-first, 24h TTL, 1 req/s), which implies the tool should be used sparingly for one-off fresh fetches. It also states the operating stance ('this tool stops instead of evading') when blocked. However, it never says when to prefer this over track, get_project, or search_* , leaving the selection criteria to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_projectsA
Search observed Tbilisi new-build projects. Criteria: district/city (korter's taxonomy, as-is), price per m² and total budget, rooms and unit area (need per-unit data — see get_skill 'apartment-search'), construction/sales status, building type, developer, free text. Served from the local journal — check staleness_days on every result. Room/area filters only consider projects whose project page has been observed; candidates lacking that data are listed separately so you can refresh them.
| Name | Required | Description | Default |
|---|---|---|---|
| q | No | substring match on name, address, developer or slug | |
| city | No | ||
| rooms | No | exact room count of at least one available unit type | |
| currency | No | price currency, default USD (korter's /en/ pages price in USD) | |
| district | No | korter district name, e.g. 'Vake', 'Isani' (their taxonomy, as-is) | |
| developer | No | substring match on developer name | |
| min_rooms | No | ||
| max_budget | No | total price cap — matches price_from or any unit's minimum price | |
| max_area_m2 | No | ||
| min_area_m2 | No | unit area range must overlap [min_area_m2, max_area_m2] | |
| building_type | No | e.g. 'cottage' | |
| include_delisted | No | ||
| max_price_per_m2 | No | ||
| min_price_per_m2 | No | ||
| construction_status | No | 'construction' | 'ready' (korter's values) | |
| include_sold_out_units | No | count allSold unit types when matching rooms/area |
Output Schema
| Name | Required | Description |
|---|---|---|
| count | No | |
| projects | No | |
| needs_unit_data | No | slugs passing card-level filters but lacking per-unit data for rooms/area criteria |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations, so the description carries the full burden and does reasonably well: it discloses data provenance ('served from the local journal'), a staleness caveat ('check staleness_days on every result'), and a significant filter limitation (room/area filters only consider projects with an observed project page). It omits auth/rate-limit and mutability facts, but says nothing contradicting a read-only search.
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 dense sentences, front-loaded with the verb and resource, then criteria, then provenance/caveats. Every sentence carries information, though the middle criteria list is a bit packed.
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?
An output schema exists so return-shape explanation is unnecessary, and the description covers provenance, staleness, and the observed-data filter constraint. Missing only guidance on flags like include_delisted and include_sold_out_units, which an agent must infer from schema descriptions 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?
With 16 parameters at 63% schema description coverage, the schema does most of the work. The description's criteria list maps to the filter families (district/city, price per m²/budget, rooms/area, status, building type, developer, free text), and it adds the important caveat that room/area matching depends on observed per-unit data, but it gives no syntax or value details 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 verb+resource ('Search observed Tbilisi new-build projects') and enumerates the searchable dimensions, which clearly separates it from the secondary-market sibling search_secondary. An agent can tell what it retrieves 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 routing guidance: per-unit room/area work points to get_skill 'apartment-search', and projects lacking observed per-unit data are returned separately so they 'can be refreshed' (presumably via refresh). It lacks an explicit when-not-to-use statement, but the context is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_secondaryB
Search the secondary market (resale and rent) from the latest snapshots of tracked secondary sources. Each result links to the korter listing — contact with the seller happens THERE; this server stores property facts only, never seller identities. Per-listing korter freshness is in actualize_staleness_days. If a district has no snapshot, the result says which source to refresh.
| Name | Required | Description | Default |
|---|---|---|---|
| city | No | ||
| rooms | No | ||
| section | No | sale prices are totals; rent is per month | sale |
| district | No | ||
| max_price | No | total for sale, monthly for rent | |
| min_rooms | No | ||
| max_area_m2 | No | ||
| min_area_m2 | No | ||
| property_type | No | e.g. flat, studio | |
| max_price_per_m2 | No | ||
| include_unavailable | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the burden and does add real context: results link to the korter listing where contact happens, no seller identities are stored, freshness is exposed via actualize_staleness_days, and empty-district results name a source to refresh. Missing rate/auth/reversibility notes, but the safety-relevant behavior is disclosed.
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?
Four tight sentences, front-loaded with the core action, then caveats. The 'actualize_staleness_days' sentence is a needed data-point but slightly cryptic without 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?
No output schema, so the description usefully explains result shape (korter link, freshness field, refresh hint). However, with 11 loosely documented parameters and no annotations, coverage is only partial 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 coverage is only 27% (3 of 11 params described) and the description adds almost no parameter meaning beyond noting district snapshot absence. City, rooms, price/area filters, and include_unavailable are undocumented in both places.
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: searching the secondary market (resale and rent) from tracked snapshots. The market scope implicitly separates it from search_projects, but no sibling is named explicitly.
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?
Usage is implied by 'search the secondary market,' and it clarifies that seller contact happens off-server. There is no explicit when-to-use vs. alternative (e.g. search_projects, secondary_trends) guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
secondary_trendsC
Secondary-market aggregates per district (korter's own figures: avg price/m², sale and rent ranges) plus the accrued trend from the journal for tracked secondary sources.
| Name | Required | Description | Default |
|---|---|---|---|
| district | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full behavioral burden, and it delivers little: it does not state that this is a read-only lookup, whether results are cached or live, how 'accrued trend' is computed or over what window, or what happens for a district with no tracked sources. The one useful disclosure is that figures are 'korter's own' rather than external market data.
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?
A single sentence that front-loads the primary output (aggregates) and tacks on the secondary output (trend) with no filler. Dense but not padded; the parenthetical earns its space by enumerating the actual metrics.
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 one optional parameter, no annotations, and no output schema, the description is the only specification an agent gets, and it does cover the return payload reasonably. It still leaves the optional-district default, the trend's time window, and any tracking precondition unaddressed, which for a data-retrieval tool of this shape is a real but modest 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 description coverage is 0% for the single 'district' parameter, so the description must compensate. 'Per district' implies the parameter scopes the aggregation, but it never says whether district is required, what format it takes, or what is returned when it is omitted (the schema marks it optional). That omission is material given districts are enumerable via list_districts.
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 its returned fields: secondary-market aggregates per district, with avg price/m² plus sale and rent ranges, and an accrued trend. The scope ('per district', 'tracked secondary sources') is concrete enough that an agent can tell what data comes back. It does not, however, distinguish itself from the sibling search_secondary, so it stops short of a 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?
There is no statement of when to call this versus search_secondary, price_history, or list_districts, and no prerequisites or exclusions. The phrase 'for tracked secondary sources' hints that tracking must exist first, but that implication is never made actionable.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
trackA
Add a source to the weekly sweep (journaled; survives restarts). Seed set: project:tsavkisi-park-tbilisi, project:ambience-avlabari-tbilisi, listing:new-projects-in-avlabari
| Name | Required | Description | Default |
|---|---|---|---|
| source_id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden, and it does disclose one meaningful behavioral trait: the source is 'journaled; survives restarts,' which tells the agent changes are durable. It omits other relevant behavior such as duplicate handling, validation failures, or what happens when an unknown source_id is passed.
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 action and the key durability fact, followed by concrete seed examples. Efficient overall, though the hardcoded seed list is arguably instance data that could live elsewhere.
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 one-parameter registration tool with no output schema and no annotations, the description covers purpose, durability, and ID format examples. Missing only edge-case behavior (duplicates, invalid IDs) and return semantics, which keeps it just short of complete.
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 0% for the single parameter, so the description must compensate. The seed set examples reveal the required ID convention (namespaced values like 'project:tsavkisi-park-tbilisi' and 'listing:new-projects-in-avlabari'), which adds real meaning about expected format. It still does not enumerate the allowed prefixes or explain what qualifies as a valid source.
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+resource: 'Add a source to the weekly sweep.' Combined with the sibling 'untrack', an agent can infer this is the inverse registration operation. It does not explicitly name untrack/list_tracked as alternatives, so it falls short of full sibling differentiation.
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?
Usage is implied by 'add a source to the weekly sweep' — the agent can infer this is for registering something to be monitored. However, there is no explicit when-to-use guidance, no mention of the untrack inverse, and no statement about preconditions such as whether the source must already exist.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
untrackC
Remove a source from the weekly sweep.
| Name | Required | Description | Default |
|---|---|---|---|
| source_id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It implies a destructive mutation ('Remove') but gives no details on permissions, reversibility, side effects, or what happens to existing data when a source is untracked.
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?
A single, front-loaded sentence with no wasted words. It is appropriately sized for a one-parameter tool, though its brevity contributes to the other gaps.
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 annotations, no output schema, and 0% parameter description coverage, the description is the only source of behavioral context. It fails to explain what 'weekly sweep' means, what 'source_id' identifies, or the consequences of removal.
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 0% and the description does not mention the single required parameter 'source_id' at all. The agent gets no additional meaning beyond the parameter name in 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 ('Remove') and resource ('source'), but the scope phrase 'weekly sweep' is jargon that is not explained. It does not distinguish this tool from its sibling 'track' or clarify what a 'sweep' is, leaving the exact effect ambiguous.
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?
No guidance on when to use this tool, when not to, or what alternatives exist (e.g., 'track' to add, 'list_tracked' to view). The description merely restates the action without context.
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.
15 tool updates
v0.0.1- First observed
consent - First observed
diff_report - First observed
get_project - First observed
get_skill - First observed
list_districts - First observed
list_tracked - First observed
list_users - First observed
my_data - First observed
price_history - First observed
refresh - First observed
search_projects - First observed
search_secondary - First observed
secondary_trends - First observed
track - First observed
untrack
TDQS
Scored across 15 tools
Most tools target distinct resources or actions: search_projects vs search_secondary cover different markets, get_project vs price_history differ in scope, and track/untrack/refresh have clear boundaries. Minor potential confusion between diff_report/price_history/secondary_trends (all change-oriented) and between refresh and the track/untrack sweep tools, but descriptions clarify.
Names use consistent snake_case, but conventions are mixed: some are verb_noun (get_project, list_districts, search_projects), others are bare verbs/nouns (track, refresh, consent), and others are noun phrases (diff_report, price_history, my_data). Readable, but not a predictable single pattern.
At 15 tools, the set is at the upper end of the ideal range but each tool maps to a concrete capability (search, track, refresh, history, secondary market, consent/privacy, skills). It is slightly heavy due to auxiliary tools (get_skill, consent, my_data, list_users) but not bloated or mismatched for the domain.
Core lifecycle for the domain is covered: source tracking (track/untrack/list_tracked), manual refresh, project search and detail, history/diff, secondary search and trends, plus consent and user data. Minor gaps exist, such as no explicit bulk source management or a per-source metadata view, but agents can work around them.
Maintenance
Related MCP Connectors
Remote MCP endpoint for U.S. home forecasts, public benchmark data, and permit or zoning readiness.
Market Data App MCP — wraps the Market Data App API (marketdata.app)
MCP server for SmartAgent CRM: leads, tasks, sales pipelines, property listings
Rentcast MCP — wraps Rentcast API (api.rentcast.io/v1)
Related MCP Servers
- FlicenseNot gradedqualityBmaintenanceMCP server for Irish classifieds, providing tools to search Daft.ie property listings and Adverts.ie marketplace ads, retrieve details, and optionally manage authenticated accounts. Supports both stdio and HTTP transports.-
- FlicenseNot gradedqualityBmaintenanceEnables comparison of residential candidate areas by land price, station walking time, and public transit commute, with PMTiles-powered interactive maps. Provides MCP tools for listing layers, retrieving land prices, computing commutes, finding and comparing areas, and building area maps.-
- AlicenseAqualityBmaintenanceProvides South Korean real estate transaction price lookup (sales and rent) for apartments, row houses, single-family homes, and officetels via MCP tools using public data from data.go.kr.817 npmMIT
- FlicenseNot gradedqualityCmaintenanceEnables querying Taiwan real-estate actual-price transaction data through MCP tools, including transaction search, market statistics, area listing, and data status, using a local SQLite database.-