@hanna84/mcp-writing 1.11.5 → 1.11.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/index.js +11 -11
  3. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -4,11 +4,21 @@ All notable changes to this project will be documented in this file. Dates are d
4
4
 
5
5
  Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
6
6
 
7
+ #### [v1.11.6](https://github.com/hannasdev/mcp-writing.git
8
+ /compare/v1.11.5...v1.11.6)
9
+
10
+ - fix: improve MCP discoverability hints and tool guidance [`#65`](https://github.com/hannasdev/mcp-writing.git
11
+ /pull/65)
12
+
7
13
  #### [v1.11.5](https://github.com/hannasdev/mcp-writing.git
8
14
  /compare/v1.11.4...v1.11.5)
9
15
 
16
+ > 24 April 2026
17
+
10
18
  - Add Copilot instructions and contribution workflow [`#64`](https://github.com/hannasdev/mcp-writing.git
11
19
  /pull/64)
20
+ - Release 1.11.5 [`9b72b8b`](https://github.com/hannasdev/mcp-writing.git
21
+ /commit/9b72b8b827ccc7b9ab7532fbb355ab5894b56a59)
12
22
 
13
23
  #### [v1.11.4](https://github.com/hannasdev/mcp-writing.git
14
24
  /compare/v1.11.3...v1.11.4)
