Skip to main content
Glama
benhuckvale

deploytest MCP server

by benhuckvale
README.md
# Deploy Test

A CLI tool for running Playwright test fixtures against live deployments, with
optional MCP (Model Context Protocol) interface for AI agents"

## Features

- ✅ Run test fixtures against live deployments
- ✅ Capture screenshots, console errors, and network failures
- ✅ Support for parallel or sequential test execution
- ✅ Tag-based test filtering
- ✅ Structured test results with assertions
- ✅ Reusable test fixture interface


## Why Deploytest? Reusable Tests vs Ad-Hoc Verification

### The Problem with Ad-Hoc Testing

When verifying a deployment, it's tempting to test things manually or write throwaway verification code. AI agents often try to create one-off bash scripts or Playwright commands to check if something works. This is inefficient for several reasons:

- **Wasteful**: Every test requires re-discovering what to check and how to check it
- **Error-prone**: Manual steps are forgotten, commands have typos
- **Not repeatable**: Can't easily re-run the same verification later
- **Token-inefficient**: Agents spend tokens re-figuring out the same verification logic

The same applies to humans doing manual testing in a browser.

### The Deploytest Approach

Deploytest follows a better pattern:

1. **Write test fixtures once** - Codify your verification logic as reusable test fixtures
2. **Run locally during development** - Test against localhost as part of your normal workflow
3. **Run against deployments** - Use the **same test code** to verify staging/production deploys
4. **Get structured results** - Receive pass/fail, errors, screenshots, and assertions

Your test fixtures are proper code that lives in your repo and can be maintained over time.

### Comparison to Browser MCPs

