vin-decode-mcp 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.
@@ -0,0 +1,42 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ matrix:
14
+ python-version: ["3.11", "3.12"]
15
+
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+
19
+ - name: Set up Python ${{ matrix.python-version }}
20
+ uses: actions/setup-python@v5
21
+ with:
22
+ python-version: ${{ matrix.python-version }}
23
+
24
+ - name: Install uv
25
+ uses: astral-sh/setup-uv@v3
26
+ with:
27
+ version: "latest"
28
+
29
+ - name: Install dependencies
30
+ run: uv pip install --system ".[dev]"
31
+
32
+ - name: Build test database
33
+ run: python tests/fixtures/build_test_db.py
34
+
35
+ - name: Run tests
36
+ run: python -m pytest tests/ -v
37
+
38
+ - name: Lint with ruff
39
+ run: python -m ruff check src/ tests/
40
+
41
+ - name: Check formatting
42
+ run: python -m ruff format --check src/ tests/
@@ -0,0 +1,129 @@
1
+ name: Rebuild Database
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ inputs:
6
+ vintage:
7
+ description: "NHTSA vintage to rebuild from (e.g. 2026_08)"
8
+ required: false
9
+ default: ""
10
+ schedule:
11
+ # Twice yearly: January 1st and July 1st
12
+ - cron: "0 0 1 1,7 *"
13
+
14
+ env:
15
+ HUGGING_FACE_REPO: "joakes90/vpic-database"
16
+
17
+ jobs:
18
+ rebuild:
19
+ runs-on: ubuntu-latest
20
+
21
+ steps:
22
+ - uses: actions/checkout@v4
23
+
24
+ - name: Set up Python
25
+ uses: actions/setup-python@v5
26
+ with:
27
+ python-version: "3.12"
28
+
29
+ - name: Install uv
30
+ uses: astral-sh/setup-uv@v3
31
+
32
+ - name: Install dependencies
33
+ run: uv pip install --system ".[dev,build]" huggingface_hub
34
+
35
+ - name: Install pg_restore
36
+ # Only the client is needed. convert_to_sqlite.py renders the archive
37
+ # to plain SQL with `pg_restore --file`; no server, no database.
38
+ run: |
39
+ sudo apt-get update -qq
40
+ sudo apt-get install -y --no-install-recommends postgresql-client
41
+ pg_restore --version
42
+
43
+ - name: Determine vintage
44
+ id: vintage
45
+ run: |
46
+ if [ -n "${{ github.event.inputs.vintage }}" ]; then
47
+ echo "vintage=${{ github.event.inputs.vintage }}" >> "$GITHUB_OUTPUT"
48
+ else
49
+ echo "vintage=$(date +%Y_%m)" >> "$GITHUB_OUTPUT"
50
+ fi
51
+
52
+ - name: Download NHTSA database
53
+ run: |
54
+ mkdir -p tools/tmp_download
55
+ set -o pipefail
56
+ for v in "${{ steps.vintage.outputs.vintage }}" \
57
+ "$(date -d '1 month ago' +%Y_%m)" \
58
+ "$(date -d '2 months ago' +%Y_%m)"; do
59
+ [ -n "$v" ] || continue
60
+ URL="https://vpic.nhtsa.dot.gov/downloads/vPICList_lite_${v}.custom.zip"
61
+ echo "Trying: $URL"
62
+ if curl -fsSL -o tools/tmp_download/vpic.custom.zip "$URL"; then
63
+ echo "vintage=$v" >> "$GITHUB_ENV"
64
+ break
65
+ fi
66
+ done
67
+ test -s tools/tmp_download/vpic.custom.zip
68
+ ls -lh tools/tmp_download/
69
+
70
+ - name: Convert PostgreSQL archive to SQLite
71
+ # Fails the build if COPY decoding regresses and NULLs are stored as
72
+ # the literal string '\N' — the defect that shipped a database in
73
+ # which most VINs decoded to a model year and nothing else.
74
+ run: |
75
+ python3 tools/convert_to_sqlite.py \
76
+ --custom tools/tmp_download/vpic.custom.zip \
77
+ --output tools/out/vpic_lite.db
78
+
79
+ - name: Build curated database
80
+ run: |
81
+ python3 tools/vpic_pare_down.py \
82
+ --source tools/out/vpic_lite.db \
83
+ --output tools/out/curated_vpic.db \
84
+ --overlay tools/overlay.json \
85
+ --curation tools/curation.json
86
+
87
+ - name: Verify curated database
88
+ # The curated file is what the MCP server downloads, so it is what
89
+ # must be checked. Referential integrity across the ID spaces is the
90
+ # invariant the previous build broke.
91
+ run: |
92
+ cp tools/out/curated_vpic.db curated_vpic.db
93
+ python3 - <<'PY'
94
+ import sqlite3
95
+ c = sqlite3.connect("file:curated_vpic.db?mode=ro", uri=True)
96
+ q = lambda s: c.execute(s).fetchone()[0]
97
+ for table in ("make", "model", "make_model", "model_years",
98
+ "wmi", "wmi_vinschema", "vin_pattern"):
99
+ print(f" {table}: {q(f'SELECT COUNT(*) FROM {table}'):,}")
100
+ assert q("SELECT COUNT(*) FROM vin_pattern p LEFT JOIN model m "
101
+ "ON m.id = p.modelid WHERE m.id IS NULL") == 0, \
102
+ "vin_pattern.modelid does not resolve against model.id"
103
+ assert q("SELECT COUNT(*) FROM wmi") > 1000, "wmi table is too small"
104
+ assert 400 < q("SELECT COUNT(*) FROM make") < 800, "make curation looks wrong"
105
+ PY
106
+ python3 -m pytest tests/ -q
107
+
108
+ - name: Upload to Hugging Face
109
+ env:
110
+ HF_TOKEN: ${{ secrets.HUGGING_FACE_TOKEN }}
111
+ run: |
112
+ if [ -z "${HF_TOKEN}" ]; then
113
+ echo "::warning::HUGGING_FACE_TOKEN not set; skipping upload"
114
+ exit 0
115
+ fi
116
+ hf upload "${HUGGING_FACE_REPO}" \
117
+ tools/out/curated_vpic.db \
118
+ curated_vpic.db \
119
+ --repo-type dataset \
120
+ --commit-message "Rebuild from NHTSA vintage ${vintage}"
121
+ echo "Uploaded curated_vpic.db to ${HUGGING_FACE_REPO}"
122
+
123
+ - name: Upload build artifact
124
+ if: always()
125
+ uses: actions/upload-artifact@v4
126
+ with:
127
+ name: curated_vpic.db
128
+ path: tools/out/curated_vpic.db
129
+ if-no-files-found: warn
@@ -0,0 +1,45 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+
7
+ # Virtual environments
8
+ .venv/
9
+ venv/
10
+ ENV/
11
+
12
+ # IDE
13
+ .idea/
14
+ .vscode/
15
+ *.swp
16
+ *.swo
17
+
18
+ # Distribution / packaging
19
+ dist/
20
+ build/
21
+ *.egg-info/
22
+ *.egg
23
+
24
+ # Compiled DB (build artifacts)
25
+ *.db
26
+ *.db-shm
27
+ *.db-wal
28
+ !tests/fixtures/build_test_db.py
29
+
30
+ # Build pipeline scratch (tools/rebuild.sh, tools/vpic_pare_down.py)
31
+ tools/out/diff_report.txt
32
+ tools/tmp_download/
33
+
34
+ # Environment variables
35
+ .env
36
+
37
+ # Hugging Face CLI cache
38
+ .huggingface/
39
+
40
+ # macOS
41
+ .DS_Store
42
+
43
+ # Node (irrelevant)
44
+ node_modules/
45
+ package-lock.json
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 VIN Decode MCP Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,302 @@
1
+ Metadata-Version: 2.5
2
+ Name: vin-decode-mcp
3
+ Version: 0.1.0
4
+ Summary: MCP server for decoding VINs and querying vehicle data from a curated NHTSA vPIC SQLite database
5
+ Project-URL: Homepage, https://github.com/joakes90/vin-decode-mcp
6
+ Project-URL: Repository, https://github.com/joakes90/vin-decode-mcp
7
+ Project-URL: Bug Tracker, https://github.com/joakes90/vin-decode-mcp/issues
8
+ Project-URL: Documentation, https://github.com/joakes90/vin-decode-mcp#readme
9
+ Author: Justin Oakes
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: fastmcp,mcp,nhtsa,sqlite,vehicle,vin,vpic
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
19
+ Requires-Python: >=3.11
20
+ Requires-Dist: fastmcp>=3.0.0
21
+ Requires-Dist: httpx>=0.27.0
22
+ Requires-Dist: huggingface-hub>=1.0.0
23
+ Requires-Dist: pydantic>=2.0.0
24
+ Requires-Dist: structlog>=24.0.0
25
+ Provides-Extra: build
26
+ Requires-Dist: hatchling>=1.22.0; extra == 'build'
27
+ Provides-Extra: dev
28
+ Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
29
+ Requires-Dist: pytest>=8.0.0; extra == 'dev'
30
+ Requires-Dist: ruff>=0.4.0; extra == 'dev'
31
+ Description-Content-Type: text/markdown
32
+
33
+ # vin-decode-mcp
34
+
35
+ **Decode VINs and query vehicle data from a curated NHTSA vPIC database — powered by the Model Context Protocol.**
36
+
37
+ A standalone, offline-capable MCP server for LLMs to decode Vehicle Identification Numbers (VINs) and look up makes, models, and vehicle specifications using data from [NHTSA's vPIC](https://vpic.nhtsa.dot.gov/).
38
+
39
+ ```
40
+ pip install vin-decode-mcp
41
+ vin-decode-mcp # Start the MCP server
42
+ ```
43
+
44
+ ## Why?
45
+
46
+ - **Offline**: Works without internet access. The curated SQLite database (~4.5 MB) is self-contained.
47
+ - **No rate limits**: Unlike calling the vPIC API directly, local queries are unlimited.
48
+ - **Fast**: Pattern matching against the SQLite database takes microseconds.
49
+ - **LLM-native**: Tools with rich docstrings, schema resources, and structured JSON output.
50
+ - **Open data**: NHTSA vPIC is US government open data — free, no API key required.
51
+
52
+ ## Data Coverage
53
+
54
+ - US-market vehicles, model year **1981 and forward**
55
+ - **536 makes**, **9,284 models**, **88,267 VIN patterns** (2026-08 vintage)
56
+ - Passenger Cars, Trucks, MPVs, Motorcycles, Off-Road Vehicles
57
+ - Excludes: Buses, Trailers, Low-Speed Vehicles, Incomplete Vehicles
58
+
59
+ > **Specifications only** — this database does not include title, accident, odometer,
60
+ > or theft history (those require NMVTIS/commercial data sources).
61
+
62
+ ## Quick Start
63
+
64
+ ### Installation
65
+
66
+ ```bash
67
+ pip install vin-decode-mcp
68
+ ```
69
+
70
+ Or from source:
71
+
72
+ ```bash
73
+ git clone https://github.com/<org>/vin-decode-mcp.git
74
+ cd vin-decode-mcp
75
+ pip install -e .
76
+ ```
77
+
78
+ ### Running
79
+
80
+ ```bash
81
+ # Default: stdio transport (for Claude Desktop, Cursor, etc.)
82
+ vin-decode-mcp
83
+
84
+ # HTTP transport
85
+ vin-decode-mcp --transport http --port 8765
86
+ ```
87
+
88
+ ### Using with Claude Desktop
89
+
90
+ Create a dedicated venv so the binary lands where you can reference it:
91
+
92
+ ```bash
93
+ python3 -m venv ~/.local/venvs/vin-decode
94
+ source ~/.local/venvs/vin-decode/bin/activate
95
+ pip install vin-decode-mcp
96
+ deactivate
97
+ ```
98
+
99
+ Add to `~/.config/claude-desktop/config.json` (or `~/Library/Application Support/claude-desktop/config.json` on macOS):
100
+
101
+ ```json
102
+ {
103
+ "mcpServers": {
104
+ "vin-decode": {
105
+ "command": "~/.local/venvs/vin-decode/bin/vin-decode-mcp"
106
+ }
107
+ }
108
+ }
109
+ ```
110
+
111
+ Replace the path with wherever you put the venv. Restart Claude Desktop. The model can now use VIN decoding tools in conversations.
112
+
113
+ > **Note:** Claude Desktop spawns processes with a minimal `$PATH` that doesn't include conda environments or virtualenvs, so always use the **absolute path** to the binary — just putting `"vin-decode-mcp"` won't work.
114
+
115
+ ## Available Tools
116
+
117
+ | Tool | Description |
118
+ |------|-------------|
119
+ | `decode_vin(vin, model_year?)` | Decode a VIN → make, model, year, vehicle type |
120
+ | `decode_partial_vin(pattern, limit?)` | Match a partial VIN with `*` wildcards |
121
+ | `get_all_makes()` | List all vehicle makes |
122
+ | `get_models_for_make(make, vehicle_type?)` | List models for a make |
123
+ | `get_model_years(make, model)` | Get production year range |
124
+ | `get_wmi_info(wmi)` | Decode a WMI → manufacturer info |
125
+ | `get_vehicle_types()` | List available vehicle types |
126
+ | `get_make_vehicle_types(make)` | List vehicle types for a make |
127
+
128
+ ### Examples
129
+
130
+ ```
131
+ >>> decode_vin("1HGCM82633A004352")
132
+ {
133
+ "vin": "1HGCM82633A004352",
134
+ "make": "Honda",
135
+ "model": "Accord",
136
+ "year": 2003,
137
+ "vehicle_type": "Passenger Car",
138
+ "wmi": "1HG",
139
+ "confidence": "full"
140
+ }
141
+
142
+ >>> get_model_years("Porsche", "911")
143
+ {"year_from": 1981, "year_to": null}
144
+
145
+ >>> decode_partial_vin("5UXWX7C5*BA")
146
+ [{"make": "BMW", "model": "X3", "year": 2011,
147
+ "vehicle_type": "Passenger Car", "confidence": "partial_match"}]
148
+ ```
149
+
150
+ ## Database
151
+
152
+ ### Download
153
+
154
+ The compiled database is hosted on Hugging Face:
155
+
156
+ **Dataset**: https://huggingface.co/datasets/joakes90/vpic-database
157
+ **Direct download**: https://huggingface.co/datasets/joakes90/vpic-database/resolve/main/curated_vpic.db
158
+
159
+ ### Custom Database Path
160
+
161
+ ```bash
162
+ # Set via environment variable
163
+ export VIN_MCP_DB_PATH=/path/to/curated_vpic.db
164
+ vin-decode-mcp
165
+
166
+ # Or via CLI flag
167
+ vin-decode-mcp --db-path /path/to/curated_vpic.db
168
+ ```
169
+
170
+ ### Rebuilding
171
+
172
+ The database is rebuilt from NHTSA's standalone PostgreSQL databases approximately every 6-12 months:
173
+
174
+ ```bash
175
+ # Requires PostgreSQL installed (pg_restore, psql)
176
+ bash tools/rebuild.sh
177
+
178
+ # Or step by step:
179
+ # 1. Download NHTSA data: https://vpic.nhtsa.dot.gov/Downloads/
180
+ # 2. Convert to SQLite
181
+ python3 tools/convert_to_sqlite.py --input dump.sql --output tools/out/vpic_lite.db
182
+ # 3. Build curated database
183
+ python3 tools/build_db.py --source tools/out/vpic_lite.db --output tools/out/curated_vpic.db
184
+ ```
185
+
186
+ See [`docs/hf-setup.md`](docs/hf-setup.md) for Hugging Face setup instructions.
187
+
188
+ ## Data Source & Attribution
189
+
190
+ Vehicle data sourced from [NHTSA's vPIC](https://vpic.nhtsa.dot.gov/) — the National
191
+ Highway Traffic Safety Administration's Vehicle Product Information Catalog and
192
+ Vehicle Listing. NHTSA is a United States government agency.
193
+
194
+ - **Data license**: US Government work (public domain)
195
+ - **API**: No key or registration required
196
+ - **Refresh frequency**: ~6-12 months
197
+ - **Report errors**: Contact the NHTSA Manufacturer Helpdesk at manufacturerinfo@dot.gov or 1-888-399-3277
198
+
199
+ ## Architecture
200
+
201
+ ```
202
+ User / LLM Agent
203
+
204
+ ▼ MCP (stdio / HTTP)
205
+ ┌──────────────────┐
206
+ │ vin-decode-mcp │ pip install vin-decode-mcp
207
+ │ (FastMCP server)│ env: VIN_MCP_DB_PATH=/path/to/curated_vpic.db
208
+ └────────┬─────────┘
209
+ │ sqlite3 (mode=ro)
210
+
211
+ ┌──────────────────────┐
212
+ │ curated_vpic.db │ ~4.5 MB, curated
213
+ │ (Hugging Face) │ makes + models + WMI + VIN patterns
214
+ └──────────────────────┘
215
+
216
+ │ rebuilds from
217
+ ┌──────────────────┐
218
+ │ NHTSA vPIC PG DB │ 69 MB, official
219
+ │ (NHTSA website) │ refreshed 2x/year
220
+ └──────────────────┘
221
+ ```
222
+
223
+ ## Project Structure
224
+
225
+ ```
226
+ vin-decode-mcp/
227
+ ├── src/vin_decode_mcp/
228
+ │ ├── __init__.py # Package init
229
+ │ ├── server.py # FastMCP server with all tools
230
+ │ ├── database.py # SQLite layer + VIN decoder
231
+ │ └── cli.py # CLI entry point
232
+ ├── tools/
233
+ │ ├── build_db.py # Pipeline orchestrator
234
+ │ ├── convert_to_sqlite.py # PG → SQLite converter (COPY text format)
235
+ │ ├── vpic_pare_down.py # Curated pare-down + VIN decode tables
236
+ │ ├── rebuild.sh # Full rebuild script
237
+ │ ├── curation.json # Make/model curation rules
238
+ │ ├── overlay.json # Grey-import classic additions
239
+ │ └── README.md # Rebuild instructions
240
+ ├── tests/
241
+ │ ├── conftest.py # Test fixtures
242
+ │ ├── test_decode.py # VIN decode canary + regression tests
243
+ │ ├── test_server.py # Bulk lookup tests
244
+ │ ├── test_convert.py # PostgreSQL COPY decoding tests
245
+ │ ├── test_real_db.py # Smoke tests against the curated DB
246
+ │ └── fixtures/
247
+ │ ├── build_test_db.py # Test database builder
248
+ │ └── test_vpic.db # Minimal test database
249
+ ├── .github/workflows/
250
+ │ ├── ci.yml # CI: test + lint
251
+ │ └── rebuild-db.yml # Scheduled DB rebuild
252
+ ├── docs/
253
+ │ └── hf-setup.md # Hugging Face setup guide
254
+ ├── pyproject.toml
255
+ ├── LICENSE
256
+ └── README.md
257
+ ```
258
+
259
+ ## Development
260
+
261
+ ```bash
262
+ # Install dev dependencies
263
+ pip install -e ".[dev]"
264
+
265
+ # Run tests
266
+ python -m pytest tests/ -v
267
+
268
+ # Lint
269
+ python -m ruff check src/ tests/
270
+
271
+ # Format
272
+ python -m ruff format src/ tests/
273
+ ```
274
+
275
+ ## Comparison with Other Solutions
276
+
277
+ | | **vin-decode-mcp** | **NHTSA vPIC API** | **vin-mcp (NLMA)** |
278
+ |---|---|---|---|
279
+ | **Transport** | Local SQLite | HTTP REST | HTTP REST |
280
+ | **Offline** | ✅ | ❌ | ❌ |
281
+ | **Rate limited** | No | Yes | Yes |
282
+ | **Data size** | ~4.5 MB | N/A | N/A |
283
+ | **VIN fields** | Make + Model + Year | ~130 fields | ~130 fields |
284
+ | **Makes/Models** | ✅ 536/9,284 | ✅ Full catalog | ✅ Full catalog |
285
+ | **Install** | `pip install` | None | `pip install` |
286
+
287
+ ## License
288
+
289
+ **MIT License** — Code is MIT. Data is US Government public domain.
290
+
291
+ See [`LICENSE`](LICENSE) for details.
292
+
293
+ ## Contributing
294
+
295
+ Contributions welcome! Please:
296
+
297
+ 1. Fork and create a feature branch
298
+ 2. Add tests for new functionality
299
+ 3. Ensure CI passes
300
+ 4. Submit a pull request
301
+
302
+ For major changes, open an issue first to discuss the approach.