API referencev0.1.0

Narrareach MCP API

Connect Claude Desktop, Claude Code, Cursor, or any MCP-compatible agent to your Narrareach workspace. Read drafts, manage your scheduling queue, and browse your inspiration library — all over the Model Context Protocol.

Overview#

Narrareach exposes a Model Context Protocol server so AI clients can read your drafts, manage your scheduling queue, and browse your inspiration library on your behalf. The endpoint is stateless, authenticated with a bearer token, and speaks JSON-RPC 2.0 over HTTP.

Endpoint
POST /api/mcp
Auth
Authorization: Bearer nrr_mcp_…
Protocol
2025-06-18
Content-Type
application/json

Quickstart#

  1. Open Settings → Developer in Narrareach and click Create. Copy the token — it's shown once.
  2. Add Narrareach to your MCP client using one of the recipes below.
  3. Call tools/list to confirm the 15 tools appear, then start asking your agent to list drafts or schedule posts.

Access tokens#

Each token is tied to the user who created it and inherits that user's permissions. There are no roles or per-tool scopes in v0.1. A token looks like nrr_mcp_… and holds 256 bits of random entropy.

Narrareach stores only the SHA-256 hash — you will never be able to retrieve the plaintext again after the creation screen. Treat tokens like passwords: don't commit them, don't share them, and revoke unused ones.

Revoking tokens#

From Settings → Developer, click Revoke next to any active token. Revocation takes effect immediately on the next request — there is no cache.

Claude Desktop#

Edit claude_desktop_config.json and add a narrareach entry under mcpServers. On macOS this file lives at ~/Library/Application Support/Claude/claude_desktop_config.json; on Windows %APPDATA%\Claude\claude_desktop_config.json.

Claude Code#

Use the claude mcp add command with the HTTP transport. Verify afterwards with claude mcp list.

Cursor#

Cursor's MCP config lives in Settings → MCP or in ~/.cursor/mcp.json. The schema matches Claude Desktop.

Generic HTTP MCP clients#

Any client that supports Streamable HTTP works. There are no sessions — each request is independent. You don't need to track Mcp-Session-Id, handle resumable SSE, or call DELETE /mcp.

Transport#

Narrareach implements a stateless subset of the MCP Streamable HTTP transport, sufficient for tools-only servers:

FeatureSupported
POST /api/mcp (JSON requests)Yes
JSON-RPC batchesYes
Notifications (no id) → 202 AcceptedYes
Bearer token authYes
CORS preflight (OPTIONS)Yes
GET /api/mcp (server-initiated SSE)No
DELETE /api/mcp (session termination)No
Mcp-Session-Id headerNo
Resources / prompts / samplingNo

Methods#

The server answers four JSON-RPC methods:

  • initialize — Handshake. Returns the server info and capabilities.
  • ping — Liveness check. Returns {}.
  • tools/list — Returns the full tool catalog with JSON Schemas.
  • tools/call — Invokes a named tool with its arguments.

Tool results always include both a content text block (for LLMs that rely on text output) and a structuredContent field with the same data as a typed object.

Tool catalog#

All tools are scoped to the token owner. Every underlying database query re-checks ownership — tokens cannot be used to touch another user's data even by guessing ids.

list_drafts#

List the user's drafts, newest first. Excludes archived unless you pass status: "ARCHIVED". Returns a compact summary — call get_draft for full content.

ArgumentTypeDescription
limitinteger (1–100)Max drafts to return. Default 25.
statusenumOne of DRAFT, PARTIALLY_PUBLISHED, PUBLISHED, ARCHIVED.
querystringCase-insensitive substring match against the draft title.

get_draft#

Fetch a single draft including full HTML + ProseMirror JSON content.

ArgumentTypeDescription
id*stringDraft id.

create_draft#

Create a new draft owned by the token holder. Newly created drafts are tagged with meta.createdVia = "mcp" so you can distinguish them from in-app drafts later.

ArgumentTypeDescription
title*stringDraft title. Max 500 chars.
contentHtmlstringStarting HTML body. Max 200,000 chars.

update_draft#

Patch an existing draft. Only supplied fields are changed.

ArgumentTypeDescription
id*stringDraft id.
titlestringNew title.
contentHtmlstringNew HTML body.

list_scheduled_posts#

List scheduled posts ordered by scheduled time ascending.

ArgumentTypeDescription
limitinteger (1–100)Default 25.
statusenumPENDING | PUBLISHING | PUBLISHED | FAILED | CANCELLED.
fromISO datetimeOnly return posts at/after this time.
toISO datetimeOnly return posts at/before this time.

cancel_scheduled_post#

Cancel a pending scheduled post. Already-published posts error; already-cancelled posts return alreadyCancelled: true.

ArgumentTypeDescription
id*stringScheduledPost id.

list_inspiration_posts#

List posts the user has saved to their inspiration library, newest first. Each post's content is truncated to 1,500 characters to fit in context windows.

ArgumentTypeDescription
limitinteger (1–100)Default 25.
platformenumSUBSTACK | LINKEDIN.
tagstringOnly posts containing this tag.

get_user_profile#

Return the authenticated user's profile, subscription, and connected platforms. Takes no arguments.

Error codes#

Narrareach uses the standard JSON-RPC 2.0 error envelope. Errors thrown by a tool handler (e.g. "Draft not found") are returned as a successful RPC response with isError: true — not as a transport error — so the model can recover.

CodeMeaningWhen it happens
-32700Parse errorRequest body is not valid JSON. HTTP 400.
-32600Invalid RequestMissing jsonrpc: "2.0" or method.
-32601Method not foundUnknown method or unknown tool name.
-32602Invalid paramstools/call missing name, or args fail validation.
-32603Internal errorUnhandled server exception.
-32001UnauthorizedMissing/invalid/revoked/expired token. HTTP 401.

Security model#

  • Token storage. Only the SHA-256 hash and a 12-character prefix for display are stored. Plaintext exists only in the creation response and your own memory thereafter.
  • Per-user scoping. Every tool handler filters Prisma queries by userId. Tokens cannot access another user's data.
  • Revocation. Revoking a token sets revokedAt; the next lookup refuses it. There is no cache.
  • Clerk boundary. /api/mcp uses bearer auth only. /api/mcp/tokens/* (the management routes) use Clerk sessions and cannot be called with an MCP token.
  • CORS. Access-Control-Allow-Origin: * is set on the endpoint so browser-based clients can connect. Since the only accepted auth is a bearer token the user explicitly pasted, there is no cookie or session a malicious origin could ride on.

Limits#

LimitValue
Active tokens per user10
limit arg on list tools1–100
title on create_draft / update_draft500 chars
contentHtml on create_draft / update_draft200,000 chars
Token name80 chars

Troubleshooting#

401 Unauthorized
Your token is missing, malformed, revoked, or expired. Double-check the header: Bearer nrr_mcp_… (case-sensitive scheme, single space, full token including the nrr_mcp_ prefix).
405 Method Not Allowed on GET /api/mcp
Narrareach does not implement server-initiated SSE streams. Use POST only. Any MCP client worth its salt will fall back automatically.
Tool call returns isError: true
That's not a transport error — the tool ran and reported a business-logic error. Read content[0].text for details.
-32602 Invalid params on tools/call
Your arguments don't match the tool's input schema. Call tools/list to see the exact schema and retry.

Changelog#

v0.1.0Initial release
  • 15 tools covering drafts, notes, scheduling, inspiration, analytics, and profile
  • Stateless Streamable HTTP transport (POST-only)
  • Per-user bearer tokens with SHA-256 hashed storage