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.
- titlemcp-0.1.0/.env.example +54 -0
- titlemcp-0.1.0/.gitignore +27 -0
- titlemcp-0.1.0/LICENSE +7 -0
- titlemcp-0.1.0/PKG-INFO +398 -0
- titlemcp-0.1.0/README.md +344 -0
- titlemcp-0.1.0/docs/ARCHITECTURE.md +113 -0
- titlemcp-0.1.0/docs/JURISDICTION_PACKAGES.md +137 -0
- titlemcp-0.1.0/docs/JURISDICTION_STRUCTURE.md +92 -0
- titlemcp-0.1.0/docs/PUBLISHING.md +87 -0
- titlemcp-0.1.0/docs/jurisdiction-adapters.example.json +45 -0
- titlemcp-0.1.0/examples/mcp_stdio_smoke.py +51 -0
- titlemcp-0.1.0/examples/ollama_prompt.py +22 -0
- titlemcp-0.1.0/pyproject.toml +133 -0
- titlemcp-0.1.0/scripts/generate_us_jurisdiction_tree.py +417 -0
- titlemcp-0.1.0/src/title_mcp/__init__.py +7 -0
- titlemcp-0.1.0/src/title_mcp/_version.py +8 -0
- titlemcp-0.1.0/src/title_mcp/adapters/__init__.py +28 -0
- titlemcp-0.1.0/src/title_mcp/adapters/base.py +60 -0
- titlemcp-0.1.0/src/title_mcp/adapters/configurable.py +66 -0
- titlemcp-0.1.0/src/title_mcp/adapters/default.py +257 -0
- titlemcp-0.1.0/src/title_mcp/adapters/registry.py +76 -0
- titlemcp-0.1.0/src/title_mcp/capabilities/__init__.py +12 -0
- titlemcp-0.1.0/src/title_mcp/capabilities/base.py +52 -0
- titlemcp-0.1.0/src/title_mcp/capabilities/registry.py +50 -0
- titlemcp-0.1.0/src/title_mcp/client/__init__.py +3 -0
- titlemcp-0.1.0/src/title_mcp/client/ollama_bridge.py +103 -0
- titlemcp-0.1.0/src/title_mcp/domain/__init__.py +161 -0
- titlemcp-0.1.0/src/title_mcp/domain/auditor.py +205 -0
- titlemcp-0.1.0/src/title_mcp/domain/commitment.py +237 -0
- titlemcp-0.1.0/src/title_mcp/domain/exam.py +250 -0
- titlemcp-0.1.0/src/title_mcp/domain/models.py +249 -0
- titlemcp-0.1.0/src/title_mcp/domain/parcel.py +160 -0
- titlemcp-0.1.0/src/title_mcp/domain/responses.py +29 -0
- titlemcp-0.1.0/src/title_mcp/domain/title.py +148 -0
- titlemcp-0.1.0/src/title_mcp/mcp/__init__.py +25 -0
- titlemcp-0.1.0/src/title_mcp/mcp/server.py +557 -0
- titlemcp-0.1.0/src/title_mcp/mcp/tool_catalog.py +688 -0
- titlemcp-0.1.0/src/title_mcp/mcp/toolsets.py +31 -0
- titlemcp-0.1.0/src/title_mcp/observability/__init__.py +4 -0
- titlemcp-0.1.0/src/title_mcp/observability/logging.py +70 -0
- titlemcp-0.1.0/src/title_mcp/observability/tracing.py +36 -0
- titlemcp-0.1.0/src/title_mcp/platform.py +114 -0
- titlemcp-0.1.0/src/title_mcp/plugins/__init__.py +4 -0
- titlemcp-0.1.0/src/title_mcp/plugins/base.py +26 -0
- titlemcp-0.1.0/src/title_mcp/plugins/loader.py +14 -0
- titlemcp-0.1.0/src/title_mcp/py.typed +1 -0
- titlemcp-0.1.0/src/title_mcp/services/__init__.py +43 -0
- titlemcp-0.1.0/src/title_mcp/services/clause_sets.py +251 -0
- titlemcp-0.1.0/src/title_mcp/services/commitment.py +643 -0
- titlemcp-0.1.0/src/title_mcp/services/document_analysis.py +42 -0
- titlemcp-0.1.0/src/title_mcp/services/exam.py +610 -0
- titlemcp-0.1.0/src/title_mcp/services/exam_extraction.py +1284 -0
- titlemcp-0.1.0/src/title_mcp/services/form_fingerprint.py +169 -0
- titlemcp-0.1.0/src/title_mcp/services/workflows.py +124 -0
- titlemcp-0.1.0/src/title_mcp/settings.py +94 -0
- titlemcp-0.1.0/src/title_mcp/sources/__init__.py +48 -0
- titlemcp-0.1.0/src/title_mcp/sources/base.py +89 -0
- titlemcp-0.1.0/src/title_mcp/sources/hoa_serpapi.py +1175 -0
- titlemcp-0.1.0/src/title_mcp/sources/pacer.py +599 -0
- titlemcp-0.1.0/src/title_mcp/sources/registry.py +54 -0
- titlemcp-0.1.0/src/title_mcp/sources/regrid.py +1112 -0
- titlemcp-0.1.0/src/title_mcp/state/__init__.py +11 -0
- titlemcp-0.1.0/src/title_mcp/state/base.py +26 -0
- titlemcp-0.1.0/src/title_mcp/state/factory.py +16 -0
- titlemcp-0.1.0/src/title_mcp/state/memory.py +49 -0
- titlemcp-0.1.0/src/title_mcp/state/postgres.py +136 -0
- titlemcp-0.1.0/src/title_mcp/vendors/__init__.py +20 -0
- titlemcp-0.1.0/src/title_mcp/vendors/base.py +82 -0
- titlemcp-0.1.0/src/title_mcp/vendors/registry.py +57 -0
- titlemcp-0.1.0/src/title_mcp/workflows/__init__.py +3 -0
- titlemcp-0.1.0/src/title_mcp/workflows/engine.py +230 -0
- titlemcp-0.1.0/templates/jurisdiction-package/README.md +22 -0
- titlemcp-0.1.0/templates/jurisdiction-package/pyproject.toml +35 -0
- titlemcp-0.1.0/templates/jurisdiction-package/src/titlemcp_us_oh_franklin_recorder/__init__.py +9 -0
- titlemcp-0.1.0/templates/jurisdiction-package/src/titlemcp_us_oh_franklin_recorder/adapters.py +44 -0
- titlemcp-0.1.0/templates/jurisdiction-package/src/titlemcp_us_oh_franklin_recorder/client.py +56 -0
- titlemcp-0.1.0/templates/jurisdiction-package/src/titlemcp_us_oh_franklin_recorder/manifest.py +33 -0
- titlemcp-0.1.0/templates/jurisdiction-package/src/titlemcp_us_oh_franklin_recorder/py.typed +1 -0
- titlemcp-0.1.0/templates/jurisdiction-package/src/titlemcp_us_oh_franklin_recorder/sources.py +55 -0
- titlemcp-0.1.0/templates/jurisdiction-package/titlemcp-capability.toml +27 -0
- titlemcp-0.1.0/tests/test_adapters.py +139 -0
- titlemcp-0.1.0/tests/test_exam_commitment.py +1201 -0
- titlemcp-0.1.0/tests/test_exam_extraction.py +760 -0
- titlemcp-0.1.0/tests/test_extension_contracts.py +182 -0
- titlemcp-0.1.0/tests/test_form_fingerprint.py +159 -0
- titlemcp-0.1.0/tests/test_hoa_serpapi.py +440 -0
- titlemcp-0.1.0/tests/test_mcp_discovery.py +251 -0
- titlemcp-0.1.0/tests/test_pacer.py +154 -0
- titlemcp-0.1.0/tests/test_packaging.py +51 -0
- titlemcp-0.1.0/tests/test_regrid.py +258 -0
- 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.
|
titlemcp-0.1.0/PKG-INFO
ADDED
|
@@ -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.
|