Turn your OpenAPI document into tools AI agents can use
Riviera reads your OpenAPI document and serves each operation it can map as an MCP tool. Agents call the tool, Riviera calls your API with your credentials, and every call is recorded. There is no MCP server for you to build, host or keep in sync with your API.
One operation in, one tool out
Each operation becomes a tool. Its operationId becomes the name, its description or summary becomes what the agent reads, and its parameters and JSON body become the input schema. The server URL and path tell Riviera where to send the call. Analysis reads the document only and never calls your API.
{
"operationId": "createInvoice",
"summary": "Create an invoice",
"description": "Creates a draft invoice for a customer.",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": ["customer_id", "amount", "currency"],
"properties": {
"customer_id": {
"type": "string",
"description": "The customer to bill, for example cus_8Hq2."
},
"amount": {
"type": "integer",
"minimum": 1,
"description": "Amount in the smallest currency unit."
},
"currency": {
"type": "string",
"enum": ["usd", "eur", "gbp"]
},
"memo": {"type": "string", "maxLength": 500}
},
"additionalProperties": false
}
}
}
}
}{
"name": "create_invoice",
"description": "Creates a draft invoice for a customer.",
"inputSchema": {
"type": "object",
"properties": {
"body": {
"type": "object",
"required": ["customer_id", "amount", "currency"],
"properties": {
"customer_id": {
"type": "string",
"description": "The customer to bill, for example cus_8Hq2."
},
"amount": {
"type": "integer",
"minimum": 1,
"description": "Amount in the smallest currency unit."
},
"currency": {
"type": "string",
"enum": ["usd", "eur", "gbp"]
},
"memo": {"type": "string", "maxLength": 500}
},
"additionalProperties": false
}
},
"required": ["body"],
"additionalProperties": false
}
}Riviera’s importer output for an example invoicing API, produced when this page was built.
You see what converts, and why the rest doesn’t
Riviera only creates a tool when it can call the operation exactly as your document describes it. In the example, 2 of 4 operations become tools. The other 2 are listed with the reason and what to change. You choose which tools to add, and nothing reaches agents until you publish.
| Operation | Tool | Result |
|---|---|---|
| POST /invoices | create_invoice | Becomes a toolChanges data, so it isn't selected until you choose it. Sends your key in X-Api-Key. |
| GET /invoices/{invoice_id} | get_invoice | Becomes a toolReads data, selected for you. Sends your key in X-Api-Key. |
| GET /customers/{customer_id} | None | Uses schema features Riviera can't map yetnullable, allOf, oneOf, anyOf, $ref with sibling fields and recursive schemas are not supported yet. |
| POST /invoices/{invoice_id}/attachments | None | Sends or returns files, forms or streamsOnly JSON request and response bodies can become tools. |
A generated tool is a first draft
Your summaries were written for people reading docs. Agents pick a tool by its name and description alone, and fill in each input from its description. A summary like “Retrieve an invoice” and an undescribed ID leave them guessing. In Riviera you rewrite what agents read without touching your API or your OpenAPI document.
The get_invoice tool in Riviera’s editor. The initial API definition describes it as “Retrieve an invoice” with no description for path_invoice_id. The edited description says to use it to look up one invoice by ID and check whether a customer has paid, and the parameter is described as the invoice ID.
What agents read
Description
Initial API definitionRetrieve an invoice
Parameters
- Publish in versions
- Edits stay in a draft. Publishing creates a new version agents read, with no deploy of your API, and every published version is kept as it was.
- See every call
- Each tool call shows the tool, the version agents were reading, the outcome, the duration and, when your API returned an error, its HTTP status.
- Check which tool a model picks
- Write the requests your customers make and the tool that should handle each. Riviera asks a real model which tool it would call, on Production and on your draft. Every plan includes model test runs each month: 200 on Free, 2,000 on Pro.
Authentication to your API
Riviera reads the security scheme each operation declares and asks for the matching credential when you add the tool. Agents never see your credentials. They connect to your Riviera endpoint with a project access token you can revoke at any time, or through per-user OAuth. The authentication documentation has the detail.
| Your API uses | What Riviera does |
|---|---|
| No authentication | Calls the operation as your document declares it. |
| An API key in a header | You enter the key once. It is stored encrypted, never shown again and sent only to your API. |
| A static bearer token | The same: stored encrypted and sent only to your API. |
| OAuth client credentials | You confirm the token endpoint, then enter the client ID and secret. Riviera requests tokens with the scopes each operation declares. |
| Per-user OAuth | Each user signs in through your own authorization server, so your API sees who is calling. Your server must publish OAuth metadata and support authorization code with PKCE, token introspection and token exchange (RFC 8693), and register the MCP clients you use. Set it up under Access. |
Not supported yet: HTTP Basic, API keys sent in a query string or cookie, and operations that accept several alternative schemes.
What converts today, and what doesn’t yet
Riviera converts the operations it can call exactly as your document describes them, and tells you why for the rest. Real documents usually need some changes first, and it won’t guess at an operation it can’t call as written. These are the limits today. Most problems are reported per operation, with the reason, and the rest of your API still imports. Every exclusion and what to change is in the import documentation, and a guide reports what stopped operations in real public documents.
| Area | Converts | Not yet |
|---|---|---|
| Document | OpenAPI 3.0 and 3.1 as JSON or YAML 1.2, up to 1 MiB and 200 operations. References inside the document, without sibling fields. A webhooks section is left out, because webhooks are requests your API sends, and the import says how many. | Swagger 2.0, OpenAPI 3.2, references to other files. YAML merge keys, custom tags and numbers with a leading zero. A document with a jsonSchemaDialect, path items defined by reference or duplicate keys is refused whole. |
| Server | One public HTTPS server URL. Server variables with default values. | Several alternative servers, relative URLs, private addresses. |
| Operations | GET, POST, PUT, PATCH and DELETE that answer synchronously. | HEAD, OPTIONS and TRACE. Callbacks and streaming. |
| Parameters | Path and query parameters with simple values, arrays of simple values, simple headers. | Cookie parameters, object-valued parameters, headers that carry credentials. |
| Request bodies | A required body whose only media type is application/json. | Optional bodies, file uploads, multipart and form bodies, bodies that also offer other media types or a charset parameter. |
| Responses | A JSON object (application/json only), the same schema for every success status, or 204 with no body. | A list or a single value at the top level, non-JSON responses, success responses with different schemas, 200 or 201 with no body. |
| Schemas | An explicit type on every schema, enums, required fields and common constraints such as minimum and maxLength. Vendor extensions (x-) are ignored. Formats Riviera knows, such as dates, uuid, email and int64, are checked when an agent calls the tool, and any other format is ignored. Patterns are checked too, with a regular-expression engine that runs in time proportional to the input. | nullable and type unions, oneOf, anyOf, allOf, discriminators, recursive schemas, readOnly and writeOnly, x-nullable, binary or byte formats, and patterns that use lookahead, lookbehind or backreferences. |
Questions teams ask
- Do I need to change or redeploy my API?
- No. Riviera calls your API the way your document describes it, and your API keeps its own rules. When a call fails, the agent is told it failed, with your API’s HTTP status. Riviera doesn’t pass on or store your API’s error body.
- Do I still need to run an MCP server?
- No. Riviera serves the MCP endpoint agents connect to. If you already run an MCP server, you can connect it instead and keep it.
- Does Riviera keep my OpenAPI document?
- Not the raw document. It keeps the tool definitions it produced and the security metadata it needs, never your credentials in plain text, or the example and default values in your schemas.
- What happens when my API changes?
- Analyze the document again. Riviera lists the operations that were added, changed or removed, and agents keep reading the published version until you review the changes and publish.
- Which MCP clients can connect?
- Riviera serves a remote MCP endpoint over Streamable HTTP. We have tested it with the official MCP TypeScript SDK using a project access token, and with ChatGPT using per-user OAuth. See connecting an AI client.
- Can I import a YAML document?
- Yes. Upload, paste or link it as it is. Riviera reads YAML 1.2 with the same limits as JSON, so a document means the same in either format. It refuses a few YAML features that would change what a document means, such as merge keys, custom tags and numbers with a leading zero, and names the line.
- What does it cost?
- Free for one project and 10,000 tool calls a month. Pro is $39 a month for more. See pricing.
Bring your OpenAPI document
Import it, choose the tools, publish and connect an agent. If your document doesn’t import cleanly, email it to hello@riviera.so and we’ll tell you what to change.