Skip to content
mcp-server-reviewing logo

MCP Server Reviewing

mcp-server-reviewing

Audits MCP servers for security vulnerabilities, missing validation, error handling issues, and production readiness. Use when reviewing MCP PRs or auditing server quality.

SKILL.md

Full skill instructions

MCP Server Reviewing

Purpose

Audit MCP (Model Context Protocol) servers for security issues, architectural violations, missing validation, and production readiness. Ensure servers follow SDK best practices.

When to Use This Skill

  • Reviewing MCP server code in PRs
  • Auditing existing MCP servers for quality
  • Pre-release security and quality checks
  • Verifying MCP servers follow best practices

When NOT to Use This Skill

  • Writing new MCP servers (use mcp-server-writing)
  • General TypeScript/​Python code review (use language-specific reviewers)
  • Reviewing non-MCP server code

Severity Classification

SeverityDescriptionAction
CRITICALSecurity vulnerabilities, secrets exposure, data leaksBlock PR, fix immediately
HIGHMissing validation, error swallowing, transport violationsBlock PR, require fix
MEDIUMMissing descriptions, poor error messages, logging issuesRequest fix before merge
LOWStyle issues, optimization opportunities, minor improvementsSuggest improvements

Automated Detection Commands

Run these commands to detect common violations. Each command includes the violation code for reference.

Security Violations (S1-S5)

S1: Hardcoded Secrets

grep -rn "api[_-]\?key\s*[:=]" --include="*.ts" --include="*.py" src/ | grep -v "process\.env\|os\.environ"

S2: Console.log to stdout (breaks stdio transport)

grep -rn "console\.log\|print(" --include="*.ts" --include="*.py" src/ | grep -v "console\.error\|sys\.stderr\|\.test\.\|\.spec\."

S3: Missing ReDoS Protection

grep -rn "new RegExp\|\.match\|\.replace\|\.split" --include="*.ts" --include="*.py" src/ | grep -v "safeInput\|MAX_INPUT"

S4: Unsafe eval/​exec

grep -rn "eval(\|exec(\|Function(" --include="*.ts" --include="*.py" src/

S5: SQL Injection Risk

grep -rn "query.*\`\|execute.*f\"\|cursor\.execute.*%" --include="*.ts" --include="*.py" src/

Architecture Violations (A1-A5)

A1: Missing Tool Descriptions

grep -rn "name:\s*['\"]" --include="*.ts" src/ -A 3 | grep -B 3 "inputSchema" | grep -v "description"

A2: Missing inputSchema Property Descriptions

grep -rn "properties:" --include="*.ts" src/ -A 10 | grep -E "type.*string|type.*number" | grep -v "description"

A3: Tools Without Validation

grep -rn "request\.params\|args\." --include="*.ts" src/ | grep -v "validate\|ajv\|zod\|schema"

A4: Missing isError Flag

grep -rn "content.*error\|success.*false" --include="*.ts" src/ | grep -v "isError"

A5: Direct Response Without JSON

grep -rn "text:.*\`" --include="*.ts" src/ | grep -v "JSON\.stringify"

Error Handling Violations (E1-E5)

E1: Empty Catch Blocks

grep -rn "catch.*{" --include="*.ts" --include="*.py" src/ -A 2 | grep -E "^\s*}\s*$"

E2: Swallowed Errors (catch without rethrow or return)

grep -rn "catch" --include="*.ts" src/ -A 5 | grep -v "throw\|return\|logger\|console\.error"

E3: Missing Error Context

grep -rn "throw new Error\|raise.*Error" --include="*.ts" --include="*.py" src/ | grep -v ":\|context\|failed"

E4: Generic Error Messages

grep -rn "\"error\"\|\"Error\"\|\"failed\"" --include="*.ts" src/ | grep -v "suggestion\|field\|message"

E5: Unhandled Promise Rejections

grep -rn "\.then(" --include="*.ts" src/ | grep -v "\.catch\|await"

Maintainability Violations (M1-M5)

M1: Magic Numbers/​Strings

grep -rn "[0-9]\{4,\}\|timeout.*[0-9]" --include="*.ts" --include="*.py" src/ | grep -v "const\|MAX_\|MIN_\|DEFAULT_"

M2: Missing Type Annotations (Python)

grep -rn "def.*(" --include="*.py" src/ | grep -v "->.*:"

M3: TODO/​FIXME in Production Code

grep -rn "TODO\|FIXME\|XXX\|HACK" --include="*.ts" --include="*.py" src/

M4: Duplicate Tool Definitions

