Skip to main content
Glama
keywaysh

Keyway MCP Server

by keywaysh

keyway_diff

Compare secrets between two environments to identify configuration differences for security validation.

Instructions

Compare secrets between two environments to find differences.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
env1YesFirst environment (e.g., "development")
env2YesSecond environment (e.g., "production")

Implementation Reference

  • The `diff` handler function, which orchestrates fetching and comparing secrets between two environments.
    export async function diff(args: { env1: string; env2: string }): Promise<CallToolResult> {
      // Validate inputs
      if (!args.env1 || !args.env2) {
        return {
          content: [{ type: 'text', text: 'Error: Both env1 and env2 are required' }],
          isError: true,
        };
      }
    
      const env1 = normalizeEnvName(args.env1);
      const env2 = normalizeEnvName(args.env2);
    
      if (env1 === env2) {
        return {
          content: [{ type: 'text', text: 'Error: Cannot compare an environment with itself' }],
          isError: true,
        };
      }
    
      const token = await getToken();
      const repository = getRepository();
    
      // Pull secrets from both environments
      let secrets1: Record<string, string> = {};
      let secrets2: Record<string, string> = {};
      let error1: Error | null = null;
      let error2: Error | null = null;
    
      try {
        const content1 = await pullSecrets(repository, env1, token);
        secrets1 = parseEnvContent(content1);
      } catch (err) {
        error1 = err as Error;
      }
    
      try {
        const content2 = await pullSecrets(repository, env2, token);
        secrets2 = parseEnvContent(content2);
      } catch (err) {
        error2 = err as Error;
      }
    
      // Handle errors
      if (error1 && error2) {
        return {
          content: [
            {
              type: 'text',
              text: `Error: Failed to fetch both environments.\n${env1}: ${error1.message}\n${env2}: ${error2.message}`,
            },
          ],
          isError: true,
        };
      }
    
      // Compare secrets
      const result = compareSecrets(env1, env2, secrets1, secrets2);
    
      // Add warnings for empty environments
      const warnings: string[] = [];
      if (error1) {
        warnings.push(`Environment '${env1}' is empty or doesn't exist`);
      }
      if (error2) {
        warnings.push(`Environment '${env2}' is empty or doesn't exist`);
      }
    
      const response = {
        repository,
        ...result,
        ...(warnings.length > 0 && { warnings }),
      };
    
      return {
        content: [
          {
            type: 'text',
            text: JSON.stringify(response, null, 2),
          },
        ],
        isError: false,
      };
    }
  • src/index.ts:85-93 (registration)
    Registration of the `keyway_diff` tool in the MCP server.
    server.tool(
      'keyway_diff',
      'Compare secrets between two environments to find differences.',
      {
        env1: z.string().describe('First environment (e.g., "development")'),
        env2: z.string().describe('Second environment (e.g., "production")'),
      },
      async (args) => diff(args)
    );
  • Helper function that performs the actual logic of comparing secret dictionaries.
    function compareSecrets(
      env1: string,
      env2: string,
      secrets1: Record<string, string>,
      secrets2: Record<string, string>
    ): DiffResult {
      const onlyInEnv1: string[] = [];
      const onlyInEnv2: string[] = [];
      const different: DiffEntry[] = [];
      const same: string[] = [];
    
      // Get all unique keys
      const allKeys = new Set([...Object.keys(secrets1), ...Object.keys(secrets2)]);
      const sortedKeys = Array.from(allKeys).sort();
    
      for (const key of sortedKeys) {
        const inEnv1 = key in secrets1;
        const inEnv2 = key in secrets2;
        const val1 = secrets1[key] ?? '';
        const val2 = secrets2[key] ?? '';
    
        if (inEnv1 && !inEnv2) {
          onlyInEnv1.push(key);
        } else if (!inEnv1 && inEnv2) {
          onlyInEnv2.push(key);
        } else if (val1 !== val2) {
          different.push({
            key,
            preview1: previewValue(val1),
            preview2: previewValue(val2),
          });
        } else {
          same.push(key);
        }
      }
    
      return {
        env1,
        env2,
        onlyInEnv1,
        onlyInEnv2,
        different,
        same,
        stats: {
          totalEnv1: Object.keys(secrets1).length,
          totalEnv2: Object.keys(secrets2).length,
          onlyInEnv1: onlyInEnv1.length,
          onlyInEnv2: onlyInEnv2.length,
          different: different.length,
          same: same.length,
        },
      };
    }
Behavior2/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 of behavioral disclosure. It states the tool compares secrets to find differences, but doesn't describe what 'differences' entail (e.g., missing, mismatched, or extra secrets), whether it's read-only or has side effects, or any constraints like rate limits or authentication needs. This leaves significant gaps for a tool that likely accesses sensitive data.

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, efficient sentence with zero waste. It's front-loaded with the core purpose and appropriately sized for a simple comparison tool, making it easy to parse quickly.

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

Completeness2/5

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

Given the complexity of comparing secrets across environments, the description is incomplete. With no annotations, no output schema, and minimal behavioral details, it fails to explain what the comparison outputs (e.g., a list of differences, a summary) or any error conditions. This leaves the agent guessing about the tool's behavior and results.

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?

Schema description coverage is 100%, with clear descriptions for both parameters ('env1' and 'env2'). The description adds minimal value beyond the schema, as it only implies the parameters are environment names without specifying format or examples. Since the schema does the heavy lifting, the baseline score of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: 'Compare secrets between two environments to find differences.' It specifies the verb ('compare'), resource ('secrets'), and scope ('between two environments'). However, it doesn't explicitly differentiate from sibling tools like 'keyway_list_secrets' or 'keyway_scan', which might also involve secret inspection.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to use this tool versus alternatives. It doesn't mention prerequisites, such as whether environments must exist or be accessible, or compare it to siblings like 'keyway_list_secrets' for single-environment views. Usage is implied by the purpose but lacks explicit context or exclusions.

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/keywaysh/keyway-mcp'

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