list_metafields
Retrieve metafields attached to a Shopify resource to inspect current custom data, filter by namespace, and audit which apps have written values before setting a metafield.
Instructions
List metafields attached to a single Shopify resource. Returns each metafield's namespace.key, type, current value, and optional description. Pass a namespace to scope the read to one app/integration's metafields (recommended when the resource has many). Empty result is normal for resources without metafields. Use this to inspect existing custom data before calling set_metafield, or to audit which apps have written what to a record.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| ownerId | Yes | GID of the resource to read metafields from. | |
| namespace | No | Filter to a single namespace. Omit to return all. | |
| first | No |
Implementation Reference
- src/tools/metafields.ts:168-210 (handler)The handler function for the 'list_metafields' tool. It executes a GraphQL query (GET_METAFIELDS_QUERY) to fetch metafields for a given ownerId, optionally filtered by namespace, and formats the results into a text response. Handles empty results and pagination hints.
async (args) => { const data = await client.graphql<{ node: { metafields?: { edges: Array<{ node: Metafield }>; pageInfo: { hasNextPage: boolean; endCursor?: string | null }; }; } | null; }>(GET_METAFIELDS_QUERY, { ownerId: args.ownerId, first: args.first, namespace: args.namespace, }); if (!data.node) { return { content: [ { type: "text" as const, text: `Owner not found: ${args.ownerId}` }, ], }; } const edges = data.node.metafields?.edges ?? []; if (edges.length === 0) { return { content: [ { type: "text" as const, text: `No metafields on ${args.ownerId}${args.namespace ? ` (namespace=${args.namespace})` : ""}.`, }, ], }; } const lines = [ `Found ${edges.length} metafield(s):`, ...edges.map(({ node }) => { const desc = node.description ? ` — ${node.description}` : ""; return ` ${node.namespace}.${node.key} (${node.type}) = ${node.value}${desc}`; }), ]; if (data.node.metafields?.pageInfo.hasNextPage) { lines.push("(more available; raise `first` to page further)"); } return { content: [{ type: "text" as const, text: lines.join("\n") }] }; }, - src/tools/metafields.ts:98-105 (schema)The input schema for the 'list_metafields' tool. Defines parameters: ownerId (string, required), namespace (string, optional), and first (number, default 50, min 1, max 100).
const listMetafieldsSchema = { ownerId: z.string().describe("GID of the resource to read metafields from."), namespace: z .string() .optional() .describe("Filter to a single namespace. Omit to return all."), first: z.number().int().min(1).max(100).default(50), }; - src/tools/metafields.ts:164-211 (registration)Registration of the 'list_metafields' tool on the MCP server via server.tool(), binding the name, description, schema (listMetafieldsSchema), and handler.
server.tool( "list_metafields", "List metafields attached to a single Shopify resource. Returns each metafield's namespace.key, type, current value, and optional description. Pass a `namespace` to scope the read to one app/integration's metafields (recommended when the resource has many). Empty result is normal for resources without metafields. Use this to inspect existing custom data before calling set_metafield, or to audit which apps have written what to a record.", listMetafieldsSchema, async (args) => { const data = await client.graphql<{ node: { metafields?: { edges: Array<{ node: Metafield }>; pageInfo: { hasNextPage: boolean; endCursor?: string | null }; }; } | null; }>(GET_METAFIELDS_QUERY, { ownerId: args.ownerId, first: args.first, namespace: args.namespace, }); if (!data.node) { return { content: [ { type: "text" as const, text: `Owner not found: ${args.ownerId}` }, ], }; } const edges = data.node.metafields?.edges ?? []; if (edges.length === 0) { return { content: [ { type: "text" as const, text: `No metafields on ${args.ownerId}${args.namespace ? ` (namespace=${args.namespace})` : ""}.`, }, ], }; } const lines = [ `Found ${edges.length} metafield(s):`, ...edges.map(({ node }) => { const desc = node.description ? ` — ${node.description}` : ""; return ` ${node.namespace}.${node.key} (${node.type}) = ${node.value}${desc}`; }), ]; if (data.node.metafields?.pageInfo.hasNextPage) { lines.push("(more available; raise `first` to page further)"); } return { content: [{ type: "text" as const, text: lines.join("\n") }] }; }, ); - src/server.ts:61-61 (registration)Top-level registration call: registerMetafieldTools is invoked with the MCP server and Shopify client in the server setup.
registerMetafieldTools(s, shopify);