list_metafields
List metafields from a Shopify resource to inspect custom data. Filter by namespace to scope results. Use before setting metafields or to audit existing values.
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. Executes a GraphQL query to fetch metafields for a given ownerId, optionally filtered by namespace, with pagination support. Returns formatted text listing each metafield's namespace.key, type, value, and description.
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)Input schema for list_metafields: ownerId (required), namespace (optional filter), first (pagination limit, default 50).
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 with the MCP server, including description, schema, 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/tools/metafields.ts:46-68 (helper)GraphQL query used by the handler to fetch metafields from Shopify. Uses the HasMetafields interface, supports namespace filtering and cursor-based pagination.
const GET_METAFIELDS_QUERY = /* GraphQL */ ` query GetMetafields($ownerId: ID!, $first: Int!, $namespace: String) { node(id: $ownerId) { ... on HasMetafields { metafields(first: $first, namespace: $namespace) { edges { node { id namespace key type value description createdAt updatedAt } } pageInfo { hasNextPage endCursor } } } } } `;