grep -rn "name:\s*['\"]" --include="*.ts" src/ | cut -d: -f3 | sort | uniq -d

M5: Inconsistent Error Response Format

grep -rn "isError.*true" --include="*.ts" src/ -B 5 | grep "text:" | grep -v "success\|errors"

Manual Review Checklist

Security Review

  • S1: No hardcoded API keys, passwords, or secrets
  • S2: All logging goes to stderr (not stdout)
  • S3: Input length limited before regex processing
  • S4: No eval(), exec(), or dynamic code execution
  • S5: Parameterized queries for any database access
  • S6: Environment variables used for configuration
  • S7: Sensitive data not logged (passwords, tokens, PII)

Architecture Review

  • A1: All tools have clear description fields
  • A2: All inputSchema properties have description
  • A3: Input validation before any processing
  • A4: Error responses include isError: true
  • A5: All responses are JSON-serialized
  • A6: Resources use appropriate URI schemes
  • A7: Prompts have clear argument descriptions

Error Handling Review

  • E1: No empty catch blocks
  • E2: Errors logged or re-thrown, never swallowed
  • E3: Error messages include context (what failed, why)
  • E4: Error responses include suggestion field
  • E5: Async operations properly awaited/​handled
  • E6: Graceful degradation for external dependencies

Production Readiness Review

  • P1: Structured logging with JSON format
  • P2: Health check endpoint or mechanism
  • P3: Configurable timeouts for external calls
  • P4: Graceful shutdown handling
  • P5: No debug/​development code in production
  • P6: Dependencies pinned to specific versions
  • P7: Dockerfile or deployment configuration present

Common Violations with Fixes

S2: Logging to stdout (CRITICAL)

Problem: stdout is reserved for JSON-RPC messages. Logging there corrupts the transport.

// ❌ BAD: Breaks MCP stdio transport
console.log("Processing request:", args);
// ✅ GOOD: Log to stderr
console.error(
  JSON.stringify({
    timestamp: new Date().toISOString(),
    level: "INFO",
    message: "Processing request",
    context: { args_keys: Object.keys(args) },
  }),
);

S3: Missing ReDoS Protection (HIGH)

Problem: Unbounded input to regex can cause catastrophic backtracking.

// ❌ BAD: No input length limit
const matches = userInput.match(/​complex.*pattern/);
// ✅ GOOD: Limit input before regex
const MAX_INPUT_LENGTH = 50_000;
const safeInput = (text: string) =>
  text.length > MAX_INPUT_LENGTH ? text.slice(0, MAX_INPUT_LENGTH) : text;

const matches = safeInput(userInput).match(/​complex.*pattern/);

A1: Missing Tool Description (MEDIUM)

Problem: LLM can't understand when to use the tool.

// ❌ BAD: No description
{
  name: "process_data",
  inputSchema: { type: "object", properties: { data: { type: "string" } } }
}
// ✅ GOOD: Clear description explaining purpose and return value
{
  name: "process_data",
  description: "Validates and transforms input data according to specified format. Returns structured result with validation errors if any.",
  inputSchema: {
    type: "object",
    properties: {
      data: {
        type: "string",
        description: "Raw data string to process"
      },
      format: {
        type: "string",
        enum: ["json", "csv", "xml"],
        description: "Expected input format for validation"
      }
    },
    required: ["data", "format"]
  }
}

A4: Missing isError Flag (HIGH)

Problem: Client can't distinguish errors from successful responses.

// ❌ BAD: Error without isError flag
return {
  content: [{ type: "text", text: JSON.stringify({ error: "Not found" }) }],
};
// ✅ GOOD: Proper error response
return {
  content: [
    {
      type: "text",
      text: JSON.stringify({
        success: false,
        errors: [
          {
            field: "id",
            message: "Resource not found",
            suggestion: "Verify the ID exists and try again",
          },
        ],
      }),
    },
  ],
  isError: true,
};

E1: Empty Catch Block (HIGH)

Problem: Errors are silently swallowed, making debugging impossible.

// ❌ BAD: Silent failure
try {
  await riskyOperation();
} catch (error) {
  // do nothing
}
// ✅ GOOD: Log and handle appropriately
try {
  await riskyOperation();
} catch (error) {
  logger.error("Risky operation failed", { error: error.message });
  return createErrorResponse([
    {
      field: "operation",
      message: "Operation failed",
      suggestion: "Check input parameters and retry",
    },
  ]);
}

E4: Generic Error Messages (MEDIUM)

Problem: Users can't understand what went wrong or how to fix it.