**[Chrome DevTools MCP](https://github.com/ChromeDevTools/chrome-devtools-mcp)** - For **exploration and discovery**
- General-purpose browser inspection and DOM manipulation
- Great for: Understanding a site, debugging issues, exploring unknown pages
- Trade-off: Ad-hoc usage, requires many tokens to figure out what to check

**[Playwright MCP](https://github.com/microsoft/playwright-mcp)** - For **scripted browser automation**
- Low-level browser automation commands
- Great for: One-off automation tasks, quick checks
- Trade-off: Each verification requires writing/running commands from scratch

**Deploytest** - For **deployment verification with reusable tests**
- Test fixtures that encode domain knowledge about your site
- Great for: Verifying deployments, regression testing, CI/CD integration
- Benefit: Write once, run many times; token-efficient; structured results

### Suggested Workflow

1. Use Chrome DevTools MCP or Playwright MCP to **explore** and understand what needs testing
2. **Codify** your findings into deploytest fixtures (proper test code in your repo)
3. Run those fixtures locally during development
4. Use deploytest (CLI or MCP) to verify staging/production deployments

### CLI First, MCP as a Subcommand

Deploytest is primarily a **CLI tool**. Run `deploytest mcp` to start it as an MCP server for AI agents:

```bash
# Direct CLI usage
deploytest run-fixture --url https://staging.example.com --fixture login-flow

# MCP server mode (for Claude Desktop/Code)
deploytest mcp
```

The **MCP mode** simply makes it convenient for AI agents to run your existing test fixtures. The agent doesn't write ad-hoc test code - it runs your well-tested, reusable fixtures.

## Installation

```bash
npm install
npm run build
```

Or with bun:

```bash
bun install
bun run build
```

## Install Playwright Browsers

```bash
npx playwright install chromium
```

## Usage

### As a CLI Tool

```bash
# List all available fixtures
deploytest list-fixtures

# List fixtures with specific tags
deploytest list-fixtures --tags smoke,critical

# Run a specific fixture against a deployment
deploytest run-fixture --url https://staging.myapp.com --fixture basic-page-load

# Run all fixtures
deploytest run-all-fixtures --url https://staging.myapp.com

# Run tagged fixtures in parallel
deploytest run-all-fixtures --url https://staging.myapp.com --tags smoke --parallel
```

### As an MCP Server (for Claude Desktop / Claude Code)

Add this to your MCP settings:

**MacOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
**Windows**: `%APPDATA%\Claude\claude_desktop_config.json`

```json
{
  "mcpServers": {
    "deploytest": {
      "command": "deploytest",
      "args": ["mcp"]
    }
  }
}
```

Or if using npx (for published packages):

```json
{
  "mcpServers": {
    "deploytest": {
      "command": "npx",
      "args": ["-y", "deploytest", "mcp"]
    }
  }
}
```

## Available Tools

### `list_fixtures`

List all available test fixtures, optionally filtered by tags.

**Parameters:**
- `tags` (optional): Array of tags to filter by

**Example:**
```typescript
// List all fixtures
await mcp.list_fixtures();

// List only smoke tests
await mcp.list_fixtures({ tags: ["smoke"] });
```

### `run_fixture`

Run a specific test fixture against a deployment URL.

**Parameters:**
- `baseUrl` (required): URL of the deployment to test
- `fixtureName` (required): Name of the fixture to run
- `headless` (optional): Run in headless mode (default: true)

**Example:**
```typescript
await mcp.run_fixture({
  baseUrl: "https://staging.myapp.com",
  fixtureName: "basic-page-load"
});
```

### `run_all_fixtures`

Run all test fixtures (or filtered by tags) against a deployment URL.

**Parameters:**
- `baseUrl` (required): URL of the deployment to test
- `tags` (optional): Only run fixtures with these tags
- `parallel` (optional): Run in parallel (default: false)
- `headless` (optional): Run in headless mode (default: true)

**Example:**
```typescript
// Run all smoke tests
await mcp.run_all_fixtures({
  baseUrl: "https://staging.myapp.com",
  tags: ["smoke"],
  parallel: true
});
```

## Creating Custom Test Fixtures

Test fixtures are defined in `src/fixtures.ts`. Each fixture implements the `TestFixture` interface:

```typescript
import type { TestFixture, TestResult } from './types.js';

export const myCustomTest: TestFixture = {
  name: 'my-custom-test',
  description: 'Description of what this tests',
  tags: ['smoke', 'critical'],
  timeout: 30000,
  
  run: async (page, baseUrl) => {
    const start = Date.now();
    const consoleErrors: string[] = [];
    
    page.on('console', msg => {
      if (msg.type() === 'error') consoleErrors.push(msg.text());
    });
    
    try {
      await page.goto(`${baseUrl}/my-page`);
      
      // Your test logic here
      const isVisible = await page.isVisible('[data-testid="my-element"]');
      
      return {
        passed: isVisible,
        duration: Date.now() - start,
        artifacts: {
          screenshot: await page.screenshot({ encoding: 'base64' }),
          consoleErrors
        },
        assertions: [
          {
            selector: '[data-testid="my-element"]',
            expected: 'visible',
            actual: isVisible,
            passed: isVisible
          }
        ]
      };
      
    } catch (error: any) {
      return {
        passed: false,
        duration: Date.now() - start,
        error: {
          message: error.message,
          stack: error.stack
        },
        artifacts: {
          screenshot: await page.screenshot({ encoding: 'base64' }).catch(() => undefined),
          consoleErrors
        }
      };
    }
  }
};

// Add to the exported array
export const testFixtures: TestFixture[] = [
  // ... existing fixtures
  myCustomTest
];
```

## Integration with Your App

To use this MCP with your own application's test fixtures:

1. **Option 1: Direct Import** (if fixtures are in same repo)
   ```typescript
   // src/fixtures.ts
   import { myAppFixtures } from '../my-app/tests/fixtures.js';
   export const testFixtures = [...myAppFixtures];
   ```

2. **Option 2: Symlink** (if fixtures are in separate repo)
   ```bash
   ln -s /path/to/my-app/tests/fixtures.ts src/app-fixtures.ts
   ```
   
   ```typescript
   // src/fixtures.ts
   import { testFixtures as appFixtures } from './app-fixtures.js';
   export const testFixtures = appFixtures;
   ```

3. **Option 3: Dynamic Import** (load at runtime)
   ```typescript
   // Configure path via environment variable
   const fixturesPath = process.env.FIXTURES_PATH || './fixtures.js';
   const { testFixtures } = await import(fixturesPath);
   ```

## Usage with Claude Code

Once configured, Claude Code can use this MCP to verify deployments:

```
User: "Test my staging deployment at https://staging.myapp.com"

Claude Code will:
1. Call list_fixtures to see available tests
2. Call run_all_fixtures with the URL
3. Analyze the results (screenshots, errors, assertions)
4. Report any issues and suggest fixes
```

## Example Claude Code Workflow

```
# Claude Code automatically uses the MCP like this:

1. User deploys to staging
2. Claude Code calls: run_all_fixtures({ 
     baseUrl: "https://staging.myapp.com",
     tags: ["smoke"]
   })
3. Gets back:
   - Test summary (10/12 passed)
   - Failed test details with screenshots
   - Console errors
   - Network failures
4. Claude analyzes and reports:
   "Deployment verification: 2 tests failed
   - login-flow: Button selector changed
   - checkout-flow: 404 on /api/cart"
5. Claude can fix the issues or alert you
```

## Development

```bash
# Watch mode for development
npm run watch

# Run directly with tsx (for testing)
npm run dev

# Build for production
npm run build
```

## Testing the MCP

You can test the MCP using the MCP Inspector:

```bash
npx @modelcontextprotocol/inspector node dist/index.js
```

## Demo & Examples

The `demo/` directory contains a complete example with working and broken demo sites that you can use to verify the tool works correctly.

**Run the automated demo:**
```bash
npm run demo
```

This will:
1. Start local servers for both working and broken example sites
2. Launch Chromium via Playwright
3. Run all test fixtures against both sites
4. Generate a comprehensive report showing detected issues

**Manual exploration:**
```bash
# Start working site on http://localhost:3000
npm run demo:working

# Start broken site on http://localhost:3001
npm run demo:broken
```

See [demo/README.md](demo/README.md) for detailed documentation.

## License

MIT

## Contributing

To add new fixtures:
1. Create your fixture in `src/fixtures.ts`
2. Follow the `TestFixture` interface
3. Add it to the exported `testFixtures` array
4. Rebuild: `npm run build`

The fixture will automatically be available to Claude Code!

TDQS

A3.9/5.0

Scored across 3 tools

Disambiguation5/5

Each tool has a distinct purpose: listing fixtures, running a single fixture, and running all fixtures. No overlap or ambiguity exists.

Naming Consistency5/5

All tool names follow a consistent verb_noun pattern with snake_case: list_fixtures, run_fixture, run_all_fixtures. The naming is predictable and uniform.

Tool Count5/5

With only 3 tools, the server is tightly scoped to its purpose of running test fixtures. Each tool is essential and there is no bloat.

Completeness5/5

The tool set covers the full lifecycle for this domain: discovering fixtures, executing a specific fixture, and executing all fixtures. No critical operations are missing for a deployment test runner.

Maintenance

ActivityInactive
ResponsivenessNo issues