MCP reference
What the Journey MCP server exposes, for testing, review and support.
If you only want to use it, start with Getting started instead.
| Server | https://mcp.jny.io/mcp |
|---|---|
| Transport | Streamable HTTP, MCP SDK 2.3.0, HTTPS only |
| Auth | OAuth 2.0 via WorkOS AuthKit, bearer token per request |
| Tools | 18 |
How a request is authorised
Every tool call carries a bearer token, verified before the tool runs. There is no API key to copy and no shared secret.
- Claude sends the user to WorkOS AuthKit, which redirects to
Journey's own login page (
/auth/workos/login). - Journey authenticates the user with its normal login — password, Google or Microsoft. The password never reaches WorkOS or Claude.
- Journey tells WorkOS who the user is, setting the WorkOS
external_idto the JourneyUser.id. - WorkOS issues an RS256 JWT, sent on every call as
Authorization: Bearer …
On each request the server checks, in order:
| Check | Why |
|---|---|
| Signature against the WorkOS JWKS | The token was issued by WorkOS |
iss matches WORKOS_ISSUER | Not another WorkOS tenant |
aud matches MCP_RESOURCE_URL | A token minted for a different resource is refused |
exp present and unexpired | Tokens age out |
sub resolves to a live user | A token outlives the account |
| Organisation membership | Checked per request, never inferred from the token |
Three existing mechanisms were deliberately not
reused: the X-Journey-API header (a plaintext key with full
session rights), PlatformApiKeys (secret derived from a
hardcoded server secret), and flask_login.current_user (no
browser session exists here).
Admin is not a tool capability. Membership is checked
with get_organization_user, not
has_access_to_organization — the latter returns true for any
is_admin user, which would let a staff token reach every
customer's rooms through a chat box.
Revocation — a known limitation
There is no server-side token revocation. A token
already issued stays valid until its exp, so disconnecting in
Claude stops new tokens being obtained but does not invalidate one already
in flight.
Two things do take effect immediately: deleting the Journey account
(is_deleted is checked per request), and removing the user
from an organisation. For a compromised-token scenario, deactivating the
account is currently the mechanism available.
Rooms have two shapes
The distinction to understand before testing content tools.
| pitch (default) | microsite | |
|---|---|---|
| Layout | One item per step, read in sequence | One long scrolling page |
| Use for | Proposals, pitches, anything ordered | A page to read |
| Supports | document, html, image, video, pdf, link | html, text, image, link, button, table, library |
| Positions | Integers, renumbered on change | Fractional strings (a1, a1m) |
Consequences: buttons and tables exist only in
microsite mode; video and pdf items exist only in pitch
mode. In pitch mode a written step is a document (with
heading and text), not a text block.
Tools
Identity and discovery
| Tool | Does | Arguments |
|---|---|---|
whoami | The current user and the organisations they can act in | — |
find_room | Find a room by name, to get the room_id other tools need | query, limit, organization_id |
follow_up_structure | The structure a sales-call follow-up should take | — |
whoami should be called before the first room of a
conversation: if the user belongs to more than one organisation, the
connector asks which to use rather than guessing.
Creating and changing rooms
| Tool | Does | Arguments |
|---|---|---|
create_room | Create a room from content, returns a tracked share link | title, content, mode, organization_id, require_email |
add_to_room | Append content to an existing room | room_id, content, organization_id |
rename_room | Change a room's title | room_id, title, organization_id |
apply_branding | Make a room match a company's brand, from its domain | room_id, domain, organization_id |
create_room content items: html,
text, link, button,
image, table, library, plus
document, video and pdf in pitch
mode. Full HTML artifacts keep their JavaScript and stay interactive.
Editing content in place
| Tool | Does | Arguments |
|---|---|---|
list_content | What is in a room, in reading order | room_id, organization_id |
replace_content | Rewrite one block, keeping its position | room_id, block_id, content, organization_id |
remove_content | Take a block out | room_id, block_id, organization_id |
move_content | Move a block elsewhere in the room | room_id, block_id, after_block_id, organization_id |
All four work in both modes. Call list_content first — the
block_id values the other three need come from it.
Library
| Tool | Does | Arguments |
|---|---|---|
search_library | Find content the organisation already has | query, limit, organization_id |
save_to_library | Store something without building a room | name, html, url, organization_id |
Library content is added to a room as
{"type": "library", "content_id": "…"}.
Sharing and tracking
| Tool | Does | Arguments |
|---|---|---|
create_share_links | One named share link per recipient | room_id, links, organization_id |
get_room_activity | Who opened a room, and for how long | room_id, organization_id |
Each named link is tracked separately, which is what makes per-recipient analytics work.
Getting content into a room
Uploading is only one of several routes, and often not the one that applies:
- File in chat or project context — Claude has already read it, and writes the content into the room as html, text or a table. No upload tool involved. This covers most PDFs, decks and documents.
- Public URL —
imageandpdfitems are fetched server-side. No upload tool involved. - Upload — needed when the bytes themselves must land in Journey: a local image to display, a video to play, a PDF to page through.
Upload routes
When Claude can read the filesystem and make an HTTP request:
| Step | Tool | Arguments |
|---|---|---|
| 1 | prepare_upload | filename, size_bytes, content_type, organization_id |
| 2 | Claude PUTs the file to the presigned url | |
| 3 | register_upload | key, name, organization_id |
When it cannot — a browser conversation:
| Step | Tool | Arguments |
|---|---|---|
| 1 | prepare_browser_upload | filename, content_type, organization_id |
| 2 | User opens the link and drags the file in | |
| 3 | register_upload | key, name, organization_id |
Images, video and PDF up to 500MB. SVG is rejected. The presigned PUT url lasts 15 minutes; the browser link is single use and lasts 30 minutes, with spent tickets recorded in Redis so they cannot be replayed.
Limits
By design, not oversight:
- No delete. Content can be removed from a room; the room itself cannot be deleted.
- Share links cannot be renamed or removed. They are only added — a link already sent is one somebody may be holding.
- A room's original URL cannot be changed. Named links are added alongside it.
- No email sending. The connector drafts; sending stays with the user.
- A room cannot move between organisations.
Operational:
- Video needs processing before it can be placed. A
Mux asset is created immediately with status
preparing; only the asset callback marks itready. - Server-side fetches are guarded.
image,pdfand branding fetch URLs server-side, so each goes through an SSRF guard that refuses private and link-local addresses, including instance metadata.