Skip to main content
Glama

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

TableJSON Schema
NameRequiredDescriptionDefault
ownerIdYesGID of the resource to read metafields from.
namespaceNoFilter to a single namespace. Omit to return all.
firstNo

Implementation Reference

  • 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") }] };
    },
  • 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),
    };
  • 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") }] };
      },
    );
  • 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 }
            }
          }
        }
      }
    `;
Behavior4/5

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

No annotations provided, so the description carries the full burden. It correctly identifies this as a read operation, describes the output fields, and normalizes empty results. It does not mention pagination beyond the 'first' parameter which is already in schema, but overall behavior is well-conveyed.

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

Conciseness5/5

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

Three sentences: first states purpose, second explains return content, third gives usage guidance. Front-loaded with key information, no fluff, every sentence adds value.

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

Completeness4/5

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

For a list tool with 3 parameters and no output schema, the description covers purpose, return structure, usage context, and a common scenario (empty results). It could mention pagination behavior (cursor-based) but overall is fairly complete.

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

Parameters3/5

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

The description adds context for the 'namespace' parameter (scope to one app/integration, recommended for many metafields). However, it does not mention the 'first' parameter (pagination) though schema has 67% coverage. The description provides some added value beyond schema but not fully compensates for the missing parameter 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?

The description clearly states the tool lists metafields for a single Shopify resource, specifies what is returned (namespace.key, type, value, description), and distinguishes from siblings like set_metafield and delete_metafield. It is specific with verb and resource.

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?

The description provides clear usage context: use before set_metafield or for auditing, and recommends passing namespace when resource has many metafields. However, it does not explicitly state when not to use it or name alternative tools beyond set_metafield.

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/miller-joe/shopify-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server