# Connect an agent

AutoUncle Data Services runs a remote MCP server, so AI agents and assistants can value cars, browse the catalogue and check your account with the same operations, limits and billing as the REST API.

```text
https://data-services.autouncle.com/mcp
```

## At a glance

| | |
| --- | --- |
| Transport | Streamable HTTP. Every JSON-RPC message is a `POST` to the endpoint above. |
| Sessions | Stateless. The server issues no `Mcp-Session-Id`, and `tools/call` works without a prior `initialize`. |
| Protocol | The server answers `initialize` with protocol version `2025-06-18`. |
| Authentication | OAuth sign-in, or an API key sent as `Authorization: Bearer au_...`. See [OAuth or API key](/docs/mcp/oauth-or-api-key). |
| Tools | `valuate_car`, `normalize_vehicle`, `decode_vin`, `decode_hsn_tsn`, `lookup_plate`, `search_vehicles`, `get_valuation`, `get_account`. See the [tool reference](/docs/mcp/tools). |
| Prompts | `value_a_car`, a guided valuation conversation. |
| Billing | A `valued` live result uses one credit, exactly as over REST. Test keys are free. OAuth connections are always live. |

## Choose how to authenticate

- **API key**: best for servers, scripts and development. A **test key** (`au_test_...`) gives free simulated results, so it is the safest way to try an agent. Configure the key through an environment variable or the client's secret input, never as plain text in a shared file.
- **OAuth**: best for people using a chat assistant. The client opens AutoUncle's sign-in page, you choose one organization and approve the scopes. No key is copied anywhere. OAuth valuations are **live** and use the organization's credits.

[OAuth or API key](/docs/mcp/oauth-or-api-key) compares the two in detail.

## Set up your client

| Client | OAuth | API key header | Guide |
| --- | --- | --- | --- |
| Claude Code | Yes | Yes | [Claude Code](/docs/mcp/claude-code) |
| Claude Desktop and claude.ai | Yes | Limited beta | [Claude Desktop & claude.ai](/docs/mcp/claude-desktop) |
| Cursor | Yes | Yes | [Cursor](/docs/mcp/cursor) |
| VS Code and GitHub Copilot | Yes | Yes | [VS Code & GitHub Copilot](/docs/mcp/vscode) |
| ChatGPT | Yes | No | [ChatGPT, OpenAI API & Codex](/docs/mcp/openai#chatgpt) |
| OpenAI Responses API and Agents SDK | Your app supplies the token | Yes | [ChatGPT, OpenAI API & Codex](/docs/mcp/openai#responses-api) |
| Codex CLI | Yes | Yes | [ChatGPT, OpenAI API & Codex](/docs/mcp/openai#codex-cli) |
| Gemini CLI and Antigravity | Yes | Yes | [Gemini & Antigravity](/docs/mcp/gemini) |
| Windsurf (Devin Desktop) | Yes | Yes | [Windsurf](/docs/mcp/windsurf) |
| Anything else | Depends | Depends | [Other MCP clients](/docs/mcp/other-clients) |

Every guide ends with the same check: ask the agent to **call `get_account`**. A working connection returns your workspace, the key's mode (`test` or `live`) and its scopes.

## Test the endpoint directly

You do not need an MCP client to see what agents receive. These examples send raw JSON-RPC over HTTP with a key from `AUTOUNCLE_API_KEY`. The `Accept` header must allow both JSON and event streams.

Initialize (optional, the server is stateless):

**curl**

```bash
curl https://data-services.autouncle.com/mcp \
  -H "Authorization: Bearer $AUTOUNCLE_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d @- <<'JSON'
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "initialize",
  "params": {
    "protocolVersion": "2025-06-18",
    "capabilities": {},
    "clientInfo": {
      "name": "my-integration",
      "version": "1.0.0"
    }
  }
}
JSON
```

**Ruby**

```ruby
require "json"
require "net/http"

uri = URI("https://data-services.autouncle.com/mcp")
request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer #{ENV.fetch("AUTOUNCLE_API_KEY")}"
request["Content-Type"] = "application/json"
request["Accept"] = "application/json, text/event-stream"
request.body = JSON.generate({
  "jsonrpc" => "2.0",
  "id" => 1,
  "method" => "initialize",
  "params" => {
    "protocolVersion" => "2025-06-18",
    "capabilities" => {},
    "clientInfo" => {
      "name" => "my-integration",
      "version" => "1.0.0"
    }
  }
})
response = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(request) }
puts JSON.pretty_generate(JSON.parse(response.body))
```

**Python**

```python
import json
import os

import requests

response = requests.post(
    "https://data-services.autouncle.com/mcp",
    headers={
        "Authorization": f"Bearer {os.environ['AUTOUNCLE_API_KEY']}",
        "Accept": "application/json, text/event-stream",
    },
    json={
        "jsonrpc": "2.0",
        "id": 1,
        "method": "initialize",
        "params": {
            "protocolVersion": "2025-06-18",
            "capabilities": {},
            "clientInfo": {
                "name": "my-integration",
                "version": "1.0.0"
            }
        }
    },
    timeout=30,
)
print(json.dumps(response.json(), indent=2))
```

**JavaScript**

```javascript
const response = await fetch("https://data-services.autouncle.com/mcp", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.AUTOUNCLE_API_KEY}`,
    "Content-Type": "application/json",
    Accept: "application/json, text/event-stream",
  },
  body: JSON.stringify({
    jsonrpc: "2.0",
    id: 1,
    method: "initialize",
    params: {
      protocolVersion: "2025-06-18",
      capabilities: {},
      clientInfo: {
        name: "my-integration",
        version: "1.0.0"
      }
    }
  }),
});
console.log(JSON.stringify(await response.json(), null, 2));
```

List the tools and their input schemas:

**curl**

```bash
curl https://data-services.autouncle.com/mcp \
  -H "Authorization: Bearer $AUTOUNCLE_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d @- <<'JSON'
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/list"
}
JSON
```

**Ruby**

```ruby
require "json"
require "net/http"

