← The evidence ledger
Evidence row 1003781
Observed , by probe.mcp/1.
- Kind
- mcp.tools
- About
- endpoint 344f1cc8-9307-450c-964b-65c9f8323eae
- Recorded
- Previous row
- None: the first of its kind about this subject
- Body SHA-256
- a3046c7c3a1084e3e7ad4b2945e8042f95e0679c826fe1e1a22e7dc789cf79b6
- Leaf
- 0x32800e2ecf354d1e088ff3c77c754360ac29fa33934594e3d4cce5e349b0318c
What was observed
{
"count": 23,
"tools": [
{
"description": "Analyse decoupling: the cost versus benefit of transferring one co-owner's share so a borrower is freed up for another purchase (including stamp duty).",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"buyer": {
"description": "The co-owner buying out the share and refinancing.",
"properties": {
"age": {
"default": 35,
"description": "Buyer's age in years; limits the loan tenure (age plus tenure at most 65), the LTV tier and, on a leasehold, the CPF usable.",
"maximum": 80,
"minimum": 21,
"type": "integer"
},
"citizenship": {
"default": "singaporean",
"description": "Buyer's residency status; sets the ABSD on taking over the share and in the comparison `options`.",
"enum": [
"singaporean",
"pr",
"foreigner"
],
"type": "string"
},
"cpfInOA": {
"default": 0,
"description": "Buyer's CPF Ordinary Account balance available for the downpayment, in SGD.",
"minimum": 0,
"type": "number"
},
"financingPercent": {
"description": "Loan-to-value percentage to borrow against the seller's share: 75 and 55 are first-housing-loan tiers, 45 and 25 second-loan tiers. It can only lower what the buyer's age and tenure allow; omit to use the highest allowed.",
"enum": [
75,
55,
45,
25
],
"type": "number"
},
"legalFees": {
"default": 3000,
"description": "Buyer's conveyancing fees, in SGD; part of the buyer's cash required.",
"minimum": 0,
"type": "number"
},
"loanInterestRate": {
"default": 2.6,
"description": "Annual rate assumed for the buyer's new loan, as a percentage (e.g. 2.6 = 2.6%); sets the monthly instalment.",
"maximum": 15,
"minimum": 0.1,
"type": "number"
},
"remainingLeaseYears": {
"description": "Remaining lease on the property, in years; caps the loan tenure and, when short, the CPF the buyer may use. Omit for freehold.",
"maximum": 99,
"minimum": 0,
"type": "number"
}
},
"type": "object"
},
"newPropertyPrice": {
"description": "Price of a subsequent property purchase the freed-up buyer plans, in SGD.",
"minimum": 0,
"type": "number"
},
"outstandingLoan": {
"default": 0,
"description": "Loan still owed on the whole property, in SGD; split between the parties by share.",
"minimum": 0,
"type": "number"
},
"seller": {
"description": "The co-owner transferring out their share.",
"properties": {
"citizenship": {
"default": "singaporean",
"description": "Seller's residency status; sets their ABSD rate in the purchase comparison `options`.",
"enum": [
"singaporean",
"pr",
"foreigner"
],
"type": "string"
},
"cpfUsageInterest": {
"default": 0,
"description": "CPF the seller used on the property plus accrued interest, in SGD; refunded to their CPF out of the seller's proceeds.",
"minimum": 0,
"type": "number"
},
"legalFees": {
"default": 3000,
"description": "Seller's conveyancing fees, in SGD; deducted from the seller's proceeds.",
"minimum": 0,
"type": "number"
},
"sellerStampDuty": {
"default": 0,
"description": "Seller's Stamp Duty on the transfer, in SGD; deducted from the seller's proceeds.",
"minimum": 0,
"type": "number"
},
"shares": {
"default": 50,
"description": "Seller's ownership share, in percent, which the buyer takes over. The buyer already holds the rest.",
"maximum": 100,
"minimum": 0,
"type": "number"
}
},
"type": "object"
},
"valuation": {
"description": "Current market value of the whole property, in SGD; each party's share is valued pro rata.",
"minimum": 0,
"type": "number"
}
},
"required": [
"valuation",
"seller",
"buyer"
],
"type": "object"
},
"name": "analyze_decoupling"
},
{
"description": "Analyse a 'sell one, buy two' plan where two co-owners sell their joint home. Returns the sale proceeds (cash after loan, CPF refunds, SSD and legal fees) and each buyer's resulting cash and CPF. With `buy1`, it compares buying one replacement jointly or under either buyer alone; with `buy2Property1` and `buy2Property2`, each buyer buying one property (both pairings). Every option is given at 30- and 35-year tenures with max loan, LTV, instalment, downpayment, stamp duties, cash/CPF shortfalls, TDSR used and an affordability verdict.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"buy1": {
"description": "The single property in the \"buy one\" scenario.",
"properties": {
"legalFees": {
"default": 3000,
"description": "Conveyancing fees for buying this property, in SGD; part of the cash required.",
"minimum": 0,
"type": "number"
},
"loanInterestRate": {
"default": 2.6,
"description": "Annual rate assumed for this loan, as a percentage (e.g. 2.6 = 2.6%); sets the instalment. Affordability is tested at the higher of this and the MAS 4% floor.",
"maximum": 15,
"minimum": 0.1,
"type": "number"
},
"propertyPrice": {
"description": "Price of the property to buy, in SGD; loan, downpayment and stamp duties follow from it.",
"minimum": 0,
"type": "number"
},
"remainingLeaseYears": {
"description": "Remaining lease in years; omit for freehold. When the lease will not last until the youngest buyer turns 95, the CPF usable on this property is prorated (none below 20 years).",
"maximum": 99,
"minimum": 0,
"type": "number"
}
},
"required": [
"propertyPrice"
],
"type": "object"
},
"buy2Property1": {
"description": "First property in the \"buy two\" scenario.",
"properties": {
"legalFees": {
"default": 3000,
"description": "Conveyancing fees for buying this property, in SGD; part of the cash required.",
"minimum": 0,
"type": "number"
},
"loanInterestRate": {
"default": 2.6,
"description": "Annual rate assumed for this loan, as a percentage (e.g. 2.6 = 2.6%); sets the instalment. Affordability is tested at the higher of this and the MAS 4% floor.",
"maximum": 15,
"minimum": 0.1,
"type": "number"
},
"propertyPrice": {
"description": "Price of the property to buy, in SGD; loan, downpayment and stamp duties follow from it.",
"minimum": 0,
"type": "number"
},
"remainingLeaseYears": {
"description": "Remaining lease in years; omit for freehold. When the lease will not last until the youngest buyer turns 95, the CPF usable on this property is prorated (none below 20 years).",
"maximum": 99,
"minimum": 0,
"type": "number"
}
},
"required": [
"propertyPrice"
],
"type": "object"
},
"buy2Property2": {
"description": "Second property in the \"buy two\" scenario.",
"properties": {
"legalFees": {
"default": 3000,
"description": "Conveyancing fees for buying this property, in SGD; part of the cash required.",
"minimum": 0,
"type": "number"
},
"loanInterestRate": {
"default": 2.6,
"description": "Annual rate assumed for this loan, as a percentage (e.g. 2.6 = 2.6%); sets the instalment. Affordability is tested at the higher of this and the MAS 4% floor.",
"maximum": 15,
"minimum": 0.1,
"type": "number"
},
"propertyPrice": {
"description": "Price of the property to buy, in SGD; loan, downpayment and stamp duties follow from it.",
"minimum": 0,
"type": "number"
},
"remainingLeaseYears": {
"description": "Remaining lease in years; omit for freehold. When the lease will not last until the youngest buyer turns 95, the CPF usable on this property is prorated (none below 20 years).",
"maximum": 99,
"minimum": 0,
"type": "number"
}
},
"required": [
"propertyPrice"
],
"type": "object"
},
"buyer1": {
"description": "Income/CPF profile of buyer 1.",
"properties": {
"age": {
"default": 35,
"description": "Buyer age in years. With income it sets the income-weighted average age, which picks the LTV tier (loan running past 65) and, on a short lease, the CPF usable.",
"maximum": 80,
"minimum": 21,
"type": "integer"
},
"citizenship": {
"default": "singaporean",
"description": "Buyer's residency status; sets the ABSD rate. On a joint purchase buyer 1's status is used.",
"enum": [
"singaporean",
"pr",
"foreigner"
],
"type": "string"
},
"cpfOA": {
"default": 0,
"description": "CPF Ordinary Account balance before the sale, in SGD; added to the CPF refunded from the sale.",
"minimum": 0,
"type": "number"
},
"isVariableIncome": {
"default": false,
"description": "True when monthlyIncome is variable (commission or bonus), so only 70% of it counts towards TDSR.",
"type": "boolean"
},
"miscIncome": {
"default": 0,
"description": "Other monthly income, in SGD; 70% of it counts towards TDSR.",
"minimum": 0,
"type": "number"
},
"monthlyDebt": {
"default": 0,
"description": "Monthly repayments on other debts (car, personal loans, cards), in SGD; reduce TDSR headroom.",
"minimum": 0,
"type": "number"
},
"monthlyIncome": {
"description": "Gross monthly employment income, in SGD; counts towards TDSR.",
"minimum": 0,
"type": "number"
}
},
"required": [
"monthlyIncome"
],
"type": "object"
},
"buyer1CpfUsage": {
"default": 0,
"description": "CPF (with accrued interest) buyer 1 must refund on sale, in SGD.",
"minimum": 0,
"type": "number"
},
"buyer1Shares": {
"default": 50,
"description": "Buyer 1's ownership share of the sold property, in percent; splits the cash proceeds.",
"maximum": 100,
"minimum": 0,
"type": "number"
},
"buyer2": {
"description": "Income/CPF profile of buyer 2.",
"properties": {
"age": {
"default": 35,
"description": "Buyer age in years. With income it sets the income-weighted average age, which picks the LTV tier (loan running past 65) and, on a short lease, the CPF usable.",
"maximum": 80,
"minimum": 21,
"type": "integer"
},
"citizenship": {
"default": "singaporean",
"description": "Buyer's residency status; sets the ABSD rate. On a joint purchase buyer 1's status is used.",
"enum": [
"singaporean",
"pr",
"foreigner"
],
"type": "string"
},
"cpfOA": {
"default": 0,
"description": "CPF Ordinary Account balance before the sale, in SGD; added to the CPF refunded from the sale.",
"minimum": 0,
"type": "number"
},
"isVariableIncome": {
"default": false,
"description": "True when monthlyIncome is variable (commission or bonus), so only 70% of it counts towards TDSR.",
"type": "boolean"
},
"miscIncome": {
"default": 0,
"description": "Other monthly income, in SGD; 70% of it counts towards TDSR.",
"minimum": 0,
"type": "number"
},
"monthlyDebt": {
"default": 0,
"description": "Monthly repayments on other debts (car, personal loans, cards), in SGD; reduce TDSR headroom.",
"minimum": 0,
"type": "number"
},
"monthlyIncome": {
"description": "Gross monthly employment income, in SGD; counts towards TDSR.",
"minimum": 0,
"type": "number"
}
},
"required": [
"monthlyIncome"
],
"type": "object"
},
"buyer2CpfUsage": {
"default": 0,
"description": "CPF (with accrued interest) buyer 2 must refund on sale, in SGD.",
"minimum": 0,
"type": "number"
},
"buyer2Shares": {
"description": "Buyer 2's ownership share of the sold property, in percent; splits the cash proceeds. Omit to use 100 minus buyer1Shares.",
"maximum": 100,
"minimum": 0,
"type": "number"
},
"outstandingLoan": {
"default": 0,
"description": "Loan still owed on the property being sold, repaid from the sale, in SGD.",
"minimum": 0,
"type": "number"
},
"sellerStampDuty": {
"default": 0,
"description": "Seller's Stamp Duty payable on the sale, in SGD.",
"minimum": 0,
"type": "number"
},
"sellingLegalFees": {
"default": 3000,
"description": "Conveyancing fees for the sale, deducted from the proceeds, in SGD.",
"minimum": 0,
"type": "number"
},
"valuation": {
"description": "Expected sale price of the jointly owned property being sold, in SGD.",
"minimum": 0,
"type": "number"
}
},
"required": [
"valuation",
"buyer1",
"buyer2"
],
"type": "object"
},
"name": "analyze_sell_one_buy_two"
},
{
"description": "Estimate the maximum loan and property price a borrower can afford from income, existing debt commitments and tenure, applying Singapore TDSR/MSR limits. Use this when you know the income and want the budget; to go the other way (a target price → the income needed), use `calculate_required_income`.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"age": {
"default": 35,
"description": "Age of the (oldest) borrower.",
"maximum": 80,
"minimum": 21,
"type": "integer"
},
"cashSavings": {
"default": 0,
"description": "Cash available for downpayment, in SGD.",
"minimum": 0,
"type": "number"
},
"citizenship": {
"default": "singaporean",
"description": "Buyer citizenship: singaporean, pr or foreigner. Drives ABSD rate.",
"enum": [
"singaporean",
"pr",
"foreigner"
],
"type": "string"
},
"cpfOA": {
"default": 0,
"description": "CPF Ordinary Account balance usable, in SGD.",
"minimum": 0,
"type": "number"
},
"existingPropertiesOwned": {
"description": "Count of residential properties already owned; sets the ABSD tier (0, 1 or 2+). Takes precedence over existingProperty when provided.",
"maximum": 10,
"minimum": 0,
"type": "integer"
},
"existingProperty": {
"default": false,
"description": "True if the borrower already owns ≥1 property (affects ABSD and LTV).",
"type": "boolean"
},
"interestRate": {
"default": 4,
"description": "Assumed annual interest rate, as a percentage (e.g. 4.0 = 4%, not 0.04).",
"maximum": 15,
"minimum": 0.1,
"type": "number"
},
"loanTenureYears": {
"default": 25,
"description": "Repayment period, in years, over which the maximum loan is sized.",
"maximum": 35,
"minimum": 1,
"type": "integer"
},
"monthlyDebt": {
"default": 0,
"description": "Total existing monthly debt commitments (other loans, cards), in SGD.",
"minimum": 0,
"type": "number"
},
"monthlyFixedIncome": {
"description": "Gross fixed monthly income (salary), in SGD.",
"minimum": 0,
"type": "number"
},
"monthlyVariableIncome": {
"default": 0,
"description": "Gross variable monthly income (bonus/commission), in SGD; haircut 30% under TDSR.",
"minimum": 0,
"type": "number"
},
"propertyType": {
"default": "hdb",
"description": "Property type: hdb, ec (Executive Condominium) or private. Sets MSR/LTV rules.",
"enum": [
"hdb",
"ec",
"private"
],
"type": "string"
},
"stressTestRate": {
"description": "Override the TDSR/MSR stress-test rate (percentage); defaults to the MAS floor.",
"maximum": 15,
"minimum": 0.1,
"type": "number"
}
},
"required": [
"monthlyFixedIncome"
],
"type": "object"
},
"name": "calculate_affordability"
},
{
"description": "Generate a step-by-step dated timeline for an HDB resale purchase, from securing the Option to Purchase through to completion and key collection. Returns the ordered steps (what happens, the date, any payment due and its CPF/cash split), a summary (total payments, CPF and cash totals, completion date, duration in days), BSD and ABSD, the funding split (LTV, downpayment, minimum cash, cash-or-CPF remainder, monthly instalment when a rate and tenure are given), the completion date used, and self-checks.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"buyerType": {
"default": "singaporean",
"description": "Residency or legal status of the buyer; sets the ABSD rate.",
"enum": [
"singaporean",
"pr",
"foreigner",
"entity",
"trust"
],
"type": "string"
},
"completionDate": {
"description": "Completion date (ISO 8601). Defaults to exerciseDate + 70 calendar days if not provided.",
"type": "string"
},
"cpfUsage": {
"default": 0,
"description": "CPF OA savings the buyer will put towards the purchase, in SGD. Drawn down in step order against the legal fee and completion payment, the only payments CPF may make; each payment reports its `cpf` and `cash` parts.",
"minimum": 0,
"type": "number"
},
"exerciseDate": {
"description": "Date the option is exercised (ISO 8601).",
"type": "string"
},
"exerciseFee": {
"default": 4000,
"description": "Fee paid to the seller when the option is exercised, in SGD.",
"minimum": 0,
"type": "number"
},
"existingPropertiesOwned": {
"default": 0,
"description": "Residential properties the buyer already owns; sets the ABSD tier.",
"maximum": 10,
"minimum": 0,
"type": "integer"
},
"interestRate": {
"description": "Annual loan interest rate, as a percentage (e.g. 3.5 = 3.5%). Supply with tenureYears to get `funding.monthlyInstalment`; otherwise it is null.",
"maximum": 15,
"minimum": 0.1,
"type": "number"
},
"legalFee": {
"default": 2000,
"description": "Conveyancing fee for the purchase, in SGD; part of the total outlay.",
"minimum": 0,
"type": "number"
},
"loanAmount": {
"default": 0,
"description": "Housing loan amount, in SGD; 0 for a cash purchase. Sets the LTV band, the minimum cash and the completion payment.",
"minimum": 0,
"type": "number"
},
"optionDate": {
"description": "Date the Option to Purchase is granted, e.g. 2026-08-01; the timeline starts here.",
"type": "string"
},
"optionExpiryDate": {
"description": "Last day to exercise the option (ISO 8601).",
"type": "string"
},
"optionFee": {
"default": 1000,
"description": "Fee paid to the seller when the Option to Purchase is granted, in SGD; HDB caps it at $1,000.",
"minimum": 0,
"type": "number"
},
"otherFees": {
"default": 0,
"description": "Other costs (valuation, repairs, admin), in SGD. Reported alongside legal fees and stamp duty as part of the total outlay.",
"minimum": 0,
"type": "number"
},
"purchasePrice": {
"description": "Agreed resale price of the HDB flat, in SGD; sets the stamp duties and downpayment.",
"minimum": 1,
"type": "number"
},
"tenureYears": {
"description": "Loan tenure in years. Supply with interestRate to get `funding.monthlyInstalment`.",
"maximum": 35,
"minimum": 1,
"type": "integer"
}
},
"required": [
"purchasePrice",
"optionDate",
"optionExpiryDate",
"exerciseDate"
],
"type": "object"
},
"name": "calculate_hdb_resale_timeline"
},
{
"description": "Compute the monthly repayment, total interest and total cost for a hypothetical loan from an interest rate you supply (standard amortisation). Use this for \"what-if\" rates; for the real rates of a specific package the borrower has chosen, use `calculate_package_schedule` instead.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"interestRate": {
"description": "Hypothetical annual interest rate held for the whole tenure, as a percentage (e.g. 3.5 = 3.5%, not 0.035).",
"maximum": 15,
"minimum": 0.1,
"type": "number"
},
"loanAmount": {
"description": "Amount borrowed, in SGD.",
"maximum": 200000000,
"minimum": 50000,
"type": "number"
},
"tenureYears": {
"description": "Loan tenure in years.",
"maximum": 35,
"minimum": 1,
"type": "integer"
}
},
"required": [
"loanAmount",
"interestRate",
"tenureYears"
],
"type": "object"
},
"name": "calculate_mortgage_repayment"
},
{
"description": "Compute the stamp duty payable on a mortgage/loan facility.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"loanAmount": {
"description": "Mortgage/loan facility amount, in SGD.",
"minimum": 0,
"type": "number"
}
},
"required": [
"loanAmount"
],
"type": "object"
},
"name": "calculate_mortgage_stamp_duty"
},
{
"description": "Compute the amortisation schedule for a SPECIFIC mortgage package using that package's real effective rates. Use this once the borrower has picked a package from `recommend_packages`; for a hypothetical \"what-if\" rate the borrower does not yet hold a package for, use `calculate_mortgage_repayment` instead.\n\nPass a `packageId` from `recommend_packages`, plus `loanAmount` and `tenureYears`. Always returns the full canonical schedule: loan facts (`context`), the per-tier breakdown (`periods`), rate structure, totals, and the per-year schedule (`annual`).\n\nThe month-by-month schedule (`monthly`) is empty unless you pass `includeMonthly: true`. To also generate downloadable files, pass `formats` (`[\"pdf\"]`, `[\"xlsx\"]`, or both) — the public URLs come back under `documents` (null otherwise). Optional `firstPaymentDate` (YYYY-MM-DD, defaults to next month) dates the schedule.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"firstPaymentDate": {
"description": "First repayment month as an ISO date (YYYY-MM-DD). Defaults to next month.",
"format": "date",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
"type": "string"
},
"formats": {
"description": "Document formats to generate and upload (pdf, xlsx); the resulting download URLs are returned under `documents`. Omit/empty for data only.",
"items": {
"enum": [
"pdf",
"xlsx"
],
"type": "string"
},
"type": "array"
},
"includeMonthly": {
"description": "Include the full month-by-month schedule (`monthly[]`) in the response. Omitted/false returns an empty `monthly[]` to keep the payload small.",
"type": "boolean"
},
"loanAmount": {
"description": "Amount borrowed under this package, in SGD.",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
"maskBankIdentity": {
"description": "When true and the bank has maskIdentity set, replace the bank name with \"Confidential Rate\" and hide the logo in generated documents.",
"type": "boolean"
},
"packageId": {
"description": "Package id, as returned by `recommend_packages`.",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
"type": "string"
},
"tenureYears": {
"description": "Repayment period of the loan, in years; the schedule amortises over it.",
"maximum": 35,
"minimum": 1,
"type": "integer"
}
},
"required": [
"packageId",
"loanAmount",
"tenureYears"
],
"type": "object"
},
"name": "calculate_package_schedule"
},
{
"description": "Generate a step-by-step dated timeline for a private (non-HDB) resale purchase, with the 1% option fee, 4% exercise payment, stamp duties and completion payment at the right steps. Exercise date defaults to 14 calendar days inclusive of the option date if not entered.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"buyerType": {
"default": "singaporean",
"description": "Residency or legal status of the buyer; sets the ABSD rate.",
"enum": [
"singaporean",
"pr",
"foreigner",
"entity",
"trust"
],
"type": "string"
},
"completionDate": {
"description": "Completion date (ISO 8601). Defaults to exerciseDate + 70 calendar days if not provided.",
"type": "string"
},
"cpfUsage": {
"default": 0,
"description": "CPF OA savings the buyer will put towards the purchase, in SGD. Drawn down in step order against the legal fee and completion payment, the only payments CPF may make; each payment reports its `cpf` and `cash` parts.",
"minimum": 0,
"type": "number"
},
"exerciseDate": {
"description": "Exercise date (ISO 8601). Defaults to optionDate + 13 calendar days if not provided.",
"type": "string"
},
"existingPropertiesOwned": {
"default": 0,
"description": "Residential properties the buyer already owns; sets the ABSD tier.",
"maximum": 10,
"minimum": 0,
"type": "integer"
},
"interestRate": {
"description": "Annual loan interest rate, as a percentage (e.g. 3.5 = 3.5%). Supply with tenureYears to get `funding.monthlyInstalment`; otherwise it is null.",
"maximum": 15,
"minimum": 0.1,
"type": "number"
},
"legalFee": {
"default": 2500,
"description": "Conveyancing fee for the purchase, in SGD; part of the total outlay.",
"minimum": 0,
"type": "number"
},
"loanAmount": {
"default": 0,
"description": "Housing loan amount, in SGD; 0 for a cash purchase. Sets the LTV band, the minimum cash and the completion payment.",
"minimum": 0,
"type": "number"
},
"optionDate": {
"description": "Option to Purchase date (ISO 8601).",
"type": "string"
},
"optionExpiryDate": {
"description": "Last day to exercise the option (ISO 8601).",
"type": "string"
},
"otherFees": {
"default": 0,
"description": "Other costs (valuation, repairs, admin), in SGD. Reported alongside legal fees and stamp duty as part of the total outlay.",
"minimum": 0,
"type": "number"
},
"purchasePrice": {
"description": "Agreed purchase price of the private property, in SGD; sets the option fee, exercise payment, stamp duties and downpayment.",
"minimum": 1,
"type": "number"
},
"tenureYears": {
"description": "Loan tenure in years. Supply with interestRate to get `funding.monthlyInstalment`.",
"maximum": 35,
"minimum": 1,
"type": "integer"
}
},
"required": [
"purchasePrice",
"optionDate",
"optionExpiryDate"
],
"type": "object"
},
"name": "calculate_private_resale_timeline"
},
{
"description": "Model the monthly instalment profile of a Singapore Building Under Construction (BUC) property loan across progressive payment stages. Handles fixed and floating rate packages, per-stage cash/CPF/loan funding split, drawdown timing, rate stepping by year, and optional prepayments. Set includeSchedule to true for the full month-by-month amortisation schedule (summary is always included).",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"availableCpfOA": {
"description": "Available CPF Ordinary Account balance, in SGD. When set, each stage’s equity CPF portion is capped at the remaining OA balance and the rest is funded by cash. When omitted, CPF covers all equity above the minimum-cash floor.",
"minimum": 0,
"type": "number"
},
"cscOffsetMonths": {
"default": 12,
"description": "Months from TOP to CSC (default 12).",
"maximum": 9007199254740991,
"minimum": 0,
"type": "integer"
},
"includeSchedule": {
"default": false,
"description": "If true, include the full month-by-month amortisation schedule in output.",
"type": "boolean"
},
"loanAmount": {
"description": "Loan amount in SGD. Takes precedence over loanQuantum.",
"minimum": 0,
"type": "number"
},
"loanQuantum": {
"description": "Loan as a fraction of the price (e.g. 0.75 = 75%). Used only when loanAmount is omitted; with neither, 75% is assumed.",
"maximum": 0.9,
"minimum": 0,
"type": "number"
},
"lockInMonths": {
"default": 0,
"description": "Lock-in period in months from first drawdown.",
"maximum": 9007199254740991,
"minimum": 0,
"type": "integer"
},
"minimumCashPercent": {
"default": 5,
"description": "Minimum cash downpayment as a percentage of the purchase price (e.g. 5 = 5%); CPF or cash covers the rest of the equity.",
"maximum": 100,
"minimum": 0,
"type": "number"
},
"otpDate": {
"description": "Option to Purchase date (ISO 8601).",
"type": "string"
},
"prepaymentOutcome": {
"default": "reduceInstalment",
"description": "What happens after a prepayment: lower instalment or shorter tenure.",
"enum": [
"reduceInstalment",
"shortenTenure"
],
"type": "string"
},
"prepaymentPenaltyPercent": {
"default": 0,
"description": "Penalty as a percentage of prepaid amount if within lock-in period.",
"minimum": 0,
"type": "number"
},
"prepayments": {
"default": [],
"description": "Optional list of prepayments.",
"items": {
"properties": {
"amount": {
"description": "Prepayment amount, in SGD.",
"minimum": 0,
"type": "number"
},
"month": {
"description": "Loan month of the prepayment, counting from 1 at the first drawdown (as in `schedule[].month`).",
"maximum": 9007199254740991,
"minimum": 1,
"type": "integer"
}
},
"required": [
"month",
"amount"
],
"type": "object"
},
"type": "array"
},
"purchasePrice": {
"description": "Purchase price of the BUC property, in SGD; each stage's payment is a share of it.",
"minimum": 1,
"type": "number"
},
"rateMode": {
"default": "fixed",
"description": "How each year's rate is set: 'fixed' takes it from ratePerYear; 'floating' uses referenceRate plus that year's spreadPerYear and ignores ratePerYear.",
"enum": [
"fixed",
"floating"
],
"type": "string"
},
"ratePerYear": {
"description": "Annual interest rates by year as percentages (e.g. [2.5, 2.5, 3.0, 3.5, 3.5, 3.5] for years 1-5 and thereafter). Last value applies to all subsequent years.",
"items": {
"minimum": 0,
"type": "number"
},
"minItems": 1,
"type": "array"
},
"referenceRate": {
"description": "Floating mode only: the benchmark rate such as 3M SORA, as a percentage (e.g. 3.5 = 3.5%), to which each year's spread is added. Omitted, it is taken as 0, so the rate is the spread alone. Ignored in fixed mode.",
"minimum": 0,
"type": "number"
},
"spreadPerYear": {
"description": "Spread per year for floating mode, as percentages. Last value applies to all subsequent years.",
"items": {
"type": "number"
},
"type": "array"
},
"stages": {
"description": "Custom stage schedule. Defaults to the standard 10-stage BUC schedule. Percentages must sum to 100.",
"items": {
"properties": {
"name": {
"description": "Stage name (e.g. \"Foundation work\").",
"type": "string"
},
"percent": {
"description": "Share of the purchase price payable at this stage, in percent.",
"maximum": 100,
"minimum": 0,
"type": "number"
}
},
"required": [
"name",
"percent"
],
"type": "object"
},
"type": "array"
},
"tenureYears": {
"description": "Loan tenure in years, counted from the first drawdown.",
"maximum": 35,
"minimum": 1,
"type": "integer"
},
"topDate": {
"description": "Expected Temporary Occupation Permit date (ISO 8601).",
"type": "string"
}
},
"required": [
"purchasePrice",
"tenureYears",
"otpDate",
"topDate",
"ratePerYear"
],
"type": "object"
},
"name": "calculate_progressive_payment"
},
{
"description": "Calculate the full upfront cost of purchasing a Singapore residential property (HDB or private resale), with each cost line attributed to its funding source (cash, CPF or bank loan). Returns option fee, exercise fee, stamp duties (BSD and ABSD), downpayment breakdown, and a sufficiency check against available funds.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"availableCash": {
"default": 0,
"description": "Cash the buyer can put towards the purchase, in SGD; checked in `cashSufficiency`.",
"minimum": 0,
"type": "number"
},
"availableCpfOA": {
"default": 0,
"description": "CPF Ordinary Account balance the buyer can put towards the purchase, in SGD; checked in `cpfSufficiency`.",
"minimum": 0,
"type": "number"
},
"buyerType": {
"default": "singaporean",
"description": "Residency or legal status of the buyer; sets the ABSD rate.",
"enum": [
"singaporean",
"pr",
"foreigner",
"entity",
"trust"
],
"type": "string"
},
"cpfFirst": {
"description": "When true, fund CPF-eligible costs from a single CPF pool capped at availableCpfOA (CPF first, remainder cash), overriding the per-item cash/cpf funding sources. ABSD stays cash.",
"type": "boolean"
},
"existingPropertiesOwned": {
"default": 0,
"description": "Residential properties the buyer already owns; sets the ABSD tier.",
"maximum": 10,
"minimum": 0,
"type": "integer"
},
"legalFeeFunding": {
"default": "cash",
"description": "Pay the legal/conveyancing fee from cash or from CPF.",
"enum": [
"cash",
"cpf"
],
"type": "string"
},
"legalFeeOverride": {
"description": "Legal/conveyancing fee to use instead of the standard estimate ($2,000 HDB, $3,000 private), in SGD.",
"minimum": 0,
"type": "number"
},
"loanAmount": {
"description": "Bank loan amount, in SGD. Takes precedence over `ltv`; with neither, a 75% loan is assumed.",
"minimum": 0,
"type": "number"
},
"ltv": {
"description": "Loan as a fraction of the purchase price (e.g. 0.75 = 75%). Used only when loanAmount is omitted.",
"maximum": 0.9,
"minimum": 0,
"type": "number"
},
"minimumCashPercent": {
"default": 5,
"description": "Minimum cash component as a percentage of price: 5 or 10 on a first housing loan, 25 with one already outstanding.",
"type": "number"
},
"propertyType": {
"description": "Whether this is an HDB resale flat or a private property; sets the option and exercise fees, default legal and valuation fees, and stamp-duty funding.",
"enum": [
"hdb",
"private"
],
"type": "string"
},
"purchasePrice": {
"description": "Agreed purchase price, in SGD; fees, stamp duties and downpayment follow from it.",
"minimum": 1,
"type": "number"
},
"stampDutyFunding": {
"description": "Pay the stamp duties (BSD and ABSD) from cash or from CPF. Omit for the usual convention: HDB pays BSD from CPF, private from cash, and ABSD is paid in cash.",
"enum": [
"cash",
"cpf"
],
"type": "string"
},
"valuationFeeOverride": {
"description": "Override for valuation fee, in SGD. Defaults to $120 (HDB) or $350 (private).",
"minimum": 0,
"type": "number"
}
},
"required": [
"propertyType",
"purchasePrice"
],
"type": "object"
},
"name": "calculate_purchase_cost"
},
{
"description": "Compare a borrower's existing mortgage against a new rate and report monthly savings, total savings and break-even months. Set `mode` to 'original' (supply the original loan amount, tenure and start date) or 'remaining' (supply the current outstanding balance and remaining tenure).",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"currentRate": {
"description": "Annual rate on the existing loan, as a percentage (e.g. 4.0 = 4%).",
"maximum": 15,
"minimum": 0.1,
"type": "number"
},
"earlyRedemptionPenalty": {
"default": 0,
"description": "Penalty the current bank charges for repaying within its lock-in, in SGD; treated as a switching cost like refinancingCosts.",
"minimum": 0,
"type": "number"
},
"loanStartMonth": {
"description": "Mode 'original': month the loan started, as a number (1 = January).",
"maximum": 12,
"minimum": 1,
"type": "integer"
},
"loanStartYear": {
"description": "Mode 'original': calendar year the loan started, e.g. 2021.",
"maximum": 2100,
"minimum": 1990,
"type": "integer"
},
"mode": {
"description": "Use 'original' when supplying the loan's original terms and start date, 'remaining' when supplying the current outstanding balance and tenure left.",
"enum": [
"original",
"remaining"
],
"type": "string"
},
"newRate": {
"description": "Annual rate offered on the new loan, as a percentage (e.g. 3.2 = 3.2%).",
"maximum": 15,
"minimum": 0.1,
"type": "number"
},
"newTenureYears": {
"description": "Tenure of the new loan, in years. Omit to keep the current loan’s remaining tenure.",
"maximum": 35,
"minimum": 1,
"type": "integer"
},
"originalLoanAmount": {
"description": "Mode 'original': the amount first borrowed, in SGD. Today's balance is worked out from it.",
"minimum": 0,
"type": "number"
},
"originalTenureYears": {
"description": "Mode 'original': the tenure the loan was first taken over, in years.",
"maximum": 35,
"minimum": 1,
"type": "integer"
},
"refinancingCosts": {
"default": 2500,
"description": "One-off cost of switching (legal and valuation fees), in SGD; deducted from the savings and recouped in the break-even.",
"minimum": 0,
"type": "number"
},
"remainingAmount": {
"description": "Mode 'remaining': the balance still owed today, in SGD.",
"minimum": 0,
"type": "number"
},
"remainingTenureYears": {
"description": "Mode 'remaining': years left to repay on the current loan.",
"maximum": 35,
"minimum": 1,
"type": "integer"
}
},
"required": [
"mode",
"currentRate",
"newRate"
],
"type": "object"
},
"name": "calculate_refinance_savings"
},
{
"description": "Compute the stamp duty payable on a property lease from the rent and lease term.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"hasPremium": {
"default": false,
"description": "True if the lease carries a lump-sum premium.",
"type": "boolean"
},
"leasePeriodMonths": {
"default": 12,
"description": "Lease term in months.",
"maximum": 1200,
"minimum": 1,
"type": "integer"
},
"monthlyRent": {
"description": "Monthly rent under the lease, in SGD.",
"minimum": 0,
"type": "number"
},
"premiumAmount": {
"default": 0,
"description": "One-off premium paid on top of the rent, in SGD; only counted when `hasPremium` is true.",
"minimum": 0,
"type": "number"
}
},
"required": [
"monthlyRent"
],
"type": "object"
},
"name": "calculate_rental_stamp_duty"
},
{
"description": "Reverse affordability: work out the gross monthly income needed to support a target property price under Singapore TDSR/MSR limits. Use this when you know the target property price; to go the other way (income → maximum budget), use `calculate_affordability`.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"age": {
"default": 35,
"description": "Age of the (oldest) borrower.",
"maximum": 80,
"minimum": 21,
"type": "integer"
},
"cashSavings": {
"default": 0,
"description": "Cash available for downpayment, in SGD.",
"minimum": 0,
"type": "number"
},
"citizenship": {
"default": "singaporean",
"description": "Buyer's residency status (Singapore citizen, permanent resident or foreigner); sets the ABSD rate.",
"enum": [
"singaporean",
"pr",
"foreigner"
],
"type": "string"
},
"cpfOA": {
"default": 0,
"description": "CPF Ordinary Account balance usable, in SGD.",
"minimum": 0,
"type": "number"
},
"existingPropertiesOwned": {
"description": "Count of residential properties already owned; sets the ABSD tier (0, 1 or 2+). Takes precedence over existingProperty when provided.",
"maximum": 10,
"minimum": 0,
"type": "integer"
},
"existingProperty": {
"default": false,
"description": "True if the borrower already owns ≥1 property (affects ABSD and LTV).",
"type": "boolean"
},
"interestRate": {
"default": 4,
"description": "Assumed annual interest rate, as a percentage (e.g. 4.0 = 4%, not 0.04).",
"maximum": 15,
"minimum": 0.1,
"type": "number"
},
"loanTenureYears": {
"default": 25,
"description": "Loan tenure in years.",
"maximum": 35,
"minimum": 1,
"type": "integer"
},
"monthlyDebt": {
"default": 0,
"description": "Total existing monthly debt commitments, in SGD.",
"minimum": 0,
"type": "number"
},
"propertyPrice": {
"description": "Target property purchase price, in SGD.",
"minimum": 0,
"type": "number"
},
"propertyType": {
"default": "hdb",
"description": "Type of property: an HDB flat, an Executive Condominium (ec) or private. HDB and EC purchases are also held to the MSR limit.",
"enum": [
"hdb",
"ec",
"private"
],
"type": "string"
},
"stressTestRate": {
"description": "Override the TDSR/MSR stress-test rate (percentage); defaults to the MAS floor.",
"maximum": 15,
"minimum": 0.1,
"type": "number"
}
},
"required": [
"propertyPrice"
],
"type": "object"
},
"name": "calculate_required_income"
},
{
"description": "Compute Buyer's Stamp Duty (BSD) and Additional Buyer's Stamp Duty (ABSD) for a Singapore residential purchase, given price/value, buyer type (singaporean | pr | foreigner | entity | trust) and the number of residential properties already owned.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"buyerType": {
"default": "singaporean",
"description": "Residency or legal status of the buyer (citizen, permanent resident, foreigner, company or trust); sets the ABSD rate.",
"enum": [
"singaporean",
"pr",
"foreigner",
"entity",
"trust"
],
"type": "string"
},
"existingPropertiesOwned": {
"default": 0,
"description": "Count of residential properties the buyer already owns (sets the ABSD tier).",
"maximum": 10,
"minimum": 0,
"type": "integer"
},
"price": {
"description": "Purchase price or market value (whichever higher), in SGD.",
"minimum": 0,
"type": "number"
},
"propertyType": {
"default": "hdb",
"description": "Type of residential property being bought. It does not change the result: BSD and ABSD depend on price, buyer and properties already owned.",
"enum": [
"hdb",
"ec",
"private"
],
"type": "string"
},
"purchaseType": {
"default": "single",
"description": "How the property will be held. `entity` (a company) or `trust` applies that ABSD rate whatever `buyerType` says; for the individual options the rate follows `buyerType`.",
"enum": [
"single",
"joint_spouse",
"joint_non_spouse",
"entity",
"trust"
],
"type": "string"
}
},
"required": [
"price"
],
"type": "object"
},
"name": "calculate_residential_stamp_duty"
},
{
"description": "Work out what a seller walks away with when selling a property: cash proceeds after redeeming the outstanding loan, refunding each owner’s CPF (principal plus accrued interest, 1 to 4 owners), and paying agent commission (with 9% GST), legal and miscellaneous fees. Flags a negative sale when the deductions exceed the selling price.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"agentFeePercent": {
"default": 1,
"description": "Agent commission as a share of the selling price, as a percentage (e.g. 1.5 = 1.5%, not 0.015), before the 9% GST added on top.",
"maximum": 5,
"minimum": 0,
"type": "number"
},
"legalFees": {
"default": 3000,
"description": "Conveyancing fees for the sale, deducted from the proceeds, in SGD.",
"minimum": 0,
"type": "number"
},
"miscellaneousFees": {
"default": 0,
"description": "Other selling costs (repairs, valuation, admin), in SGD.",
"minimum": 0,
"type": "number"
},
"outstandingLoanAmount": {
"default": 0,
"description": "Home loan still owed, repaid from the sale on completion, in SGD.",
"minimum": 0,
"type": "number"
},
"owners": {
"description": "CPF usage per owner (1 to 4 owners). Include every owner; use zeros for an owner who used no CPF.",
"items": {
"properties": {
"cpfAccruedInterest": {
"default": 0,
"description": "Accrued interest owed to this owner's CPF account on the CPF used, in SGD.",
"minimum": 0,
"type": "number"
},
"cpfUtilised": {
"default": 0,
"description": "CPF principal this owner used for the property (downpayment, instalments, stamp duty), in SGD.",
"minimum": 0,
"type": "number"
}
},
"type": "object"
},
"maxItems": 4,
"minItems": 1,
"type": "array"
},
"sellingPrice": {
"description": "Price the property sells for, in SGD; every deduction comes out of it.",
"minimum": 0,
"type": "number"
}
},
"required": [
"sellingPrice",
"owners"
],
"type": "object"
},
"name": "calculate_sales_proceeds"
},
{
"description": "Compute Seller's Stamp Duty (SSD) from the sale price/value and how long the property has been held.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"price": {
"description": "Sale price or market value (whichever higher), in SGD.",
"minimum": 0,
"type": "number"
},
"purchaseDate": {
"description": "Date the property was acquired (ISO date, YYYY-MM-DD).",
"type": "string"
},
"saleDate": {
"description": "Date the property is/was sold (ISO date, YYYY-MM-DD).",
"type": "string"
}
},
"required": [
"price",
"purchaseDate",
"saleDate"
],
"type": "object"
},
"name": "calculate_seller_stamp_duty"
},
{
"description": "Run the regulatory affordability gate for one main borrower and up to three joint borrowers. Given each borrower's income, rental, pledged/unpledged assets and liabilities plus a proposed loan, returns the qualifying income (after MAS haircuts), the TDSR and MSR for the proposed loan, the income-weighted average age (IWAA), and the maximum loan under both HDB/EC and private property rules. Use this upstream of `recommend_packages` to confirm what a borrower can qualify for.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"ageConvention": {
"description": "How borrower age is computed; defaults to birth-date. The tRPC router resolves it per bank from the bank slug.",
"enum": [
"birth-date",
"birth-year"
],
"type": "string"
},
"asOfDate": {
"description": "Reference date (ISO YYYY-MM-DD) for age and IWAA; defaults to today.",
"type": "string"
},
"benchmarkRate": {
"default": 4,
"description": "MAS medium-term stress rate, as a percentage (e.g. 4.0 = 4%, not 0.04).",
"maximum": 15,
"minimum": 0.1,
"type": "number"
},
"borrowers": {
"description": "The main borrower followed by any joint borrowers; their qualifying incomes and liabilities are pooled.",
"items": {
"properties": {
"age": {
"description": "Borrower age in years. When supplied it is used directly and dateOfBirth is ignored.",
"maximum": 120,
"minimum": 0,
"type": "number"
},
"annualNoa": {
"description": "Annual income per the IRAS Notice of Assessment, in SGD. Only used when employedTwoYears is true; recognised variable income is then max(NOA − basic×12, annualVariableIncome).",
"minimum": 0,
"type": "number"
},
"annualVariableIncome": {
"default": 0,
"description": "Yearly bonus, commission and allowances, in SGD; 70% of it, spread over 12 months, counts.",
"minimum": 0,
"type": "number"
},
"dateOfBirth": {
"description": "Borrower date of birth, e.g. \"1990-05-14\"; must not be in the future. Gives the age at `asOfDate` when `age` is not supplied. A borrower with neither is treated as age unknown and left out of the IWAA.",
"type": "string"
},
"employedTwoYears": {
"description": "True if the borrower has ≥2 years with the current employer, which permits using the NOA for variable income.",
"type": "boolean"
},
"liabilities": {
"default": [],
"description": "Up to three monthly liability lines.",
"items": {
"properties": {
"label": {
"default": "",
"description": "What the liability is, e.g. \"car loan\" or \"credit card\". For display only.",
"maxLength": 60,
"type": "string"
},
"monthlyAmount": {
"default": 0,
"description": "Monthly repayment for this liability, in SGD.",
"minimum": 0,
"type": "number"
}
},
"type": "object"
},
"maxItems": 3,
"type": "array"
},
"monthlyBasicIncome": {
"default": 0,
"description": "Fixed monthly salary before deductions, in SGD; counts in full.",
"minimum": 0,
"type": "number"
},
"monthlyRentalIncome": {
"default": 0,
"description": "Monthly rental income (requires a valid tenancy agreement), in SGD. Recognised at 70%.",
"minimum": 0,
"type": "number"
},
"pledgedFunds": {
"default": 0,
"description": "Eligible financial assets pledged ≥4 years, in SGD. Amortised over 48 months at 100%.",
"minimum": 0,
"type": "number"
},
"unpledgedFunds": {
"default": 0,
"description": "Eligible financial assets not pledged, in SGD. Amortised over 48 months at 30%.",
"minimum": 0,
"type": "number"
}
},
"type": "object"
},
"maxItems": 4,
"minItems": 1,
"type": "array"
},
"combinationSplit": {
"description": "For the pledge/show combination: fraction of the income gap covered by pledged funds; the remainder is covered by show funds. Defaults to 0.5.",
"maximum": 1,
"minimum": 0,
"type": "number"
},
"existingHousingLoans": {
"description": "Number of outstanding housing loans held. Selects the LTV tier (0 -> full, 1 -> second, 2+ -> third). Defaults to 0 when omitted.",
"maximum": 10,
"minimum": 0,
"type": "integer"
},
"loanTenureYears": {
"default": 25,
"description": "Loan tenure being tested, in years; checked against the longest tenure these borrowers can get.",
"maximum": 35,
"minimum": 1,
"type": "integer"
},
"propertyType": {
"default": "private",
"description": "Property type: hdb, ec or private. Sets the maximum loan tenure (35y private and EC, 30y HDB) and the lower-LTV-tier triggers. EC also carries MSR, like HDB.",
"enum": [
"hdb",
"ec",
"private"
],
"type": "string"
},
"proposedLoanAmount": {
"description": "The loan amount being tested, in SGD.",
"minimum": 0,
"type": "number"
},
"targetLoanAmount": {
"description": "Optional target loan amount, in SGD. With targetPurchasePrice it sets the LTV (loan / price, capped at the applicable LTV) and takes precedence over targetLtvCap. Without a price, the price is derived as the loan divided by the applicable LTV. Either way toReachTarget is produced.",
"minimum": 0,
"type": "number"
},
"targetLtvCap": {
"description": "Optional manual LTV cap for the target loan, as a decimal (e.g. 0.6 = 60%). When set and below the applicable LTV, toReachTarget is sized at this lower LTV so the loan and unlock figures reflect a smaller loan the borrower chooses to take.",
"maximum": 0.9,
"minimum": 0,
"type": "number"
},
"targetPurchasePrice": {
"description": "Optional target purchase price, in SGD. When set, the result includes toReachTarget: the loan needed at the first-loan LTV and the eligible funds to reach it.",
"minimum": 0,
"type": "number"
}
},
"required": [
"borrowers",
"proposedLoanAmount"
],
"type": "object"
},
"name": "check_eligibility"
},
{
"description": "Compare 2–3 SPECIFIC mortgage packages side by side: average rate over the lock-in, benchmark index, effective rate and monthly instalment per year, interest paid per year, and flexibility terms (prepayment, free conversion, sale waiver, penalties, minimum loan).\n\nPass `packageIds` from `recommend_packages`, plus `loanAmount` and optionally `tenureYears` (default 25). `dealKind`/`propertyType`/`propertyStatus` only label the report header. Pass `formats: [\"pdf\"]` to also render the one-page comparison document — the download URL comes back under `documents.pdfUrl` (null otherwise).\n\nThis comparison has no verdict/recommendation section by default because it carries no borrower context; for a personalised ranking with verdicts, use `recommend_packages` (optionally with `formats`). The optional `verdicts`/`recommendedId` inputs only carry over the reasoning from a prior `recommend_packages` call — never author them.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"dealKind": {
"description": "Whether the loan is a new PURCHASE or a REFINANCE from another lender. Only labels the report header; the comparison is unchanged.",
"enum": [
"PURCHASE",
"REFINANCE"
],
"type": "string"
},
"formats": {
"description": "Document formats to generate and upload (currently only \"pdf\"); the download URL is returned under `documents`. Omit/empty for data only.",
"items": {
"enum": [
"pdf"
],
"type": "string"
},
"type": "array"
},
"loanAmount": {
"description": "Loan principal in SGD (whole dollars).",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
"maskBankIdentity": {
"description": "When true and a bank has maskIdentity set, replace the bank name with \"Confidential Rate\" and hide the logo in the comparison report.",
"type": "boolean"
},
"packageIds": {
"description": "2–3 package ids to compare, e.g. from `recommend_packages`.",
"items": {
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
"type": "string"
},
"maxItems": 3,
"minItems": 2,
"type": "array"
},
"propertyStatus": {
"description": "Stage or use of the property, e.g. COMPLETED (resale or ready-built), BTO or BUC (new, under construction). Only labels the report header; the comparison is unchanged.",
"enum": [
"BTO",
"OWNEROCCUPIED",
"INVESTMENT",
"PERSONAL",
"COMPLETED",
"BUC"
],
"type": "string"
},
"propertyType": {
"description": "The kind of property securing the loan (HDB flat, private home or commercial). Only labels the report header; the comparison is unchanged.",
"enum": [
"HDB",
"PRIVATE",
"COMMERCIAL"
],
"type": "string"
},
"recommendedId": {
"description": "The rank-1 package from the prior `recommend_packages` call; its column is highlighted as \"Recommended\". Only meaningful together with `verdicts`.",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
"type": "string"
},
"tenureYears": {
"default": 25,
"description": "Repayment period, in years, used for each package’s instalment and interest.",
"maximum": 35,
"minimum": 1,
"type": "integer"
},
"verdicts": {
"description": "Per-package verdict texts carried over from a prior `recommend_packages` call (the LLM reasoning). Adds the verdict row to the comparison; omit for a verdict-free report. Do not author these by hand.",
"items": {
"properties": {
"packageId": {
"description": "Package the verdict belongs to: one of `packageIds`, taken from `recommended[].packageId` of the prior `recommend_packages` call.",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
"type": "string"
},
"text": {
"description": "Verdict text, copied verbatim from the matching `recommended[].reasoning`.",
"maxLength": 2000,
"minLength": 1,
"type": "string"
}
},
"required": [
"packageId",
"text"
],
"type": "object"
},
"maxItems": 3,
"type": "array"
}
},
"required": [
"packageIds",
"loanAmount"
],
"type": "object"
},
"name": "compare_packages"
},
{
"description": "Return historical quotes (rate by date) for a market benchmark index such as SORA. Requires `marketIndexId` — use `list_market_indices` to resolve a benchmark name/slug into its UUID. Optional `startDate`/`endDate` narrow the range; results are paginated, newest first. Quote `rate` values are decimal fractions (0.0356 = 3.56% p.a.).",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"endDate": {
"description": "Latest quote date to include. Omit for no upper bound.",
"format": "date",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
"type": "string"
},
"limit": {
"default": 50,
"description": "Number of quotes per page.",
"maximum": 100,
"minimum": 1,
"type": "integer"
},
"marketIndexId": {
"description": "Market index UUID. Resolve a benchmark name/slug via `list_market_indices`.",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
"type": "string"
},
"page": {
"default": 1,
"description": "Page of results to return, counting from 1; `totalPages` gives the last.",
"maximum": 9007199254740991,
"minimum": 1,
"type": "integer"
},
"startDate": {
"description": "Earliest quote date to include. Omit for no lower bound.",
"format": "date",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
"type": "string"
}
},
"required": [
"marketIndexId"
],
"type": "object"
},
"name": "get_index_quotes"
},
{
"description": "Indicative SPML valuation for a Singapore unit. Requires postal code and unit number in FF-SS format (e.g. \"04-02\"). propertyType (\"Condo\" or \"HDB\") and areaSqft are optional — when propertyType is omitted, both types are probed and the one that values the unit is used (`propertyTypeUsed` in the result tells you which). A `valued: false` result means SPML could not value the unit — that is a valid answer, not an error.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"areaSqft": {
"description": "Optional built-in/strata area in sqft; can rescue a \"$0\" valuation.",
"exclusiveMinimum": 0,
"type": "number"
},
"postalCode": {
"description": "Postal code of the building the unit is in, e.g. \"248973\".",
"pattern": "^\\d{6}$",
"type": "string"
},
"propertyType": {
"description": "Whether the unit is a private condominium or an HDB flat. Omit to auto-detect: both are probed and the one that values the unit is used (`propertyTypeUsed` reports which).",
"enum": [
"Condo",
"HDB"
],
"type": "string"
},
"unitNumber": {
"description": "Floor and stack of the unit, e.g. \"04-02\" for floor 4, stack 02.",
"pattern": "^\\d{2,3}-\\d{1,4}$",
"type": "string"
}
},
"required": [
"postalCode",
"unitNumber"
],
"type": "object"
},
"name": "get_property_valuation"
},
{
"description": "List active banks (id + name), sorted by name. Use this to map a borrower's current lender name to the `currentBankId` UUID required by `recommend_packages` for refinance deals.",
"inputSchema": {
"properties": {},
"type": "object"
},
"name": "list_banks"
},
{
"description": "List market benchmark indices (id, slug, name, currency), sorted by slug. Use this to resolve a benchmark name like 'SORA' into the `marketIndexId` required by `get_index_quotes`.",
"inputSchema": {
"properties": {},
"type": "object"
},
"name": "list_market_indices"
},
{
"description": "Rank Singapore mortgage packages for a borrower. Returns `recommended` (up to 3 picks, each with a package id and `reasoning`; ranked by the LLM when `userContext` is given, otherwise the cheapest package of each rate structure), `lowestRateIds` (up to 3 package ids, cheapest eligible first), `isPersonalised` (whether `userContext` shaped the ranking), and `packages`, a lookup of full package details for every id referenced.\n\nCore inputs (gather these first; ask the borrower if missing — do not guess): `dealKind` (PURCHASE | REFINANCE); `currentBankId` (required only for REFINANCE — use `list_banks` to resolve the lender name into its UUID); `propertyType` (HDB | PRIVATE | COMMERCIAL); `propertyStatus`; `loanAmount`.\n\n`propertyStatus` depends on `propertyType` — only these pairings are valid: HDB → COMPLETED (resale) or BTO (Build-To-Order, new); PRIVATE → COMPLETED (ready-built) or BUC (Built-Under-Construction, new); COMMERCIAL → OWNEROCCUPIED, INVESTMENT or PERSONAL. Do not mix across types (e.g. HDB + BUC or PRIVATE + BTO are invalid).\n\nOptional inputs (only refine the ranking): `ratesType` (FIXED | FLOATING) and `userContext` (free-text borrower priorities, timeline, bank relationships, citizenship, etc.).\n\nPass `formats: [\"pdf\"]` to also generate a one-page comparison document of the recommended set (with per-package verdicts); the download URL comes back under `documents`. Optional `tenureYears` (default 25) sets the document's instalment assumptions.\n\nStateless: if any input or preference changes, call this tool again with the full updated set — never infer an updated answer from a previous response.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"candidateLimit": {
"default": 60,
"description": "How many candidate packages the ranker weighs for each of its slots (floating, 2-year fixed, longest fixed); values above 8 have no further effect. Leave unset unless deliberately narrowing the choice.",
"maximum": 60,
"minimum": 1,
"type": "integer"
},
"currentBankId": {
"description": "The borrower's current lender, as the bank `id` returned by `list_banks`. Needed for REFINANCE deals, where that bank's packages are left out; ignored for PURCHASE.",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
"type": "string"
},
"dealKind": {
"description": "PURCHASE (new loan) or REFINANCE (switching lender).",
"enum": [
"PURCHASE",
"REFINANCE"
],
"type": "string"
},
"fixedDurationYrs": {
"anyOf": [
{
"maximum": 5,
"minimum": 1,
"type": "integer"
},
{
"items": {
"maximum": 5,
"minimum": 1,
"type": "integer"
},
"minItems": 1,
"type": "array"
}
],
"description": "Optional filter: keep only packages whose fixed-rate period lasts this many years. Pass an array to accept any of several. Only applied when `ratesType` is FIXED."
},
"formats": {
"description": "Document formats to generate for the recommended set (currently only \"pdf\"); the download URL is returned under `documents`. Omit/empty for data only.",
"items": {
"enum": [
"pdf"
],
"type": "string"
},
"type": "array"
},
"loanAmount": {
"description": "Amount the borrower wants to borrow, in SGD. Packages whose loan-size range does not cover it are excluded.",
"maximum": 9007199254740991,
"minimum": 0,
"type": "integer"
},
"lockInPeriodYrs": {
"description": "Optional filter: the longest lock-in, in years, the borrower will accept. Packages with a longer lock-in are excluded; packages without one always qualify.",
"maximum": 5,
"minimum": 0,
"type": "integer"
},
"propertyStatus": {
"description": "Stage or use of the property, which must suit `propertyType`. For HDB: COMPLETED for a resale flat, BTO for a new Build-To-Order flat. For PRIVATE: COMPLETED for a ready-built home, BUC for one still under construction. For COMMERCIAL: OWNEROCCUPIED, INVESTMENT or PERSONAL.",
"enum": [
"BTO",
"OWNEROCCUPIED",
"INVESTMENT",
"PERSONAL",
"COMPLETED",
"BUC"
],
"type": "string"
},
"propertyType": {
"description": "The kind of property securing the loan: an HDB flat, a private home or a commercial property. Only packages offered for it are considered, and it decides which `propertyStatus` values are valid.",
"enum": [
"HDB",
"PRIVATE",
"COMMERCIAL"
],
"type": "string"
},
"ratesType": {
"description": "Optional rate type: FIXED or FLOATING. This is a hard filter on the candidate pool, not a ranking hint. Omit it when the borrower stated no preference, so a mix of rate types stays eligible.",
"enum": [
"FIXED",
"FLOATING"
],
"type": "string"
},
"tenureYears": {
"description": "Repayment period, in years, for the instalments shown in the comparison document; only used with `formats`. 25 when omitted.",
"maximum": 35,
"minimum": 1,
"type": "integer"
},
"userContext": {
"anyOf": [
{
"maxLength": 2000,
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Optional free-text summary of the borrower's priorities, timeline, bank relationships, citizenship, employment, family changes, etc. Only refines the LLM ranking; omit if there are no stated priorities."
}
},
"required": [
"propertyType",
"propertyStatus",
"dealKind",
"loanAmount"
],
"type": "object"
},
"name": "recommend_packages"
}
]
}What the leaf hashes
{"body":"a3046c7c3a1084e3e7ad4b2945e8042f95e0679c826fe1e1a22e7dc789cf79b6","id":1003781,"kind":"mcp.tools","method":"probe.mcp/1","observed_us":1793258885218269,"prev":null,"subject":"344f1cc8-9307-450c-964b-65c9f8323eae","subject_kind":"endpoint"}Proof
Its day has not closed yet. A day closes ten minutes after midnight UTC; the proof appears here then.