Skip to main content
Glama

get_testcase_details

Retrieve detailed test case information including error messages, code snippets, test steps, and artifacts to debug test failures.

Instructions

Get detailed information about a specific test case. You can identify the test case in two ways: 1) By testcase_id (can be used alone), or 2) By testcase_name combined with testrun_id or counter (required because test cases can have the same name across different test runs). Returns error message, code snippet, file location, test steps per attempt, console logs, and optional artifacts (screenshots, videos, traces). Use steps_filter='failed_only' to return only steps that errored, stripping passing setup/hook steps. Use this to debug why a test failed or understand how it executed. Example: 'Get test case details for "Verify user can logout and login" in testrun #43'.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
projectIdYesProject ID (Required). The TestDino project identifier.
testcase_idNoTest case ID. Can be used alone to get test case details. Example: 'test_case_123'.
testcase_nameNoTest case title (partial match, case-insensitive). Must be combined with testrun_id or counter when used alone. Example: 'Verify user can logout and login'.
testcase_fulltitleNoFull test case title including suite path (partial match, case-insensitive). Example: 'auth.spec.js > Login > Verify user can logout and login'.
testrun_idNoSingle test run ID to filter results. Example: 'test_run_6901b2abc6b187e63f536a6b'.
testrun_idsNoMultiple test run IDs (comma-separated, max 20). Example: 'test_run_abc,test_run_def'.
testsuite_idNoFilter by test suite ID.
counterNoTest run counter number. Alternative to testrun_id to identify the test run. Example: 43.
by_statusNoFilter by test case status.
by_error_messageNoSearch in error messages (partial match, case-insensitive). Example: 'Timeout 15000ms exceeded'.
by_code_snippetNoSearch in error code snippets (partial match, case-insensitive).
include_historyNoInclude historical executions of the same test case when searching by name. Default: false.
history_limitNoMax number of history entries to return (default: 10).
include_artifactsNoInclude all artifacts (screenshots, traces, videos, attachments) with authenticated URLs. Default: false.
include_screenshotsNoInclude screenshot URLs from test attempts. Default: false.
include_tracesNoInclude Playwright trace links from test attempts. Default: false.
include_videosNoInclude video recording URLs from test attempts. Default: false.
include_attachmentsNoInclude all attachment metadata from test attempts. Default: false.
steps_filterNoFilter steps in each attempt. Use 'failed_only' to return only steps with errors, stripping passing setup and hook steps.
limitNoMax results to return (default: 1 for ID lookup, 50 for search, max: 1000).
pageNoPage number for pagination (default: 1).
sort_byNoSort results by field (default: startTime).
sort_orderNoSort direction (default: desc).
get_allNoReturn all matching results up to 1000 (default: false).

