# MCP server

> Connect Claude, ChatGPT and other MCP clients to your Parklio account with the Parklio MCP server.

The **Parklio MCP server** lets AI assistants such as **Claude Code**, **Claude Desktop** and the
**ChatGPT desktop app**, and any other client that speaks the
[Model Context Protocol](https://modelcontextprotocol.io), work with your Parklio account.
Ask in plain language, for example *"Which devices are offline?"* or *"Share the
entrance barrier with Iva until Friday"*, and the assistant calls the Parklio API for
you with your own API token.

The server runs locally on your computer, started by your MCP client. It is published on
npm as [`@parklio/mcp-server`](https://www.npmjs.com/package/@parklio/mcp-server).

By default it is **read-only**: it can look up lots, devices, occupancy and shared access,
but can't change anything. Sharing access and opening or closing products have to be
[turned on](#enable-write-tools) explicitly.

## Prerequisites

- **Node.js 22 or later**, so your MCP client can run `npx`.
- A **Parklio API token**, created by your account's **Super Admin** (below).
- For [write tools](#write-tools) only:
  - the plan features each tool needs (`REMOTE_CONTROL`, `KEY_SHARE`, `QR_CODE_SHARE`),
    see [Plans and permissions](/concepts/plans-and-permissions);
  - for opening and closing products and for weblinks, an online **Parklio Gateway** on
    the same lot as the product. See [What you need](/get-started/what-you-need).

## Get an API token

The MCP server authenticates to Parklio with an API token, the same kind used for direct
API access. See [Authentication](/api/authentication) for the full flow. In short:

1. [Log in once](/api/authentication#1-log-in-once-as-the-super-admin) with your
   account's **Super Admin** credentials. Only a Super Admin can create API tokens.
2. [Create an API token](/api/authentication#2-create-an-api-token).
3. Copy the `token` from the response.

:::warning
The token is only shown once, at creation time: save it before navigating away. Create a
**dedicated token** for the MCP server rather than reusing one from another integration,
so you can revoke it on its own.
:::

## Install

Pick your MCP client. In each case, replace `<token>` with your API token.

### Claude Code

```bash
claude mcp add parklio -e PARKLIO_API_KEY=<token> -- npx -y @parklio/mcp-server
```

Run `/mcp` in Claude Code to check that `parklio` is connected.

### Claude Desktop

Open **Settings → Developer → Edit Config** and add Parklio to
`claude_desktop_config.json`:

```json title="claude_desktop_config.json"
{
  "mcpServers": {
    "parklio": {
      "command": "npx",
      "args": ["-y", "@parklio/mcp-server"],
      "env": {
        "PARKLIO_API_KEY": "<token>"
      }
    }
  }
}
```

Restart Claude Desktop after saving the file.

### ChatGPT

Use the **ChatGPT desktop app** or the **Codex CLI**. ChatGPT on the web can't start
servers on your computer, so it can't use the Parklio MCP server.

In the desktop app:

1. Open **Settings → MCP servers** and select **Add server**.
2. Enter `parklio` as the name and choose **STDIO**.
3. Enter the command `npx -y @parklio/mcp-server` and add the environment variable
   `PARKLIO_API_KEY` with your token.
4. Save, then select **Restart**.

Or from the Codex CLI:

```bash
codex mcp add parklio --env PARKLIO_API_KEY=<token> -- npx -y @parklio/mcp-server
```

The desktop app, the Codex CLI and the Codex IDE extension share one configuration,
`~/.codex/config.toml`, so adding the server once makes it available in all of them. The
entry looks like this:

```toml title="~/.codex/config.toml"
[mcp_servers.parklio]
command = "npx"
args = ["-y", "@parklio/mcp-server"]

[mcp_servers.parklio.env]
PARKLIO_API_KEY = "<token>"
```

Type `/mcp` in the composer to check that `parklio` is connected.

### Other MCP clients

Any client that runs local (stdio) MCP servers works. Configure it with:

| Setting | Value |
| --- | --- |
| Command | `npx` |
| Arguments | `-y @parklio/mcp-server` |
| Environment | `PARKLIO_API_KEY=<token>` |

### Check the connection

Ask your assistant *"Which Parklio account am I connected to?"*. It answers with the
account name, its enabled features and whether write tools are on.

## Read tools

Always available. They never change anything.

| Tool | What it does | Example prompt |
| --- | --- | --- |
| `get_account_info` | Shows the connected account, its enabled features and whether write tools are on | "Which Parklio account am I connected to?" |
| `list_lots_and_zones` | Lists lots with their zones, address and time zone; finds a lot by name | "List my lots and zones" |
| `list_devices` | Lists devices with their status; filters by lot, zone, type, online status, problems or name | "Which devices are offline?" |
| `get_device_status` | Detailed status of one device by name or device ID | "What's the battery level of the entrance barrier?" |
| `get_occupancy` | Free and occupied spaces per lot and zone | "How many free spaces are there in lot B?" |
| `list_allowlist` | License plates on a lot's allowlist with their validity | "Is ZG-1234-AB on the allowlist of lot A?" |
| `list_shares` | Shared access: app keys, key invitations, weblinks, QR codes, allowlist entries | "Which keys did we share for the entrance barrier?" |
| `find_recipients` | Finds a person's email among account users and past recipients | "What's Iva's email address?" |

You can refer to lots, zones and devices by name. Names match regardless of case and
diacritics; when a name is ambiguous, the assistant gets a list of candidates instead of
a guess.

## Write tools

Available only when you [enable them](#enable-write-tools). They act on real access
control and real hardware.

| Tool | What it does | Plan feature | Example prompt |
| --- | --- | --- | --- |
| `share_key` | Shares an app key; people without a Parklio account get an invitation email | `KEY_SHARE` | "Share the entrance barrier with Iva until Friday" |
| `share_weblink` | Emails a time-limited [weblink](/concepts/access-and-keys#weblinks) that opens a device without the app | – | "Send Marko a one-time link for the gate tomorrow" |
| `create_qr_code` | Creates a [QR code](/concepts/access-and-keys#qr-codes) that opens a device and returns the image | `QR_CODE_SHARE` | "Make a QR code for the visitor chain for the weekend" |
| `add_allowlist_plates` | Adds up to 20 plates to a lot's allowlist | – | "Add ZG-1234-AB to lot A until the end of the month" |
| `remove_allowlist_plates` | Removes plates from a lot's allowlist | – | "Remove ZG-1234-AB from lot A" |
| `open_device` | Opens a barrier, gate, chain, bollard or brain through the Gateway and waits for it to confirm | `REMOTE_CONTROL` | "Open the entrance barrier" |
| `close_device` | Closes one, the same way | `REMOTE_CONTROL` | "Close the visitor chain" |

How they behave:

- **Time windows use the lot's time zone.** "Until Friday" ends on Friday at 23:59:59
  local time at the lot.
- **Open and close report only confirmed results.** The server listens for the Gateway's
  [realtime confirmation](/concepts/asynchronous-operations). If none arrives within 30
  seconds, it says the result is unconfirmed and shows the last known state; it never
  claims an unconfirmed success. Failure reasons, such as a car on top of a barrier, are
  passed on.
- **Writes are never retried**, and an ambiguous device or lot name never leads to a
  write.

### Enable write tools

Set `PARKLIO_READ_ONLY=false` in the server's environment.

Claude Code:

```bash
claude mcp add parklio \
  -e PARKLIO_API_KEY=<token> \
  -e PARKLIO_READ_ONLY=false \
  -- npx -y @parklio/mcp-server
```

Claude Desktop: add `"PARKLIO_READ_ONLY": "false"` to the `env` object, then restart.

ChatGPT: add `PARKLIO_READ_ONLY` with the value `false` to the server's environment
variables (in `config.toml`, under `[mcp_servers.parklio.env]`), then restart.

:::danger
Write tools open real barriers and hand out real access. Your MCP client asks you to
confirm each write call: read what it is about to do before you approve it, and don't
choose **Always allow** for these tools. QR codes can't be revoked once created.
:::

## Configuration

| Variable | Required | Default | Meaning |
| --- | --- | --- | --- |
| `PARKLIO_API_KEY` | Yes | – | Parklio API token, sent as `Authorization: Bearer <token>` |
| `PARKLIO_READ_ONLY` | No | `true` | `false` or `0` enables the write tools |
| `PARKLIO_LOG_LEVEL` | No | `warn` | `error`, `warn`, `info` or `debug`. Logs go to stderr. |
| `PARKLIO_TIMEOUT_MS` | No | `15000` | Timeout for each HTTP request, from `1000` to `300000` |

Run `npx -y @parklio/mcp-server --help` to print this reference, or `--version` for the
installed version.

## Troubleshooting

**The server doesn't start, or the client shows it as failed.**

Check that `node --version` prints 22 or later and that `PARKLIO_API_KEY` is set in the
client's config. The server checks its configuration at startup and writes any problem to
stderr. In Claude Desktop, see the MCP logs under **Settings → Developer**. ChatGPT on
the web can't run the server; use the desktop app.

**The assistant says the token is invalid.**

The token was revoked or copied incompletely. [Create a new one](#get-an-api-token) and
update your client's config.

**The assistant can't find the write tools.**

They are off by default. [Enable them](#enable-write-tools) and restart your client. Ask
*"Which Parklio account am I connected to?"* to check whether write tools are on.

**A share or QR code fails with a permission error.**

Your plan doesn't include the feature the tool needs. See the
[write tools](#write-tools) table and [Plans and permissions](/concepts/plans-and-permissions).

**Open or close comes back unconfirmed or fails.**

Check that the Gateway on the product's lot is online and the product responds in the
Parklio Connect app. See [Troubleshooting](/resources/troubleshooting).

**Who do I contact about issues?**

[Contact Support](https://tickets.parklio.com/).
