DEV Community

Arthur Palyan
Arthur Palyan

Posted on

MCP Analyzer: How We Made Our MCP Server Configure Itself for Each User

We ship The Nervous System - an MCP server with 18 tools for LLM behavioral enforcement. Security audits, drift detection, session handoffs, guardrails.

18 tools is a lot. New users would install it and ask: which tools do I actually need?

So we built mcp_analyzer - a tool that scans your project and tells you exactly which tools matter for your workflow. Then it generates a CLAUDE.md so your LLM already knows what to do.

The Problem

MCP servers ship tools as a flat list. You get tools/list, you see 18 entries, and you have to read each description to figure out which ones are relevant.

For a production Node.js system with PM2, you need drift_audit, security_audit, session_close, and dispatch_to_llm. For a simple web app, you need page_health and preflight_check. For a publishable npm package, you need pre_publish_audit.

But users don't know this upfront. They either use everything (noisy) or nothing (useless).

The Solution: Analyze, Then Configure

mcp_analyzer has three modes:

  • mode=analyze - scans your project and returns recommendations
  • mode=write - generates a tailored CLAUDE.md for your project
  • mode=reload - re-scans after your project changes

Here's the core detection logic:

function runMCPAnalyzer(mode, outputPath) {
  const projectRoot = PROJECT.project_root || process.cwd();
  const characteristics = {
    has_protected_files: false,
    has_html_pages: false,
    has_pm2: false,
    has_package_json: false,
    has_git: false,
    has_tests: false,
    project_type: 'unknown',
    languages: [],
    js_files: 0,
    py_files: 0,
    html_files: 0
  };

  // Recursive scan (max depth 3, skips node_modules)
  const scanDir = function(dir, depth) {
    if (depth > 3) return;
    const items = fs.readdirSync(dir);
    for (const item of items) {
      if (item.startsWith('.') || item === 'node_modules') continue;
      const stat = fs.statSync(path.join(dir, item));
      if (stat.isDirectory()) {
        if (item === 'test' || item === 'tests') {
          characteristics.has_tests = true;
        }
        scanDir(path.join(dir, item), depth + 1);
      } else {
        if (item.endsWith('.js')) characteristics.js_files++;
        if (item === 'package.json') characteristics.has_package_json = true;
      }
    }
  };
  scanDir(projectRoot, 0);
Enter fullscreen mode Exit fullscreen mode

It figures out what kind of project you have, then maps that to tool recommendations:

  // Production system with PM2 = you need the heavy tools
  if (characteristics.has_pm2 && characteristics.js_files > 5) {
    characteristics.project_type = 'production_system';
  }

  // Tool recommendations based on project type
  const recommendations = [];

  // Everyone needs these
  recommendations.push({
    tool: 'get_framework',
    priority: 'essential',
    reason: 'Core behavioral rules. Read this first.'
  });
  recommendations.push({
    tool: 'preflight_check',
    priority: 'essential',
    reason: 'Protects critical files from accidental edits.'
  });

  // Production systems get extra tools
  if (characteristics.project_type === 'production_system') {
    recommendations.push({
      tool: 'drift_audit',
      priority: 'high',
      reason: 'Catches when configs and running processes go out of sync.'
    });
    recommendations.push({
      tool: 'security_audit',
      priority: 'high',
      reason: 'Catches exposed secrets and misconfigurations.'
    });
  }

  // Publishable packages need pre-publish audit
  if (characteristics.has_package_json && characteristics.has_git) {
    recommendations.push({
      tool: 'pre_publish_audit',
      priority: 'high',
      reason: 'Catches secrets and hardcoded paths before they ship.'
    });
  }
Enter fullscreen mode Exit fullscreen mode

The Generated CLAUDE.md

When you run mode=write, it generates a project-specific CLAUDE.md that tells your LLM exactly how to behave:

# CLAUDE.md - Generated by The Nervous System MCP Analyzer
# Project type: production_system
# Re-run: mcp_analyzer mode=reload to refresh

## BEHAVIORAL RULES

This project uses The Nervous System for LLM behavioral enforcement.
Before doing anything, internalize these rules:

1. DISPATCH DONT DO - If a task takes 2+ messages, write a task file
   and dispatch it.
2. ALWAYS UPDATE SESSION_HANDOFF - Before ending, update the handoff
   so the next session starts with full context.
3. PREFLIGHT BEFORE EDITING - Run preflight_check before modifying
   any file.

## ESSENTIAL TOOLS (use every session)
- get_framework - Your behavioral rules
- preflight_check - File protection
- worklog - Progress logging
- session_handoff - Context continuity

## HIGH PRIORITY TOOLS
- drift_audit - Config/process sync
- security_audit - Secret scanning
- dispatch_to_llm - Background task delegation

## PRODUCTION RULES
- Run security_audit after any auth or config changes
- Run drift_audit after any file changes
- Run pre_publish_audit before publishing any packages
Enter fullscreen mode Exit fullscreen mode

The LLM reads this at session start and already knows which tools to use and when.

The Difference Between a Utility and a Product

Before mcp_analyzer, The Nervous System was a utility. You installed it, read the docs, figured out which tools mattered, and configured everything yourself.

After mcp_analyzer, it's closer to a product. Install it, run one command, and it configures itself for your project. The barrier to value went from "read docs and experiment" to "run analyze".

The pattern is simple:

  1. Detect what the user has (project scan)
  2. Recommend based on what you detected (priority mapping)
  3. Generate the config so they don't have to write it (CLAUDE.md output)

This works for any tool with a complex surface area. If your tool has more than 5 features, build an analyzer that recommends which ones matter for each user.

Try It

npm install mcp-nervous-system
Enter fullscreen mode Exit fullscreen mode

Add it to your MCP config, then ask your LLM:

Use mcp_analyzer mode=analyze to see which tools I need

Or go straight to config generation:

Use mcp_analyzer mode=write to generate my CLAUDE.md

GitHub | npm

Top comments (0)