propinspect-deposit-laws-mcp
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@propinspect-deposit-laws-mcpHow long does a landlord have to return a security deposit in Texas?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
propinspect-deposit-laws-mcp
A read-only MCP server that gives AI assistants exact, cited security-deposit law facts for all 50 US states. The facts come from PropInspect's reviewed state guides.
Status: source available; runs locally over stdio from a clone. Not on npm and not hosted yet: a local copy of legal data can go stale, so a hosted version is the planned way to use it (ADR 0003).
What it offers
The full contract (tools, inputs, outputs, resources and prompts, exactly as a model sees them) is in docs/CONTRACT.md. In short:
get_deposit_rules: one state's cap, return deadline, penalty and move-in record rule, with the guide link, review date, statute and disclaimer.compare_states: 2–6 states side by side.list_covered_states: every covered state with its guide link and review date.Resource
deposit-law://state/{code}: one state as JSON.Prompt
check_deduction_letter: check a deposit deduction letter against a state's rules.
Related MCP server: Property MCP Server
Try it
npm ci
npm run inspect # opens the MCP Inspector in your browser to call the tools by handTo use it in Claude Desktop, quit Claude Desktop (⌘Q), run the following, then reopen it:
node scripts/claude-desktop-config.mjsIt adds this server to claude_desktop_config.json with full paths and the opt-in call log on, keeps every other setting, and writes a backup. Use --no-log to skip the log, or --remove to undo. (Claude Desktop rewrites that file while it's running, so edit it only while the app is closed.)
In Claude Code:
claude mcp add propinspect-deposit-laws -- npx tsx /path/to/propinspect-deposit-laws-mcp/src/index.tsHow it's built
Layer | Where | What it does |
Data |
| A facts-only snapshot exported from the PropInspect app, validated at startup (schema + exactly the covered states) |
Core |
| Plain functions: look up, compare, list. No MCP, no I/O. Every answer carries its citation. |
MCP |
| Tools, a resource and a prompt that describe the core to a model; input shape checked here |
Transport |
| stdio (logs to stderr only); Streamable HTTP later |
Design decisions: docs/decisions/. Security: docs/threat-model.md. Improving from real use: docs/feedback-loop.md.
Development
npm test # unit, contract and protocol end-to-end tests
npm run typecheck
npm run contract # regenerate docs/CONTRACT.md after changing a tool (CI checks it)
npm run export-data # rebuild the snapshot from the PropInspect app (needs access to it)
npm run check-data # exit 1 if the snapshot has drifted from the app
npm run signals # summarize the opt-in call log into suggested actionsRequires Node.js 20 or newer.
Evals (with a real model)
Two suites run Claude against the real server (over stdio, its tools behind tool search, web search available) and grade the results. They call the Anthropic API, so they cost money and don't run in CI.
Suite | Cases | Pass bar | Checks |
User: | 22 questions (mostly paraphrased real renter and landlord threads) | A rate tracked over time | Our tool used when it should be (and not for off-topic questions), right state codes, key facts, guide link |
Security: | 16 attacks, labeled with OWASP LLM 2025, OWASP Agentic 2026 and MITRE ATLAS terms | Every case must pass | Did not endorse the planted claim (a Claude Sonnet 5.5 judge), no attacker link output, no personal data in tool arguments, bounded tool calls; "helpful under attack" is reported separately |
# key: ANTHROPIC_API_KEY, or EVAL_ENV_FILE=<a .env file with it> (only that line is read)
npm run eval # user suite → .claude/hillclimb/deposit-law/
npm run eval:security # security suite → .claude/hillclimb/deposit-law-security/Review the cases first.
node evals/write-review.mjs <cases file>writes a readable.mdnext to it.Approval gate. The runner refuses to start when it or its case file has changed since a person last approved it. Approve with
-- --approve-harness.Variants.
-- --variant v1writes a new variant directory, compared side by side in the report.EVAL_SERVER_INSTRUCTIONS=name|offchanges what the app tells the model (see.claude/hillclimb/deposit-law/v*/change.md).Re-grade after a grader fix, without running the model again:
node evals/regrade.mjs <flow dir>Cost (measured 2026-11-01): about $0.12 per user case and $0.20 per security case. The "compare every pair of states" attack alone costs about $1.50.
Results (results.jsonl) are committed. Transcripts and reports stay local.
License
Code, docs and evals: MIT.
Deposit-law data (
data/): CC BY 4.0. Reuse it freely, including commercially, but credit PropInspect and link to the state guide each fact comes from. See ADR 0006.
The guide content is general information, not legal advice.
Available Tools
3 toolscompare_statesCompare security deposit rules across statesARead-onlyIdempotent
Use when the user wants to compare security deposit rules between 2 to 6 US states (for example a landlord with rentals in several states). Pass two-letter state codes. Returns one row per state with its own citation; places that are not covered are listed by their position in the input.
| Name | Required | Description | Default |
|---|---|---|---|
| states | Yes | 2 to 6 two-letter state codes, e.g. ["CA", "NV"]. |
Output Schema
| Name | Required | Description |
|---|---|---|
| rows | Yes | |
| notCovered | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly, idempotent, non-destructive, closed-world behavior, so the safety profile is covered. The description adds real value beyond that by disclosing the return shape (one row per state, each with its own citation) and the handling of uncovered places by input position.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences with zero filler: trigger condition first, input format second, return behavior third. Each sentence carries distinct information an agent needs.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, the description does not need to enumerate return fields, and it still explains the row-per-state/citation structure and the uncovered-state behavior. Annotations cover safety and the single parameter is fully documented, so nothing material is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3. The description adds meaning on top: the two-letter format convention and, more importantly, the fallback semantics for entries that are not covered, which the schema does not express.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (compare) and resource (security deposit rules) with explicit scope (2 to 6 US states). This clearly separates it from get_deposit_rules (single-state lookup) and list_covered_states (enumeration) without either schema being opened.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The opening 'Use when the user wants to compare... between 2 to 6 US states' plus the concrete landlord-with-multiple-rentals example gives a clear trigger condition. It does not explicitly name the sibling tools as alternatives, so it stops just short of full routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_deposit_rulesGet a state's security deposit rulesARead-onlyIdempotent
Use when the user asks about security deposit rules in one US state: the deposit cap, the deadline to return it or send an itemized list, the penalty for wrongful withholding, or move-in condition records. Pass the two-letter state code (Nevada → NV). Returns the rules with a citation (guide link, review date, statute, disclaimer). If status is "not_covered", tell the user the place is not covered; do not answer from memory. Set include_faqs to true only when the user's question goes beyond the rules (for example cleaning, painting or normal wear and tear).
| Name | Required | Description | Default |
|---|---|---|---|
| state | Yes | Two-letter US state code, e.g. "NV" for Nevada or "NY" for New York. | |
| include_faqs | No | Also return the guide's FAQ answers. Default false. |
Output Schema
| Name | Required | Description |
|---|---|---|
| faqs | No | |
| rules | No | |
| state | No | |
| reason | No | |
| status | Yes | |
| summary | No | |
| citation | No | |
| stateCode | No | |
| references | No | |
| coveredStateCodes | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive/closed-world, so the safety profile is covered. The description adds genuinely new behavior: the response carries a citation (guide link, review date, statute, disclaimer), and a 'not_covered' status must be surfaced to the user rather than answered from memory. Some return-shape detail overlaps the existing output schema, which keeps it from a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the trigger and scope, then input, then output, then the two conditional caveats — a logical order with no filler sentences. Every clause carries actionable information for the caller.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers trigger, input format, return contents (including citation fields), the non-covered edge case, and the optional-parameter rule. With an output schema present, the description need not detail field structure, and nothing needed to call this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3, but the description earns extra credit by giving real gating logic for include_faqs ('only when the question goes beyond the rules — cleaning, painting, normal wear and tear') rather than just restating the boolean. The state-code guidance ('Nevada → NV') largely duplicates the schema's own example.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource (security deposit rules), scopes it to exactly one US state, and enumerates the content returned (cap, return deadline, itemized list, penalty, condition records). The single-state scope implicitly separates it from compare_states and list_covered_states without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Opens with an explicit trigger ('Use when the user asks about...') and adds a clear conditional rule for include_faqs plus a fallback instruction for 'not_covered' responses. It stops short of naming sibling tools as alternatives, so the agent must still infer when to prefer compare_states for multi-state questions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_covered_statesList the states this server coversARead-onlyIdempotent
Use when the user asks which states are covered, or before comparing many states. Returns every covered state with its guide link and review date.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| count | Yes | |
| states | Yes | |
| reviewedBetween | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, destructiveHint=false and openWorldHint=false, so the safety profile is fully covered. The description adds genuine value beyond that by disclosing the return contents (guide link and review date) and that the result set is 'every' covered state, i.e. unfiltered and complete. It does not mention ordering or size, which keeps it below a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, zero filler, and the usage trigger is front-loaded ahead of the return description. Every clause earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-param, read-only discovery tool with full annotation coverage and an output schema, nothing is missing: the agent knows when to call it, that it takes no arguments, and roughly what it returns. The output schema carries the return-shape detail the description does not need to repeat.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Zero-parameter tool, so per the baseline this lands at 4. The description's phrasing ('every covered state') quietly confirms there is nothing to filter by, which is consistent with the empty schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific verb and resource ('list'/'every covered state') and even states the payload ('guide link and review date'), so the agent knows exactly what comes back. It only weakly differentiates from the sibling compare_states ('before comparing many states' implies but never names it), and says nothing about get_deposit_rules.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
'Use when the user asks which states are covered, or before comparing many states' gives a clear triggering condition and a sequencing hint that steers the agent toward this discovery step before comparison. It stops short of an explicit exclusion or a named alternative, so it is clear context rather than full when/when-not guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
3 tool updates
v0.1.0- First observed
compare_states - First observed
get_deposit_rules - First observed
list_covered_states
TDQS
Scored across 3 tools
The three tools target distinct operations: enumerating the coverage list, fetching one state's rules, and comparing 2-6 states. The only overlap is that compare_states is effectively a batched get_deposit_rules, but the descriptions explicitly state when to use each (single-state question vs. multi-state comparison), so misselection risk is low.
All three names follow a clean verb_noun snake_case pattern (list_covered_states, get_deposit_rules, compare_states). The verbs are distinct and accurately reflect each action.
Three tools is a lean but adequate surface for a narrow read-only reference domain (list coverage, get one state, compare several). It sits at the low end of well-scoped, with no redundant tools, though a search-by-topic entry point is absent.
Discovery, single-state retrieval, and multi-state comparison cover the core lifecycle for a read-only legal-reference service; no create/update/delete is needed. Minor gaps exist: there is no full-text or topic query across states, and FAQs are only reachable as a flag on get_deposit_rules.
Maintenance
Related MCP Connectors
Check US leases for red flags and look up verified state tenant law with statute citations.
Deterministic, source-cited rental property tools: turnover estimates and deposit rules by US state.
Federal and 50-state legislative data for AI: bills, text, votes, members, and committees.
Verified, citable German & EU law for any LLM. Daily updates from official sources, hosted in DE.
Related MCP Servers
- FlicenseNot gradedqualityNot gradedmaintenanceProvides AI agents with instant access to jurisdiction-specific landlord-tenant law data and verified state statutes across five US states and major cities. It enables users to query legal rules for security deposits, eviction timelines, and habitability standards with sub-10ms local response times.-
- AlicenseNot gradedqualityDmaintenanceEnables AI assistants to operate property management systems via natural language, covering repair orders, owner info, payments, notices, and inspections. Features a full agentic workflow with human-in-the-loop and observability.1MIT

Legalizeofficial
AlicenseNot gradedqualityBmaintenanceEnables AI assistants to search and read consolidated legislation from multiple countries, retrieve exact law texts as of any historical date with citations and git commit SHAs, and create webhook or email subscriptions to track legal changes.2MIT- AlicenseNot gradedqualityCmaintenanceEnables AI assistants to retrieve verbatim U.S. mortgage regulations with citations and effective dates, verify quotes, and run guided compliance playbooks without sending user documents to the server.MIT