plym Docs
    plym.io

    Features

    A complete list of features that plym MCP server exposes.

    Updated Aug 04, 2026

    On this page

    The plym MCP server exposes six tools. This page lists each one's parameters, return fields, required role, and errors.

    All six are write-once or read-only. There is no tool to update, delete, publish, or unpublish anything — a post created through MCP lands as a draft and a person finishes it in the admin. Set up the connection first in Client setup.

    Tools

    Tool Minimum role Result
    create_post editor Creates a draft post
    upload_media editor Uploads an image, returns its URL
    list_posts editor Lists every post, drafts included
    list_users reader Lists every account with email and role
    get_from_url reader Returns the raw HTML at a URL
    md_from_html reader Converts an HTML string to markdown

    plym has three roles: reader, editor, and administrator. administrator satisfies every row above.

    create_post

    Takes a single post object. Creates the post with status draft — there is no parameter to publish it.

    Field Type Default Description
    title string, 1–240 chars required Post title
    slug string, 1–240 chars required Must match ^[a-z0-9]+(?:-[a-z0-9]+)*$, and must be unique across every post and category on the instance
    content string "" Markdown body
    excerpt string or null null Summary used in listings and meta description
    cover string or null null Image URL; pass the url returned by upload_media
    canonical_url string, max 2048 null Must match ^https?://.+
    weight integer or null null Manual ordering value
    category_id integer or null null Existing category id; null leaves the post uncategorised
    tags array of strings [] Tag names, created if they do not exist
    faqs array of integers [] Existing FAQ ids

    No tool returns category or FAQ ids. Read them from GET /api/categories and GET /api/faqs, or from the admin, before calling this tool.

    The return value carries every field of the created post plus id, path, status, reading_time, author, category, tags, created_at, and updated_at. path is <category-slug>/<slug>, or just <slug> when uncategorised.

    {
      "id": 17,
      "slug": "static-rendering-benchmarks",
      "path": "engineering/static-rendering-benchmarks",
      "title": "Static rendering benchmarks",
      "status": "draft",
      "reading_time": 4,
      "weight": null,
      "published_at": null,
      "rendered_path": null,
      "author": { "id": 3, "display_name": "Ada Okonjo", "avatar_url": null, "links": [] },
      "category": { "id": 2, "name": "Engineering", "slug": "engineering", "weight": 10 },
      "tags": [{ "id": 41, "name": "performance", "slug": "performance" }],
      "faqs": []
    }

    upload_media

    Pass url for an image plym should fetch, or data for base64-encoded file bytes. Passing both is an error, as is passing neither.

    Parameter Type Default Description
    url string or null null Publicly reachable image URL
    data base64 string or null null File bytes
    filename string or null null Name for a data upload; falls back to upload

    plym re-encodes every upload to WebP at quality 82 and stores it under a generated UUID filename. The original format and filename are not kept as the served file. The size limit is 10 MB by default, set by PLYM_UPLOAD_MAX_BYTES.

    {
      "id": 12,
      "filename": "702e159035704dcd952792bd91ef31ee.webp",
      "original_name": "benchmark-chart.png",
      "mime_type": "image/webp",
      "size_bytes": 48210,
      "width": 1600,
      "height": 900,
      "url": "/blog/media/702e159035704dcd952792bd91ef31ee.webp",
      "uploader_id": 3
    }

    Base64 of a real image runs to megabytes of tokens. Prefer url, or have the client shell out to a script that reads the file and makes the call.

    list_posts

    Takes no parameters. Returns every post on the instance in every status — draft, published, and archived — paging through the API 200 at a time until it has them all. There is no filter, search, or limit parameter.

    Each item has id, slug, path, title, status, reading_time, excerpt, cover, canonical_url, weight, published_at, author, category, tags, created_at, and updated_at. Post bodies are not included; there is no tool that returns the content of an existing post.

    This tool requires editor because it always asks for drafts.

    list_users

    Takes no parameters. Returns every account with id, email, role, is_active, display_name, bio, avatar_url, links, created_at, and updated_at.

    Any signed-in account can call this, including a reader. Every client you connect can read every user's email address and role.

    get_from_url

    Takes url and returns the response body as text, untouched and untruncated. Redirects are followed and the request times out after 30 seconds.

    The fetch runs from inside the MCP container, not from your client. It can therefore reach private addresses and other containers on your Docker network that the client cannot — including your own api on http://api:8000. Treat the tool as an unrestricted server-side fetcher when deciding who gets an account.

    md_from_html

    Takes html and returns markdown, with leading and trailing whitespace stripped. The conversion is local; no network request is made and nothing on your instance is touched.

    Input:  <h1>Benchmarks</h1><p>Rendered in <b>1.2s</b></p>
    Output: Benchmarks
            ==========
    
            Rendered in **1.2s**

    Errors

    A failed call returns isError: true with the message as text content.

    Message Cause Action
    Missing credentials: set the X-User-Identity and X-Mcp-Token headers. One or both headers absent Add both headers to the client config
    X-User-Identity is not a valid email address. The header value is not an email address Send the account's email address
    Authentication failed: check your email and password. plym rejected the pair Fix the password; X-Mcp-Token takes the account password
    This account is not allowed to list this resource. list_posts or list_users refused Give the account the editor role
    This account cannot create posts (editor role required). create_post refused Give the account the editor role
    This account cannot upload media (editor role required). upload_media refused Give the account the editor role
    Pass eitherurlordata, not both. Both image inputs given Send one
    Passurlfor a remote image, ordatawith base64-encoded file bytes. Neither image input given Send one
    Unsupported image format: the bytes are not a readable image. plym could not decode the upload Convert to PNG, JPEG, or WebP first
    File is too large for this plym instance's upload limit. Upload over PLYM_UPLOAD_MAX_BYTES Shrink the image or raise the limit
    Client error '409 Conflict' for url '.../api/posts' The slug is taken by a post or a category Choose another slug
    Client error '404 Not Found' for url '.../api/posts' category_id does not exist Read the real ids from GET /api/categories
    String should match pattern '^[a-z0-9]+(?:-[a-z0-9]+)*$' Slug rejected before the request left the client Use lowercase words joined by single hyphens

    The two Client error rows are raw HTTP failures passed through with the status code and no plym-specific wording.

    Not available

    • Updating, deleting, publishing, unpublishing, or re-rendering a post.
    • Reading the body of an existing post.
    • Creating or listing categories, tags, FAQs, or users.
    • Reading or writing instance config.
    • Listing or deleting uploaded media.

    Use the REST API or the admin for all of the above.