uri = URI("https://data-services.autouncle.com/mcp")
request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer #{ENV.fetch("AUTOUNCLE_API_KEY")}"
request["Content-Type"] = "application/json"
request["Accept"] = "application/json, text/event-stream"
request.body = JSON.generate({
  "jsonrpc" => "2.0",
  "id" => 1,
  "method" => "tools/list"
})
response = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(request) }
puts JSON.pretty_generate(JSON.parse(response.body))
```

**Python**

```python
import json
import os

import requests

response = requests.post(
    "https://data-services.autouncle.com/mcp",
    headers={
        "Authorization": f"Bearer {os.environ['AUTOUNCLE_API_KEY']}",
        "Accept": "application/json, text/event-stream",
    },
    json={
        "jsonrpc": "2.0",
        "id": 1,
        "method": "tools/list"
    },
    timeout=30,
)
print(json.dumps(response.json(), indent=2))
```

**JavaScript**

```javascript
const response = await fetch("https://data-services.autouncle.com/mcp", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.AUTOUNCLE_API_KEY}`,
    "Content-Type": "application/json",
    Accept: "application/json, text/event-stream",
  },
  body: JSON.stringify({
    jsonrpc: "2.0",
    id: 1,
    method: "tools/list"
  }),
});
console.log(JSON.stringify(await response.json(), null, 2));
```

Value a car through the `valuate_car` tool. The arguments are the same body as `POST /v1/valuations`, with `idempotency_key` as an argument instead of a header:

**curl**

```bash
curl https://data-services.autouncle.com/mcp \
  -H "Authorization: Bearer $AUTOUNCLE_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d @- <<'JSON'
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "valuate_car",
    "arguments": {
      "country": "DK",
      "vehicle": {
        "make": "Volkswagen",
        "model": "Golf",
        "model_year": 2020,
        "mileage": {
          "value": 60000,
          "unit": "km"
        }
      },
      "idempotency_key": "first-valuation-001"
    }
  }
}
JSON
```

**Ruby**

```ruby
require "json"
require "net/http"

uri = URI("https://data-services.autouncle.com/mcp")
request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer #{ENV.fetch("AUTOUNCLE_API_KEY")}"
request["Content-Type"] = "application/json"
request["Accept"] = "application/json, text/event-stream"
request.body = JSON.generate({
  "jsonrpc" => "2.0",
  "id" => 1,
  "method" => "tools/call",
  "params" => {
    "name" => "valuate_car",
    "arguments" => {
      "country" => "DK",
      "vehicle" => {
        "make" => "Volkswagen",
        "model" => "Golf",
        "model_year" => 2020,
        "mileage" => {
          "value" => 60000,
          "unit" => "km"
        }
      },
      "idempotency_key" => "first-valuation-001"
    }
  }
})
response = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(request) }
puts JSON.pretty_generate(JSON.parse(response.body))
```

**Python**

```python
import json
import os

import requests

response = requests.post(
    "https://data-services.autouncle.com/mcp",
    headers={
        "Authorization": f"Bearer {os.environ['AUTOUNCLE_API_KEY']}",
        "Accept": "application/json, text/event-stream",
    },
    json={
        "jsonrpc": "2.0",
        "id": 1,
        "method": "tools/call",
        "params": {
            "name": "valuate_car",
            "arguments": {
                "country": "DK",
                "vehicle": {
                    "make": "Volkswagen",
                    "model": "Golf",
                    "model_year": 2020,
                    "mileage": {
                        "value": 60000,
                        "unit": "km"
                    }
                },
                "idempotency_key": "first-valuation-001"
            }
        }
    },
    timeout=30,
)
print(json.dumps(response.json(), indent=2))
```

**JavaScript**

```javascript
const response = await fetch("https://data-services.autouncle.com/mcp", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.AUTOUNCLE_API_KEY}`,
    "Content-Type": "application/json",
    Accept: "application/json, text/event-stream",
  },
  body: JSON.stringify({
    jsonrpc: "2.0",
    id: 1,
    method: "tools/call",
    params: {
      name: "valuate_car",
      arguments: {
        country: "DK",
        vehicle: {
          make: "Volkswagen",
          model: "Golf",
          model_year: 2020,
          mileage: {
            value: 60000,
            unit: "km"
          }
        },
        idempotency_key: "first-valuation-001"
      }
    }
  }),
});
console.log(JSON.stringify(await response.json(), null, 2));
```

[Open this request in the console playground](https://data-services.autouncle.com/console/playground?example=valuation&transport=mcp)

The console playground's **MCP** transport sends this exact call through the same server, so you can compare it with the REST result side by side.

## What results look like

Tool results carry the same JSON as REST: once as `structuredContent` and once as text in `content`, for clients that only read text. They include `notes` and `attributions`; agents must keep them with the price and show `attribution_text` when present ([notes and data sources](/docs/notices)).

Refused and failed valuations return `isError: true` with the full valuation envelope and its `error` object, including `code`, `fix` steps and `retryable`. They are free. If the connection itself is rejected, for example with a missing or revoked key, the server answers with HTTP `401` and a JSON-RPC error whose `data` is a [Problem](/docs/reference/valuations#the-problem-object).

## Next steps

- [Tool reference](/docs/mcp/tools): every argument and result.
- [Agent prompts & examples](/docs/mcp/examples): prompts that make agents use the tools well.
- [Safety & spend control](/docs/mcp/safety): keep agents from spending credits by surprise.
- [Agent skill](/docs/skill): teach a coding agent to integrate the REST API safely.
