titlemcp 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. titlemcp-0.1.0/.env.example +54 -0
  2. titlemcp-0.1.0/.gitignore +27 -0
  3. titlemcp-0.1.0/LICENSE +7 -0
  4. titlemcp-0.1.0/PKG-INFO +398 -0
  5. titlemcp-0.1.0/README.md +344 -0
  6. titlemcp-0.1.0/docs/ARCHITECTURE.md +113 -0
  7. titlemcp-0.1.0/docs/JURISDICTION_PACKAGES.md +137 -0
  8. titlemcp-0.1.0/docs/JURISDICTION_STRUCTURE.md +92 -0
  9. titlemcp-0.1.0/docs/PUBLISHING.md +87 -0
  10. titlemcp-0.1.0/docs/jurisdiction-adapters.example.json +45 -0
  11. titlemcp-0.1.0/examples/mcp_stdio_smoke.py +51 -0
  12. titlemcp-0.1.0/examples/ollama_prompt.py +22 -0
  13. titlemcp-0.1.0/pyproject.toml +133 -0
  14. titlemcp-0.1.0/scripts/generate_us_jurisdiction_tree.py +417 -0
  15. titlemcp-0.1.0/src/title_mcp/__init__.py +7 -0
  16. titlemcp-0.1.0/src/title_mcp/_version.py +8 -0
  17. titlemcp-0.1.0/src/title_mcp/adapters/__init__.py +28 -0
  18. titlemcp-0.1.0/src/title_mcp/adapters/base.py +60 -0
  19. titlemcp-0.1.0/src/title_mcp/adapters/configurable.py +66 -0
  20. titlemcp-0.1.0/src/title_mcp/adapters/default.py +257 -0
  21. titlemcp-0.1.0/src/title_mcp/adapters/registry.py +76 -0
  22. titlemcp-0.1.0/src/title_mcp/capabilities/__init__.py +12 -0
  23. titlemcp-0.1.0/src/title_mcp/capabilities/base.py +52 -0
  24. titlemcp-0.1.0/src/title_mcp/capabilities/registry.py +50 -0
  25. titlemcp-0.1.0/src/title_mcp/client/__init__.py +3 -0
  26. titlemcp-0.1.0/src/title_mcp/client/ollama_bridge.py +103 -0
  27. titlemcp-0.1.0/src/title_mcp/domain/__init__.py +161 -0
  28. titlemcp-0.1.0/src/title_mcp/domain/auditor.py +205 -0
  29. titlemcp-0.1.0/src/title_mcp/domain/commitment.py +237 -0
  30. titlemcp-0.1.0/src/title_mcp/domain/exam.py +250 -0
  31. titlemcp-0.1.0/src/title_mcp/domain/models.py +249 -0
  32. titlemcp-0.1.0/src/title_mcp/domain/parcel.py +160 -0
  33. titlemcp-0.1.0/src/title_mcp/domain/responses.py +29 -0
  34. titlemcp-0.1.0/src/title_mcp/domain/title.py +148 -0
  35. titlemcp-0.1.0/src/title_mcp/mcp/__init__.py +25 -0
  36. titlemcp-0.1.0/src/title_mcp/mcp/server.py +557 -0
  37. titlemcp-0.1.0/src/title_mcp/mcp/tool_catalog.py +688 -0
  38. titlemcp-0.1.0/src/title_mcp/mcp/toolsets.py +31 -0
  39. titlemcp-0.1.0/src/title_mcp/observability/__init__.py +4 -0
  40. titlemcp-0.1.0/src/title_mcp/observability/logging.py +70 -0
  41. titlemcp-0.1.0/src/title_mcp/observability/tracing.py +36 -0
  42. titlemcp-0.1.0/src/title_mcp/platform.py +114 -0
  43. titlemcp-0.1.0/src/title_mcp/plugins/__init__.py +4 -0
  44. titlemcp-0.1.0/src/title_mcp/plugins/base.py +26 -0
  45. titlemcp-0.1.0/src/title_mcp/plugins/loader.py +14 -0
  46. titlemcp-0.1.0/src/title_mcp/py.typed +1 -0
  47. titlemcp-0.1.0/src/title_mcp/services/__init__.py +43 -0
  48. titlemcp-0.1.0/src/title_mcp/services/clause_sets.py +251 -0
  49. titlemcp-0.1.0/src/title_mcp/services/commitment.py +643 -0
  50. titlemcp-0.1.0/src/title_mcp/services/document_analysis.py +42 -0
  51. titlemcp-0.1.0/src/title_mcp/services/exam.py +610 -0
  52. titlemcp-0.1.0/src/title_mcp/services/exam_extraction.py +1284 -0
  53. titlemcp-0.1.0/src/title_mcp/services/form_fingerprint.py +169 -0
  54. titlemcp-0.1.0/src/title_mcp/services/workflows.py +124 -0
  55. titlemcp-0.1.0/src/title_mcp/settings.py +94 -0
  56. titlemcp-0.1.0/src/title_mcp/sources/__init__.py +48 -0
  57. titlemcp-0.1.0/src/title_mcp/sources/base.py +89 -0
  58. titlemcp-0.1.0/src/title_mcp/sources/hoa_serpapi.py +1175 -0
  59. titlemcp-0.1.0/src/title_mcp/sources/pacer.py +599 -0
  60. titlemcp-0.1.0/src/title_mcp/sources/registry.py +54 -0
  61. titlemcp-0.1.0/src/title_mcp/sources/regrid.py +1112 -0
  62. titlemcp-0.1.0/src/title_mcp/state/__init__.py +11 -0
  63. titlemcp-0.1.0/src/title_mcp/state/base.py +26 -0
  64. titlemcp-0.1.0/src/title_mcp/state/factory.py +16 -0
  65. titlemcp-0.1.0/src/title_mcp/state/memory.py +49 -0
  66. titlemcp-0.1.0/src/title_mcp/state/postgres.py +136 -0
  67. titlemcp-0.1.0/src/title_mcp/vendors/__init__.py +20 -0
  68. titlemcp-0.1.0/src/title_mcp/vendors/base.py +82 -0
  69. titlemcp-0.1.0/src/title_mcp/vendors/registry.py +57 -0
  70. titlemcp-0.1.0/src/title_mcp/workflows/__init__.py +3 -0
  71. titlemcp-0.1.0/src/title_mcp/workflows/engine.py +230 -0
  72. titlemcp-0.1.0/templates/jurisdiction-package/README.md +22 -0
  73. titlemcp-0.1.0/templates/jurisdiction-package/pyproject.toml +35 -0
  74. titlemcp-0.1.0/templates/jurisdiction-package/src/titlemcp_us_oh_franklin_recorder/__init__.py +9 -0
  75. titlemcp-0.1.0/templates/jurisdiction-package/src/titlemcp_us_oh_franklin_recorder/adapters.py +44 -0
  76. titlemcp-0.1.0/templates/jurisdiction-package/src/titlemcp_us_oh_franklin_recorder/client.py +56 -0
  77. titlemcp-0.1.0/templates/jurisdiction-package/src/titlemcp_us_oh_franklin_recorder/manifest.py +33 -0
  78. titlemcp-0.1.0/templates/jurisdiction-package/src/titlemcp_us_oh_franklin_recorder/py.typed +1 -0
  79. titlemcp-0.1.0/templates/jurisdiction-package/src/titlemcp_us_oh_franklin_recorder/sources.py +55 -0
  80. titlemcp-0.1.0/templates/jurisdiction-package/titlemcp-capability.toml +27 -0
  81. titlemcp-0.1.0/tests/test_adapters.py +139 -0
  82. titlemcp-0.1.0/tests/test_exam_commitment.py +1201 -0
  83. titlemcp-0.1.0/tests/test_exam_extraction.py +760 -0
  84. titlemcp-0.1.0/tests/test_extension_contracts.py +182 -0
  85. titlemcp-0.1.0/tests/test_form_fingerprint.py +159 -0
  86. titlemcp-0.1.0/tests/test_hoa_serpapi.py +440 -0
  87. titlemcp-0.1.0/tests/test_mcp_discovery.py +251 -0
  88. titlemcp-0.1.0/tests/test_pacer.py +154 -0
  89. titlemcp-0.1.0/tests/test_packaging.py +51 -0
  90. titlemcp-0.1.0/tests/test_regrid.py +258 -0
  91. titlemcp-0.1.0/tests/test_workflows.py +93 -0
