---
title: "For developers — the Storywright MCP server"
description: "Build on Storywright with the Model Context Protocol: 59 tools over campaign, session, and world state, OAuth 2.1 with PKCE and Dynamic Client Registration, and public discovery documents."
doc_version: "1.0"
last_updated: 2026-08-28
---

# For developers — build on Storywright with MCP

Plain-text Markdown mirror of [storywright.io/developers](https://storywright.io/developers).

We don't publish a REST API for third parties — our REST surface is internal
and unversioned, and freezing it as a public contract isn't something we can
honestly promise yet. What we do ship, and what this page documents, is a
real, public [Model Context Protocol](https://modelcontextprotocol.io) server:
59 tools over a signed-in user's own campaign data, authenticated with
OAuth 2.1.

This page documents the MCP tool surface only — it does not enumerate
individual REST endpoints. That is a deliberate boundary, not an omission.

## The server

One remote MCP server, reachable over Streamable HTTP:

```
https://mcp.storywright.io/mcp
```

Point any MCP-capable client at that URL — Claude, ChatGPT, or anything else
speaking the protocol — and it discovers everything else on this page
automatically: the OAuth configuration, Dynamic Client Registration, and the
tool/resource/prompt catalog. No API key to request, no manual credential
setup.

## What the tools let you do

The server exposes a signed-in user's own worlds, sessions, player journals,
quests, lore ("Drafting Table"), characters, and the Campaign Weave graph —
read and write, scoped to whatever that user could already do in the app. It
is a thin adapter over the same internal REST API the product itself uses;
permissions are always enforced by the Storywright backend, never by this
process.

| Surface | Count | What it covers |
| --- | --- | --- |
| Read tools | 27 | Worlds, sessions, characters, journals, quests, lore, the Weave graph, and campaign overviews. |
| Write tools | 26 | Journal entries, quests, objectives, lore, annotations, sessions, AI session recaps and briefings. |
| Delete tools | 6 | Permanent removal — quests, objectives, lore items, threads, characters, journal entries. There is deliberately no session-delete tool. |
| Total tools | 59 | Read + write + delete. |
| Resources | 5 | Attachable reading material rendered as prose, not JSON — so a user can hand a client their campaign to read. |
| Prompts | 6 | Ready-made slash commands: starting a new campaign, session prep, recap, loose threads, catching a player up, importing a module. |

## Every tool, before you connect

The counts above are a summary. The full list — every tool, prompt, and
resource with its description and argument schema — is published as JSON at:

```
https://mcp.storywright.io/tools.json
```

**No authentication required.** Reading what the server can do should not
itself need a token; you cannot evaluate a surface you have to sign in to see.
The manifest is generated from the running server on each request rather than
maintained by hand, so it always describes the build that answers it — add a
tool and it appears there in the same deploy. It also carries the server's live
rate limit and the OAuth documents a client needs.

## Authentication

Every client authenticates as a real Storywright user, with that user's
explicit consent — there are no API keys. The server runs as an **OAuth 2.1**
Resource Server: **PKCE** (S256) is required on the authorization code grant,
and a client can self-register with **Dynamic Client Registration** (RFC
7591) instead of asking us for credentials by hand.

- **Grant type**: Authorization Code + PKCE (S256 required); `refresh_token`
  for staying connected.
- **Client registration**: open Dynamic Client Registration (RFC 7591) at
  `POST https://storywright.io/api/oauth/register/` — public clients only
  (`token_endpoint_auth_method: none`), rate-limited. Registration is open
  today and we intend to keep it that way; a deployment *may* restrict which
  redirect-URI hosts can register, in which case an unlisted host is refused
  with `400 invalid_redirect_uri` at registration rather than failing later
  in the flow.
- **Consent**: a human consent screen on Storywright; the user grants only
  the scopes they choose.
- **Tokens**: short-lived bearer access tokens, sent as
  `Authorization: Bearer <token>`.

### Scopes

| Scope | Grants |
| --- | --- |
| `campaigns:read` | Read the user's worlds, sessions, journals, quests, and lore. |
| `campaigns:write` | Create and update journals, quests, lore, and recaps. |

### Discovery documents

All public, CORS-open JSON — a spec-compliant client walks these
automatically:

| Document | URL |
| --- | --- |
| Authorization server metadata (RFC 8414) | `https://storywright.io/.well-known/oauth-authorization-server` |
| Protected resource metadata (RFC 9728) | `https://storywright.io/.well-known/oauth-protected-resource` |
| API catalog (RFC 9727) | `https://storywright.io/.well-known/api-catalog` |
| MCP server card | `https://storywright.io/.well-known/mcp.json` |

## Connecting and revoking access

For the human-facing walkthrough — adding Storywright as a custom connector
in Claude, ChatGPT, or another MCP client — see [Connect an
assistant](/connect/assistant.md). Once connected, a user can review exactly
what a client can do, and revoke any connected client's access at any time,
from [Trust](/trust.md).

## What we don't promise yet

This surface is offered **as-is**, with **no versioning guarantee** yet — a
tool's name, arguments, or behavior can change, and we make no uptime
commitment. Expect the tool list to grow. If a tool's behavior needs to change
in a breaking way, we'll say so in `mcp/README.md` and on this page, not
silently — and the tool manifest above is generated from the running server, so
it always describes what is actually deployed.

**Rate limits.** Requests to `/mcp` are limited per client over a fixed window.
Over the limit you get a `429` with a `Retry-After` header and
`{"error": "rate_limited"}`; honour the header rather than retrying
immediately. The numbers in force are published in the manifest's `rateLimit`
block — read them there rather than here, because a limit written into a
document is a claim about a build, and that one is the value the limiter is
actually counting with.

## More for agents

- [Agent authentication](/auth.md) — the fuller OAuth 2.1 technical reference.
- [llms.txt](/llms.txt) — site guide for AI agents.
- [FAQ](/faq.md)
- [Manual](/manual.md)
- [Full site index](/sitemap.md)
