Skip to main content
Get Started

Appearance

100%
800px
Page shows a markdown document as a sheet of paper you can print or save as a PDF.

Connect an agent

Pick your client. Everything below the tabs is the full reference.

https://marke.st/mcp

ChatGPT connects over OAuth, so there is no key to paste.

ChatGPT cannot use an API key. You will sign in to Markest and approve the scopes when the first tool runs.

  1. Open Settings → Security and login and turn on Developer mode.
  2. Go to Plugins, select +, and enter the endpoint above as the MCP server URL.
  3. Complete the connection details and create the plugin.
  4. Open the plugin, install it, then start a chat and type @ to invoke it.
  5. The first tool call asks you to sign in to Markest and approve the scopes.

Agent access over MCP

Markest speaks the Model Context Protocol, so an AI agent can search, read and write your pastes as tools rather than by constructing HTTP requests.

The quick start above covers connecting. This page is the reference behind it.

If you want to call Markest from a script rather than an agent, the API reference covers the REST endpoints instead — same permissions, same quotas, same rate limits.

For artifacts encrypted end to end, which this endpoint cannot open, the markest command runs a small MCP server on your own machine, described under Encrypted artifacts: the local server below.

The endpoint

POST https://marke.st/mcp

The transport is streamable HTTP with JSON-RPC 2.0, revision 2025-06-18 — one endpoint, no session setup, one JSON-RPC message per POST. A batch is refused with 400; a notification is accepted with 202 and no body. Opening the endpoint in a browser shows the connection guide; any other GET gets 405, because the server offers no event stream.

Authentication happens before anything is dispatched, tools/list included, so an unauthenticated call returns 401 with a WWW-Authenticate challenge pointing at the server's protected-resource metadata. Tool discovery is not anonymous.

A request carrying an Origin header is refused with 403 unless it comes from Markest itself or a supported client's web app, so a hostile page cannot drive the endpoint through someone's browser; clients calling from their own servers send no Origin and are unaffected. An MCP-Protocol-Version header naming a revision the server does not implement gets 400.

Two ways to connect

An API key suits anything that can set its own headers — Claude Code, Codex, Cursor, VS Code, your own client. Create one under Account → API keys and send it as Authorization: Bearer mk_live_….

OAuth is for ChatGPT, which cannot present an API key at all, and for Claude Desktop, which adds a remote server only as a custom connector in its settings. You add the endpoint, sign in to Markest, and approve the scopes on Markest's own consent screen. Nothing is shared with the application beyond what you approve.

Agent access is a plan feature. If your plan does not include it, calls return a message saying so rather than failing obscurely.

Tools

Shared tools

Discovery now offers 35 purpose-named tools. Shared calls use target (type is artifact or site, plus id for existing resources) and options. mode selects an explicit variant: create/replace, template, preview, upload/inline, or add/remove. The schema lists only variants allowed by your credential. Site writes require expected_revision; public artifact edits appear immediately, while site edits change drafts. Picture selection is separate from site build preview.

