{"name":"io.polyblog/polyblog","slug":"polyblog","title":null,"description":"Manage multilingual Polyblog articles, localization coverage and editorial plans through OAuth.","url":"https://mcp.market/server/polyblog","rating":null,"grade":"C","score":60,"certified":false,"status":"active","category":"other","tags":[],"presence":{"score":8,"stars":null,"forks":null,"downloads_week":null,"last_push_at":null,"license":null},"uptime":{"percent":100,"checks":19,"ok":19,"last_checked_at":"2026-09-24T04:26:20.023Z","last_ok_at":"2026-09-24T04:26:20.023Z","latency_ms":855},"claimed":false,"transport":"remote","callable_via_gateway":true,"default_price_micros":0,"repository":null,"website":"https://www.polyblog.io/developers/?utm_source=official-mcp-registry&utm_medium=mcp_directory&utm_campaign=mcp-registries-2026#mcp","version":"0.1.0","remotes":[{"type":"streamable-http","url":"https://mcp.polyblog.io/mcp"}],"packages":[],"tools":[{"name":"create_article","description":"Create a new Polyblog article in the given blog. Returns the created article id and title and fires an `article.created` webhook. Defaults to unpublished; passing `published: true` also creates a public article page. To write a TRANSLATION of an article you already have, pass that article's id as `originalArticleId` together with the new `locale`; without it the translation becomes a separate article that no locale of the original links to.","write_action":true,"price_micros":0,"input_schema":{"type":"object","properties":{"blogId":{"type":"string","minLength":1,"maxLength":200,"description":"Target blog id"},"title":{"type":"string","maxLength":300,"minLength":1},"content":{"type":"string","maxLength":100000,"minLength":1,"description":"Article body (Markdown or HTML based on format)"},"format":{"type":"string","enum":["markdown","html"]},"locale":{"type":"string","maxLength":50},"originalArticleId":{"type":"string","maxLength":200,"description":"Create this article as the `locale` version of an existing article, inside that article's translation group. Pass the ORIGINAL id — the one `list_article_translations` reports — never a sibling translation id. Omit it to create a new original."},"slug":{"type":"string","maxLength":300},"description":{"type":"string","maxLength":1000},"author":{"type":"string","maxLength":200},"categories":{"type":"array","items":{"type":"string","maxLength":100},"maxItems":50},"published":{"type":"boolean"}},"required":["blogId","title","content"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"create_blog","description":"Create a new Polyblog blog in the signed-in organization. The name is globally unique because it becomes the public <name>.polyblog.io subdomain, so a clashing name fails rather than being adjusted. Creating a blog also fires a `blog.created` webhook to the organization subscribers.","write_action":true,"price_micros":0,"input_schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200,"description":"Blog name; also becomes the public <name>.polyblog.io subdomain and must be globally unique"},"description":{"type":"string","maxLength":600},"defaultLocale":{"type":"string","maxLength":50,"description":"ISO 639-1 code the blog writes in by default, e.g. \"en\""},"locales":{"type":"array","items":{"$ref":"#/properties/defaultLocale"},"maxItems":100,"description":"ISO 639-1 codes the blog publishes translations in"},"articlesFormat":{"type":"string","enum":["markdown","html"]}},"required":["name"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"delete_article","description":"Permanently delete a Polyblog article by id. Deleting a published article removes its public page and fires an `article.deleted` webhook. This cannot be undone — confirm with the user before calling.","write_action":true,"price_micros":0,"input_schema":{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":200,"description":"Article id to delete"}},"required":["id"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"generate_article","description":"Generate a text-only SEO blog article: an LLM drafts bounded HTML, internal links come from the blog customDomain sitemap.xml, and the article is saved as a draft by default. This MCP tool always disables cover and inline image generation. Pass `topic` or `topicIdeaId`. It spends paid model usage and usually takes 30–60 seconds.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"blogId":{"type":"string","minLength":1,"maxLength":200,"description":"Target blog id"},"topic":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":200,"description":"Article topic title"},"angle":{"type":"string","maxLength":500,"description":"One-line angle / framing for the article"}},"required":["title"],"additionalProperties":false,"description":"Topic to write about. Skip if using topicIdeaId."},"topicIdeaId":{"type":"string","maxLength":200,"description":"Use a previously-saved topic idea instead of supplying topic.title."},"locale":{"type":"string","maxLength":50,"description":"Locale code (defaults to blog defaultLocale)."},"autoPublish":{"type":"boolean","description":"Publish immediately. Default false (saves as draft)."},"persist":{"type":"boolean","description":"Save to Mongo. Default true. Set false for a dry-run preview."},"sitemapMaxUrls":{"type":"integer","exclusiveMinimum":0,"maximum":500,"description":"Max sitemap URLs to feed the LLM as the allowed internal-link pool (default 150)."}},"required":["blogId"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"get_article","description":"Fetch a single Polyblog article by id or by slug+locale. Returns allowlisted metadata and at most 8,000 characters of article content, with an explicit truncation flag.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"idOrSlug":{"type":"string","minLength":1,"maxLength":300,"description":"Article id or slug"},"locale":{"type":"string","maxLength":50,"description":"Locale to disambiguate when looking up by slug"}},"required":["idOrSlug"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"get_blog","description":"Fetch a single Polyblog blog by id or name. Returns the blog metadata formatted as Markdown.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"idOrName":{"type":"string","minLength":1,"maxLength":200,"description":"Blog id (uuid) or name"}},"required":["idOrName"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"get_blog_localization_summary","description":"Summarize multilingual article coverage for one organization-owned Polyblog blog. Compares configured locales with up to 100 recently edited article translations and clearly marks the result when the sample is truncated.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"blogId":{"type":"string","minLength":1,"maxLength":200,"description":"Polyblog blog id or name to audit"}},"required":["blogId"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"get_sitemap_urls","description":"Summarize URLs from the blog's customDomain `/sitemap.xml` (following a sitemap index one level) and return at most 25 safe sample URLs. Used by `generate_article` as the allowed internal-link pool.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"blogId":{"type":"string","minLength":1,"maxLength":200,"description":"Target blog id"},"locale":{"type":"string","maxLength":50,"description":"Two-letter locale to filter by (e.g. \"en\")"},"maxUrls":{"type":"integer","exclusiveMinimum":0,"maximum":2000,"description":"Cap on URLs returned (default 500, max 2000)"}},"required":["blogId"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"list_article_translations","description":"List up to 100 locale versions of one article, grouped by its `originalArticleId`, and mark a truncated result. Returns safe article metadata and translation method. Pass `blogId` to compare against at most 100 configured locales.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"originalArticleId":{"type":"string","minLength":1,"maxLength":200,"description":"Original article id — the id of the source-locale article; every translation shares it"},"blogId":{"type":"string","maxLength":200,"description":"Optional blog id. When given, the reply also lists the blog locales that are still missing a translation."}},"required":["originalArticleId"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"list_blogs","description":"List Polyblog blogs the authenticated tenant has access to. Returns a bounded page of id, name, and custom domain. Pass the returned cursor to continue.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"limit":{"type":"integer","exclusiveMinimum":0,"maximum":100},"cursor":{"type":"string","maxLength":4096,"description":"Opaque pagination cursor from a previous call"}},"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"list_topic_ideas","description":"List saved topic ideas for a blog, optionally filtered by status and minimum score. Returns id, score, title, status, and source. Use the id with `generate_article` to write the article.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"blogId":{"type":"string","minLength":1,"maxLength":200,"description":"Target blog id"},"status":{"type":"string","enum":["new","used","dismissed"],"description":"Filter by lifecycle status (default: all)"},"minScore":{"type":"integer","minimum":0,"maximum":10,"description":"Minimum LLM score (0-10) to include"},"limit":{"type":"integer","exclusiveMinimum":0,"maximum":100},"cursor":{"type":"string","maxLength":4096}},"required":["blogId"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"refresh_topic_ideas","description":"Fetch fresh content from bounded Reddit subreddits and public HTTPS RSS feeds, spend paid model usage to score candidates, dedupe against published articles, and persist the keepers. Returns aggregate counts and at most five safe ideas; raw source errors are suppressed. Confirm sources and limits first.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"blogId":{"type":"string","minLength":1,"maxLength":200,"description":"Target blog id"},"sources":{"type":"object","properties":{"reddit":{"type":"array","items":{"type":"string","minLength":1,"maxLength":100,"pattern":"^[A-Za-z0-9_]+$"},"maxItems":20,"description":"Subreddit names (without /r/)"},"rss":{"type":"array","items":{"type":"string","format":"uri","maxLength":2048},"maxItems":20,"description":"Full RSS / Atom feed URLs"}},"additionalProperties":false,"description":"Override the blog topicSources. If omitted, the blog `topicSources` field is used."},"audience":{"type":"string","maxLength":600,"description":"Audience description. Defaults to the blog `context` field if omitted."},"sinceHours":{"type":"integer","exclusiveMinimum":0,"maximum":8760,"description":"Lookback window in hours (default 168 = 7 days)"},"limitPerSource":{"type":"integer","exclusiveMinimum":0,"maximum":100,"description":"Max items fetched per source (default 25)"},"minScore":{"type":"integer","minimum":0,"maximum":10,"description":"Minimum LLM score (0-10) to keep a candidate (default 5)"},"perSourceCap":{"type":"integer","exclusiveMinimum":0,"maximum":100,"description":"Cap on scored candidates per source (default: no cap)"}},"required":["blogId"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"search_articles","description":"Search Polyblog articles with optional filters by blog, locale, slug, and published state. Returns a Markdown table of matches with id, title, locale, slug, and published. Use the returned cursor to page through results.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"blogId":{"type":"string","maxLength":200,"description":"Filter to a specific blog"},"locale":{"type":"string","maxLength":50,"description":"ISO 639-1 locale code, e.g. \"en\", \"it\""},"slug":{"type":"string","maxLength":300,"description":"Exact slug match"},"published":{"type":"string","enum":["true","false"],"description":"Filter by published state"},"limit":{"type":"integer","exclusiveMinimum":0,"maximum":100},"cursor":{"type":"string","maxLength":4096,"description":"Opaque pagination cursor from a previous call"}},"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"set_topic_idea_status","description":"Move a saved topic idea through its lifecycle: mark it `used` once an article has been written from it, `dismissed` to keep it out of future suggestions, or back to `new`. Only the status (and optionally the article it produced) is changed.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"topicIdeaId":{"type":"string","minLength":1,"maxLength":200,"description":"Topic idea id from `list_topic_ideas`"},"status":{"type":"string","enum":["new","used","dismissed"],"description":"New lifecycle status for the topic idea"},"usedForArticleId":{"type":"string","maxLength":200,"description":"Article id this idea produced; only meaningful with \"used\""}},"required":["topicIdeaId","status"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"set_topic_sources","description":"Replace the Reddit subreddits and/or public HTTPS RSS feeds used for topic research. Confirm the complete replacement lists before calling. Once set, `refresh_topic_ideas` only needs the blogId. Pass `reddit` and/or `rss`, or `clear: true` to wipe all sources.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"blogId":{"type":"string","minLength":1,"maxLength":200,"description":"Target blog id or name"},"reddit":{"type":"array","items":{"type":"string","minLength":1,"maxLength":100,"pattern":"^[A-Za-z0-9_]+$"},"maxItems":20,"description":"Subreddit names (without /r/). Replaces the existing list."},"rss":{"type":"array","items":{"type":"string","format":"uri","maxLength":2048},"maxItems":20,"description":"Full RSS / Atom feed URLs. Replaces the existing list."},"clear":{"type":"boolean","description":"Remove the topicSources field entirely."}},"required":["blogId"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"show_article_preview","description":"Render a focused preview for a known Polyblog article, including its publication state, metadata, and a bounded content excerpt.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"articleId":{"type":"string","minLength":1,"maxLength":200,"description":"Polyblog article id to preview, at most 200 characters"}},"required":["articleId"],"$schema":"https://json-schema.org/draft/2020-12/schema"}},{"name":"show_blog_overview","description":"Render a compact overview for a known Polyblog blog, including its domain, locales, and up to ten recently edited articles.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"blogId":{"type":"string","minLength":1,"maxLength":200,"description":"Polyblog blog id to render, at most 200 characters"}},"required":["blogId"],"$schema":"https://json-schema.org/draft/2020-12/schema"}},{"name":"update_article","description":"Partially update an existing Polyblog article by id. Only the fields you pass are changed; everything else is preserved. Passing `published` can publish or unpublish its public page, and every update fires an `article.updated` webhook.","write_action":true,"price_micros":0,"input_schema":{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":200,"description":"Article id to update"},"title":{"type":"string","maxLength":300},"content":{"type":"string","maxLength":100000},"format":{"type":"string","enum":["markdown","html"]},"description":{"type":"string","maxLength":1000},"slug":{"type":"string","maxLength":300},"author":{"type":"string","maxLength":200},"categories":{"type":"array","items":{"type":"string","maxLength":100},"maxItems":50},"published":{"type":"boolean"}},"required":["id"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}],"scan":{"score":60,"grade":"C","scanned_at":"2026-09-23T11:54:33.279Z","report":{"scannerVersion":"0.1.9","scannedAt":"2026-09-23T11:54:33.256Z","components":{"code":{"score":-1,"max":25,"notes":["remote-only server, no package to scan"]},"reliability":{"score":20,"max":20,"notes":["remote reachable in 1842ms"]},"poisoning":{"score":15,"max":15,"notes":["18 tool descriptions checked"]},"auth":{"score":3,"max":15,"notes":["open endpoint exposes 4 write-action tools with no auth"]},"maintenance":{"score":3,"max":15,"notes":["no repository listed"]},"identity":{"score":4,"max":10,"notes":["verified namespace with website, no repo"]}},"findings":[{"id":"auth.open-write","severity":"high","component":"auth","title":"Write-action tools reachable without authentication"},{"id":"maint.no-repo","severity":"low","component":"maintenance","title":"No source repository listed"}],"inputs":{"probes":[{"url":"https://mcp.polyblog.io/mcp","reachable":true,"authRequired":false,"latencyMs":1842,"serverInfo":{"name":"polyblog-mcp","version":"0.1.0"}}],"packages":[],"repo":{"found":false},"icon":{"url":"https://www.imagelato.com/images/favicon-polyblog-cf8afb2c.svg","source":"site"},"presence":{"stars":null,"forks":null,"downloadsWeek":null,"license":null,"lastPushAt":null,"score":8}}}},"grade_history":[],"reviews":[]}