@aioproductoscom/mcp 0.15.3 → 0.15.5
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.
- package/dist/client.js +48 -0
- package/dist/index.js +122 -1
- package/package.json +1 -1
package/dist/client.js
CHANGED
|
@@ -48,6 +48,54 @@ export class PlatformClient {
|
|
|
48
48
|
createTask(body) {
|
|
49
49
|
return this.req("/api/pm/tasks", { method: "POST", body: JSON.stringify(body) });
|
|
50
50
|
}
|
|
51
|
+
createFeature(body) {
|
|
52
|
+
return this.req("/api/me/features", { method: "POST", body: JSON.stringify(body) });
|
|
53
|
+
}
|
|
54
|
+
createObjective(body) {
|
|
55
|
+
return this.req("/api/me/objectives", { method: "POST", body: JSON.stringify(body) });
|
|
56
|
+
}
|
|
57
|
+
createSprint(body) {
|
|
58
|
+
return this.req("/api/me/sprints", { method: "POST", body: JSON.stringify(body) });
|
|
59
|
+
}
|
|
60
|
+
createPage(body) {
|
|
61
|
+
return this.req("/api/me/pages", { method: "POST", body: JSON.stringify(body) });
|
|
62
|
+
}
|
|
63
|
+
updateFeature(body) {
|
|
64
|
+
return this.req("/api/me/features", { method: "PATCH", body: JSON.stringify(body) });
|
|
65
|
+
}
|
|
66
|
+
updateObjective(body) {
|
|
67
|
+
return this.req("/api/me/objectives", { method: "PATCH", body: JSON.stringify(body) });
|
|
68
|
+
}
|
|
69
|
+
updateKeyResult(body) {
|
|
70
|
+
return this.req("/api/me/key-results", { method: "PATCH", body: JSON.stringify(body) });
|
|
71
|
+
}
|
|
72
|
+
updateSprint(body) {
|
|
73
|
+
return this.req("/api/me/sprints", { method: "PATCH", body: JSON.stringify(body) });
|
|
74
|
+
}
|
|
75
|
+
updatePage(body) {
|
|
76
|
+
return this.req("/api/me/pages", { method: "PATCH", body: JSON.stringify(body) });
|
|
77
|
+
}
|
|
78
|
+
createRelease(body) {
|
|
79
|
+
return this.req("/api/me/releases", { method: "POST", body: JSON.stringify(body) });
|
|
80
|
+
}
|
|
81
|
+
updateRelease(body) {
|
|
82
|
+
return this.req("/api/me/releases", { method: "PATCH", body: JSON.stringify(body) });
|
|
83
|
+
}
|
|
84
|
+
createExperiment(body) {
|
|
85
|
+
return this.req("/api/me/experiments", { method: "POST", body: JSON.stringify(body) });
|
|
86
|
+
}
|
|
87
|
+
updateExperiment(body) {
|
|
88
|
+
return this.req("/api/me/experiments", { method: "PATCH", body: JSON.stringify(body) });
|
|
89
|
+
}
|
|
90
|
+
listDecisions(status) {
|
|
91
|
+
return this.req(`/api/me/decisions${status ? `?status=${encodeURIComponent(status)}` : ""}`);
|
|
92
|
+
}
|
|
93
|
+
createDecision(body) {
|
|
94
|
+
return this.req("/api/me/decisions", { method: "POST", body: JSON.stringify(body) });
|
|
95
|
+
}
|
|
96
|
+
updateDecision(body) {
|
|
97
|
+
return this.req("/api/me/decisions", { method: "PATCH", body: JSON.stringify(body) });
|
|
98
|
+
}
|
|
51
99
|
updateTask(id, body) {
|
|
52
100
|
return this.req(`/api/pm/tasks/${encodeURIComponent(id)}`, { method: "PATCH", body: JSON.stringify(body) });
|
|
53
101
|
}
|
package/dist/index.js
CHANGED
|
@@ -23,7 +23,7 @@ function text(data) {
|
|
|
23
23
|
function promptMsg(body) {
|
|
24
24
|
return { messages: [{ role: "user", content: { type: "text", text: body } }] };
|
|
25
25
|
}
|
|
26
|
-
const server = new McpServer({ name: "AIOProductOS", version: "0.15.
|
|
26
|
+
const server = new McpServer({ name: "AIOProductOS", version: "0.15.5" }, {
|
|
27
27
|
instructions: "You manage product work on AIOProductOS for the connected member — board, insights, features, and " +
|
|
28
28
|
"analytics all hang off one spine. Call get_pm_playbook first for how to operate: ground in " +
|
|
29
29
|
"get_product_brain, keep work tied to the spine (insight→feature→task→outcome), and prioritize on " +
|
|
@@ -49,6 +49,127 @@ server.tool("create_task", "Create a task and return the created task. A write
|
|
|
49
49
|
insight_id: z.string().optional().describe("Link to an insight (optional)."),
|
|
50
50
|
assignee_member_ids: z.array(z.string()).optional().describe("Member ids to assign, from pm_meta (optional)."),
|
|
51
51
|
}, async (a) => text(await client.createTask(a)));
|
|
52
|
+
server.tool("create_feature", "Create a feature on the product spine and return it (id, key, name, status). The key is generated from the name; status starts 'active'. product_id defaults to the org's primary product when omitted — pass one from whoami for a multi-product org. Only name is required; create the feature before linking tasks to it with create_task.", {
|
|
53
|
+
name: z.string().describe("Feature name (the only required field), e.g. 'SAML SSO'."),
|
|
54
|
+
description: z.string().optional().describe("What the feature is / why it matters (optional)."),
|
|
55
|
+
product_id: z.string().optional().describe("Product to create it under, from whoami (optional; the org's primary product when omitted)."),
|
|
56
|
+
}, async (a) => text(await client.createFeature(a)));
|
|
57
|
+
server.tool("create_objective", "Create an objective (OKR), optionally with key results, and return it. period is free text (e.g. 'Q3 2026'); product_id and parent_id (a parent objective) are optional and verified in-org. Each key result takes name + optional unit / start_value / target_value. Only name is required.", {
|
|
58
|
+
name: z.string().describe("Objective name (the only required field), e.g. 'Reach $50k MRR'."),
|
|
59
|
+
description: z.string().optional().describe("Context for the objective (optional)."),
|
|
60
|
+
period: z.string().optional().describe("Free-text period, e.g. 'Q3 2026' (optional)."),
|
|
61
|
+
product_id: z.string().optional().describe("Product to scope it to, from whoami (optional)."),
|
|
62
|
+
parent_id: z.string().optional().describe("Parent objective id to nest under (optional)."),
|
|
63
|
+
key_results: z
|
|
64
|
+
.array(z.object({
|
|
65
|
+
name: z.string().describe("Key result name, e.g. 'MRR'."),
|
|
66
|
+
unit: z.string().optional().describe("Unit, e.g. 'USD' or '%' (optional)."),
|
|
67
|
+
start_value: z.number().optional().describe("Starting value (optional; default 0)."),
|
|
68
|
+
target_value: z.number().optional().describe("Target value (optional)."),
|
|
69
|
+
}))
|
|
70
|
+
.optional()
|
|
71
|
+
.describe("Key results to attach (optional; up to 10)."),
|
|
72
|
+
}, async (a) => text(await client.createObjective(a)));
|
|
73
|
+
server.tool("create_sprint", "Create a sprint and return it (id, name, goal, state, dates). state is 'future' (default) or 'active'; start_date / end_date are optional ISO 8601. Only name is required. Schedule tasks into it by passing the returned sprint id as sprint_id on create_task / update_task.", {
|
|
74
|
+
name: z.string().describe("Sprint name (the only required field), e.g. 'Sprint 12'."),
|
|
75
|
+
goal: z.string().optional().describe("The sprint goal (optional)."),
|
|
76
|
+
state: z.enum(["future", "active"]).optional().describe("Lifecycle state (optional; default 'future')."),
|
|
77
|
+
start_date: z.string().optional().describe("Start, ISO 8601 e.g. '2026-07-15T00:00:00Z' (optional)."),
|
|
78
|
+
end_date: z.string().optional().describe("End, ISO 8601 (optional)."),
|
|
79
|
+
}, async (a) => text(await client.createSprint(a)));
|
|
80
|
+
server.tool("create_page", "Create a Page (in-product doc / PRD on the spine) and return it (id, title). `body` is plain text — blank-line-separated blocks become paragraphs; omit it for a blank page. title defaults to 'Untitled'. product_id / parent_id (a parent page) are optional and verified in-org.", {
|
|
81
|
+
title: z.string().optional().describe("Page title (optional; 'Untitled' when omitted)."),
|
|
82
|
+
body: z.string().optional().describe("Page content as plain text; blank lines separate paragraphs (optional)."),
|
|
83
|
+
icon: z.string().optional().describe("An emoji icon for the page (optional)."),
|
|
84
|
+
product_id: z.string().optional().describe("Product to scope it to, from whoami (optional)."),
|
|
85
|
+
parent_id: z.string().optional().describe("Parent page id to nest under (optional)."),
|
|
86
|
+
}, async (a) => text(await client.createPage(a)));
|
|
87
|
+
server.tool("update_feature", "Update a feature and return it; omitted fields are unchanged. status is 'active' | 'discovered' | 'archived' (there is NO 'shipped' status — set mark_shipped:true to stamp its ship date instead). target_date is 'YYYY-MM-DD' (or null to clear). Resolve the id via list_features; only id is required.", {
|
|
88
|
+
id: z.string().describe("Feature id to update, from list_features (required)."),
|
|
89
|
+
name: z.string().optional().describe("New name (optional)."),
|
|
90
|
+
description: z.string().nullable().optional().describe("New description; null clears it (optional)."),
|
|
91
|
+
status: z.enum(["active", "discovered", "archived"]).optional().describe("Lifecycle status (optional)."),
|
|
92
|
+
target_date: z.string().nullable().optional().describe("Target ship date 'YYYY-MM-DD', or null to clear (optional)."),
|
|
93
|
+
mark_shipped: z.boolean().optional().describe("true stamps the ship date now; false clears it (optional)."),
|
|
94
|
+
}, async (a) => text(await client.updateFeature(a)));
|
|
95
|
+
server.tool("update_objective", "Update an objective's name / description / period and return it; omitted fields are unchanged (null clears description or period). Resolve the id via list_objectives; only id is required. To move a key result's value use update_key_result.", {
|
|
96
|
+
id: z.string().describe("Objective id, from list_objectives (required)."),
|
|
97
|
+
name: z.string().optional().describe("New name (optional)."),
|
|
98
|
+
description: z.string().nullable().optional().describe("New description; null clears it (optional)."),
|
|
99
|
+
period: z.string().nullable().optional().describe("New period, e.g. 'Q4 2026'; null clears it (optional)."),
|
|
100
|
+
}, async (a) => text(await client.updateObjective(a)));
|
|
101
|
+
server.tool("update_key_result", "Update a key result — most often to move current_value as progress lands — and return it; omitted fields are unchanged. Resolve the id via list_objectives (each objective carries its key_results with ids). Only id is required.", {
|
|
102
|
+
id: z.string().describe("Key result id, from list_objectives (required)."),
|
|
103
|
+
current_value: z.number().optional().describe("New current value (optional)."),
|
|
104
|
+
target_value: z.number().nullable().optional().describe("New target value; null clears it (optional)."),
|
|
105
|
+
start_value: z.number().optional().describe("New starting baseline (optional)."),
|
|
106
|
+
name: z.string().optional().describe("New name (optional)."),
|
|
107
|
+
unit: z.string().nullable().optional().describe("New unit, e.g. 'USD'; null clears it (optional)."),
|
|
108
|
+
}, async (a) => text(await client.updateKeyResult(a)));
|
|
109
|
+
server.tool("update_sprint", "Update a sprint and return it. state is 'future' | 'active' | 'closed' — moving to 'closed' stamps the completion time, reopening clears it. start_date / end_date are ISO 8601 (or null to clear). Resolve the id via list_sprints; only id is required.", {
|
|
110
|
+
id: z.string().describe("Sprint id, from list_sprints (required)."),
|
|
111
|
+
name: z.string().optional().describe("New name (optional)."),
|
|
112
|
+
goal: z.string().nullable().optional().describe("New goal; null clears it (optional)."),
|
|
113
|
+
state: z.enum(["future", "active", "closed"]).optional().describe("Lifecycle state; 'closed' completes it (optional)."),
|
|
114
|
+
start_date: z.string().nullable().optional().describe("Start, ISO 8601, or null (optional)."),
|
|
115
|
+
end_date: z.string().nullable().optional().describe("End, ISO 8601, or null (optional)."),
|
|
116
|
+
}, async (a) => text(await client.updateSprint(a)));
|
|
117
|
+
server.tool("update_page", "Update a Page — rename, set icon, replace the body, or archive/unarchive (archived:true hides it, false restores it). `body` is plain text (blank lines → paragraphs) and REPLACES the page content. Omitted fields are unchanged. Resolve the id via list_pages; only id is required.", {
|
|
118
|
+
id: z.string().describe("Page id, from list_pages (required)."),
|
|
119
|
+
title: z.string().optional().describe("New title (optional)."),
|
|
120
|
+
icon: z.string().nullable().optional().describe("New emoji icon; null clears it (optional)."),
|
|
121
|
+
body: z.string().optional().describe("New content as plain text; blank lines separate paragraphs. REPLACES existing content (optional)."),
|
|
122
|
+
archived: z.boolean().optional().describe("true archives (hides) the page; false restores it (optional)."),
|
|
123
|
+
}, async (a) => text(await client.updatePage(a)));
|
|
124
|
+
server.tool("create_release", "Create a release and return it (id, version, changelog, released_at). Omit released_at for an unreleased/draft entry. product_id defaults to the org's primary product. Only version is required.", {
|
|
125
|
+
version: z.string().describe("Version string (required), e.g. 'v2.4.0'."),
|
|
126
|
+
changelog: z.string().optional().describe("What shipped (optional)."),
|
|
127
|
+
released_at: z.string().optional().describe("Ship time, ISO 8601 (optional; omit for a draft)."),
|
|
128
|
+
product_id: z.string().optional().describe("Product, from whoami (optional; the primary product when omitted)."),
|
|
129
|
+
}, async (a) => text(await client.createRelease(a)));
|
|
130
|
+
server.tool("update_release", "Update a release and return it; omitted fields unchanged. Set released_at to ship it (or null to move it back to draft). Resolve the id via list_releases; only id is required.", {
|
|
131
|
+
id: z.string().describe("Release id, from list_releases (required)."),
|
|
132
|
+
version: z.string().optional().describe("New version (optional)."),
|
|
133
|
+
changelog: z.string().nullable().optional().describe("New changelog; null clears it (optional)."),
|
|
134
|
+
released_at: z.string().nullable().optional().describe("Ship time ISO 8601, or null for draft (optional)."),
|
|
135
|
+
}, async (a) => text(await client.updateRelease(a)));
|
|
136
|
+
server.tool("create_experiment", "Create a PM experiment (a Build-Measure-Learn hypothesis) and return it. state is 'hypothesis' (default) | 'build' | 'measure' | 'learn'. Only title is required. This is the PM hypothesis tracker list_experiments reads, not the analytics A/B engine.", {
|
|
137
|
+
title: z.string().describe("Experiment title / the hypothesis in a line (required)."),
|
|
138
|
+
hypothesis: z.string().optional().describe("The full hypothesis (optional)."),
|
|
139
|
+
metric: z.string().optional().describe("The metric it moves, e.g. 'activation rate' (optional)."),
|
|
140
|
+
target: z.string().optional().describe("Target change, e.g. '+5pp' (optional)."),
|
|
141
|
+
state: z.enum(["hypothesis", "build", "measure", "learn"]).optional().describe("Build-Measure-Learn stage (optional; default 'hypothesis')."),
|
|
142
|
+
product_id: z.string().optional().describe("Product, from whoami (optional)."),
|
|
143
|
+
}, async (a) => text(await client.createExperiment(a)));
|
|
144
|
+
server.tool("update_experiment", "Update a PM experiment — advance its state and record the outcome — and return it. state ∈ hypothesis|build|measure|learn; verdict ∈ validated|invalidated; decision ∈ pivot|persevere. Resolve the id via list_experiments; only id is required.", {
|
|
145
|
+
id: z.string().describe("Experiment id, from list_experiments (required)."),
|
|
146
|
+
title: z.string().optional().describe("New title (optional)."),
|
|
147
|
+
hypothesis: z.string().nullable().optional().describe("New hypothesis; null clears it (optional)."),
|
|
148
|
+
metric: z.string().nullable().optional().describe("New metric; null clears it (optional)."),
|
|
149
|
+
target: z.string().nullable().optional().describe("New target; null clears it (optional)."),
|
|
150
|
+
state: z.enum(["hypothesis", "build", "measure", "learn"]).optional().describe("Build-Measure-Learn stage (optional)."),
|
|
151
|
+
verdict: z.enum(["validated", "invalidated"]).nullable().optional().describe("Outcome (optional)."),
|
|
152
|
+
decision: z.enum(["pivot", "persevere"]).nullable().optional().describe("What you'll do next (optional)."),
|
|
153
|
+
result: z.string().nullable().optional().describe("Free-text result / what you learned; null clears it (optional)."),
|
|
154
|
+
}, async (a) => text(await client.updateExperiment(a)));
|
|
155
|
+
server.tool("list_decisions", "List the org's logged decisions — title, rationale, status, and any linked feature/release/objective — newest first. Read-only; returns an empty list when none. Optional status filter (decided | proposed | revisit). Resolve a decision id here before update_decision.", {
|
|
156
|
+
status: z.enum(["decided", "proposed", "revisit"]).optional().describe("Filter by status (optional)."),
|
|
157
|
+
}, async (a) => text(await client.listDecisions(a.status)));
|
|
158
|
+
server.tool("create_decision", "Log a decision and return it. status is 'decided' (default) | 'proposed' | 'revisit'; a 'decided' one stamps the decision time. Optionally weld it to a feature / release / objective via link_type + link_id (verified in-org). Only title is required.", {
|
|
159
|
+
title: z.string().describe("The decision in a line (required)."),
|
|
160
|
+
rationale: z.string().optional().describe("Why — the reasoning (optional)."),
|
|
161
|
+
status: z.enum(["decided", "proposed", "revisit"]).optional().describe("Decision status (optional; default 'decided')."),
|
|
162
|
+
link_type: z.enum(["feature", "release", "objective"]).optional().describe("What it's linked to (optional; pair with link_id)."),
|
|
163
|
+
link_id: z.string().optional().describe("Id of the linked feature/release/objective, from list_features / list_releases / list_objectives (optional)."),
|
|
164
|
+
}, async (a) => text(await client.createDecision(a)));
|
|
165
|
+
server.tool("update_decision", "Update a decision and return it; omitted fields unchanged. Moving status to 'decided' re-stamps the decision time. Re-link via link_type + link_id (verified in-org), or clear with nulls. Resolve the id via list_decisions; only id is required.", {
|
|
166
|
+
id: z.string().describe("Decision id, from list_decisions (required)."),
|
|
167
|
+
title: z.string().optional().describe("New title (optional)."),
|
|
168
|
+
rationale: z.string().nullable().optional().describe("New rationale; null clears it (optional)."),
|
|
169
|
+
status: z.enum(["decided", "proposed", "revisit"]).optional().describe("New status (optional)."),
|
|
170
|
+
link_type: z.enum(["feature", "release", "objective"]).nullable().optional().describe("New link target (optional)."),
|
|
171
|
+
link_id: z.string().nullable().optional().describe("New linked id, or null to unlink (optional)."),
|
|
172
|
+
}, async (a) => text(await client.updateDecision(a)));
|
|
52
173
|
server.tool("update_task", "Update one or more of a task's fields and return the updated task; fields you omit are left unchanged (idempotent — re-sending the same values is a no-op), and passing null clears a nullable field. Resolve ids first — the task via list_tasks/get_task, and status/feature/insight/member ids via pm_meta — never guess them. Only id is required.", {
|
|
53
174
|
id: z.string().describe("Task id, from list_tasks or get_task."),
|
|
54
175
|
title: z.string().optional().describe("New title (optional)."),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aioproductoscom/mcp",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.5",
|
|
4
4
|
"mcpName": "com.aioproductos/mcp",
|
|
5
5
|
"description": "AIOProductOS MCP — manage the board, read your product brain + analytics, and run the support inbox from Claude Code, Cursor, Codex, and any MCP host.",
|
|
6
6
|
"type": "module",
|