Skip to main content
Glama
mrchris2000

MCP DevOps Plan Server

by mrchris2000

update_work_item

Modify existing work item fields like description, owner, sprint, or release. Ensure PlannedRelease is set before assigning Sprint to maintain proper hierarchy.

Instructions

Updates fields of an existing work item. Provide the fields you want to update with their new values. IMPORTANT: When assigning a Sprint to a work item, the work item MUST first have the corresponding Release assigned to its PlannedRelease field. You cannot assign a sprint to a work item unless that work item is already part of the release that owns the sprint. Always update PlannedRelease before updating Sprint field.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
dbidYesThe dbid field from the workitem to identify it
applicationYesName of the application
fieldsYesArray of fields to update. CRITICAL: To assign a Sprint, first ensure PlannedRelease is set to the release that contains that sprint, otherwise the Sprint assignment will fail.

Implementation Reference

  • The implementation of the `update_work_item` tool. It uses a multi-step PATCH sequence (Modify action, Edit operation, Commit operation) to update fields of an existing WorkItem entity in Plan.
    server.tool(
        "update_work_item",
        "Updates fields of an existing work item. Provide the fields you want to update with their new values. IMPORTANT: When assigning a Sprint to a work item, the work item MUST first have the corresponding Release assigned to its PlannedRelease field. You cannot assign a sprint to a work item unless that work item is already part of the release that owns the sprint. Always update PlannedRelease before updating Sprint field.",
        {
            dbid: z.string().describe("The dbid field from the workitem to identify it"),
            application: z.string().describe("Name of the application"),
            fields: z.array(z.object({
                name: z.string().describe("Field name (e.g., 'Description', 'Owner', 'Component', 'Sprint', 'PlannedRelease', 'StoryPoints', 'BusinessValue', etc.)"),
                value: z.string().describe("The new value for the field. For 'Sprint' field, use the exact sprint name (e.g., 'Sprint 1 - Planning & Foundation'). For 'PlannedRelease' field, use the exact release name (e.g., 'Release 2')."),
                type: z.string().optional().describe("Field type (e.g., 'SHORT_STRING', 'MULTILINE_STRING', 'INT', 'REFERENCE', 'DATE_TIME'). Use 'REFERENCE' for Sprint and PlannedRelease fields. Defaults to 'SHORT_STRING'."),
            })).describe("Array of fields to update. CRITICAL: To assign a Sprint, first ensure PlannedRelease is set to the release that contains that sprint, otherwise the Sprint assignment will fail."),
        },
        async ({ dbid, application, fields }) => {
            try {
                if (!globalCookies) {
                    globalCookies = await getCookiesFromServer(serverURL);
                    if (!globalCookies) {
                        console.error("Failed to retrieve cookies from server.");
                        return { error: "Failed to retrieve cookies." };
                    }
                    console.log("Received Cookies:", globalCookies);
                } else {
                    console.log("Reusing Stored Cookies:", globalCookies);
                }
    
                // Step 1: Modify action + Edit operation with empty body (like UI does)
                const modifyUrl = `${serverURL}/ccmweb/rest/repos/${teamspaceID}/databases/${application}/records/WorkItem/${dbid}?actionName=Modify&operation=Edit&useDbid=true`;
                
                const modifyResponse = await fetch(modifyUrl, {
                    method: 'PATCH',
                    headers: {
                        'Content-Type': 'application/json',
                        'Accept': 'application/json',
                        'Authorization': `Basic ${personal_access_token_string}`,
                        'Cookie': globalCookies
                    },
                    body: "{}"
                , ...getAgentOptions(serverURL)
                });
    
                if (!modifyResponse.ok) {
                    const errorText = await modifyResponse.text();
                    throw new Error(`Modify action failed: ${modifyResponse.statusText} - ${errorText}`);
                }
    
                console.log("Modify action successful");
    
                // Step 2: Edit operation with simple field structure (name and value only)
                const editBody = {
                    fields: fields.map(field => ({
                        name: field.name,
                        value: field.value
                    }))
                };
    
                const editUrl = `${serverURL}/ccmweb/rest/repos/${teamspaceID}/databases/${application}/records/WorkItem/${dbid}?operation=Edit&useDbid=true`;
                
                const editResponse = await fetch(editUrl, {
                    method: 'PATCH',
                    headers: {
                        'Content-Type': 'application/json',
                        'Accept': 'application/json',
                        'Authorization': `Basic ${personal_access_token_string}`,
                        'Cookie': globalCookies
                    },
                    body: JSON.stringify(editBody)
                , ...getAgentOptions(serverURL)
                });
    
                if (!editResponse.ok) {
                    const errorText = await editResponse.text();
                    throw new Error(`Edit operation failed: ${editResponse.statusText} - ${errorText}`);
                }
    
                const editData = await editResponse.json();
                console.log("Edit operation successful");
    
                // Step 3: Commit operation with full field structure
                const commitBody = {
                    dbId: dbid,
                    fields: fields.map(field => ({
                        name: field.name,
                        value: field.value,
                        valueStatus: field.value ? "HAS_VALUE" : "HAS_NO_VALUE",
                        validationStatus: "_KNOWN_VALID",
                        requiredness: "OPTIONAL",
                        requirednessForUser: "OPTIONAL",
                        type: field.type || "SHORT_STRING",
                        valueAsList: field.value ? [field.value] : [],
                        messageText: "",
                        maxLength: field.type === "SHORT_STRING" ? 254 : 0
                    }))
                };
    
                const commitUrl = `${serverURL}/ccmweb/rest/repos/${teamspaceID}/databases/${application}/records/WorkItem/${dbid}?operation=Commit&useDbid=true`;
                
                const commitResponse = await fetch(commitUrl, {
                    method: 'PATCH',
                    headers: {
                        'Content-Type': 'application/json',
                        'Accept': 'application/json',
                        'Authorization': `Basic ${personal_access_token_string}`,
                        'Cookie': globalCookies
                    },
                    body: JSON.stringify(commitBody)
                , ...getAgentOptions(serverURL)
                });
    
                if (commitResponse.ok) {
                    const result = await commitResponse.json();
                    const updatedFields = fields.map(f => `- ${f.name}: ${f.value}`).join('\n');
                    return {
                        content: [{ type: 'text', text: `Work item ${dbid} updated successfully.\n\nUpdated fields:\n${updatedFields}` }]
                    };
                } else {
                    const errorText = await commitResponse.text();
                    throw new Error(`Commit operation failed: ${commitResponse.statusText} - ${errorText}`);
                }
            } catch (e) {
                return {
                    content: [{ type: 'text', text: `Error updating work item: ${e.message}` }]
                };
            }
        }
    );

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/mrchris2000/mcp-devops-plan'

If you have feedback or need assistance with the MCP directory API, please join our Discord server