Implementation Reference

  • Main handler function that executes the tool logic. Validates API key, checks search parameters, builds the query, calls the API endpoint, and returns the test case details with optional screenshot detection.
    export async function handleGetTestCaseDetails(args?: GetTestCaseDetailsArgs) {
      // Read PAT from environment variable (set in mcp.json) or from args
      const token = getApiKey(args);
    
      if (!token) {
        throw new Error(
          "Missing TESTDINO_PAT environment variable. " +
            "Please configure it in your .cursor/mcp.json file under the 'env' section."
        );
      }
    
      // Validate: need at least one search parameter
      const hasTestCaseId = !!args?.testcase_id;
      const hasSearchParam = !!(
        args?.testcase_name ||
        args?.testcase_fulltitle ||
        args?.by_error_message ||
        args?.by_code_snippet ||
        args?.by_status
      );
    
      if (!hasTestCaseId && !hasSearchParam) {
        throw new Error(
          "At least one of the following must be provided: 'testcase_id', 'testcase_name', 'testcase_fulltitle', 'by_error_message', or 'by_code_snippet'."
        );
      }
    
      try {
        // Build query parameters
        const queryParams: Record<string, string> = {
          projectId: String(args.projectId),
        };
    
        if (args.testcase_id) {
          queryParams.testcaseid = String(args.testcase_id);
        }
        if (args.testcase_name) {
          queryParams.by_title = String(args.testcase_name);
        }
        if (args.testcase_fulltitle) {
          queryParams.by_fulltitle = String(args.testcase_fulltitle);
        }
        if (args.testrun_id) {
          queryParams.by_testrun_id = String(args.testrun_id);
        }
        if (args.testrun_ids) {
          queryParams.by_testrun_ids = String(args.testrun_ids);
        }
        if (args.testsuite_id) {
          queryParams.by_testsuite_id = String(args.testsuite_id);
        }
        if (args.counter !== undefined) {
          queryParams.counter = String(args.counter);
        }
        if (args.by_status) {
          queryParams.by_status = args.by_status;
        }
        if (args.by_error_message) {
          queryParams.by_error_message = String(args.by_error_message);
        }
        if (args.by_code_snippet) {
          queryParams.by_code_snippet = String(args.by_code_snippet);
        }
        if (args.include_history !== undefined) {
          queryParams.include_history = String(args.include_history);
        }
        if (args.history_limit !== undefined) {
          queryParams.history_limit = String(args.history_limit);
        }
        if (args.include_artifacts !== undefined) {
          queryParams.include_artifacts = String(args.include_artifacts);
        }
        if (args.include_screenshots !== undefined) {
          queryParams.include_screenshots = String(args.include_screenshots);
        }
        if (args.include_traces !== undefined) {
          queryParams.include_traces = String(args.include_traces);
        }
        if (args.include_videos !== undefined) {
          queryParams.include_videos = String(args.include_videos);
        }
        if (args.include_attachments !== undefined) {
          queryParams.include_attachments = String(args.include_attachments);
        }
        if (args.steps_filter) {
          queryParams.steps_filter = args.steps_filter;
        }
        if (args.limit !== undefined) {
          queryParams.limit = String(args.limit);
        }
        if (args.page !== undefined) {
          queryParams.page = String(args.page);
        }
        if (args.sort_by) {
          queryParams.sort_by = args.sort_by;
        }
        if (args.sort_order) {
          queryParams.sort_order = args.sort_order;
        }
        if (args.get_all !== undefined) {
          queryParams.get_all = String(args.get_all);
        }
    
        // Build URL with query parameters using endpoints helper
        const testCaseDetailsUrl = endpoints.getTestCaseDetails(
          queryParams as Parameters<typeof endpoints.getTestCaseDetails>[0]
        );
    
        const response = await apiRequestJson<unknown>(testCaseDetailsUrl, {
          headers: {
            Authorization: `Bearer ${token}`,
          },
        });
    
        const responseText = JSON.stringify(response, null, 2);
        const content: Array<{ type: string; text: string }> = [
          { type: "text", text: responseText },
        ];
    
        // If response contains screenshot/image attachments, instruct the agent to view them
        if (
          responseText.includes('"contentType": "image/') ||
          responseText.includes('"screenshots"')
        ) {
          content.push({
            type: "text",
            text: "This test case has screenshot images attached. You should fetch and view the screenshot URLs above (in the 'screenshots' or attachment 'path' fields) to visually inspect the application state at the time of failure — this is critical for accurate diagnosis.",
          });
        }
    
        return { content };
      } catch (error) {
        const errorMessage = error instanceof Error ? error.message : String(error);
        throw new Error(`Failed to retrieve test case details: ${errorMessage}`);
      }
    }
  • Tool definition including name ('get_testcase_details'), description, and full inputSchema with all parameters (projectId, testcase_id, testcase_name, filters, pagination, artifact includes, etc.).
    export const getTestCaseDetailsTool = {
      name: "get_testcase_details",
      description:
        "Get detailed information about a specific test case. You can identify the test case in two ways: 1) By testcase_id (can be used alone), or 2) By testcase_name combined with testrun_id or counter (required because test cases can have the same name across different test runs). Returns error message, code snippet, file location, test steps per attempt, console logs, and optional artifacts (screenshots, videos, traces). Use steps_filter='failed_only' to return only steps that errored, stripping passing setup/hook steps. Use this to debug why a test failed or understand how it executed. Example: 'Get test case details for \"Verify user can logout and login\" in testrun #43'.",
      inputSchema: {
        type: "object",
        properties: {
          projectId: {
            type: "string",
            description: "Project ID (Required). The TestDino project identifier.",
          },
          testcase_id: {
            type: "string",
            description:
              "Test case ID. Can be used alone to get test case details. Example: 'test_case_123'.",
          },
          testcase_name: {
            type: "string",
            description:
              "Test case title (partial match, case-insensitive). Must be combined with testrun_id or counter when used alone. Example: 'Verify user can logout and login'.",
          },
          testcase_fulltitle: {
            type: "string",
            description:
              "Full test case title including suite path (partial match, case-insensitive). Example: 'auth.spec.js > Login > Verify user can logout and login'.",
          },
          testrun_id: {
            type: "string",
            description:
              "Single test run ID to filter results. Example: 'test_run_6901b2abc6b187e63f536a6b'.",
          },
          testrun_ids: {
            type: "string",
            description:
              "Multiple test run IDs (comma-separated, max 20). Example: 'test_run_abc,test_run_def'.",
          },
          testsuite_id: {
            type: "string",
            description: "Filter by test suite ID.",
          },
          counter: {
            type: "number",
            description:
              "Test run counter number. Alternative to testrun_id to identify the test run. Example: 43.",
          },
          by_status: {
            type: "string",
            enum: ["passed", "failed", "skipped", "flaky"],
            description: "Filter by test case status.",
          },
          by_error_message: {
            type: "string",
            description:
              "Search in error messages (partial match, case-insensitive). Example: 'Timeout 15000ms exceeded'.",
          },
          by_code_snippet: {
            type: "string",
            description:
              "Search in error code snippets (partial match, case-insensitive).",
          },
          include_history: {
            type: "boolean",
            description:
              "Include historical executions of the same test case when searching by name. Default: false.",
            default: false,
          },
          history_limit: {
            type: "number",
            description: "Max number of history entries to return (default: 10).",
            default: 10,
          },
          include_artifacts: {
            type: "boolean",
            description:
              "Include all artifacts (screenshots, traces, videos, attachments) with authenticated URLs. Default: false.",
            default: false,
          },
          include_screenshots: {
            type: "boolean",
            description:
              "Include screenshot URLs from test attempts. Default: false.",
            default: false,
          },
          include_traces: {
            type: "boolean",
            description:
              "Include Playwright trace links from test attempts. Default: false.",
            default: false,
          },
          include_videos: {
            type: "boolean",
            description:
              "Include video recording URLs from test attempts. Default: false.",
            default: false,
          },
          include_attachments: {
            type: "boolean",
            description:
              "Include all attachment metadata from test attempts. Default: false.",
            default: false,
          },
          steps_filter: {
            type: "string",
            enum: ["failed_only"],
            description:
              "Filter steps in each attempt. Use 'failed_only' to return only steps with errors, stripping passing setup and hook steps.",
          },
          limit: {
            type: "number",
            description:
              "Max results to return (default: 1 for ID lookup, 50 for search, max: 1000).",
          },
          page: {
            type: "number",
            description: "Page number for pagination (default: 1).",
            default: 1,
          },
          sort_by: {
            type: "string",
            enum: ["startTime", "duration"],
            description: "Sort results by field (default: startTime).",
          },
          sort_order: {
            type: "string",
            enum: ["asc", "desc"],
            description: "Sort direction (default: desc).",
          },
          get_all: {
            type: "boolean",
            description: "Return all matching results up to 1000 (default: false).",
            default: false,
          },
        },
        required: ["projectId"],
      },
    };
  • TypeScript interface defining all typed arguments for the handler (GetTestCaseDetailsArgs).
    interface GetTestCaseDetailsArgs {
      projectId: string;
      testcase_id?: string;
      testcase_name?: string;
      testcase_fulltitle?: string;
      testrun_id?: string;
      testrun_ids?: string;
      testsuite_id?: string;
      counter?: number;
      by_status?: "passed" | "failed" | "skipped" | "flaky";
      by_error_message?: string;
      by_code_snippet?: string;
      include_history?: boolean;
      history_limit?: number;
      include_artifacts?: boolean;
      include_screenshots?: boolean;
      include_traces?: boolean;
      include_videos?: boolean;
      include_attachments?: boolean;
      steps_filter?: "failed_only";
      limit?: number;
      page?: number;
      sort_by?: "startTime" | "duration";
      sort_order?: "asc" | "desc";
      get_all?: boolean;
    }
  • src/index.ts:219-222 (registration)
    Registration in the CallToolRequestSchema handler that routes 'get_testcase_details' to handleGetTestCaseDetails.
    if (name === "get_testcase_details") {
      return await handleGetTestCaseDetails(
        args as Parameters<typeof handleGetTestCaseDetails>[0]
      );
  • src/index.ts:104-104 (registration)
    Tool registered in the tools array (line 104) which is sent via ListToolsRequestSchema.
    getTestCaseDetailsTool,
  • Endpoint helper function that builds the URL for the get-testcase-details API endpoint with all query parameters.
    getTestCaseDetails: (params?: {
      projectId?: string;
      testcaseid?: string;
      by_title?: string;
      by_fulltitle?: string;
      by_testrun_id?: string;
      by_testrun_ids?: string;
      by_testsuite_id?: string;
      counter?: string | number;
      by_status?: string;
      by_error_message?: string;
      by_code_snippet?: string;
      include_history?: boolean | string;
      history_limit?: number;
      include_artifacts?: boolean | string;
      include_screenshots?: boolean | string;
      include_traces?: boolean | string;
      include_videos?: boolean | string;
      include_attachments?: boolean | string;
      steps_filter?: "failed_only";
      limit?: number;
      page?: number;
      sort_by?: string;
      sort_order?: string;
      get_all?: boolean | string;
    }): string => {
      const baseUrl = getBaseUrl();
      const projectId = params?.projectId || "";
      const { projectId: _, ...queryParams } = params || {};
      const queryString = queryParams ? buildQueryString(queryParams) : "";
      return `${baseUrl}/api/mcp/${projectId}/get-testcase-details${queryString}`;
    },
Behavior4/5

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

Despite no annotations, the description discloses what the tool returns (error message, code snippet, file location, steps per attempt, console logs, optional artifacts) and explains the steps_filter behavior. It does not cover potential side effects, but as a read-only operation, this is sufficient.

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

Conciseness4/5

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

The description is well-structured, starting with the primary purpose, then detailing identification methods, return values, and filtering options. While a bit lengthy, every sentence serves a purpose and adds clarity.

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?

Given the tool's complexity (24 parameters), the description provides a solid overview of usage patterns and return values. It does not cover every edge case or parameter interaction, but it is sufficiently complete for an AI agent to understand how to invoke the tool effectively.

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?

With 100% schema coverage, the baseline is 3. The description adds value by explaining the two identification strategies, the steps_filter parameter's effect, and examples for testcase_name and counter. This goes beyond the schema's property 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 clearly states that the tool retrieves detailed information about a specific test case, with explicit identification methods (testcase_id alone or testcase_name with testrun_id/counter). This distinguishes it from sibling tools like list_run_test_cases or get_run_details, which serve different purposes.

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 explains when to use the tool ('to debug why a test failed or understand how it executed') and provides examples and explicit guidance on identification methods. It does not exhaustively list when not to use it, but the context is clear.

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/testdino-hq/testdino-mcp'

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