Skip to content

Improve AI agent usability across all MCP tools - #14

Open
lucasjahn wants to merge 7 commits into
GeLi2001:mainfrom
lucasjahn:feat/ai-agent-tool-improvements
Open

Improve AI agent usability across all MCP tools#14
lucasjahn wants to merge 7 commits into
GeLi2001:mainfrom
lucasjahn:feat/ai-agent-tool-improvements

Conversation

@lucasjahn

Copy link
Copy Markdown
Contributor

Problem

When an AI agent/LLM consumed this MCP toolset autonomously, it hits several friction points that cause unnecessary round-trips, context bloat, and outright errors:

  1. Response bloat: Every GET tool returns all fields by default. An agent asking "what's the product title?" gets back variants, media, SEO, collections, and more — flooding its context window.
  2. Blind pagination: No way to know how many results exist before fetching.
  3. Inconsistent ID formats: Some tools expect numeric IDs, others expect full GIDs, but descriptions didn't clarify which.
  4. Missing cross-tool references: e.g. create-fulfillment requires a fulfillmentOrderId but nothing told the agent to call get-fulfillment-orders first.
  5. Unsafe defaults: Customer notification params could send real emails/SMS without user confirmation.
  6. Free-text where enums exist: inventory-set-quantities.reason accepted any string but Shopify rejects invalid values.
  7. No bulk tag operations: Tagging 50 resources required 50 sequential calls.

Solution

Iterative improvements driven by a consumer AI agent auditing all 45 tools.

  • Field selection (fields param) on all GET tools — fetch only what you need
  • Count-only mode (countOnly) on list tools — { count: N } without data
  • Bulk tag management — new manage-tags-bulk for up to 100 resources
  • Description consistency — ID format examples, cross-tool hints, metafield upsert semantics, notification safety warnings
  • Correctness — reason enum with 17 valid Shopify values
  • README — updated from 31 to 45 tools with new sections

All changes are backwards compatible. No new dependencies.

List tools (orders, products, customers, collections) now accept an
optional 'fields' parameter to select which fields the GraphQL query
returns, reducing context pollution when only IDs or specific data is
needed. Max page size raised from 10-100 to 250 (Shopify API limit).

Affected tools: get-orders, get-products, get-customers,
get-collections, get-customer-orders
Make descriptions more assertive so AI agents actually use the fields
parameter instead of fetching all data. Descriptions now tell agents
to always specify fields, and to ask the user which fields are needed
when unsure rather than defaulting to all fields.
… and bulk tags

Driven by iterative feedback from an AI consumer agent testing all 45 tools,
this addresses the main friction points when an LLM operates the MCP toolset
without human guidance.

Field selection & countOnly:
- Add `fields` param to all GET tools (products, orders, customers, collections,
  metafields, variants) so agents fetch only the data they need
- Add `countOnly` param to list tools (get-products, get-orders, get-customers,
  get-customer-orders) to size result sets before paginating
- Increase max page size from 50 to 250 on list endpoints

Bulk tag management:
- Add manage-tags-bulk tool for batch add/remove on up to 100 resources

Description clarity & consistency:
- Add format examples to all ID params (GID vs numeric, with examples)
- Add cross-tool navigation hints (e.g. create-fulfillment references
  get-fulfillment-orders for obtaining required IDs)
- Add metafield upsert semantics to all update tools
- Add customer notification safety warnings requiring user confirmation
- Change inventory-set-quantities reason from free text to validated enum

Collection improvements:
- Add field selection to get-collection-by-id

README:
- Update tool count from 31 to 45
- Document new sections: Collections, Configuration, Enhanced Order,
  Inventory & Pricing, shared field selection and countOnly capabilities
@GeLi2001

GeLi2001 commented Apr 5, 2026

Copy link
Copy Markdown
Owner

hi @lucasjahn thanks for the PR, I found there's merge conflicts after #13 got merged, can you sync with origin main again? thanks

@bhargav-nexie

Copy link
Copy Markdown

Hi, just curious. Do we have some bandwidth issues to get this merged?

If yes, are you guys open for help here? Would love to contribute and get this merged before I use this in my project.

lucasjahn and others added 4 commits June 22, 2026 09:44
Resolves conflicts from upstream's "Add Shopify GraphQL codegen
validation" change, which added #graphql magic comments so codegen
validates queries against the live Shopify schema.

Conflict: the field-selection tools build queries dynamically via
${fieldSelection} interpolation, which is incompatible with static
codegen extraction (interpolations are stripped, yielding empty
selection sets). graphql-tag-pluck only picks up gql-tagged /
#graphql documents, so the dynamic queries use plain template
strings and are simply skipped by validation (their result type was
already `any`, so no type coverage is lost).

Resolution for the 10 conflicted GET tools: keep the dynamic
plain-string queries (field selection, countOnly, and getMetafields'
keys/namespace branches). Every fully-static query elsewhere keeps
its gql/#graphql tag and stays schema-validated.

Verified: `npm run build` and `npm run validate:graphql` both pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Deepening refactor (architecture review candidates A + B). The field
selection feature was three shallow pieces kept in sync by hand across
10 GET tools: a FIELD_MAP of fragments, an AVAILABLE_*_FIELDS enum, a
~450-char copy-pasted "always specify fields" describe string, and a
per-tool formatter that re-discovered which fields are connections.

defineProjection() in src/lib/projection.ts is now the single source of
truth per tool. From one field→fragment map it derives:
- selection(fields): the GraphQL selection set (id always included),
  joined with newlines — removes the hidden 16-space indent coupling in
  the old buildFieldSelection (GraphQL is whitespace-insensitive).
- fieldsParam({noun, extra}): the zod `fields` param with the shared
  agent guidance baked in — the describe text now lives in exactly one
  place instead of being copy-pasted (with drift) across 10 files.
- normalize(node): flattens any top-level connection-shaped value
  ({edges:[...]}) to an array of nodes. Shape-based, so field aliases
  (e.g. addressesV2 under key "addresses") are handled correctly.
countOnlyParam() likewise centralizes the countOnly guidance.

Pure refactor — output shapes unchanged. Per-tool renames (priceRangeV2
→priceRange, addressesV2→addresses), computed fields (imageUrl, variant
image), and formatOrderSummary delegation are preserved; default
(no-fields) paths are untouched. getMetafields keeps its own keys/
namespace model. buildFieldSelection removed.

Net: tools shrink by ~200 lines; selection/normalize are now pure and
unit-testable without the GraphQL client global.

Verified: npm run build and npm run validate:graphql both pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
`fallow` flagged the count-only block as duplicated across the four list
tools (get-products, get-orders, get-customers, get-customer-orders) —
each inlined a near-identical *Count query, request, and unwrap that
differed only by the count field name and the query filter.

Add fetchCount(client, countField, query?) to projection.ts (alongside
countOnlyParam, its schema counterpart) and call it from all four tools.
Pure refactor — behavior unchanged.

Verified: npm run build and npm run validate:graphql both pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The shared `fields` guidance hardcoded the example ["id", "title"], but
orders use `name` and customers have no `title` field — an agent copying
the example into get-orders/get-customers would hit a zod enum rejection.

Derive the example field from the projection's own fields (first non-id
key), so the example is always a valid selection for that tool.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@lucasjahn

Copy link
Copy Markdown
Contributor Author

@GeLi2001 you can have another look over it. It diverged a bit from main so I had to make some conflict resolving.

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