Developer reference
DFX Intelligence MCP server
One connection, four domains: US real estate (properties, parcels, ownership, recorded sales, commercial debt maturities), family offices, independent sponsors and their capital providers, and venture capital, with cross-graph identity, relationships, events, matching and verification. 47 tools, all free, read-only and unauthenticated. Coverage is uneven by design and the gaps are printed below.
Connect
Short answer
GET on the endpoint returns the full tool schemas so you can evaluate it before calling anything.# read the schemas, no handshake required
curl -s https://exchange-production-9123.up.railway.app/mcp
# call a tool
curl -s https://exchange-production-9123.up.railway.app/mcp \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":
{"name":"resolve_address","arguments":
{"address":"100 Binney St","city":"Cambridge","state":"MA"}}}'Registry entry: io.github.Capital-W-Holdings/us-property-parcel-real-estate-debt. Transport is Streamable HTTP. Both the current 2026-07-28 revision and the older initialize handshake are served, because most deployed clients still send the latter.
Install it in your agent
Short answer
Claude Code. One command, no config file. Verified against this endpoint: the server reports Connected on the next claude mcp list.
claude mcp add --transport http dfx-real-estate https://exchange-production-9123.up.railway.app/mcp
Claude Desktop. Settings, then Connectors, then Add custom connector, and paste the endpoint. On a build with no custom connector option, put this in claude_desktop_config.json instead and restart the app. The bridge exists because that config accepts a subprocess rather than a URL; it is not a DFX requirement.
{
"mcpServers": {
"dfx-real-estate": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://exchange-production-9123.up.railway.app/mcp"]
}
}
}Cursor, Windsurf and Cline. A remote server is a URL entry in ~/.cursor/mcp.json, .cursor/mcp.json for one project, or the equivalent file in the other two.
{
"mcpServers": {
"dfx-real-estate": { "url": "https://exchange-production-9123.up.railway.app/mcp" }
}
}VS Code. .vscode/mcp.json in the workspace, which uses servers rather than mcpServers and wants the transport named.
{
"servers": {
"dfx-real-estate": { "type": "http", "url": "https://exchange-production-9123.up.railway.app/mcp" }
}
}Anything else that speaks MCP over stdio only. npx -y mcp-remote https://exchange-production-9123.up.railway.app/mcp puts a local stdio process in front of the HTTPS endpoint. No key is passed through it because there is no key.
There is no account to create and no credential to rotate, so an install that works once keeps working. If a client asks for an API key before it will save the server, the field can be left empty or filled with any string: the endpoint does not require one and never checks it.
The 47 tools
Read from tools/list when this page was rendered, so the table cannot say a number production does not. Real estate first, then the family office, independent sponsor and venture capital tools, then the tools that work across every domain.
| Tool | Takes | Returns |
|---|---|---|
resolve_address | address, city?, state? | canonical DFX ids with the match basis and any ambiguityReturns typed objects: a property (national federal-programme multifamily) and/or a parcel (Massachusetts assessor layer). These are separate populations that barely overlap, so an address may return one, the other, or both. |
resolve_organization | name | canonical entity ids for owners, managers, lenders, servicersA name is treated as a blocking key and never as an identity, so ALL candidates are returned rather than a guess. Person lookup is deliberately not offered. |
get_occupancy | dfx_id?, company?, address?, city?, state?, limit? | Two directions from one call |
get_property_record | dfx_id | state, dated events, relationships, debt with maturity dates, recorded salesRecorded sales carry consideration, registry book and page, and both the instrument's full price and this parcel's allocated share. |
search_property_events | event_type?, state?, within_days?, limit? | dated events over properties and parcels, with provenanceAn unrecognised event_type is REFUSED with the served vocabulary, never answered with an empty list. |
search_bank_cre_exposure | state?, name?, min_cre_to_equity_pct?, max_cre_to_equity_pct?, above_guidance?, min_assets_usd?, min_noncurrent_pct?, sort?, limit? | Search 4,313 FDIC-insured banks by their commercial real estate book at the June 2026 call report: total CRE, construction and multifamily in dollars and against equity and assets, noncurrent and net charge-off ratios, ROA, and two screens against the 2006 Interagency CRE guidance (construction over 100%, total CRE over 300%) |
search_subsidised_housing | state?, city?, program?, min_waiting_months?, min_occupancy?, max_occupancy?, min_units?, limit? | Search HUD's project-level Picture of Subsidized Households: 29,455 subsidised projects nationally, one row per project and programme, with units AVAILABLE (HUD's subsidised units available, which excludes units offline for rehab or disposition; occupancy is measured against these, so 100% of 20 available can be 20 of 50 built), occupied units, occupancy percent, MONTHS ON THE WAITING LIST, average rent, average household income, average tenure and what HUD pays per unit per month |
search_parcels | filters over the parcel layer | parcels by attribute rather than by an address you already hadMassachusetts only, like everything in the parcel layer. This is the way in when you do not already know the address you are looking for. |
what_can_dfx_answer | objective (natural language) | whether DFX can help, which tool to call, the arguments, and a free sampleSays no clearly when the answer is no, and records the ask so unmet demand shapes what gets built. |
changes_since | since (opaque cursor)?, event_type?, state?, place_dfx_id?, limit? | what DFX has LEARNED since your cursor, plus the cursor to use nextOrdered by when DFX came to know a fact, not by when the fact occurred: a deed signed in March is recorded in August, so polling search() with a date filter would show you the same rows forever. Call with no cursor to take a position and receive nothing; call again with what you were given. The cursor is opaque, and an empty delta returns it unchanged. |
debt_maturity_schedule | state, within_days?, limit? | the LOAN rather than the event: principal, lender, instrument, origination, maturity, and the secured buildingFree. Up to 200 loans per call for one state, with a population count so a capped answer is never mistaken for a complete one. It is the loan tape rather than the event tape, and it reaches loans the event index does not. |
dfx_coverage | nothing | measured coverage, served sources, object types and the known gapsCall this before concluding that an empty result means an absent market. |
search_family_offices | query?, state?, city?, sector?, asset_class?, invests_directly?, class?, min_aum_usd?, recent_activity_days?, has_sponsor_relationships?, has_real_estate?, sort?, limit?, cursor? | Family offices as compact cards: class (single, multi, embedded...) with confidence, whether they invest directly, sectors and asset classes on record, check size where stated, direct investment count, latest deployment, and counts of people, sponsor and real estate relationships |
get_family_office | dfx_id | The full card for one family office: profile, AUM / RAUM / 13F value kept apart with their as-of dates, behaviour, the people who run it with roles, its observed investments, relationships, recent events, evidence rows and cross-graph links (same_as by shared CRD/CIK/EIN) |
search_family_office_investments | office_dfx_id?, sector?, asset_class?, state?, investment_kind?, since?, include_candidates?, limit? | Dated investments family offices have been observed making: target, sector, asset class, structure, control or minority, lead or participant, amounts where disclosed (with basis), board seats, exits, and the source quote |
search_independent_sponsors | query?, state?, city?, include_unverified?, sector?, kind?, min_confidence?, sort?, limit? | Verified independent sponsor firms (deal-by-deal acquirers of lower middle market companies) as compact cards: verification status, classification, mandate summary, principals, vehicle count and latest vehicle, and how many companies resemble the sponsor's observed deals |
get_independent_sponsor | dfx_id | The full card for any entity on the sponsor graph: a sponsor (with its verification status, the companies resembling its observed deals as counted facts and reasons with no score, its announced transactions and its observed capital relationships), a capital provider (with fund size, average investment, SBIC status, strategy, whether making new investments) or a private company (with its transition signals and sponsor matches) |
search_sponsor_capital_providers | query?, state?, provider_type?, sector?, sbic_licensed?, making_new_investments?, min_fund_size_usd?, sort?, limit? | SBICs, mezzanine and private equity funds, and family offices observed providing capital to independent sponsors: provider type, strategy, fund style, fund size and average investment (kept apart), vintage, SBIC licence, whether making new investments, mandate summary |
search_private_companies | query?, vertical?, subsector?, state?, city?, naics_prefix?, min_opportunity?, min_participants?, max_participants?, record_status?, sort?, limit? | US private companies whose filings (Form 5500 plan history, final filings, ownership changes) show a transition: vertical, plan participants as a size proxy, EBITDA band where derivable, and scores 0 to 100 for opportunity, dealability, transition readiness and urgency, each backed by observations |
search_sponsor_deals | sponsor_dfx_id?, target_dfx_id?, txn_type?, state?, since?, query?, limit? | Announced acquisitions, recapitalisations and exits by independent sponsors: sponsor, target, dates, enterprise value range where disclosed, structure, parties and source |
search_pending_ownership_changes | state?, view?, tag?, query?, changed_since?, limit? | OFFICIAL state records that a skilled nursing facility's ownership, control or operator is changing, before the change takes effect (Kentucky, New York, Rhode Island, New Jersey, Maine): facility, CCN, beds, current and proposed operator, real estate owner where public, the state's own stage, record class (OFFICIAL_PENDING_FILING, DERIVED_STATUS, CONFIRMED_EFFECTIVE_CHANGE, WITHDRAWN_OR_DENIED), first public record date, days pending, planned close, evidence tags with their facts, source URL and last checked |
search_vc_firms | query?, state?, city?, sector?, stage?, active_only?, raising_only?, emerging_manager?, min_investments?, recent_activity_days?, sort?, limit? | Venture firms as compact cards: stated sectors, stages, geography and check size beside OBSERVED behaviour (investments in the last 6 and 12 months, lead count, behaviour summary and divergence from the stated thesis), funds with the latest vintage and Form D, people and partner counts |
get_vc_firm | dfx_id | The full card for any entity on the venture graph: a firm (with recent investments, co-investors and funds), a person (with attributed investments and board seats), a fund (with all seven fund amounts kept apart and its lifecycle state) or a portfolio company (with its investors) |
search_vc_investments | investor_dfx_id?, company_dfx_id?, partner_dfx_id?, stage?, state?, since?, lead_only?, query?, limit? | Investor-by-investor participations in rounds: investor, company, fund, the partner attributed (with attribution level), role (lead or participant), new or follow-on, board seat, round type, stage and amount (the round's, never the check), and the source quote |
search_vc_funds | query?, organization_dfx_id?, lifecycle_state?, min_vintage?, max_vintage?, strategy?, min_form_d_sold_usd?, sort?, limit? | Funds with every amount under its own name (target, first close, final close, announced size, Form D offering and sold, ADV gross asset value), vintage and basis, lifecycle state, investor counts, LP count |
search_pe_firms | query?, class?, class_state?, size_band?, state?, min_transactions_36m?, sort?, limit?, cursor? | Private equity firms (management companies and advisers) as compact cards: the classifier's class with its state, confidence and basis; size band with the evidence it was sized on; fund counts, latest vintage and Form ADV gross assets reported for private equity funds since 2024 (reported gross assets, NOT fund size or dry powder); portfolio and transaction counts (36 and 12 months); team counts; acquisition appetite and investment velocity values |
get_pe_firm | dfx_id | The full card for a private equity firm: identity (website, HQ, ADV filing dates), classification with basis and the size band's definition and evidence, classification history, stated criteria (sectors, EBITDA, EV, equity check, control) kept apart from observed behaviour, funds summary and its ten latest funds, team summary and current people with titles, portfolio summary with recent investments and transactions, top counterparties (lenders, advisers, placement agents, co-investors with shared-deal counts), every score WITH its components and missing_inputs, recent events, evidence, and same_as links to the family office, sponsor and venture graphs by shared identifier |
search_pe_funds | query?, organization_dfx_id?, adv_fund_type?, min_vintage?, max_vintage?, lifecycle_state?, min_adv_gav_usd?, sort?, limit?, cursor? | Funds on the private equity graph with every amount under its own name and beside its basis: target, first close, final close, announced size, Form D offering and sold, and the Form ADV gross asset value with its as-of date |
get_pe_fund | dfx_id | One fund: manager, vintage and basis, every amount kept apart with its basis (adv_gross_asset_value is reported gross assets, not fund size or dry powder), the year-by-year Form ADV reporting tape (gross assets, owners, minimum investment, ownership percentages), LP commitments where disclosed, relationships (placement agents, auditors, principals), events and evidence |
search_pe_transactions | firm_dfx_id?, target_dfx_id?, platform_dfx_id?, transaction_type?, state?, since?, add_on_only?, control_status?, query?, limit? | Acquisitions, add-ons, recapitalisations, carve-outs, secondary sales and exits on the private equity graph: type, status, announced and closed dates, target with industry and state, platform for an add-on (with the basis for calling it one), control, every party with role, side and attribution, and money (enterprise value, purchase price, equity value, target revenue and EBITDA) ONLY where disclosed, each beside its basis |
search_pe_platforms | query?, state?, sector?, min_add_ons_24m?, owner_dfx_id?, sort?, limit? | Companies that act as a platform (a sponsor's platform investment, or a company that has made add-ons): industry, add-on counts (total and last 24 months) and latest add-on date, current owners with role, status and dates, ownership since, and the platform acquisition activity and exit readiness scores |
find_pe_buyers_for_company | dfx_id, limit? | Computed buyer_for_company matches from the private equity matcher for one company (a dfx:pe:, dfx:isi: or dfx:vc: company id): each firm with the matcher's reasons, blockers, why_now and comparable transactions verbatim, the deal partner where attributed, score, confidence, model version and computed date |
find_pe_companies_for_buyer | dfx_id, limit? | Computed company_for_buyer matches for one private equity firm (dfx:pe: id): each company (on the private equity, sponsor or venture graph, with its dfx id) with the matcher's reasons, blockers, why_now and comparables verbatim, score, confidence and computed date |
find_pe_addons_for_platform | dfx_id, limit? | Computed addon_for_platform matches for one platform (a dfx:pe: company id from search_pe_platforms): each candidate company with the matcher's reasons, blockers, why_now and comparable add-ons verbatim, the platform's owner, score, confidence and computed date |
search_entities | query?, domain?, entity_type?, state?, city?, sector?, asset_class?, stage?, invests_directly?, recent_activity_days?, min_aum_usd?, vertical?, min_opportunity?, has_sponsor_relationships?, has_real_estate?, active_only?, sort?, limit?, cursor? | One search across family offices, independent sponsors and their capital providers, private companies, venture firms, private equity firms and funds, and real estate organisations: by name, or by filters (entity_type, domain, state, sector, ...) |
resolve_name | name, domain?, entity_type?, limit? | Resolve a firm, fund, person or company name to canonical dfx ids from the Data Factory's index of every published name and alias (former names, dbas, legal names) on the family office, sponsor, venture and private equity graphs |
get_entity | dfx_id, include?, relationship_limit?, event_limit?, evidence_limit? | For any DFX id: the full card, published relationships with sources and dates, recent events, evidence rows (the observation each fact traces to), cross-graph same_as links by shared identifier, same-name candidates on other graphs (labelled as candidates), and pointers to deeper views |
search_people | query?, domain?, organization_dfx_id?, role?, investment_responsibility?, current_only?, cross_graph_only?, limit? | Investment professionals, principals and family office staff as names with titles, roles, seniority, investment responsibility, organisation and tenure, from public filings and firm pages |
search_relationships | dfx_id, rel_type?, current_only?, limit? | Every published relationship touching one entity (EMPLOYS, PRINCIPAL_OF, INVESTED_IN, CO_INVESTED_WITH, MANAGES, OWNS, BOARD_MEMBER_OF, VEHICLE_OF, ...), each with role, dates, currency, confidence, evidence class and source |
relationship_path | from_dfx_id, to_dfx_id, max_hops? | An evidence-backed path between two DFX ids across every graph: each hop is a published relationship with its source, or a SAME_AS identity link by shared CRD/CIK/EIN |
search_events | domain?, dfx_id?, event_type?, state?, since?, within_days?, signal_family?, min_significance?, exclude_routine?, limit? | Dated events across family offices, sponsors, venture, private equity and real estate: investments announced, vehicles formed, Form D and ADV filings, people joining and leaving, funds raised, acquisitions, plan final filings, record departures, loan maturities |
verify | claim?, subject_dfx_id?, subject?, predicate?, object_dfx_id?, object?, year? | SUPPORTED, PARTIALLY_SUPPORTED, CONTRADICTED or UNKNOWN for a claim, with the observations |
find_capital_for_opportunity | dfx_id?, sector?, vertical?, state?, deal_size_usd?, check_size_usd?, asset_class?, stage?, control?, sponsor_involved?, investor_types?, limit? | Investors for a company (dfx_id) or a described opportunity (sector, state, deal size, stage, control): verified independent sponsors with observed acquisitions in the sector (listed, not paired or ranked; company to sponsor pairs are withdrawn), family offices with observed investments or stated sectors in it, venture firms when the opportunity is venture-shaped, and private equity matcher rows where that graph computes them |
find_opportunities_for_capital | dfx_id, limit? | For a family office, sponsor, capital provider or venture firm: the opportunities DFX knows that fit its DEMONSTRATED behaviour: computed matches where the graph has them (with reasons and blockers), then private companies with transition signals in the sectors it has actually invested in, sponsors seeking capital, companies raising in its stated sectors |
explain_match | dfx_id_a, dfx_id_b | For an investor and an opportunity (either order): MATCH REASONS, BLOCKERS, SUPPORTING OBSERVATIONS, COMPARABLE HISTORY (the investor's dated investments in the same sector, with sources), RELATIONSHIPS (a path on the graph if one exists), RECENT EVENTS on both, the computed match if the graph has one, and a confidence label |
why_now | dfx_id, within_days? | Evidence-backed reasons an entity matters now: recent filings, vehicles formed, deployments, people moves, fundraising, transition signals, loan maturities, each dated with its source |
who_should_care | dfx_id?, event_id?, limit? | Given an entity or an event id: who is likely to care and why |
Beyond real estate: family offices, independent sponsors, venture capital
Short answer
dfx:fo:, dfx:isi:, dfx:vc:, plus the real estate ids), one response contract, and cross-graph identity by shared CRD, CIK or EIN only. A same-name entity on another graph is returned as a candidate, never merged.Family Office Intelligence. 2,335 offices on the graph (849 candidates, 125 confirmed multi-family, 344 probable single-family), 4,236 foundations, 637 offices with 13F positions, 201 with observed direct investments.
Independent Sponsor Intelligence. 3,677 sponsors, 9,870 capital providers, 97,287 private companies with plan-filing history of which 15,015 carry a transition signal, 27,724 computed company-to-sponsor matches with reasons and blockers, 1,285 announced transactions.
Venture Capital Intelligence. unknown firms (unknown with a fund raising in the last 18 months), 71,074 funds with every fund amount kept apart, 107,222 people, 43,517 companies, 23,211 rounds. Stated sectors are populated on unknown firms today, so a sector filter on firms answers NOT_COVERED rather than an empty list.
Across all of them: search_entities, get_entity (everything on one id: card, relationships, events, evidence, cross-graph links), search_people, search_relationships, relationship_path (how X connects to Y, every hop an evidenced edge), search_events, verify (SUPPORTED, PARTIALLY_SUPPORTED, CONTRADICTED or UNKNOWN, with the observations), and the economic tools find_capital_for_opportunity, find_opportunities_for_capital, explain_match (reasons and blockers, never a bare score), why_now and who_should_care.
Contact points are withheld over MCP on every graph. Call what_can_dfx_answer with domain set to family_office, independent_sponsor, venture_capital or real_estate for that domain's entity types, event families, rights, freshness and limitations.
What a call actually returns
Resolving 100 Binney St, Cambridge MA returns a parcel with its assessed value and a dfx_id. Passing that id to get_property_record returns the recorded sale:
{
"object": { "type": "parcel", "name": "100 BINNEY ST",
"city": "Cambridge", "state": "MA",
"assessed_total": 494419400.0, "assessment_year": 2026,
"address_ambiguous": false },
"sales": [{
"transaction_type": "sale",
"closed_date": "2022-04-01",
"consideration": 1020000000.0,
"allocated_consideration": 1020000000.0,
"allocation_basis": "single parcel deed, consideration as published",
"parcels_on_this_instrument": 1,
"arms_length": "unknown",
"arms_length_basis": "$1,020,000,000 is 2.06x the FY2026 assessed value…",
"recording": { "book": "79922", "page": "0115" }
}],
"coverage_notes": ["Recorded sales here carry a buyer but never a seller…"]
}Both consideration figures travel together deliberately. A deed repeats its full price on every parcel it covers, so summing the naive column multiplies a portfolio sale by the number of parcels in it.
Coverage, with denominators
| Dated events, publishable | 62,524 | 16 event types over 13 sources; see per-type breakdown |
| …falling inside the next 18 months | 8,631 | what search_property_events returns at within_days=548 |
| Properties resolvable by address | 90,278 | national, federal programme multifamily; 83,664 distinct addresses |
| Parcels resolvable by address | 269,984 | Massachusetts only |
| Recorded sales | 80,448 | Massachusetts only, $146.6bn |
| Loans with a maturity date | 19,881 | FHA-insured and securitised CMBS; reachable via get_property_record on a resolved property |
| …maturing inside 18 months, in the loan table | 1,728 | over 1,407 properties, national, median original principal $13.4m |
| …of those, reachable by searching for events | 132 | over 70 properties. THE SEARCH INDEX REACHES 5% OF THEM. Read the note below. |
| Building permits | 201,288 | City of Boston only |
| Leases / tenancies | 3,971 | national, from securitised disclosure |
Where coverage is weak, stated plainly
- Parcels, recorded sales and ownership are MASSACHUSETTS ONLY. Permits are the City of Boston only. Everything national is federal-programme multifamily: HUD, LIHTC and FHA.
- Recorded sales carry a buyer and NEVER a seller. The source is an assessor roster, which publishes no grantor, so repeat-sale pairs and hold periods are not derivable from it at any volume. No amount of further ingestion changes this.
- THE DEBT SEARCH INDEX IS INCOMPLETE AND ITS EMPTY RESULTS ARE NOT EVIDENCE OF AN EMPTY MARKET. DFX holds 1,728 loans maturing inside eighteen months across 1,407 properties, nationally, at a median original principal of $13.4m. Only 132 of them, over 70 properties, are published as dated events, which is what search_property_events reaches: about 5%. The lag is also not uniform by geography, because published maturity events are HUD/FHA nationally plus CMBS in Massachusetts only, while the loan table is national. A cold agent searching New York for near-term maturities received count 0 with complete true, while the loan table held 193 and 245 Park Avenue alone carries thirteen maturing 2027-06-01. Every maturity search now returns this denominator with it. To reach the other 95%, call resolve_address then get_property_record, which reads the loan table directly and does not depend on the event index.
- A MATURITY IS COUNTED ONCE, WHICH IT WAS NOT UNTIL 2026-08-31. A HUD maturity is published by two sources and a CMBS maturity once per note, so one building on one date could arrive as four rows. Results are now deduplicated on property and date, and `sources` lists every source that agreed. Note that `original_principal` on a CMBS record is the NOTE, not the loan: 245 Park returns thirteen pieces summing to $668.75m against a $1.02bn loan, so summing them is a trap.
- The Registries of Deeds are closed to automation, so conventional bank and private-credit mortgages are absent entirely. A property absent from a maturity search is NOT a property without debt, and across most of the United States it is a property whose debt we have never been able to see.
- Ownership relationships are Massachusetts-only and structurally so: HUD publishes a management agent and never an owner.
- One street address can carry several records. Every property record returns address_group_size so you can see it; above 1, deduplicate by address before summing anything. DFX has not merged them because thousands of these clusters are genuinely different buildings sharing one address.
- Nothing served here carries a calibrated probability. No prediction in this system has had an outcome resolved, so every score is a ranked signal and is labelled as one.
- LIHTC compliance periods are statutory and every one falls on 31 December, so a count bucketed by day shows a December cliff that is an artefact of the statute rather than a market event.
Polling for what is new
Short answer
changes_since answers what DFX has learned, not what has happened. Call it with no cursor to get a starting position, then call again with the cursor you were handed. The cursor is opaque: pass it back byte for byte and do not parse it.# 1. establish a position. returns no events, on purpose.
{"name":"changes_since","arguments":{}}
-> { "count": 0, "first_call": true,
"cursor": "2026-08-31T10:38:55.382135+00:00" }
# 2. later, ask what arrived. pass the cursor back unchanged.
{"name":"changes_since","arguments":{"since":"2026-08-31T10:38:55.382135+00:00"}}
-> { "count": 50, "complete": false,
"cursor": "2026-08-28T23:23:06.51893+00:00|30adacd5-36e3-4cd8-8752-0e4377353105" }
# 3. keep calling with the newest cursor until complete: true.The argument is since and the response field is cursor. They are the same value and the names do not match. A client that reads cursor and sends it back as cursor gets a first-call response with zero events and no error, which looks like “nothing changed” forever. It is the first thing a careful caller gets wrong, so it is printed here rather than left to be discovered.
Paging is exact. The cursor is a composite of the learn-time and the event id, so a page boundary falling inside a group of events learned in the same instant does not skip the remainder. Until 2026-08-31 the cursor was the timestamp alone, and because the tape carries 58,743 events across only 254 distinct learn-times, an agent paging to completion saw roughly a fifth of it and was told the tape was complete. Fixed, and pinned by a test that walks tapes with tie groups of 1 to 500 rows at page sizes 1, 7 and 50 and asserts every row is returned exactly once.
An empty response returns your own cursor unchanged, because standing still is safe where advancing is not. A malformed cursor is refused as INVALID_CURSOR with safe_to_retry: false, never as a DFX outage.
Failure states
An empty list is a claim, and this endpoint will not make it carelessly. Five distinct outcomes are served rather than collapsed:
- Known no result. DFX looked inside applicable coverage and found none.
- Coverage unavailable. The geography or category is not held. Says so.
- Resolution failed. The input could not be keyed; the reason is returned.
- Rights blocked. DFX holds the information and may not republish it.
- Temporarily unavailable. A DFX availability problem, marked safe to retry, explicitly not a statement about your query or our coverage.
Rights and provenance
Every observation carries its source, the time it was retrieved and a content hash. Rights are determined by reading the operative terms for each source and are recorded as versioned rows: when a determination changes, the old one is superseded rather than edited, because the question diligence asks is what the terms said on the day we ingested.
Unclear means no. Two sources totalling over two million observations are held and not published because their terms could not be established. Sources published under an attribution condition carry that notice in the response envelope itself rather than in documentation somebody may not read.
Latency, price and limits
Measured cold path from a standing start with no prior knowledge: five requests, about 1.5 seconds total, to a first useful answer. Typical single tool call is 200ms to 700ms.
All 47 tools are free, read-only and unauthenticated. No key, no signup, no OAuth, and no account or payment step anywhere on the server.
The loan tape is free too: debt_maturity_schedule returns up to 200 loans per call for one state. It is the loan rather than the event: the principal, the lender, the instrument and the origination, rather than a date and a headline. It also reaches loans the event index does not, which is the gap described above. Every response states how many loans DFX holds for the filter, so a capped answer is never presented as the whole population.
How many rows a state actually holds, because it is not the same everywhere. 19,881 loans carry a maturity date and every one of them carries maturity_basis: confirmed, filed with the SEC by a servicer or recorded by HUD. Not one is estimated or inferred from a term length. But only 1,614 of them fall inside the default eighteen-month window, and they concentrate: California holds 329, New York 193, Texas 117, Ohio 61, and twenty-eight states hold fewer than twenty each. Montana and Wyoming hold one apiece. Widen within_days to reach further out.
Bulk access and higher volumes. If you need the full tape, higher limits or a feed, write to jesse@dfxintel.com and say what you are building.
Rate limits, so you can plan around them instead of discovering them. 20 requests per minute and 300 per hour for any caller. search_property_events and changes_since are additionally capped at 60 per hour, because those two are the paging capabilities. A refusal is a structured answer carrying the state, the reason and a retry time rather than a bare 429. Search results cap at 50 rows per call; the loan tape caps at 200.
One page per capability
Each of these answers one question, states the coverage for that question alone, and shows a real call with the real response. They exist because an agent searching for a capability should land on the capability rather than on a reference manual.
- Which commercial real-estate loans mature in a given state and window?3,422 published events, 52 states and territories, effectively national. Free.
- Which LIHTC properties are reaching the end of a compliance period?11,956 published events, 56 states and territories, effectively national. Free.
- Which HUD-subsidised properties have contracts approaching expiry?4,721 published events, 54 states and territories, effectively national. Free.
- Where is commercial real estate in distress, foreclosure or workout?307 published events, 28 states, broad but NOT national. Free.
- What did this property sell for, and who owns it?43,680 published events, 2 states only: MA, NY. Free.
- Which commercial leases are approaching expiry, and who occupies a building?3,966 published events, 55 states and territories, effectively national. Free.
Every count above was measured against the running exchange on 12 September 2026. These pages are built rather than fetched, so a count is a dated reading and not a claim about this moment; call dfx_coverage for the grid as it stands when you read it.
Machine-readable surfaces
Everything on this page is available without reading it. None of these need a key or a handshake:
GET https://exchange-production-9123.up.railway.app/mcpreturns the full tool schemas, the coverage block and a worked example.GET https://exchange-production-9123.up.railway.app/openapi.jsonis the OpenAPI description of the same surface.GET https://exchange-production-9123.up.railway.app/.well-known/agent-card.jsonis the A2A agent card.GET https://exchange-production-9123.up.railway.app/.well-known/mcp/server-cards.jsonis the SEP-2127 server card.GET https://exchange-production-9123.up.railway.app/returns the capability manifest with versions and coverage.
GET https://dfxintel.com/ai/real-estate-mcp/catalog.json is the full machine-readable capability catalog: every tool schema, the measured per-family coverage grid, the price, the stated gaps and a real executed example response for each capability. It exists so a machine can decide whether DFX is worth connecting to WITHOUT connecting to it first, which is the decision most evaluating agents actually have to make.
The registry listing and this page are meant to agree. If they ever disagree, the live endpoint is the truth and this page is the thing that is wrong.
Facts on this page were last checked against the running product on . Prices are read from the live billing configuration, so this page and your invoice cannot disagree. The machine-readable version of this record is at /ai/entity.json.