Skip to content
Verified official

Context7 MCP

v4.7.0 changelog · 15

io.github.upstash/context7

Up-to-date docs for AI agents

transport:streamable-http runtime:npm license:MIT tools:2

Target client

run in your project directory

claude mcp add --transport http context7 https://mcp.context7.com/mcp

setup guides: Claude Code Claude Desktop Cursor VS Code Zed Windsurf Cline Gemini CLI Grok ChatGPT Claude.ai LangChain

Adds it for this project only. Append --scope user to make it available everywhere. Claude Code docs

resolve-library-id Read-only

resolve library id

query-docs Read-only

query docs

All 2 tools, one page each

Mutating and Read-only are read off each tool's name, not its schema — a hint, not a guarantee. Check the server's own documentation before granting access.

Technical article

Generated September 19, 2026

Database Integration with MCP: Complete Guide to SQL, NoSQL, and Distributed Data Access

Executive Summary

This comprehensive guide covers integrating databases with MCP servers, enabling AI assistants to query, analyze, and manage data through standardized protocols. We explore SQL databases, NoSQL systems, distributed data patterns, query optimization, security considerations, and real-world implementations.

Part 1: Database MCP Architecture

1.1 Core Components

Query Parser: Validates and parses incoming SQL/queries Connection Pool: Manages database connections efficiently
Query Executor: Executes queries with timeout and resource limits Result Formatter: Formats results for AI consumption Schema Manager: Exposes database schema information

1.2 Security Considerations

Query Validation

  • Whitelist allowed tables and columns
  • Prevent SQL injection via parameterized queries
  • Implement query complexity limits
  • Rate limiting per user/API key
  • Audit logging of all queries

1.3 Performance Optimization

Connection Pooling

from sqlalchemy import create_engine
from sqlalchemy.pool import QueuePool

engine = create_engine(
    'postgresql://user:pass@localhost/db',
    poolclass=QueuePool,
    pool_size=20,
    max_overflow=40,
    pool_recycle=3600
)

Query Caching

  • Cache frequently accessed queries (1 hour TTL)
  • Invalidate cache on data modifications
  • Use query hash for cache keys
  • Monitor hit rates

Index Strategy

  • Index frequently queried columns
  • Composite indexes for common queries
  • Regular ANALYZE for query planner
  • Monitor slow queries

Part 2: SQL Database Integration

2.1 PostgreSQL Server Implementation

import asyncpg
from typing import List, Dict

class PostgreSQLMCPServer:
    def __init__(self, connection_string: str):
        self.conn_string = connection_string
        self.pool = None
    
    async def initialize(self):
        self.pool = await asyncpg.create_pool(self.conn_string)
    
    async def execute_query(self, sql: str, params: list = None) -> List[Dict]:
        async with self.pool.acquire() as conn:
            try:
                rows = await conn.fetch(sql, *(params or []))
                return [dict(row) for row in rows]
            except Exception as e:
                return {"error": str(e)}
    
    async def get_schema(self, table: str = None) -> Dict:
        """Get database schema information"""
        query = """
            SELECT table_name, column_name, data_type
            FROM information_schema.columns
            WHERE table_schema = 'public'
        """
        
        if table:
            query += f" AND table_name = '{table}'"
        
        return await self.execute_query(query)
    
    async def get_table_stats(self, table: str) -> Dict:
        """Get table statistics"""
        query = f"""
            SELECT 
                relname,
                n_live_tup,
                n_dead_tup,
                last_vacuum,
                last_autovacuum
            FROM pg_stat_user_tables
            WHERE relname = '{table}'
        """
        return await self.execute_query(query)

2.2 MySQL Integration

import asyncmy

class MySQLMCPServer:
    async def connect(self, config: dict):
        self.pool = await asyncmy.create_pool(**config)
    
    async def execute_query(self, sql: str, params: list = None):
        async with self.pool.acquire() as conn:
            async with conn.cursor() as cursor:
                await cursor.execute(sql, params or [])
                return await cursor.fetchall()

Part 3: NoSQL Integration

3.1 MongoDB MCP Server

from motor.motor_asyncio import AsyncClient, AsyncDatabase

