Skip to main content

Building an AI agent

If you are giving a model the ability to read and act on an MTRO PRO portfolio, you have two starting points. Pick the MCP server unless you have a reason not to.

Option 1 — the MCP server​

MTRO PRO ships an MCP server that wraps the API in 172 tools, each with a description and typed arguments the model can use directly: properties_list, bookings_create, leads_update_stage, conversations_send_message, and so on.

It handles authentication, path building, and the error envelope for you, and it is tested against the live route table, so a tool cannot silently point at an endpoint that no longer exists.

The server is open source and MIT licensed, at github.com/mtropro/mcp. Run it pinned to a release tag:

npx -y github:mtropro/mcp#v1.0.0

Configure it with your API key:

{
"mcpServers": {
"mtropro": {
"command": "npx",
"args": ["-y", "github:mtropro/mcp#v1.0.0"],
"env": {
"MTROPRO_API_KEY": "mtro_your_api_key",
"MTROPRO_API_URL": "https://core.mtro.app"
}
}
}
}

Every operation in the API reference names the MCP tool that calls it, so you can move between the two views freely.

Option 2 — the OpenAPI document​

If you are building tools yourself, generate them from the contract rather than by hand:

https://core.mtro.app/openapi.json

It is public, needs no key, and carries everything a generator needs: operation ids, parameters, request schemas, and the scope each operation requires under x-mtro-scopes. There is a browsable console at https://core.mtro.app/api-docs.

Rules your agent has to respect​

Check error in the body, not just the status. Some failures come back as HTTP 200 with error: true. An agent that reads the status alone will report a refused write as a success and carry on. See Errors and conventions.

Give the key the narrowest scopes that work. A key with no scopes inherits everything its creator can do. A read-only agent should hold only the .read scopes it needs. See Authentication and scopes.

Put a human in front of anything that leaves the building. Sending a message reaches a real guest. Creating a payment or a checkout link moves real money. Signing a lease is a legal act. These should require explicit confirmation, not model judgement.

Read before you write. Stage ids, vendor ids, and property ids are per-organization. Fetch the list, then act on an id from it, rather than assuming.

Poll, do not wait. There are no outbound webhooks. Nothing will notify your agent that a message arrived; it has to look.

Watch the shape of list responses. Almost nothing is paginated. A portfolio with hundreds of properties returns all of them in one response, which is a large amount of context to hand a model. Filter before you put it in a prompt. Conversations, logs, and notifications are the exceptions and do take page parameters — use them.

A sensible first agent​

A read-only assistant is a good place to start and carries almost no risk:

  1. Create a key with properties.read, bookings.read, guests.read, leads.read, conversations.read, tasks.read, vendors.read.
  2. Point it at the development environment first.
  3. Let it answer questions: which properties are free next month, which leads have gone quiet, which tasks are overdue.
  4. Add write scopes one at a time, each behind a confirmation step, once you trust what it does with reads.