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}` }]
                };
            }
        }
    );
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations provided, so description carries full burden. Reveals critical business rule about Sprint/PlannedRelease ordering constraint not visible in schema structure. However, missing safety profile (idempotency, reversibility, validation behavior) and error scenarios (what happens if dbid invalid?).

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Second sentence 'Provide the fields you want to update with their new values' is redundant given schema's 'Array of fields to update' description. The Sprint/PlannedRelease constraint requires four sentences where two would suffice. Well front-loaded with main purpose.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Addresses the most critical domain constraint (Sprint/Release ordering) preventing common usage errors. However, for a mutation tool with no annotations and no output schema, omits operational context such as success indicators, partial update behavior, or permission requirements.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema has 100% description coverage (baseline 3). Description adds crucial semantic context that Sprint values must correspond to the PlannedRelease value, and provides concrete value format examples ('Sprint 1 - Planning & Foundation', 'Release 2') beyond schema's generic 'The new value' description.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description opens with specific verb 'Updates' and resource 'fields of an existing work item', clearly distinguishing from sibling tools like create_work_item (creates new) and delete_work_item (removes). The scope is precisely defined as field-level updates rather than state transitions (change_work_item_state).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides explicit prerequisite guidance: 'Always update PlannedRelease before updating Sprint field' and explains the dependency constraint ('you cannot assign a sprint... unless that work item is already part of the release'). Lacks explicit comparison to alternatives (e.g., 'use create_work_item for new items').

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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