Introduction
plym ships an MCP server that gives an AI client read and write access to your blog.
Updated Aug 04, 2026
On this page
The plym MCP server runs as a second container built from the same plym image and reaches the api over the internal network. It exposes six tools — create a post, upload an image, list posts, list users, fetch a URL, convert HTML to markdown — over streamable HTTP at /mcp. Unlike the REST API, there is no key to issue: every tool call authenticates with a plym account email and password.
Enable the server
Run this in your blog directory:
plym enable mcp
The endpoint becomes https://blog.flapico.com/mcp, served through the reverse proxy your blog already uses. No extra domain and no extra certificate are needed. If the blog is not on a domain yet, the endpoint is http://localhost:9173/mcp against the blog's own port.
A separate hostname
Use the default above for most setups. Give MCP its own hostname when you want it off the blog's domain, and name the proxy plym should configure:
plym enable mcp mcp.flapico.com --caddy
The accepted proxies are --nginx, --caddy, and --traefik. --nginx and --caddy need sudo to write the site config; --traefik writes docker-compose.mcp-traefik.yml for you to finish and needs no sudo.
What enabling changes
Key in .env |
Value |
|---|---|
COMPOSE_PROFILES |
gains mcp |
PLYM_MCP_PUBLISH_PORT |
the first free port from 9369 up |
PLYM_MCP_PUBLIC_URL |
written only when you pass a hostname |
PLYM_MCP_PROXY |
written only when you pass a hostname |
The published port is bound to 127.0.0.1, so the container is reachable from the machine and through the proxy, never directly from the internet. While the profile is on, plym reload and plym rebuild restart the MCP container along with the api.
The endpoint path
/mcp sits at the domain root even when the blog is served under a prefix. With a blog_prefix of /blog, the blog is at https://flapico.com/blog and MCP is at https://flapico.com/mcp. A request to https://flapico.com/blog/mcp returns 405.
Authentication
Every request carries two headers:
| Header | Value |
|---|---|
X-User-Identity |
The email address of a plym account |
X-Mcp-Token |
That account's password |
X-Mcp-Token holds the account password. Despite the name, plym issues no MCP-specific credential. The server trades the pair for a short-lived access token by calling the login endpoint on every tool call, which costs one extra round trip per call.
What these credentials cannot do
There is no expiry, no revocation list, and no per-tool scoping. To rotate, change the account password in the admin — every configured client then fails until you update it. A client holding an administrator account can do through the tools everything that account can do.
Connecting is unauthenticated
initialize and tools/list succeed with no credentials at all; only tool calls check them. Anyone who can reach /mcp can read the tool list. Put the endpoint behind the same network controls you would put in front of the admin.
Roles
Tools that touch content need an account with the editor or administrator role. A reader account can call list_users, get_from_url, and md_from_html, and nothing else. The per-tool table is in Features.
HTTP is the only usable transport
Credentials arrive as HTTP headers, so the server needs an HTTP transport to read them. Setting PLYM_MCP_TRANSPORT=stdio starts a stdio server that answers initialize and tools/list, but every tool call fails with Missing credentials: set the X-User-Identity and X-Mcp-Token headers. A client that speaks only stdio needs a bridge — see Client setup.
Disable the server
plym disable mcp
This stops the container, removes the proxy config plym wrote, drops mcp from COMPOSE_PROFILES, and clears PLYM_MCP_PUBLIC_URL and PLYM_MCP_PROXY. PLYM_MCP_PUBLISH_PORT stays, so re-enabling reuses the same port.