PendiumDocs

Edit and refine posts

Find a brand's blog posts and revise their title, body, slug, generated text, or hero image.

Once a workflow has produced posts — or you've drafted them another way — these tools list the brand's blog posts and revise them: title, body, URL slug, a full text regeneration, or a new hero image.

When to use

Use these tools to iterate on existing blog posts before or after publishing. Start with list_blog_posts to find a postId, then get_blog_post to read the current body, then apply the edit you need. Reading, title/body/slug edits, and setting an external hero image are synchronous and free; regenerating text or generating an image is async and consumes credits.

Editing a published post's text or image is a two-step consideration: update_blog_post edits the title, body, and/or slug in place and preserves published status, but regenerate_blog_post and generate_blog_post_image reject published posts (they reset the post to a draft). To rewrite a live post, move_blog_post_to_draft → regenerate → publish_blog_post.

Blog-only over MCP (MEE-1995): every tool here operates on blog posts only. A social-post postId is rejected — social posts are managed in the Pendium app, not over MCP.

Typical sequence

  1. list_blog_posts — find the postId to iterate on.
  2. update_blog_post — quick in-place fixes to the title, body, and/or slug, or
  3. regenerate_blog_post — rewrite the body from the stored outline, and/or generate_blog_post_image — refresh the hero image.
  4. Re-list to confirm the changes landed, then publish.

Tools

list_blog_posts

List a brand's blog posts for an agent. This is the discovery tool: use it to find a postId before editing, regenerating, or publishing.

Deprecated alias: list_posts is still accepted but list_blog_posts is the canonical name.

Authentication: Required

ParameterTypeRequiredDescription
syntheticIdnumberYesThe agent ID whose posts to list. Use get_account to find your agent IDs.
limitnumberNoMax posts to return, newest first. Default 25, max 50. The response includes totalCount so you can tell when there are more.

Returns up to limit blog posts, newest first, plus count (returned) and totalCount (all blog posts for the agent). Each post includes postId, title, slug, postUrl (nullable), platform (always blog), status, generationStatus, mediaId (nullable), mediaUrl (nullable), views (lifetime), and a linked workflow (id + name, nullable).

