Blogmaker
Write and publish blog content, manage design and settings, and read analytics in Blogmaker.
Servidor MCP hospedado
npx add-mcp 'https://editor.blogmaker.app/api/mcp'Instala no Claude Code, Codex, Cursor e outros
Documentação
Blogmaker's MCP server lets an assistant read your blog, work on drafts, upload featured images, publish posts and pages, and report on traffic analytics. It uses the same content and permissions as API v2. Connect with OAuth to choose a blog and approve access without sharing your API key.
Connect your blog
- In an assistant or MCP client that supports remote HTTP servers and OAuth, add the Blogmaker server URL below. Choose Streamable HTTP if the client asks for a transport.
- Start the connection and sign in to Blogmaker. Your normal two-step verification applies.
- Choose a blog you own. The picker uses the dashboard's blog name, configured public URL, and icon, including a custom domain or subdirectory.
- Review the app's callback address and requested permissions, then choose Connect app.
https://editor.blogmaker.app/api/mcp
Choose an assistant, then review the requested permissions and approve the connection. You can also add the server URL manually in another compatible MCP client.
You can also copy the URL from Settings > APIs. One connection grants access to one blog. To connect another blog, authorize it separately. Invited authors cannot authorize an owner's blog.
Start with a writing prompt: “Write a 600-word blog post about starting an herb garden on a small balcony. Include sections on choosing herbs, pots, sunlight, and watering, plus a beginner's checklist. Save it as a draft in my connected Blogmaker blog.”
The assistant writes the article and uses create_content to save it. Review the draft in Blogmaker, then ask the assistant to publish it when it is ready.
Moving from another platform? Follow Import your existing blog with MCP for a workflow with copyable prompts, sample drafts, image uploads, and migration checks.
Permissions and plan access
| Permission | What it allows |
|---|---|
mcp:read | Read blog metadata and public content. Read editor drafts and analytics when the blog's plan allows them. |
mcp:write | Create and edit drafts, create categories and tags, and upload images. |
mcp:publish | Publish or unpublish posts and pages. |
The default connection requests all three permissions. Clients can request less, such as mcp:read. The consent page shows what is requested; the available tools reflect the granted scopes.
Draft access, editing, publishing, image uploads, and analytics require the Advanced plan. Analytics also requires active analytics access. Eligible blogs on lower plans can connect with read-only access to public content; the consent page marks that restriction. Connecting an assistant does not change your plan or bypass editing restrictions.
Creating or editing a draft does not update the public article. Ask explicitly when you want the assistant to publish or unpublish. Public-content tools exclude hidden, scheduled, subscriber-only, and other-blog content.
Configure your blog
Ask: “Set my blog title to Notes from the Studio, use America/Chicago as its timezone, and change the banner headline to Welcome.” For a favicon, attach an image and ask the assistant to upload it and use it as your blog's favicon.
The assistant reads get_blog_settings, then calls update_blog_settings with the returned revision and only the settings to change. It can configure the blog name, public title and description, timezone, favicon, logo, header/footer HTML and navigation links, footer visibility, and banner text/image. See the settings field reference.
Settings changes are live immediately and need both edit and publish permissions on the Advanced plan. They preserve unrelated Design Studio drafts. If another edit changes the revision, read the latest settings before retrying.
Design Studio
get_design reads up to 20 controls at a time so responses remain readable in assistants. Use query to find a Design Studio area or label, or keys to request exact controls. Follow settings_page.next_offset with the same filters and revision for more. Values omitted from a page are not unset. Custom CSS is available separately with section: "custom_css", in 1,000-character chunks; read all chunks before replacing it.
Ask: “Make my blog cards more spacious, use three columns on desktop and one on mobile, and leave the design as a draft.” The assistant reads get_design for current draft and published values, supported controls, and a revision, then calls update_design. Native controls cover colors, typography, spacing, card layouts, and mobile layouts. Custom CSS can also be replaced or cleared when requested.
Design tools require the Advanced plan. Saving needs edit permission and does not change your public blog. Ask explicitly to publish: publish_design needs publish permission and makes all supported native controls and custom CSS in the current draft live, including native edits saved in Design Studio. It preserves other pending changes, including legacy font/color palettes, branding, and page-specific overrides. Theme switches must be published in Design Studio first.
Use changes as a list of {"key":"post_list_columns","value":"3"} objects. Values are strings, including numbers; get_design.supported_settings lists accepted keys, ranges, colors, and choices. Use reset: ["post_list_columns"] to restore inheritance. Omitted controls are preserved. custom_css replaces the full CSS draft (up to 60,000 UTF-8 bytes); an empty string clears it. Every edit or publish requires the latest exact revision. If the design changes elsewhere, read it again and review before retrying. These Design Studio operations are available through MCP only. On themes older than the native presets theme_has_native_defaults is false: nothing is inherited, so effective_settings lists only the values that blog has set.
For phone or tablet changes, first inspect draft.devices and published.devices: each includes explicit settings, resolved effective_settings, and its max_width in CSS pixels (phone: 640; tablet: 1024). Phone overrides tablet, and tablet overrides all-device values. Older mobile_* controls may still be stored; supported_settings identifies their device_replacement. These older controls are marked reset_only: you can reset their saved values, but new edits must use the replacement.
For example, use changes: [{"key":"blog_name_size","value":"20","device":"phone"}] to change only the phone title size, or reset: [{"key":"blog_name_size","device":"phone"}] to restore its inherited value. Omit device for all devices; existing device overrides remain in place. Only controls marked device_overridable: true accept a device. Shared wording and controls that change page markup apply to all devices. Device changes remain drafts until publish_design.
Preserve publication dates when importing
When publishing an imported draft, pass publication_date to publish_content, for example 2020-01-01T12:34. The date uses the blog timezone returned by get_blog. Past dates publish immediately with that date; future dates schedule publication. Dates must represent a time from January 1, 1970 through January 19, 2038 (UTC). Omit the field to preserve an existing date or schedule, or send an empty string to publish now. Read the latest draft revision first. In the editor, uncheck Automatically update to the current time on publish to enable the Publication date field. Choosing a past date asks for confirmation before publishing.
Manage redirects
Use list_redirects or get_redirect to inspect existing permanent redirects. Ask the assistant to create an approved old-to-new URL mapping with create_redirect, change one with update_redirect, or remove one with delete_redirect. These changes affect the live site immediately and need both edit and publish permissions on the Advanced plan.
Use from for the old path, such as 2020/old-article.html, and to for the full HTTP or HTTPS destination URL. Reads return a revision required for updates and deletion. Duplicate sources, reserved paths, and redirect loops on your blog are rejected. See the redirect reference for fields and limits.
Available tools
Use posts or pages for content kind. Editor tools use an opaque id returned by a list or creation; published tools use the public slug. List tools accept limit (1–100) and cursor where shown. Continue with the returned next_cursor until it is null.
| Tool | Inputs | Permission and purpose |
|---|---|---|
list_redirects / get_redirect | Optional limit / cursor for list; id for get | Read: permanent redirects and revisions (Advanced). |
create_redirect | from, to | Edit + publish: create a live 301 redirect. |
update_redirect | id, revision, from and/or to | Edit + publish: change a live redirect. |
delete_redirect | id, revision | Edit + publish: remove a live redirect. |
get_blog_settings | None | Read settings and their revision (Advanced). |
get_design | None | Read: draft and published native Design Studio values, supported controls, and revision (Advanced). |
update_design | revision; at least one of changes, reset, custom_css | Write: save a native design draft without publishing. |
publish_design | revision | Publish: make the current native settings and custom CSS live; preserve other Studio drafts. |
update_blog_settings | revision, settings | Edit + publish: change live settings (Advanced). |
get_blog | None | Read: details of the connected blog. |
list_published | kind; optional limit, cursor | Read: publicly visible post or page summaries. |
get_published | kind, slug | Read: a public snapshot with its stored rendered HTML. |
render_published | kind, slug | Read: an HTML fragment with current reusable content and metadata for your own website. |
search | query | Read: search public post and page titles and descriptions. |
fetch | id from search | Read: fetch a public document and its citation URL. Search IDs have the form posts/slug or pages/slug. |
list_content | kind; optional status, limit, cursor | Read: editor summaries; status can be draft or published. |
get_content | kind, id | Read: full editor content, native elements, relations, and the current revision. |
create_content | kind, content; optional idempotency_key | Write: create a draft. content.publish: true also requires publish permission. |
update_content | kind, id, revision, content | Write: update a draft using its exact current revision. |
upload_asset | Exactly one of file or source_url | Write: upload an image and return its Blogmaker URL. |
publish_content | kind, id, revision; optional publication_date, idempotency_key | Publish: make the current draft public. |
unpublish_content | kind, id, revision | Publish: remove the public snapshot and retain the editor draft. |
list_taxonomy | kind (categories or tags); optional limit, cursor | Read: available categories or tags. |
create_taxonomy | kind, name, slug; optional description | Write: create a category or tag. |
list_authors | Optional limit, cursor | Read: confirmed visible authors for assigning content. |
get_analytics | Optional range, timezone, filters | Read: traffic totals, comparisons, trends, pages, sources, devices, locations, and interactions. |
get_current_visitors | Optional filters | Read: visitors active within the last five minutes. |
The content object uses the API v2 content fields, including title, html or ordered elements, featured_image_url, categories, tags, and authors. Use IDs or slugs returned by the corresponding list tools for relations.
For post slugs, you can supply a bare slug or the blog’s configured article path, such as food/roasted-tomatoes or /food/roasted-tomatoes. One leading slash is removed and the article prefix is applied once. Other nested paths, full URLs, and unsafe URL syntax are rejected. Publication checks the final URL for conflicts. Use the returned full slug for published reads, and pass search result IDs unchanged to fetch.
Create, edit, and publish
For a new article, ask: “Create a Blogmaker draft called A photo story with this text. Leave it as a draft for review.” The assistant uses create_content. This example is a complete MCP tool-call request:
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "create_content",
"arguments": {
"kind": "posts",
"content": {
"title": "A photo story",
"html": "<h2>Our story</h2><p>An introduction.</p>"
}
}
}
}
To edit an existing article, the assistant first calls get_content, then passes its exact quoted revision to update_content. Use the new revision returned by the update for publish_content. A 412 revision_conflict means someone changed the article: read it again and review the changes before retrying.
If an update includes elements, it replaces the complete ordered content array. Preserve every element and gallery image you want to keep, including their existing IDs. Omit elements when changing only fields such as the title or featured image. See the content editing workflow.
Reuse an idempotency_key when retrying the same creation or publication. Setting content.publish: true creates and publishes together; a publication failure can return a saved draft with publish_error, which the assistant should report.
Upload and set a featured image
Attach an image and ask: “Upload this image to my connected Blogmaker blog and set it as the featured image of A photo story, with descriptive alt text. Leave the edit unpublished.” For a live update, also ask the assistant to republish the article.
- Find the article with
list_contentand read it withget_content. - Call
upload_assetwith the attachedfile, or a direct public HTTPS image insource_url. - Pass the returned
urlascontent.featured_image_urltoupdate_content, with the current revision. Addfeatured_image_altand an optionalfeatured_image_caption. - When publication is requested, call
publish_contentwith the revision returned by the update.
The featured image must be uploaded to that same blog first. An external image URL cannot be assigned directly, and uploading alone does not change or publish an article. To clear a featured image through MCP, set content.featured_image_url to an empty string.
Image uploads accept JPEG, PNG, GIF, and WebP up to 10 MB, 32 megapixels, and 8000 pixels in either dimension. The assistant supplies an attachment's temporary download URL and file ID; those values must come from the client. Expired attachment links need to be refreshed. Other clients can use a direct URL, as shown below; it must return the image without a redirect.
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "upload_asset",
"arguments": {
"source_url": "https://example.com/photo.webp"
}
}
}
MCP uploads images. To upload MP4 or WebM videos, use the REST video upload endpoint, then use its URL in a native video element's settings.url.
Read analytics
Ask: “Show the last seven days of Blogmaker traffic in America/Chicago, compare it with the previous period, and list the top pages.” Use get_analytics with a string range such as "7" and an IANA timezone. Defaults are 30 calendar days, including today, in UTC; yesterday selects the preceding local day.
For one article, use filters.path with its tracked page path. Filters use exact matches and are combined with AND. MCP uses a filters object; REST uses filter[dimension] query parameters. The analytics reference lists ranges, dimensions, and response fields.
{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "get_analytics",
"arguments": {
"range": "7",
"timezone": "America/Chicago",
"filters": {"path": "/a-photo-story"}
}
}
}
Ask “How many visitors are active on my blog right now?” to use get_current_visitors. It accepts the same filters and counts activity in the last 300 seconds.
Reports contain aggregate metrics. Visitor IDs rotate daily, so a returning person counts again on another day. Filtered reports exclude imported historical aggregates. A 503 analytics_unavailable error means the data source is unavailable, rather than zero traffic.
Render a post or page for your website
Use render_published when your website provides the header, footer, and theme. The result contains a published HTML body fragment with current reusable content and footnotes, plus separate summary, table of contents, featured image, public URL, and SEO metadata.
{
"jsonrpc": "2.0",
"id": 4,
"method": "tools/call",
"params": {
"name": "render_published",
"arguments": {"kind": "posts", "slug": "a-photo-story"}
}
}
Replace posts with pages for a page. Your integration places the title and cover image and supplies CSS and interaction handlers. Rendering reads the public snapshot; it does not publish draft edits. For an ongoing website integration, fetch the REST rendering endpoint from your server or build process and keep your API key there.
Manage or troubleshoot a connection
Open Settings > APIs > Connected apps to see and disconnect an app. Disconnection revokes access immediately. Each authorization has its own connection; disconnect every grant you want to revoke.
| Issue | What to do |
|---|---|
| Upload, analytics, rendering, or Design Studio tool is missing | Refresh the client's tool list or reconnect Blogmaker. Older client catalogs can omit newer tools. Draft design edits and uploads need edit permission; publishing a design needs publish permission. |
| Permission or plan error | Check the granted scopes and blog plan. Reconnect to request additional scopes; a new connection does not unlock an ineligible plan. |
Invalid or expired token (401) | Let the client refresh its OAuth token or sign in again. A revoked connection must be authorized again. |
Content not found (404) | Check the connected blog and use an editor ID for draft tools or a public slug for published tools. Published tools require publicly visible content. |
Stale revision (412) | Read get_content again and review the current draft before applying the edit. |
Rate limit (429) | Wait for the returned Retry-After interval. Tool calls use API v2's 120-request-per-minute limit. |
Changing ownership, disabling the blog or its API access, or disabling the account prevents further use of existing OAuth grants. A client must support the remote HTTP transport and OAuth flow to use the sign-in connection.
For developers
The endpoint accepts authenticated JSON-RPC POST requests and returns JSON. Initialize the connection and use tools/list for current input schemas, then tools/call for a tool. The supported protocol versions are 2025-11-25, 2025-06-18, and 2025-03-26. It does not provide an SSE stream, session IDs, or batch requests; opening the endpoint in a browser with GET returns 405.
OAuth clients discover protected-resource metadata and authorization-server metadata. Authorization uses the code flow with S256 PKCE, supports dynamic registration and HTTPS client metadata documents, and refreshes access tokens. Use the exact server URL as the resource. Your OAuth client handles tokens.
A private integration without OAuth can send an existing blog API key in the Bearer header. OAuth access tokens work on MCP; REST API requests require the blog's API key. This example calls get_blog with a key kept in an environment variable:
curl https://editor.blogmaker.app/api/mcp \
-H "Authorization: Bearer $BLOGMAKER_API_KEY" \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"get_blog","arguments":{}}}'
Tool results include JSON text and structuredContent. API failures are tool results with isError: true, the API error, and its status; check that flag even when the HTTP response is 200. Invalid tool arguments produce a JSON-RPC error. Consult the API v2 reference for shared content fields, limits, and errors.