Chapter 37

Official MCP Server Ecosystem: Core Servers Including filesystem / postgres / redis / puppeteer

Chapter 37: MCP Ecosystem and Official Servers: File System, Database, Browser Control

37.1 The MCP Ecosystem at a Glance

Since MCP's official release in November 2024, a rapidly growing server ecosystem has formed around the protocol. Anthropic maintains a collection of high-quality reference servers covering the most common integration scenarios; the open-source community has contributed hundreds of third-party servers supporting everything from code hosting platforms to enterprise SaaS products.

Official server repository: https://github.com/modelcontextprotocol/servers

The MCP server ecosystem breaks down into several major categories:

Category Representative Servers Primary Function
File System @modelcontextprotocol/server-filesystem Local file read/write, directory operations
Database server-postgres, server-sqlite SQL queries, schema browsing
Code Hosting server-github, server-gitlab PRs, Issues, code search
Browser server-puppeteer, server-playwright Screenshots, automation
Search server-brave-search, server-tavily Web search
Memory @modelcontextprotocol/server-memory Persistent memory storage

37.2 Filesystem Server

@modelcontextprotocol/server-filesystem is the most fundamental and widely used MCP server, providing AI with controlled access to the local filesystem.

37.2.1 Installation and Configuration

{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-filesystem",
        "/Users/alice/Documents",
        "/Users/alice/code"
      ]
    }
  }
}

The server accepts one or more directory paths as arguments when launching โ€” these are the "root directories" accessible to the AI. All file operations are restricted to these directories. This is the core security guarantee.

37.2.2 Available Tools

Tool Function Key Parameters
read_file Read file contents path
read_multiple_files Read multiple files at once paths: string[]
write_file Write file (overwrite) path, content
create_directory Create a directory path
list_directory List directory contents path
move_file Move/rename a file source, destination
search_files Recursively search files path, pattern
get_file_info Get file metadata path

37.2.3 Real-World Scenarios

Automated code refactoring: "Convert all .jsx files in src/components to .tsx with TypeScript type annotations"

Claude with the filesystem server will automatically:

  1. Call list_directory to enumerate all .jsx files
  2. Call read_file for each file
  3. Analyze the code and add type annotations
  4. Call write_file to write the .tsx files
  5. Delete the old .jsx files after confirmation

Codebase analysis: "Analyze this Python project's import dependencies and find circular imports"

Claude reads all .py files via read_multiple_files, builds the dependency graph, and identifies cycles.

37.2.4 Extending the Filesystem Server

If the official server doesn't meet your needs (custom filtering rules, integration with other systems), you can extend it:

from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp import types
import fnmatch
from pathlib import Path
import difflib

app = Server("enhanced-filesystem")
ALLOWED_ROOTS = [Path("/home/user/projects")]
IGNORE_PATTERNS = [".git", "__pycache__", "node_modules", "*.pyc"]

@app.list_tools()
async def list_tools():
    return [
        types.Tool(
            name="smart_search",
            description="Search by filename and/or content, ignoring binary files automatically",
            inputSchema={
                "type": "object",
                "properties": {
                    "query": {"type": "string"},
                    "search_type": {"type": "string", "enum": ["content", "filename", "both"], "default": "both"},
                    "extensions": {"type": "array", "items": {"type": "string"}}
                },
                "required": ["query"]
            }
        ),
        types.Tool(
            name="diff_files",
            description="Show the diff between two files",
            inputSchema={
                "type": "object",
                "properties": {
                    "file_a": {"type": "string"},
                    "file_b": {"type": "string"}
                },
                "required": ["file_a", "file_b"]
            }
        )
    ]

@app.call_tool()
async def call_tool(name: str, arguments: dict):
    if name == "diff_files":
        a = Path(arguments["file_a"]).read_text(encoding="utf-8")
        b = Path(arguments["file_b"]).read_text(encoding="utf-8")
        diff = list(difflib.unified_diff(
            a.splitlines(keepends=True), b.splitlines(keepends=True),
            fromfile=arguments["file_a"], tofile=arguments["file_b"]
        ))
        if not diff:
            return [types.TextContent(type="text", text="Files are identical")]
        return [types.TextContent(type="text", text="".join(diff))]
    raise ValueError(f"Unknown tool: {name}")

37.3 Database Servers

37.3.1 PostgreSQL Server