{"target":{"type":"site","id":"01M..."},"options":{"path":"index.html","offset":1,"limit":80}}
Tool Scope Does
search pastes.read / sites.read Find your pastes by title, folder or document path / List sites
fetch pastes.read / sites.read Read a paste in full, or one document of it / Read site structure / Read which picture a paste shows where it is listed
markest_list_files pastes.read / sites.read List a paste's documents with their size in lines and bytes / Find files by glob, with sizes and hashes
markest_read_file pastes.read / sites.read Read a range of lines of one document, numbered / Read source file lines
markest_grep pastes.read / sites.read Search the text of documents across several pastes, like grep / Search source with numbered matches and context
markest_list_versions pastes.read / sites.read List a paste's saved versions and what each changed / List immutable preview builds
markest_diff_versions pastes.read / sites.read Compare two versions, or a version and now, as a diff / Compare builds and draft, including manifest changes
markest_create pastes.write / pastes.read + pastes.write / sites.read + sites.write Create a paste from one or more documents / Make an artifact from a template, filled with fields / Create a private site draft
markest_fork pastes.read + pastes.write / sites.read + sites.write Copy pastes you can read into your account, up to ten at once / Copy a full site or its reusable structure into a new draft
markest_write_file pastes.write / sites.read + sites.write Append a document to an existing paste / Replace or rename one document
markest_edit_file pastes.write / sites.read + sites.write Replace exact text in one document / Exact text edits with revision checks and dry run
markest_apply_patch pastes.write / sites.read + sites.write Change one or more documents with a unified diff / Atomic multi-file patches with dry run
markest_update pastes.write / sites.read + sites.write Update draft files and structure / Change title, folder, tags, expiry, password, burn-after-reading, version history, or move it to another space / Choose the picture a paste shows where it is listed
markest_add_images pastes.write Add image files from your disk to a paste - one, or a whole folder - with no base64 / Upload an image to a paste, for its documents to show
markest_update_collaborators pastes.write Let people open a private paste by their e-mail addresses / Stop people opening a paste as collaborators
markest_get_version pastes.read Read one saved version, and a document's text as it was
markest_list_templates pastes.read List the templates you can make an artifact from, with their fields
markest_restore_version pastes.write Put an earlier version back, as a new version
markest_delete_document pastes.write Remove one document
markest_set_visibility pastes.write Change who can see one or many pastes
markest_create_signed_link pastes.write Create an expiring link that opens a private paste
markest_list_collaborators pastes.read List who, besides you, may open a paste
markest_list_images pastes.read List a paste's images, with the markdown to show each
markest_get_image pastes.read Read one image of a paste
markest_delete_image pastes.write Delete an image uploaded to a paste
markest_list_comments pastes.read Read what readers said under your pastes, thread by thread
markest_reply_to_comments pastes.read + pastes.write Answer several comments at once, as yourself
markest_resolve_comments pastes.read + pastes.write Mark conversation threads resolved, or reopen them
markest_get_views pastes.read How many times your pastes were read, by day and document
markest_delete_paste pastes.write Delete a paste and everything in it
markest_list_workspaces pastes.read List your workspaces, and which of them this agent may reach
markest_request_workspace_access pastes.read Ask you, with a link, to let this agent into a workspace
markest_preview_site sites.read + sites.write Build a private ten-minute preview
markest_publish_site sites.read + sites.write + sites.publish Request browser approval for an immutable build
markest_validate_site sites.read Validate draft structure without creating a build

Compatibility aliases

The native names and examples below remain callable for existing integrations, but aliases are omitted from discovery. New clients should use the shared table above. Unsupported target/mode combinations are refused without changes. Site binary image uploads are not yet supported.

Tool Scope Does
search read Find your pastes by title, folder or document path
fetch read Read a paste in full, or one document of it
markest_list_documents read List a paste's documents with their size in lines and bytes
markest_read_document read Read a range of lines of one document, numbered
markest_grep read Search the text of documents across several pastes, like grep
markest_list_versions read List a paste's saved versions and what each changed
markest_get_version read Read one saved version, and a document's text as it was
markest_diff_versions read Compare two versions, or a version and now, as a diff
markest_create_paste write Create a paste from one or more documents
markest_list_templates read List the templates you can make an artifact from, with their fields
markest_create_from_template read, write Make an artifact from a template, filled with fields
markest_fork_paste read, write Copy pastes you can read into your account, up to ten at once
markest_add_document write Append a document to an existing paste
markest_add_images write Add image files from your disk to a paste - one, or a whole folder - with no base64
markest_upload_image write Upload an image to a paste, for its documents to show
markest_list_images read List a paste's images, with the markdown to show each
markest_get_image read Read one image of a paste
markest_delete_image write Delete an image uploaded to a paste
markest_get_preview read Read which picture a paste shows where it is listed
markest_set_preview write Choose the picture a paste shows where it is listed
markest_update_document write Replace or rename one document
markest_edit_document write Replace exact text in one document
markest_apply_patch write Change one or more documents with a unified diff
markest_restore_version write Put an earlier version back, as a new version
markest_delete_document write Remove one document
markest_update_paste write Change title, folder, tags, expiry, password, burn-after-reading, version history, or move it to another space
markest_set_visibility write Change who can see one or many pastes
markest_create_signed_link write Create an expiring link that opens a private paste
markest_list_collaborators read List who, besides you, may open a paste
markest_add_collaborators write Let people open a private paste by their e-mail addresses
markest_remove_collaborators write Stop people opening a paste as collaborators
markest_list_comments read Read what readers said under your pastes, thread by thread
markest_reply_to_comments read, write Answer several comments at once, as yourself
markest_resolve_comments read, write Mark conversation threads resolved, or reopen them
markest_get_views read How many times your pastes were read, by day and document
markest_delete_paste write Delete a paste and everything in it
markest_list_workspaces read List your workspaces, and which of them this agent may reach
markest_request_workspace_access read Ask you, with a link, to let this agent into a workspace
markest_list_sites sites.read List sites
markest_get_site sites.read Read site structure
markest_read_site_file sites.read Read source file lines
markest_create_site sites.read, sites.write Create a private site draft
markest_update_site sites.read, sites.write Update draft files and structure
markest_preview_site sites.read, sites.write Build a private ten-minute preview
markest_publish_site sites.read, sites.write, sites.publish Request browser approval for an immutable build
markest_list_site_files sites.read Find files by glob, with sizes and hashes
markest_grep_site sites.read Search source with numbered matches and context
markest_edit_site_file sites.read, sites.write Exact text edits with revision checks and dry run
markest_apply_site_patch sites.read, sites.write Atomic multi-file patches with dry run
markest_list_site_builds sites.read List immutable preview builds
markest_diff_site sites.read Compare builds and draft, including manifest changes
markest_validate_site sites.read Validate draft structure without creating a build
markest_fork_site sites.read, sites.write Copy a full site or its reusable structure into a new draft