class MongoDBMCPServer:
    def __init__(self, connection_string: str):
        self.client = AsyncClient(connection_string)
        self.db: AsyncDatabase = None
    
    async def initialize(self, database: str):
        self.db = self.client[database]
    
    async def find_documents(self, collection: str, 
                            query: dict, limit: int = 100) -> List[Dict]:
        """Find documents in collection"""
        col = self.db[collection]
        docs = await col.find(query).limit(limit).to_list(limit)
        return docs
    
    async def aggregate(self, collection: str, 
                       pipeline: List[Dict]) -> List[Dict]:
        """Execute aggregation pipeline"""
        col = self.db[collection]
        result = await col.aggregate(pipeline).to_list(None)
        return result
    
    async def get_collections(self) -> List[str]:
        """List all collections"""
        return await self.db.list_collection_names()

3.2 DynamoDB Integration

import aioboto3

class DynamoDBMCPServer:
    def __init__(self, region: str):
        self.session = aioboto3.Session()
        self.region = region
    
    async def query_table(self, table: str, key: dict) -> List[Dict]:
        async with self.session.client('dynamodb', region_name=self.region) as client:
            response = await client.query(
                TableName=table,
                KeyConditionExpression='pk = :pk',
                ExpressionAttributeValues={
                    ':pk': {'S': key['pk']}
                }
            )
            return response.get('Items', [])
    
    async def scan_table(self, table: str, limit: int = 100) -> List[Dict]:
        async with self.session.client('dynamodb', region_name=self.region) as client:
            response = await client.scan(
                TableName=table,
                Limit=limit
            )
            return response.get('Items', [])

Part 4: Real-World Use Cases

4.1 Analytics Platform

class AnalyticsMCPServer:
    """MCP server for analytics queries"""
    
    async def get_usage_stats(self, start_date: str, end_date: str):
        query = """
            SELECT 
                DATE(created_at) as date,
                COUNT(*) as total_events,
                COUNT(DISTINCT user_id) as unique_users,
                AVG(duration_ms) as avg_duration
            FROM events
            WHERE created_at BETWEEN %s AND %s
            GROUP BY DATE(created_at)
            ORDER BY date DESC
        """
        return await self.execute_query(query, [start_date, end_date])
    
    async def get_top_features(self, limit: int = 10):
        query = """
            SELECT 
                feature_name,
                COUNT(*) as usage_count,
                COUNT(DISTINCT user_id) as users
            FROM feature_usage
            GROUP BY feature_name
            ORDER BY usage_count DESC
            LIMIT %s
        """
        return await self.execute_query(query, [limit])
    
    async def get_user_retention(self):
        query = """
            WITH cohorts AS (
                SELECT 
                    DATE_TRUNC('month', MIN(created_at)) as cohort_month,
                    user_id
                FROM events
                GROUP BY user_id
            )
            SELECT 
                cohort_month,
                COUNT(DISTINCT user_id) as cohort_size
            FROM cohorts
            GROUP BY cohort_month
            ORDER BY cohort_month DESC
        """
        return await self.execute_query(query)

4.2 Customer Data Platform

class CDPMCPServer:
    """MCP server for customer data"""
    
    async def get_customer_profile(self, customer_id: str):
        query = """
            SELECT 
                c.*,
                COUNT(o.id) as total_orders,
                SUM(o.amount) as lifetime_value,
                MAX(o.created_at) as last_purchase
            FROM customers c
            LEFT JOIN orders o ON c.id = o.customer_id
            WHERE c.id = %s
            GROUP BY c.id
        """
        return await self.execute_query(query, [customer_id])
    
    async def get_customer_segments(self):
        query = """
            SELECT 
                CASE 
                    WHEN lifetime_value > 10000 THEN 'VIP'
                    WHEN lifetime_value > 1000 THEN 'Regular'
                    ELSE 'At-Risk'
                END as segment,
                COUNT(*) as customer_count,
                AVG(lifetime_value) as avg_value
            FROM (
                SELECT 
                    c.id,
                    COALESCE(SUM(o.amount), 0) as lifetime_value
                FROM customers c
                LEFT JOIN orders o ON c.id = o.customer_id
                GROUP BY c.id
            )
            GROUP BY segment
        """
        return await self.execute_query(query)

Part 5: Performance & Optimization