{
  "mcpServers": {
    "postgres": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-postgres"],
      "env": {
        "POSTGRES_CONNECTION_STRING": "postgresql://user:password@localhost:5432/mydb"
      }
    }
  }
}

Available tools: query (SELECT only), describe_table, list_tables

Available resources: postgres://{host}/{database}/schema โ€” the complete database schema

The official PostgreSQL server allows only SELECT queries by default โ€” a critical security design. AI can analyze data but cannot modify it.

Practical usage:

User: "Analyze the orders table to find each customer's average order amount
       in the past 30 days, sorted descending by amount"

Claude:
1. describe_table("orders") to understand the schema
2. Construct the query:
   SELECT customer_id, AVG(amount) as avg_amount
   FROM orders WHERE created_at >= NOW() - INTERVAL '30 days'
   GROUP BY customer_id ORDER BY avg_amount DESC
3. Execute via query() and return results

37.3.2 SQLite Server

The SQLite server supports read-write operations and is suitable for local development:

{
  "mcpServers": {
    "sqlite": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-sqlite", "--db-path", "/path/to/database.db"]
    }
  }
}

Additional write-enabled tools: write_query (INSERT/UPDATE/DELETE), create_table, append_insight (for recording AI analysis findings in a memo resource).

37.3.3 Custom Database MCP Server

For MySQL or other databases, implement your own:

import mysql.connector
from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp import types
import os, json

app = Server("mysql-server")

def get_connection():
    return mysql.connector.connect(
        host=os.environ.get("MYSQL_HOST", "localhost"),
        user=os.environ.get("MYSQL_USER"),
        password=os.environ.get("MYSQL_PASSWORD"),
        database=os.environ.get("MYSQL_DATABASE"),
    )

@app.call_tool()
async def call_tool(name: str, arguments: dict):
    conn = get_connection()
    try:
        cursor = conn.cursor(dictionary=True)
        if name == "query":
            sql = arguments["sql"].strip()
            if not sql.upper().startswith("SELECT"):
                return [types.TextContent(type="text", text="Security: only SELECT allowed")]
            cursor.execute(sql + " LIMIT 100")
            rows = cursor.fetchall()
            return [types.TextContent(type="text", text=json.dumps(rows, default=str, indent=2))]
        elif name == "list_tables":
            cursor.execute("SHOW TABLES")
            tables = [list(r.values())[0] for r in cursor.fetchall()]
            return [types.TextContent(type="text", text="\n".join(tables))]
    finally:
        conn.close()

37.4 GitHub Server

37.4.1 Configuration

{
  "mcpServers": {
    "github": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": {
        "GITHUB_PERSONAL_ACCESS_TOKEN": "ghp_your_token"
      }
    }
  }
}

37.4.2 Core Tools

Repository operations: create_or_update_file, get_file_contents, push_files, create_repository, fork_repository

Issue management: create_issue, list_issues, update_issue, add_issue_comment

Pull Request operations: create_pull_request, get_pull_request, list_pull_requests, merge_pull_request, create_pull_request_review

Search: search_repositories, search_code, search_issues

37.4.3 Practical Usage

User: "Check new issues in anthropics/sdk from the past 7 days,
       summarize the main problems, and create a tracking issue"

Claude via GitHub Server:
1. search_issues(repo="anthropics/sdk", since="7 days ago", state="open")
2. Analyze all new issue titles and content
3. Categorize problems (security, feature requests, docs)
4. create_issue(title="Weekly Issue Summary", body="This week: X new issues, mainly...")

37.5 Browser Automation Servers

37.5.1 Puppeteer Server

{
  "mcpServers": {
    "puppeteer": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-puppeteer"]
    }
  }
}

Available tools:

Tool Function
puppeteer_navigate Navigate to a URL
puppeteer_screenshot Take a page screenshot
puppeteer_click Click a specific element
puppeteer_fill Fill a form field
puppeteer_evaluate Execute JavaScript
puppeteer_select Select a dropdown option

Web scraping example:

User: "Visit news.ycombinator.com, take a screenshot, and extract the top 10 story titles and links"

Claude:
1. puppeteer_navigate("https://news.ycombinator.com")
2. puppeteer_screenshot() โ†’ get page screenshot
3. puppeteer_evaluate("""
     Array.from(document.querySelectorAll('.titleline > a'))
       .slice(0, 10).map(a => ({title: a.textContent, url: a.href}))
   """)
