Bouncie MCP Server
Deploy the MCP server anywhere with Docker and Docker Compose for easy containerized setup.
HTTP mode uses Express.js to serve MCP endpoint and OAuth routes for multi-user deployments.
The server is built with TypeScript for type safety and development efficiency.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Bouncie MCP ServerCheck my car's current location, fuel level, and battery health."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Bouncie MCP Server
A Model Context Protocol (MCP) server for the Bouncie OBD2 vehicle tracking API. Give Claude, ChatGPT, or any MCP-compatible AI assistant real-time access to your vehicle data — location, trips, diagnostics, fuel level, and more.
What it does
Connect your Bouncie GPS tracker to AI. Ask natural language questions like:
"Where is my car right now?"
"Show me my trips from last week"
"Is my check engine light on? What codes?"
"How much fuel do I have left?"
"What was my longest drive this week?"
Related MCP server: Unoffical Polestar 2 MCP
Features
Real-time vehicle tracking — GPS location, speed, heading, address
Trip history & analytics — distance, duration, average/max speed, fuel consumed, hard braking & acceleration counts, GPS traces (polyline or GeoJSON)
Vehicle diagnostics — check engine light (MIL) status, OBD2 diagnostic trouble codes (DTCs), battery health
Vehicle info — make, model, year, VIN, engine, odometer, fuel level
Multi-user OAuth — HTTP mode proxies Claude.ai's OAuth to Bouncie's, so each user authorizes with their own Bouncie account
Stdio + HTTP modes — run locally with a pre-issued access token, or host centrally for multiple users
Stateless — safe behind a load balancer — no session or token state is held in memory or on disk, so any instance can serve any request
Docker-ready — deploy anywhere with HTTPS
Quick Start
Local (stdio) mode
npm install && npm run buildAdd to Claude Desktop or Claude Code MCP settings:
{
"mcpServers": {
"bouncie": {
"command": "node",
"args": ["/path/to/bouncie-mcp/dist/index.js"],
"env": {
"BOUNCIE_ACCESS_TOKEN": "your-access-token"
}
}
}
}Stdio mode uses a pre-obtained Bouncie access token — no OAuth flow. Use HTTP mode for multi-user deployments.
Remote (HTTP) mode with Docker
cp .env.example .env # fill in your credentials
docker compose up -dThe server exposes:
/mcp— MCP endpoint (Bearer token auth)/authorize— kicks off the OAuth flow, redirects the user to Bouncie/callback— Bouncie's OAuth redirect target/token— token exchange endpoint for MCP clients/register— RFC 7591 dynamic client registration/.well-known/oauth-authorization-server— RFC 8414 authorization server metadata/.well-known/oauth-protected-resource— RFC 9728 protected resource metadata/health— health check
Both .well-known documents are also served under a /mcp suffix, which is where
clients probe when the resource has a path component.
Bouncie App Setup
Register at bouncie.dev and create an app
Note your Client ID and Client Secret
Set the Redirect URL to
{PUBLIC_URL}/callback(e.g.https://bouncie.example.com/callback)
That's all the portal work — users authorize individually through the OAuth flow when they connect via Claude.ai.
Environment Variables
Stdio mode (single-user)
Variable | Required | Description |
| Yes | Pre-obtained Bouncie access token |
HTTP mode (multi-user)
Variable | Required | Description |
| Yes | Bouncie app client ID |
| Yes | Bouncie app client secret |
| Yes | Public URL (e.g. |
| No | MCP access token lifetime in hours, default 24 |
| No | Delay between upstream |
| No | Key material for sealing tokens. Defaults to deriving from |
| No | HTTP server port, default 3000 |
Tools
get_vehicles
List all vehicles on the account with live stats.
Parameter | Type | Description |
| string (optional) | Filter by VIN |
| string (optional) | Filter by device IMEI |
Returns: vehicle info (make/model/year, VIN, IMEI, nickname) and live stats (GPS location, speed, fuel level, odometer, engine running status, battery, check engine light, DTCs).
get_vehicle
Get a single vehicle by VIN or IMEI. At least one identifier required.
get_trips
Get individual trips for a vehicle.
Parameter | Type | Description |
| string | Device IMEI (required) |
| string (optional) | ISO date — trips starting after this time |
| string (optional) | ISO date — trips ending before this time |
| boolean (optional) | Include route geometry. Default |
|
| Format when |
| string (optional) | Fetch a specific trip by transaction ID |
| object (optional) | Keep only trips touching this box — see Geographic filtering |
|
| How the trip must relate to the box (default: intersects) |
Date window max 1 week. Defaults to last 7 days.
Returns: distance, duration, average/max speed, fuel consumed, hard braking/acceleration counts, odometer.
GPS is excluded unless you ask for it. Route geometry is roughly 90% of a
typical response, and most questions don't need it. The upstream API requires a
gpsFormat on every request, so the server always sends one and strips the
result when include_gps is false.
For anything spanning more than a week, use get_mileage_summary rather than
paging this tool.
get_mileage_summary
Driving totals over any date range, bucketed by day, week, month, or year. This
is the tool for trend questions — monthly series, before/after comparisons,
year-over-year — which are impractical to answer by paging get_trips.
Parameter | Type | Description |
| string | Device IMEI (required) |
| string | Start of range, inclusive ( |
| string | End of range, inclusive ( |
|
| Bucket size (default: month) |
| object (optional) | Restrict to trips touching this box — see Geographic filtering |
|
| How the trip must relate to the box (default: intersects) |
Returns a bucket per non-empty period plus a totals block, a partial_trips
count, and warnings if any window could not be fetched. Contains no GPS data.
Field | Meaning |
| Moving trips only |
| Zero-distance records — real fuel burn, counted separately so they don't inflate |
| Summed from each trip's exact |
| Includes fuel burned during idle events |
| Total trip time |
| Moving vs. stopped, within trips |
| Distance over moving time, excluding idle |
| Event counts |
Notes on correctness:
Trips are bucketed by the vehicle's local date, using each trip's own
timeZoneoffset. A 9pm trip on the last day of a month stays in that month.Distances are summed from the per-trip
distancefield, never by differencing odometer readings —startOdometeris rounded to whole miles whileendOdometeris not, so consecutive trips disagree at the seam.Trips still in progress are excluded from totals and reported in
partial_trips.Both metric and imperial units are emitted, matching the shape of the e-bike MCP's
mileage_over_timeso the two series can be compared field for field.
Geographic filtering
Both get_trips and get_mileage_summary accept a bbox to restrict results to
a geographic area. Coordinates are decimal degrees (WGS84):
{ "min_lat": 30.2, "min_lon": -97.8, "max_lat": 30.4, "max_lon": -97.6 }bbox_match chooses what "in the box" means:
Mode | Matches when the trip |
| passes through the box at any point |
| began inside it |
| finished inside it |
| stayed entirely within it |
Three things are worth understanding before relying on this:
Filtering forces GPS to be fetched. A trip record carries no coordinates of its own — position exists only inside
gps. So a box filter always fetches and decodes the route, then discards it again unlessinclude_gpsis set. Usingbboxtherefore costs the full payload upstream even though the response stays small, and it will be slower than an unfiltered query.A matched trip counts in full.
get_mileage_summarywith abboxincludes the entire distance and fuel of every matching trip, including the portion driven outside the box. It answers "how much driving involved this area", not "how many miles were driven inside this area". The response says so in itsnote, and reportsexcluded_by_bboxandunlocatable_trips(trips with no decodable route, which no box can match).Boxes crossing the antimeridian are rejected.
min_lonmust be<=max_lon; split such a query into two boxes.
get_odometer_at
The odometer reading at or before a given moment, from the most recent completed trip. Searches backward up to 30 days.
Parameter | Type | Description |
| string | Device IMEI (required) |
| string | Point in time ( |
Returns odometer_mi (from the unrounded endOdometer), reading_time,
local_time, source_transaction_id, and gap_hours — how far before the
requested time the reading actually is, so you can judge whether it's close
enough to be meaningful.
get_user
Get the authenticated user's profile.
Timestamps
All timestamps from the Bouncie API are in UTC. Each vehicle/trip includes a timezone offset field (localTimeZone or timeZone, e.g. "-0500") for local time conversion.
Development
npm run dev # Run with tsx (hot reload)
npm run build # Compile TypeScript
npm test # Run tests (59 tests)
npm run lint # Type checkArchitecture
src/index.ts— stdio transport entry pointsrc/http.ts— HTTP/Express entry point with OAuthsrc/server.ts— MCP tool definitionssrc/api.ts— Bouncie REST API clientsrc/trips.ts— trip range paging, caching, and aggregationsrc/oauth.ts— OAuth provider that proxies Claude.ai's OAuth to Bouncie's (PKCE supported)src/types.ts— TypeScript types for vehicles, trips, and webhook events
Running more than one instance
This server holds no state — not in memory, not on disk. That is a deliberate design constraint, not an incidental property, because the reference deployment runs two instances behind a load balancer that shares nothing between them.
Everything the server would otherwise need to remember is carried inside the values it hands out, sealed with AES-256-GCM:
Value | Carries | Lifetime |
Bouncie | the pending authorization (client, PKCE challenge, redirect URI, client's own state) | 10 min |
MCP authorization code | Bouncie access token, PKCE challenge, redirect URI | 10 min |
MCP access token | Bouncie access token |
|
MCP refresh token | Bouncie access token | 30 days |
Each blob carries a purpose label and an expiry, and is rejected if either fails.
The sealing key is derived via HKDF from TOKEN_SECRET, or from
BOUNCIE_CLIENT_SECRET when that is unset — a value every instance already
shares, so a multi-instance deployment needs no extra configuration.
The MCP transport is stateless for the same reason: a session pinned to one
process breaks as soon as the next request lands on another instance. GET and
DELETE /mcp therefore return 405, and an mcp-session-id header from a
client's earlier connection is ignored rather than rejected.
For the debugging history behind this design, see docs/oauth-debugging-notes.md.
Two consequences worth knowing:
Rotating
BOUNCIE_CLIENT_SECRETinvalidates every outstanding MCP token, since the sealing key derives from it. SetTOKEN_SECRETexplicitly to decouple them.Individual tokens cannot be revoked, because nothing records that they exist. Rotating the sealing key revokes all of them at once.
Bouncie Webhook Events
The Bouncie API also supports webhooks (documented here for reference):
Event | Description |
| Device plugged in / unplugged |
| Battery status change (normal/critical) |
| Check engine light on/off with DTC codes |
| Trip begins/ends with odometer, fuel consumed |
| Trip summary — distance, speeds, braking/acceleration |
| Real-time GPS breadcrumbs during a trip |
License
MIT
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
- ZapierOAuthcom.zapier
Hosted MCP server connecting AI assistants to 9,000+ apps and 40,000+ actions via Zapier.
- UnifAPIOAuthcom.unifapi
Hosted MCP server for live public-data APIs and Skills for AI agents.
MCP server for Argo RPG Platform — connects AI assistants to campaign data via OAuth2
An MCP server that provides an API to LLMs to manage their JumpCloud resources.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceAn MCP server that exposes Smartcar's vehicle API as tools, enabling AI agents to query vehicle telemetry and send commands using natural language.-
- AlicenseNot gradedqualityDmaintenanceAn MCP (Model Context Protocol) server that exposes Polestar 2 vehicle data to AI assistants like Claude. Query your car's battery status, vehicle info, and health data through natural conversation.MIT
- FlicenseAqualityDmaintenanceMCP server that connects AI assistants to Garmin Connect health and fitness data, enabling natural language queries about workouts, sleep, heart rate, and more.29-
- FlicenseNot gradedqualityCmaintenanceMCP server that exposes health metrics from the Sapphire Wellness App to AI assistants, enabling natural language queries for activity, blood pressure, glucose, heart rate, sleep, and SpO2 data.-