Skip to main content
Glama
debugg-ai

Debugg AI MCP

Official
by debugg-ai

Search Environments

search_environments

Search environments by UUID or keyword, with inline credentials (excluding passwords). Auto-resolves project from git repo for filtered searches.

Instructions

Search or look up environments, with credentials expanded inline per environment.

Two modes:

  • uuid mode: {"uuid": ""} → single env with full detail + its credentials. NotFound if the uuid doesn't exist.

  • filter mode: omit uuid, optionally {"q": "", "projectUuid", "page", "pageSize"} → paginated envs, each with its credentials.

Project resolution: if projectUuid is omitted, the current git repo's origin is auto-resolved to a DebuggAI project. Returns {error:"NoProjectResolved", environments:[]} if neither is available.

Credentials are returned inline per env as {uuid, label, username, role}. Password is NEVER returned — the handler defensively strips it regardless of what the service layer provides.

Response: {project, filter, pageInfo, environments[]} — each environment includes a credentials[] array.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
uuidNoEnvironment UUID. Returns single env with credentials inline. Mutually exclusive with projectUuid/q filter params.
projectUuidNoOverride the auto-detected project. Used in filter mode.
qNoFree-text search over environment name. Mutually exclusive with uuid.
pageNoPage number (1-indexed).
pageSizeNoPage size (1..200). Default 20.

