MCP

Aegisv1

Quick Start Guide

MCP Testing in 5 Minutes

Get up and running with MCP Aegis Model Context Protocol testing in 5 minutes with this step-by-step guide.

๐Ÿš€ Choose Your Path

โšก Quick Setup (Recommended)

Automatic setup with one command

Jump to Quick Setup โ†’

๐Ÿ”ง Manual Setup

Step-by-step custom configuration

Jump to Manual Setup โ†’

โšก Method 1: Quick Setup (Recommended)

1

Navigate and Initialize

bash
# Navigate to your MCP project directory
cd my-mcp-project

# Initialize MCP Aegis (automatically installs as dev dependency)
npx mcp-aegis init

This creates: aegis.config.json, a test directory structure, and installs the package.

๐Ÿ“ Project Structure After InitAuto-generated

text
project/
โ”œโ”€โ”€ aegis.config.json    # โ† Server configuration  
โ”œโ”€โ”€ package.json            # โ† Updated with mcp-aegis dev dependency
โ”œโ”€โ”€ test/                   # โ† Uses 'test/' if exists, otherwise creates 'tests/'
โ”‚   โ””โ”€โ”€ mcp/
โ”‚       โ”œโ”€โ”€ AGENTS.md       # โ† AI assistant guide
โ”‚       โ”œโ”€โ”€ yaml/           # โ† YAML test files (.test.mcp.yml)
โ”‚       โ”‚   โ””โ”€โ”€ AGENTS.md   # โ† YAML-specific guidance
โ”‚       โ””โ”€โ”€ node/           # โ† Programmatic tests (.programmatic.test.js)
โ”‚           โ””โ”€โ”€ AGENTS.md   # โ† Node.js-specific guidance
โ””โ”€โ”€ server.js              # โ† Your MCP server (update aegis.config.json if different)

๐Ÿ’กThe init command detects existing 'test/' or 'tests/' directories and uses whichever exists, or creates 'test/' by default.Skip to Step 3 if using this method.

โœ… Quick Setup Complete!

Your project is now ready for MCP testing. You can either:

๐Ÿ”ง Method 2: Manual Setup

1

Install MCP Aegis

You can install MCP Aegis globally for system-wide access or locally in your project:

bash
# Option A: Global installation (recommended for CLI usage)
npm install -g mcp-aegis

# Option B: Local installation (if you prefer local dependencies)
npm install --save-dev mcp-aegis
# Then use: npx mcp-aegis instead of just aegis
2

Create a Simple MCP Server

Create a basic MCP server for testing (server.js):

javascript
#!/usr/bin/env node

const serverInfo = { name: "demo-server", version: "1.0.0" };
const tools = [
  {
    name: "hello",
    description: "Says hello with a friendly greeting",
    inputSchema: { 
      type: "object", 
      properties: { 
        name: { type: "string", description: "Name to greet" } 
      }, 
      required: ["name"] 
    }
  }
];

let initialized = false;

process.stdin.on('data', (data) => {
  try {
    const message = JSON.parse(data.toString().trim());
    
    if (message.method === 'initialize') {
      sendResponse(message.id, { 
        protocolVersion: "2025-06-18", 
        capabilities: { tools: {} }, 
        serverInfo 
      });
    } else if (message.method === 'initialized') {
      initialized = true;
      // Notifications don't get responses
    } else if (message.method === 'tools/list') {
      if (!initialized) {
        sendError(message.id, -32002, "Server not initialized");
        return;
      }
      sendResponse(message.id, { tools });
    } else if (message.method === 'tools/call' && message.params?.name === 'hello') {
      if (!initialized) {
        sendError(message.id, -32002, "Server not initialized");
        return;
      }
      const name = message.params.arguments?.name;
      if (!name) {
        sendResponse(message.id, { 
          isError: true, 
          content: [{ type: "text", text: "Missing required parameter: name" }] 
        });
        return;
      }
      sendResponse(message.id, { 
        content: [{ type: "text", text: `Hello, ${name}! ๐Ÿ‘‹ Welcome to MCP!` }],
        isError: false
      });
    } else {
      sendError(message.id, -32601, "Method not found");
    }
  } catch (error) {
    sendError(null, -32700, "Parse error");
  }
});

