Publive MCP Connector
Last updated: 9 September 2026
Connect Publive to an AI assistant and manage your publication by asking for it: pull published articles, audit categories and tags, draft and update posts, run a live blog, and build content-type schemas — all against your own Publive instance, with your own API credentials.
The connector reaches your own editorial content and nothing else. No tool here can
create or change a reader's account, read or alter anyone's newsletter subscription, or
send a password-reset or email-verification message. (fetch_newsletter_groups reads
your own newsletter group configuration — names, logos, descriptions — and returns no
subscriber.)
Endpoint
https://mcp.thepublive.com/mcp
Streamable HTTP (POST), stateless. Supports MCP protocol versions 2025-06-18
(preferred), 2025-03-26, and 2024-11-05.
HTTPS only (HSTS, with plain HTTP redirected), and the endpoint validates the Origin
header: a request from a browser origin that is not allowlisted is refused with 403
before authentication is even attempted. Clients that do not run in a browser — Claude's
servers, Claude Desktop, Claude Code — send no Origin and are unaffected.
Connecting
You need, from your Publive dashboard:
- your Publisher ID
- a CDS API key and secret — for reading published content
- a CMS API key and secret — for editorial reads and content changes
Both pairs are optional; at least one is required. They are independent credentials and are not interchangeable. Supplying only the CDS pair gives you a read-only connection with 21 tools; only the CMS pair gives you the 40 editorial tools; both gives you all 61.
Add the endpoint above to your assistant as a custom connector. You will be sent to
https://mcp.thepublive.com/connect, where you enter your Publisher ID and whichever
key pairs you want the connection to use. Each supplied pair is verified against its own
Publive API before any token is issued.
Authentication
OAuth 2.0 authorization code flow with PKCE (S256 required). Discovery documents:
| Document | URL |
|---|---|
| Authorization server metadata | /.well-known/oauth-authorization-server |
| Protected resource metadata | /.well-known/oauth-protected-resource |
| Endpoint | Purpose |
|---|---|
POST /register |
Dynamic client registration (RFC 7591) |
GET/POST /authorize |
Authorization + credential entry |
POST /token |
authorization_code and refresh_token grants |
POST /revoke |
Token revocation (RFC 7009) |
GET /userinfo |
Publisher identity claims |
Access tokens are issued with a 1 hour lifetime, reported as expires_in in the
token response and as tokenExpiresAt on initialize. Use the refresh_token grant to
rotate before then; you do not need to reconnect. A refresh returns a new access token
and a new refresh token, and the previous refresh token stops working.
Redirect URIs must be registered and are matched exactly, except for loopback URIs
(http://localhost / http://127.0.0.1), where the port may vary per RFC 8252.
What a connection can reach
There are no separate authorization scopes to request. A connection reaches exactly the
services whose credential pairs you supplied at sign-in, and the tool surface narrows to
match: tools/list advertises only the tools that connection can authenticate, and
tools/call refuses anything else with service_unavailable before the request reaches
Publive.
So a CDS-only sign-in is a genuinely read-only connection — the 21 CDS tools and nothing else — because the 40 CMS tools have no credential to spend.
Safety model
Content-changing tools never write on the first call.
| Tier | Behaviour |
|---|---|
| Read | Returns immediately. |
| Create | dry_run=true by default — returns a preview of exactly what will be created. Call again with dry_run=false to write. |
| Update | dry_run=true by default — returns a field-by-field diff of old vs new. Publishing (status=Published) additionally requires confirm_publish=true. |
| Delete | Requires both dry_run=false and confirm_delete=true. |
There is no exception: a post's status, Draft included, does not change this.
Every tool carries MCP safety annotations (readOnlyHint, destructiveHint,
idempotentHint) so your assistant can tell a read from a write before calling it.
Tools
CDS — published content (21, all read-only)
fetch_published_posts · fetch_published_post · fetch_post_by_url ·
fetch_liveblog_with_updates · fetch_trending_posts · fetch_published_categories ·
fetch_published_category · fetch_published_tags · fetch_published_tag ·
fetch_authors · fetch_author · fetch_publisher_profile · fetch_site_navigation ·
fetch_site_footer · fetch_newsletter_groups · resolve_url_to_content_type ·
fetch_ad_slots · fetch_content_type_definitions · fetch_sitemap ·
fetch_sitemap_page · fetch_static_file
CMS — editorial (40)
Read (18) — list_editorial_categories, get_editorial_category,
list_editorial_tags, get_editorial_tag, list_editorial_posts, get_editorial_post,
list_editorial_liveblog_updates, get_liveblog_update, list_component_schemas,
get_component_schema, list_content_type_schemas, get_content_type_schema,
list_media_assets, get_media_asset, validate_media_asset, validate_category,
validate_author, validate_post_slug
Create (8) — create_category, create_tag, create_post, add_liveblog_update,
create_component_schema, create_content_type_schema, register_media_asset,
upload_media_asset
Update / delete (14) — update_category, delete_category, update_tag,
delete_tag, update_post, delete_post, update_liveblog_update,
delete_liveblog_update, update_component_schema, delete_component_schema,
update_content_type_schema, delete_content_type_schema, update_media_asset,
delete_media_asset
Full argument schemas are served by tools/list on a connected session.
Uploads via upload_media_asset are capped at 25 MB.
Example prompts
Five prompts covering the range: a published-content read, a schema read, a pre-flight check, a gated write, and a live blog. The names below are from the demo publication — an eye-care hospital group — so swap in your own categories, tags and authors.
1. "Show me the six most recent published posts on my site, and which categories
they're filed under."
→ fetch_published_posts, then fetch_published_categories. You get a collection page:
each post's title, slug, type (Article, LiveBlog, CustomEntity, …), banner image
and absolute URL — followed by the category tree those posts sit in. Editorial types
(Article, Video, Gallery, LiveBlog) also carry a primary category and
contributors; a schema-driven CustomEntity row is filed by its collection rather than
a category, and carries its schema's field values under custom_entity instead.
2. "List our content types, then show me every field on the Doctor type."
→ list_content_type_schemas, then get_content_type_schema. The first call names each
schema; the second returns that type's field_types — for Doctor: name, photo,
qualifications, specialties, years_of_experience, primary_hospital_branch,
consultation_hours, bio and two booking ids, each with its field type and
validations. Ask the same way about components (list_component_schemas →
get_component_schema) for HeroSection, FaqSection, ReviewsSection and friends.
The listing expands every schema's field definitions inline, so it is a large response on
a publication with many types — leave limit at its default of 10 and page through it
rather than asking for all of them at once.
3. "Before I write it — is the slug cataract-surgery-recovery-guide free, and is
Srishti a valid author?"
→ validate_post_slug, plus fetch_authors → validate_author: the author check takes
a contributor id, so the name is resolved to one first. Verdicts and nothing written:
{"valid": true, "slug": "cataract-surgery-recovery-guide", "available": true} and
{"valid": true, "id": 53430, "name": "Srishti"}.
4. "Draft an article called 'Cataract Surgery Recovery: What to Expect' in the All
About Cataract category, tagged Cataract Surgery — show me the preview before you write
anything."
→ create_post with dry_run=true. The result carries dry_run: true,
confirmation_required: true and a preview listing every field that would be
created. Nothing exists in the CMS yet. Say go ahead and the same call repeats with
dry_run=false, returning the new post's id and URL.
5. "Pull up our live blog and its updates, then post a new update summarising the last
one."
→ list_editorial_posts to find the LiveBlog, then read its entries newest-first with
their titles, HTML bodies and is_pinned flags, then add_liveblog_update — previewed
first, like every other write.
A live blog is addressed by two ids, and the row you just listed carries both. Its id
is the CMS post id, which the editorial tools take: list_editorial_liveblog_updates,
add_liveblog_update, update_liveblog_update, delete_liveblog_update. Its
published_post is the published-post id, which the delivery reader
fetch_liveblog_with_updates takes. Each tool says which one it wants, and refuses the
other rather than acting on the wrong post.
Deletes ask twice, and the second ask is explicit: delete_tag with dry_run=false
alone still returns confirmation_required, and only dry_run=false plus
confirm_delete=true removes anything.
Results
Every tool declares an outputSchema describing the object it returns, and a successful
tools/call returns that object as structuredContent as well as the JSON text block —
so a client can read the result as data instead of re-parsing it out of the text. Tools
answer in one of four shapes:
| Shape | Returned by | Read |
|---|---|---|
| Collection page | the list_* / plural fetch_* tools |
results, plus count (null when Publive reports no real total — page until a request comes back empty) |
| Single resource | the get_* / singular fetch_* tools |
the resource's own fields; some endpoints nest them under data |
| Validation verdict | the validate_* tools |
valid, and reason when false |
| Write result | every create / update / delete tool | dry_run first — when true nothing was written and preview says what would be |
The declared properties are documented rather than type-pinned: the payload is a pass-through of a Publive response, and a schema strict enough to reject an upstream quirk would fail a call that actually succeeded.
A failed call carries no structuredContent — the error envelope below is not what the
tool's outputSchema describes.
Errors
Tool failures come back as a normal tool result with isError: true, carrying a JSON
body with a stable error_type, a human-readable message, and a retryable flag.
error_type |
Meaning |
|---|---|
invalid_params |
Arguments failed schema validation. Fix and retry. |
service_unavailable |
The tool needs a credential pair this connection does not hold. |
missing_required_field |
A required argument was omitted; message names it. |
confirmation_required |
A write needs dry_run=false (and confirm_delete=true to delete). |
not_found |
No such resource — usually a wrong or mistyped id. |
bad_request / client_error |
Publive rejected the request; message carries the reason. |
auth_error |
Credentials were rejected. Reconnect. |
timeout |
Upstream was slow. retryable: true. |
upstream_error |
Publive returned a 5xx. Not retryable — a failed write may still have committed, so verify state before trying again. |
system_error |
An unexpected fault in the connector. Not retryable; report it. |
Protocol-level failures use standard JSON-RPC codes (-32700 parse error, -32601
method not found, -32603 internal error).
Failures that stop a request before it becomes JSON-RPC answer with an HTTP status
instead: 401 (no or expired credentials — the WWW-Authenticate header points at the
OAuth discovery document), 403 forbidden_origin (disallowed browser Origin),
415 (Content-Type was not application/json), and 400 (an
MCP-Protocol-Version this server does not support).
Privacy and data handling
See the privacy policy and the terms of service. In short: your API credentials are encrypted at rest, your conversations are never collected (prompt arguments are stripped before any tool runs), and revoking the connection deletes the stored credentials.
Support
https://www.thepublive.com/contact-us