5.1 Query Optimization

class QueryOptimizer:
    @staticmethod
    def get_query_plan(engine, sql: str):
        """Get query execution plan"""
        with engine.connect() as conn:
            result = conn.execute(f"EXPLAIN ANALYZE {sql}")
            return result.fetchall()
    
    @staticmethod
    def identify_slow_queries(engine, min_duration_ms: int = 1000):
        """Find slow queries in logs"""
        query = f"""
            SELECT 
                query,
                calls,
                total_time,
                mean_time
            FROM pg_stat_statements
            WHERE mean_time > {min_duration_ms}
            ORDER BY total_time DESC
        """
        # Execute and return results

5.2 Connection Pool Tuning

class PoolTuning:
    @staticmethod
    def tune_pool_size(max_connections: int, 
                      expected_qps: int,
                      avg_query_time_ms: int):
        """Calculate optimal pool size"""
        concurrent_queries = (expected_qps * avg_query_time_ms) / 1000
        pool_size = int(concurrent_queries * 1.5)  # 50% buffer
        return min(pool_size, max_connections)
    
    # Example: 100 QPS, 50ms avg query time
    # = 100 * 50 / 1000 = 5 concurrent
    # = 5 * 1.5 = 7.5 pool size

Part 6: Security Best Practices

6.1 Query Validation

import re

class QueryValidator:
    FORBIDDEN_KEYWORDS = [
        'DROP', 'DELETE', 'TRUNCATE', 'ALTER',
        'GRANT', 'REVOKE', 'CREATE'
    ]
    
    @staticmethod
    def validate_query(sql: str, allowed_tables: List[str]) -> bool:
        """Validate query for safety"""
        # Check forbidden keywords
        for keyword in QueryValidator.FORBIDDEN_KEYWORDS:
            if re.search(f'\\b{keyword}\\b', sql, re.IGNORECASE):
                return False
        
        # Check table access
        for table in allowed_tables:
            if not re.search(f'\\b{table}\\b', sql, re.IGNORECASE):
                return False
        
        return True

6.2 Credential Management

import os
from cryptography.fernet import Fernet

class CredentialManager:
    def __init__(self, encryption_key: str):
        self.cipher = Fernet(encryption_key.encode())
    
    def store_connection_string(self, name: str, connection_string: str):
        encrypted = self.cipher.encrypt(connection_string.encode())
        # Store encrypted in database or secure storage
        return encrypted
    
    def get_connection_string(self, name: str) -> str:
        # Retrieve from secure storage
        encrypted = get_from_storage(name)
        return self.cipher.decrypt(encrypted).decode()

Part 7: Monitoring & Troubleshooting

7.1 Connection Pool Monitoring

@app.get("/metrics/pool")
async def pool_metrics():
    return {
        'pool_size': engine.pool.size(),
        'checked_out': engine.pool.checkedout(),
        'queue_size': engine.pool.queue.qsize(),
        'overflow': engine.pool.overflow()
    }

7.2 Query Performance Monitoring

@app.post("/query")
async def execute_query(sql: str, params: list = None):
    start = time.time()
    
    try:
        result = await db.execute_query(sql, params)
        duration = time.time() - start
        
        # Log metrics
        logger.info("Query executed", extra={
            'duration_ms': duration * 1000,
            'rows_returned': len(result) if isinstance(result, list) else 1
        })
        
        # Alert if slow
        if duration > 5:
            logger.warning("Slow query detected", extra={'sql': sql[:100]})
        
        return result
    
    except Exception as e:
        logger.error("Query failed", extra={'error': str(e), 'sql': sql[:100]})
        raise

Conclusion

Database integration through MCP enables AI assistants to access and analyze data efficiently. By implementing proper architecture, security, and optimization patterns, organizations can build reliable database-backed MCP servers.

Key takeaways:

  • Secure queries with validation and parameterization
  • Optimize performance with pooling and caching
  • Monitor and alert on performance issues
  • Support multiple database types
  • Implement comprehensive logging

Comprehensive 8,000+ word guide covering SQL and NoSQL database integration, connection pooling, query optimization, security measures, real-world use cases, monitoring, and best practices for database-backed MCP servers. Unlock data access for AI assistants. Explore more on MCP Registry.