Fabrica MCP Server
[Add to Claude]
Give AI agents access to US land on Fabrica. Search properties, research a parcel, check what it could borrow, and explore portfolios across the US land held on the Fabrica protocol.
What is this?
On Fabrica, a property is held in a trust; once its ERC-1155 token on Ethereum is issued, the token controls the trust, which holds title. This MCP server lets any AI agent query the full property catalog, lending market, and portfolio data, with no API keys required. A person can also connect their own Fabrica account (Connect Fabrica) so the agent reads their properties, offers and loans: the same server URL asks them to sign in and approve read-only access on fabrica.land the first time the agent needs it.
Built on the Model Context Protocol (MCP).
Quick Start
Hosted (recommended): nothing to install
Point any MCP client at the hosted server:
No sign-in is needed for public data. Ask about your own properties, offers or loans and the client asks you to sign in to Fabrica and approve read-only access, then answers; disconnect any time in Connected apps on fabrica.land.
Claude (claude.ai, desktop and mobile): Fabrica is listed in the Claude directory. Open claude.ai/directory/fabrica-land and select Connect. Or add it by hand: Settings → Connectors → Add custom connector → paste the URL (this is also how to add the testnet server).
Signing in to Fabrica (only for your own account data) opens fabrica.land. On iPhone and iPad, start the connection from claude.ai in Safari: the Claude iOS app's in-app browser can't complete the sign-in.
Claude Code:
Cursor: one click installs the mainnet server:
[Add Fabrica to Cursor]
Or add it by hand (.cursor/mcp.json):
Any other client that supports remote MCP servers (Streamable HTTP) works the same way. Add both URLs as two separate servers if you want to try things on testnet before mainnet: the network is fixed per URL, so an agent can never reach mainnet through the testnet server.
Discovery without a registry: each host serves /.well-known/mcp.json (URL, transport, auth, docs, the other network's server) and /.well-known/mcp/server-card.json (the same plus every tool with its title and annotations, the prompts and the resource templates), plus /.well-known/ai-catalog.json, the AI Catalog that domain-level discovery reads first, pointing at both servers' cards. The card is read from the running server, so it always matches what that host registers.
Run locally (stdio)
The hosted URLs above are the supported way to use the server; it is not published to npm. To run it on your own machine from source (Node 20 or later; Yarn 4 is pinned in .yarn/releases, so any yarn on your PATH runs the right version):
Set FABRICA_NETWORK=sepolia in the server's environment for the testnet.
Available Tools
Your account (sign-in)
These tools read the connected person's own account, across every wallet on it, on mainnet. The first call asks the person to sign in to Fabrica and approve read-only access; disconnect any time in Connected apps on fabrica.land.
Adding a property
Two tools add a property as the connected person. They need the Fabrica API's add-property grants (onramp:write, premint:write, asked for at sign-in) and, for listing links, the web app's listing import key (FABRICA_LISTING_IMPORT_KEY).
The questions are Fabrica's own rules for that county, state and kind of owner, read from the property's record each time (the same ones the web app's owner form shows), never a list kept here. The fee approval and the notarized signing session stay on fabrica.land; nothing is signed, paid or recorded by these tools.
Sign requests (testnet host first)
On mcp-testnet.fabrica.land (and on mainnet only with FABRICA_SIGN_REQUESTS=enabled), seven tools prepare actions: the marketplace's make_land_offer, list_land_for_sale, accept_land_offer, buy_land and cancel_land_order, and the DeFi lending pool's borrow_against_land (checks the wallet holds the token, no loan is active and the amount is within the pool's maximum) and repay_loan_against_land (checks the loan is active and the wallet is its borrower, with the payoff today). Each checks the live data (the property is live, the wallet holds it or not, the listing or offer is open, buyable and the wallet's own where it has to be), then returns a signRequest: a summary, warnings, a sign link to the property page on fabrica.land with the dialog prefilled, and an expiry 15 minutes out. The person opens the link and signs with their own wallet. The server holds no keys, signs nothing and submits nothing; payload (typed data or an unsigned transaction for a wallet in the conversation) stays null until Connect Fabrica ships. get_sign_request says whether a request was signed (it also checks the order book), and get_transaction_status follows a transaction by hash.
Where the sign-request tools are on, list_land_for_sale also takes a property its owner is still adding to Fabrica (claimed, token not issued yet): the listing goes on the marketplace at once, buyers can send offers, and it becomes buyable when the token is issued, as the web app's own list-for-sale dialog does. The other sign-request tools keep refusing a property that is still being added.
Owner actions follow the same pattern, on testnet first (on mainnet only with FABRICA_OWNER_ACTIONS=enabled as well): transfer_land moves a property the wallet holds outright to another account linked to the same Fabrica login (final once confirmed), update_trust_agreement moves it to the latest trust agreement version (the contract requires 70% of the property), update_land_description replaces its description with the prepared text, and update_land_photos opens its photo editor, where the owner picks files from their own device. Each checks that the wallet holds the share the contract requires and that the property backs no loan.
On the testnet server (and on mainnet only with FABRICA_POOL_SIGN_REQUESTS=enabled as well), deposit_to_lending_pool and withdraw_from_lending_pool prepare a deposit into, or a withdrawal from, one tick of the DeFi lending pool the same way. A tick sets the largest loan it funds (a share of a property's value, or a fixed dollar amount) and the longest loan length; the ticks come from the Fabrica API and the wallet's position at a tick is read from the pool contract. The sign link opens the pool page's deposit or withdraw dialog, prefilled. Interest is set by the pool, variable and not guaranteed, and deposits are at risk. A withdrawal larger than the funds the tick has not lent out waits in the pool's withdrawal queue for the rest and is claimed later on the pool page.
Pending requests live in the server's own store (Vercel KV / Upstash Redis: KV_REST_API_URL and KV_REST_API_TOKEN, plus SIGN_REQUEST_SECRET for the records' HMAC). The sign link is {web}/property/{network}/{tokenId}?action=…&request={id}. The sign page reads the request at GET /sign-requests/{id} (410 once expired) and reports the outcome at POST /sign-requests/{id}/result with { orderHash } or { transactionHash }, which the server checks against the API or the chain before recording. Without a store the tools say they are not configured; locally (stdio) an in-process map is used.
Knowledge layer
ask_fabrica answers questions about Fabrica (the trust, fees, Property checks, lending, taxes, adding and removing a property, the legal framework) from Fabrica's own text and returns the passages with their URLs, so an agent cites the page instead of paraphrasing from memory. Three sources feed it: docs.fabrica.land, the help center and the US trust agreement.
The index lives at src/knowledge/generated/index.json and is committed, so deploys and tests never fetch the sources at runtime. Retrieval is BM25 over passage text with titles weighted in and a small synonym list for Fabrica's vocabulary; there is no model call and no external service. To rebuild after the sources change:
Source pins (docs commit, help center sitemap fingerprint, trust agreement commit) are recorded in knowledge/sources.json. The build takes about 30 seconds and the index is under 1 MB.
A scheduled workflow (.github/workflows/refresh-knowledge.yml, daily and on demand) rebuilds the index, runs the tests and opens a pull request titled "Knowledge index: " whose body lists the pages added, removed and changed (scripts/knowledge-diff.mjs). Merging it deploys both servers. The workflow needs one repository secret, KNOWLEDGE_TOKEN, a fine-grained GitHub token with read access to the contents of the private fabrica-land/docs repository; a failed source fetch fails the run, so a partial index is never proposed.
Resources
The same documents are registered as MCP resources, so a person can attach one to a conversation from the client's resource picker (Claude's "add from connector", Cursor's @) without the agent searching for it. All are text/markdown, and every read starts with the source URL and the content's updated date.
fabrica://docs/{slug} and fabrica://help/{id} are also resource templates with completion.
Prompts and skill file
The server offers four MCP prompts: due_diligence (one property, ending with what to verify yourself), work_parcel_list (a list of addresses or parcel numbers through find_us_parcel), wallet_review (holdings, loans and maturities) and how_to_add_land (adding one parcel to Fabrica). The same loops, the tool list and the legal red lines are in the Agent Skills file skills/fabrica/SKILL.md, served at https://mcp.fabrica.land/skill.md for agents that do not connect to the server.
Example Conversations
"Find me all tokenized properties in Texas"
"What's the current average APR on Fabrica's lending market? How much liquidity does the lending pool have?"
"Do a full due diligence report on property token 12743610130101631987"
"Show me the portfolio for wallet 0x23bc...fce4. What properties do they own?"
"Give me protocol-wide stats for Fabrica: how many properties, in which states, and total loan volume?"
"How much can I borrow against property token 12743610130101631987?"
"Show me all recent activity for wallet 0x23bc...fce4"
"What is property 3484741603659410548 listed for, and what offers are waiting on it?"
"Explain the Property checks number 73242. What does each digit mean?"
"Show me a map of property token 12743610130101631987"
"Show me a map of all properties in this wallet's portfolio"
Property card (MCP App)
In clients that support MCP Apps (such as Claude on the web and desktop), get_land_property renders a property card inline in the conversation:
- a gallery with the parcel map first, followed by the owner's photos when there are any
- name, location and acreage
- Property checks, estimated value, listing price, and borrowing capacity
- Buy (when listed), Make an offer, Contact owner and View on Fabrica buttons
Every button opens the property on Fabrica, where the user completes the action and signs; the server itself never prepares or submits a transaction. Clients without MCP Apps support receive the same data as JSON.
The agent can ask for the card fullscreen with display: "fullscreen"; the host may decline.
The card is on by default on Sepolia and off on mainnet unless FABRICA_MCP_APPS=enabled. Photos are limited to the origins the card's sandbox allows (see WIDGET_IMAGE_ORIGINS in src/tools/media.ts).
Network Selection
The hosted servers are split by URL (see Quick Start). A local server connects to Ethereum Mainnet by default, where properties represent real parcels of US land with real legal consequences. To experiment with test properties first, set FABRICA_NETWORK=sepolia:
Claude Code (Sepolia):
Claude Desktop (Sepolia):
Mainnet notice: On mainnet, the server instructions carry a legal notice stated as facts: the properties are real US land, each held in a trust; owning a token means owning the beneficial interest in the trust that holds the property; the trustee is designated by the token holder and is, by default, the holder; and acquiring, transferring, listing or borrowing against a token has legal, tax and liability consequences set out in the trust agreement attached to it.
Sepolia: Test properties only, no real-world implications.
Configuration
All optional; sensible defaults are built in:
Regression list
yarn regression (mainnet) or yarn regression sepolia calls every tool on a hosted server with the case list in scripts/regression/cases.json: happy paths, edge cases and the wording of a miss. One line per case, exit code 1 on a failure. Run it after each release and before a directory submission.
Hosting
The hosted servers run on Vercel from this repository: one Vercel project per network, both built with yarn build:vercel (see vercel.json), which emits a stateless Streamable HTTP function at /mcp, the sign-request endpoints at /sign-requests, the discovery documents at /.well-known/, and a landing page at /. Set FABRICA_NETWORK in each project's environment (ethereum or sepolia). The same handler (src/http.ts) can run behind any Node HTTP server.
MCP Registry
Both hosts are listed in the official MCP Registry as land.fabrica/mcp and land.fabrica/mcp-testnet (remote servers, no package). PulseMCP, Glama, the GitHub MCP registry and VS Code read from it. The entries live in server.json and server.testnet.json.
To republish after a release: bump version in package.json, src/server.ts and both server files (a test keeps them equal), then run yarn registry:publish (--dry-run prints the entries). Before writing anything it checks both entries against the registry: a version already there with the same content is skipped, so a rerun after a partial publish finishes the job, and one with different content stops the run. The namespace is proven by the v=MCPv1 TXT record on fabrica.land; the script reads the matching Ed25519 private key from MCP_REGISTRY_PRIVATE_KEY or ~/.config/mcp-registry/fabrica-land-ed25519.pem.
Links
License
MIT