@idea-base/mcp-server 2.3.0 → 2.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.
- package/README.md +8 -0
- package/package.json +1 -1
- package/src/index.js +165 -0
package/README.md
CHANGED
|
@@ -67,6 +67,14 @@ Ask Claude to manage your projects:
|
|
|
67
67
|
| `get_project` | Get project details and statistics |
|
|
68
68
|
| `create_project` | Create a new project or sub-project |
|
|
69
69
|
| `update_project` | Update a project name, description, status, parent (re-parent, or `null` to detach) or product |
|
|
70
|
+
| `list_sprints` | List a product's sprints with real task counts and its cadence |
|
|
71
|
+
| `get_sprint` | One sprint: tasks, counts, commitment ledger; optionally candidates + blocked work |
|
|
72
|
+
| `create_sprint` | Open a sprint — next on the cadence, or an explicit window |
|
|
73
|
+
| `add_tasks_to_sprint` | Commit tasks (refuses a task already in another sprint) |
|
|
74
|
+
| `remove_tasks_from_sprint` | Take tasks out of a sprint |
|
|
75
|
+
| `close_sprint` | Close it; unfinished work carries forward. Irreversible |
|
|
76
|
+
| `get_sprint_cadence` | Read a product's sprint rhythm |
|
|
77
|
+
| `set_sprint_cadence` | Set length, start weekday, carry-over, auto-open |
|
|
70
78
|
|
|
71
79
|
### Tasks
|
|
72
80
|
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -943,6 +943,108 @@ const tools = [
|
|
|
943
943
|
},
|
|
944
944
|
},
|
|
945
945
|
},
|
|
946
|
+
{
|
|
947
|
+
name: 'list_sprints',
|
|
948
|
+
description: 'List a product\'s sprints, newest first, with real task counts and its cadence. Sprints are owned by the PRODUCT: the product sets the rhythm and owns the lifecycle, while projects add and remove the work. A sprint can hold tasks from any project under that product, sub-projects included.',
|
|
949
|
+
inputSchema: {
|
|
950
|
+
type: 'object',
|
|
951
|
+
properties: {
|
|
952
|
+
product_id: { type: 'number', description: 'The product whose sprints to list. Find ids via list_products.' },
|
|
953
|
+
},
|
|
954
|
+
required: ['product_id'],
|
|
955
|
+
},
|
|
956
|
+
},
|
|
957
|
+
{
|
|
958
|
+
name: 'get_sprint',
|
|
959
|
+
description: 'Get one sprint: its tasks with derived status, counts taken from real task rows, and — for a CLOSED sprint — the commitment ledger saying what it committed to and what became of each item. Pass candidates:true to also get the open work that could be pulled in, and the work being held back as blocked (with the reason).',
|
|
960
|
+
inputSchema: {
|
|
961
|
+
type: 'object',
|
|
962
|
+
properties: {
|
|
963
|
+
sprint_id: { type: 'number', description: 'The sprint to retrieve' },
|
|
964
|
+
candidates: { type: 'boolean', description: 'Also return work eligible to be added, and blocked work held out of it. Default false.' },
|
|
965
|
+
},
|
|
966
|
+
required: ['sprint_id'],
|
|
967
|
+
},
|
|
968
|
+
},
|
|
969
|
+
{
|
|
970
|
+
name: 'create_sprint',
|
|
971
|
+
description: 'Open a sprint on a product. With no dates it opens the NEXT one on the product\'s cadence, which is the normal case; pass starts_on/ends_on only to set an explicit window. One sprint per product per period — a second for the same period is refused rather than duplicated.',
|
|
972
|
+
inputSchema: {
|
|
973
|
+
type: 'object',
|
|
974
|
+
properties: {
|
|
975
|
+
product_id: { type: 'number', description: 'The product to open the sprint on' },
|
|
976
|
+
name: { type: 'string', description: 'Optional. Defaults to its date range.' },
|
|
977
|
+
goal: { type: 'string', description: 'What this sprint is meant to achieve' },
|
|
978
|
+
starts_on: { type: 'string', description: 'YYYY-MM-DD. Omit to follow the cadence.' },
|
|
979
|
+
ends_on: { type: 'string', description: 'YYYY-MM-DD. Omit to run one cadence length from starts_on.' },
|
|
980
|
+
state: { type: 'string', enum: ['planned', 'active'], description: 'Default planned. A sprint cannot be created closed.' },
|
|
981
|
+
},
|
|
982
|
+
required: ['product_id'],
|
|
983
|
+
},
|
|
984
|
+
},
|
|
985
|
+
{
|
|
986
|
+
name: 'add_tasks_to_sprint',
|
|
987
|
+
description: 'Commit tasks to a sprint. Each task is checked on its own and the result says which were added and which were refused and why — a task already in another sprint is REFUSED, not moved, because a task belongs to at most one. Tasks must belong to a project under the sprint\'s product.',
|
|
988
|
+
inputSchema: {
|
|
989
|
+
type: 'object',
|
|
990
|
+
properties: {
|
|
991
|
+
sprint_id: { type: 'number', description: 'The sprint to add to' },
|
|
992
|
+
task_ids: { type: 'array', items: { type: 'number' }, description: 'Task ids to commit (max 100)' },
|
|
993
|
+
},
|
|
994
|
+
required: ['sprint_id', 'task_ids'],
|
|
995
|
+
},
|
|
996
|
+
},
|
|
997
|
+
{
|
|
998
|
+
name: 'remove_tasks_from_sprint',
|
|
999
|
+
description: 'Take tasks out of a sprint. The tasks themselves are untouched — the sprint is the time box, not the owner of the work.',
|
|
1000
|
+
inputSchema: {
|
|
1001
|
+
type: 'object',
|
|
1002
|
+
properties: {
|
|
1003
|
+
sprint_id: { type: 'number', description: 'The sprint to remove from' },
|
|
1004
|
+
task_ids: { type: 'array', items: { type: 'number' }, description: 'Task ids to remove (max 100)' },
|
|
1005
|
+
},
|
|
1006
|
+
required: ['sprint_id', 'task_ids'],
|
|
1007
|
+
},
|
|
1008
|
+
},
|
|
1009
|
+
{
|
|
1010
|
+
name: 'close_sprint',
|
|
1011
|
+
description: 'Close a sprint. Unfinished work moves into the next sprint and its carry count increments (unless the product\'s cadence has carry-over off, in which case it is released); finished work stays attached. Every task held is written to the commitment ledger first, so what the sprint committed to survives the carry. This is an action, not a status edit — closing is irreversible.',
|
|
1012
|
+
inputSchema: {
|
|
1013
|
+
type: 'object',
|
|
1014
|
+
properties: {
|
|
1015
|
+
sprint_id: { type: 'number', description: 'The sprint to close' },
|
|
1016
|
+
carry_to_sprint_id: { type: 'number', description: 'Optional explicit destination for unfinished work. Must be an open sprint in the same product; otherwise the next sprint is used or opened.' },
|
|
1017
|
+
},
|
|
1018
|
+
required: ['sprint_id'],
|
|
1019
|
+
},
|
|
1020
|
+
},
|
|
1021
|
+
{
|
|
1022
|
+
name: 'get_sprint_cadence',
|
|
1023
|
+
description: 'Get a product\'s sprint rhythm: length in days, which weekday it starts, whether unfinished work carries over, and whether sprints open unattended. A product with no cadence row still reports the weekly-Monday default, flagged as not configured.',
|
|
1024
|
+
inputSchema: {
|
|
1025
|
+
type: 'object',
|
|
1026
|
+
properties: {
|
|
1027
|
+
product_id: { type: 'number', description: 'The product whose cadence to read' },
|
|
1028
|
+
},
|
|
1029
|
+
required: ['product_id'],
|
|
1030
|
+
},
|
|
1031
|
+
},
|
|
1032
|
+
{
|
|
1033
|
+
name: 'set_sprint_cadence',
|
|
1034
|
+
description: 'Set a product\'s sprint rhythm. "Mon-Sun weekly" is length_days 7 + start_weekday 1; a Wednesday fortnight is 14 + 3. Changing it does not move sprints that already exist — it applies from the next sprint opened. Setting a cadence is also what opts a product into having sprints opened and closed on the schedule.',
|
|
1035
|
+
inputSchema: {
|
|
1036
|
+
type: 'object',
|
|
1037
|
+
properties: {
|
|
1038
|
+
product_id: { type: 'number', description: 'The product to configure' },
|
|
1039
|
+
length_days: { type: 'number', description: 'Sprint length in days, 1-90. Default 7.' },
|
|
1040
|
+
start_weekday: { type: 'number', description: '0 = Sunday through 6 = Saturday. Default 1 (Monday). Only decides the FIRST sprint; later ones follow the previous sprint\'s end.' },
|
|
1041
|
+
carry_over_unfinished: { type: 'boolean', description: 'Move unfinished work into the next sprint on close. Default true.' },
|
|
1042
|
+
auto_create: { type: 'boolean', description: 'Open the next sprint unattended on the schedule. Default true.' },
|
|
1043
|
+
enabled: { type: 'boolean', description: 'Whether the schedule touches this product at all. Default true.' },
|
|
1044
|
+
},
|
|
1045
|
+
required: ['product_id'],
|
|
1046
|
+
},
|
|
1047
|
+
},
|
|
946
1048
|
{
|
|
947
1049
|
name: 'get_product',
|
|
948
1050
|
description: 'Get details of a specific product including linked projects, team members, and statistics.',
|
|
@@ -1623,6 +1725,69 @@ const toolHandlers = {
|
|
|
1623
1725
|
};
|
|
1624
1726
|
},
|
|
1625
1727
|
|
|
1728
|
+
async list_sprints({ product_id }) {
|
|
1729
|
+
const data = await apiRequest(`/products/${product_id}/sprints`);
|
|
1730
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
1731
|
+
},
|
|
1732
|
+
|
|
1733
|
+
async get_sprint({ sprint_id, candidates }) {
|
|
1734
|
+
const data = await apiRequest(`/sprints/${sprint_id}${candidates ? '?candidates=1' : ''}`);
|
|
1735
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
1736
|
+
},
|
|
1737
|
+
|
|
1738
|
+
async create_sprint({ product_id, name, goal, starts_on, ends_on, state }) {
|
|
1739
|
+
const data = await apiRequest(`/products/${product_id}/sprints`, {
|
|
1740
|
+
method: 'POST',
|
|
1741
|
+
body: JSON.stringify({ name, goal, starts_on, ends_on, state }),
|
|
1742
|
+
});
|
|
1743
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
1744
|
+
},
|
|
1745
|
+
|
|
1746
|
+
async add_tasks_to_sprint({ sprint_id, task_ids }) {
|
|
1747
|
+
const data = await apiRequest(`/sprints/${sprint_id}/tasks`, {
|
|
1748
|
+
method: 'POST',
|
|
1749
|
+
body: JSON.stringify({ task_ids }),
|
|
1750
|
+
});
|
|
1751
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
1752
|
+
},
|
|
1753
|
+
|
|
1754
|
+
async remove_tasks_from_sprint({ sprint_id, task_ids }) {
|
|
1755
|
+
const data = await apiRequest(`/sprints/${sprint_id}/tasks`, {
|
|
1756
|
+
method: 'DELETE',
|
|
1757
|
+
body: JSON.stringify({ task_ids }),
|
|
1758
|
+
});
|
|
1759
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
1760
|
+
},
|
|
1761
|
+
|
|
1762
|
+
async close_sprint({ sprint_id, carry_to_sprint_id }) {
|
|
1763
|
+
const data = await apiRequest(`/sprints/${sprint_id}/close`, {
|
|
1764
|
+
method: 'POST',
|
|
1765
|
+
body: JSON.stringify({ carry_to_sprint_id }),
|
|
1766
|
+
});
|
|
1767
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
1768
|
+
},
|
|
1769
|
+
|
|
1770
|
+
async get_sprint_cadence({ product_id }) {
|
|
1771
|
+
const data = await apiRequest(`/products/${product_id}/sprint-cadence`);
|
|
1772
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
1773
|
+
},
|
|
1774
|
+
|
|
1775
|
+
async set_sprint_cadence({ product_id, length_days, start_weekday, carry_over_unfinished, auto_create, enabled }) {
|
|
1776
|
+
const body = {};
|
|
1777
|
+
// Forwarded on `!== undefined` so an omitted field keeps its current value
|
|
1778
|
+
// rather than being reset to a default the caller never asked for.
|
|
1779
|
+
if (length_days !== undefined) body.length_days = length_days;
|
|
1780
|
+
if (start_weekday !== undefined) body.start_weekday = start_weekday;
|
|
1781
|
+
if (carry_over_unfinished !== undefined) body.carry_over_unfinished = carry_over_unfinished;
|
|
1782
|
+
if (auto_create !== undefined) body.auto_create = auto_create;
|
|
1783
|
+
if (enabled !== undefined) body.enabled = enabled;
|
|
1784
|
+
const data = await apiRequest(`/products/${product_id}/sprint-cadence`, {
|
|
1785
|
+
method: 'PUT',
|
|
1786
|
+
body: JSON.stringify(body),
|
|
1787
|
+
});
|
|
1788
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
1789
|
+
},
|
|
1790
|
+
|
|
1626
1791
|
async get_product({ product_id }) {
|
|
1627
1792
|
const product = await apiRequest(`/products/${product_id}`);
|
|
1628
1793
|
return {
|