function sendResponse(id, result) {
  console.log(JSON.stringify({ jsonrpc: "2.0", id, result }));
}

function sendError(id, code, message) {
  console.log(JSON.stringify({ jsonrpc: "2.0", id, error: { code, message } }));
}

// Signal server is ready
setTimeout(() => console.error("Server ready"), 100);
3

Create Configuration (Manual Setup Only)

Create aegis.config.json:

๐Ÿ“ Config File Naming

Standard: Use aegis.config.json (default, auto-detected)
Custom: Use any name like server.config.json or config.json and specify with --config flag
Examples: You'll see both patterns in the repository - the examples use short names like config.json for brevity, but aegis.config.json is recommended for clarity in real projects.

json
{
  "name": "Demo MCP Server",
  "command": "node",
  "args": ["./server.js"],
  "startupTimeout": 5000,
  "readyPattern": "Server ready"
}

๐Ÿ“ Step 3: Write Your First Test

Create demo.test.mcp.yml:

๐Ÿ’ก Working Example AvailableVerified

You can find this complete working example in examples/demo-server/ in the MCP Aegis repository. All the code below has been tested and verified to work.

๐Ÿš€ Beginner Approach (Recommended)Auto-handshake

Let MCP Aegis handle the handshake automatically. MCP Aegis will send the initialize request and initialized notification before your first test runs. This approach ensures your tools work correctly without needing to understand the handshake protocol details. This covers 90% of use cases.

yaml
description: "Demo MCP Server Tests"
tests:
  - it: "should list available tools"
    request:
      jsonrpc: "2.0"
      id: "tools-test"
      method: "tools/list"
      params: {}
    expect:
      response:
        jsonrpc: "2.0"
        id: "tools-test"
        result:
          tools:
            - name: "hello"
              description: "match:contains:hello"
              inputSchema:
                type: "object"
                properties: "match:type:object"
                required: ["name"]
      stderr: "toBeEmpty"

  - it: "should execute hello tool"
    request:
      jsonrpc: "2.0"
      id: "hello-test"
      method: "tools/call"
      params:
        name: "hello"
        arguments:
          name: "World"
    expect:
      response:
        jsonrpc: "2.0"
        id: "hello-test"
        result:
          content:
            - type: "text"
              text: "match:contains:Hello, World"
          isError: false
      stderr: "toBeEmpty"

  - it: "should handle invalid tool"
    request:
      jsonrpc: "2.0" 
      id: "error-test"
      method: "tools/call"
      params:
        name: "nonexistent"
        arguments: {}
    expect:
      response:
        jsonrpc: "2.0"
        id: "error-test"
        error:
          code: -32601
          message: "Method not found"
      stderr: "toBeEmpty"

โš™๏ธ Advanced: Manual Handshake Testing

Include an initialize test if you want to verify handshake behavior or test specific protocol versions. This runs as an additional test alongside MCP Aegis's automatic handshake.

yaml
# Add this as the FIRST test if you want manual control:
- it: "should initialize successfully"
  request:
    jsonrpc: "2.0"
    id: "init-test" 
    method: "initialize"
    params:
      protocolVersion: "2025-06-18"
      capabilities: { tools: {} }
      clientInfo: { name: "test-client", version: "1.0.0" }
  expect:
    response:
      jsonrpc: "2.0"
      id: "init-test"
      result:
        protocolVersion: "match:regex:20\\d{2}-\\d{2}-\\d{2}"
        capabilities: "match:type:object"
        serverInfo:
          name: "demo-server"
          version: "1.0.0"
  stderr: "toBeEmpty"

