> ## Documentation Index
> Fetch the complete documentation index at: https://docs.volteras.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Tools reference

> Every tool the Volteras MCP server exposes, with its arguments, results and the scopes it needs.

The Volteras MCP server exposes two read-only tools. Neither changes anything in your account, and both only ever see the organization your credential belongs to.

| Tool | Title | Scope needed | What it does |
| - | - | - | - |
| [`get_me`](#get_me) | Get caller identity | None | Reports the organization, user and scopes behind the connection. |
| [`list_vehicles`](#list_vehicles) | List vehicles | `vehicles:read` | Lists your connected vehicles, filtered and paged. Hidden from connections without the scope. |

You rarely call these yourself. Your AI client picks the tool and fills in the arguments from what you ask it. This page is for when you want to know exactly what the model can see, or you are calling the server from your own code.

## get\_me

Reports who is calling: the organization the connection is bound to, the portal user acting through it (if any), and the scopes it holds. Any valid token can call it, so it is the quickest way to check a new connection and to find out which scopes are missing.

**Arguments:** none.

### Result

<ResponseField name="organization" type="object" required>
  The organization every tool call is bounded to.

  <Expandable title="properties">
    <ResponseField name="id" type="string">Volteras identifier of the organization.</ResponseField>
    <ResponseField name="name" type="string">Organization name.</ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="user" type="object | null" required>
  The portal user acting through this connection. `null` when a machine credential is calling.

  <Expandable title="properties">
    <ResponseField name="id" type="string">Volteras identifier of the user.</ResponseField>
    <ResponseField name="email" type="string">The user's email address.</ResponseField>
    <ResponseField name="name" type="string">First and last name when set, otherwise the email address.</ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="authenticated_as" type="string" required>
  `user` for a person who signed in through the Volteras Portal and is still active in the organization. `organization_credential` for a machine credential, or for a user token whose person has since left the organization.
</ResponseField>

<ResponseField name="client_id" type="string" required>
  The OAuth client the token was issued to: your AI client's metadata URL when you signed in, or the client id of an MCP credential.
</ResponseField>

<ResponseField name="scopes" type="string[]" required>
  The scopes granted to this connection. See [Scopes](/overview/mcp-authentication#scopes).
</ResponseField>

```json Example result theme={null}
{
  "organization": { "id": "4f6c1d0e-...", "name": "Acme Fleet" },
  "user": { "id": "a1b2c3d4-...", "email": "sam@acme.com", "name": "Sam Taylor" },
  "authenticated_as": "user",
  "client_id": "https://client.example.com/oauth/metadata.json",
  "scopes": ["location:read", "vehicles:read"]
}
```

## list\_vehicles

Lists your organization's connected vehicles, filtered and paged, oldest connection first.

By default only vehicles with an active connection are listed and counted. That means a `connection_status` of `CONNECTED`, `RECONNECTION_REQUIRED` or `PENDING_DISCONNECTION`. Set `include_inactive` to also see the rest.

**Scope needed:** `vehicles:read`. Position fields also need `location:read`.

### Arguments

<ParamField body="fields" type="string[]">
  The fields each vehicle carries. Omit it to get the default set: `id`, `vin`, `make`, `model`, `model_year`, `registration_plate` and `connection_status`. Only the fields you select appear in the result. See [Vehicle fields](#vehicle-fields) for the full list.
</ParamField>

<ParamField body="filters" type="object[]">
  Clauses every returned vehicle must satisfy. Clauses are combined with AND.

  <Expandable title="properties">
    <ParamField body="field" type="string" required>
      The vehicle field to filter on. Must be a filterable field (see [Vehicle fields](#vehicle-fields)).
    </ParamField>

    <ParamField body="operator" type="string" default="==">
      One of `==`, `!=`, `<`, `<=`, `>`, `>=`, `in`, `ilike`, `isNull`, `isNotNull`. See [Filter operators](#filter-operators).
    </ParamField>

    <ParamField body="value" type="string | number | boolean | array">
      The value to compare with. A list for `in`. Omit it for `isNull` and `isNotNull`.
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="page_size" type="integer" default="50">
  Maximum number of vehicles in the page. Between 1 and 200.
</ParamField>

<ParamField body="cursor" type="string">
  The `next_cursor` from the previous page. See [Paging](#paging).
</ParamField>

<ParamField body="include_inactive" type="boolean" default="false">
  Also list and count vehicles whose connection is not active: `DISCONNECTED`, `PENDING_CONNECTION` and `INCOMPATIBLE`. A filter on one of these statuses only matches when this is `true`.
</ParamField>

### Result

<ResponseField name="vehicles" type="object[]" required>
  One page of vehicles. Each vehicle carries exactly the fields you selected.
</ResponseField>

<ResponseField name="total" type="integer" required>
  How many vehicles match across all pages.
</ResponseField>

<ResponseField name="next_cursor" type="string | null" required>
  Pass this back as `cursor` to fetch the next page. `null` on the last page.
</ResponseField>

```json Example result theme={null}
{
  "vehicles": [
    {
      "id": "b7e1c2f0-...",
      "make": "Tesla",
      "model": "Model 3",
      "state_of_charge": 18,
      "state_of_charge_at": "2026-10-14T21:04:11Z"
    }
  ],
  "total": 7,
  "next_cursor": null
}
```

### Vehicle fields

A field you request but whose value is unavailable comes back as `null`. Every telemetry value has a matching `*_at` field saying when the vehicle reported it.

| Field | Type | Filterable | Notes |
| - | - | - | - |
| `id` | string | Yes | Volteras identifier of the vehicle. |
| `vin` | string | No | Vehicle identification number. [Consent-gated](#consent-gated-fields). |
| `make` | string | Yes | Manufacturer. |
| `model` | string | Yes | Model name as reported by the manufacturer. |
| `trim` | string | Yes | The manufacturer's variant name within the model. |
| `model_year` | string | Yes | Model year as reported by the manufacturer. |
| `manufacture_year` | integer | Yes | Year the vehicle was built. Can differ from the model year. |
| `registration_plate` | string | No | [Consent-gated](#consent-gated-fields). |
| `connection_status` | string | Yes | Status of the vehicle's connection to Volteras. |
| `connected_at` | timestamp | Yes | When the connection completed. |
| `last_seen_at` | timestamp | Yes | When the vehicle last reported data. |
| `odometer_km` | number | Yes | Total distance travelled, in kilometres. Telemetry. |
| `state_of_charge` | integer | Yes | Battery state of charge, as a percentage. Telemetry. |
| `range_km` | number | Yes | Estimated range on the current charge, in kilometres. Telemetry. |
| `latitude` | number | Yes | Decimal degrees (WGS84). Position, needs `location:read`. |
| `longitude` | number | Yes | Decimal degrees (WGS84). Position, needs `location:read`. |
| `speed_ms` | number | Yes | Speed, in metres per second. Position, needs `location:read`. |
| `heading_degrees` | number | Yes | Direction of travel, in degrees clockwise from north. Position, needs `location:read`. |
| `elevation_m` | number | Yes | Altitude above sea level, in metres. Position, needs `location:read`. |
| `odometer_at`, `state_of_charge_at`, `range_at` | timestamp | Yes | When each telemetry value was reported. |
| `location_at`, `speed_at`, `heading_at`, `elevation_at` | timestamp | Yes | When each position value was reported. Need `location:read`. |

All timestamps are ISO 8601, in UTC. Units follow our [standardized units](/overview/standardized-units-of-measurement-in-our-api).

`vin` and `registration_plate` can be selected but not filtered on.

### Consent-gated fields

Some values depend on what each vehicle's connection was granted, not on your credential. These come back as `null` for vehicles whose connection does not allow them:

* `vin` and `registration_plate` need the connection to grant access to vehicle information.
* Telemetry and position fields need the connection to grant telemetry access.

A filter on a consent-gated field only matches vehicles whose connection grants that access. So a filter like `state_of_charge < 20` never returns a vehicle whose telemetry you cannot see. See [Scopes](/overview/scopes) for how connection consent works.

### Filter operators

| Operator | Applies to | Meaning |
| - | - | - |
| `==`, `!=` | All filterable fields | Equal or not equal. Case-insensitive for text. |
| `<`, `<=`, `>`, `>=` | Numbers, text and timestamps | Ordering comparisons. |
| `in` | All filterable fields | Matches any value in a list. |
| `ilike` | Text | Case-insensitive substring match. |
| `isNull`, `isNotNull` | All filterable fields | Whether the field has a value. Takes no `value`. |

`connection_status` takes `==`, `!=`, `in`, `isNull` and `isNotNull`, and its values are case-insensitive. A clause using an operator its field does not take is refused with a message listing the operators that field accepts.

Timestamp values are ISO 8601 dates or datetimes. A bare date stands for the whole day under `==` and `!=`, for the start of the day under `<` and `>=`, and for the end of the day under `<=` and `>`.

```json Vehicles below 20% charge, last seen this week theme={null}
{
  "fields": ["id", "make", "model", "state_of_charge", "last_seen_at"],
  "filters": [
    { "field": "state_of_charge", "operator": "<", "value": 20 },
    { "field": "last_seen_at", "operator": ">=", "value": "2026-10-12" }
  ]
}
```

### Paging

When a page has a `next_cursor`, pass it back unchanged as `cursor` with the same `filters`, `page_size` and `include_inactive` to get the next page. You can change `fields` between pages.

A cursor belongs to one walk through the results. It is refused if any of those arguments change, and it expires one hour after the first page was fetched. In either case, call again without a cursor to start over.

## Errors

When a call cannot be answered, the tool returns an error result with a plain sentence explaining why, which your AI client reads and usually acts on. Common ones:

| Message | What to do |
| - | - |
| `latitude requires the location:read scope on your credential.` | Reconnect with the `location:read` scope, or leave out position fields. |
| `` `ilike` is not allowed on state_of_charge. Allowed operators: ... `` | Use one of the listed operators. |
| `Unknown connection_status value 'ONLINE'. Legal values: ...` | Use one of the listed values. |
| `Invalid cursor: ...` | Pass the cursor back unchanged with the same arguments, or start over without one. |
| `Cursor expired; call again without a cursor to start over.` | Start the listing again. |

A connection without the `vehicles:read` scope does not see `list_vehicles` at all: the server leaves it out of the tool list. If your client only shows `get_me`, call it to see which scopes your connection holds.