Implementation Reference

  • Main handler function for search_environments. Supports uuid mode (single env lookup) and filter mode (paginated search with q keyword). Resolves projectUuid via git repo detection if not provided; expands credentials inline; strips password defensively.
    export async function searchEnvironmentsHandler(
      input: SearchEnvironmentsInput,
      _context: ToolContext,
    ): Promise<ToolResponse> {
      const start = Date.now();
      const pagination = toPaginationParams({ page: input.page, pageSize: input.pageSize });
      logger.toolStart('search_environments', { ...input, ...pagination });
    
      try {
        const client = new DebuggAIServerClient(config.api.key);
        await client.init();
    
        // ── Resolve projectUuid ──
        // Bead gb4n: when projectUuid is provided directly (caller skips git
        // auto-resolution), `name` and `repoName` are unknown. OMIT those fields
        // rather than emitting nulls — null fields surprised callers and
        // muddied the contract. If a caller needs them, they fetch via
        // search_projects.
        let projectUuid = input.projectUuid;
        let project: { uuid: string; name?: string; repoName?: string } | null = null;
    
        if (!projectUuid) {
          const repoName = detectRepoName();
          if (!repoName) {
            return noProjectResolved(pagination,
              'No git repo detected and no projectUuid provided. Pass projectUuid (get via search_projects) or invoke from a directory with a git origin.');
          }
          const resolved = await client.findProjectByRepoName(repoName);
          if (!resolved) {
            return noProjectResolved(pagination,
              `No DebuggAI project found for repo "${repoName}". Pass projectUuid explicitly.`);
          }
          projectUuid = resolved.uuid;
          project = { uuid: resolved.uuid };
          if (resolved.name) project.name = resolved.name;
          const rn = resolved.repo?.name ?? repoName;
          if (rn) project.repoName = rn;
        } else {
          project = { uuid: projectUuid };
        }
    
        // ── uuid mode ──
        if (input.uuid) {
          try {
            const env = await client.getEnvironment(projectUuid, input.uuid);
            const creds = await client.listCredentialsForEnvironment(projectUuid, input.uuid).catch(() => []);
            const payload = {
              project,
              filter: { uuid: input.uuid },
              pageInfo: { page: 1, pageSize: 1, totalCount: 1, totalPages: 1, hasMore: false },
              environments: [{ ...env, credentials: creds.map(stripPassword) }],
            };
            logger.toolComplete('search_environments', Date.now() - start);
            return { content: [{ type: 'text', text: JSON.stringify(payload, null, 2) }] };
          } catch (err: any) {
            if (err?.statusCode === 404 || err?.response?.status === 404) return notFound(input.uuid);
            throw err;
          }
        }
    
        // ── Filter mode ──
        const { pageInfo, environments } = await client.listEnvironmentsPaginated(projectUuid, pagination, input.q);
    
        // Expand creds per env (sequential — bounded by page size, typically ≤20)
        const withCreds = [];
        for (const env of environments) {
          const creds = await client.listCredentialsForEnvironment(projectUuid, env.uuid).catch(() => []);
          withCreds.push({ ...env, credentials: creds.map(stripPassword) });
        }
    
        const payload = {
          project,
          filter: { q: input.q ?? null },
          pageInfo,
          environments: withCreds,
        };
        logger.toolComplete('search_environments', Date.now() - start);
        return { content: [{ type: 'text', text: JSON.stringify(payload, null, 2) }] };
      } catch (error) {
        logger.toolError('search_environments', error as Error, Date.now() - start);
        throw handleExternalServiceError(error, 'DebuggAI', 'search_environments');
      }
    }
  • Zod schema for SearchEnvironmentsInput: optional uuid (uuid mode), projectUuid, q, page, pageSize. Enforces mutual exclusivity of uuid and q via refine.
    export const SearchEnvironmentsInputSchema = z.object({
      uuid: z.string().uuid().optional(),
      projectUuid: z.string().uuid().optional(),
      q: z.string().min(1).optional(),
      page: z.number().int().min(1).optional(),
      pageSize: z.number().int().min(1).optional(),
    }).strict().refine(
      (v) => !(v.uuid && v.q !== undefined),
      { message: 'Cannot combine uuid with q (they are mutually exclusive — uuid mode returns one env; q filters a list).' },
    );
  • TypeScript type SearchEnvironmentsInput inferred from Zod schema.
    export type SearchEnvironmentsInput = z.infer<typeof SearchEnvironmentsInputSchema>;
  • buildSearchEnvironmentsTool() returns the Tool definition with name 'search_environments', description, and inputSchema.
    export function buildSearchEnvironmentsTool(): Tool {
      return {
        name: 'search_environments',
        title: 'Search Environments',
        description: DESCRIPTION,
        inputSchema: {
          type: 'object',
          properties: {
            uuid: { type: 'string', description: 'Environment UUID. Returns single env with credentials inline. Mutually exclusive with projectUuid/q filter params.' },
            projectUuid: { type: 'string', description: 'Override the auto-detected project. Used in filter mode.' },
            q: { type: 'string', description: 'Free-text search over environment name. Mutually exclusive with uuid.' },
            page: { type: 'number', description: 'Page number (1-indexed).' },
            pageSize: { type: 'number', description: 'Page size (1..200). Default 20.' },
          },
          additionalProperties: false,
        },
      };
    }
  • buildValidatedSearchEnvironmentsTool() wraps the tool with Zod-validated inputSchema and the handler function.
    export function buildValidatedSearchEnvironmentsTool(): ValidatedTool {
      const tool = buildSearchEnvironmentsTool();
      return { ...tool, inputSchema: SearchEnvironmentsInputSchema, handler: searchEnvironmentsHandler };
    }
  • tools/index.ts:34-96 (registration)
    initTools() registers search_environments via both buildSearchEnvironmentsTool() (plain) and buildValidatedSearchEnvironmentsTool() (validated). getTool() returns from toolRegistry.
    export function initTools(ctx: ProjectContext | null): void {
      const tools: Tool[] = [
        buildTestPageChangesTool(ctx),
        buildTriggerCrawlTool(ctx),
        buildProbePageTool(),
        buildSearchProjectsTool(),
        buildSearchEnvironmentsTool(),
        buildCreateEnvironmentTool(),
        buildUpdateEnvironmentTool(),
        buildDeleteEnvironmentTool(),
        buildUpdateProjectTool(),
        buildDeleteProjectTool(),
        buildSearchExecutionsTool(),
        buildCreateProjectTool(),
        buildCreateTestSuiteTool(),
        buildSearchTestSuitesTool(),
        buildDeleteTestSuiteTool(),
        buildCreateTestCaseTool(),
        buildUpdateTestCaseTool(),
        buildDeleteTestCaseTool(),
        buildRunTestSuiteTool(),
        buildGetTestSuiteResultsTool(),
      ];
      const validated: ValidatedTool[] = [
        buildValidatedTestPageChangesTool(ctx),
        buildValidatedTriggerCrawlTool(ctx),
        buildValidatedProbePageTool(),
        buildValidatedSearchProjectsTool(),
        buildValidatedSearchEnvironmentsTool(),
        buildValidatedCreateEnvironmentTool(),
        buildValidatedUpdateEnvironmentTool(),
        buildValidatedDeleteEnvironmentTool(),
        buildValidatedUpdateProjectTool(),
        buildValidatedDeleteProjectTool(),
        buildValidatedSearchExecutionsTool(),
        buildValidatedCreateProjectTool(),
        buildValidatedCreateTestSuiteTool(),
        buildValidatedSearchTestSuitesTool(),
        buildValidatedDeleteTestSuiteTool(),
        buildValidatedCreateTestCaseTool(),
        buildValidatedUpdateTestCaseTool(),
        buildValidatedDeleteTestCaseTool(),
        buildValidatedRunTestSuiteTool(),
        buildValidatedGetTestSuiteResultsTool(),
      ];
    
      _tools = tools;
      _validatedTools = validated;
    
      toolRegistry.clear();
      for (const v of validated) toolRegistry.set(v.name, v);
    }
    
    export function getTools(): Tool[] {
      if (!_tools) initTools(null);
      return _tools!;
    }
    
    export function getTool(name: string): ValidatedTool | undefined {
      if (!_validatedTools) initTools(null);
      return toolRegistry.get(name);
    }
Behavior5/5

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

No annotations are provided, so the description fully carries the burden. It discloses that passwords are never returned (defensive stripping), credentials are expanded inline, and error response for unresolved project. This is comprehensive.

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 with clear sections and bullet points. It is slightly verbose but each sentence adds value. Front-loading the purpose is effective.

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

Completeness5/5

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

Given 5 parameters, no output schema, and no annotations, the description covers all needed context: modes, parameter interactions, error handling, response format, and security behavior. It leaves no significant gaps.

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

Parameters5/5

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

Schema coverage is 100%, but the description adds significant meaning: explains uuid vs filter mode, mutual exclusivity, auto-resolution of projectUuid, default pageSize, and response structure. This greatly aids parameter understanding.

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 'Search or look up environments' with credentials inline, and distinguishes two modes (uuid vs filter). It clearly differentiates from sibling tools like search_projects and search_test_suites by focusing on environments.

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 when-to-use guidance: uuid mode for a single env, filter mode for paginated search. It explains project auto-resolution and error cases. It does not explicitly mention when not to use, but the context is sufficient.

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/debugg-ai/debugg-ai-mcp'

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