// ❌ BAD: Unhelpful error
return { error: "Something went wrong" };
// ✅ GOOD: Specific, actionable error
return {
  success: false,
  errors: [
    {
      field: "partner_id",
      message: "Invalid UUID format: 'abc123'",
      suggestion: "Use format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    },
  ],
};

Review Report Template

Use this template when reporting review findings:

# MCP Server Review: [Server Name]

**Reviewer:** [Name]
**Date:** [Date]
**Files Reviewed:** [List of files]

## Summary

| Severity | Count |
| -------- | ----- |
| CRITICAL | X     |
| HIGH     | X     |
| MEDIUM   | X     |
| LOW      | X     |

**Recommendation:** [APPROVE / APPROVE WITH CHANGES / REQUEST CHANGES / BLOCK]

## Critical Issues

### [S1] Hardcoded API Key

- **File:** src/​config.ts:42
- **Code:** `const API_KEY = "sk_live_..."`
- **Fix:** Move to environment variable

## High Issues

### [A4] Missing isError Flag

- **File:** src/​tools/​processor.ts:128
- **Code:** Error response without isError
- **Fix:** Add `isError: true` to error responses

## Medium Issues

### [A1] Missing Tool Description

- **File:** src/​index.ts:56
- **Tool:** `validate_input`
- **Fix:** Add description explaining tool purpose

## Low Issues

### [M3] TODO Comment

- **File:** src/​utils/​parser.ts:89
- **Comment:** `// TODO: optimize this`
- **Suggestion:** Create ticket or remove

## Checklist Results

- [x] Security: 6/​7 passed
- [x] Architecture: 5/​7 passed
- [ ] Error Handling: 4/​6 passed
- [x] Production: 7/​7 passed

Workflow

Step 1: Run Automated Detection

# Run all security checks
grep -rn "console\.log\|api[_-]\?key\s*[:=]" --include="*.ts" src/

# Run all architecture checks
grep -rn "name:\s*['\"]" --include="*.ts" src/ -A 5 | grep -v description

Step 2: Manual Checklist Review

Walk through each section of the manual review checklist, marking items as pass/​fail.

Step 3: Code Walkthrough

  1. Read each tool definition
  2. Trace request handling flow
  3. Verify error paths
  4. Check resource and prompt definitions

Step 4: Generate Report

Use the review report template to document findings with specific file locations and code snippets.

Step 5: Classify and Prioritize

  1. Group findings by severity
  2. Identify blocking issues (CRITICAL/​HIGH)
  3. Suggest fixes for each issue

Related Skills

  • mcp-server-writing - Create new MCP servers
  • security-scan - General security scanning
  • quality-check - Code quality checks

Resources

More skills from majiayu000

xiaohongshu logo
majiayu000/claude-arsenal

xiaohongshu

xiaohongshu

286 148
View
agent-task-conductor logo
majiayu000/claude-skill-registry

agent-task-conductor

Conduct multi-agent task orchestration and workflow coordination.

663 1
View
conductor-setup logo
majiayu000/claude-skill-registry

conductor-setup

Initialize project with Conductor artifacts (product definition,

663 1
View
animation-designer logo
majiayu000/claude-skill-registry

animation-designer

Expert in web animations, transitions, and motion design using Framer Motion and CSS

663 1
View
diagramming logo
majiayu000/claude-skill-registry

diagramming

Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...

663 1
View
h3-pg logo
majiayu000/claude-skill-registry-data

h3-pg

PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.

23 1
View
conductor-development logo
majiayu000/claude-skill-registry

conductor-development

Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...

663 1
View
conductor-status logo
majiayu000/claude-skill-registry

conductor-status

Display project status, active tracks, and next actions

663 1
View
dockerization logo
majiayu000/claude-skill-registry

dockerization

Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.

663 1
View

Popular AI tools

Kaiber logo
Video

Kaiber

Generate, edit, and beat-sync AI video with leading models in one workspace.

Paid
View
Vimcal logo
Productivity

Vimcal

The world's fastest calendar for remote work

Free
View

Transform Your Design with AI Designer by ImgCreator.ai

Freemium
View
Akool AI logo
Content & writing

Akool AI

Revolutionizing Video Production with AI-Powered Creativity

Paid
View

Extend an image past the frame and let AI fill the new aspect ratio.

Freemium
View
StarByFace logo
Security

StarByFace

Discover your celebrity doppelgänger with StarByFace!

Free
View
C

ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.

Freemium
View
Opus Clip logo
Coding & apps

Opus Clip

Opus.ai: Revolutionize Your Web Experience

Free
View