package/index.js CHANGED
@@ -1296,7 +1296,7 @@ function createMcpServer() {
1296
1296
 
1297
1297
  s.tool(
1298
1298
  "get_async_job_status",
1299
- "Get status and result for an asynchronous job started by async tools such as import_scrivener_sync_async, merge_scrivener_project_beta_async, or enrich_scene_characters_batch.",
1299
+ "Get status and result for an asynchronous job started by async tools such as import_scrivener_sync_async, merge_scrivener_project_beta_async, or enrich_scene_characters_batch. Use this to poll job progress after receiving a job_id. Common next step: if status is still running, call this tool again; if completed, inspect result and optionally run sync().",
1300
1300
  {
1301
1301
  job_id: z.string().describe("Job ID returned by an async start tool."),
1302
1302
  include_result: z.boolean().optional().describe("If true (default), includes completed result payload when available."),
@@ -1305,7 +1305,7 @@ function createMcpServer() {
1305
1305
  pruneAsyncJobs();
1306
1306
  const job = asyncJobs.get(job_id);
1307
1307
  if (!job) {
1308
- return errorResponse("NOT_FOUND", `Async job '${job_id}' was not found. It may have expired.`);
1308
+ return errorResponse("NOT_FOUND", `Async job '${job_id}' was not found. It may have expired. Hint: call list_async_jobs to see currently tracked job IDs.`);
1309
1309
  }
1310
1310
  return jsonResponse({ ok: true, async: true, job: toPublicJob(job, include_result) });
1311
1311
  }
@@ -1313,7 +1313,7 @@ function createMcpServer() {
1313
1313
 
1314
1314
  s.tool(
1315
1315
  "list_async_jobs",
1316
- "List asynchronous jobs currently known to this server.",
1316
+ "List asynchronous jobs currently known to this server. Use this when you lost a job_id or need a dashboard view of running/completed jobs. Returns an object envelope containing a jobs array of job objects sorted by newest first.",
1317
1317
  {
1318
1318
  include_results: z.boolean().optional().describe("If true, includes completed result payloads."),
1319
1319
  },
@@ -1328,7 +1328,7 @@ function createMcpServer() {
1328
1328
 
1329
1329
  s.tool(
1330
1330
  "cancel_async_job",
1331
- "Cancel a running asynchronous job.",
1331
+ "Cancel a running asynchronous job. Use this when an import/merge/batch run was started with overly broad scope or is no longer needed. Returns the updated job state; cancellation is cooperative and may transition through 'cancelling' before 'cancelled'.",
1332
1332
  {
1333
1333
  job_id: z.string().describe("Job ID returned by an async start tool."),
1334
1334
  },
@@ -1336,7 +1336,7 @@ function createMcpServer() {
1336
1336
  pruneAsyncJobs();
1337
1337
  const job = asyncJobs.get(job_id);
1338
1338
  if (!job) {
1339
- return errorResponse("NOT_FOUND", `Async job '${job_id}' was not found. It may have expired.`);
1339
+ return errorResponse("NOT_FOUND", `Async job '${job_id}' was not found. It may have expired. Hint: call list_async_jobs to find active IDs.`);
1340
1340
  }
1341
1341
 
1342
1342
  if (job.status !== "running") {
@@ -1461,7 +1461,7 @@ function createMcpServer() {
1461
1461
 
1462
1462
  const rows = db.prepare(query).all(...params);
1463
1463
  if (rows.length === 0) {
1464
- return errorResponse("NO_RESULTS", "No scenes match the given filters.");
1464
+ return errorResponse("NO_RESULTS", "No scenes match the given filters. Hint: broaden filters or call search_metadata with a keyword first.");
1465
1465
  }
1466
1466
 
1467
1467
  const staleCount = rows.filter(r => r.metadata_stale).length;
@@ -1909,7 +1909,7 @@ function createMcpServer() {
1909
1909
  // ---- list_threads --------------------------------------------------------
1910
1910
  s.tool(
1911
1911
  "list_threads",
1912
- "List all subplot/storyline threads for a project. Returns a structured JSON envelope with results and total_count. Supports pagination via page/page_size.",
1912
+ "List all subplot/storyline threads for a project. Returns a structured JSON envelope with results and total_count. Use this to discover valid thread_id values before calling get_thread_arc or upsert_thread_link. Supports pagination via page/page_size.",
1913
1913
  {
1914
1914
  project_id: z.string().describe("Project ID."),
1915
1915
  page: z.number().int().min(1).optional().describe("Optional page number for paginated responses (1-based)."),
@@ -1937,7 +1937,7 @@ function createMcpServer() {
1937
1937
  // ---- get_thread_arc ------------------------------------------------------
1938
1938
  s.tool(
1939
1939
  "get_thread_arc",
1940
- "Get ordered scene metadata for all scenes belonging to a thread, including the per-thread beat. Returns a structured JSON envelope with thread metadata, results, and total_count. Supports pagination via page/page_size.",
1940
+ "Get ordered scene metadata for all scenes belonging to a thread, including the per-thread beat. Returns a structured JSON envelope with thread metadata, results, and total_count. Use list_threads first to find a valid thread_id, then call get_scene_prose for close reading of specific scenes. Supports pagination via page/page_size.",
1941
1941
  {
1942
1942
  thread_id: z.string().describe("Thread ID."),
1943
1943
  page: z.number().int().min(1).optional().describe("Optional page number for paginated responses (1-based)."),
@@ -1946,7 +1946,7 @@ function createMcpServer() {
1946
1946
  async ({ thread_id, page, page_size }) => {
1947
1947
  const thread = db.prepare(`SELECT * FROM threads WHERE thread_id = ?`).get(thread_id);
1948
1948
  if (!thread) {
1949
- return errorResponse("NOT_FOUND", `Thread '${thread_id}' not found.`);
1949
+ return errorResponse("NOT_FOUND", `Thread '${thread_id}' not found. Hint: call list_threads with project_id to get valid thread IDs.`);
1950
1950
  }
1951
1951
 
1952
1952
  const rows = db.prepare(`
@@ -2326,7 +2326,7 @@ function createMcpServer() {
2326
2326
 
2327
2327
  const scene = db.prepare(`SELECT file_path FROM scenes WHERE scene_id = ?`).get(scene_id);
2328
2328
  if (!scene) {
2329
- return errorResponse("NOT_FOUND", `Scene '${scene_id}' not found.`);
2329
+ return errorResponse("NOT_FOUND", `Scene '${scene_id}' not found. Hint: call find_scenes to get valid scene IDs.`);
2330
2330
  }
2331
2331
 
2332
2332
  try {
@@ -2397,7 +2397,7 @@ function createMcpServer() {
2397
2397
 
2398
2398
  const proposal = pendingProposals.get(proposal_id);
2399
2399
  if (!proposal) {
2400
- return errorResponse("PROPOSAL_NOT_FOUND", `Proposal '${proposal_id}' not found or has expired.`);
2400
+ return errorResponse("PROPOSAL_NOT_FOUND", `Proposal '${proposal_id}' not found or has expired. Hint: call propose_edit again to create a fresh proposal_id.`);
2401
2401
  }
2402
2402
 
2403
2403
  if (proposal.scene_id !== scene_id) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hanna84/mcp-writing",
3
- "version": "1.11.5",
3
+ "version": "1.11.6",
4
4
  "description": "MCP service for AI-assisted reasoning and editing on long-form fiction projects",
5
5
  "type": "module",
6
6
  "main": "index.js",