postUrl is the live, canonical public URL to share — it honors a verified custom domain, proxy hosting, or the default agent-site host, so always use it rather than assembling a URL yourself. It is populated only when the post is actually publicly reachable (published, fully generated, not a synced copy, on a public site that isn't feed-hidden); a draft, scheduled, private, or feed-hidden post keeps its slug but returns postUrl: null. mediaUrl is a directly-fetchable link: stock-library and uploaded images are returned as-is; AI-generated media stored privately is a short-lived signed URL that expires after about an hour (re-list to refresh). It's null only when a post has no media yet or its media isn't ready.

Blog-only over MCP (MEE-1995): returns the brand's blog posts only. Social posts are managed in the Pendium app, not over MCP.

get_blog_post

Read one blog post's full body and metadata. list_blog_posts returns metadata only; this is the read-body companion — use it to pull the actual content for reading, summarizing, or proposing edits.

Authentication: Required. Available on any plan.

ParameterTypeRequiredDescription
syntheticIdnumberYesThe agent the post belongs to.
postIdstringYesThe post to read. From list_blog_posts.

Synchronous, no LLM call, no credit cost. Returns the post's title, slug, status, generationStatus, description, mediaUrl, mediaSource, timestamps, and body — the body is plain markdown, the same string the public blog renders and that update_blog_post writes to. If neither the edited body nor a generated outline exists yet, body is null and the post is still pre-generation. mediaUrl is a directly-fetchable hero image link resolved the same way as list_blog_posts (stock/uploaded heroes as-is, AI-generated media as a short-lived signed URL), null when the post has no ready media.

Blog-only over MCP (MEE-1995): operates on blog posts only. A social-post postId is rejected.

update_blog_post

Edit a blog post's title, body, and/or URL slug in one call. Pass any combination of title, body, and slug; omitted fields are left unchanged, and at least one must be provided.

Deprecated aliases: the former granular tools update_blog_post_title, update_blog_post_body, and update_blog_post_slug (and the older short names update_title, update_caption, update_slug) still work — they route to update_blog_post. Their legacy field names caption (→ body) and requestedSlug (→ slug) are also still accepted.

Authentication: Required. Available on any plan.

ParameterTypeRequiredDescription
syntheticIdnumberYesThe agent the post belongs to.
postIdstringYesThe post to edit. From list_blog_posts.
titlestringNoNew title. Appears in every listing and index.
bodystringNoNew body / main text for the post.
slugstringNoNew URL slug: lowercase letters, numbers, and hyphens only (e.g. my-new-post-url).

Synchronous — writes the change and returns immediately. No LLM call, no credit cost. Each field refreshes the right public surface: a title change fans out across every listing and index; a body change refreshes the post's own page; a slug change refreshes the listings and 308-redirects the old URL to the new one. Changing the title does not change the slug — pass slug too if you want the URL to change. A slug is rejected when the post isn't a blog post, the slug is invalid (anything other than lowercase letters, numbers, and hyphens), or another post on the same agent already uses it. The response includes an updated array naming which fields changed, plus oldSlug/newSlug when the slug changed.

regenerate_blog_post

Re-run text generation for one existing post. Pulls from the post's stored outline or source content and rewrites the body.

Deprecated alias: regenerate_post is still accepted but regenerate_blog_post is the canonical name.

Authentication: Paid — uses credits; available on any plan with credits remaining.

ParameterTypeRequiredDescription
syntheticIdnumberYesThe agent the post belongs to.
postIdstringYesThe post to regenerate. From list_blog_posts.

Returns immediately after enqueueing; generation is async. The post's status flips to generating and new text lands in roughly 30–90 seconds. Credit-gated — if the brand's account is out of credits the call fails with an error telling the user to add credits or upgrade, and nothing is enqueued (a structured error: "insufficient_credits" result). The post must already have a stored outline or source content (posts created via workflows do). Poll list_blog_posts to see when it completes.

Published posts are rejected. Regeneration resets the post to a generating state and the worker returns it as a draft, so regenerating a live article would pull it off the public site. To edit a published post's body in place use update_blog_post (preserves published status); to rewrite from scratch, move_blog_post_to_draftregenerate_blog_postpublish_blog_post.

Blog-only over MCP (MEE-1995): operates on blog posts only. A social-post postId is rejected.

generate_blog_post_image

Generate — or regenerate — the hero image and media for one post.

Deprecated alias: generate_post_image is still accepted but generate_blog_post_image is the canonical name.

Authentication: Paid — uses credits; available on any plan with credits remaining.

ParameterTypeRequiredDescription
syntheticIdnumberYesThe agent the post belongs to.
postIdstringYesThe post to generate an image for. From list_blog_posts.

Enqueues image generation and returns immediately — generation is async. If media generation is already running for that post, the call is a no-op success (alreadyInProgress: true), so concurrent calls are safe. Credit-gated — if the brand's account is out of credits the call fails with an error telling the user to add credits or upgrade, and nothing is enqueued (a structured error: "insufficient_credits" result). A post sitting in a media_failed state is reset and retried. Poll list_blog_posts for the resulting mediaUrl.

Published posts are rejected. The media-generation worker returns the post to draft when the new image saves, so generating an image for a live article would pull it off the public site. To swap a published post's image, move_blog_post_to_draftgenerate_blog_post_imagepublish_blog_post.

Blog-only over MCP (MEE-1995): operates on blog posts only. A social-post postId is rejected.

set_blog_post_image

Set a blog post's hero image to an external, already-hosted image URL. Use this to point the hero at a specific image you host elsewhere, instead of generating one.

Authentication: Required. Available on any plan.

ParameterTypeRequiredDescription
syntheticIdnumberYesThe agent the post belongs to.
postIdstringYesThe post whose hero image to set. From list_blog_posts.
imageUrlstringYesA durable, publicly reachable https URL for the hero image, on a renderable host (see below).

Synchronous, no LLM call, no credit cost. The image is referenced, not re-hosted, so pass a durable URL — one that later 404s breaks the post's hero. Only works on blog posts whose current image is a stock photo or a prior upload; posts with an AI-generated image are not replaceable this way (use generate_blog_post_image to re-run those instead). The change is live in Pendium immediately.

Renderable hosts only. Heroes are served through Next.js <Image>, which only loads image hosts allowlisted in the app's next.config.mjs remotePatterns. Prefer a Pendium-hosted blob URL (e.g. *.public.blob.vercel-storage.com) or an already-allowlisted CDN (Google user-content, images.pexels.com). An image on an unlisted host is accepted but renders broken on the public page.

Blog-only over MCP (MEE-1995): operates on blog posts only. A social-post postId is rejected.

On this page