๐Ÿ“ Note: Both automatic handshake (for setup) and manual initialize test (for validation) will occur, giving you the best of both worlds - working tools plus handshake verification.

Error Handling Models

Two patterns exist for representing failures:

  • JSON-RPC transport / protocol error: Use the top-level error object (method not found, invalid request).
  • Tool-level logical failure: Return a normal result with isError: true and explanatory content.

Pick one per response; do not mix both for the same request.

Step 4: Run Your Tests

For Quick Setup (Method 1):

bash
# Universal pattern that works for both test/ and tests/ directories:
npx mcp-aegis "test*/mcp/yaml/**/*.test.mcp.yml"

# Or add to package.json scripts for convenience:
# "scripts": { 
#   "test:mcp:yaml": "mcp-aegis \"test*/mcp/yaml/**/*.test.mcp.yml\"",
#   "test:mcp:node": "node --test \"test*/mcp/node/**/*.programmatic.test.js\""
# }
# Then run:
npm run test:mcp:yaml

# Specific directory examples (if you know your structure):
# npx mcp-aegis "test/mcp/yaml/**/*.test.mcp.yml"     # if test/ directory
# npx mcp-aegis "tests/mcp/yaml/**/*.test.mcp.yml"   # if tests/ directory

For Manual Setup (Method 2):

bash
# If installed globally, use 'aegis':
aegis demo.test.mcp.yml --config aegis.config.json

# If installed locally, use 'npx mcp-aegis':
npx mcp-aegis demo.test.mcp.yml --config aegis.config.json

# With verbose output for detailed results
aegis demo.test.mcp.yml --config aegis.config.json --verbose

# With debug mode for MCP communication details  
aegis demo.test.mcp.yml --config aegis.config.json --debug

# With timing information for performance analysis
aegis demo.test.mcp.yml --config aegis.config.json --timing

# Combine options for maximum debugging
aegis demo.test.mcp.yml --config aegis.config.json --verbose --debug --timing

# Error reporting options for focused debugging
aegis demo.test.mcp.yml --config aegis.config.json --errors-only
aegis demo.test.mcp.yml --config aegis.config.json --syntax-only
aegis demo.test.mcp.yml --config aegis.config.json --group-errors
aegis demo.test.mcp.yml --config aegis.config.json --max-errors 3

๐Ÿ“Š Understanding the Test Output

โœ… Success Output ExampleAll tests passed

When your tests run successfully, you should see output like this:

bash
๐Ÿ“‹ Loaded configuration for: Demo MCP Server
๐Ÿงช Found 1 test suite(s)
โ„น๏ธ  Starting MCP server...
โ„น๏ธ  Server started successfully
โ„น๏ธ  Performing MCP handshake...
โ„น๏ธ  Handshake completed successfully

๐Ÿ“‹ Demo MCP Server Tests
   demo.test.mcp.yml

  โ— should initialize successfully ... โœ“ PASS
  โ— should list available tools ... โœ“ PASS
  โ— should execute hello tool ... โœ“ PASS
  โ— should handle invalid tool ... โœ“ PASS
โ„น๏ธ  Shutting down server...
โ„น๏ธ  Server shut down successfully

๐Ÿ“Š Test Results:
   โœ“ 4 passed
   ๐Ÿ“ˆ Total: 4

๐ŸŽ‰ All tests passed!

๐Ÿ—๏ธ Understanding the Test Structure

๐Ÿ“‹ YAML Test Anatomy

Each MCP Aegis YAML test follows this structure:

๐Ÿ“ description

Human-readable test suite description

๐Ÿงช tests

Array of individual test cases

โœ… it

Description of what the test should do

๐Ÿ“ค request

JSON-RPC request to send to server

๐Ÿ“ฅ expect

Expected response structure

๐Ÿ“ข stderr

Expected stderr output (optional)