4. Return structured news list

37.5.2 Playwright Server (More Powerful Alternative)

The officially released @playwright/mcp (released by the Playwright team in 2025) provides more stable browser automation with Chromium, Firefox, and WebKit support:

{
  "mcpServers": {
    "playwright": {
      "command": "npx",
      "args": ["@playwright/mcp@latest"],
      "env": { "PLAYWRIGHT_BROWSER": "chromium" }
    }
  }
}

Playwright MCP highlights:

37.6 Memory Server (Persistent Memory)

{
  "mcpServers": {
    "memory": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-memory"]
    }
  }
}

The Memory server gives AI a cross-session persistent knowledge graph store.

Available tools: create_entities, create_relations, add_observations, delete_entities, search_nodes, read_graph

Typical usage pattern:

[Session 1]
User: "I'm building a React app called TaskFlow with TypeScript
       and Tailwind CSS โ€” my main challenge is state management"

Claude stores in Memory:
- create_entities([{name: "TaskFlow", type: "Project", 
                    observations: ["React+TS+Tailwind", "State management challenge"]}])
- create_relations([{from: "User", to: "TaskFlow", type: "is_building"}])

[Session 2, days later]
User: "How is that project I mentioned going?"

Claude searches: search_nodes("TaskFlow")
โ†’ Returns: "Based on my records, you're building TaskFlow (React+TS+Tailwind).
            Last time you mentioned state management was the main challenge..."
{
  "mcpServers": {
    "brave-search": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-brave-search"],
      "env": { "BRAVE_API_KEY": "your_api_key" }
    }
  }
}

Tools: brave_web_search (web results with summaries and links), brave_local_search (local places โ€” restaurants, stores, etc.)

Brave Search advantages over Google: no user tracking, lower API pricing, and a dedicated AI query interface.

37.8 Building an Enterprise MCP Server Suite

37.8.1 Typical Enterprise Configuration

{
  "mcpServers": {
    "codebase": {
      "command": "python",
      "args": ["/opt/mcp-servers/codebase_server.py"],
      "env": { "REPOS_ROOT": "/data/repositories" }
    },
    "jira": {
      "command": "node",
      "args": ["/opt/mcp-servers/jira_server.js"],
      "env": {
        "JIRA_BASE_URL": "https://mycompany.atlassian.net",
        "JIRA_API_TOKEN": "${JIRA_TOKEN}",
        "JIRA_EMAIL": "[email protected]"
      }
    },
    "slack-notify": {
      "command": "python",
      "args": ["/opt/mcp-servers/slack_server.py"],
      "env": {
        "SLACK_BOT_TOKEN": "${SLACK_BOT_TOKEN}",
        "ALLOWED_CHANNELS": "dev-team,alerts"
      }
    }
  }
}

37.8.2 Server Registry Pattern

For teams managing many MCP servers, a server registry simplifies configuration management:

SERVER_REGISTRY = {
    "filesystem": {
        "package": "@modelcontextprotocol/server-filesystem",
        "risk_level": "medium",
        "required_env": [],
    },
    "postgres": {
        "package": "@modelcontextprotocol/server-postgres",
        "risk_level": "low",
        "required_env": ["POSTGRES_CONNECTION_STRING"],
    },
    "puppeteer": {
        "package": "@modelcontextprotocol/server-puppeteer",
        "risk_level": "high",
        "required_env": [],
    }
}

Summary

The MCP ecosystem provides official servers covering file systems, databases, code hosting, browser automation, search, and persistent memory. With these servers, AI can genuinely operate in local environments, query databases, and automate web workflows.

Key takeaways:

  1. The filesystem server uses "root directory restriction" to enforce safe operation boundaries
  2. The PostgreSQL server is read-only by default; the SQLite server supports writes
  3. The GitHub server supports complete Issue, PR, and code search workflows
  4. Puppeteer/Playwright servers give AI browser automation capabilities
  5. The Memory server implements cross-session persistence via a knowledge graph
  6. For enterprise deployment, an internal server registry simplifies centralized management

The next chapter dives into MCP's security model: OAuth authentication, sandbox isolation, and the least privilege principle.

Rate this chapter
4.7  / 5  (3 ratings)

๐Ÿ’ฌ Comments