> For the complete documentation index, see [llms.txt](https://docs.otari.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.otari.ai/otari/for-integrators/api-reference/mcp.md).

# MCP

## Execute Mcp Tool

> Execute one caller-authorized tool call against a stored MCP server.\
> \
> The calling application owns any user approval, argument editing,\
> cancellation and action history; Otari executes exactly the tool name and\
> arguments it is given, once, and returns the remote server's native result.\
> A result with \`\`isError: true\`\` is a definitive outcome and comes back as an\
> HTTP 200.\
> \
> \*\*This request must never be retried automatically.\*\* \`\`client\_execution\_id\`\`\
> is correlation, not idempotency: once the call has been dispatched Otari\
> cannot know whether the tool ran, and an \`\`outcome\_unknown\`\` response means\
> exactly that. Proxies, service meshes and SDKs on this path have to disable\
> retries for it, including on connection resets and 5xx responses.

```json
{"openapi":"3.1.0","info":{"title":"otari","version":"0.33.0"},"security":[{"ApiKeyAuth":[]},{"XApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"description":"Enter your API key here (sent as Otari-Key header).","in":"header","name":"Otari-Key","type":"apiKey"},"XApiKeyAuth":{"description":"Anthropic-native clients send credentials here (no Bearer prefix).","in":"header","name":"x-api-key","type":"apiKey"}},"schemas":{"McpExecuteRequest":{"additionalProperties":false,"description":"One stored server, and the exact call the application authorized.\n\nNo inline server fields: a caller registers a remote MCP server\nthrough the control plane once and refers to it by id afterwards, which\nkeeps URLs, credentials, revocation and allowlist policy on Otari's side of\nthe boundary instead of in every request.\n\nExtras are forbidden rather than ignored, so a caller still sending the old\ninline ``server`` block is told its configuration was not used instead of\nwatching Otari quietly execute against a different server than the one it\nnamed.","properties":{"arguments":{"additionalProperties":true,"description":"The exact caller-authorized JSON-object arguments.","title":"Arguments","type":"object"},"client_execution_id":{"description":"A caller-generated UUID, for correlation only. It is not proof of approval and not an idempotency key: repeating a request with the same value may execute the tool again, so this request must never be retried automatically.","format":"uuid","title":"Client Execution Id","type":"string"},"mcp_server_id":{"description":"The stored MCP server to execute against.","format":"uuid","title":"Mcp Server Id","type":"string"},"server_revision":{"description":"The stored-server revision returned by tool discovery. Required, and compared against the current one so a configuration change since the caller authorized this call is refused rather than executed. Not an approval credential.","pattern":"^[A-Za-z0-9._:\\-]{1,128}$","title":"Server Revision","type":"string"},"tool_name":{"description":"The remote MCP tool name the caller authorized for this one execution.","maxLength":256,"minLength":1,"title":"Tool Name","type":"string"}},"required":["mcp_server_id","tool_name","server_revision","client_execution_id"],"title":"McpExecuteRequest","type":"object"},"CallToolResult":{"description":"The server's response to a tool call.\n\nErrors that originate from the tool SHOULD be reported inside the result\nwith `is_error` set to true, not as an MCP protocol-level error, so the LLM\ncan see and self-correct. Errors in finding the tool, or any other\nexceptional condition, should be reported as an MCP error response.","properties":{"_meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"content":{"items":{"anyOf":[{"$ref":"#/components/schemas/TextContent"},{"$ref":"#/components/schemas/ImageContent"},{"$ref":"#/components/schemas/AudioContent"},{"$ref":"#/components/schemas/ResourceLink"},{"$ref":"#/components/schemas/EmbeddedResource"}]},"title":"Content","type":"array"},"isError":{"default":false,"title":"Iserror","type":"boolean"},"resultType":{"anyOf":[{"enum":["complete","input_required"],"type":"string"},{"type":"string"}],"default":"complete","title":"Resulttype"},"structuredContent":{"title":"Structuredcontent"}},"required":["content"],"title":"CallToolResult","type":"object"},"TextContent":{"description":"Text provided to or from an LLM.","properties":{"_meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/Annotations"},{"type":"null"}]},"text":{"title":"Text","type":"string"},"type":{"const":"text","default":"text","title":"Type","type":"string"}},"required":["text"],"title":"TextContent","type":"object"},"Annotations":{"description":"Optional annotations the client can use to inform how objects are used or displayed.","properties":{"audience":{"anyOf":[{"items":{"enum":["user","assistant"],"type":"string"},"type":"array"},{"type":"null"}],"title":"Audience"},"lastModified":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastmodified"},"priority":{"anyOf":[{"maximum":1,"minimum":0,"type":"number"},{"type":"null"}],"title":"Priority"}},"title":"Annotations","type":"object"},"ImageContent":{"description":"An image provided to or from an LLM.","properties":{"_meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/Annotations"},{"type":"null"}]},"data":{"title":"Data","type":"string"},"mimeType":{"title":"Mimetype","type":"string"},"type":{"const":"image","default":"image","title":"Type","type":"string"}},"required":["data","mimeType"],"title":"ImageContent","type":"object"},"AudioContent":{"description":"Audio provided to or from an LLM.","properties":{"_meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/Annotations"},{"type":"null"}]},"data":{"title":"Data","type":"string"},"mimeType":{"title":"Mimetype","type":"string"},"type":{"const":"audio","default":"audio","title":"Type","type":"string"}},"required":["data","mimeType"],"title":"AudioContent","type":"object"},"ResourceLink":{"description":"A resource that the server is capable of reading, included in a prompt or tool call result.\n\nNote: resource links returned by tools are not guaranteed to appear in the results of `resources/list` requests.","properties":{"_meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/Annotations"},{"type":"null"}]},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"icons":{"anyOf":[{"items":{"$ref":"#/components/schemas/Icon"},"type":"array"},{"type":"null"}],"title":"Icons"},"mimeType":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Mimetype"},"name":{"title":"Name","type":"string"},"size":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Size"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"type":{"const":"resource_link","default":"resource_link","title":"Type","type":"string"},"uri":{"title":"Uri","type":"string"}},"required":["name","uri"],"title":"ResourceLink","type":"object"},"Icon":{"description":"An optionally-sized icon for display in a user interface (2025-11-25+).","properties":{"mimeType":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Mimetype"},"sizes":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Sizes"},"src":{"title":"Src","type":"string"},"theme":{"anyOf":[{"enum":["light","dark"],"type":"string"},{"type":"null"}],"title":"Theme"}},"required":["src"],"title":"Icon","type":"object"},"EmbeddedResource":{"description":"The contents of a resource, embedded into a prompt or tool call result.\n\nIt is up to the client how best to render embedded resources for the benefit\nof the LLM and/or the user.","properties":{"_meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/Annotations"},{"type":"null"}]},"resource":{"anyOf":[{"$ref":"#/components/schemas/TextResourceContents"},{"$ref":"#/components/schemas/BlobResourceContents"}],"title":"Resource"},"type":{"const":"resource","default":"resource","title":"Type","type":"string"}},"required":["resource"],"title":"EmbeddedResource","type":"object"},"TextResourceContents":{"description":"Text contents of a resource.","properties":{"_meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"mimeType":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Mimetype"},"text":{"title":"Text","type":"string"},"uri":{"title":"Uri","type":"string"}},"required":["uri","text"],"title":"TextResourceContents","type":"object"},"BlobResourceContents":{"description":"Binary contents of a resource.","properties":{"_meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"blob":{"title":"Blob","type":"string"},"mimeType":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Mimetype"},"uri":{"title":"Uri","type":"string"}},"required":["uri","blob"],"title":"BlobResourceContents","type":"object"},"McpErrorBody":{"description":"The one error shape both stored-server endpoints return.","properties":{"code":{"title":"Code","type":"string"},"detail":{"title":"Detail","type":"string"},"execution_state":{"$ref":"#/components/schemas/ExecutionState"},"request_id":{"title":"Request Id","type":"string"}},"required":["detail","code","execution_state","request_id"],"title":"McpErrorBody","type":"object"},"ExecutionState":{"description":"Whether the remote tool may have run.\n\nA retry-safety classification, not a description of how the HTTP request\nwent. ``NOT_STARTED`` is Otari saying it knows the tool did not run;\n``OUTCOME_UNKNOWN`` is Otari saying it cannot know, which is the only honest\nanswer once the transport has begun writing ``tools/call``.","enum":["not_started","outcome_unknown","completed"],"title":"ExecutionState","type":"string"}}},"paths":{"/api/v1/mcp/execute":{"post":{"description":"Execute one caller-authorized tool call against a stored MCP server.\n\nThe calling application owns any user approval, argument editing,\ncancellation and action history; Otari executes exactly the tool name and\narguments it is given, once, and returns the remote server's native result.\nA result with ``isError: true`` is a definitive outcome and comes back as an\nHTTP 200.\n\n**This request must never be retried automatically.** ``client_execution_id``\nis correlation, not idempotency: once the call has been dispatched Otari\ncannot know whether the tool ran, and an ``outcome_unknown`` response means\nexactly that. Proxies, service meshes and SDKs on this path have to disable\nretries for it, including on connection resets and 5xx responses.","operationId":"mcp-execute_mcp_tool","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpExecuteRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallToolResult"}}},"description":"Successful Response"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpErrorBody"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpErrorBody"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpErrorBody"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpErrorBody"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpErrorBody"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpErrorBody"}}},"description":"Conflict"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpErrorBody"}}},"description":"Unprocessable Content"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpErrorBody"}}},"description":"Too Many Requests"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpErrorBody"}}},"description":"Internal Server Error"},"502":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpErrorBody"}}},"description":"Bad Gateway"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpErrorBody"}}},"description":"Service Unavailable"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpErrorBody"}}},"description":"Gateway Timeout"}},"summary":"Execute Mcp Tool","tags":["mcp"]}}}}
```

## List Mcp Tools

> List the tools a stored MCP server exposes to the authenticated workspace.\
> \
> Call this once per server when preparing a model or workflow run, and reuse\
> the answer for every tool from that server for the length of the run: there\
> is no cross-run cache in this version, so a later run rediscovers and\
> staleness stays bounded without any invalidation state to keep.\
> \
> The response is the whole authorized catalog or an error. It is never\
> partial, because a caller would read a short catalog as the complete input\
> to its own authorization and risk policy. The single exception is\
> \`\`warnings\`\`, which names a tool whose descriptor Otari could not carry.\
> \
> A tool the server removes after discovery may still be proposed from the\
> run's snapshot; execution then returns the remote server's own typed error.

```json
{"openapi":"3.1.0","info":{"title":"otari","version":"0.33.0"},"security":[{"ApiKeyAuth":[]},{"XApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"description":"Enter your API key here (sent as Otari-Key header).","in":"header","name":"Otari-Key","type":"apiKey"},"XApiKeyAuth":{"description":"Anthropic-native clients send credentials here (no Bearer prefix).","in":"header","name":"x-api-key","type":"apiKey"}},"schemas":{"McpToolsResponse":{"description":"The authorized catalog for one stored server.\n\nCarries no server URL, no credential, and no allowlist entry that the live\ncatalog did not return. ``server_revision`` is what an\napplication persists with a proposed call and sends back to\n``/api/v1/mcp/execute``, so a stored-configuration change between the two is\nrefused rather than executed.","properties":{"server_id":{"format":"uuid","title":"Server Id","type":"string"},"server_revision":{"description":"An opaque revision of the stored server's URL, credential, enabled state and allowlist. It detects Otari-side configuration changes only: a remote server that changes its own catalog or a tool's behavior behind an unchanged URL will not move it.","title":"Server Revision","type":"string"},"tools":{"items":{"$ref":"#/components/schemas/McpToolDefinition"},"maxItems":200,"title":"Tools","type":"array"},"warnings":{"items":{"$ref":"#/components/schemas/McpToolWarning"},"title":"Warnings","type":"array"}},"required":["server_id","server_revision","tools","warnings"],"title":"McpToolsResponse","type":"object"},"McpToolDefinition":{"description":"One live tool a caller-orchestrated application may expose to its model.\n\n``annotations`` is the remote server's own metadata, passed through as\nuntrusted data. Otari never turns ``readOnlyHint`` into an authorization\ndecision; each application owns its risk policy, and a server\ncannot waive an application's approval gate by labeling itself read-only.","properties":{"annotations":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"description":"The server's MCP annotations, untrusted metadata rather than policy.","title":"Annotations"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The server's own description, untrusted.","title":"Description"},"input_schema":{"additionalProperties":true,"description":"The tool's MCP inputSchema, unmodified.","title":"Input Schema","type":"object"},"name":{"description":"The remote MCP tool name to send back to /api/v1/mcp/execute.","title":"Name","type":"string"}},"required":["name","input_schema"],"title":"McpToolDefinition","type":"object"},"McpToolWarning":{"description":"One tool that was omitted, and the code that omitted it.","properties":{"code":{"title":"Code","type":"string"},"tool_name":{"title":"Tool Name","type":"string"}},"required":["tool_name","code"],"title":"McpToolWarning","type":"object"},"McpErrorBody":{"description":"The one error shape both stored-server endpoints return.","properties":{"code":{"title":"Code","type":"string"},"detail":{"title":"Detail","type":"string"},"execution_state":{"$ref":"#/components/schemas/ExecutionState"},"request_id":{"title":"Request Id","type":"string"}},"required":["detail","code","execution_state","request_id"],"title":"McpErrorBody","type":"object"},"ExecutionState":{"description":"Whether the remote tool may have run.\n\nA retry-safety classification, not a description of how the HTTP request\nwent. ``NOT_STARTED`` is Otari saying it knows the tool did not run;\n``OUTCOME_UNKNOWN`` is Otari saying it cannot know, which is the only honest\nanswer once the transport has begun writing ``tools/call``.","enum":["not_started","outcome_unknown","completed"],"title":"ExecutionState","type":"string"}}},"paths":{"/api/v1/mcp/servers/{mcp_server_id}/tools":{"get":{"description":"List the tools a stored MCP server exposes to the authenticated workspace.\n\nCall this once per server when preparing a model or workflow run, and reuse\nthe answer for every tool from that server for the length of the run: there\nis no cross-run cache in this version, so a later run rediscovers and\nstaleness stays bounded without any invalidation state to keep.\n\nThe response is the whole authorized catalog or an error. It is never\npartial, because a caller would read a short catalog as the complete input\nto its own authorization and risk policy. The single exception is\n``warnings``, which names a tool whose descriptor Otari could not carry.\n\nA tool the server removes after discovery may still be proposed from the\nrun's snapshot; execution then returns the remote server's own typed error.","operationId":"mcp-list_mcp_tools","parameters":[{"in":"path","name":"mcp_server_id","required":true,"schema":{"format":"uuid","title":"Mcp Server Id","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpToolsResponse"}}},"description":"Successful Response"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpErrorBody"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpErrorBody"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpErrorBody"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpErrorBody"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpErrorBody"}}},"description":"Not Found"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpErrorBody"}}},"description":"Unprocessable Content"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpErrorBody"}}},"description":"Too Many Requests"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpErrorBody"}}},"description":"Internal Server Error"},"502":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpErrorBody"}}},"description":"Bad Gateway"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpErrorBody"}}},"description":"Service Unavailable"}},"summary":"List Mcp Tools","tags":["mcp"]}}}}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.otari.ai/otari/for-integrators/api-reference/mcp.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