Next Steps

Now that you have a basic test running, explore these advanced features:

๐ŸŽฏ Essential Next Steps

๐Ÿš€ Advanced Features

๐ŸŽฏ Recommended Learning Path

  1. Master Testing Fundamentals to understand core concepts
  2. Start with Basic Patterns for core validation techniques
  3. Explore Array Patterns for validating tool lists and response arrays
  4. Learn Query Command for interactive debugging
  5. Graduate to AI Agent Testing for enterprise scenarios

Quick Debugging with Query Command

Use the query command to test tools directly without writing test files:

bash
# List all available tools from your server (if globally installed)
aegis query --config aegis.config.json

# If locally installed, use npx:
npx mcp-aegis query --config aegis.config.json

# Test the hello tool with arguments
aegis query hello '{"name": "World"}' --config aegis.config.json

# Using the method-based approach (newer interface)
aegis query --config aegis.config.json --method tools/list
aegis query --config aegis.config.json --method tools/call --params '{"name": "hello", "arguments": {"name": "World"}}'

# Get JSON output (useful for scripting)
aegis query hello '{"name": "World"}' --config aegis.config.json --json

# If using custom config file names (e.g., examples use config.json):
aegis query --config examples/demo-server/config.json --method tools/list

This is perfect for:

  • Verifying your server is working before writing tests
  • Exploring what tools your server provides
  • Testing tool arguments and responses quickly
  • Debugging issues during development
  • Learning MCP responses before writing pattern matching assertions

๐Ÿšจ Common Quick Start Issues

๐Ÿ”ด Server Won't StartCommon Issue

1
Make server executable:chmod +x server.js
2
Check shebang line:Ensure server starts with #!/usr/bin/env node
3
Verify config:Ensure aegis.config.json command/args match your setup
4
Increase timeout:If server takes time to start, try "startupTimeout": 10000

๐ŸŸ  Tests Fail ImmediatelySetup Issue

1
Check ready pattern:If using readyPattern, ensure your server outputs it to stderr
2
Verify handshake:Ensure your server responds to initialize method
3
Debug mode:Add --debug flag to see MCP communication

๐ŸŸก Permission IssuesSystem Config

bash
# Make server executable
chmod +x server.js

# If using npm scripts, ensure proper escaping:
"test:mcp": "mcp-aegis \"test*/mcp/yaml/**/*.test.mcp.yml\""

๐ŸŸฃ Pattern Matching IssuesSyntax Help

1
Escape backslashes:Use \\\\d+ instead of \\d+ in YAML regex patterns
2
Check exact vs partial matching:Use match:contains:text for partial matches
3
Use verbose mode:Add --verbose to see detailed comparison output

Common Patterns

Here are some useful patterns you'll use frequently:

Pattern Matching Basics

yaml
# Type validation
result: "match:type:object"
tools: "match:type:array"
count: "match:type:number"

# String patterns
message: "match:contains:success"
filename: "match:startsWith:data_"
extension: "match:endsWith:.json"

# Array patterns
tools: "match:arrayLength:3"        # Exactly 3 elements
# To assert presence of a specific tool name (use in a separate assertion, not together):
# tools: "match:arrayContains:name:hello"

# Negation & extraction examples
tools: "match:not:arrayLength:0"    # Array must NOT be empty
match:extractField: "tools.*.name"  # (Use in separate test: extract all tool names)

Error Handling

yaml
- it: "should handle errors gracefully"
  request:
    method: "tools/call"
    params:
      name: "invalid_tool"
      arguments: {}
  expect:
    response:
      result:
        isError: true
        content:
          - type: "text"
            text: "match:contains:Unknown tool"

# Alternative: JSON-RPC error response (for protocol-level errors)
- it: "should return JSON-RPC error for invalid method"
  request:
    method: "invalid/method"
    params: {}
  expect:
    response:
      error:
        code: -32601
        message: "Method not found"