# Vehicle Data Consistency Analysis & Solutions
## Executive Summary
The StockSpark MCP server has inconsistent data formats between different vehicle-related tools, causing confusion for both LLMs and developers. This document analyzes the issue and proposes three solution approaches with clear trade-offs.
## π The Problem
### Current State
The MCP server exposes **two incompatible data models**:
1. **Template/User Model** (returned by `get_vehicle_version_template`):
```javascript
{
engine: { size: 1598, power: 143, powerHp: 194 }, // Nested
seats: 7, // Plural
body: "SUV" // String
}
```
2. **API Storage Model** (expected by vehicle APIs):
```javascript
{
cubicCapacity: 1598, // Flat
power: 143, // Flat
powerHp: 194, // Flat
seat: 7, // Singular
body: { name: "SUV", description: "SUV" } // Object
}
```
### Impact Analysis
| Tool | Current Behavior | Issues |
|------|-----------------|--------|
| `get_vehicle` | Returns API format | β
Consistent |
| `list_vehicles` | Returns API format | β
Consistent |
| `get_vehicle_version_template` | Returns user format | β Inconsistent with other outputs |
| `add_vehicle` | Accepts both formats, converts internally | β οΈ Hidden complexity |
| `update_vehicle` | Has conversion logic for nestedβflat | β οΈ Scattered logic |
### Root Causes
1. **API Mismatch**: Template compilation API returns different format than storage API
2. **Legacy Support**: Maintaining backward compatibility with multiple formats
3. **Scattered Logic**: Conversion code duplicated across multiple tools
## π― Proposed Solutions
### Solution 1: Documentation-Only Fix (Quick)
**Approach**: Update tool schemas to explicitly document expected formats
**Implementation**:
```javascript
// Update inputSchema for update_vehicle tool
{
description: "Update vehicle. IMPORTANT: Use flat field structure",
properties: {
updates: {
properties: {
// Make it clear these are flat fields
cubicCapacity: { description: "Engine size in cc (NOT engine.size)" },
power: { description: "Power in kW (NOT engine.power)" },
powerHp: { description: "Power in HP (NOT engine.powerHp)" },
seat: { description: "Number of seats (NOT seats - singular!)" },
body: {
type: "object",
description: "Body type object with name and description",
properties: {
name: { enum: ["SUV", "SEDAN", "ESTATE_CAR", ...] }
}
}
}
}
}
}
```
**Pros**:
- β
Immediate fix
- β
No code changes
- β
Low risk
**Cons**:
- β LLMs must remember different formats
- β Inconsistent user experience
- β Doesn't fix underlying problem
**Effort**: 1 hour
### Solution 2: Centralized Transformation Layer (Recommended)
**Approach**: Create single transformation utility used by all tools
**Implementation**:
```javascript
// New file: src/utils/vehicle-transformer.js
class VehicleTransformer {
/**
* Convert user-friendly format to API format
* Handles both nested and flat inputs gracefully
*/
static toApiFormat(data) {
const result = { ...data };
// Handle engine transformation
if (data.engine) {
result.cubicCapacity = data.engine.size;
result.power = data.engine.power;
result.powerHp = data.engine.powerHp;
delete result.engine;
}
// Handle seat/seats
if (data.seats !== undefined) {
result.seat = data.seats;
delete result.seats;
}
// Handle body string β object
if (typeof data.body === 'string') {
result.body = this.getBodyObject(data.body);
}
return result;
}
/**
* Convert API format to user-friendly format
* Used for all outputs to ensure consistency
*/
static toUserFormat(data) {
return {
...data,
engine: {
size: data.cubicCapacity,
power: data.power,
powerHp: data.powerHp
},
seats: data.seat,
body: data.body?.name || data.body,
// Remove API-specific fields
cubicCapacity: undefined,
seat: undefined
};
}
static getBodyObject(bodyString) {
const bodyMap = {
'SUV': { name: 'SUV', description: 'SUV' },
'SEDAN': { name: 'SEDAN', description: 'Berlina' },
'ESTATE': { name: 'ESTATE_CAR', description: 'Station Wagon' },
// ... etc
};
return bodyMap[bodyString.toUpperCase()] ||
{ name: bodyString.toUpperCase(), description: bodyString };
}
}
```
**Integration Points**:
```javascript
// In vehicle-tools.js
update_vehicle: async (args, { vehicleAPI }) => {
// Transform once at entry point
const apiFormat = VehicleTransformer.toApiFormat(args.updates);
await vehicleAPI.updateVehicle(args.vehicleId, apiFormat);
}
// In get_vehicle handler
get_vehicle: async (args, { vehicleAPI }) => {
const vehicle = await vehicleAPI.getVehicle(args.vehicleId);
// Transform once at exit point
return VehicleTransformer.toUserFormat(vehicle);
}
```
**Pros**:
- β
Single source of truth
- β
Consistent transformation
- β
Easy to maintain
- β
Backwards compatible
**Cons**:
- β οΈ Requires updating all vehicle tools
- β οΈ Small performance overhead
**Effort**: 4-6 hours
### Solution 3: Unified Data Model (Best Long-term)
**Approach**: Standardize on ONE format everywhere
#### Option 3A: User-Friendly Format Everywhere
```javascript
// All tools use this format
{
engine: { size, power, powerHp }, // Always nested
seats: 7, // Always plural
body: "SUV" // Always string
}
```
**Implementation**:
1. Update all tool outputs to use user format
2. Update all tool inputs to expect user format
3. Transform only at API client boundary
4. Update all documentation
#### Option 3B: API Format Everywhere
```javascript
// All tools use this format
{
cubicCapacity: 1598,
power: 143,
powerHp: 194,
seat: 7,
body: { name: "SUV", description: "SUV" }
}
```
**Implementation**:
1. Update template tool to return API format
2. Remove all transformation logic
3. Update documentation to use API field names
**Comparison**:
| Aspect | User Format | API Format |
|--------|-------------|------------|
| **Intuitiveness** | β
High (engine.size) | β Low (cubicCapacity) |
| **Code Simplicity** | β οΈ Medium | β
High |
| **Performance** | β οΈ Transformation overhead | β
No overhead |
| **User Experience** | β
Better | β Technical |
**Recommendation**: Use **User Format** with transformation at API boundary
**Pros**:
- β
Best user experience
- β
Consistent everywhere
- β
Future-proof
**Cons**:
- β Most work required
- β Breaking change for existing users
**Effort**: 8-12 hours
## π Implementation Plan
### Phase 1: Immediate (Solution 1)
- [ ] Update tool documentation with explicit field formats
- [ ] Add examples showing correct field names
- [ ] Timeline: 1 hour
### Phase 2: Short-term (Solution 2)
- [ ] Create VehicleTransformer utility class
- [ ] Update critical tools (add_vehicle, update_vehicle)
- [ ] Test transformation logic
- [ ] Timeline: 1 week
### Phase 3: Long-term (Solution 3)
- [ ] Choose unified format (recommend user-friendly)
- [ ] Update all vehicle tools
- [ ] Update all documentation
- [ ] Add migration guide for existing users
- [ ] Timeline: 2-3 weeks
## π Migration Strategy
### For Existing Users
1. **Phase 1**: No changes needed
2. **Phase 2**: Both formats supported (backwards compatible)
3. **Phase 3**: Deprecation notice β Grace period β Migration
### For New Users
- Start with documented format from Phase 1
- Automatically benefit from Phase 2/3 improvements
## π Decision Matrix
| Criteria | Solution 1 | Solution 2 | Solution 3 |
|----------|------------|------------|------------|
| **Implementation Effort** | π’ Low | π‘ Medium | π΄ High |
| **User Experience** | π΄ Poor | π‘ Good | π’ Excellent |
| **Maintainability** | π΄ Poor | π’ Good | π’ Excellent |
| **Risk** | π’ Low | π‘ Medium | π΄ High |
| **Long-term Value** | π΄ Low | π‘ Good | π’ Excellent |
## π― Recommendation
**Immediate**: Implement Solution 1 (documentation fix) TODAY
**Next Sprint**: Implement Solution 2 (transformation layer)
**Future Roadmap**: Plan Solution 3 (unified model) for major version
## π Examples of Current Issues
### Issue 1: Template Output vs Update Input
```javascript
// What get_vehicle_version_template returns:
{
engine: { size: 1598, power: 143, powerHp: 194 }
}
// What update_vehicle expects (after today's fix):
{
cubicCapacity: 1598,
power: 143,
powerHp: 194
}
// LLM confusion: Why different formats?
```
### Issue 2: Inconsistent Field Names
```javascript
// Some tools return:
{ seats: 7 } // Plural, intuitive
// Others expect:
{ seat: 7 } // Singular, API format
// Error-prone for users
```
### Issue 3: Scattered Conversion Logic
```javascript
// In update_vehicle:
if (updates.engine) { /* convert */ }
// In add_vehicle:
if (template.engine) { /* convert */ }
// In vehicles.js:
if (data.seats) { /* convert */ }
// Maintenance nightmare
```
## π Next Steps
1. **Review** this document with team
2. **Decide** on approach based on priorities
3. **Create** implementation tickets
4. **Assign** owner for each phase
5. **Track** progress and issues
## π Related Files
- `src/tools/vehicle-tools.js` - Vehicle management tools
- `src/tools/reference-tools.js` - Template generation
- `src/api/vehicles.js` - API client for vehicles
- `src/utils/mappers.js` - Current formatting utilities
- `KNOWN_ISSUES.md` - Tracks this as active issue
## π References
- Original issue: Vehicle update failing with nested engine object
- Error: 400 Bad Request on PUT /vehicle/{id}
- Date discovered: 2025-08-20
- Temporary fix: Added conversion logic to update_vehicle handler
---
**Document maintained by**: AI Assistant
**Last updated**: 2025-08-20
**Status**: Awaiting decision on implementation approach