search and fetch use the input and result shapes ChatGPT expects of a knowledge source, so Markest can be cited as one.

Tools that change state are annotated destructiveHint, which lets a client ask for confirmation before running them. Annotations are a hint to the client, not a substitute for the checks the server performs regardless.

Building a paste over several calls

This is the expected pattern rather than a workaround:

markest_create_paste  → { id: "01J…", documents: ["README.md"] }
markest_add_document  → { paste_id: "01J…", path: "docs/setup.md", … }
markest_add_document  → { paste_id: "01J…", path: "docs/api.md", … }

Working on part of a paste

The tools an agent uses on a repository work on a paste too, so a long document never has to travel whole:

markest_list_documents → { paste_id: "01J…" }
markest_grep           → { pattern: "TODO", pastes: ["01J…", "01K…"], context: 2 }
markest_read_document  → { paste_id: "01J…", path: "docs/setup.md", offset: 120, limit: 40 }
markest_edit_document  → { paste_id: "01J…", path: "docs/setup.md", edits: [{ old_text: "…", new_text: "…" }] }
markest_diff_versions  → { paste_id: "01J…", from: 3 }

Line numbers agree across markest_read_document, markest_grep and markest_diff_versions. An edit or a patch applies completely or not at all, and is saved as one version. A diff from markest_diff_versions can be edited and handed back to markest_apply_patch, which also takes the *** Begin Patch format. markest_grep searches up to 20 pastes by id or URL, or every paste you own, and pages its results like search.

Adding images

An agent adds image files from its disk to a paste's image store without writing them out as base64 in a tool call: it asks for an address, then sends the files there, a whole folder with one command.

