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

# Connect your AI assistant

> Give Claude Code, Cursor or Claude Desktop accurate, first-hand knowledge of the Maat Stays Partner API.

Your coding assistant already knows a great deal about REST APIs in general and nothing
at all about this one. It will guess at our field names, and it will guess plausibly —
which is the expensive kind of wrong.

Connecting it to our MCP server fixes that. One command, and your assistant reads the
real specification: the actual operations, the actual field names, the actual error
codes, the samples we publish. It stops guessing.

## What you'll need

A **partner API key** — the `maat_partner_…` credential your Maat contact issued you.

The key needs the **`partner:mcp.read`** scope. It is separate from the scope your
integration uses, on purpose: reading our documentation and pushing properties into a
workspace are different jobs, and a credential for one should not quietly grant the
other. If your existing key predates this, ask your Maat contact for a docs key rather
than trying the one your sync uses — you will get a `403`, which is the system working.

<Warning>
  **Put the key in an environment variable. Never paste it into the config file
  itself.**

  Every command below writes to a configuration file, and configuration files get
  committed, synced between machines, and shared in screenshots when something breaks.
  A key in an environment variable stays on the machine that needs it.
</Warning>

Set it however your shell does secrets:

```bash theme={null}
export MAAT_PARTNER_API_KEY="maat_partner_..."
```

## Claude Code

```bash theme={null}
claude mcp add --transport http maat-stays https://maatstays.wtf/v1/mcp \
  --header "Authorization: Bearer $MAAT_PARTNER_API_KEY"
```

Then `/mcp` inside Claude Code to confirm `maat-stays` is connected.

## Cursor

Add the server to `~/.cursor/mcp.json` (all projects) or `.cursor/mcp.json` (this project
only):

```json theme={null}
{
    "mcpServers": {
        "maat-stays": {
            "url": "https://maatstays.wtf/v1/mcp",
            "headers": {
                "Authorization": "Bearer ${MAAT_PARTNER_API_KEY}"
            }
        }
    }
}
```

Cursor expands `${MAAT_PARTNER_API_KEY}` from your environment, so the file itself stays
free of secrets — which matters most for `.cursor/mcp.json`, the one that sits inside a
repository.

## Claude Desktop

Edit `claude_desktop_config.json` (**Settings → Developer → Edit Config**):

```json theme={null}
{
    "mcpServers": {
        "maat-stays": {
            "command": "npx",
            "args": [
                "-y",
                "mcp-remote",
                "https://maatstays.wtf/v1/mcp",
                "--header",
                "Authorization:${MAAT_PARTNER_API_KEY}"
            ],
            "env": {
                "MAAT_PARTNER_API_KEY": "Bearer maat_partner_..."
            }
        }
    }
}
```

Claude Desktop speaks stdio rather than HTTP, so `mcp-remote` bridges the two. Two details
that will cost you ten minutes if you miss them: there is **no space** after
`Authorization:` (the argument is split on the first space, so a space there truncates
your header), and the word `Bearer` therefore has to live inside the environment variable.
Restart Claude Desktop after saving.

## What you get

Five tools, and your assistant will reach for them on its own once it knows they exist:

| Tool                                  | What it answers                                              |
| :------------------------------------ | :----------------------------------------------------------- |
| `search_endpoints(query)`             | "Which operation does X?"                                    |
| `get_endpoint(operation_id)`          | Every parameter, body field, response and error for one call |
| `get_data_type(schema_name)`          | The fields of one named type                                 |
| `explain_authentication()`            | How the key-for-token exchange works                         |
| `get_code_sample(operation_id, lang)` | The sample we publish, in cURL, JavaScript, Python or Go     |

Plus three resources it can read whole: the OpenAPI specification, the authentication
guide and the error reference.

Ask it something real:

> How do I push a calendar block for a reservation on my platform?

You should get back the actual operation, keyed on your own `external_uid`, with the
field names we actually use.

## What it can't do — read this before you ask it

The server reads **the published specification and the published guides. That is the
entire corpus.**

It holds no bookings, no properties, no calendars and no guest data. It cannot call the
API on your behalf, cannot see your workspace, and cannot change anything anywhere. Ask
it "what did I sync last night?" and it has no way to know.

That is a deliberate design, not a first release waiting to grow. It is why connecting
your assistant is safe: the credential in your config file unlocks documentation we
already publish to anyone who asks, so a leaked MCP key is an embarrassment rather than
an incident. Everything that touches real data goes through the short-lived token your
integration mints — a different credential, on a different path, with a much shorter
leash.

<Note>
  Your assistant is reading a specification, not running your code. It will still write bugs. Test
  what it gives you against the sandbox before you point it at production.
</Note>

## When it stops working

**Every failure looks the same from inside your editor** — the server disconnects, or the
tools quietly vanish. The cause is almost always the credential.

<AccordionGroup>
  <Accordion title="401 — the key is not valid">
    The key was revoked, rotated, or never made it into the environment variable.
    `echo $MAAT_PARTNER_API_KEY` in the same shell that launched your editor: an
    editor started from the desktop does not inherit a variable you exported in a
    terminal afterwards.

    If the key really is gone, ask your Maat contact for a new one, update the
    environment variable, and re-run the setup command. Claude Code:

    ```bash theme={null}
    claude mcp remove maat-stays
    claude mcp add --transport http maat-stays https://maatstays.wtf/v1/mcp \
      --header "Authorization: Bearer $MAAT_PARTNER_API_KEY"
    ```
  </Accordion>

  <Accordion title="403 — the key is valid but not for this">
    The key is missing the `partner:mcp.read` scope. This is what you get from using
    your integration's key here. Scopes cannot be added to a key after it is issued,
    so ask your Maat contact for a docs key.
  </Accordion>

  <Accordion title="429 — too many requests">
    Each key has its own hourly ceiling. An assistant in a tight loop can reach it.
    Wait for the hour to roll over; if you hit it in normal use, tell us — the ceiling
    is per key and can be raised.
  </Accordion>

  <Accordion title="It connects, but says a route doesn't exist">
    That is usually correct and worth trusting. Much of this API is published as a
    contract before it is enabled, and the specification says so per operation. If the
    server says something is not published, it is not published — it will not invent
    an endpoint to be helpful.
  </Accordion>
</AccordionGroup>

## Rotating your key

Rotation is the same two steps as recovery, in a calmer order: update
`MAAT_PARTNER_API_KEY` in your environment, then restart your editor. Claude Code and
Cursor read the variable when the server starts, so nothing needs reconfiguring — the
config file never held the secret in the first place, which is the whole reason to keep
it out of there.
