@ezquill/mcp-server
An MCP server that lets an AI agent read and add to a writer's ezQuill manuscript, story world, and timeline with the writer's consent, while protecting existing prose through suggested edits.
Read project structure: list projects, get project details, and browse the outline (parts, chapters, scenes, status, word counts).
Semantic search: search a project by meaning, not keywords, to find where a topic is discussed.
Read prose and story world: read scenes (prose, plan, characters/places), list and get entities (characters, locations, factions, items, notes), and view timelines (story chronology or writer milestones).
Read feedback: list open comment threads and suggested edits before revising.
Additive writing: create projects, manage the outline (add/rename/move/delete binder items), append paragraphs, fill planned-but-unwritten scenes, manage entities, cast, timeline events, and feedback.
Protect existing prose: replacing a writer's words creates a suggested edit the writer accepts in ezQuill; there is deliberately no tool to accept suggestions.
Word tools: look up word senses, synonyms, antonyms, forms, and list the writer's starred words.
Authentication: sign in via a returned link (local-only or OAuth for remote connectors), sign out, and optionally request delete permission when the writer explicitly asks.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@@ezquill/mcp-serverWhere is the prophecy mentioned in my manuscript?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
@ezquill/mcp-server
An MCP server for ezQuill. It lets an AI agent read and write a writer's manuscript, story world and timeline — on their behalf, with their consent, and only as far as they allowed.
Reads and additive writes; never a silent overwrite. Adding scenes,
paragraphs, characters and whole projects goes straight through. Changing words
a person already wrote becomes a suggested edit they accept in ezQuill — see
Writing. Read tools declare readOnlyHint; write tools do not.
Tools
tool | what it answers |
| which projects are there |
| what one project is, how far along, its premise |
| where is this discussed — semantic, not keyword |
| the binder: parts, chapters, scenes, status |
| one scene's prose, its plan, and who is in it |
| the story world: characters, places, factions, notes |
| one of them in full, with relations and appearances |
| story chronology, or the writer's own milestones |
| open comments and suggested edits |
| a word's senses, synonyms by meaning, antonyms, forms — the writer's dictionary |
| the words the writer has starred, with their notes |
| signing in. Local only — over a connector the client owns OAuth |
Writing
tool | what it does |
| start a project of any writing type, with its parts, chapters or posts — only when the writer asks |
| add, rename, move, restatus or delete parts of the binder; set a paragraph's plan |
|
|
| create and edit characters, places, notes, and the relationships between them |
| who is in a scene, and in what role |
| events in the story, or milestones in the writing |
| comment, reply, resolve |
Additive writes go straight through; replacing a person's words does not. Adding a paragraph, filling in one that was planned but never written, creating a scene — all destroy nothing and are restorable. Changing prose somebody wrote creates a suggested edit instead: anchored, visible in ezQuill with a diff, and accepted or rejected by the writer.
There is deliberately no tool that accepts a suggestion. A connector granted
ezquill:write holds the permission to accept as well as to propose, so a
suggestion an agent could accept itself would be a write with extra steps. The
safeguard is that the tool does not exist.
Two more things the tools do so a caller cannot get them wrong: write_draft
composes the whole-section reconcile itself (sending only your new paragraphs
to that endpoint would delete every paragraph you left out), and every writer of
a JSONB column rebuilds it from the row it read (a partial write to
nodes.metadata replaces the whole blob; a partial write to a timeline event's
story drops its cast).
search_project is the one nothing else can offer: a question can match the
passage that answers it without sharing any words with it.
Related MCP server: Echoes MCP Server
Three things worth knowing before you use the output
Prose lives in paragraph rows. A scene's own body is usually empty — its
text is in child block nodes. read_scene reassembles it. Never conclude a
scene is unwritten because a node has no content.
Search results carry no score. They are ordered by similarity and that is the entire signal. There is deliberately no distance, no rank and no threshold: the underlying measure has no absolute meaning — a question matched its answering scene at 0.60 while the wrong scenes sat at 0.68 and 0.74, so any cutoff tight enough to look meaningful throws away correct answers.
Quote text, never context. text is the writer's own words. context
is generated description of where the passage sits; presenting it as a quotation
attributes invented sentences to the writer.
Running it
# stdio, for an editor or desktop client. No credential needed.
npx -y -p @ezquill/mcp-server mcp-server
# Streamable HTTP, for a remote connector
PORT=8080 node src/http.jsDo not shorten that to npx @ezquill/mcp-server, and do not "simplify" it
later. npx resolves a multi-bin package only when one bin matches the
unscoped name; this package has three bins and does keep one called
mcp-server, so the short form happens to work today. The explicit -p <package> <bin> form keeps working if a bin is ever renamed, and it works
against versions already published — which the short form would not, silently.
ezmodo shipped a package with three bins and none matching, and npx exited 1
with "could not determine executable to run", which Claude Code surfaces as
CONNECTION_CLOSED and nothing else. A test pins the naming rule
(__tests__/package.test.js); this line pins the invocation.
And it will not run from a checkout of THIS repository, which costs an hour
the first time. npx -p @ezquill/mcp-server@x mcp-server, run from a directory
whose own package.json is named @ezquill/mcp-server, finds the package
already present, skips the install, and exits:
sh: line 1: mcp-server: command not foundAn MCP client reports that as CONNECTION_CLOSED: Connection closed and
nothing else. It is the working directory, not the package — a bare
package.json of that name is enough, node_modules is irrelevant, and the
same command works from anywhere else. Run it elsewhere, or use the connector.
Installing is the whole install. There is no key to mint and paste. The first tool call returns a sign-in link, the person opens it, and the agent retries — the same flow a remote connector uses, and better UX than an environment variable rather than a workaround for one.
The sign-in asks for read and write. It does not ask for permission to
delete: Keycloak's consent screen is accept-or-decline over the whole set, so
requesting it would make "permanently delete your scenes, characters, timeline
events and projects" a condition of installing an MCP server. Call
authenticate with includeDelete if you actually want that.
Tokens are cached at ~/.ezquill/mcp-token.json, mode 0600. sign_out
forgets them.
variable | meaning |
| defaults to |
| OIDC issuer; defaults to |
| where a PERSON is sent, not where requests go; defaults to |
| an explicit credential. Outranks a cached sign-in, and while it is set the server will not offer to sign in — a browser flow could not take effect, and sending someone on an errand that cannot work is worse than saying nothing |
| where the cached sign-in lives |
| never launch a browser. The link is still returned — that is the contract; opening it is a convenience |
| HTTP transport; |
The remote transport is stateless — no session affinity is assumed, because
it runs on autoscaled instances that scale to zero. GET /mcp answers 405 with
a reason rather than appearing broken.
Development
npm install
npm test # node:test, no frameworkThere is no build step. That is deliberate: it is what lets the package be published from a workflow that never installs dependencies.
Claude Code plugin
/plugin marketplace add EasyModeOnly/ezquill-mcp-server
/plugin install ezquill@ezquillThe plugin declares one thing: the remote connector at
https://mcp.ezquill.com/mcp. No Node, no npx, no local process, nothing to
install but the manifest. Claude Code runs OAuth against the connector, which
is the branded ezQuill sign-in and consent flow.
It ships no version pin, and that is the improvement. The plugin used to run the published npm package pinned to an exact version, which meant a fix reached an installed plugin only when somebody updated the plugin. A URL has no version: a fix reaches every installed plugin on the next deploy.
Its own version field is a different thing, and it does track npm. It is
not a statement about the manifest's contents — the manifest is three lines of
URL and client id and hardly ever changes. It is the only signal an already
installed machine gets that anything changed on the other end. See
"Releasing".
It carries the pre-registered OAuth client id, and without that it cannot authenticate at all. An MCP client with no client id tries Dynamic Client Registration, and the ezquill realm refuses:
Dynamic Client Registration rejected (HTTP 403): insufficient_scope
Policy 'Trusted Hosts' rejected request to client-registration serviceThe refusal is deliberate — the realm holds customer identities, and
allowlisting Anthropic's published egress range would admit registration from
anyone with a claude.ai account, because that range carries all outbound tool
traffic. The design assumes the client id is SUPPLIED, and oauth.clientId in
the manifest is where a plugin supplies it. The same value goes in the
--client-id flag when adding the server by hand:
claude mcp add --transport http --client-id ezquill-mcp ezquill https://mcp.ezquill.com/mcpIt is a public client with no secret, so publishing it costs nothing: it names which pre-registered client to use and opens nothing on its own.
It points at production, and a test enforces that. A plugin shipped
pointing at mcp.dev.ezquill.com would route every installer's manuscript
through the dev stack — and nothing about it would look wrong, because dev
answers and the tools work.
The manifest lives in plugin/ rather than at the repository root so the
plugin root holds the manifest and nothing else, instead of putting this whole
checkout into everybody's plugin cache.
The local stdio path is not gone — it is just not what the plugin ships.
It is still the way to run the connector offline, against a dev stack, or as a
self-hosted process: see "Running it" above, and add it with claude mcp add.
Updating the plugin does not update an open session's tools
/plugin marketplace update ezquill
→ ✔ Updated 1 marketplace (1 plugin bumped)
/reload-plugins
→ Reloaded: 5 plugins · 2 plugin MCP serversBoth of those succeeded and neither re-read the tool list. A session open across a connector deploy keeps the tool definitions it connected with, and nothing says so — the commands are telling the truth about what they did, which is update a manifest. The manifest is a URL. Tool definitions come from the server, fetched once, when the client connects.
Reconnect the server with /mcp, or start a new session.
Only descriptions go stale, never behaviour. The server runs the deployed code whatever the client believes, so a client holding an old tool list is told the wrong thing — a description missing a rule, an action it does not know exists — rather than made to do the wrong thing. A session on 0.3.0's definitions still gets 0.4.0's refusals, because the guards are server-side. That is the difference between an annoyance and a data problem, and it is why this is documented rather than fixed with a version pin.
To find out which side is behind, from 0.4.0:
curl https://mcp.ezquill.com/version
→ {"name":"ezquill-mcp-server","version":"0.4.0","sha":"78c0d74"}and ask the agent which version it is talking to — the server names itself in
the instructions it sends at the start of every session. The two disagreeing is
the whole diagnosis. Note the instructions are also taken at connect time, so
a stale session reports the stale version confidently; /version is the one
answer that cannot be out of date, because it is fetched when you ask.
This was worth a day on 2026-09-15, when two machines went on offering the 0.2.1 tools against a 0.3.0 server with nothing anywhere disagreeing.
When the marketplace will not refresh
/plugin marketplace update ezquill
→ 1 marketplace could not be refreshedThat message is about a directory on your own machine, not about GitHub and
not about this repository. A marketplace is an ordinary git clone at
~/.claude/plugins/marketplaces/ezquill, and "refresh" is a git operation
inside it. When the clone gets into a state git will not fast-forward out of,
the refresh fails and the message says none of that.
First, the reassuring part: a stale manifest is not stale tools. The plugin
declares a URL. Every tool, and every fix, comes from the hosted connector at
https://mcp.ezquill.com/mcp, so a marketplace that will not update costs you a
version number rather than a capability — the next session to connect gets the
current tools regardless. (A session already open is a separate matter, and not
this one: see "Updating the plugin does not update an open session's tools".)
Check what you are actually talking to — it needs no token:
curl https://mcp.ezquill.com/version
→ {"name":"ezquill-mcp-server","version":"0.4.0","sha":"78c0d74"}A 404 there is itself an answer: /version arrives in 0.4.0, so a
connector that does not serve it predates that release. From 0.4.0 the server
also names its version in the instructions it sends at the start of every
session, so you can simply ask the agent which connector it is talking to.
Tell a local problem apart from a network one before changing anything:
git ls-remote https://github.com/EasyModeOnly/ezquill-mcp-serveroutcome | means |
a list of refs | GitHub is fine and reachable. The problem is the local clone — carry on below. |
hangs, or a TLS/DNS/proxy error | Network or proxy. Fixing the clone will not help. |
| An auth or SSO problem reaching a repo that is in fact public — check for a credential helper or a corporate proxy rewriting the request. |
Then look at the clone itself:
git -C ~/.claude/plugins/marketplaces/ezquill status -sb## main...origin/main [ahead 30] is the tell, and it is what this machine
actually showed. A clone that has only ever been pulled from cannot be ahead of
anything. It means the remote-tracking ref is stale — here origin/main was
still pointing at the 0.1.1 release merge while the checkout had moved on — so
git compares against a commit from months ago and reports the difference as
local work it must not discard. Divergence, a detached HEAD, or a genuine local
modification produce the same refusal.
The recovery, which is cheap because there is nothing in that clone worth keeping — it is a copy of a public repository, and no configuration of yours lives in it:
/plugin marketplace remove ezquill
/plugin marketplace add EasyModeOnly/ezquill-mcp-server
/plugin install ezquill@ezquill
/reload-pluginsThen reconnect the server with /mcp — see "Updating the plugin does not
update an open session's tools" above for why that step is not optional, and
why none of the four commands before it is what fetches the tool list.
Releasing
A release has two destinations, and neither is the plugin:
workflow | ships | to |
Release (npm package + remote connector) — | the server package | npm, for people running it themselves |
Deploy remote connector (Cloud Run) — | the same code as a container |
|
The plugin is plugin/.claude-plugin/plugin.json: a manifest pointing at
the remote connector's URL, installed from this repository. Nothing publishes
it, and its contents only change when the URL or OAuth client does — which is
why a fix reaches plugin users through a deploy, not a plugin update.
Cut a release with npm version
npm version minor # or patch / major
git push --follow-tagsUse it rather than editing package.json by hand. A version lifecycle
script rewrites plugin/.claude-plugin/plugin.json,
.claude-plugin/marketplace.json and __tests__/tool-surface.json and stages
them, so all four move in the release commit. Tests fail if they disagree, so a
hand-edited bump is caught rather than shipped — but it is caught on your
branch, which is a worse place to find out than not having to think about it.
Why the plugin version has to move. 0.3.0 added three outline actions with
both manifests left at 0.2.1. Nothing on any machine had a signal: /plugin marketplace update had nothing to show, and the new actions reached whoever
happened to reconnect for unrelated reasons — Claude Code went on serving the
old tool definitions on two machines for a day, with nothing red anywhere. The
server was right, the package was right, and the only thing wrong was a number
in a file that describes neither.
And __tests__/tool-surface.json is what makes that stick. It records the
tool names, action enums and top-level parameter names the released version
serves. Change any of them and the test fails; npm run fingerprint refuses to
re-record until the version has been bumped, so the only way back to green is
the release that tells installed machines to look again. It deliberately
ignores descriptions and types — a test that fails for a reworded sentence gets
regenerated without being read, which is the reflex that defeats it on the day
it matters.
publish.yml keeps its filename because npm's trusted publisher is configured
against it by name.
.github/workflows/publish.yml runs on every push to main and decides what
to do by asking the registry — npm view <name>@<version> — rather than by
diffing HEAD against HEAD^. Fixing a broken publish necessarily adds a
commit, and adding a commit is exactly what makes those two carry the same
version: a diff-based workflow skips the fix and a re-run replays the bug. So
most merges reach this workflow and correctly do nothing. Bump the version in
package.json and it publishes; that is the entire release process.
The same bump deploys the remote connector — the Cloud Run service every plugin and claude.ai connection talks to — to dev, then to prod once dev has deployed and verified. It is keyed on the registry decision, not on the npm approval below, since the remote connector is not installed from npm. So a fix that should reach plugin users needs a version bump, exactly as it does for npm users; a merge without one ships nowhere.
If a deploy job fails after the version was staged, the next merge will find the version already staged and deploy nothing. Re-run the failed jobs in that run, or dispatch Deploy remote connector (Cloud Run) by hand, which is also how to redeploy without a release.
While a staged version waits for approval, later merges stay green and release nothing: npm refuses to stage the same version twice, and the workflow reads that refusal as "awaiting approval" rather than failing.
It uses npm Trusted Publishing — an OIDC token minted per run, no npm token stored in this repository — and it stages rather than publishes:
npm stage list @ezquill/mcp-server
npm stage approve <stage-id> # takes 2FA; this is what makes it installable
npm stage reject <stage-id>The approval gate is deliberately outside GitHub. A GitHub environment approval sits in the same trust domain as the token and the workflow doing the publishing, so whoever compromises one can usually satisfy the other; npm's 2FA approval is the one gate a compromised GitHub credential cannot pass.
The consequence to plan around: the version in main is not installable
until somebody approves it. Anything that checks whether the pinned version
is published must warn, not fail — a red run for a gap that is expected
trains people to ignore red.
The first publish is manual, once
A trusted publisher is configured in a package's settings on npmjs.com, and a package has to exist to have settings. So the bootstrap is:
npm publishonce, by hand, from a maintainer account in theezquillorg.publishConfig.accessispublic, so no flag is needed — without it a scoped package defaults to restricted and fails with a 402 that reads like a billing problem.On npmjs.com, add a trusted publisher for the package naming this repository and
publish.yml.Optionally restrict token-based publishing entirely, which leaves the trusted publisher as the only way in.
After that this workflow owns every release and nothing is published by hand again.
Available Tools
11 toolsauthenticateA
Sign in to ezQuill. Returns a link for the person to open. Call this only if a tool reports NOT_AUTHENTICATED and no link was already given.
| Name | Required | Description | Default |
|---|---|---|---|
| includeDelete | No | Also request permission to delete. Off by default — ask the person first. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotations only indicate that this is not read-only and is open-world, but the description adds meaningful behavioral context: it returns a link for a person to open rather than directly authenticating the agent, and it should only be used when no link has already been provided. This clarifies the interactive nature of the operation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences deliver the core purpose, the output, and the precise usage condition with no wasted words. The critical 'only if' guidance is placed prominently.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple one-parameter authentication tool with a helpful schema and clear annotations, the description covers what the tool does, what it returns, and exactly when to invoke it. Nothing essential is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema already provides full coverage for the single parameter, including its meaning and default behavior. The description does not repeat parameter details, but that is acceptable since schema coverage is 100%; the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: 'Sign in to ezQuill.' It also explains the tool's immediate output ('Returns a link for the person to open'), making it clearly distinct from siblings like sign_out and the project-reading tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives an explicit condition for when to call the tool: 'Call this only if a tool reports NOT_AUTHENTICATED and no link was already given.' This also states an exclusion, preventing unnecessary repeated calls when a link is already available.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_entityBRead-only
One character, place or note in full: its profile, who and what it is connected to, and every scene it appears in.
| Name | Required | Description | Default |
|---|---|---|---|
| entityId | Yes | ||
| projectId | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotation readOnlyHint=true is present, so the description's job is lighter. It adds context about what is returned (profile, connections, scenes) but does not disclose potential size limits, pagination, or error behaviors. The description adds some value but not rich behavioral context.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The entire description is a single, front-loaded sentence that clearly states the purpose and scope without waste. It is concise and immediately actionable.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers the main output (full entity with profile, connections, scenes) but omits the necessity of projectId and the semantics of entityId. With no output schema, the description should also mention what the return format looks like, but it only lists content categories. It is adequate but leaves gaps.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must fully compensate for the two parameters (entityId, projectId). It does not mention them at all, leaving an agent to infer their roles from names alone. This is a critical gap for a tool with zero schema documentation.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb (get) and resource (entity, defined as character, place, or note) and details the return content: profile, connections, and every scene. This distinguishes it from siblings like get_project, read_scene, and list_entities, making the tool's purpose unmistakable.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage for retrieving full entity details as opposed to search or list operations, but it does not explicitly name alternatives or state when not to use this tool. There is no guidance on when to prefer get_entity over search_project or get_outline.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_outlineARead-only
The structure of a project: its parts, chapters and scenes, with status and word counts. Returns no prose — use read_scene for that.
| Name | Required | Description | Default |
|---|---|---|---|
| parentId | No | Limit to one branch. Omit for the whole binder. | |
| projectId | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The readOnlyHint annotation already establishes the safety profile. The description adds behavioral context by specifying what the response contains (parts, chapters, scenes, status, word counts) and what it deliberately omits (prose), which goes beyond the annotation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, with the core purpose front-loaded and the exclusion/alternative in the second sentence. There is no filler or repetition of schema content.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only, two-parameter tool, the description plus parentId schema note cover the essential call context. It explains the return shape and the no-prose boundary, though it leaves response format details (e.g., how status/word counts are nested) unspecified.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 50%: parentId is documented ('Limit to one branch. Omit for the whole binder') but projectId is not. The tool description does not add parameter detail, so it does not compensate for the undocumented required parameter; still, the simple parameter names plus the schema's parentId note make this minimally adequate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states the resource precisely: 'the structure of a project: its parts, chapters and scenes, with status and word counts.' It also explicitly distinguishes itself from read_scene by noting it 'returns no prose,' so an agent can tell what this tool is for at a glance.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives an explicit when-not and alternative: 'Returns no prose — use read_scene for that.' This directly tells the agent when not to call get_outline and which sibling to choose for content, which is exactly the kind of routing guidance needed.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_projectARead-only
One project in detail: what it is, how far along it is, and its story-world premise.
| Name | Required | Description | Default |
|---|---|---|---|
| projectId | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare readOnlyHint=true, so the description doesn't need to restate safety. It adds useful context about the returned data (identity, progress, premise), but does not disclose error behavior, missing-project handling, or response structure.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
One short, front-loaded sentence that immediately communicates the tool's scope and then lists what the detail includes. No redundant words or filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple single-parameter read tool with readOnlyHint=true, the description conveys enough to select and call it correctly. It tells the agent what kind of detail will come back, though it leaves out explicit mention of the projectId parameter and any error or not-found behavior.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The single parameter projectId is self-explanatory from the name, and the tool name makes its role clear. However, the description itself does not mention projectId or add any meaning beyond the schema, so it doesn't fully compensate for the 0% schema description coverage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states the resource ('project') and the action ('in detail'), and specifies the returned content: what it is, progress, and story-world premise. It implicitly distinguishes from list_projects by focusing on a single project, though it doesn't explicitly name a sibling.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The phrase 'One project in detail' implies use when a single project's full details are needed rather than a list or search result. However, there is no explicit guidance about when not to use it or which alternative to choose.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_timelineARead-only
The project timeline. Story mode is chronology inside the fiction; project mode is the writer's own milestones.
| Name | Required | Description | Default |
|---|---|---|---|
| mode | No | Omit for both. | |
| nodeId | No | Only events attached to this node. | |
| projectId | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, so the safety profile is covered. The description adds semantic behavior by distinguishing the two timeline modes, but it does not disclose operational details like pagination, ordering, or whether the result includes events, milestones, or both. For a simple read-only tool this is a minor gap.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences with no filler: the first names the resource, the second explains the key mode distinction. Every sentence contributes to correct usage.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
This is a simple read-only tool with one required parameter and a clear mode distinction. The description plus schema cover mode and node filtering. There is no output schema, so the return shape is left implicit, but 'timeline' plus the mode explanation makes the expected content reasonably inferable.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema already documents mode ('Omit for both') and nodeId ('Only events attached to this node'). The description adds meaningful value by explaining what story vs project mode actually represent, which helps the agent choose the right value. projectId is not described, but it is self-evident from the tool name and required field.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description identifies the resource as the project timeline and clearly explains the two modes: story mode is chronology inside the fiction, project mode is the writer's own milestones. It lacks an explicit verb like 'retrieve' or 'get', but the resource and mode semantics are unambiguous enough for an agent to understand what the tool returns.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The mode definitions give useful context for choosing between story and project views, and the schema adds 'Omit for both.' However, the description does not explicitly state when to use this tool instead of siblings like get_project or get_outline, nor does it mention any exclusions or alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_entitiesARead-only
The project's story world: characters, locations, factions, items, and research notes. Filter by kind, by tag, or by which scene they appear in.
| Name | Required | Description | Default |
|---|---|---|---|
| tag | No | ||
| kind | No | character, location, faction, item, source, term, research, … | |
| role | No | Used with appearsInNode: pov, present, setting, mentioned, cited. Together these answer "who is the POV of this scene". | |
| search | No | Match against the name. | |
| projectId | Yes | ||
| appearsInNode | No | Only entities linked to this node. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotations already declare readOnlyHint=true, so the read-only nature is covered. The description adds useful scope about which entity types are included and what filter dimensions exist, but it does not disclose output shape, ordering, pagination, or any other runtime behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences with no filler. The entity scope is front-loaded and the filter capabilities are stated compactly. Every phrase contributes to understanding the tool.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only listing tool, the description plus schema give an agent enough to understand the purpose, required projectId, and primary filter options. Some details like pagination or return value shape are absent, but they are not critical enough to make the tool hard to invoke correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 67%, and the description adds some meaning by mapping 'scene' to appearsInNode and introducing 'tag' and 'kind' as filters. However, it does not clarify the undocumented tag parameter or add much beyond what the schema already provides for role, search, and appearsInNode.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names the resource ('the project's story world') and the entity categories it covers, and explains that results can be filtered by kind, tag, or scene. It is clear, but it does not use an explicit verb like 'list' and does not explicitly differentiate itself from the sibling get_entity tool.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies when to use the tool: when you need story-world entities filtered by kind, tag, or scene. However, it does not state when to prefer this over get_entity or any other sibling, and it offers no exclusions or alternative routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_feedbackARead-only
Open comment threads and suggested edits on a project. Read this before revising a chapter — it is what the writer's collaborators have already said about it.
| Name | Required | Description | Default |
|---|---|---|---|
| nodeId | No | Only threads on this node. | |
| projectId | Yes | ||
| includeResolved | No | Default false. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The readOnlyHint annotation already communicates safety. The description adds useful context about the returned content ('comment threads and suggested edits') and the collaborative nature of the data, but it does not disclose behaviors like default resolved filtering or pagination. This is acceptable but not exceptional beyond the annotation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences with no wasted words. The core behavior is front-loaded, and the second sentence gives practical guidance without redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only list tool with three parameters and no output schema, the description provides enough context for correct invocation: it names the resource, scope, and timing. A small gap is that it doesn't mention resolved-thread behavior or return format, but these are minor and partially covered by the schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 67%, with nodeId and includeResolved already described in the schema. The description does not add parameter-specific semantics, though it does clarify that the data is attached to a project/chapter context. With partial schema coverage, this is adequate but could do more to explain the relationship between projectId and nodeId.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('Open') with a clear resource ('comment threads and suggested edits on a project'). This is distinct from all sibling tools, none of which are feedback-focused, so an agent can immediately recognize what this tool does.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It provides an explicit usage trigger: 'Read this before revising a chapter.' This tells the agent when to call the tool, though it does not state when not to use it or name an alternative. The sibling list contains no other feedback-specific tool, so no alternative comparison is necessary.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_projectsARead-only
List the writer's projects. Start here: every other tool needs a projectId.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Default 50. | |
| search | No | Match against the title. | |
| shared | No | List projects shared WITH the writer instead of ones they own. | |
| status | No | Filter by project status. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, and the description's 'List' is consistent with that. The description adds the valuable workflow context that this tool is the starting point and that other tools depend on its output (projectId). This is beyond the annotation and helps an agent understand its role in a multi-step process.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, tightly packed sentence that leads with the core purpose and immediately follows with the critical usage note. There is zero redundancy; every word earns its place. It is optimally concise and front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers purpose and the entry-point role, but it does not mention the return format or that the response contains project IDs, which is essential for an agent to proceed with other tools. Since there is no output schema, the description carries the burden of describing the result, and it does not. For a simple list tool this is a gap, though the name hints at a list.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so each parameter (limit, search, shared, status) already has an explanatory description. The tool description adds no parameter-specific details, so the baseline of 3 is appropriate—the schema carries the semantic weight.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb 'List' and resource 'the writer's projects', and crucially adds 'Start here: every other tool needs a projectId.' This clearly distinguishes it from siblings like get_project and search_project by positioning it as the entry point. It leaves no ambiguity about what the tool does.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The phrase 'Start here' gives explicit when-to-use guidance, and the statement 'every other tool needs a projectId' implies that this tool is the prerequisite for others. It does not explicitly mention alternatives like search_project for filtered discovery, but the context is strong. It lacks an explicit 'when not to use' clause, hence a 4.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
read_sceneARead-only
Read one scene: its prose, its outline plan, and which characters and places appear in it. One node at a time — to find a scene, use search_project or get_outline.
| Name | Required | Description | Default |
|---|---|---|---|
| nodeId | Yes | From get_outline or a search result. | |
| projectId | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The readOnlyHint annotation already signals a safe read operation, and the description adds useful behavioral context: it is scoped to a single node and returns specific content types. It does not mention errors or permissions, but the annotation plus the explicit single-node constraint covers the essential behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two tight sentences: the core action and content are front-loaded, followed by the single-node limitation and routing advice. There is no filler or redundant restating of the tool name.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers what is returned, how to obtain the scene identifier, and the single-node constraint. With readOnlyHint declaring safety and no output schema, this is close to complete for a simple read tool; the main residual gap is the meaning of projectId.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 50%, with only nodeId having a description. The description adds context by indicating nodeId comes from get_outline or a search result, which helps an agent populate it correctly. However, projectId remains undocumented in both the schema and description, so it only partially compensates.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb and resource ('Read one scene') and enumerates the returned contents: prose, outline plan, and characters/places. It also distinguishes itself from discovery tools like search_project and get_outline, making its purpose unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly tells the agent how to find a scene ('use search_project or get_outline') and sets a clear expectation that the tool reads only one node at a time. It does not list explicit when-not-to-use cases, but the stated scope and routing are sufficient for correct selection.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_projectARead-only
Search a project semantically — by meaning, not keywords. Use this to find where something is discussed when you do not know what words the writer used. Results are ordered by similarity; there is no relevance score and no threshold.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Default 10, maximum 50. | |
| query | Yes | A question or a description of what you are looking for. | |
| projectId | Yes | ||
| sourceTypes | No | Narrow the search. Omit to search everything. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already indicate readOnlyHint=true, and the description adds useful behavioral context: results are ordered by similarity, with no relevance score and no threshold. This goes beyond the annotation and helps the agent set expectations. It doesn't cover all edge cases (e.g., empty results, pagination), but for a read-only search it is reasonably transparent.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences with no filler. The core semantic-search purpose and the key behavioral caveats (ordering, no threshold) are front-loaded. Every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the lack of an output schema, the description could clarify what the results actually contain (e.g., a list of matches with snippets). It does mention ordering and lack of threshold, but not the result shape. However, since sibling tools like get_entity and read_scene likely clarify the object types, and the annotations cover safety, the description is reasonably complete for the agent's needs.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 75%, which is moderate. The description does not add any parameter-specific details beyond what the schema already provides (e.g., limit default, query format, sourceTypes narrowing). Since it neither compensates for a low-coverage schema nor adds value on top, a baseline of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb+resource ('Search a project semantically') and clearly distinguishes from keyword search by emphasizing 'by meaning, not keywords'. It also explains the use case ('when you do not know what words the writer used'), making the purpose unambiguous and distinct from sibling list/get tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It provides an explicit condition for use ('when you do not know what words the writer used'), which tells the agent when to choose this over other tools. However, it does not explicitly mention when not to use it or name alternative tools, so it stops short of full when/when-not guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
sign_outA
Forget the stored ezQuill sign-in on this machine.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotations only indicate readOnlyHint=false, so the description carries the burden of explaining the mutation. It does this well by specifying the stored sign-in and the machine-local scope, which clarifies what state is affected and that this is not a global revocation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single, front-loaded sentence with no filler. Every word adds meaning: the action, the entity, and the machine-local scope.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a no-parameter, side-effect tool, the description is sufficiently complete: it states what is forgotten and where. It does not mention return values or behavior when no sign-in exists, but these are minor for such a simple operation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, so the description does not need to explain parameter meaning. The baseline of 4 applies because there is nothing for the description to add beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('Forget') and resource ('stored ezQuill sign-in'), and clarifies the scope ('on this machine'). It clearly contrasts with the sibling tool authenticate, so an agent can distinguish sign_out from it.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage: call this when you want to clear the locally stored sign-in. However, it does not explicitly state when not to use it or mention authenticate as the alternative for signing in, leaving some routing to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
11 tool updates
v0.1.0- First observed
authenticate - First observed
get_entity - First observed
get_outline - First observed
get_project - First observed
get_timeline - First observed
list_entities - First observed
list_feedback - First observed
list_projects - First observed
read_scene - First observed
search_project - First observed
sign_out
TDQS
Scored across 11 tools
Each tool targets a clearly distinct resource or action: project listing/detail/search, outline vs. scene, entity list/detail, timeline, feedback, and auth. There is little risk of an agent selecting the wrong tool for a given intent.
All tools use a consistent lowercase snake_case verb_noun pattern: list_projects, get_project, search_project, get_outline, read_scene, list_entities, get_entity, get_timeline, list_feedback. authenticate and sign_out are the only exceptions but they are auth actions and still read predictably.
Eleven tools is well within the ideal range for this domain. Each tool covers a distinct need without unnecessary duplication, and the auth tools are justified for a service that requires sign-in.
The read-side surface is thorough: projects, outline, scenes, entities, timeline, and feedback are all covered. The only notable gap is the absence of any create/update/delete operations, but that appears intentional for a read-only writing-project assistant.
Maintenance
Related MCP Connectors
Connect QuickBooks Online to AI agents with secure read or write access across multiple companies.
Safe write access for AI agents. Every change is kept, attributed, and can be undone.
- OpenOakOAuthorg.openoak
Secure AI access to OpenOak tasks, notes, and Kanban boards.
- HAVNOAuthapp.havnre
Read-only AI access to HAVN properties, leads, tasks, files, media, and analytics.
Related MCP Servers
- AlicenseAqualityNot gradedmaintenanceEnables AI assistants to read, write, organize, search, and compile Scrivener writing projects. Supports manuscript editing, document management, consistency checking, and PDF export for writers using Scrivener 3.228 npm-

Echoes MCP Serverofficial
AlicenseNot gradedqualityAmaintenanceEnables AI integration with the Echoes storytelling platform, providing narrative knowledge graph extraction, semantic search, and arc isolation.27 npmMIT
AutoRFP.ai MCP Serverofficial
AlicenseNot gradedqualityDmaintenanceEnables AI assistants to connect to AutoRFP.ai and query RFP projects, requirements, tags, and approved content library with read-only access.1MIT- AlicenseNot gradedqualityBmaintenanceEnables collaborative manuscript editing where an AI agent reads the page, proposes changes scored against the writer's voice, and waits for acceptance or rejection before any text is committed.MIT