Claude Skills Guide

Claude Code MCP Server Penetration Testing Guide

Model Context Protocol (MCP) servers extend Claude Code’s capabilities by connecting to external services, databases, and APIs. Since these servers often handle sensitive data and execute commands on your behalf, testing them for security vulnerabilities is essential. This guide walks you through penetration testing your MCP server implementations using Claude Code skills and practical testing methodologies.

Understanding Your MCP Server Attack Surface

Before testing, map out what your MCP server exposes. MCP servers typically provide tools that Claude Code can invoke—these tools may execute shell commands, query databases, call external APIs, or access file systems. Each tool represents a potential attack vector if input validation is insufficient.

Common vulnerability categories in MCP servers include:

Setting Up Your Testing Environment

Isolate your testing from production systems. Create a dedicated test environment that mirrors your production MCP server configuration without connecting to real services or containing sensitive data.

# Clone your MCP server for testing
git clone git@github.com:your-org/your-mcp-server.git
cd your-mcp-server

# Create a test configuration
cp config/production.json config/test.json
# Edit test.json to use mock services and test credentials

The supermemory skill helps you maintain a testing checklist across sessions. Before starting a penetration test, create a comprehensive test plan:

/supermemory
Remember this testing checklist for MCP server penetration testing:
1. Input validation - test all tool parameters with special characters
2. Authentication - verify credential handling
3. Authorization - confirm least-privilege execution
4. Data exposure - check for sensitive data in responses
5. Logging - review what gets logged and where

Testing Input Validation

The most common vulnerability in MCP servers is insufficient input validation. Test each tool parameter with payloads designed to trigger unexpected behavior.

Command Injection Testing

If your MCP server includes a tool that runs shell commands, test it with command separators:

# Test input for command injection
"; ls -la /"
"| cat /etc/passwd"
"`whoami`"
"$(whoami)"

A properly validated server should reject these inputs or sanitize them before passing to shell execution functions. Here’s a test case you can run:

// test-command-injection.js
const testCases = [
  "; echo injected",
  "| echo injected",
  "`echo injected`",
  "$(echo injected)",
  "\nwhoami",
];

for (const payload of testCases) {
  try {
    const result = await mcpClient.callTool('run_command', { 
      command: payload 
    });
    console.log(`Payload: ${payload}`);
    console.log(`Result: ${result}`);
    // If result contains "injected", vulnerability exists
  } catch (e) {
    console.log(`Payload blocked: ${payload}`);
  }
}

Path Traversal Testing

For file system tools, test whether users can access files outside intended directories:

# Path traversal test payloads
../../../etc/passwd
..%2F..%2F..%2Fetc%2Fpasswd
/etc/../../etc/passwd

The frontend-design skill can help you build a test UI that systematically probes these vulnerabilities:

/frontend-design
Create a simple React form with input fields for each tool parameter.
Add a "Run Tests" button that iterates through a predefined list of 
test payloads and displays pass/fail results for each.

Authentication and Authorization Testing

Verify that your MCP server properly enforces authentication on all endpoints:

# Test unauthenticated access
curl -X POST http://localhost:3000/mcp/tools \
  -H "Content-Type: application/json" \
  -d '{"name": "sensitive_tool"}'

# Should return 401 Unauthorized, not tool results

Test authorization by creating multiple users with different privilege levels and verifying they can only access permitted tools:

// test-authorization.js
async function testAuthorization() {
  const lowPrivUser = await authenticate('testuser', 'password123');
  const highPrivUser = await authenticate('admin', 'adminpass');
  
  // Low-priv user should be denied
  const lowPrivResult = await lowPrivUser.callTool('admin_tool', {});
  console.log('Low priv result:', lowPrivResult);
  // Expect: { error: 'Unauthorized' }
  
  // High-priv user should succeed
  const highPrivResult = await highPrivUser.callTool('admin_tool', {});
  console.log('High priv result:', highPrivResult);
  // Expect: actual tool results
}

Integration Testing with the TDD Skill

Use the tdd skill to build a comprehensive test suite for your MCP server:

/tdd
Create integration tests for our MCP server that verify:
1. Each tool rejects invalid input with appropriate error messages
2. Authentication is enforced on all endpoints
3. Authorization checks prevent privilege escalation
4. Rate limiting prevents brute force attacks
5. Sensitive data is never logged

The skill generates tests covering edge cases you might miss:

// tests/security/input-validation.test.js
describe('Tool Input Validation', () => {
  it('rejects SQL injection in database query tool', async () => {
    const maliciousInput = "'; DROP TABLE users; --";
    await expect(
      mcpClient.callTool('query', { sql: maliciousInput })
    ).rejects.toMatchObject({ 
      error: /invalid input/i 
    });
  });

  it('rejects XSS payloads in string parameters', async () => {
    const xssPayload = '<script>alert(1)</script>';
    await expect(
      mcpClient.callTool('format_string', { input: xssPayload })
    ).rejects.toMatchObject({ 
      error: /invalid input/i 
    });
  });

  it('enforces maximum input length', async () => {
    const longInput = 'a'.repeat(10001);
    await expect(
      mcpClient.callTool('process_text', { text: longInput })
    ).rejects.toMatchObject({ 
      error: /too long|max length/i 
    });
  });
});

Documenting Findings with the PDF Skill

After testing, use the pdf skill to generate a professional security report:

/pdf
Create a penetration test report with sections for:
1. Executive Summary
2. Methodology
3. Findings (Critical, High, Medium, Low)
4. Proof of Concept Code
5. Remediation Recommendations
6. Conclusion

Use a clean, professional layout suitable for stakeholders.

The pdf skill generates formatted reports you can share with your team:

// generate-report.js
import { PDFDocument, rgb } from 'pdf-lib';

async function generateReport(findings) {
  const pdfDoc = await PDFDocument.create();
  const page = pdfDoc.addPage([600, 800]);
  
  // Add findings to PDF
  const { height } = page.getSize();
  let y = height - 50;
  
  page.drawText('Penetration Test Report', { 
    x: 50, y, size: 20, color: rgb(0, 0, 0) 
  });
  y -= 40;
  
  for (const finding of findings) {
    page.drawText(`${finding.severity}: ${finding.title}`, {
      x: 50, y, size: 14, color: getSeverityColor(finding.severity)
    });
    y -= 20;
    page.drawText(finding.description, { x: 50, y, size: 12 });
    y -= 40;
  }
  
  const pdfBytes = await pdfDoc.save();
  return pdfBytes;
}

Continuous Security Testing

Integrate security tests into your development workflow:

# .github/workflows/security-test.yml
name: MCP Server Security Tests

on: [push, pull_request]

jobs:
  security:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Run security tests
        run: |
          npm install
          npm run test:security
      
      - name: Upload results
        uses: actions/upload-artifact@v4
        with:
          name: security-report
          path: reports/security/

Run these tests on every commit to catch regressions early.

Conclusion

Penetration testing your MCP servers protects both your application and your users. Use the tdd skill to build comprehensive test suites, supermemory to maintain testing knowledge across sessions, and pdf to generate professional reports. Regular security testing—combined with input validation, proper authentication, and least-privilege tool design—keeps your MCP server implementations secure.


Built by theluckystrike — More at zovo.one