Skip to content

Add update_project_items batch/bulk field-value writes via aliased GraphQL mutations#2903

Draft
veralizeth wants to merge 5 commits into
zwick-paginate-project-item-lookupfrom
veralizeth/mcp-batch-bulk-field-value
Draft

Add update_project_items batch/bulk field-value writes via aliased GraphQL mutations#2903
veralizeth wants to merge 5 commits into
zwick-paginate-project-item-lookupfrom
veralizeth/mcp-batch-bulk-field-value

Conversation

@veralizeth

@veralizeth veralizeth commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds batched project field-value writes to update_project_items using chunked, aliased GraphQL update and clear mutations. Results remain input-ordered and report succeeded, failed, or unknown per item.

Why

Implements the MCP portion of https://github.com/github/planning-tracking/issues/3331; CLI work will follow separately. This PR is stacked on #2914 for paginated issue-to-project-item resolution.

What changed

  • Resolves the project once, caches field metadata by name and numeric ID, and resolves item references from node_id, numeric item_id, or repository issue coordinates before writing.
  • Converts TEXT, NUMBER, DATE, SINGLE_SELECT, and ITERATION values; null clears a field. Invalid values, unsupported updates, and duplicate item+field targets fail deterministically without blocking valid siblings.
  • Sends update and clear work in sequential chunks of 20 using positional reflected aliases and variables through the existing authenticated githubv4.Client.
  • Preserves confirmed aliases on partial GraphQL errors, marks unconfirmed writes unknown, and stops later chunks after transport, timeout, cancellation, or missing-data ambiguity. No automatic retries or per-item fallback writes are issued.

MCP impact

  • No tool or API changes
  • Tool schema or behavior changed
  • New tool added

update_project_items adds node_id references and structured tri-state batch results. Existing single-item behavior is unchanged.

Prompts tested (tool changes only)

  • "Set Status to Done for project items 1001 and 1002"
  • "Update an issue's Notes field and clear its Estimate field"
  • "Update 21 project items in one call"

Security / limits

  • No security or limits impact
  • Auth / permissions considered
  • Data exposure, filtering, or token/size limits considered

Uses the existing injected REST and GraphQL clients and project scope. The tool cap remains 100 items; numeric reads are deduplicated with at most five in flight, while writes remain sequential. The 20-write wire chunk is provisional and leaves headroom under typical 10-second request timeouts; it is not based on a live benchmark.

Tool renaming

  • I am renaming tools as part of this PR (e.g. a part of a consolidation effort)
    • I have added the new tool aliases in deprecated_tool_aliases.go
  • I am not renaming tools as part of this PR

Note: if you're renaming tools, you must add the tool aliases. For more information on how to do so, please refer to the official docs.

Lint & tests

  • Linted locally with ./script/lint
  • Tested locally with ./script/test

Docs

  • Not needed
  • Updated (README / docs / examples)

@Swastiksrijan

Copy link
Copy Markdown

go

@zwick zwick self-assigned this Jul 20, 2026
@zwick
zwick force-pushed the veralizeth/mcp-batch-bulk-field-value branch from 15ca2ee to b8f5ca9 Compare July 20, 2026 19:43
@zwick
zwick changed the base branch from main to zwick-paginate-project-item-lookup July 20, 2026 19:43
@zwick zwick changed the title Adding an initial draft of batch/bulk field-value writes Adding an initial draft of batch/bulk field-value writes Jul 20, 2026
@zwick zwick changed the title Adding an initial draft of batch/bulk field-value writes Add update_project_items batch/bulk field-value writes via aliased GraphQL mutations Jul 20, 2026
zwick and others added 3 commits July 20, 2026 16:25
Extend ResolvedField with the GraphQL node ID alongside the existing
numeric databaseId, and extend the #2914 paginated issue-item resolver
to also return the item's node ID (resolveProjectItemByIssueNumber),
keeping resolveProjectItemIDByIssueNumber as a numeric-only wrapper for
existing callers. These node IDs are what the upcoming aliased
GraphQL mutations need as ItemID/FieldID inputs, in place of the
numeric IDs the REST API takes.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d7dc302d-e6f2-41e9-a2c8-ed598de47067
Add projects_batch_mutation.go: builds a runtime struct type
(reflect.StructOf) for sending up to 20 aliased
updateProjectV2ItemFieldValue / clearProjectV2ItemFieldValue mutations
in a single GraphQL request, still via the existing authenticated
*githubv4.Client.

Fields and aliases are purely positional (Item0/item0, Item1/item1,
...); per the pinned githubv4.Client.Mutate signature, the first
input is always sent under the $input variable, so aliases 1+
reference $input1, $input2, ... via the variables map. Reflected
types are cached by (operation kind, chunk size) only, never by
request data.

This file is not yet wired up to any caller.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d7dc302d-e6f2-41e9-a2c8-ed598de47067
Rewire update_project_items to resolve the project, every distinct
field, and every item once up front, then write via the
projects_batch_mutation.go aliased-mutation builder, chunked into
sequential requests of 20, instead of one REST PATCH per item.

- projects_batch_resolve.go: field/item resolution. Adds node_id as a
  third item-reference form (alongside item_id and
  item_owner+item_repo+issue_number, exactly one required per item),
  bypassing REST lookup entirely. Numeric item_id values are
  deduplicated and resolved to node IDs via bounded-concurrency REST
  GETs; issue refs are deduplicated and resolved via the paginated
  resolver from the previous commit. updated_field.value is converted
  to the matching ProjectV2FieldValue member for TEXT, NUMBER, DATE,
  SINGLE_SELECT, and ITERATION; null routes to the clear mutation.
- projects_batch.go: orchestration. Rejects duplicate item+field
  targets before any writes, partitions into update/clear chunks, and
  tracks tri-state per-item results (succeeded/failed/unknown). After
  an ambiguous transport-level failure or context cancellation, no
  further chunks are sent.
- projects.go: removed the old REST-loop implementation and its
  helpers; added node_id to the update_project_items item schema.
- Removed the stale comment claiming the pinned client couldn't build
  dynamic aliases.
- Updated/added tests accordingly, including toolsnap and README
  regeneration for the schema change.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d7dc302d-e6f2-41e9-a2c8-ed598de47067
@zwick
zwick force-pushed the veralizeth/mcp-batch-bulk-field-value branch from 983d5f4 to 047505f Compare July 20, 2026 20:26
Distinguish GraphQL response errors from ambiguous transport or missing-data responses, validate numeric references before narrowing them, reuse the resolved project ID for issue lookups, and cache field-load failures. Add focused regression coverage and align the tool schema with the supported issue-reference contract.\n\nCo-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>\nCopilot-Session: d7dc302d-e6f2-41e9-a2c8-ed598de47067
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants