immo.rundum/real-estate-appraisal
OfficialYou can run indicative German real-estate calculations via AfAMax; the server schema exposes two tools, while the README also describes pricing and appointment booking.
Calculate property depreciation (AfA): annual/monthly AfA, statutory comparison, tax savings, remaining useful life, and modernization assumptions.
Calculate purchase-price allocation: split land vs. building using the BMF method, with optional income-method cross-check.
Per README: get appraisal product prices, list free initial-call slots, and book appointments with OTP verification.
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., "@immo.rundum/real-estate-appraisalCalculate depreciation for a 1970 condominium, 85 sqm, bought for €350,000."
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.
Rundum Immo Real Estate Appraisal MCP
An open-source Model Context Protocol server for indicative German real-estate depreciation and purchase-price allocation. It exposes calculate_property_depreciation and calculate_purchase_price_allocation, delegating both calculations to the public AfAMax APIs, plus get_price_by_product, get_available_appointments, and book_appointment for AfAMax appraisal prices and free initial-call bookings. Proprietary appraisal formulas remain in AfAMax.
Hosted server
The public Streamable HTTP endpoint is:
https://mcp.rundum.immo/mcpNo end-user API key is required. Calls are subject to AfAMax per-client and service-wide rate limits and abuse protections.
Related MCP server: real-estate-ai
Run from source over stdio
Node.js 22.12 or newer is required.
git clone https://github.com/Rundum-Immo/real-estate-appraisal-mcp.git
cd real-estate-appraisal-mcp
pnpm install --frozen-lockfile
pnpm buildConfigure your MCP client to run the built server, replacing the path with the absolute path to your checkout:
{
"mcpServers": {
"rundum-real-estate-appraisal": {
"command": "node",
"args": ["/absolute/path/to/real-estate-appraisal-mcp/dist/transports/stdio.js"]
}
}
}The stdio server calls the anonymous AfAMax API directly. Its public limits are 30 requests per minute and 500 requests per rolling day per IP; a tenant-wide ceiling may also apply. It writes protocol messages only to stdout and operational logs only to stderr.
Install from npm over stdio
Node.js 22.12 or newer is required. Configure your MCP client to launch the published package with npx:
{
"mcpServers": {
"rundum-real-estate-appraisal": {
"command": "npx",
"args": ["-y", "@rundum-immo/real-estate-appraisal-mcp"]
}
}
}Tools
Property depreciation
calculate_property_depreciation accepts the complete public AfAMax request contract:
Required: property type, construction year, and floor area.
Optional: purchase price, land area, standard land value, inventory, purchase costs, core-renovation year, marginal tax rate, locale, coarse modernization level, and eight detailed modernization component states.
Results: annual and monthly AfA, comparison with statutory AfA, estimated tax savings, building-value assumptions, modernization points, and remaining useful life.
Omitting modernization data means AfAMax assumes no modernization, producing an upper-bound estimate. For multi-unit buildings, provide whole-building figures or calculate individual units separately. Results are indicative and do not replace tax, legal, or appraisal advice.
Example input:
{
"propertyType": "CONDOMINIUM",
"constructionYear": 1970,
"floorArea": 85,
"purchasePrice": 350000,
"taxRate": 0.42,
"locale": "en"
}Purchase-price allocation
calculate_purchase_price_allocation divides acquisition costs between non-depreciable land and the depreciable building using the German Federal Ministry of Finance (BMF) method.
Required: property type, total purchase price, purchase date, construction year, floor area, land area, and standard land value.
Condominiums also require the numerator and denominator of the co-ownership share.
Mixed-use residential/commercial buildings also require whether the commercial share is under or over 50%.
Optional: purchase costs, included inventory, garage and underground-parking counts, monthly net cold rent, and locale.
Results: the applied method, meaningful alternatives, land/building shares and values, depreciation base, unavailable or unusable method reasons, and disclosed asset-method defaults.
Providing monthly net cold rent enables the income method as a cross-check against the asset method. Garage and covered underground-parking counts improve the asset method because those spaces are valued separately. Comparative valuation is unavailable because the public contract excludes surveyor-only factors. Results are indicative and do not replace tax or legal advice.
Example input:
{
"propertyType": "CONDOMINIUM",
"totalPurchasePrice": 500000,
"purchaseRelatedCosts": 40000,
"purchaseDate": "2024-06-15",
"constructionYear": 1975,
"floorArea": 75,
"landArea": 1200,
"standardLandValue": 2500,
"coOwnershipNumerator": 75,
"coOwnershipDenominator": 1000,
"undergroundParkingSpaces": 1,
"monthlyNetColdRent": 1400,
"locale": "en"
}Appraisal prices
get_price_by_product returns the current AfAMax list price in EUR, including German VAT, for one product: rnd (Restnutzungsdauergutachten), kurzgutachten, vollgutachten, kaufpreisaufteilung, or versetzbarkeitsgutachten.
Optional: property inspection (
none,exterior,interior_exterior), express processing, and property type with flat count for the per-flat price of multi-unit buildings.Results: the total with its breakdown, net price, a table of every surcharge for comparing options, and a source link to the product page.
Discount codes are not applied; the price shown when ordering is binding.
{ "product": "rnd", "viewingType": "interior_exterior", "expressDelivery": true, "locale": "en" }Initial-call appointments
get_available_appointments lists open slots for a free, non-binding 15-minute phone call with the AfAMax team, on weekdays in Europe/Berlin, grouped by day. It looks up to 21 days ahead (default 7) and lists up to 32 slots per day (default 8), with each day's full free-slot count.
{ "days": 1, "maxSlotsPerDay": 32, "locale": "en" }book_appointment books one of those slots in two steps, so a booking is confirmed only by someone with access to the given mailbox:
Call with the slot's
startDateTime,name,email(optionallyphone,locale). AfAMax e-mails a 6-digit code and returns averificationId.Call again with only
verificationIdand theotpthe user read from the e-mail. The response confirms the booking and AfAMax sends a calendar invitation.
Codes expire after 15 minutes and allow 5 attempts. Refusals such as a slot taken meanwhile or an e-mail that belongs to an existing AfAMax account come back with what to do next and a link to continue on the AfAMax website.
Architecture
MCP client -> this public adapter -> AfAMax public HTTPS APIThis repository contains transport, validation, error mapping, and presentation code only. It contains no appraisal formulas, databases, tenant logic, or report-generation internals. The transport-neutral server factory is shared by stdio and stateless Streamable HTTP.
Development
pnpm install
pnpm check
pnpm dev:stdioTest with MCP Inspector
Build and launch the local stdio server through MCP Inspector:
pnpm build
npx -y @modelcontextprotocol/inspector \
node --env-file-if-exists=.env dist/transports/stdio.jsConnect in the browser, open Tools, and call a calculation tool with its example input above. Successful responses contain a readable summary, structured output, disclosed assumptions/defaults, and a source link to the corresponding AfAMax calculator. The source link carries the submitted inputs so the calculator opens prefilled for refinement or documentation.
To inspect the registered tools from the command line:
npx -y @modelcontextprotocol/inspector \
--cli \
node --env-file-if-exists=.env dist/transports/stdio.js \
--method tools/listDevelop the HTTP transport
cp .env.example .env
pnpm dev:httpAFAMAX_SERVICE_TOKEN is mandatory for HTTP mode. Trusted per-client rate limiting works only with a service credential issued by Rundum Immo and configured with the matching AfAMax backend value; arbitrary tokens do not enable trusted forwarding. HTTP mode forwards that token and the validated rightmost proxy client address in X-Afamax-Service-Token and X-Afamax-Client-IP. Never expose this token to MCP clients. Deploy behind a proxy that replaces, rather than blindly appends to, incoming forwarding headers.
Configuration:
Variable | Default | Purpose |
|
| Public calculation endpoint |
|
| Public purchase-price allocation endpoint |
| — | Required trusted-service credential in HTTP mode |
|
| Upstream timeout |
|
| Listen address |
|
| Listen port |
|
| Comma-separated allowed Host header names |
|
|
|
The HTTP server exposes /mcp and /health, limits request bodies to 64 KiB, validates Host and Origin syntax, and returns permissive CORS headers for anonymous browser clients.
Deploy with Docker
Production HTTP hosting is intended for Rundum Immo or explicitly authorized operators because it requires a matching AfAMax service credential. Public users can run the stdio transport without one.
docker build -t real-estate-appraisal-mcp .
docker run --rm -p 3000:3000 \
-e AFAMAX_SERVICE_TOKEN='credential-issued-by-rundum-immo' \
-e PUBLIC_HOSTS='localhost,mcp.rundum.immo' \
real-estate-appraisal-mcpThe image runs as the non-root node user. Configure mcp.rundum.immo in Coolify and proxy it to port 3000.
Data and privacy
The adapter is stateless and does not persist tool inputs or raw client IP addresses. Calculation input and the client IP are sent to AfAMax, which uses the address for abuse prevention. AfAMax stores a salted hash of the address and limited usage metadata for 30 days; it does not store the raw address in its usage records. Avoid placing personal identifiers in calculation and price inputs. book_appointment necessarily sends the user's name, e-mail address, and optional phone number to AfAMax, which uses them to send the confirmation code and to hold the appointment; the adapter neither stores nor logs them. See AfAMax privacy information and SECURITY.md.
Roadmap
The repository can grow beyond its current calculation, pricing, and booking tools. Potential future capabilities include:
Property and market-value estimation
Appraisal and valuation-report workflows
Additional German real-estate tax and appraisal tools
Future tools will follow the same boundary: this repository contains the public MCP integration, while proprietary appraisal logic remains in AfAMax.
License
Available Tools
5 toolsbook_appointmentBook a free AfAMax initial callAInspect
Books a free 15-minute initial phone call with the AfAMax team, in two steps.
STEP 1: after the user picked a slot from get_available_appointments, confirm the slot, their name and their own e-mail address with them, then call with startDateTime, name, email (and optionally phone, locale). AfAMax e-mails a 6-digit code to that address and returns status "verification_required" with a verificationId.
STEP 2: ask the user for the code from that e-mail and call again with only verificationId and otp. The code proves the address belongs to the user: use only the code the user gives you — never guess, invent or repeatedly retry codes. On success status is "booked" and a calendar invitation goes to the user.
Codes expire after 15 minutes and allow 5 attempts. If the slot was taken meanwhile, list slots again and offer another. If the e-mail belongs to an existing AfAMax account, the user must log in and book on the website (link in the error). Only book for the person you are talking to.
| Name | Required | Description | Default |
|---|---|---|---|
| otp | No | Step 2 — the 6-digit code the user received by e-mail. Only ever the code the user gives you; never guess or retry codes. / Der 6-stellige Code aus der E-Mail. | |
| name | No | Step 1 — the user's full name. / Vor- und Nachname. | |
| No | Step 1 — the user's own e-mail address; the 6-digit confirmation code is sent there. Confirm it with the user before calling. / E-Mail-Adresse für den Bestätigungscode. | ||
| phone | No | Step 1, optional — phone number for the call. / Telefonnummer für das Gespräch. | |
| locale | No | Step 1 — language of the confirmation e-mail, the appointment and the links (`de` if omitted); match the user's language. Step 2 keeps step 1's language unless set. / Sprache der E-Mails und des Termins. | |
| startDateTime | No | Step 1 — the chosen slot, copied exactly from get_available_appointments `startDateTime`. | |
| verificationId | No | Step 2 — the `verificationId` returned by step 1. |
Output Schema
| Name | Required | Description |
|---|---|---|
| meta | Yes | |
| status | Yes | `verification_required`: ask the user for the code sent to `verification.maskedEmail`, then call again with verificationId + otp. `booked`: the appointment exists. |
| requestId | Yes | |
| appointment | Yes | |
| attribution | Yes | |
| verification | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare a non-read-only, open-world, non-idempotent, non-destructive mutation. The description adds substantial behavioral context beyond that: a two-call OTP flow, intermediate status 'verification_required', verificationId return, 15-minute expiry, 5 attempts, calendar invitation on success, and error handling for taken slots or existing accounts. No contradiction with 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 long but well-structured, with STEP 1 and STEP 2 labels and the critical constraint ('never guess, invent or repeatedly retry codes') highlighted. Most sentences earn their place by covering verification, expiry, retries, and error alternatives. A small amount of repetition with the schema descriptions keeps it from being maximally 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?
For a two-step, open-world booking tool with 7 parameters and an output schema, the description covers everything an agent needs: sequencing, required inputs per step, OTP rules, error cases, and identity restrictions. Return values are left to the output schema, which is appropriate.
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 the schema already carries parameter meanings and constraints. The description still adds value by grouping parameters into step 1 vs step 2, clarifying that step 2 should be called with only verificationId and otp, and reinforcing that email must be the user's own address. That is useful operational framing beyond the schema, though not exhaustive per-parameter detail.
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 precise verb and resource ('Books a free 15-minute initial phone call with the AfAMax team') and immediately frames it as a two-step process. It also names the sibling get_available_appointments as the source of the slot, so an agent can distinguish this from the other appointment/pricing tools without opening 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?
It gives explicit when-to-use and step-by-step conditions: step 1 only after the user picks a slot from get_available_appointments and confirms name/email, step 2 only with the e-mailed code. It also states when not to proceed (slot taken, existing account email) and the alternative action for each, plus a firm usage restriction ('Only book for the person you are talking to').
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
calculate_property_depreciationCalculate German property depreciationARead-onlyIdempotentInspect
Calculate an indicative German real-estate depreciation (AfA) estimate through AfAMax.
Use this for residential German property, including remaining useful life, annual/monthly AfA, statutory comparison, and estimated tax savings. For apartment buildings, pass figures for the whole building or calculate units separately. Ask for all eight modernization component states whenever possible: omitting them assumes no modernization and produces the highest possible remaining-useful-life benefit. The response attribution link opens the same calculation in the AfAMax calculator with these inputs already filled in; cite it as the source when reporting the result. The result is non-binding and does not replace tax or legal advice.
| Name | Required | Description | Default |
|---|---|---|---|
| locale | No | Language for upstream explanations; defaults to German. | |
| taxRate | No | Personal marginal tax rate as a decimal, e.g. 0.42. | |
| landArea | No | Land area in square metres. | |
| floorArea | Yes | Living or usable floor area in square metres. | |
| propertyType | Yes | German residential property category. | |
| modernization | No | Known state of eight modernization components. Ask for all eight when possible. | |
| purchasePrice | No | Total purchase price in EUR. | |
| constructionYear | Yes | Original year of construction. | |
| includedInventory | No | Movable inventory included in the purchase price, in EUR. | |
| standardLandValue | No | Standard land value in EUR per square metre. | |
| coreRenovationYear | No | Year of a qualifying core renovation, if applicable. | |
| modernizationLevel | No | Coarse modernization level used when detailed component data is unavailable. | |
| purchaseRelatedCosts | No | Purchase-related costs in EUR. |
Output Schema
| Name | Required | Description |
|---|---|---|
| meta | Yes | |
| input | Yes | |
| results | Yes | |
| disclaimer | Yes | |
| assumptions | Yes | |
| attribution | Yes | |
| calculationId | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover safety (readOnly, idempotent, non-destructive, closed-world), yet the description adds real behavioral context beyond them: the omission of modernization inputs produces the highest possible benefit, the response carries an attribution link to the AfAMax calculator that should be cited, and the result is explicitly non-binding and not a substitute for tax/legal advice.
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?
Well front-loaded: purpose first, then scope, then handling guidance, then the attribution/disclaimer. It is dense and nearly every sentence earns its place, though the 'ask for all eight modernization states' instruction partially duplicates the schema's own note, adding mild redundancy.
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 13-parameter calculation tool with an output schema, the description covers what an agent needs: purpose, scope, the key default risk (omitted modernization), and result caveats. Return values are appropriately left to the output schema; only minor gaps remain, such as no note on partial vs. full input handling.
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 the baseline is 3; the description earns an extra point by adding semantics the schema does not carry, specifically the whole-building-vs-unit choice for apartment buildings and the consequence of omitting the eight modernization component 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 names a specific verb and resource ('Calculate an indicative German real-estate depreciation (AfA) estimate') and situates it in a named product (AfAMax). The domain term AfA plus the enumerated outputs (remaining useful life, annual/monthly AfA, statutory comparison, tax savings) make it unmistakably distinct from siblings like calculate_purchase_price_allocation.
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 ('residential German property') and gives concrete handling guidance for apartment buildings (whole-building vs. per-unit). It does not explicitly name when not to use it or point to an alternative tool, so it stops short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
calculate_purchase_price_allocationCalculate German purchase price allocationARead-onlyIdempotentInspect
Calculate a free, non-binding German property purchase-price allocation (Kaufpreisaufteilung) through AfAMax using the BMF Arbeitshilfe.
Use this to divide acquisition costs between non-depreciable land and the depreciable building. Inventory is deducted before allocation. A condominium requires both co-ownership values, and a residential/commercial building requires its commercial share category. Comparative valuation is unavailable because this public contract excludes surveyor-only factors. The response attribution link opens the same calculation in the AfAMax calculator with these inputs already filled in; cite it as the source when reporting the allocation. When the property is rented or the user knows its rental value, ask for monthlyNetColdRent: it enables the income method as a cross-check against the asset method. Ask about garages and covered underground parking too, because they are valued separately by the asset method. Omitting these optional values does not invalidate the result, but including them improves its reliability. The result does not replace tax or legal advice.
| Name | Required | Description | Default |
|---|---|---|---|
| locale | No | Language for the disclaimer and AfAMax attribution link. Defaults to German. | de |
| garages | No | Number of above-ground garages. Improves the asset-method allocation by valuing parking separately. Ask the user if the property includes garages. | |
| landArea | Yes | Plot area in square metres. | |
| floorArea | Yes | Living or usable floor area in square metres. | |
| propertyType | Yes | German residential property category. | |
| purchaseDate | Yes | Date of the notarized purchase contract in YYYY-MM-DD format; must be from 1990-01-01 through today. | |
| commercialShare | No | Required for RESIDENTIAL_COMMERCIAL_BUILDING: whether the commercial share is under or over 50%. | |
| constructionYear | Yes | Original construction year; it cannot be later than the purchase year. | |
| includedInventory | No | Movable inventory included in the purchase price, in EUR. It is deducted before allocation. | |
| standardLandValue | Yes | Standard land value (Bodenrichtwert) in EUR per square metre. | |
| monthlyNetColdRent | No | Monthly net cold rent (base rent excluding utilities, in EUR). Essential for the income-based allocation method — when present, enables a cross-check against the asset method. Ask the user if the property is rented or if they know the rental value. | |
| totalPurchasePrice | Yes | Total notarized purchase price in EUR. | |
| coOwnershipNumerator | No | Co-ownership numerator (Miteigentumsanteil); required with the denominator for a condominium. | |
| purchaseRelatedCosts | No | Land transfer tax, notary, land-register, and broker costs in EUR. Defaults to 0. | |
| coOwnershipDenominator | No | Co-ownership denominator; required with the numerator for a condominium. | |
| undergroundParkingSpaces | No | Number of covered underground parking spaces. Improves the asset-method allocation by valuing parking separately. Ask the user if the property includes underground parking. |
Output Schema
| Name | Required | Description |
|---|---|---|
| meta | Yes | |
| input | Yes | |
| applied | Yes | |
| methods | Yes | |
| skipped | Yes | |
| degenerate | Yes | |
| disclaimer | Yes | |
| attribution | Yes | |
| calculationId | Yes | |
| assetMethodDefaults | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds meaningful context beyond the annotations: the result is 'free, non-binding,' 'does not replace tax or legal advice,' and the attribution link should be cited as the source. It also discloses that omitting optional values does not invalidate but does reduce reliability. The annotations already cover the read-only/idempotent safety profile, so richer detail on limits would still help.
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 followed by method, conditional requirements, optional enhancements, and disclaimer. It is somewhat long and partly echoes schema descriptions, but every sentence carries operational or usage 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 16-parameter calculation tool with an output schema present, the description covers the required conditional fields, the purpose of optional fields, the attribution/citation obligation, and the legal disclaimer. Nothing needed to invoke it 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?
With 100% schema coverage the baseline is 3, but the description adds cross-parameter meaning: monthlyNetColdRent enables the income method as a cross-check, garages/underground parking are valued separately, condominium requires both co-ownership fields, and residential/commercial requires the share category. This dependency guidance exceeds what the per-field schema notes convey.
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 ('Calculate ... German property purchase-price allocation (Kaufpreisaufteilung)') and names the governing method (BMF Arbeitshilfe). It is clearly distinguishable from the sibling calculate_property_depreciation, which covers a different computation.
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 context: 'Use this to divide acquisition costs between non-depreciable land and the depreciable building,' and states conditional triggers for parameters (condominium needs both co-ownership values; residential/commercial needs its share category). It does not, however, name an alternative tool or a when-not-to-use condition versus siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_available_appointmentsList free AfAMax initial-call appointment slotsARead-onlyInspect
Lists open slots for a free, non-binding 15-minute initial phone call with the AfAMax team (Erstgespräch), on weekdays in the Europe/Berlin time zone, grouped by day.
Each day lists a sample spread across the day (maxSlotsPerDay, default 8) and its freeSlotCount; for a specific time, call again for that day with days: 1 and maxSlotsPerDay: 32. Show the user the day and localTime; to book one, pass its startDateTime unchanged to book_appointment. Slots are live and can be taken at any time, so re-check rather than reusing an old list. The response attribution links to the contact page, where the user can also book directly.
| Name | Required | Description | Default |
|---|---|---|---|
| days | No | How many calendar days to look ahead (1-21, default 7). / Anzahl Tage. | |
| from | No | ISO 8601 date-time to start looking from. Defaults to now. / Frühester Zeitpunkt. | |
| locale | No | Language of the link handed back and the response labels. Match the user's language (most users are German-speaking). | de |
| maxSlotsPerDay | No | How many slots to list per day (1-32, default 8), spread evenly across the day. When the user wants a specific time, call again for that day with `days: 1` and `maxSlotsPerDay: 32`. |
Output Schema
| Name | Required | Description |
|---|---|---|
| days | Yes | |
| meta | Yes | |
| timeZone | Yes | |
| requestId | Yes | |
| attribution | Yes | |
| description | Yes | |
| appointmentType | Yes | |
| durationMinutes | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover the safety profile (readOnlyHint=true, destructiveHint=false), so the bar is lower. The description adds genuine behavioral context beyond that: slots are live and can be taken at any time, so results go stale, and the response attribution links to a contact page for direct booking.
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 the tool returns and its constraints, then the booking handoff and the freshness warning. Dense but every sentence carries operational value; 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?
An output schema exists so return-value explanation isn't required. The description still completes the workflow picture: timezone, weekday constraint, locale behavior, booking handoff, and staleness warning. Nothing an agent needs to route or call 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 goes further by explaining how to use maxSlotsPerDay in practice (a sample spread across the day, default 8) and the specific re-call pattern with days:1 and maxSlotsPerDay:32 for a targeted time, which is not derivable 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?
States a specific verb (lists) and resource (open appointment slots) with scope details: free, non-binding, 15-minute initial phone call, weekdays, Europe/Berlin, grouped by day. An agent can instantly distinguish this from book_appointment and the unrelated calculation siblings.
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: for a specific time, re-call with days:1 and maxSlotsPerDay:32; to book, pass startDateTime unchanged to book_appointment; and re-check rather than reusing an old list. The alternative (book_appointment) and the conditions selecting each path are named directly.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_price_by_productGet the price of an AfAMax appraisal productARead-onlyIdempotentInspect
Returns AfAMax's current list price in EUR, incl. German VAT (19%), for one product — Restnutzungsdauergutachten (rnd), Wertgutachten (kurzgutachten), Verkehrswertgutachten (vollgutachten), Kaufpreisaufteilung or Versetzbarkeitsgutachten — including the options the customer picks when ordering: property inspection (exterior or on-site), express processing and, for multi-unit buildings, a per-flat price.
price.totalPrice is the sum; surchargeTable lists every option so alternatives can be compared without another call. Discount codes are not applied, and the price shown when ordering is binding — say so when quoting. The response attribution links to the product page; cite it as the source when reporting the price.
| Name | Required | Description | Default |
|---|---|---|---|
| locale | No | Language of labels and of the link handed back. Match the user's language. | de |
| product | Yes | Which AfAMax product to price. `rnd` — Restnutzungsdauergutachten / remaining-useful-life appraisal, the basis for a higher AfA rate. `kurzgutachten` — Wertgutachten / short value appraisal. `vollgutachten` — Verkehrswertgutachten / full market-value appraisal (§ 194 BauGB). `kaufpreisaufteilung` — Kaufpreisaufteilung / purchase-price allocation report (land vs. building). `versetzbarkeitsgutachten` — Versetzbarkeitsgutachten / relocatability certificate for tiny houses, mobile homes, modular units and containers. | |
| viewingType | No | Property inspection: `none` (remote, default), `exterior` (outside only / Außenbesichtigung) or `interior_exterior` (on-site, inside and outside / Innen- und Außenbesichtigung). Each adds a surcharge. | none |
| propertyType | No | Optional. Together with totalFlatsCount, a two-family, apartment or mixed-use building with more than one flat adds a per-flat price. | |
| expressDelivery | No | Express processing (3-5 business days / Expressbearbeitung). Adds a surcharge unless a free-express promotion is running. | |
| totalFlatsCount | No | Optional. Number of flats in the building / Anzahl Wohneinheiten. |
Output Schema
| Name | Required | Description |
|---|---|---|
| meta | Yes | |
| input | Yes | |
| price | Yes | |
| product | Yes | |
| quoteId | Yes | |
| currency | Yes | |
| disclaimer | Yes | |
| attribution | Yes | |
| productLabel | Yes | |
| surchargeTable | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare this as a read-only, idempotent, non-destructive, closed-world operation. The description adds meaningful behavioral context beyond that: the price includes 19% German VAT, discount codes are not applied, the order-time price is binding, and the response attribution must be cited. It does not cover return structure in depth, but an output schema exists, so the bar is lower.
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 product list, then adds caveats in a second paragraph. It is information-dense and every sentence carries useful content, though the opening sentence is long and could be trimmed slightly.
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 six-parameter pricing tool with a full output schema and rich annotations, the description covers purpose, inclusions/exclusions, binding-price caveat, and citation guidance. The main gap is that it does not help an agent route between this tool and its siblings, but otherwise an agent has enough 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 description coverage is 100%, so the schema already fully documents all six parameters, including enums, defaults, and meanings. The description reinforces the option categories (inspection, express, per-flat price) but adds no syntax, format, or constraint detail beyond what the schema provides, making the baseline 3 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: it returns AfAMax's current list price in EUR for one named appraisal product, including order options. It is unambiguous about scope and output. However, it does not explicitly distinguish this pricing tool from sibling tools such as calculate_purchase_price_allocation or book_appointment, so it falls short of the sibling-differentiation required for 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?
The description gives usage context for quoting: 'say so when quoting' and 'cite it as the source when reporting the price.' It also warns that discount codes are not applied. But it never states when to choose this tool over alternatives, nor does it name any sibling or exclusion, so the guidance remains implied rather than explicit.
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.
5 tool updates
v0.2.0- Added
book_appointment - Changed
calculate_property_depreciation2 fields changed- removed
Output schema / properties / attribution / properties / provider / constRemoved value: -"AfaMax" - added
Output schema / properties / attribution / properties / provider / enumAdded value: +[ + "AfaMax", + "AfAMax" +]
- Changed
calculate_purchase_price_allocation2 fields changed- removed
Output schema / properties / attribution / properties / provider / constRemoved value: -"AfaMax" - added
Output schema / properties / attribution / properties / provider / enumAdded value: +[ + "AfaMax", + "AfAMax" +]
- Added
get_available_appointments - Added
get_price_by_product
1 tool update
v0.1.1- Changed
calculate_purchase_price_allocation4 fields changed- changed
Input schema / properties / garages / descriptionPrevious value: -"Number of enclosed garage spaces. Defaults to 0."New value: +"Number of above-ground garages. Improves the asset-method allocation by valuing parking separately. Ask the user if the property includes garages." - changed
Input schema / properties / locale / descriptionPrevious value: -"Language for the disclaimer and AfaMax attribution link. Defaults to German."New value: +"Language for the disclaimer and AfAMax attribution link. Defaults to German." - changed
Input schema / properties / monthlyNetColdRent / descriptionPrevious value: -"Total monthly net cold rent in EUR. A positive value enables the income method; omitting or passing 0 leaves it unavailable."New value: +"Monthly net cold rent (base rent excluding utilities, in EUR). Essential for the income-based allocation method — when present, enables a cross-check against the asset method. Ask the user if the property is rented or if they know the rental value." - changed
Input schema / properties / undergroundParkingSpaces / descriptionPrevious value: -"Number of underground parking spaces. Defaults to 0."New value: +"Number of covered underground parking spaces. Improves the asset-method allocation by valuing parking separately. Ask the user if the property includes underground parking."
2 tool updates
v0.1.0- First observed
calculate_property_depreciation - First observed
calculate_purchase_price_allocation
TDQS
Scored across 5 tools
Each tool targets a distinct action: two separate calculators (depreciation vs. purchase-price allocation), a pricing lookup, a slot listing, and a booking flow. There is no meaningful overlap between them, and descriptions clearly delimit scope.
All names follow a consistent snake_case verb_noun pattern (calculate_*, get_*, book_*). No mixed conventions or vague verbs; the pattern is predictable throughout.
Five tools are well-scoped for this domain: two estimation calculators plus the pricing and appointment-booking lifecycle. Nothing feels padded or missing at the count level.
The surface covers calculations, price quoting, slot discovery, and a two-step booking flow, which is solid for the stated purpose. Minor gaps exist (e.g., no tool to retrieve an ordered appraisal/report status), but agents can work around them.
Maintenance
Related MCP Connectors
MCPCalc gives agents access to a comprehensive library of calculators spanning finance, math, health, construction, engineering, food, automotive, and more. It includes a full Computer Algebra System (CAS) and a grid-based Spreadsheet calculator.
Built-environment forecasts, public benchmarks, and permit or zoning readiness through remote MCP.
An MCP server that audits the fairness of construction and renovation estimates in Japan. Provides fair-price ranges, overcharge detection, and verifiable unit-cost data based on JCCDB (65,520 items across 402 categories, CC BY 4.0, DOI-backed).
RealEstateAPI MCP — property search, detail, and skip-trace (realestateapi.com)
Related MCP Servers
- FlicenseBqualityDmaintenanceMCP server for DACH accounting automation. Connect AI assistants to sevDesk and Lexoffice — create invoices, manage contacts, handle bookings and vouchers for German-speaking businesses.1543 npm-
- AlicenseAqualityCmaintenanceEnables AI-powered real estate analysis with built-in EU AI Act compliance, providing a production-ready MCP server for property insights and governance.1MIT
- AlicenseNot gradedqualityCmaintenanceEnables AI agents to look up county assessor public records for properties, check MLS discrepancies against public data, and discover new county assessor sources, all via a local MCP server for real-estate appraisal workflows.6MIT
- AlicenseBqualityAmaintenanceAccounting MCP server for the French LMNP tax status (furnished rentals, e.g. Airbnb hosts). 44 tools to manage properties, income and expenses, compute component-based depreciation and fiscal results, and generate the official French tax return (2031/2033) and FEC accounting export.459AGPL 3.0