@@ -0,0 +1,54 @@
1
+ TITLE_MCP_APP_NAME="Title Operations MCP"
2
+ TITLE_MCP_ENVIRONMENT=local
3
+ TITLE_MCP_LOG_LEVEL=INFO
4
+ TITLE_MCP_LOG_JSON=true
5
+
6
+ # Use memory for local prototyping. Use postgres for durable deployments.
7
+ TITLE_MCP_STATE_BACKEND=memory
8
+ TITLE_MCP_POSTGRES_DSN=postgresql://title_mcp:title_mcp@localhost:5432/title_mcp
9
+
10
+ TITLE_MCP_MCP_TRANSPORT=stdio
11
+ TITLE_MCP_MCP_HOST=127.0.0.1
12
+ TITLE_MCP_MCP_PORT=8000
13
+ TITLE_MCP_MCP_PUBLIC_URL=
14
+ TITLE_MCP_INSPECTOR_URL=
15
+ TITLE_MCP_INSPECTOR_BACKEND_URL=
16
+ TITLE_MCP_MCP_DNS_REBINDING_PROTECTION=true
17
+ TITLE_MCP_MCP_ALLOWED_HOSTS=
18
+ TITLE_MCP_MCP_ALLOWED_ORIGINS=
19
+
20
+ TITLE_MCP_OLLAMA_MODEL=qwen3
21
+ TITLE_MCP_JURISDICTION_CONFIG_PATH=
22
+
23
+ # PACER Case Locator API credentials. Leave blank until a deployment is authorized to query PACER.
24
+ TITLE_MCP_PACER_USERNAME=
25
+ TITLE_MCP_PACER_PASSWORD=
26
+ TITLE_MCP_PACER_CLIENT_CODE=
27
+ TITLE_MCP_PACER_QA_MODE=false
28
+ TITLE_MCP_PACER_TIMEOUT_SECONDS=30
29
+
30
+ # Parcel lookup provider. Smart proxy is required for this source.
31
+ TITLE_MCP_SMART_PROXY=
32
+ TITLE_MCP_REGRID_PROXY_PORT_START=10001
33
+ TITLE_MCP_REGRID_PROXY_PORT_END=10999
34
+ TITLE_MCP_REGRID_MAX_RETRIES=5
35
+ TITLE_MCP_REGRID_BACKOFF_FACTOR=0.5
36
+ TITLE_MCP_REGRID_COOKIE_REFRESH_THRESHOLD=25
37
+ TITLE_MCP_REGRID_MAX_PROXY_ATTEMPTS=10
38
+ TITLE_MCP_REGRID_TIMEOUT_SECONDS=10
39
+ TITLE_MCP_REGRID_COOKIE_TIMEOUT_SECONDS=5
40
+
41
+ # SerpAPI Google search for HOA contact lookup.
42
+ TITLE_MCP_SERPAPI_API_KEY=
43
+ TITLE_MCP_SERPAPI_TIMEOUT_SECONDS=30
44
+
45
+ TITLE_MCP_LOAD_ENTRY_POINT_CAPABILITIES=true
46
+ TITLE_MCP_LOAD_ENTRY_POINT_ADAPTERS=true
47
+ TITLE_MCP_LOAD_ENTRY_POINT_SOURCES=true
48
+ TITLE_MCP_LOAD_ENTRY_POINT_VENDORS=true
49
+ TITLE_MCP_LOAD_ENTRY_POINT_TOOLSETS=true
50
+ TITLE_MCP_LOAD_ENTRY_POINT_PLUGINS=false
51
+
52
+ # Optional AWS Textract settings for a production document-analysis plugin/service.
53
+ TITLE_MCP_AWS_REGION=us-east-1
54
+ TITLE_MCP_TEXTRACT_S3_BUCKET=
@@ -0,0 +1,27 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.pyo
5
+ *.pyd
6
+ *.egg-info/
7
+ .pytest_cache/
8
+ .ruff_cache/
9
+ .mypy_cache/
10
+ .coverage
11
+ htmlcov/
12
+
13
+ # Builds and packaging
14
+ build/
15
+ dist/
16
+ wheelhouse/
17
+
18
+ # Local environments
19
+ .venv/
20
+ venv/
21
+ .env
22
+ !.env.example
23
+
24
+ # Editors and OS files
25
+ .idea/
26
+ .vscode/
27
+ .DS_Store
titlemcp-0.1.0/LICENSE ADDED
@@ -0,0 +1,7 @@
1
+ Copyright (c) 2026 Razi Title MCP Contributors.
2
+
3
+ All rights reserved.
4
+
5
+ This repository is currently prepared for private or commercial package distribution. Before
6
+ publishing as open source, replace this file and the `license` metadata in `pyproject.toml`
7
+ with the selected open-source license, such as Apache-2.0 or MIT.
@@ -0,0 +1,398 @@
1
+ Metadata-Version: 2.5
2
+ Name: titlemcp
3
+ Version: 0.1.0
4
+ Summary: Reusable MCP platform for title and real estate service operations.
5
+ Author: Razi Title MCP Contributors
6
+ Maintainer: Razi Title MCP Contributors
7
+ License-Expression: LicenseRef-Proprietary
8
+ License-File: LICENSE
9
+ Keywords: mcp,model-context-protocol,ollama,real-estate,title,workflow
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: Other/Proprietary License
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Topic :: Office/Business
18
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
19
+ Classifier: Typing :: Typed
20
+ Requires-Python: >=3.12
21
+ Requires-Dist: mcp<2.0,>=1.27.1
22
+ Requires-Dist: ollama<1.0,>=0.6.2
23
+ Requires-Dist: pydantic-settings<3.0,>=2.14.1
24
+ Requires-Dist: pydantic<3.0,>=2.13.4
25
+ Requires-Dist: requests<3.0,>=2.32.0
26
+ Provides-Extra: anthropic
27
+ Requires-Dist: anthropic>=0.75.0; extra == 'anthropic'
28
+ Requires-Dist: pillow>=10.0; extra == 'anthropic'
29
+ Provides-Extra: aws
30
+ Requires-Dist: boto3>=1.35.0; extra == 'aws'
31
+ Provides-Extra: dev
32
+ Requires-Dist: build>=1.2.0; extra == 'dev'
33
+ Requires-Dist: pytest>=8.0.0; extra == 'dev'
34
+ Requires-Dist: ruff>=0.8.0; extra == 'dev'
35
+ Requires-Dist: twine>=5.0.0; extra == 'dev'
36
+ Provides-Extra: jurisdictions
37
+ Requires-Dist: titlemcp-us-oh-auditor>=0.1.0; extra == 'jurisdictions'
38
+ Requires-Dist: titlemcp-us-oh-franklin-recorder>=0.1.0; extra == 'jurisdictions'
39
+ Provides-Extra: postgres
40
+ Requires-Dist: asyncpg>=0.30.0; extra == 'postgres'
41
+ Provides-Extra: publish
42
+ Requires-Dist: build>=1.2.0; extra == 'publish'
43
+ Requires-Dist: twine>=5.0.0; extra == 'publish'
44
+ Provides-Extra: test
45
+ Requires-Dist: pillow>=10.0; extra == 'test'
46
+ Provides-Extra: us-oh-auditor
47
+ Requires-Dist: titlemcp-us-oh-auditor>=0.1.0; extra == 'us-oh-auditor'
48
+ Provides-Extra: us-oh-franklin
49
+ Requires-Dist: titlemcp-us-oh-auditor>=0.1.0; extra == 'us-oh-franklin'
50
+ Requires-Dist: titlemcp-us-oh-franklin-recorder>=0.1.0; extra == 'us-oh-franklin'
51
+ Provides-Extra: us-oh-franklin-recorder
52
+ Requires-Dist: titlemcp-us-oh-franklin-recorder>=0.1.0; extra == 'us-oh-franklin-recorder'
53
+ Description-Content-Type: text/markdown
54
+
55
+ # Razi Title MCP
56
+
57
+ Python MCP platform for title companies that want to expand their MCP server
58
+ toolkit with practical title and real estate service operations. TitleMCP
59
+ provides structured tools for source lookups, jurisdiction-specific searches,
60
+ vendor requests, and review-first workflows that local LLMs, hosted agents, and
61
+ internal automation can call through MCP.
62
+
63
+ The project is structured as a reusable framework rather than a pile of tool
64
+ scripts: MCP tools delegate into typed workflow services, workflow state is
65
+ persisted behind repository interfaces, and county/state behavior is supplied
66
+ through jurisdiction adapters or plugins. Tools should return predictable domain
67
+ records, preserve source-specific evidence, and leave legal or underwriting
68
+ judgment to a human reviewer.
69
+
70
+ If you are new to the project, start with the root docs:
71
+ [docs/README.md](../../docs/README.md).
72
+
73
+ ## What Is Included
74
+
75
+ - FastMCP server with reusable title operations tools
76
+ - MCP client bridge for Ollama/local LLM function calling
77
+ - Pydantic domain schemas for workflows, audits, reviews, tasks, orders, and jurisdictions
78
+ - Async workflow engine with review-first state transitions
79
+ - In-memory repository for local development and tests
80
+ - Optional Postgres repository for durable JSONB workflow persistence
81
+ - Adapter, source connector, vendor connector, capability, and toolset registries
82
+ - Plugin and package loading through Python entry points
83
+ - Structured JSON logging and lightweight trace spans
84
+ - Source-tree smoke examples under `examples/`
85
+
86
+ ## Architecture
87
+
88
+ ```text
89
+ MCP tools
90
+ -> WorkflowService
91
+ -> WorkflowEngine
92
+ -> WorkflowRepository
93
+ -> JurisdictionAdapter
94
+ -> SourceConnectorRegistry
95
+ -> VendorConnectorRegistry
96
+ -> CapabilityRegistry
97
+ ```
98
+
99
+ The MCP layer is intentionally thin. Business state lives in `WorkflowRecord` models and repositories, so the same services can later be embedded into Django views, Celery tasks, or admin workflows.
100
+
101
+ Human review is first-class. The included workflows plan and track work, but they do not make autonomous legal or underwriting decisions.
102
+
103
+ See [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) for the extension boundaries and package
104
+ entry-point contracts.
105
+
106
+ ## Jurisdiction Routing
107
+
108
+ Jurisdictions are modeled as `country`, `state`, `county`, and `municipality`. Routing resolves the
109
+ most specific adapter that supports both the jurisdiction and the workflow kind. For example:
110
+
111
+ - `US`, `MD`, `Baltimore`, `Baltimore City` routes public records searches to a Baltimore City adapter.
112
+ - `US`, `FL`, `Dade` or `Miami-Dade` routes public records searches to a Miami-Dade adapter.
113
+ - Other workflows in the same place can still fall back to state or generic adapters.
114
+
115
+ You can configure additional jurisdiction-specific adapters with JSON:
116
+
117
+ ```bash
118
+ TITLE_MCP_JURISDICTION_CONFIG_PATH=docs/jurisdiction-adapters.example.json titlemcp-server
119
+ ```
120
+
121
+ See [docs/jurisdiction-adapters.example.json](docs/jurisdiction-adapters.example.json) for the
122
+ shape of a configured adapter.
123
+
124
+ The monorepo also includes a generated `jurisdiction-catalog/` workspace at the repository root so
125
+ it is clear where country/state/county/municipality capabilities fit. See
126
+ [docs/JURISDICTION_STRUCTURE.md](docs/JURISDICTION_STRUCTURE.md) for the convention and refresh
127
+ command.
128
+
129
+ Reusable jurisdiction behavior should be distributed as its own pip package. For example:
130
+
131
+ ```bash
132
+ python -m pip install "titlemcp[us-oh-franklin]"
133
+ ```
134
+
135
+ This installs the `titlemcp-us-oh-franklin-recorder` jurisdiction package and `titlemcp` discovers
136
+ its manifest, adapter, and source connector through Python entry points by default. See
137
+ [docs/JURISDICTION_PACKAGES.md](docs/JURISDICTION_PACKAGES.md) and the template in
138
+ `packages/titlemcp/templates/jurisdiction-package/`.
139
+
140
+ ## Local Setup
141
+
142
+ ```bash
143
+ python -m venv .venv
144
+ .venv/bin/pip install -e packages/titlemcp
145
+ ```
146
+
147
+ From inside `packages/titlemcp`, use `python -m pip install -e .` instead.
148
+
149
+ For the existing local virtualenv in this monorepo, you can run without reinstalling by setting
150
+ `PYTHONPATH`:
151
+
152
+ ```bash
153
+ PYTHONPATH=packages/titlemcp/src .venv/bin/python -m title_mcp.mcp.server
154
+ ```
155
+
156
+ ## Install From A Package
157
+
158
+ After publishing, install with:
159
+
160
+ ```bash
161
+ python -m pip install titlemcp
162
+ ```
163
+
164
+ Optional extras:
165
+
166
+ ```bash
167
+ python -m pip install "titlemcp[postgres]"
168
+ python -m pip install "titlemcp[aws]"
169
+ ```
170
+
171
+ Jurisdiction extras install jurisdiction packages with the framework:
172
+
173
+ ```bash
174
+ python -m pip install "titlemcp[us-oh-franklin]"
175
+ ```
176
+
177
+ That extra depends on the separate `titlemcp-us-oh-franklin-recorder` package. It must be available
178
+ on PyPI or on the private package index configured for your deployment.
179
+
180
+ ## Run The MCP Server
181
+
182
+ Stdio transport, suitable for MCP clients:
183
+
184
+ ```bash
185
+ titlemcp-server
186
+ ```
187
+
188
+ HTTP transport:
189
+
190
+ ```bash
191
+ TITLE_MCP_MCP_TRANSPORT=streamable-http titlemcp-server
192
+ ```
193
+
194
+ When running from a source checkout without installing the package:
195
+
196
+ ```bash
197
+ PYTHONPATH=packages/titlemcp/src .venv/bin/python -m title_mcp.mcp.server
198
+ ```
199
+
200
+ ## Try The MCP Smoke Client
201
+
202
+ ```bash
203
+ PYTHONPATH=packages/titlemcp/src .venv/bin/python packages/titlemcp/examples/mcp_stdio_smoke.py
204
+ ```
205
+
206
+ The client lists MCP tools and creates a municipal lien search workflow.
207
+
208
+ ## MCP Inspector Support
209
+
210
+ In Streamable HTTP mode, MCP Inspector can browse tools, resources, and prompts.
211
+ TitleMCP exposes read-only resources for server info, sanitized runtime config,
212
+ tool catalog/detail, and workflow kinds:
213
+
214
+ ```text
215
+ titlemcp://server/info
216
+ titlemcp://server/runtime
217
+ titlemcp://tools/catalog
218
+ titlemcp://tools/{tool_name}
219
+ titlemcp://workflows/kinds
220
+ ```
221
+
222
+ Prompt templates are available for title workflow intake, parcel lookup review,
223
+ HOA contact review, and sample prompts derived from the Ollama examples. HTTP
224
+ health checks are available at `/healthz` and `/readyz`.
225
+
226
+ ## Ollama Client
227
+
228
+ Make sure Ollama is running and the configured model is available, then run:
229
+
230
+ ```bash
231
+ titlemcp-ollama
232
+ ```
233
+
234
+ Or:
235
+
236
+ ```bash
237
+ titlemcp-ollama \
238
+ "Create an HOA estoppel workflow for file 2025-123 in Orange County, FL"
239
+ ```
240
+
241
+ Set `TITLE_MCP_OLLAMA_MODEL` to change the model.
242
+
243
+ ## HOA Contact Search
244
+
245
+ The core MCP server includes `hoa_contact_search`, which searches Google through SerpAPI for HOA
246
+ contact candidates by association name and optional state. The tool returns
247
+ `title_mcp.hoa_contact_search` records with candidate websites, addresses, phone numbers, and email
248
+ addresses when those fields are available from search result snippets or place panels.
249
+ The connector first identifies a likely official HOA domain, then performs a second
250
+ `site:<domain>` search for contact, management, assessment, payment, and board pages.
251
+
252
+ ```env
253
+ TITLE_MCP_SERPAPI_API_KEY=
254
+ TITLE_MCP_SERPAPI_TIMEOUT_SECONDS=30
255
+ ```
256
+
257
+ Keep SerpAPI credentials in `.env` or deployment secrets. Do not hardcode keys in client samples or
258
+ application code.
259
+
260
+ ## PACER Bankruptcy Search
261
+
262
+ The core MCP server includes `pacer_bankruptcy_search`, which uses the PACER Case Locator
263
+ party-search API for bankruptcy searches. Configure credentials in `.env` or the process
264
+ environment:
265
+
266
+ ```env
267
+ TITLE_MCP_PACER_USERNAME=
268
+ TITLE_MCP_PACER_PASSWORD=
269
+ TITLE_MCP_PACER_CLIENT_CODE=
270
+ TITLE_MCP_PACER_QA_MODE=false
271
+ TITLE_MCP_PACER_TIMEOUT_SECONDS=30
272
+ ```
273
+
274
+ The tool returns a deterministic `title_mcp.pacer_bankruptcy_search` record with redacted tax
275
+ identifiers, case rows, and a title-officer review flag. It does not use LLM summarization or local
276
+ application caching. Production PACER searches may be billable; use `TITLE_MCP_PACER_QA_MODE=true`
277
+ with QA credentials for non-billable API testing.
278
+
279
+ ## Parcel Lookup
280
+
281
+ The core MCP server includes `parcel_lookup`, which searches parcel data by address and returns a
282
+ canonical `title_mcp.parcel_record`. This source requires provider configuration and will return
283
+ `requires_configuration` when it is not configured.
284
+
285
+ ```env
286
+ TITLE_MCP_SMART_PROXY=
287
+ TITLE_MCP_REGRID_PROXY_PORT_START=10001
288
+ TITLE_MCP_REGRID_PROXY_PORT_END=10999
289
+ TITLE_MCP_REGRID_MAX_RETRIES=5
290
+ TITLE_MCP_REGRID_BACKOFF_FACTOR=0.5
291
+ TITLE_MCP_REGRID_COOKIE_REFRESH_THRESHOLD=25
292
+ TITLE_MCP_REGRID_MAX_PROXY_ATTEMPTS=10
293
+ TITLE_MCP_REGRID_TIMEOUT_SECONDS=10
294
+ TITLE_MCP_REGRID_COOKIE_TIMEOUT_SECONDS=5
295
+ ```
296
+
297
+ Set `TITLE_MCP_SMART_PROXY` to the provider proxy host/auth portion without the rotating port, for
298
+ example `user:password@proxy.example.com`. The legacy `SMART_PROXY` environment variable is also
299
+ supported. `TITLE_MCP_REGRID_MAX_PROXY_ATTEMPTS` bounds how many rotating proxy endpoints are tried
300
+ per request so bad proxy configuration fails visibly instead of walking the full port range.
301
+
302
+ ## State Backends
303
+
304
+ Local default:
305
+
306
+ ```env
307
+ TITLE_MCP_STATE_BACKEND=memory
308
+ ```
309
+
310
+ Postgres:
311
+
312
+ ```env
313
+ TITLE_MCP_STATE_BACKEND=postgres
314
+ TITLE_MCP_POSTGRES_DSN=postgresql://title_mcp:title_mcp@localhost:5432/title_mcp
315
+ ```
316
+
317
+ Install the Postgres extra for durable deployments:
318
+
319
+ ```bash
320
+ .venv/bin/pip install -e "packages/titlemcp[postgres]"
321
+ ```
322
+
323
+ The Postgres repository creates a `title_mcp_workflows` table and stores auditable workflow records as JSONB.
324
+
325
+ ## Extending Jurisdictions
326
+
327
+ Create an adapter that implements `JurisdictionAdapter`:
328
+
329
+ ```python
330
+ from title_mcp.adapters.base import AdapterPlan, JurisdictionScope
331
+ from title_mcp.domain.models import Jurisdiction, WorkflowKind, WorkflowRequest
332
+
333
+
334
+ class MiamiDadePublicRecordsAdapter:
335
+ adapter_id = "us-fl-miami-dade-public-records"
336
+ priority = 150
337
+ workflow_kinds = frozenset({WorkflowKind.PUBLIC_RECORDS_SEARCH})
338
+ scope = JurisdictionScope(country="US", state="FL", county="Miami-Dade")
339
+
340
+ def supports(self, jurisdiction: Jurisdiction) -> bool:
341
+ return self.scope.matches(jurisdiction)
342
+
343
+ async def plan(self, request: WorkflowRequest) -> AdapterPlan:
344
+ ...
345
+ ```
346
+
347
+ Adapters can be registered directly on `TitleMCPPlatform.adapters`, exposed through the
348
+ `title_mcp.adapters` entry point group, or loaded from `TITLE_MCP_JURISDICTION_CONFIG_PATH`.
349
+ Packages can also register source connectors with `title_mcp.sources`, vendor connectors with
350
+ `title_mcp.vendors`, capability manifests with `title_mcp.capabilities`, and optional MCP toolsets
351
+ with `title_mcp.toolsets`.
352
+
353
+ ## Tool Surface
354
+
355
+ The server exposes a generic `start_title_workflow` tool plus convenience tools:
356
+
357
+ - `analyze_document`
358
+ - `request_public_records_search`
359
+ - `request_hoa_estoppel`
360
+ - `request_municipal_lien_search`
361
+ - `request_tax_certificate`
362
+ - `track_release`
363
+ - `parse_payoff_letter`
364
+ - `generate_checklist_packet`
365
+ - `get_workflow_status`
366
+ - `list_workflows`
367
+ - `submit_human_review`
368
+ - `list_title_capabilities`
369
+ - `list_source_connectors`
370
+ - `list_vendor_connectors`
371
+
372
+ These wrappers all create normal workflow records, so private deployments can add or replace tools
373
+ without changing the state model. Core tools live in `src/title_mcp/mcp/tool_catalog.py`; optional
374
+ packages should use the `title_mcp.toolsets` entry point only when they need additional MCP-facing
375
+ commands.
376
+
377
+ ## Tests
378
+
379
+ ```bash
380
+ PYTHONPATH=packages/titlemcp/src .venv/bin/python -m unittest discover \
381
+ -s packages/titlemcp/tests -v
382
+ ```
383
+
384
+ ## Build And Publish
385
+
386
+ ```bash
387
+ .venv/bin/pip install -e "packages/titlemcp[publish]"
388
+ rm -rf packages/titlemcp/dist packages/titlemcp/build packages/titlemcp/*.egg-info
389
+ cd packages/titlemcp
390
+ ../../.venv/bin/python -m build
391
+ ../../.venv/bin/python -m twine check dist/*
392
+ ```
393
+
394
+ See [docs/PUBLISHING.md](docs/PUBLISHING.md) for TestPyPI, PyPI, and trusted publishing notes.
395
+
396
+ The current package metadata is marked `LicenseRef-Proprietary` for private/commercial
397
+ distribution. Replace `LICENSE` and the `license` field in `pyproject.toml` before publishing as
398
+ open source.