Skip to main content
Glama
BandaruDheeraj

TestFlight Feedback MCP Server

get_feedback_detail

Retrieve comprehensive details for a TestFlight feedback submission, including device information, tester details, screenshot assets, or crash log references.

Instructions

Get detailed information about a specific feedback submission, including device info, tester details, screenshot asset, or crash log reference.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
submission_idYesThe feedback submission ID
typeYesType of feedback submission

Implementation Reference

  • Zod schema defining the input for get_feedback_detail: requires submission_id (string) and type (enum: 'screenshot' | 'crash').
    export const getFeedbackDetailSchema = z.object({
      submission_id: z.string().describe("The feedback submission ID"),
      type: z
        .enum(["screenshot", "crash"])
        .describe("Type of feedback submission"),
    });
  • Handler function that fetches a feedback detail from App Store Connect API, resolves included betaTester and build relationships, and returns a structured response with device info, tester details, screenshot asset, or crash log reference.
    export async function handleGetFeedbackDetail(
      client: AppStoreConnectClient,
      args: z.infer<typeof getFeedbackDetailSchema>
    ) {
      const endpoint =
        args.type === "screenshot"
          ? `/betaFeedbackScreenshotSubmissions/${args.submission_id}`
          : `/betaFeedbackCrashSubmissions/${args.submission_id}`;
    
      const response = await client.request<JsonApiResource>(endpoint, {
        include: "betaTester,build",
        "fields[betaTesters]": "firstName,lastName,email",
        "fields[builds]": "version,uploadedDate",
      });
    
      const data = response.data;
      const included = response.included ?? [];
      const attrs = data.attributes as Record<string, unknown>;
    
      const testerRef = data.relationships?.betaTester?.data;
      const buildRef = data.relationships?.build?.data;
    
      const tester =
        testerRef && !Array.isArray(testerRef)
          ? included.find((r) => r.type === "betaTesters" && r.id === testerRef.id)
          : null;
      const build =
        buildRef && !Array.isArray(buildRef)
          ? included.find((r) => r.type === "builds" && r.id === buildRef.id)
          : null;
    
      const testerAttrs = tester?.attributes as
        | { firstName?: string; lastName?: string; email?: string }
        | undefined;
      const buildAttrs = build?.attributes as
        | { version?: string; uploadedDate?: string }
        | undefined;
    
      return {
        id: data.id,
        type: args.type,
        timestamp: attrs.timestamp,
        comment: attrs.comment ?? null,
        tester: testerAttrs
          ? {
              name: `${testerAttrs.firstName ?? ""} ${testerAttrs.lastName ?? ""}`.trim(),
              email: testerAttrs.email,
            }
          : null,
        build: buildAttrs
          ? {
              version: buildAttrs.version,
              uploadedDate: buildAttrs.uploadedDate,
            }
          : null,
        device: {
          model: attrs.deviceModel,
          osVersion: attrs.osVersion,
          locale: attrs.locale,
          carrier: attrs.carrier,
          timezone: attrs.timezone,
          architecture: attrs.architecture,
          connectionStatus: attrs.connectionStatus,
          batteryPercentage: attrs.batteryPercentage,
          appUptime: attrs.appUptime,
          screenResolution:
            attrs.screenWidth != null
              ? `${attrs.screenWidth}x${attrs.screenHeight}`
              : null,
          diskSpaceFree: attrs.diskSpaceFree,
        },
        screenshot:
          args.type === "screenshot" && attrs.screenshotAsset
            ? attrs.screenshotAsset
            : null,
        crashLog:
          args.type === "crash"
            ? {
                url: `https://api.appstoreconnect.apple.com/v1/betaFeedbackCrashSubmissions/${data.id}/relationships/crashLog`,
              }
            : null,
      };
    }
  • src/index.ts:100-110 (registration)
    Registration of the 'get_feedback_detail' tool with the MCP server, wiring the schema and handler together.
    server.tool(
      "get_feedback_detail",
      "Get detailed information about a specific feedback submission, including device info, tester details, screenshot asset, or crash log reference.",
      getFeedbackDetailSchema.shape,
      async (args) => {
        const result = await handleGetFeedbackDetail(client, args);
        return {
          content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
        };
      }
    );
  • Imports for the file: zod for validation, AppStoreConnectClient type, and JsonApiResource type.
    import { z } from "zod";
    import type { AppStoreConnectClient } from "../api/client.js";
    import type { JsonApiResource } from "../api/types.js";
Behavior3/5

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

No annotations are provided, so the description carries the full burden. It reveals that the tool returns details contingent on the 'type' parameter (screenshot asset or crash log reference), but it does not disclose permissions, rate limits, or the exact structure of the response. Given the conditional nature implied by the enum, more explicit behavioral notes would be beneficial.

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?

The description is a single 16-word sentence that immediately states the verb and resource, then lists included items. There is no wasted text, and it is well-structured for quick parsing by an AI agent.

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?

With no output schema, the description reasonably covers the return content (device info, tester details, screenshot or crash reference). While it does not detail the exact structure or nesting, the tool's low parameter count and simple purpose make the description sufficiently complete for most usage scenarios.

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

Parameters4/5

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

The input schema has 100% description coverage, and the description adds value by explaining that the 'type' parameter determines whether the response includes a screenshot asset or crash log reference. This linkage between parameters and return content goes beyond the schema's bare descriptions.

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 explicitly states the verb 'Get' and the resource 'detailed information about a specific feedback submission', listing specific content like device info, tester details, screenshot asset, or crash log reference. This clearly distinguishes it from sibling tools like list_feedback (lists summaries) and get_crash_log (standalone crash log retrieval).

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 indicates this tool is used for obtaining detailed info on a single feedback submission, implying it is suitable after a list operation. While it does not explicitly state when not to use it or mention alternatives, the purpose is clear enough for an agent to infer appropriate usage from the sibling context (e.g., use list_feedback first, then this).

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/BandaruDheeraj/testflight-feedback-mcp'

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