Get started with HERE Location Reasoning

Beta availability
HERE Location Reasoning is currently available to beta participants. For information about joining the beta, visit HERE Location Reasoning.

Connect to HERE Location Reasoning through the Model Context Protocol (MCP), authenticate with HERE OAuth 2.1 machine-to-machine (M2M) credentials, start a session, discover available tools, and call a tool.

Prerequisites

  1. Install Python 3.10 or later.

  2. Install the required libraries:

    python3 -m pip install httpx "PyJWT[crypto]"
  3. Verify the installation:

    python3 -c "import httpx, jwt; print(httpx.__version__, jwt.__version__)"
  4. Make sure the openssl command is available to generate your signing key. It is preinstalled on most Linux and macOS systems. On Windows, use Git Bash (included with Git for Windows) or the Windows Subsystem for Linux (WSL).

Step 1: Create and register a signing key

HERE Location Reasoning uses the OAuth 2.1 private_key_jwt flow: you sign a short-lived JWT assertion with a private RSA key, and HERE verifies it against the matching public key you register. The private key never leaves your environment.

  1. Generate a private RSA key. Run this in your terminal; it writes private-key.pem to your current directory:

    openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:3072 -out private-key.pem

    Then derive the matching public key, written as public-key.pem:

    openssl pkey -in private-key.pem -pubout -out public-key.pem
  2. Print the public modulus (n) and exponent (e) you will register with HERE. Run this in your terminal; it uses the cryptography package installed with PyJWT[crypto]:

    python3 -c "
    import base64
    from cryptography.hazmat.primitives.serialization import load_pem_public_key
    nums = load_pem_public_key(open('public-key.pem','rb').read()).public_numbers()
    b64 = lambda v: base64.urlsafe_b64encode(v.to_bytes((v.bit_length()+7)//8,'big')).rstrip(b'=').decode()
    sep = '-' * 40
    print(f'{sep}\nn = {b64(nums.n)}\n\ne = {b64(nums.e)}')
    "
  3. Refer to the steps listed in Using OAuth 2.1 in the HERE Platform for creating OAuth 2.1 credentials. When you register the JWK, paste the RSA public modulus (n) and RSA public exponent (e) generated above.

After registering, you should have the following values:

ValueUsed as
APP IDOAuth client_id
KEY IDJWT header kid

Step 2: Generate a HERE token

Sign a JWT client assertion with your private key and exchange it for a short-lived access token that you include as a bearer token in MCP requests.

import time
import uuid
import httpx
import jwt

TOKEN_URL = "https://account.api.here.com/oauth2/token"
RESOURCE = "https://hlr.here.ai/mcp"
CLIENT_ID = "<YOUR_APP_ID>"     # APP ID from the HERE platform
KEY_ID = "<YOUR_KEY_ID>"        # KEY ID of the registered JWK
PRIVATE_KEY_PATH = "private-key.pem"    # path to your private key file

CLIENT_ASSERTION_TYPE = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"


def get_here_token() -> str:
    """Generate a HERE OAuth 2.1 token using a private_key_jwt client assertion."""
    private_key = open(PRIVATE_KEY_PATH, "r").read()
    now = int(time.time())
    assertion = jwt.encode(
        {
            "iss": CLIENT_ID,
            "sub": CLIENT_ID,
            "aud": TOKEN_URL,
            "iat": now,
            "exp": now + 300,
            "jti": str(uuid.uuid4()),
        },
        private_key,
        algorithm="RS256",
        headers={"kid": KEY_ID},
    )

    resp = httpx.post(
        TOKEN_URL,
        data={
            "grant_type": "client_credentials",
            "client_id": CLIENT_ID,
            "client_assertion_type": CLIENT_ASSERTION_TYPE,
            "client_assertion": assertion,
            "resource": RESOURCE
        },
        headers={"Content-Type": "application/x-www-form-urlencoded"},
        timeout=30,
    )
    resp.raise_for_status()
    try:
        return resp.json()["access_token"]
    except KeyError as exc:
        raise RuntimeError("The token response did not include an access token.") from exc


token = get_here_token()
print("Access token obtained.")

The code signs a five-minute JWT assertion with your private key and exchanges it for a short-lived access token.

Step 3: Initialize the MCP session

Send an initialize request to start an MCP session. The server returns its capabilities and an Mcp-Session-Id header. Include this header in later requests to maintain session context.

HERE_LOCATION_REASONING_URL = "https://hlr.here.ai/mcp"

headers = {
    "Content-Type": "application/json",
    "Authorization": f"Bearer {token}",
}

resp = httpx.post(HERE_LOCATION_REASONING_URL, json={
    "jsonrpc": "2.0",
    "id": 1,
    "method": "initialize",
    "params": {
        "protocolVersion": "2025-03-26",
        "capabilities": {},
        "clientInfo": {"name": "quickstart", "version": "1.0"},
    },
}, headers=headers, timeout=30)
resp.raise_for_status()

session_id = resp.headers.get("mcp-session-id")
if not session_id:
    raise RuntimeError("The initialize response did not include Mcp-Session-Id.")

headers["Mcp-Session-Id"] = session_id
print("Session established.")

A successful request prints Session established.

Step 4: Send initialized notification

Notify the server that your client completed initialization and is ready to use MCP features:

resp = httpx.post(HERE_LOCATION_REASONING_URL, json={
    "jsonrpc": "2.0",
    "method": "notifications/initialized",
    "params": {},
}, headers=headers, timeout=30)
resp.raise_for_status()

This is a notification, so it has no id field. It signals that the handshake is complete.

📘

Note
If you skip this notification, some MCP servers may reject later requests or behave unpredictably.

Step 5: Discover available tools

List the tools exposed by the HERE Location Reasoning MCP server. The tools/list response returns each tool's name, description, and schema, so your application can discover tools without hardcoding them.

resp = httpx.post(HERE_LOCATION_REASONING_URL, json={
    "jsonrpc": "2.0",
    "id": 2,
    "method": "tools/list",
    "params": {},
}, headers=headers, timeout=30)
resp.raise_for_status()

tools = resp.json()["result"]["tools"]
print(f"Available tools: {[t['name'] for t in tools]}")

This returns the full list of tools with their input and output schemas.

Step 6: Call a tool

Call a tool with the tools/call method. Include the tool name and its required arguments.

resp = httpx.post(HERE_LOCATION_REASONING_URL, json={
    "jsonrpc": "2.0",
    "id": 3,
    "method": "tools/call",
    "params": {
        "name": "hlr___geocode",
        "arguments": {"q": "Alexanderplatz, Berlin"},
    },
}, headers=headers, timeout=30)
resp.raise_for_status()

result = resp.json()["result"]
print(result)

This calls the hlr___geocode tool and returns structured coordinate and address data. The tool arguments are:

{
  "name": "hlr___geocode",
  "arguments": {
    "q": "Alexanderplatz, Berlin"
  }
}

A successful call returns a result similar to the following:

{
  "title": "Alexanderplatz",
  "address": {
    "label": "Alexanderplatz, 10178 Berlin, Germany",
    "city": "Berlin",
    "postalCode": "10178",
    "countryName": "Germany",
    "countryCode": "DEU"
  },
  "position": {
    "lat": 52.52192,
    "lng": 13.41321
  }
}

Each response value has its own field. For example, use position.lat and position.lng to place the result on a map, or use address.city and address.countryName to filter or store the result.

Troubleshooting

IssueRoot causeSolution
invalid_client on token requestThe client_id is not the APP ID, or the JWK was registered for another application.Use the APP ID as client_id and confirm the application is active.
Signature or key error on token requestThe JWT kid does not match the registered KEY ID, or private-key.pem is not the pair of the registered public key.Set kid to the registered KEY ID and sign with the matching private key.
Session initialization failsThe bearer token is missing, expired, or invalid.Generate a new token and retry the initialize request.
Later requests fail after initializationThe Mcp-Session-Id header is missing.Include the session ID returned by the initialize response in subsequent requests.
The server returns an MCP errorThe request is invalid or the tool is unavailable.Review the error code and message, then verify the request against the schema returned by tools/list.
Tool call failsThe tool name or arguments do not match the tool schema.Call tools/list and verify the tool name and required arguments.

Next steps


Did this page help you?