@ign8t/mcp 0.3.1 → 0.4.0

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/README.md +33 -5
  2. package/dist/index.js +40 -10
  3. package/package.json +3 -3
package/README.md CHANGED
@@ -9,7 +9,7 @@ Model Context Protocol (MCP) is an open standard that enables AI assistants to s
9
9
  - 📋 Access all your ign8t projects without switching contexts
10
10
  - 📄 Read master specs, feature specs, legacy PRP/BRD/PRD/TRD documents, and task specs
11
11
  - 📊 View and manage your backlog in real-time
12
- - 🧩 See which feature specs exist and which tasks still need specs
12
+ - 🧩 See which feature specs exist and which tasks still need specs, and create a missing one after you approve its price
13
13
  - ✅ Update task statuses as you complete work
14
14
  - 🔍 Search across all tasks and projects
15
15
  - 🎯 Review, accept, or reject AI/backlog recommendations
@@ -155,6 +155,7 @@ Once configured, you can interact with ign8t naturally through your AI assistant
155
155
  "List the master spec, generated task specs, and missing specs"
156
156
  "Show me the feature spec for the authentication task"
157
157
  "Get all task specs for project [id]"
158
+ "Create the missing spec for task [id]"
158
159
  ```
159
160
 
160
161
  ### Task Workflow
@@ -191,14 +192,15 @@ The MCP server also provides quick access to resources:
191
192
  | ------------------------ | ------------------------------------------------ | -------------------------------------------- |
192
193
  | `list_projects` | List all projects with optional status filter | "Show my active projects" |
193
194
  | `get_project` | Get detailed project information | "Get details for project abc123" |
194
- | `get_documents` | Retrieve master spec, task specs, and legacy documents | "Show me the master spec for project xyz" |
195
+ | `get_documents` | One document in full (`master_spec`, `brd`, `prd`, `trd`, `prp`, `task_spec:<task id>`); `all` or `task_spec` lists documents without text | "Show me the master spec for project xyz" |
195
196
  | `get_backlog` | View epics, stories, and tasks | "Display backlog including completed items" |
196
197
  | `get_specs` | List master, generated, and missing task specs | "What specs are left?" |
197
- | `get_next_task` | Next todo task (highest priority, then oldest) plus task spec preview | "What should I work on next?" |
198
+ | `get_next_task` | The task to work on next (unfinished setup task, then the in-progress task to resume, then the next todo) with its full task spec and the project's rules | "What should I work on next?" |
198
199
  | `create_task` | Add a concrete task directly to backlog | "Add a task for OAuth callback handling" |
199
200
  | `update_task_status` | Change task status with notes | "Set task 123 to blocked: waiting on API" |
200
201
  | `search_tasks` | Search across tasks | "Find all tasks mentioning 'payment'" |
201
- | `get_task_context` | Full task context with requirements | "Show context for task 456" |
202
+ | `get_task_context` | One task with its full spec, the master spec and the project's rules | "Show context for task 456" |
203
+ | `create_task_spec` | Create a task's missing spec after you approve its price (Sparks) | "Create the spec for task 456" |
202
204
  | `add_feature_request` | Queue a feature idea as a backlog recommendation | "I want to add team invites next" |
203
205
  | `list_recommendations` | List queued backlog recommendations | "Show pending feature recommendations" |
204
206
  | `accept_recommendations` | Convert recommendations into tasks | "Accept recommendations abc and def" |
@@ -208,7 +210,22 @@ The MCP server also provides quick access to resources:
208
210
  | `update_context` | Change the tech stack and constraints after you confirm the exact change | "We moved from Firebase to Supabase" |
209
211
  | `import_project` | Import the local codebase into project context (28 Sparks) | "Import this codebase into project abc123" |
210
212
 
211
- The write tools (`create_task`, `update_task_status`, `accept_recommendations`, `reject_recommendations`, `add_feature_request`, `add_user_persona`, `update_success_criteria`, `update_context`) are free. Only `import_project` costs Sparks.
213
+ The write tools (`create_task`, `update_task_status`, `accept_recommendations`, `reject_recommendations`, `add_feature_request`, `add_user_persona`, `update_success_criteria`, `update_context`) are free. Only `import_project` and `create_task_spec` cost Sparks. A change made with `add_user_persona`, `update_success_criteria` or `update_context` marks the project's previously generated documents out of date, and regenerating them costs Sparks, so the AI asks you before making one.
214
+
215
+ ### Working from the task spec
216
+
217
+ `get_next_task` hands the AI the task to work on next: the project's setup task while it is unfinished, then the in-progress task updated most recently (so interrupted work resumes), then the next todo task. With it come the task's full spec and the project's rules (`implementation_guidance`). `get_task_context` returns the same for one task; the AI calls it before resuming a task after a pause.
218
+
219
+ Each task spec has a state. A current spec is implemented as is. For an out-of-date one, the AI asks whether to regenerate it on the task board (costs Sparks) or go on with it. When a task's spec is missing or incomplete, the AI writes no production code for it until the spec exists or you tell it to go on without one. The same holds for a spec read with `get_documents` (the master spec or one task's spec).
220
+
221
+ ### Creating a missing task spec
222
+
223
+ `create_task_spec` creates the spec of a task that has none, from your IDE.
224
+
225
+ - **Cost:** the same Sparks as creating it on the task board. The AI first asks ign8t for the price (nothing is charged), tells you, and creates the spec only after you agree.
226
+ - **Never charged twice:** if the answer is lost or the AI calls again, the spec already created is returned for free. While a spec is still being generated, another call is told to wait and is not charged. After a failed attempt has been refunded, retrying starts a new paid attempt. Follow the response for charge or recovery exceptions.
227
+ - **Time:** usually about 45 seconds.
228
+ - **An existing spec is never replaced:** it is returned for free. To regenerate an out-of-date or incomplete spec, use the task board.
212
229
 
213
230
  ### Updating the implementation context
214
231
 
@@ -304,6 +321,17 @@ For contributors working on the MCP server itself:
304
321
  2. Install dependencies: `pnpm install`
305
322
  3. Build the project: `pnpm build`
306
323
  4. Test locally: `pnpm dev --api-key your-key`
324
+ 5. Run the tests: `pnpm test` (builds, then runs `test/` against `dist/`)
325
+
326
+ ## Changelog
327
+
328
+ ### 0.4.0
329
+
330
+ - New `create_task_spec`: create a task's missing spec from your IDE after you approve its price.
331
+ - `get_next_task` and `get_task_context` describe the full hand-over: setup task first, then the in-progress task to resume, the full task spec with its state and what to do when it is not ready, and the project's rules.
332
+ - `get_documents` no longer suggests `all` as its default: one document type returns the full text (including `task_spec:<task id>`); `all`, `task_spec` or no type returns a list without text.
333
+ - `add_user_persona` and `update_success_criteria` tell the AI to ask you first, since a change marks generated documents out of date.
334
+ - Requests identify the client as `ign8t-mcp/<version>`.
307
335
 
308
336
  ## Support
309
337
 
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
3
3
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
4
  import { CallToolRequestSchema, ListResourcesRequestSchema, ListToolsRequestSchema, ReadResourceRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
5
5
  import { buildWorkspaceSnapshot } from "./workspace-snapshot.js";
6
- const VERSION = "0.3.1";
6
+ const VERSION = "0.4.0";
7
7
  // Parse command line arguments
8
8
  function parseArgs() {
9
9
  const args = process.argv.slice(2);
@@ -78,12 +78,14 @@ async function describeApiError(response) {
78
78
  const message = `${typeof error === "string" ? error : "API error"} (HTTP ${response.status})`;
79
79
  return Object.keys(details).length ? `${message}\n${JSON.stringify(details, null, 2)}` : message;
80
80
  }
81
- // Helper function to call ign8t API
81
+ // Helper function to call ign8t API. No timeout of its own: Node's fetch waits up to
82
+ // 300 s for a response, and create_task_spec can take the server about 250 s.
82
83
  async function callIgn8tAPI(endpoint, data = {}) {
83
84
  const response = await fetch(`${API_URL}/api/mcp${endpoint}`, {
84
85
  method: "POST",
85
86
  headers: {
86
87
  "Content-Type": "application/json",
88
+ "User-Agent": `ign8t-mcp/${VERSION}`,
87
89
  "X-API-Key": API_KEY,
88
90
  },
89
91
  body: JSON.stringify(data),
@@ -135,7 +137,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
135
137
  },
136
138
  {
137
139
  name: "get_documents",
138
- description: "Get master specs, task specs, and legacy BRD/PRD/TRD documents for a project",
140
+ description: "Get a project's documents. One document type returns that document in full text: master_spec, brd, prd, trd, prp (legacy), or task_spec:<task id> for one task's spec; it comes with the project's rules (implementation_guidance, rules). A spec document (master_spec, task_spec:<id>) carries readiness.status: for draft, write no production code; for stale, ask the user whether to regenerate it (costs Sparks) or proceed. To implement a task, read it with get_task_context instead. all, task_spec, or no document_type returns only a list of documents (no text) with a hint on how to read one.",
139
141
  inputSchema: {
140
142
  type: "object",
141
143
  properties: {
@@ -146,9 +148,9 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
146
148
  },
147
149
  document_type: {
148
150
  type: "string",
149
- enum: ["master_spec", "prp", "brd", "prd", "trd", "task_spec", "all"],
150
- description: "Type of document to retrieve",
151
- default: "all",
151
+ // A pattern, not an enum, so one task's spec (task_spec:<task id>) can be named.
152
+ pattern: "^(master_spec|brd|prd|trd|prp|all|task_spec(:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})?)$",
153
+ description: "master_spec, brd, prd, trd, prp or task_spec:<task id> for one document in full; all or task_spec for a list only",
152
154
  },
153
155
  },
154
156
  required: ["project_id"],
@@ -315,7 +317,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
315
317
  },
316
318
  {
317
319
  name: "get_next_task",
318
- description: "Get the next todo task to work on (highest priority, then oldest), including its generated task spec when available.",
320
+ description: "Get the task to work on next, with what is needed to implement it. While the project's setup task is unfinished it comes first, since every other task depends on it; otherwise the most recently updated in-progress task is resumed (resume: true, other in-progress tasks in other_in_progress); otherwise the next todo task (highest priority, then oldest). Returns the task, its full spec in task_spec.content_text with task_spec.state (ready, stale, draft or missing), task_spec.instruction when the spec is not ready, and the project's rules (implementation_guidance, rules) to implement under. Follow task_spec.instruction exactly: for missing or draft, write no production code for the task; for stale, ask the user whether to regenerate the spec or proceed. A missing spec can also be created with create_task_spec once the user agrees to its price. later_decisions, when present, are accepted decisions the spec does not reflect yet: follow them where they differ. With no task, message says why and what to do next.",
319
321
  inputSchema: {
320
322
  type: "object",
321
323
  properties: {
@@ -380,7 +382,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
380
382
  },
381
383
  {
382
384
  name: "get_task_context",
383
- description: "Get a task with its story, epic, its own task spec and the project's master spec",
385
+ description: "Get one task with what is needed to implement it: the task with its story and epic, its full spec and the project's master spec (documents), spec_state (ready, stale, draft or missing), a warning to follow when a spec is missing, a draft or out of date (the same rules as get_next_task's instruction), board_url, and the project's rules (implementation_guidance, rules). Call it before resuming work on a task after a pause, so you work from its current spec and rules. later_decisions, when present, are accepted decisions the spec does not reflect yet: follow them where they differ.",
384
386
  inputSchema: {
385
387
  type: "object",
386
388
  properties: {
@@ -393,6 +395,31 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
393
395
  required: ["task_id"],
394
396
  },
395
397
  },
398
+ {
399
+ name: "create_task_spec",
400
+ description: "Create the spec for a task that has none (task_spec.state missing). It costs Sparks: call first with confirmed_with_user false, which charges nothing and answers with the price (error_code CONFIRMATION_REQUIRED, sparks_cost); tell the user the price, ask, and call again with confirmed_with_user true only after they agree. Calling again is safe: while the spec is being generated the answer is IN_PROGRESS and once it is saved EXISTS, both free; after a failed attempt was refunded, a new call starts a new paid attempt. It usually takes about 45 seconds, at most about 5 minutes. outcome says what happened: CREATED — the new spec is in content_text and the Sparks were charged; EXISTS — the task already has a spec, returned without a charge (this tool never replaces a spec; follow instruction: the user regenerates a draft one on the task board, and decides whether to regenerate a stale one there or proceed with it); IN_PROGRESS — the spec is being generated (by the board or an earlier call), nothing charged: call again with the same arguments in a minute or two, for up to 10 minutes if an earlier call was cut off; INSUFFICIENT_SPARKS — nothing charged, the user adds Sparks (billing_url) first; RECOVERY_PENDING — an earlier attempt's result is not confirmed yet, nothing new is charged: call again in a few minutes; FAILED — no spec was created and any charge was refunded unless the message says otherwise. Follow any returned instruction first, then implement from content_text under implementation_guidance; later_decisions, when present, are accepted decisions the spec does not reflect yet: follow them where they differ.",
401
+ inputSchema: {
402
+ type: "object",
403
+ properties: {
404
+ project_id: {
405
+ type: "string",
406
+ format: "uuid",
407
+ description: "The project ID",
408
+ },
409
+ task_id: {
410
+ type: "string",
411
+ format: "uuid",
412
+ description: "The task whose spec is missing",
413
+ },
414
+ confirmed_with_user: {
415
+ type: "boolean",
416
+ description: "true only after the user was told the price and agreed to it; false returns the price without creating or charging anything",
417
+ },
418
+ },
419
+ required: ["project_id", "task_id", "confirmed_with_user"],
420
+ additionalProperties: false,
421
+ },
422
+ },
396
423
  {
397
424
  name: "import_project",
398
425
  description: "Import the local codebase into the ign8t project's context (AI extraction of product vision, users, features and tech stack). Costs 28 Sparks per new import; re-importing the same content (README, package.json name/description/script/dependency names, notable paths, primary language) is free while nothing else has changed the project context since the last import. Uploads only: the README (first 6000 characters), the package.json name (or the folder name when it has none), description, script names and dependency names, up to 120 notable file paths, the file count and the primary language guessed from file extensions — never other file contents or environment values.",
@@ -474,7 +501,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
474
501
  },
475
502
  {
476
503
  name: "add_user_persona",
477
- description: "Add a new user persona discovered during development. Enriches the project context with detailed user information. Adding a persona with an existing name replaces that persona.",
504
+ description: "Add a new user persona discovered during development. Enriches the project context with detailed user information. Adding a persona with an existing name replaces that persona. Changing the project context marks the previously generated documents (BRD/PRD/TRD, delivery brief, master spec, task specs) as out of date, and regenerating them costs Sparks: before calling, show the user the exact persona and tell them this, and call only after the user agreed. Resending a saved persona unchanged changes nothing.",
478
505
  inputSchema: {
479
506
  type: "object",
480
507
  properties: {
@@ -536,7 +563,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
536
563
  },
537
564
  {
538
565
  name: "update_success_criteria",
539
- description: "Add or update success criteria and metrics for the project. Helps define how success will be measured. A criterion with an existing metric name replaces that criterion.",
566
+ description: "Add or update success criteria and metrics for the project. Helps define how success will be measured. A criterion with an existing metric name replaces that criterion. Changing the project context marks the previously generated documents (BRD/PRD/TRD, delivery brief, master spec, task specs) as out of date, and regenerating them costs Sparks: before calling, show the user the exact criteria and tell them this, and call only after the user agreed. Resending saved criteria unchanged changes nothing.",
540
567
  inputSchema: {
541
568
  type: "object",
542
569
  properties: {
@@ -683,6 +710,9 @@ server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
683
710
  case "get_task_context":
684
711
  result = await callIgn8tAPI("/tasks/context", args);
685
712
  break;
713
+ case "create_task_spec":
714
+ result = await callIgn8tAPI("/tasks/spec/create", args);
715
+ break;
686
716
  case "import_project": {
687
717
  const { snapshot, unreadableDirectories, fileLimitReached } = await buildWorkspaceSnapshot(args?.workspace_path);
688
718
  // The upload is what charges Sparks: a call the user cancelled while the folder
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ign8t/mcp",
3
- "version": "0.3.1",
3
+ "version": "0.4.0",
4
4
  "description": "MCP server for ign8t project management - AI IDE integration",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -18,7 +18,7 @@
18
18
  "dev": "tsx src/index.ts",
19
19
  "dev:help": "tsx src/index.ts --help",
20
20
  "clean": "rm -rf dist",
21
- "test": "node debug-mcp.js",
21
+ "test": "pnpm build && node --test test/index.test.mjs",
22
22
  "test:local": "node dist/index.js --help",
23
23
  "link:local": "npm link",
24
24
  "unlink:local": "npm unlink -g @ign8t/mcp",
@@ -38,7 +38,7 @@
38
38
  "mcp": {
39
39
  "name": "ign8t-mcp",
40
40
  "description": "MCP server for ign8t project management - AI IDE integration",
41
- "version": "0.3.1"
41
+ "version": "0.4.0"
42
42
  },
43
43
  "author": "nocodecat",
44
44
  "license": "MIT",