@pipeworx/mcp-nhtsa 0.1.0 → 0.2.0

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.
package/README.md CHANGED
@@ -1,31 +1,57 @@
1
- # @pipeworx/mcp-nhtsa
1
+ # mcp-nhtsa
2
2
 
3
- MCP server for vehicle data via the [NHTSA vPIC API](https://vpic.nhtsa.dot.gov/api/). Free, no authentication required.
3
+ NHTSA MCP — wraps the NHTSA vPIC (Vehicle Product Information Catalog) API (free, no auth)
4
+
5
+ Part of [Pipeworx](https://pipeworx.io) — an MCP gateway connecting AI agents to 884+ live data sources.
4
6
 
5
7
  ## Tools
6
8
 
7
9
  | Tool | Description |
8
10
  |------|-------------|
9
- | `decode_vin` | Decode a 17-character VIN to get make, model, year, body style, engine, and more |
10
- | `get_makes` | Retrieve all vehicle makes (brands) registered with NHTSA |
11
- | `get_models` | Get all vehicle models for a specific make and model year |
12
-
13
- ## Quickstart via Pipeworx Gateway
14
-
15
- ```bash
16
- curl -X POST https://gateway.pipeworx.io/mcp \
17
- -H "Content-Type: application/json" \
18
- -d '{
19
- "jsonrpc": "2.0",
20
- "method": "tools/call",
21
- "params": {
22
- "name": "nhtsa__decode_vin",
23
- "arguments": { "vin": "1HGBH41JXMN109186" }
24
- },
25
- "id": 1
26
- }'
11
+ | `get_makes` | Get all vehicle brands for a model year. Returns make names and IDs. E.g., year \'2023\'. |
12
+ | `get_models` | Get all vehicle models for a make and year. Returns model names and IDs. E.g., make \'Toyota\', year \'2023\'. |
13
+
14
+ ## Quick Start
15
+
16
+ Add to your MCP client (Claude Desktop, Cursor, Windsurf, etc.):
17
+
18
+ ```json
19
+ {
20
+ "mcpServers": {
21
+ "nhtsa": {
22
+ "url": "https://gateway.pipeworx.io/nhtsa/mcp"
23
+ }
24
+ }
25
+ }
27
26
  ```
28
27
 
28
+ Or connect to the full Pipeworx gateway for access to all 884+ data sources:
29
+
30
+ ```json
31
+ {
32
+ "mcpServers": {
33
+ "pipeworx": {
34
+ "url": "https://gateway.pipeworx.io/mcp"
35
+ }
36
+ }
37
+ }
38
+ ```
39
+
40
+ ## Using with ask_pipeworx
41
+
42
+ Instead of calling tools directly, you can ask questions in plain English:
43
+
44
+ ```
45
+ ask_pipeworx({ question: "your question about Nhtsa data" })
46
+ ```
47
+
48
+ The gateway picks the right tool and fills the arguments automatically.
49
+
50
+ ## More
51
+
52
+ - [All tools and guides](https://github.com/pipeworx-io/examples)
53
+ - [pipeworx.io](https://pipeworx.io)
54
+
29
55
  ## License
30
56
 
31
57
  MIT
package/package.json CHANGED
@@ -1,18 +1,20 @@
1
1
  {
2
2
  "name": "@pipeworx/mcp-nhtsa",
3
- "version": "0.1.0",
4
- "description": "MCP server for vehicle data (VIN decoding, makes, models) via NHTSA vPIC API",
3
+ "version": "0.2.0",
4
+ "description": "NHTSA MCP — wraps the NHTSA vPIC (Vehicle Product Information Catalog) API (free, no auth)",
5
+ "type": "module",
5
6
  "main": "src/index.ts",
6
7
  "types": "src/index.ts",
7
- "files": ["src"],
8
+ "keywords": ["mcp", "mcp-server", "model-context-protocol", "pipeworx", "nhtsa"],
9
+ "license": "MIT",
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "https://github.com/pipeworx-io/mcp-nhtsa"
13
+ },
8
14
  "scripts": {
9
- "build": "tsc",
10
- "check": "tsc --noEmit"
15
+ "typecheck": "tsc --noEmit"
11
16
  },
12
- "keywords": ["mcp", "mcp-server", "model-context-protocol", "pipeworx", "nhtsa", "vehicles", "vin", "automotive"],
13
- "author": "Pipeworx",
14
- "license": "MIT",
15
17
  "devDependencies": {
16
- "typescript": "^5.0.0"
18
+ "typescript": "^5.7.0"
17
19
  }
18
20
  }
package/server.json ADDED
@@ -0,0 +1,18 @@
1
+ {
2
+ "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
3
+ "name": "io.github.pipeworx-io/nhtsa",
4
+ "title": "Nhtsa",
5
+ "description": "NHTSA MCP — wraps the NHTSA vPIC (Vehicle Product Information Catalog) API (free, no auth)",
6
+ "version": "0.2.0",
7
+ "websiteUrl": "https://pipeworx.io/packs/nhtsa",
8
+ "repository": {
9
+ "url": "https://github.com/pipeworx-io/mcp-nhtsa",
10
+ "source": "github"
11
+ },
12
+ "remotes": [
13
+ {
14
+ "type": "streamable-http",
15
+ "url": "https://gateway.pipeworx.io/nhtsa/mcp"
16
+ }
17
+ ]
18
+ }
package/src/index.ts CHANGED
@@ -1,12 +1,3 @@
1
- /**
2
- * NHTSA MCP — wraps the NHTSA vPIC (Vehicle Product Information Catalog) API (free, no auth)
3
- *
4
- * Tools:
5
- * - decode_vin: decode a Vehicle Identification Number into make, model, year, and attributes
6
- * - get_makes: retrieve all vehicle makes registered with NHTSA
7
- * - get_models: retrieve all models for a given make and model year
8
- */
9
-
10
1
  interface McpToolDefinition {
11
2
  name: string;
12
3
  description: string;
@@ -20,15 +11,29 @@ interface McpToolDefinition {
20
11
  interface McpToolExport {
21
12
  tools: McpToolDefinition[];
22
13
  callTool: (name: string, args: Record<string, unknown>) => Promise<unknown>;
14
+ meter?: { credits: number };
15
+ cost?: Record<string, unknown>;
16
+ provider?: string;
23
17
  }
24
18
 
19
+ /**
20
+ * NHTSA MCP — wraps the NHTSA vPIC (Vehicle Product Information Catalog) API (free, no auth)
21
+ *
22
+ * Tools:
23
+ * - decode_vin: decode a Vehicle Identification Number into make, model, year, and attributes
24
+ * - get_makes: retrieve all vehicle makes registered with NHTSA
25
+ * - get_models: retrieve all models for a given make and model year
26
+ */
27
+
28
+
25
29
  const BASE_URL = 'https://vpic.nhtsa.dot.gov/api';
30
+ const SAFETY_BASE = 'https://api.nhtsa.gov';
26
31
 
27
32
  const tools: McpToolExport['tools'] = [
28
33
  {
29
34
  name: 'decode_vin',
30
35
  description:
31
- 'Decode a 17-character Vehicle Identification Number (VIN) to get make, model, year, body style, engine, and other attributes.',
36
+ 'Decode a VIN to get vehicle details. Returns make, model, year, body style, engine type, drivetrain, and plant. E.g., \'1HGBH41JXMN109186\'. (For recalls/ratings use get_recalls / get_safety_ratings.)',
32
37
  inputSchema: {
33
38
  type: 'object' as const,
34
39
  properties: {
@@ -42,7 +47,7 @@ const tools: McpToolExport['tools'] = [
42
47
  },
43
48
  {
44
49
  name: 'get_makes',
45
- description: 'Retrieve all vehicle makes (brands) registered with NHTSA.',
50
+ description: 'Get all vehicle brands for a model year. Returns make names and IDs. E.g., year \'2023\'.',
46
51
  inputSchema: {
47
52
  type: 'object' as const,
48
53
  properties: {},
@@ -50,7 +55,7 @@ const tools: McpToolExport['tools'] = [
50
55
  },
51
56
  {
52
57
  name: 'get_models',
53
- description: 'Get all vehicle models available for a specific make and model year.',
58
+ description: 'Get all vehicle models for a make and year. Returns model names and IDs. E.g., make \'Toyota\', year \'2023\'.',
54
59
  inputSchema: {
55
60
  type: 'object' as const,
56
61
  properties: {
@@ -60,6 +65,48 @@ const tools: McpToolExport['tools'] = [
60
65
  required: ['make', 'year'],
61
66
  },
62
67
  },
68
+ {
69
+ name: 'get_recalls',
70
+ description:
71
+ 'Get official NHTSA safety RECALLS for a vehicle. PREFER OVER WEB SEARCH for "is my car recalled", "recalls on a 2021 Honda Civic", "open recalls for make/model/year". Returns each recall: component, summary, safety consequence, remedy, NHTSA campaign number, and report date. Pass make + model + model_year.',
72
+ inputSchema: {
73
+ type: 'object' as const,
74
+ properties: {
75
+ make: { type: 'string', description: 'Vehicle make (e.g., "Honda")' },
76
+ model: { type: 'string', description: 'Vehicle model (e.g., "Civic")' },
77
+ model_year: { type: 'number', description: 'Model year (e.g., 2021)' },
78
+ },
79
+ required: ['make', 'model', 'model_year'],
80
+ },
81
+ },
82
+ {
83
+ name: 'get_complaints',
84
+ description:
85
+ 'Get owner-filed NHTSA complaints for a vehicle — real-world problems drivers reported (vs official recalls). Use for "common problems with a 2020 Ford Explorer", "what are owners complaining about". Returns components, summary, crash/fire flags, injuries/deaths, and filing date. Pass make + model + model_year.',
86
+ inputSchema: {
87
+ type: 'object' as const,
88
+ properties: {
89
+ make: { type: 'string', description: 'Vehicle make (e.g., "Ford")' },
90
+ model: { type: 'string', description: 'Vehicle model (e.g., "Explorer")' },
91
+ model_year: { type: 'number', description: 'Model year (e.g., 2020)' },
92
+ },
93
+ required: ['make', 'model', 'model_year'],
94
+ },
95
+ },
96
+ {
97
+ name: 'get_safety_ratings',
98
+ description:
99
+ 'Get NHTSA 5-Star Safety Ratings (NCAP crash-test results) for a vehicle — overall, frontal, side, and rollover star ratings. Use for "crash test rating for a 2021 Honda Civic", "how safe is X". Pass make + model + model_year.',
100
+ inputSchema: {
101
+ type: 'object' as const,
102
+ properties: {
103
+ make: { type: 'string', description: 'Vehicle make (e.g., "Honda")' },
104
+ model: { type: 'string', description: 'Vehicle model (e.g., "Civic")' },
105
+ model_year: { type: 'number', description: 'Model year (e.g., 2021)' },
106
+ },
107
+ required: ['make', 'model', 'model_year'],
108
+ },
109
+ },
63
110
  ];
64
111
 
65
112
  async function callTool(name: string, args: Record<string, unknown>): Promise<unknown> {
@@ -70,11 +117,95 @@ async function callTool(name: string, args: Record<string, unknown>): Promise<un
70
117
  return getMakes();
71
118
  case 'get_models':
72
119
  return getModels(args.make as string, args.year as number);
120
+ case 'get_recalls':
121
+ return getRecalls(args.make as string, args.model as string, args.model_year as number);
122
+ case 'get_complaints':
123
+ return getComplaints(args.make as string, args.model as string, args.model_year as number);
124
+ case 'get_safety_ratings':
125
+ return getSafetyRatings(args.make as string, args.model as string, args.model_year as number);
73
126
  default:
74
127
  throw new Error(`Unknown tool: ${name}`);
75
128
  }
76
129
  }
77
130
 
131
+ function reqVehicle(make: string, model: string, year: number) {
132
+ if (!make || !model || !year) {
133
+ throw new Error('make, model, and model_year are all required (e.g., make:"Honda", model:"Civic", model_year:2021).');
134
+ }
135
+ }
136
+
137
+ async function getRecalls(make: string, model: string, modelYear: number) {
138
+ reqVehicle(make, model, modelYear);
139
+ const url = `${SAFETY_BASE}/recalls/recallsByVehicle?make=${encodeURIComponent(make)}&model=${encodeURIComponent(model)}&modelYear=${modelYear}`;
140
+ const res = await fetch(url, { headers: { Accept: 'application/json' } });
141
+ if (!res.ok) throw new Error(`NHTSA recalls error: ${res.status}`);
142
+ const data = (await res.json()) as { Count?: number; results?: Array<Record<string, unknown>> };
143
+ return {
144
+ make, model, model_year: modelYear,
145
+ count: data.Count ?? (data.results?.length ?? 0),
146
+ recalls: (data.results ?? []).map((r) => ({
147
+ campaign_number: r.NHTSACampaignNumber ?? null,
148
+ component: r.Component ?? null,
149
+ summary: r.Summary ?? null,
150
+ consequence: r.Consequence ?? null,
151
+ remedy: r.Remedy ?? null,
152
+ report_received_date: r.ReportReceivedDate ?? null,
153
+ manufacturer: r.Manufacturer ?? null,
154
+ })),
155
+ };
156
+ }
157
+
158
+ async function getComplaints(make: string, model: string, modelYear: number) {
159
+ reqVehicle(make, model, modelYear);
160
+ const url = `${SAFETY_BASE}/complaints/complaintsByVehicle?make=${encodeURIComponent(make)}&model=${encodeURIComponent(model)}&modelYear=${modelYear}`;
161
+ const res = await fetch(url, { headers: { Accept: 'application/json' } });
162
+ if (!res.ok) throw new Error(`NHTSA complaints error: ${res.status}`);
163
+ const data = (await res.json()) as { count?: number; results?: Array<Record<string, unknown>> };
164
+ const results = data.results ?? [];
165
+ return {
166
+ make, model, model_year: modelYear,
167
+ count: data.count ?? results.length,
168
+ complaints: results.slice(0, 25).map((c) => ({
169
+ odi_number: c.odiNumber ?? null,
170
+ components: c.components ?? null,
171
+ summary: c.summary ?? null,
172
+ date_filed: c.dateComplaintFiled ?? null,
173
+ crash: c.crash ?? null,
174
+ fire: c.fire ?? null,
175
+ injuries: c.numberOfInjuries ?? null,
176
+ deaths: c.numberOfDeaths ?? null,
177
+ })),
178
+ };
179
+ }
180
+
181
+ async function getSafetyRatings(make: string, model: string, modelYear: number) {
182
+ reqVehicle(make, model, modelYear);
183
+ const lookupUrl = `${SAFETY_BASE}/SafetyRatings/modelyear/${modelYear}/make/${encodeURIComponent(make)}/model/${encodeURIComponent(model)}`;
184
+ const lookupRes = await fetch(lookupUrl, { headers: { Accept: 'application/json' } });
185
+ if (!lookupRes.ok) throw new Error(`NHTSA safety ratings error: ${lookupRes.status}`);
186
+ const lookup = (await lookupRes.json()) as { Count?: number; Results?: Array<{ VehicleId?: number; VehicleDescription?: string }> };
187
+ const variants = (lookup.Results ?? []).filter((v) => v.VehicleId);
188
+ if (variants.length === 0) {
189
+ return { make, model, model_year: modelYear, count: 0, note: 'No NCAP crash-test ratings published for this make/model/year (not all vehicles are tested).', ratings: [] };
190
+ }
191
+
192
+ // Each VehicleId is a tested variant (body style/drivetrain). Resolve up to 5.
193
+ const ratings = await Promise.all(
194
+ variants.slice(0, 5).map(async (v) => {
195
+ const r = await fetch(`${SAFETY_BASE}/SafetyRatings/VehicleId/${v.VehicleId}`, { headers: { Accept: 'application/json' } });
196
+ const rd = ((await r.json()) as { Results?: Array<Record<string, unknown>> }).Results?.[0] ?? {};
197
+ return {
198
+ variant: v.VehicleDescription ?? null,
199
+ overall: rd.OverallRating ?? null,
200
+ frontal_crash: rd.OverallFrontCrashRating ?? null,
201
+ side_crash: rd.OverallSideCrashRating ?? null,
202
+ rollover: rd.RolloverRating ?? null,
203
+ };
204
+ }),
205
+ );
206
+ return { make, model, model_year: modelYear, count: ratings.length, ratings };
207
+ }
208
+
78
209
  interface NhtsaResult {
79
210
  Variable?: string;
80
211
  Value?: string | null;
@@ -161,4 +292,4 @@ async function getModels(make: string, year: number) {
161
292
  };
162
293
  }
163
294
 
164
- export default { tools, callTool } satisfies McpToolExport;
295
+ export default { tools, callTool, meter: { credits: 5 } } satisfies McpToolExport;
package/tsconfig.json ADDED
@@ -0,0 +1,14 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "strict": true,
7
+ "esModuleInterop": true,
8
+ "skipLibCheck": true,
9
+ "outDir": "dist",
10
+ "rootDir": "src",
11
+ "declaration": true
12
+ },
13
+ "include": ["src"]
14
+ }