# Authentication & workspaces Source: https://docs.montra.com/authentication OAuth 2.1 sign-in, the workspace consent screen, and how a connection is scoped. ## OAuth sign-in The connector authenticates with **OAuth 2.1**: PKCE, dynamic client registration, and standard discovery. When an MCP client connects for the first time it is redirected to Montra, where you sign in with your normal Montra account. There are no API keys to create or store — the client ends up holding a short-lived access token for your user, refreshed automatically. Discovery works the standard way: the server publishes protected-resource metadata at `https://montra.com/.well-known/oauth-protected-resource`, which names the authorization server; unauthenticated requests to `/api/mcp` return a `401` whose `WWW-Authenticate` header points at that metadata. Compliant clients handle the whole flow without configuration. ## Workspace binding During sign-in, Montra shows a **consent screen** where you choose exactly one workspace. That choice is recorded per **connection** — keyed by your user *and* the OAuth client — so: * Your Claude connection and your Cursor connection can be bound to different workspaces. * Everyone on a team binds their own connections; nothing is shared implicitly. Every tool except [`get_document_by_share_url`](/tools/get-document-by-share-url) operates strictly inside the bound workspace. Documents you can technically reach as a user — for example, ones shared with you from another workspace — read as *not found* through the connector, because the connection was consented to one workspace only. Share links are the deliberate exception: a pasted link names one specific resource, so the share tool resolves it regardless of the binding. The binding is checked on every request. If your membership in the bound workspace is revoked, or the workspace is deleted, tool calls start failing with a message asking you to reconnect. ### Switching workspaces Reconnect the connector (remove and re-add it in your client, or use the client's re-authenticate action) and pick a different workspace on the consent screen. The new choice replaces the old binding for that connection. If your account belongs to exactly one workspace, a connection that predates the consent screen still resolves to it automatically. With more than one workspace, an unbound connection returns an error asking you to reconnect and choose. ## Revoking access Disconnecting the connector in your MCP client stops it from making further requests. Because access rides on your Montra sign-in, anything that ends your Montra session — or removal from the workspace — also cuts the connection off. ## What the connector can do as you The connector acts **as your user**, through the same row-level security rules as the Montra apps. It can never see more than you can. Writes are real, though: [`update_ticket`](/tools/update-ticket), [`update_document`](/tools/update-document), and [`delete_ticket`](/tools/delete-ticket) overwrite or remove content the same way editing in the app does, so agents should treat them with the care the tool descriptions ask for. # Connect your agent Source: https://docs.montra.com/connect Add the Montra MCP connector to Claude, Claude Code, ChatGPT, Codex, Cursor, or any other MCP client. The connector is a remote MCP server at: ```text theme={null} https://montra.com/api/mcp ``` It uses the Streamable HTTP transport and OAuth 2.1 sign-in. No API key is involved — every client below opens a browser window where you sign in with your Montra account and pick a workspace. See [Authentication](/authentication) for how that works. Montra is also listed in two directories, which is the quickest way in for most people: * [Montra in the Claude directory](https://claude.ai/directory/montra) * [Montra in the ChatGPT plugin directory](https://chatgpt.com/plugins/plugin_asdk_app_6a7f37e662988191af8714ea2c247a3e) ## Claude Open [Montra in the Claude directory](https://claude.ai/directory/montra), click **Connect**, sign in with your Montra account, and choose the workspace this connection should act in. The connector lives on your claude.ai account, so one connect covers: * Claude on the web, desktop, and mobile, * Claude Code, whenever it is signed in with the same claude.ai account (`/mcp` lists it as **claude.ai Montra**). ### Claude Code on an API key, Amazon Bedrock, or another account Those never receive claude.ai's connectors, so give Claude Code its own sign-in: ```bash theme={null} claude mcp add --scope user --transport http montra https://montra.com/api/mcp claude mcp login montra ``` Follow the browser sign-in. After the consent screen the tools are available as `mcp__montra__*`. ## ChatGPT and Codex Install [Montra from the ChatGPT plugin directory](https://chatgpt.com/plugins/plugin_asdk_app_6a7f37e662988191af8714ea2c247a3e) and connect it when asked, signing in with your Montra account and choosing a workspace. The plugin is an account-level grant on your ChatGPT account, so one install covers: * ChatGPT on the web, desktop, and mobile, * Codex inside the ChatGPT desktop app, * the Codex CLI, whenever it is signed in with the same ChatGPT account (`/apps` lists it as `$montra`). ### Codex CLI on an API key, another account, or in the IDE extension Plugins need a ChatGPT sign-in, and the IDE extension does not support plugins at all. For those cases add the server directly: ```bash theme={null} codex mcp add montra --url https://montra.com/api/mcp codex mcp login montra ``` Follow the browser sign-in and choose the workspace this connection should act in. This writes to `~/.codex/config.toml`, which the ChatGPT desktop app, CLI, and IDE extension share. Run `/mcp` in Codex to verify the connection. Pick one path per machine. The plugin and a `codex mcp add` entry both expose Montra's tools, so a Codex session with both configured sees them twice. If you installed the plugin, you can remove the direct entry with `codex mcp remove montra`; the plugin itself is managed from ChatGPT's plugin settings, not from the CLI. ## Cursor Add the server to `~/.cursor/mcp.json` (or the project's `.cursor/mcp.json`): ```json theme={null} { "mcpServers": { "montra": { "url": "https://montra.com/api/mcp" } } } ``` Cursor prompts you to authenticate the first time it connects. ## Other MCP clients Any client that supports remote MCP servers with the Streamable HTTP transport and OAuth 2.1 authorization can connect. Point it at `https://montra.com/api/mcp`; the server advertises its authorization server through the standard protected-resource metadata at: ```text theme={null} https://montra.com/.well-known/oauth-protected-resource ``` Clients that implement the MCP authorization spec (PKCE + dynamic client registration) will discover everything else from there. ## Verify the connection Ask your agent to call [`get_workspace`](/tools/get-workspace). It returns the name and id of the workspace the connection is bound to — a quick confirmation that sign-in and workspace binding both worked. Requests without a valid token get a `401` with a `WWW-Authenticate` challenge pointing at the metadata URL above. That is the protocol working as intended — it is how clients discover where to send you for sign-in, not an outage. # Agent workflow Source: https://docs.montra.com/guides/agent-workflow The recommended loop for implementing Montra tickets without touching what the person wrote. Montra documents are built from screen recordings: a person narrates what they want while pointing at real UI, and Montra turns that into tickets whose bodies are markdown implementation specs. The connector gives an agent everything the person captured. Reading is the default; writing back happens only when the person asks for it. This is the loop that works well. Start from [`list_documents`](/tools/list-documents) (optionally narrowed by a folder from [`list_folders`](/tools/list-folders)), or from a pasted share link via [`get_document_by_share_url`](/tools/get-document-by-share-url). Then open the document with [`get_document`](/tools/get-document) — it returns the document, its folder, its latest generation status, and the visible tickets in order. List views omit ticket bodies. Call [`get_ticket`](/tools/get-ticket) for each ticket you are about to work on — the `body` field is the markdown implementation spec. Then fetch [`get_ticket_images`](/tools/get-ticket-images) and actually look at the images. They are real UI captures the person marked up while recording — arrows, boxes, and notes are instructions, not decoration. For surrounding intent, [`get_transcript`](/tools/get-transcript) returns the narration; treat it as supporting context, the tickets remain the spec. If a ticket is ambiguous or underspecified, ask the person clarifying questions first instead of implementing a guess. If they want the clarified scope written back onto the ticket, they will say so — then, and only then, record it with [`update_ticket`](/tools/update-ticket). Tell the person what you built in the conversation. Do not write progress into Montra: there is no ticket status to set, and rewriting a title or body to say "implemented" or "✅" overwrites the person's spec. The one write you should make without being asked separately is [`link_ticket_issue`](/tools/link-ticket-issue): whenever the person asks you to create a Linear or Notion issue from a ticket, record the link as part of that export so the Montra ticket points at the downstream issue. ## Rules of the road * **Writes are opt-in.** Call [`create_ticket`](/tools/create-ticket), [`update_ticket`](/tools/update-ticket), [`delete_ticket`](/tools/delete-ticket), [`create_document`](/tools/create-document), or [`update_document`](/tools/update-document) only when the person explicitly asks for that change in the conversation — never on your own initiative, and never to mark work done. [`link_ticket_issue`](/tools/link-ticket-issue) is the exception: it is part of any export the person asked for. * **Overwrites are total.** [`update_ticket`](/tools/update-ticket) and [`update_document`](/tools/update-document) replace each field you pass outright — send the complete new text, never a fragment or a diff. Fields you omit are untouched. * **Edits are protected.** Ticket writes made through the connector are flagged as manual edits, so a later background generation will not silently overwrite them. * **Signed URLs are short-lived.** Image and media URLs from [`get_ticket_images`](/tools/get-ticket-images) (and member-resolved share links) expire — fetch them while working the ticket rather than storing them. * **Scope is the bound workspace.** Anything outside the workspace chosen at [consent](/authentication#workspace-binding) reads as not found. Share links are the one deliberate exception. * **Deletes are soft.** [`delete_ticket`](/tools/delete-ticket) removes the ticket from the document but it stays recoverable from the Montra app. # Share links Source: https://docs.montra.com/guides/share-links One Montra share link serves people and agents — and the connector resolves it without touching the web page. A Montra share link looks like: ```text theme={null} https://montra.com/share/ ``` The same link serves two audiences: * **People** open it in a browser and get the share viewer — video, tickets, screenshots. * **Agents** resolve it to a machine-readable payload: the document, every in-scope ticket with its markdown spec, annotated screenshot URLs, recordings, extracted frames, and a set of agent instructions. There is no separate "agent link". When someone hands your agent a share link, the agent should never fetch or browse the web page. ## Resolving a link through the connector Pass the link — exactly as given, query parameters included — to [`get_document_by_share_url`](/tools/get-document-by-share-url). Resolution happens in two legs: 1. **Public access.** If the link is set to *Anyone with the link*, it resolves through the link's own access. Every URL in the payload (images, media, transcript endpoints) is fetchable without authentication. 2. **Member access — "your agent is you."** If the link is invite-only, the tool resolves it as the Montra user who authorized the connection. You can always read your own links and links shared with you, no matter the link's visibility setting. In this mode media URLs are re-minted as short-lived signed links and transcripts are inlined in the response, because the payload's anonymous endpoints cannot serve a private link. The response's `access` field says which leg applied, and `note` explains how to treat the URLs inside. This works on links from **any** workspace — the share tool is the one deliberate exception to the connection's [workspace binding](/authentication#workspace-binding), because a pasted link names one specific resource. ## Query parameters carry scope * `?tickets=` — the person selected specific tickets before copying the link. The resolved payload is narrowed to those tickets; the rest of the document remains readable for context, but only the listed tickets are in scope for implementation. * `?documentId=` — for folder shares, points at one document inside the folder. Folder links resolve to an index of the folder's documents; call the tool again with the same URL plus a `documentId` to read one of them in full. ## Fetching the payload without the connector Public links also serve the payload over plain HTTP, for agents without MCP access: * Append `.json` to the share path: `https://montra.com/share/.json` (query parameters are honored). * Or request the share URL with an `Accept` header that doesn't ask for HTML — non-browser fetches get the JSON payload directly. This anonymous path only works when the link's access is *Anyone with the link*. Invite-only links return a structured `403` explaining that the caller should use the MCP connector instead — which resolves them as the signed-in user, as described above. ## If a link fails to resolve The tool returns an actionable error when a link is invalid, expired, revoked, or invite-only for a user without access. The fixes are on the sharing side: invite the connecting user, switch the link to *Anyone with the link* in Montra's Share dialog, or send a fresh link. # Montra MCP connector Source: https://docs.montra.com/index Give any MCP-capable AI agent direct access to your Montra documents, tickets, screenshots, and transcripts. Montra turns narrated screen recordings into implementation-ready documents made of **tickets** — each ticket a markdown spec with the exact annotated screenshots and narration behind it. The Montra MCP connector exposes those documents to any AI tool that speaks the [Model Context Protocol](https://modelcontextprotocol.io): Claude, Claude Code, Cursor, and other MCP clients. Once connected, your agent can: * **Read work items** — list documents and folders, open a document, and pull each ticket's full markdown implementation spec. * **See what you saw** — fetch the annotated screenshots attached to a ticket and the transcript of what you said while recording. * **Write back when asked** — update titles and specs the person wants changed, and record links to the Linear or Notion issues it created from them. Writes are opt-in; progress is reported in conversation, not by editing tickets. * **Resolve share links** — turn a pasted `montra.com/share/...` link into the full machine-readable payload with [`get_document_by_share_url`](/tools/get-document-by-share-url), no web scraping involved. ## Connection at a glance | | | | ------------------ | ----------------------------------------------------------------------------------------------------------- | | **Server URL** | `https://montra.com/api/mcp` | | **Transport** | Streamable HTTP | | **Authentication** | OAuth 2.1 with PKCE and dynamic client registration — you sign in with your Montra account | | **Scope** | One Montra workspace, chosen on the consent screen ([workspace binding](/authentication#workspace-binding)) | ## Where to go next Set up the connector in Claude, Claude Code, Cursor, or any other MCP client. How OAuth sign-in and per-connection workspace binding work. The recommended loop for implementing Montra tickets without touching what the person wrote. Every tool the connector exposes, with inputs and outputs. # create_document Source: https://docs.montra.com/tools/create-document Create a draft Montra document in the connected workspace. Creates a new draft document in the workspace this connection is bound to, with the title you pass and nothing else. Add work to it with [`create_ticket`](/tools/create-ticket), and fill in a summary later with [`update_document`](/tools/update-document). Call it only when the person explicitly asks for a new document. ## Input Title for the new Montra document. Surrounding whitespace is trimmed; 1 to 200 characters after trimming. ## Output Id of the new document. Pass this to [`create_ticket`](/tools/create-ticket) or [`get_document`](/tools/get-document). Document title. Short summary of the document. Empty on a new document. Document status. Id of the folder holding this document. `null` when the document is not in a folder. Id of the workspace the document belongs to. When the document was last updated. ## Notes * The document is created in the bound workspace; there is no way to create one elsewhere through the connector. * It appears in the Montra app immediately, so use a title a person will recognize. # create_ticket Source: https://docs.montra.com/tools/create-ticket Add a ticket to a Montra document. Adds a new ticket to an existing document. `title` is the short label, `summary` is the one-line gist shown next to it, and `body` is the markdown implementation spec an agent reads before building. Call it only when the person explicitly asks you to add a ticket — never on your own initiative, for example to break work down or log follow-ups you noticed. Tickets created through the connector carry the same "manual" source as tickets a person adds in the app — they are hand-authored work items, not output of a generation job. ## Input Id of the Montra document the ticket belongs to (UUID). Short title for the ticket. Trimmed; 1–300 characters. One-line gist of the ticket. Trimmed; up to 1000 characters. Markdown implementation spec for the ticket. ## Output Id of the newly created ticket. Id of the document the ticket belongs to. Short title for the ticket. One-line gist shown next to the title. Empty string when none was given. Markdown implementation spec. Empty string when none was given. `todo` or `done`. New tickets start at `todo`. Opaque ordering key that places the ticket within its document. Empty for tickets created here. Offset into the source recording, in milliseconds, that the ticket points at. `0` for tickets created here, which are not tied to a recording moment. Id of the input whose generation produced the ticket. `null` for tickets created here. ISO 8601 creation timestamp. ISO 8601 timestamp of the last change. ## Notes * The document must be in the workspace this connection is bound to; anything else reads as not found. See [workspace binding](/authentication#workspace-binding). * To create the document first, use [`create_document`](/tools/create-document). * Related: [`update_ticket`](/tools/update-ticket), [`get_ticket`](/tools/get-ticket), and the [agent workflow guide](/guides/agent-workflow). # delete_ticket Source: https://docs.montra.com/tools/delete-ticket Remove a ticket from its Montra document. Removes a ticket from its document. The delete is soft: the ticket stops appearing in the document and stops being readable through the connector, but it stays recoverable from the app. Call it only when the person explicitly asks you to delete that ticket. Finished work is not a reason to delete — report progress in conversation and leave the ticket alone. ## Input Id of the Montra ticket (UUID). ## Output Always `true` when the call succeeds. Id of the deleted ticket. ## Notes * Deleting an already-deleted ticket reads as not found rather than succeeding again. * Tickets outside the workspace this connection is bound to read as not found. See [workspace binding](/authentication#workspace-binding). * Related: [`get_ticket`](/tools/get-ticket), [`update_ticket`](/tools/update-ticket). # get_document Source: https://docs.montra.com/tools/get-document Read one Montra document with its folder, tickets, and latest generation status. Reads one document in full: the document itself, the folder it lives in, the status of its latest generation, and the tickets a reader sees in the app. Each ticket's `body` is the markdown implementation spec — that is the work you are being asked to do. Get a `documentId` from [`list_documents`](/tools/list-documents). For the typical read-then-implement loop, see [the agent workflow guide](/guides/agent-workflow). ## Input Id of the document to read, as returned by [`list_documents`](/tools/list-documents). ## Output Document id. Document title. Short summary of the document. Empty when none has been written. Document status. Whether the document has been marked complete. Id of the folder holding this document. `null` when the document is not in a folder. When the document was created. When the document was last updated. The folder holding the document. `null` when the document is not in a folder. Folder id. Folder name. Folder description. Empty when none has been written. Status of the document's latest generation. `null` when nothing has been generated yet. Status of the latest generation. When that generation last changed status. Ticket id. Pass this to [`get_ticket`](/tools/get-ticket) or [`get_ticket_images`](/tools/get-ticket-images). Ticket title. One-line summary of the ticket. Markdown implementation spec. May be empty — see the notes below. Either `todo` or `done`. How many screenshots are attached. Read them with [`get_ticket_images`](/tools/get-ticket-images). Id of the recording or other input this ticket came from. `null` when the ticket is not tied to one. Pass it to [`get_transcript`](/tools/get-transcript) for the narration behind it. Sort key. Tickets are already returned in this order. Position in the recording, in milliseconds, that the ticket refers to. ## Notes * Tickets that are hidden, deleted, or merged into another ticket are left out, so the list matches what a person sees in the app. The rest are returned in the app's own order. * A ticket's `body` can come back empty when the document is read in a compact form. When that happens, read the ticket with [`get_ticket`](/tools/get-ticket) to get the full spec rather than treating it as an empty ticket. * A document outside the bound workspace reads as not found, even if your user account can otherwise reach it — for example a document shared with you from another workspace. Resolve those with a [share link](/guides/share-links) instead. * `imageCount` above zero means the person marked up real UI screenshots while recording. Fetch them with [`get_ticket_images`](/tools/get-ticket-images) and read them as part of the spec. # get_document_by_share_url Source: https://docs.montra.com/tools/get-document-by-share-url Resolve a pasted Montra share link into its full machine-readable payload. Someone pastes you a Montra share link. This tool turns it into the payload behind it: the document, every in-scope ticket with its markdown spec, annotated screenshot URLs, recordings, extracted frames, and the agent instructions that come with the share. Always use this instead of fetching or browsing the share web page. The page is built for people; this returns the same content in a form you can act on, and it works on links the anonymous web fetch would refuse. ## Input The Montra share link exactly as it was given to you, or a bare share token. Accepted forms: a `/share/` or `/tasks-for-agents/` URL on any host (a trailing `.json` is fine), or the token on its own (16–128 characters of letters, digits, `-`, and `_`). Query parameters on the URL are honored — `?tickets=` narrows the payload to the tickets the person selected, and `?documentId=` points at one document inside a folder share. Paste the link whole rather than trimming it. For folder shares: id of one document from the folder payload's `documents[]` to read in full (UUID). Takes precedence over a `documentId` in the URL. ## Output Which resolution leg applied: `public` or `member`. See [How resolution works](#how-resolution-works). Plain-language guidance for this particular response — how to treat the URLs inside it, and whether it is a folder index rather than a document. The share payload. A document share and a folder share return different shapes; `resourceType` tells you which. `document` or `document_ticket`. `document` or `ticket`. Id of the shared resource. Document title. Document summary. `null` when it has none. The share URL this payload was resolved from. Can be a legacy expiring link, so when pasting a link anywhere durable — an external tracker, a commit message — use `humanShareUrl` instead. Durable human-facing link to the same resource, safe to paste into a tracker. `null` when no durable link exists yet. How the share's author wants the payload used — which object is primary, and guidance to follow. Anonymous `context` and `transcript` URLs for re-fetching. Only resolvable when `access` is `public`. The in-scope tickets — the implementation instructions. Ticket id, usable with the ticket tools when the document is in your bound workspace. Ticket title. `todo` or `done`. One-line gist. `null` when the ticket has none. The markdown body split into bullet lines. The original markdown body, unsplit. Offset into the source recording the ticket points at, in milliseconds. Id of the recording in `recordings[]` this ticket came from. `null` for hand-added tickets. Durable link scoped to this one ticket, ready to paste into an external tracker. `null` when no durable link exists. Annotated screenshots — `id`, `timestampMs`, `caption` (`null` when absent), and `annotatedImageUrl`. Load these before implementing; the user's markup is the instruction. Unannotated frames from the recording, as supporting context: `id`, `timestampMs`, `description` (`null` when absent), `inputId` (`null` when unattributed), `frameUrl`. The document's inputs: `id`, `title` (`null` when unnamed), `kind`, `durationMs` (`null` when unknown), `transcriptUrl`, and `mediaUrl` (`null` when no media). Present while task generation can still change the ticket list. When it says generation is not complete, the tickets here are partial — wait and re-read before implementing. Absent means complete. `folder`. Folder id. Folder name. The share URL this payload was fetched with. Durable human-facing link to the folder. `null` when none exists yet. Guidance to follow, as on a document share. The folder's documents: `id`, `title`, and a per-document `context` URL. Call this tool again with the same url plus one of these ids as `documentId` to read a document in full. Recording narration, inlined. Present only in `member` mode, and only for recordings that have a transcript. Id of the recording this transcript belongs to. Full transcript text. Timed chunks: `startMs` and `endMs` (either may be `null`) plus `text`. ## How resolution works Resolution happens in two legs, and `access` tells you which one applied. 1. **`public`** — the link is set to *Anyone with the link*, so it resolves through its own access. Every URL in the payload (images, media, transcript and context endpoints) is fetchable without authentication, and you can re-fetch `endpoints.context` later. 2. **`member`** — the link is invite-only, so it resolves as the Montra user who authorized this connection. Your agent is you: you can read your own links and links shared with you regardless of the link's visibility setting. In `member` mode the payload's anonymous endpoints cannot serve the link, so two things change: image and media URLs are re-minted as **short-lived signed links** — fetch them while you work rather than storing them — and transcripts are **inlined** in `transcripts` instead of being left behind `transcriptUrl`. ## Notes * This tool works on links from **any** workspace. It is the one deliberate exception to the connection's [workspace binding](/authentication#workspace-binding), because a pasted link names one specific resource. Every other tool stays inside the bound workspace. * Folder links resolve to an index of the folder's documents. Read one by calling again with the same url plus its `documentId`. * A `?tickets=` filter means the person chose those tickets deliberately: only they are in scope for implementation, even though the rest of the document is readable for context. * If the link fails to resolve, it is either invalid, expired, or revoked, or it is invite-only and the connecting Montra account has no access. The fixes are on the sharing side: have the person invite that account, switch the link to *Anyone with the link* in Montra's Share dialog, or send a fresh link. * The full story — how the same link serves people and agents, and how to fetch a public payload without the connector — is in the [share links guide](/guides/share-links). # get_ticket Source: https://docs.montra.com/tools/get-ticket Read one Montra ticket in full, including its markdown implementation spec. Reads a single ticket, including `body` — the markdown implementation spec that tells you what to build. Document and ticket listings omit `body` because it is the heavy field, so fetch the ticket here before you start implementing it. Screenshots are not part of this response. When a ticket refers to UI, pull its annotated images with [`get_ticket_images`](/tools/get-ticket-images) and actually look at them: the user's markup is the instruction. ## Input Id of the Montra ticket (UUID). ## Output Ticket id. Id of the document the ticket belongs to. Short title for the ticket. One-line gist shown next to the title. Empty string when the ticket has none. Markdown implementation spec. Empty string when the ticket has no body. `todo` or `done`. Opaque ordering key that places the ticket within its document. Offset into the source recording, in milliseconds, that the ticket points at. Id of the input (usually a recording) whose generation produced this ticket. `null` when the ticket was added by hand rather than generated. ISO 8601 creation timestamp. ISO 8601 timestamp of the last change. ## Notes * A ticket whose document sits outside the workspace this connection is bound to reads as not found, even if your Montra account can see it in the app. See [workspace binding](/authentication#workspace-binding). * Deleted tickets are not returned. * Related: [`update_ticket`](/tools/update-ticket), [`get_ticket_images`](/tools/get-ticket-images), and the [agent workflow guide](/guides/agent-workflow). # get_ticket_images Source: https://docs.montra.com/tools/get-ticket-images Get the screenshots attached to a Montra ticket, as short-lived signed URLs. Returns the screenshots attached to a ticket. These are real UI captures the person marked up while recording — arrows, boxes, and notes drawn straight onto the screen — so read them as part of the implementation spec rather than as decoration. Each `url` is a short-lived signed link, minted fresh on every call. Fetch the images while you are working the ticket instead of storing the URLs for later. Ticket ids come from [`get_document`](/tools/get-document); its `imageCount` tells you whether a ticket has any images before you call this. ## Input Id of the Montra ticket whose images to read. ## Output Returned in the order they appear on the ticket. Id of this image reference on the ticket. Signed link to the image. `null` when the image has no resolved version yet — for example while it is still uploading. Caption written for the image. Empty when there is none. Whether Montra includes this image when it builds the prompt for the ticket. Position in the recording, in milliseconds, the screenshot was taken from. Image type, such as `image/png`. `null` when no version has resolved. Image width in pixels. `null` when no version has resolved. Image height in pixels. `null` when no version has resolved. Id of the underlying media asset. Id of the exact image version the `url` points at. `null` when no version has resolved. Sort key. Images are already returned in this order. How long the signed URLs stay valid, in seconds. Currently one hour (3600). `true` when the ticket has more images than were returned. ## Notes * URLs expire after `expiresInSeconds` (one hour). Once they lapse, call the tool again for fresh links rather than reusing the old ones. * At most 100 images are returned per ticket. Anything beyond that is dropped and `truncated` comes back `true`. * An image that is still uploading, or whose version cannot be resolved, comes back with `url`, `mimeType`, `width`, `height`, and `revisionId` all `null`. Retry later rather than treating it as missing. * Each reference resolves to its pinned version if one was chosen, otherwise the asset's current version — so you see the same image a person sees in the app. * A ticket whose document is outside the bound workspace reads as not found. See [workspace binding](/authentication#workspace-binding). # get_transcript Source: https://docs.montra.com/tools/get-transcript Read the recording narration behind a document or a single input. Returns what the person said while recording — the narration the document's tickets were generated from. Pass a `documentId` for every transcribed input on that document, or an `inputId` for a single recording. This is supporting context. The tickets from [`get_document`](/tools/get-document) remain the spec; use the transcript to understand intent or resolve a vague reference, not to invent extra work. ## Input Id of the Montra document whose input transcripts to read. Id of a single input (recording) whose transcript to read. Ticket `inputId` values from [`get_document`](/tools/get-document) work here. ## Output One entry per transcribed input. Id of the input this transcript belongs to. Title of the input. What kind of input it is, such as a recording. The narration as spoken. For older captures whose plain text was never stored, this is rebuilt from the segments with a `[mm:ss]` timestamp on each line. Timed segments of the narration. Empty when the transcript has none. What was said in this segment. Segment start, in milliseconds. `null` when the transcript did not record one. Segment end, in milliseconds. `null` when the transcript did not record one. Id of the exact transcript version returned. When that transcript version was created. `true` when this transcript's text or segments were cut short by the response caps. `true` when any returned transcript was cut short. ## Notes * Pass exactly one of `documentId` or `inputId`. Passing both, or neither, is rejected. * Inputs without a transcript are dropped from the result: text inputs never have one, and a recording is transcribed in the background, so a recent one may still be processing. When nothing on the document has a transcript yet, the call comes back with a message saying so — retry later rather than concluding there was no narration. * The response is capped across all transcripts at 200,000 characters and 2,000 segments so a long recording cannot flood your context. Whatever is cut is flagged by `truncated`, both per transcript and at the top level. * An input that has not been filed into a document yet is still being classified and reads as not found, as does anything hanging off a document outside the bound workspace. See [workspace binding](/authentication#workspace-binding). # get_workspace Source: https://docs.montra.com/tools/get-workspace Show which Montra workspace this connection is bound to. Returns the name and id of the workspace this connection was bound to on the consent screen. Useful as a quick check that sign-in and [workspace binding](/authentication#workspace-binding) both worked. ## Input This tool takes no input. ## Output Workspace id. Workspace display name. # Tool reference Source: https://docs.montra.com/tools/index Every tool the Montra MCP connector exposes. All tools operate in the workspace the connection was [bound to at consent](/authentication#workspace-binding), except [`get_document_by_share_url`](/tools/get-document-by-share-url), which resolves a pasted share link from any workspace. Write tools are opt-in: an agent should call them only when the person explicitly asks for that change in the conversation. The exception is [`link_ticket_issue`](/tools/link-ticket-issue), which is part of any export the person asked for. Progress is reported in conversation, never by editing a ticket — see the [agent workflow guide](/guides/agent-workflow#rules-of-the-road). ## Workspace | Tool | Access | What it does | | --------------------------------------- | ------ | ------------------------------------------------- | | [`get_workspace`](/tools/get-workspace) | Read | Show which workspace this connection is bound to. | ## Documents & folders | Tool | Access | What it does | | ------------------------------------------- | ------ | ------------------------------------------------------------------------- | | [`list_documents`](/tools/list-documents) | Read | List recent documents, optionally limited to one folder. | | [`get_document`](/tools/get-document) | Read | Read one document with its folder, tickets, and latest generation status. | | [`create_document`](/tools/create-document) | Write | Create a draft document. | | [`update_document`](/tools/update-document) | Write | Replace a document's title and/or summary. | | [`list_folders`](/tools/list-folders) | Read | List the workspace's folders. | ## Tickets | Tool | Access | What it does | | ----------------------------------------------- | ------ | -------------------------------------------------------------------- | | [`get_ticket`](/tools/get-ticket) | Read | Read one ticket in full, including its markdown implementation spec. | | [`create_ticket`](/tools/create-ticket) | Write | Add a ticket to a document. | | [`update_ticket`](/tools/update-ticket) | Write | Replace a ticket's title, summary, or body. | | [`delete_ticket`](/tools/delete-ticket) | Write | Soft-delete a ticket from its document. | | [`link_ticket_issue`](/tools/link-ticket-issue) | Write | Record the Linear or Notion issue a ticket was exported to. | ## Media & transcripts | Tool | Access | What it does | | ----------------------------------------------- | ------ | ------------------------------------------------------------------- | | [`get_ticket_images`](/tools/get-ticket-images) | Read | Get the annotated screenshots attached to a ticket, as signed URLs. | | [`get_transcript`](/tools/get-transcript) | Read | Read the recording narration behind a document or a single input. | ## Share links | Tool | Access | What it does | | --------------------------------------------------------------- | ------ | -------------------------------------------------------------------------- | | [`get_document_by_share_url`](/tools/get-document-by-share-url) | Read | Resolve a pasted Montra share link into its full machine-readable payload. | # link_ticket_issue Source: https://docs.montra.com/tools/link-ticket-issue Record the Linear or Notion issue a Montra ticket was exported to. Records where a ticket now lives downstream — the Linear issue or Notion page you just created from it — so the Montra ticket shows a link back to it. Whenever the person asks you to create an external issue from a ticket, call this as part of that export — it does not need a separate ask. Do not call it for issues you did not create, and it is not a way to mark a ticket done. A ticket holds one link per provider. Calling this again for the same ticket and provider re-points the existing link rather than adding a second one. ## Input Id of the Montra ticket (UUID). External system the ticket was exported to: `linear` or `notion`. Provider-facing id of the issue or page, such as a Linear identifier like `MON-123`. Trimmed; 1–64 characters. Deep link to the external issue or page. Must be an `https` URL. ## Output Id of the recorded link. Id of the Montra ticket the link belongs to. Id of the document that ticket belongs to. `linear` or `notion`. Provider-facing id of the issue or page. Deep link to the external issue or page. ## Notes * When you create the external issue, link it back to Montra using that ticket's own durable `humanShareUrl` from the [share link payload](/tools/get-document-by-share-url) — not the `shareUrl` the payload was fetched with, which can be a legacy expiring link. * Tickets outside the workspace this connection is bound to read as not found. See [workspace binding](/authentication#workspace-binding). * Related: [`get_ticket`](/tools/get-ticket), [`update_ticket`](/tools/update-ticket), and the [agent workflow guide](/guides/agent-workflow). # list_documents Source: https://docs.montra.com/tools/list-documents List recent Montra documents in the connected workspace, optionally limited to one folder. Lists the most recently updated documents in the workspace this connection is bound to. This is the usual starting point: pick a document here, then read it in full with [`get_document`](/tools/get-document). Pass a `folderId` to narrow the list to one folder. Folder ids come from [`list_folders`](/tools/list-folders). ## Input Only return documents in this folder. Folder ids come from [`list_folders`](/tools/list-folders). Omit to list across the whole workspace. Maximum number of documents to return. Defaults to 25; minimum 1, maximum 100. ## Output Document id. Pass this to [`get_document`](/tools/get-document). Document title. Short summary of the document. Empty when none has been written. Document status. Id of the folder holding this document. `null` when the document is not in a folder. Id of the workspace the document belongs to. When the document was last updated. ## Notes * Results are ordered by recency, newest first, whether or not a folder filter is applied. With a `folderId`, the folder's documents are read first and the limit is applied afterwards, so the newest ones survive the cut rather than the oldest. * Documents are never returned from outside the bound workspace, even ones your user account can otherwise reach. See [workspace binding](/authentication#workspace-binding). * The list carries no tickets. Use [`get_document`](/tools/get-document) for a document's tickets and generation status. # list_folders Source: https://docs.montra.com/tools/list-folders List the folders in the connected workspace. Lists the folders in the workspace this connection is bound to. Folders group documents the way project folders do in the app; use a folder id to narrow [`list_documents`](/tools/list-documents). ## Input This tool takes no input. ## Output Folder id. Pass this as `folderId` to [`list_documents`](/tools/list-documents). Folder name. Folder description. Empty when none has been written. # update_document Source: https://docs.montra.com/tools/update-document Replace the title and/or summary of a Montra document. Replaces a document's title, its summary, or both. This overwrites whatever is stored, including text a person wrote in the app, so read the document with [`get_document`](/tools/get-document) first and only write when you mean to replace what is there. Call it only when the person explicitly asks you to change the title or summary — never on your own initiative, and never to note progress. ## Input Id of the document to update. New title. Replaces the existing title. Surrounding whitespace is trimmed; 1 to 200 characters after trimming. New summary. Replaces the existing summary; pass an empty string to clear it. Maximum 2000 characters. ## Output Document id. Title after the update. Summary after the update. Document status. Id of the folder holding this document. `null` when the document is not in a folder. Id of the workspace the document belongs to. When the document was last updated. ## Notes * Pass at least one of `title` or `summary`. A call with neither is rejected. * Fields you leave out are untouched. Fields you pass are replaced outright — there is no merge or append, and human edits are overwritten like any other value. * A document outside the bound workspace reads as not found and is never written to. # update_ticket Source: https://docs.montra.com/tools/update-ticket Replace a Montra ticket's title, summary, or markdown body. Rewrites a ticket's text. Each field you pass overwrites the stored value outright, so send the complete new text rather than a fragment or a diff — read the current ticket with [`get_ticket`](/tools/get-ticket) first if you are amending rather than replacing. Call it only when the person explicitly asks you to change the ticket's text — for example to record a clarification they want captured on the ticket. Never call it on your own initiative, and never to record progress: adding "implemented", "done", or "✅" to a title or body overwrites the person's spec, and there is no ticket status to set. Report progress in conversation instead. Pass at least one of `title`, `summary`, or `body`; a call with none of them is an error. ## Input Id of the Montra ticket (UUID). Replacement title. Trimmed; 1–300 characters. Replacement one-line gist. Trimmed; up to 1000 characters. Replacement markdown implementation spec. ## Output Ticket id. Id of the document the ticket belongs to. Title after the update. One-line gist after the update. Empty string when the ticket has none. Markdown implementation spec after the update. Empty string when the ticket has none. `todo` or `done`. Opaque ordering key that places the ticket within its document. Offset into the source recording, in milliseconds, that the ticket points at. Id of the input whose generation produced this ticket. `null` for hand-added tickets. ISO 8601 creation timestamp. ISO 8601 timestamp of this update. ## Notes * Fields you omit are left untouched. Fields you pass are replaced wholesale — there is no append or patch mode. * The edit is flagged as a manual edit, so a generation still running in the background will not overwrite what you wrote. * Tickets outside the workspace this connection is bound to read as not found. See [workspace binding](/authentication#workspace-binding). * Related: [`get_ticket`](/tools/get-ticket), [`link_ticket_issue`](/tools/link-ticket-issue), and the [agent workflow guide](/guides/agent-workflow).