Introduced in v7.2.0 - Unified array-based tools that replace separate single-item and batch operations with a single interface.
Version 7.2.0 introduces array-based tools that accept 1-100 items per call and return consistent response formats. This replaces the previous pattern of having separate tools for single and batch operations.
Before (v7.1.0 and earlier):
// Single item
await create_work_item({ title: 'Task', categoryId: 'programming' });
// Batch (different tool)
await batch_create_work_items({
items: [
{ title: 'Task 1', categoryId: 'programming' },
{ title: 'Task 2', categoryId: 'design' }
]
});After (v7.2.0+):
// Single OR batch - same tool
await create_work_items({
items: [
{ title: 'Task', categoryId: 'programming' } // Single
]
});
await create_work_items({
items: [
{ title: 'Task 1', categoryId: 'programming' }, // Batch
{ title: 'Task 2', categoryId: 'design' }
]
});One tool handles both single and batch operations:
- Simpler API - Fewer tools to learn
- Consistent usage - Same parameters for 1 or 100 items
- Better scaling - Start with 1, scale to 100 seamlessly
All array-based tools return:
{
items: Array<T | null>; // Results (null for failures)
total: number; // Total items processed
successful: number; // Success count
failed: number; // Failure count
errors: Array<ErrorDetail>; // Per-item errors
warnings: Array<string>; // Non-fatal warnings
}Update operations auto-create tags by name:
await update_work_items({
items: [{
workItemId: 123,
tagIds: ['existing-tag', 'new-tag-name'] // Auto-creates 'new-tag-name'
}]
});
// Response includes warning:
// warnings: ["Auto-created tag: 'new-tag-name'"]Individual failures don't block other items:
const result = await create_work_items({
items: [
{ title: 'Valid Task', categoryId: 'programming' }, // ✅ Success
{ title: 'Invalid', categoryId: 'nonexistent' }, // ❌ Fails
{ title: 'Another Valid', categoryId: 'design' } // ✅ Success
]
});
// result.successful: 2
// result.failed: 1
// result.items: [{ workItemId: 1 }, null, { workItemId: 3 }]Combined with Slim Mode, reduces tool count by 73%:
- Full Mode: 89 tools
- Slim Mode + Array API: 26 tools (~71% reduction)
- With verbosity=slim: Additional ~60% response size reduction
Create 1-100 work items in a single call.
Parameters:
projectId(number, optional): Project IDitems(array, required): Work items to create (1-100)title(string, required): Task titlecategoryId(number|string, required): Category ID or namedescription(string, optional): Details (markdown)importanceLevelId(number|string, optional): PrioritytagIds(array, optional): Tag IDs or namesboardId(number, optional): Sprint assignmentestimatedCost(number, optional): Hours/pointsassignedUserIds(array, optional): User IDs
Response:
{
"items": [
{ "workItemId": 1, "title": "Task 1", ... },
{ "workItemId": 2, "title": "Task 2", ... }
],
"total": 2,
"successful": 2,
"failed": 0,
"errors": [],
"warnings": []
}Examples:
// Single task
await create_work_items({
items: [{
title: 'Implement OAuth',
categoryId: 'programming',
importanceLevelId: 'high',
estimatedCost: 8
}]
});
// Multiple tasks with name resolution
await create_work_items({
projectId: 230954,
items: [
{
title: 'Backend API',
categoryId: 'programming',
tagIds: ['vulkan', 'performance']
},
{
title: 'UI Bug',
categoryId: 'bug',
importanceLevelId: 'urgent'
},
{
title: 'Design Review',
categoryId: 'design',
estimatedCost: 4,
boardId: 650299
}
]
});Update 1-100 work items. Supports auto-creating tags by name.
Parameters:
projectId(number, optional): Project IDitems(array, required): Updates (1-100)workItemId(number, required): Item to updatetitle(string, optional): New titledescription(string, optional): New descriptionstageId(number, optional): Move to stageboardId(number, optional): Move to boardisCompleted(boolean, optional): Mark completedtagIds(array, optional): Replace tags (auto-creates unknowns)assignedUserIds(array, optional): Replace assignmentsparentStoryId(number, optional): Set parent
Response:
{
"items": [
{ "workItemId": 123, "title": "Updated Task", ... }
],
"total": 1,
"successful": 1,
"failed": 0,
"errors": [],
"warnings": ["Auto-created tag: 'new-feature'"]
}Examples:
// Single update
await update_work_items({
items: [{
workItemId: 123,
stageId: 2,
isCompleted: true
}]
});
// Batch updates with tag auto-create
await update_work_items({
items: [
{
workItemId: 123,
tagIds: ['vulkan', 'new-feature'], // Auto-creates 'new-feature'
stageId: 3
},
{
workItemId: 124,
isCompleted: true
},
{
workItemId: 125,
boardId: 650300,
assignedUserIds: [1, 2]
}
]
});Delete 1-100 work items (requires confirmation).
Parameters:
projectId(number, optional): Project IDworkItemIds(array, required): IDs to delete (1-100)
Response (Staging):
{
"status": "confirmation_required",
"confirmationToken": "del_1734567890000_abc123",
"expiresAt": "2025-12-18T15:00:00.000Z",
"preview": {
"totalItems": 3,
"exceedsCache": false,
"itemsAtRisk": 0,
"breakdown": {
"completed": 1,
"inProgress": 1,
"inClosedSprints": 0,
"withLoggedHours": 2
},
"samples": [
{ "workItemId": 1, "title": "Task 1", "status": "completed" }
]
}
}Workflow:
// 1. Stage deletion
const staged = await delete_work_items({
workItemIds: [123, 124, 125]
});
// 2. Review preview
console.log(`Deleting ${staged.preview.totalItems} items`);
console.log(`Breakdown:`, staged.preview.breakdown);
// 3. Confirm
const result = await confirm_deletion({
confirmationToken: staged.confirmationToken,
acknowledged: 'DELETE'
});
// Or cancel
await cancel_deletion({
confirmationToken: staged.confirmationToken
});See Deletion Safety for comprehensive guide.
Add 1-100 comments to work items.
Parameters:
projectId(number, optional): Project IDcomments(array, required): Comments (1-100)workItemId(number, required): Target work itemtext(string, required): Comment text (markdown)
Response:
{
"items": [
{ "commentId": 1, "text": "Comment", "workItemId": 42 }
],
"total": 1,
"successful": 1,
"failed": 0,
"errors": [],
"warnings": []
}Example:
// Add comments to multiple tasks
await add_comments({
comments: [
{
workItemId: 123,
text: '## Progress\n\nCompleted phase 1, moving to testing'
},
{
workItemId: 124,
text: 'Blocked by dependency on #123'
},
{
workItemId: 125,
text: 'Ready for code review'
}
]
});Create 1-100 boards/sprints.
Parameters:
projectId(number, optional): Project IDboards(array, required): Boards to create (1-100)name(string, required): Board namedescription(string, optional): DescriptionstartDate(string, optional): Start date (ISO)endDate(string, optional): End date (ISO)
Response:
{
"items": [
{ "boardId": 1, "name": "Sprint 1", "startDate": "2025-01-01" }
],
"total": 1,
"successful": 1,
"failed": 0,
"errors": [],
"warnings": []
}Example:
// Create quarterly sprints
await create_boards({
boards: [
{
name: 'Sprint 1: Foundation',
startDate: '2025-01-01',
endDate: '2025-01-14'
},
{
name: 'Sprint 2: Core Features',
startDate: '2025-01-15',
endDate: '2025-01-28'
},
{
name: 'Sprint 3: Polish',
startDate: '2025-01-29',
endDate: '2025-02-11'
}
]
});Log work time for 1-100 work items.
Parameters:
projectId(number, optional): Project IDsessions(array, required): Work sessions (1-100)workItemId(number, required): Work item IDhours(number, required): Hours worked (> 0)description(string, optional): Session descriptiondate(string, optional): Date (ISO, default: today)
Response:
{
"items": [
{ "workItemId": 42, "hours": 2.5 }
],
"total": 1,
"successful": 1,
"failed": 0,
"totalHours": 2.5,
"errors": [],
"warnings": []
}Example:
// Log time across multiple tasks
await log_work_sessions({
sessions: [
{
workItemId: 123,
hours: 2,
description: 'Backend API implementation'
},
{
workItemId: 124,
hours: 1.5,
description: 'Code review and testing'
},
{
workItemId: 125,
hours: 0.5,
description: 'Bug fix in auth flow'
}
]
});
// Response: { totalHours: 4 }Note: This tool does NOT integrate with automatic time tracking. Use complete_task for auto-tracked time logging.
All array-based tools return a consistent structure:
interface ArrayResponse<T> {
items: Array<T | null>; // Results (null for failures)
total: number; // Total items processed
successful: number; // Success count
failed: number; // Failure count
errors: ErrorDetail[]; // Per-item errors
warnings: string[]; // Non-fatal warnings
}
interface ErrorDetail {
index: number; // Position in input array (0-based)
error: string; // Error message
item: any; // Original input item
}The items array preserves input order:
- Successful items: Full object at original position
- Failed items:
nullat original position
Example:
const result = await create_work_items({
items: [
{ title: 'Task 1', categoryId: 'programming' }, // Index 0 - success
{ title: 'Task 2', categoryId: 'invalid' }, // Index 1 - fails
{ title: 'Task 3', categoryId: 'design' } // Index 2 - success
]
});
// result.items: [
// { workItemId: 1, title: 'Task 1', ... }, // Index 0
// null, // Index 1 (failed)
// { workItemId: 3, title: 'Task 3', ... } // Index 2
// ]
//
// result.successful: 2
// result.failed: 1
//
// result.errors: [{
// index: 1,
// error: "Invalid category: 'invalid'",
// item: { title: 'Task 2', categoryId: 'invalid' }
// }]Individual failures don't block other items:
const result = await create_work_items({
items: [
{ title: 'Valid 1', categoryId: 'programming' }, // ✅
{ title: 'Invalid', categoryId: 'nonexistent' }, // ❌
{ title: 'Valid 2', categoryId: 'design' }, // ✅
{ title: 'Missing category' }, // ❌ (missing required field)
{ title: 'Valid 3', categoryId: 'bug' } // ✅
]
});
// result.successful: 3
// result.failed: 2
// result.errors: [
// { index: 1, error: "Invalid category...", item: {...} },
// { index: 3, error: "Missing required field...", item: {...} }
// ]const result = await update_work_items({ items: [...] });
if (result.failed > 0) {
console.error(`${result.failed} items failed:`);
result.errors.forEach(err => {
console.error(` Item ${err.index}: ${err.error}`);
console.error(` Input:`, err.item);
});
}
if (result.successful > 0) {
console.log(`✅ Successfully processed ${result.successful} items`);
const successfulItems = result.items.filter(item => item !== null);
// Process successful items...
}Non-fatal warnings (e.g., auto-created tags):
const result = await update_work_items({
items: [{
workItemId: 123,
tagIds: ['existing-tag', 'new-tag']
}]
});
if (result.warnings.length > 0) {
console.warn('Warnings:', result.warnings);
// ["Auto-created tag: 'new-tag'"]
}Before (v7.1.0):
await create_work_item({
title: 'My Task',
categoryId: 'programming'
});After (v7.2.0):
await create_work_items({
items: [{
title: 'My Task',
categoryId: 'programming'
}]
});Tip: Wrap single item in array.
Before (v7.1.0):
await batch_create_work_items({
items: [
{ title: 'Task 1', categoryId: 'programming' },
{ title: 'Task 2', categoryId: 'design' }
]
});After (v7.2.0):
await create_work_items({ // Renamed (no 'batch_' prefix)
items: [
{ title: 'Task 1', categoryId: 'programming' },
{ title: 'Task 2', categoryId: 'design' }
]
});Tip: Remove batch_ prefix, parameters unchanged.
Before (v7.1.0):
// Multiple API calls
await set_work_item_tags({
workItemId: 123,
tagIds: [1, 5]
});
await assign_work_item({
workItemId: 123,
userIds: [10, 20]
});
await set_work_item_parent({
workItemId: 123,
parentStoryId: 100
});After (v7.2.0):
// Single API call
await update_work_items({
items: [{
workItemId: 123,
tagIds: [1, 5],
assignedUserIds: [10, 20],
parentStoryId: 100
}]
});Tip: Use update_work_items for all property changes.
❌ Bad:
for (const id of workItemIds) {
await update_work_items({
items: [{ workItemId: id, stageId: 3 }]
});
}
// N API calls!✅ Good:
await update_work_items({
items: workItemIds.map(id => ({
workItemId: id,
stageId: 3
}))
});
// 1 API callconst result = await update_work_items({ items: updates });
// Separate successful from failed
const successful = result.items
.map((item, i) => ({ item, originalInput: updates[i] }))
.filter(({ item }) => item !== null);
const failed = result.errors.map(err => ({
input: err.item,
error: err.error
}));
// Retry failed items if appropriate
if (failed.length > 0 && shouldRetry(failed)) {
const retryResult = await update_work_items({
items: failed.map(f => f.input)
});
}// Let the API create tags automatically
await update_work_items({
items: [{
workItemId: 123,
tagIds: ['backend', 'urgent', 'new-feature'] // Auto-creates unknowns
}]
});
// Check warnings for created tags
if (result.warnings.length > 0) {
console.log('Auto-created:', result.warnings);
}Max 100 items per call. For larger sets, chunk:
const chunkSize = 100;
const chunks = [];
for (let i = 0; i < allItems.length; i += chunkSize) {
chunks.push(allItems.slice(i, i + chunkSize));
}
for (const chunk of chunks) {
const result = await create_work_items({ items: chunk });
console.log(`Processed ${result.successful}/${result.total}`);
}See Also:
- Work Items API - Full work item documentation
- Deletion Safety - Deletion workflow details
- Slim Mode - Context optimization
- Best Practices - General guidelines