markest_add_images    → { paste_id: "01J…" }
for f in shots/*; do curl -sT "$f" 'https://marke.st/api/v1/image-uploads/…/'; done
markest_edit_document → { paste_id: "01J…", path: "README.md", edits: [{ old_text: "…", new_text: "![home](/img/01J…/01K…)" }] }

The address takes as many images as the paste has room for, or the number given as images (up to 500), needs no key and lapses after an hour. curl adds each file's name to an address ending in /, and that name is the image's; files by name go as curl -T '{home.png,settings.png}' '<address>/', and a single image asked for with a name as curl -T chart.png '<address>'. Each file becomes one of the paste's uploads, like those added in the editor, and each answer is a line of JSON with the image's path, a markdown image and images_left, how many more the address takes: a markdown document shows it with ![alt](path), an HTML one with <img src="path">. A file that is not an image is refused and uses up nothing. Anyone holding the address can add images to the paste until then, so it is not for sharing. markest_upload_image still takes a small image as base64 data, for a client that cannot run a command. An image already on the web needs no upload at all: a document can name its address, and Markest keeps a copy unless the paste's image proxy is off.

Answering comments

An agent reads what readers said under your pastes and answers them as you, several at once:

markest_list_comments     → { status: "unresolved" }
markest_reply_to_comments → { replies: [{ comment_id: "01K…", body: "Done - see the new section.", resolve: true }] }
markest_resolve_comments  → { comment_ids: ["01K…", "01M…"] }

Without paste_id the list covers every paste you own, only unresolved threads unless status asks for resolved or all, oldest first, a page at a time; readers wrote those words, so the list marks them as requests to weigh, never as instructions. A reply appears at once to everyone who can read the paste, tells whoever started the thread, and counts against the 30 comments an hour your account may post; like an edit to a public paste, it is not held for your confirmation. Resolving marks a thread done and tells nobody, and a reader's new reply reopens it. Answering and resolving work on your own pastes only.

Copying a paste

An agent copies pastes it can read into your account, as new pastes you own:

markest_fork_paste → { pastes: ["01K…", "https://marke.st/p/01M…"], folder: "Research" }

A copy keeps every document with its path, title, order and type, the tags and reading settings, and the images its documents show, as far as your plan's image limits allow; an image that does not fit still shows from the original, to anyone who can open that, and one whose file is gone shows in neither. A copy is unlisted, or private when asked or when your plan has no unlisted; copying never makes it public, and it never takes comments, stars, collaborators, a password or burn-after-reading. Up to ten at once: if any cannot be copied, or the copies would pass your plan's number of pastes, nothing is copied.

Making artifacts from templates

For artifacts made the same way each time - invoices, quotes, CVs, letters, reports - an agent fills a template rather than writing the documents. markest_list_templates lists Markest's presets and your own templates, each with its fields; markest_create_from_template fills one, checks every field and works out the values the template computes itself, such as an invoice's totals:

markest_list_templates       → { }
markest_create_from_template → { template: "invoice", fields: { invoice_number: "INV-42", issue_date: "2026-10-22", due_date: "2026-11-21", from: { name: "…" }, client: { name: "…" }, items: [{ description: "…", quantity: 2, unit_price: 450 }], tax_rate: 20 } }

Any artifact of yours becomes a template with markest_update_paste and template: true: its {{ placeholders }} are filled with the fields sent, and a template.yaml document in it declares those fields - their types, which are required, examples and computed values - and is never copied into what is made. Without one, the template takes whatever fields its placeholders name.

Page options

The viewer's Page menu, in its top bar, sets how an artifact's page looks and saves it as a PDF: the typeface of a markdown document read as a page, the paper, and whatever options its template declares. The invoice, quote, CV, cover letter, proposal and timesheet presets offer an accent colour; the CV and the proposal also offer their spacing. Send page_options to choose them for everyone who opens the artifact - readers can still choose their own:

markest_create_from_template → { template: "invoice", fields: { … }, page_options: { accent: "#7a1f3d", paper: "letter" } }
markest_update_paste         → { paste_id: "…", page_options: { font: "plex" } }

A template declares its own under options in its template.yaml: a colour, a choice or a toggle, each with a name, a label, a default and what it offers. An HTML document reads each value as --option-<name> and data-option-<name> on its root element, and Save PDF prints it on the paper chosen:

options:
  - name: accent
    type: colour
    label: "Accent colour"
    default: "#0b5f70"
    choices: ["#0b5f70", "#7a1f3d", "#2e6b3f"]

Publishing needs your confirmation

Restricting a paste — to unlisted or private — happens immediately, in batches of up to 100. Making one public is the single change that cannot be walked back: once something has been read, copied or indexed, setting it private again retracts nothing.

So by default an agent cannot publish directly. markest_set_visibility returns a link instead, and so does markest_create_paste when asked for a public paste, which it creates unlisted in the meantime; nothing is public until you open the link and approve.

The confirmation screen covers every paste in the request at once, with a checkbox each — so an agent publishing thirty documents costs you one visit, not thirty, and you can approve a subset. The link works once and expires after 24 hours.

What you approve is what you saw: a paste that changes after the confirmation page opened is not published, and you are asked to review it again. Asking for the same change while a confirmation is pending returns the same link.

A well-behaved agent will hand you the link and stop. It should not retry.

Changing a paste that is already public is not gated: markest_update_document and markest_add_document publish the change as soon as it is saved, and their descriptions tell the agent so.

Turn the gate off under Account → Publishing if you would rather publish directly. Restricting a paste is never gated either way.

Workspaces need your approval

An agent does not reach your shared workspaces on its own. Until you let it into a workspace, it reads that workspace's pastes only as someone with no account would - public and unlisted ones - and search, markest_grep and markest_list_comments pass over them.

To reach one, the agent asks: markest_request_workspace_access names the workspace, and so does any tool that reaches for a paste in it. Either hands back a link for you to open in Markest, signed in, where you choose how long it may reach that workspace:

  • for 10, 30 or 60 minutes;
  • for this session - until the agent disconnects or restarts, or after a day unused;
  • until you revoke it.

It then acts with your role there. Each workspace is approved on its own, the link waits a day, and asking again while it waits gives the same link. markest_list_workspaces lists your workspaces and what this agent may reach in each.

Once let in, an agent can also work in one workspace on purpose. search and markest_grep take a workspace - its id or name, or personal for your own space - and say which workspace each paste they find is in. markest_create_paste creates a paste in that workspace, and markest_update_paste moves a paste between your own space and your workspaces. A paste made in a workspace belongs to the workspace and counts against the plan that pays for it; making one there takes your editor or owner role, and moving one out takes your owner role in the workspace it leaves.

Account → API keys lists what each agent may reach, with Revoke. Leaving a workspace ends what your agents were let into there, and disconnecting your applications ends theirs. A key made for a workspace itself needs no approval for that workspace.

A session is the connection an agent makes when it starts. Markest names it in the Mcp-Session-Id header of its answer to initialize, and the agent sends it back with every request; a DELETE to the endpoint with that header ends it. A request naming a session that ended is answered 404, and the agent starts a new one.

What an agent can and cannot do

Every tool runs as the owner of the credential presented, and re-checks that credential's permissions on each call:

  • A key without create_paste sees no write tools and cannot call them.
  • A read-only OAuth grant (pastes.read) likewise cannot write.
  • Tools a credential cannot use are omitted from tools/list entirely.
  • Asking for a paste that is not yours returns the same answer as one that does not exist, so ids cannot be probed.
  • Plan quotas — paste count, documents per paste, visibility, expiry — apply exactly as they do on the web.
  • A paste's version history is readable by its owner only, even when the paste is public.
  • markest_restore_version puts an earlier version back as a new version: history is never rewritten, and who can see the paste does not change.
  • markest_create_signed_link issues links for private pastes only, lasting from an hour to 90 days. A link opens the whole paste until it expires; Revoke all signed links in Markest stops every link to a paste.
  • markest_add_collaborators lets people open a private paste by signing in to Markest with a verified account under the address given. Each address is added once however it is written or repeated, your own is left out, and a call with any bad address, or one that would pass your plan's collaborator limit, changes nothing. Markest sends no invitation, and no answer says whether an address has an account.
  • markest_reply_to_comments and markest_resolve_comments act only under your own pastes and need a credential that may read as well as write, so a key made only to create pastes cannot answer anyone. A batch with any comment they cannot act on changes nothing.
  • markest_fork_paste copies only what the credential can read, and needs a credential that may read as well as write. A private paste opened through a signed link can be read but not copied, and one behind someone else's password or that burns after reading is not copied at all.
  • fetch reads a private paste from a signed link until the link expires. A password-protected or burn-after-reading paste still opens only in a browser.
  • In a workspace, a credential acts with its account's role there once its agent is let in (see above): every member's agent reads the workspace's pastes, private ones included; an editor's also changes them and reads their history; only an owner's changes who may read one - its password, expiry, burning after reading, visibility, signed links and collaborators - or deletes it. A key made for a workspace itself reaches that workspace alone, and is shown only the tools its role there allows: it never publishes, deletes, shares, copies a paste elsewhere or answers comments.
  • /mcp shares the API rate-limit bucket.

Document bodies over 100 KB are truncated in fetch results with a link to the full raw document, so one large file cannot exhaust an agent's context.

Disconnecting

Account → API keys → Connected applications disconnects every OAuth application at once. Every access and refresh token issued before that moment stops working immediately; an application that wants back in has to be authorised again. API keys are revoked individually on the same screen.

OAuth details

For anyone implementing a client rather than using one.

Document Purpose
/.well-known/oauth-protected-resource Names this resource and its authorization server (RFC 9728)
/.well-known/oauth-authorization-server Endpoints, scopes and PKCE support (RFC 8414)

Neither is rate-limited, and both are readable without credentials.

Scope Grants
pastes.read Read your pastes and the documents in them
pastes.write Create, change and delete your pastes

Scopes are declared per tool via securitySchemes, so a client knows which tools need a linked account before calling one.

  • Authorization code with PKCE, S256 only — plain is neither advertised nor accepted.
  • Clients identify themselves by Client ID Metadata Document: the client_id is an HTTPS URL Markest fetches and checks, and the requested redirect_uri must appear in it.
  • A client that cannot publish a document of its own can use one Markest publishes for it. For mcp-remote, pass --client-metadata-url https://marke.st/.well-known/oauth-client-metadata/mcp-remote.json and the port 3334, the one its document lists (http://localhost:3334/oauth/callback). As for any app on your own computer, a sign-in waiting on another local port is accepted too, at that address and path only.
  • iss is returned on every authorization response, success or error (RFC 9207).
  • The authorization request must carry resource naming this endpoint; any other value is refused with invalid_target.
  • Access tokens are signed JWTs carrying the resource as their audience, valid one hour, verified for signature, issuer, audience and expiry on every request.
  • Refresh tokens last 30 days and rotate on each use. A refresh token presented again after its replacement has been used, or more than five minutes after it was replaced, ends the connection: two parties hold the same grant, and the application must be authorised again.
  • Authorization codes are single-use and expire in five minutes; redeeming one twice ends the connection it produced.

Tokens are only ever issued after a signed-in person approves the request on Markest's consent screen. There is no client-credentials or machine-to-machine grant: every token belongs to someone.

ChatGPT specifics

A ChatGPT plugin is an MCP server — there is no separate manifest or OpenAPI document to install. Point ChatGPT at the endpoint and it discovers the rest.

If you change plans or Markest adds tools, refresh the connector: the tool list is captured when you install it, so a new conversation alone will not pick up new tools.

Encrypted artifacts: the local server

An artifact encrypted end to end is encrypted in the browser, or on your own machine, and its key never reaches Markest. This endpoint runs on Markest's servers, so it cannot open one.

The markest command includes a small MCP server that runs on your machine and offers only the tools for encrypted artifacts: markest_sealed_create, markest_sealed_read, markest_sealed_write, markest_sealed_remove_documents, markest_sealed_link and markest_sealed_keys. It encrypts and decrypts there, with keys your machine keeps. Add it beside this endpoint; in Claude Code, once you have run markest login:

claude mcp add markest-sealed -- markest mcp

What an agent reads or writes through these tools passes through its conversation, so the company that runs the agent's model sees it. Markest still never does.

See also

  • Command line — the markest command, and its local MCP server for encrypted artifacts.
  • API reference — the REST endpoints, for scripts rather than agents.
  • Account → API keys — create a key, and disconnect connected applications.
  • Account → Publishing — the confirmation gate for making pastes public.

Artifact and Sites permissions are independent for OAuth connections and API keys. If an older client requests only artifact access, choose “Include Sites permissions” on the authorization screen to open an explicit new request, then select only the permissions you want. Sites remains limited by the account package. A Sites-only agent can list workspaces and request access, but must wait for the account holder’s workspace approval; it receives no artifact permissions. Publication still needs browser approval.

OAuth tool discovery describes all supported artifact and Sites variants consistently, even before a particular permission is granted. Every invocation still checks the actual credential scopes, package, workspace approval and resource rights. Missing OAuth scopes return a standard authorization challenge. API-key discovery remains filtered by the key’s explicit permissions. After changing an older connection, refresh the plugin’s tools in the client to replace its cached executable schemas; reconnecting alone may not refresh them.