Update docs and solution file for the stdio MCP server's removal
CI / build-and-push (push) Successful in 47s
CI / deploy (push) Successful in 10s

The prior commit's git add silently dropped these five files because
one path in the same invocation didn't exist. Docs, solution file, and
example config still needed the paired update: Novelly.slnx drops the
Novelly.Mcp project entry, README and CLAUDE.md describe MCP as an
in-API HTTP endpoint instead of a stdio binary, .mcp.json.example uses
the type: http shape, and outline-importer.md's tool references are
fixed to real tool names.
This commit is contained in:
James Wampler
2026-08-21 11:00:25 -07:00
parent 2d6bb9fc57
commit e1df79b31e
5 changed files with 34 additions and 42 deletions
+5 -5
View File
@@ -1,7 +1,7 @@
---
name: outline-importer
description: Imports an author's existing novel outline (chapters + character dossiers, in the Kingdom Sleeps folder format) into a Novelly project over the MCP server. Invoke explicitly with a source folder path — this agent does not run proactively.
tools: Read, Glob, Grep, Write, mcp__novelly__list_projects, mcp__novelly__get_project_brief, mcp__novelly__create_project, mcp__novelly__update_project_brief, mcp__novelly__list_chapters, mcp__novelly__get_chapter, mcp__novelly__create_chapter, mcp__novelly__update_chapter, mcp__novelly__get_chapter_outline, mcp__novelly__create_beat, mcp__novelly__update_beat, mcp__novelly__list_characters, mcp__novelly__get_character, mcp__novelly__create_character, mcp__novelly__update_character, mcp__novelly__get_character_arc, mcp__novelly__add_arc_stage, mcp__novelly__list_tags
tools: Read, Glob, Grep, Write, mcp__novelly__list_novels, mcp__novelly__get_novel_brief, mcp__novelly__create_novel, mcp__novelly__update_novel_brief, mcp__novelly__list_chapters, mcp__novelly__get_chapter, mcp__novelly__create_chapter, mcp__novelly__update_chapter, mcp__novelly__get_chapter_outline, mcp__novelly__create_beat, mcp__novelly__update_beat, mcp__novelly__list_characters, mcp__novelly__get_character, mcp__novelly__create_character, mcp__novelly__update_character, mcp__novelly__get_character_arc, mcp__novelly__add_arc_stage, mcp__novelly__list_tags
model: inherit
---
@@ -101,9 +101,9 @@ in your final report.
Do not skip ahead — each pass depends on ids the previous one minted. If you're picking up a
resumed run, jump straight to the first incomplete pass.
**0. Preflight.** Call `list_projects` to confirm the API is reachable at all — if this fails, stop
and tell the user to start the API (`ASPNETCORE_URLS=http://localhost:5080 dotnet run --project src/Novelly.Api`)
and that `.mcp.json` must point at a published `Novelly.Mcp` binary. Glob the source root for
**0. Preflight.** Call `list_novels` to confirm the API is reachable at all — if this fails, stop
and tell the user to start the API (`ASPNETCORE_URLS=http://localhost:5080 dotnet run --project src/Novelly.Api`).
Glob the source root for
`outline.md`, `outlines/*.md` or `chapters/*.md`, and `characters/*.md`. If `outline.md` is
missing, stop — that's the one file every pass depends on. Report the file counts found before
proceeding.
@@ -111,7 +111,7 @@ proceeding.
**1. Project.** Skip if `completedPasses` already has `"project"`. Read `outline.md`. Its heading is
`# Outline — <Title> (<Author>)` or similar — parse title and author out of it; if there's no
author, leave it null. The paragraph(s) before the chapter table are the blurb — pass as `notes`
argument to `create_project` (there's no dedicated blurb field; `synopsis` may be filled in later
argument to `create_novel` (there's no dedicated blurb field; `synopsis` may be filled in later
by the author). Record `projectId` in the ledger, mark `"project"` complete.
**2. Characters — dossier fields only, not arcs yet.** Skip files whose name (matched
+4 -4
View File
@@ -1,10 +1,10 @@
{
"mcpServers": {
"novelly": {
"command": "./mcp-server/Novelly.Mcp",
"env": {
"NOVELLY_API_URL": "http://localhost:5080",
"NOVELLY_API_KEY": "<matches the API's Auth:ServiceApiKey user secret>"
"type": "http",
"url": "http://localhost:5080/mcp",
"headers": {
"X-Novelly-Api-Key": "<matches the API's Auth:ServiceApiKey user secret>"
}
}
}
+5 -6
View File
@@ -8,13 +8,12 @@ Novelly: software plan + write novel. ASP.NET Core 10, C#, TypeScript, React, .N
## Structure
- `src/Novelly.Api/` — whole back end, organised by feature. One folder per feature holds
entity, DTOs, service, endpoints together: `Novels/`, `Characters/`, `Chapters/`, `Beats/`,
`Scenes/`, `Tags/`, `Agent/`. `Common/` holds what crosses features; `Data/` holds
`DbContext` + EF migrations.
- `src/Novelly.Api/` — whole back end, organised by feature, plus the MCP endpoint. One folder
per feature holds entity, DTOs, service, endpoints together: `Novels/`, `Characters/`,
`Chapters/`, `Beats/`, `Scenes/`, `Tags/`, `Agent/`, `Mcp/`. `Common/` holds what crosses
features; `Data/` holds `DbContext` + EF migrations.
- `src/Novelly.AppHost/` — .NET Aspire orchestration; run this to bring up API + web client
- `src/Novelly.ServiceDefaults/` — shared Aspire wiring: OpenTelemetry, health checks, service discovery
- `src/Novelly.Mcp/` — MCP stdio server
- `src/Novelly.Web/` — React + Vite client
- `tests/` — test suite
- `docs/` — documentation
@@ -86,7 +85,7 @@ Build + tests passing ≠ working. Anything touching endpoint, agent loop, or MC
Vite dev server on :5173, dashboard for logs + traces
- API alone: `ASPNETCORE_URLS=http://localhost:5080 dotnet run --project src/Novelly.Api`, then exercise route with curl
- Web alone: `cd src/Novelly.Web && npm run dev` — proxies `/api` to :5080
- MCP: build it, then drive over stdio JSON-RPC (`initialize``notifications/initialized``tools/list``tools/call`)
- MCP: with the API running, drive `/mcp` over HTTP (`initialize``notifications/initialized``tools/list``tools/call`) — Streamable HTTP, so responses are SSE-framed and requests need `Accept: application/json, text/event-stream`
Several real bugs here — SQLite refusing ORDER BY DateTimeOffset, agent's model client throwing at construction + taking read-only endpoints down with it — passed build + test suite, only showed up when app actually ran.
-1
View File
@@ -8,7 +8,6 @@
<Folder Name="/src/">
<Project Path="src/Novelly.Api/Novelly.Api.csproj" />
<Project Path="src/Novelly.AppHost/Novelly.AppHost.csproj" />
<Project Path="src/Novelly.Mcp/Novelly.Mcp.csproj" />
<Project Path="src/Novelly.ServiceDefaults/Novelly.ServiceDefaults.csproj" />
<Project Path="src/Novelly.Web/Novelly.Web.esproj">
<Build />
+20 -26
View File
@@ -6,22 +6,21 @@
Software for planning and writing a novel. You outline the book, keep character
dossiers, break chapters into scenes, and draft prose — with a Claude-powered agent
embedded in the app that can read and edit the same data you can, and an MCP server that
exposes that data to Claude Code, Claude Desktop, or any other MCP client.
embedded in the app that can read and edit the same data you can, and an MCP endpoint that
exposes that same data to Claude Code, Claude Desktop, or any other MCP client.
The point of the three-way arrangement is that there is exactly one source of truth. The
React UI, the embedded agent, and the MCP server all go through the same REST API, so an
edit made from a chat in Claude Code and an edit made by typing in the browser are the
same edit.
React UI's REST calls, the embedded agent, and MCP clients all resolve to the same
application services in-process, so an edit made from a chat in Claude Code and an edit
made by typing in the browser are the same edit.
## Stack
| Piece | Built with |
|---|---|
| `Novelly.Api` | ASP.NET Core 10 minimal APIs, EF Core 10 + SQLite, Anthropic SDK, OpenAPI |
| `Novelly.Api` | ASP.NET Core 10 minimal APIs, EF Core 10 + SQLite, Anthropic SDK, OpenAPI, MCP over Streamable HTTP (`ModelContextProtocol.AspNetCore`) |
| `Novelly.AppHost` | .NET Aspire orchestration for the API and the web client |
| `Novelly.ServiceDefaults` | Shared OpenTelemetry, health checks and service discovery |
| `Novelly.Mcp` | MCP stdio server (`ModelContextProtocol`) |
| `Novelly.Web` | React 19, TypeScript, Vite, TanStack Query, Tailwind v4 |
The back end is one project organised by feature, not by layer. Each feature folder —
@@ -192,19 +191,10 @@ A few deliberate choices worth knowing about:
## The MCP server
A stdio MCP server exposing 45 tools over the same REST API. It holds no domain logic of
its own — it is a second front end, not a second implementation.
Build it, then point your MCP client at the produced binary:
```bash
./scripts/publish-mcp.sh
```
Aspire does not run or manage this process — it's a separate stdio subprocess your MCP
client spawns directly, so nothing rebuilds it automatically. Re-run the script (and
reconnect your MCP client) after pulling changes that touch `src/Novelly.Mcp`, or it keeps
serving whatever was published last, including against a stale auth contract.
The API itself serves MCP over Streamable HTTP at `POST /mcp`, exposing 45 tools that call
the same application services the REST endpoints and the embedded web agent call — it holds
no domain logic of its own, and there's nothing to build or publish separately. The API
process just needs to be running; there's no separate subprocess to keep in sync with it.
Copy `.mcp.json.example` to `.mcp.json` (gitignored, since it carries your API key) and
fill in the key:
@@ -213,10 +203,10 @@ fill in the key:
{
"mcpServers": {
"novelly": {
"command": "/absolute/path/to/mcp-server/Novelly.Mcp",
"env": {
"NOVELLY_API_URL": "http://localhost:5080",
"NOVELLY_API_KEY": "<matches the API's Auth:ServiceApiKey user secret>"
"type": "http",
"url": "http://localhost:5080/mcp",
"headers": {
"X-Novelly-Api-Key": "<matches the API's Auth:ServiceApiKey user secret>"
}
}
}
@@ -225,8 +215,12 @@ fill in the key:
The API must be running, with `Auth:ServiceApiKey` set (e.g. via
`dotnet user-secrets set Auth:ServiceApiKey <key> -p src/Novelly.Api`) to the same value
as `NOVELLY_API_KEY` above. If the API is not running, or the key is missing or mismatched,
the tools say so in a message the model can act on rather than failing opaquely.
as the `X-Novelly-Api-Key` header above. If the API is not running, or the key is missing or
mismatched, the request 401s.
Tool argument names are camelCase, matching the REST API and every other MCP argument name
this project has ever used. `create_novel` called over MCP is owned by the seeded service
user (an Admin), not whichever person is signed into the web app.
### Importing an existing outline