influxdata / influxdata/influxdb3_mcp_server

Feature Request: Pluggable Query & Tool Execution Logging for MCP Audit & Observability

Open
#61 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
38
Forks
14
Avg merge
5d 9h
Merged PRs (30d)
7

Description

Feature Request: Pluggable Query & Tool Execution Logging for MCP Audit & Observability

Summary

Add a pluggable logging system to track all MCP tool executions (queries, writes, database operations) with query ID correlation for audit trails, performance monitoring, and observability. The system should be backend-agnostic with built-in support for Loki, file logging, stdout/JSON, and custom implementations.

Motivation

Business Value
  • Audit Compliance: Track who executed what queries/operations and when
  • Performance Monitoring: Identify slow queries and bottlenecks
  • Troubleshooting: Correlate MCP requests with InfluxDB execution logs
  • Usage Analytics: Understand tool usage patterns and optimize MCP server deployments
  • Security: Detect unauthorized access attempts or suspicious query patterns
Technical Benefits
  • Query ID Correlation: Injecting unique UUIDs as SQL comments enables perfect 1:1 correlation between MCP requests and InfluxDB execution logs
  • Multi-instance Tracking: Distinguish logs from different MCP container instances in load-balanced environments
  • Structured Logging: JSON-formatted logs enable fast filtering and aggregation
  • Backend Flexibility: Different customers have different logging infrastructure (Loki, Splunk, ELK, CloudWatch, files, etc.)

Proposed Solution

Architecture: Pluggable Logging System
┌─────────────────────────────────────────────────────────────┐
│                   MCP Tool Execution                        │
│  (execute_query, write_line_protocol, create_database, etc)│
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
         ┌─────────────────────────┐
         │  Query Logger Service   │
         │  - Generate query_id    │
         │  - Inject SQL comment   │
         │  - Timing & metadata    │
         │  - Success/error capture│
         └────────┬────────────────┘
                  │
                  ▼
      ┌───────────────────────────────┐
      │  Logging Backend Interface    │
      │  (abstract/pluggable)         │
      └──┬──────────┬─────────┬───────┘
         │          │         │
    ┌────▼───┐ ┌───▼────┐ ┌──▼──────┐
    │ Loki   │ │ File   │ │ Stdout  │
    │ Push   │ │ Writer │ │ JSON    │
    └────────┘ └────────┘ └─────────┘
         │          │         │
         ▼          ▼         ▼
    Grafana     Log file    Docker logs
                            → Promtail/etc
Core Components
1. Query Logger Service (src/services/query-logger.service.ts)

Responsibilities:

  • Generate unique query IDs (UUID v4)
  • Inject query IDs into SQL as comments: -- query_id: <uuid>
  • Capture timing, metadata, results, errors
  • Route log entries to configured backend(s)

Key Methods:

class QueryLoggerService {
  // Wrap query execution with logging
  async logQuery<T>(
    operation: QueryOperation,
    execute: () => Promise<T>
  ): Promise<T>;

  // Wrap write operations
  async logWrite(
    operation: WriteOperation,
    execute: () => Promise<void>
  ): Promise<void>;

  // Wrap database management operations
  async logDbOperation(
    operation: DbOperation,
    execute: () => Promise<any>
  ): Promise<any>;
}
2. Logging Backend Interface (src/services/logging/backend.interface.ts)
interface LogEntry {
  // Core fields
  query_id: string;
  timestamp_ms: number;
  tool_name: string;
  duration_ms: number;
  success: boolean;
  
  // Query-specific
  database?: string;
  query?: string;
  result_count?: number;
  
  // Write-specific
  write_database?: string;
  line_protocol_bytes?: number;
  
  // Error info
  error_message?: string;
  http_status?: number;
  
  // Context
  mcp_server_hostname: string;
  cluster_uuid?: string;
  session_id?: string;
}

interface LoggingBackend {
  log(entry: LogEntry): Promise<void>;
  flush?(): Promise<void>;
  close?(): Promise<void>;
}
3. Built-in Backend Implementations
a) Loki Backend (src/services/logging/loki-backend.ts)
  • Push logs to Grafana Loki via HTTP API
  • Batch log entries for efficiency
  • Add Loki labels: job, source, database, success, mcp_server_hostname
  • Configuration via LOKI_URL, LOKI_BATCH_SIZE, LOKI_FLUSH_INTERVAL
b) File Backend (src/services/logging/file-backend.ts)
  • Write JSON lines to rotating log files
  • Support file rotation by size/date
  • Configuration via LOG_FILE_PATH, LOG_FILE_MAX_SIZE, LOG_FILE_MAX_AGE
c) Stdout Backend (src/services/logging/stdout-backend.ts)
  • Write JSON to stdout for collection by Docker logging drivers
  • Compatible with Promtail, Fluentd, Logstash, etc.
  • Configuration via LOG_TO_STDOUT=true
d) Null Backend (src/services/logging/null-backend.ts)
  • No-op implementation for disabling logging
  • Default when no backend configured
Configuration
Environment Variables
# Enable query logging
ENABLE_QUERY_LOGGING=true  # Default: false

# Logging backend selection (comma-separated for multiple)
QUERY_LOG_BACKEND=loki,file,stdout  # Default: null

# Loki backend configuration
LOKI_URL=http://loki:3100
LOKI_JOB_LABEL=influxdb-mcp-server
LOKI_SOURCE_LABEL=mcp_query_log
LOKI_BATCH_SIZE=100
LOKI_FLUSH_INTERVAL_MS=5000

# File backend configuration
LOG_FILE_PATH=/var/log/mcp/queries.log
LOG_FILE_MAX_SIZE_MB=100
LOG_FILE_MAX_FILES=10
LOG_FILE_ROTATION=daily  # Options: daily, weekly, size

# Stdout backend configuration
LOG_TO_STDOUT=true
LOG_STDOUT_PRETTY=false  # Pretty-print JSON (dev only)

# Query ID injection
INJECT_QUERY_ID=true  # Default: true when logging enabled
QUERY_ID_COMMENT_PREFIX=-- query_id:  # SQL comment format

# Filtering options
LOG_MIN_DURATION_MS=0  # Only log queries slower than N ms
LOG_SAMPLE_RATE=1.0  # Sample 0.0-1.0 (1.0 = log everything)
LOG_ERRORS_ONLY=false  # Only log failed operations

# Privacy/security options
LOG_QUERY_TEXT=true  # Include full query text (may contain sensitive data)
LOG_QUERY_TEXT_MAX_LENGTH=10000  # Truncate long queries
REDACT_QUERY_PARAMS=false  # Redact parameter values
Example Docker Compose Configuration
version: '3.8'

services:
  influxdb-mcp-server:
    image: influxdata/influxdb-mcp-server:latest
    environment:
      # InfluxDB connection
      INFLUX_DB_HOST_URL: http://influxdb-node1:8181
      INFLUX_DB_TOKEN: ${INFLUXDB_TOKEN}
      
      # Query logging - Loki backend
      ENABLE_QUERY_LOGGING: "true"
      QUERY_LOG_BACKEND: loki
      LOKI_URL: http://loki:3100
      LOKI_JOB_LABEL: influxdb-mcp-server
      LOKI_SOURCE_LABEL: mcp_query_log
      
      # Optional: also log to file
      # QUERY_LOG_BACKEND: loki,file
      # LOG_FILE_PATH: /var/log/mcp/queries.log
    volumes:
      # Uncomment if using file backend
      # - ./logs:/var/log/mcp
    depends_on:
      - influxdb-node1
      - loki
Query ID Injection Pattern
SQL Comment Format

For SQL queries, inject query ID as a leading comment:

-- query_id: 550e8400-e29b-41d4-a716-446655440000
SELECT * FROM temperature WHERE time > now() - INTERVAL '1 hour'

Why SQL comments?

  • ✅ Don't affect query execution or results
  • ✅ Preserved in InfluxDB query logs
  • ✅ Easy to extract with regex: -- query_id: ([a-f0-9-]+)
  • ✅ Standard SQL comment syntax (works across all SQL dialects)
Implementation in Query Service
async executeQuery(database: string, query: string): Promise<QueryResult> {
  const queryId = generateQueryId();
  
  // Inject query ID into SQL
  const annotatedQuery = `-- query_id: ${queryId}\n${query}`;
  
  // Log with query ID
  return await queryLogger.logQuery(
    {
      tool_name: 'execute_query',
      database,
      query,  // Original query without comment
      query_id: queryId
    },
    async () => {
      // Execute annotated query
      return await influxDbClient.query(database, annotatedQuery);
    }
  );
}
Log Entry Schema
Query Operation
{
  "source": "mcp_query_log",
  "query_id": "550e8400-e29b-41d4-a716-446655440000",
  "timestamp_ms": 1738512000000,
  "tool_name": "execute_query",
  "database": "metrics",
  "query": "SELECT * FROM cpu WHERE time > now() - INTERVAL '1h'",
  "duration_ms": 42.5,
  "success": true,
  "result_count": 1234,
  "http_status": 200,
  "mcp_server_hostname": "mcp-server-1",
  "cluster_uuid": "550e8400-1111-2222-3333-446655440000",
  "session_id": "sess_abc123"
}
Write Operation
{
  "source": "mcp_write_log",
  "query_id": "660e8400-e29b-41d4-a716-446655440001",
  "timestamp_ms": 1738512001000,
  "tool_name": "write_line_protocol",
  "database": "metrics",
  "duration_ms": 15.2,
  "success": true,
  "line_protocol_bytes": 4096,
  "points_written": 50,
  "http_status": 204,
  "mcp_server_hostname": "mcp-server-1",
  "cluster_uuid": "550e8400-1111-2222-3333-446655440000"
}
Error Log
{
  "source": "mcp_query_log",
  "query_id": "770e8400-e29b-41d4-a716-446655440002",
  "timestamp_ms": 1738512002000,
  "tool_name": "execute_query",
  "database": "nonexistent",
  "query": "SELECT * FROM missing_table",
  "duration_ms": 5.1,
  "success": false,
  "error_message": "Database 'nonexistent' not found",
  "http_status": 404,
  "mcp_server_hostname": "mcp-server-1"
}
Integration with Grafana Dashboard
Loki Labels
{
  job="influxdb-mcp-server",
  source="mcp_query_log",
  database="metrics",
  success="true",
  mcp_server_hostname="mcp-server-1",
  cluster_uuid="550e8400-1111-2222-3333-446655440000"
}
Example Dashboard Queries

Total Queries:

sum(count_over_time({job="influxdb-mcp-server", source="mcp_query_log"}[24h]))

Success Rate:

(sum(count_over_time({job="influxdb-mcp-server", success="true"}[24h])) 
 / sum(count_over_time({job="influxdb-mcp-server", source="mcp_query_log"}[24h]))) * 100

Average Query Duration:

avg_over_time({job="influxdb-mcp-server", source="mcp_query_log"} 
  | json 
  | unwrap duration_ms [24h])

Query Details Table:

{job="influxdb-mcp-server", source="mcp_query_log"} 
  | json 
  | line_format "{{.query}}"

Correlated Query Analysis (MCP + InfluxDB):

# MCP side
{job="influxdb-mcp-server", source="mcp_query_log"} | json

# InfluxDB side (joined by query_id)
{job="influxdb3_logs"} 
  |= "query_id" 
  | json 
  | regexp `-- query_id: (?P<query_id>[a-f0-9-]+)`
Tool Coverage
Query Operations (inject query_id)
  • execute_query - Main SQL query execution
  • get_measurements - List tables (uses SHOW TABLES)
  • get_measurement_schema - Get schema (uses DESCRIBE)
  • list_databases - List databases (uses SHOW DATABASES)
Write Operations (log without query_id injection)
  • write_line_protocol - Write data
  • ⚠️ Note: Line protocol writes don't support SQL comments, but still logged with query_id for correlation
Database Management (log without query_id injection)
  • create_database
  • delete_database
  • update_database
Token Management (optional logging)
  • ⚠️ create_admin_token, create_resource_token, etc.
  • ⚠️ Consider security implications - may want to exclude token values from logs
Other Tools
  • health_check - Should this be logged? (could be noisy)
  • get_help - Probably don't need to log
Privacy & Security Considerations
Sensitive Data in Logs
  • Query Text: May contain sensitive data (names, IDs, filter values)

    • Option: LOG_QUERY_TEXT=false to exclude query text
    • Option: REDACT_QUERY_PARAMS=true to redact parameter values
  • Token Operations: Token values should NEVER be logged

    • Redact: token field in all token management operations
  • Database Names: Generally safe but may reveal internal structure

    • Option: LOG_DATABASE_NAMES=false
Access Control
  • Log files should have restrictive permissions (600/640)
  • Loki should require authentication in production
  • Consider log retention policies (GDPR, compliance requirements)
Performance Considerations
Async/Non-blocking
  • All logging operations must be non-blocking
  • Use async queues/buffers to avoid slowing down query execution
  • Batch Loki pushes (default: 100 entries or 5 seconds)
Resource Usage
  • Loki batch buffer: ~10KB per 100 queries
  • File logging: Rotating files, max 10 files × 100MB = 1GB
  • Memory overhead: < 5MB for logging service
Sampling
  • For high-throughput deployments, support sampling:
    • LOG_SAMPLE_RATE=0.1 - Log 10% of queries
    • LOG_MIN_DURATION_MS=100 - Only log slow queries (> 100ms)
Testing Plan
Unit Tests
  • query-logger.service.test.ts - Service logic
  • loki-backend.test.ts - Loki push logic
  • file-backend.test.ts - File rotation logic
  • stdout-backend.test.ts - JSON formatting
Integration Tests
  • Test query ID injection in actual queries
  • Test log entry creation for all tool types
  • Test error handling and logging
  • Test Loki push with mock Loki server
  • Test file rotation
E2E Tests
  • Deploy with Loki backend, verify logs in Grafana
  • Deploy with file backend, verify log rotation
  • Test correlation: Execute query, find query_id in both MCP and InfluxDB logs
Documentation Updates
README.md
  • Add "Query Logging & Observability" section
  • Document environment variables
  • Add Docker Compose example with Loki
OBSERVABILITY.md (new)
  • Detailed guide to query logging
  • Grafana dashboard JSON export
  • Example LogQL queries
  • Troubleshooting guide
SECURITY.md (update)
  • Add section on sensitive data in logs
  • Redaction options
  • Log access control
Migration & Backward Compatibility
Default Behavior (No Breaking Changes)
  • Query logging disabled by default (ENABLE_QUERY_LOGGING=false)
  • Existing deployments continue working without any changes
  • No performance impact when disabled
Opt-in Activation
# Minimal setup - stdout logging
ENABLE_QUERY_LOGGING=true
QUERY_LOG_BACKEND=stdout

# Production setup - Loki
ENABLE_QUERY_LOGGING=true
QUERY_LOG_BACKEND=loki
LOKI_URL=http://loki:3100
Future Enhancements (Out of Scope)

These are NOT part of this initial implementation:

  • ❌ Custom backend plugins (filesystem-based or npm packages)
  • ❌ Metrics export (Prometheus, StatsD)
  • ❌ Real-time alerting
  • ❌ Query result caching based on query_id
  • ❌ Distributed tracing (OpenTelemetry spans)
  • ❌ Log encryption at rest
Open Questions
  1. Should token management operations be logged?

    • My recommendation: Yes, but redact token values
    • Log: tool_name, success, error, but NOT the actual token string
  2. Should health_check be logged?

    • My recommendation: No, or make it opt-in with LOG_HEALTH_CHECKS=true
    • Reason: Can be very noisy (every 10 seconds)
  3. Query text truncation length?

    • My recommendation: 10,000 characters (configurable)
    • Reason: Some queries can be massive (large IN clauses, etc.)
  4. Should we support multiple backends simultaneously?

    • My recommendation: Yes
    • Use case: Log to Loki for monitoring AND file for audit compliance
  5. Product type scoping?

    • Should this work for all InfluxDB product types?
    • My assumption: Yes (Enterprise, Core, Cloud Dedicated, Cloud Serverless)

Implementation Plan

Phase 1: Core Infrastructure (PR #1)
  • Create query-logger.service.ts base service
  • Create LoggingBackend interface
  • Implement NullBackend (no-op)
  • Implement StdoutBackend
  • Add configuration parsing
  • Add unit tests
Phase 2: Query ID Injection (PR #2)
  • Modify query.service.ts to inject query IDs
  • Wrap execute_query with logging
  • Wrap get_measurements with logging
  • Wrap get_measurement_schema with logging
  • Add integration tests
Phase 3: Advanced Backends (PR #3)
  • Implement LokiBackend with batching
  • Implement FileBackend with rotation
  • Add backend-specific tests
  • Add E2E tests with mock Loki
Phase 4: Extended Tool Coverage (PR #4)
  • Wrap write operations
  • Wrap database management operations
  • Handle errors and logging failures gracefully
  • Add comprehensive tests
Phase 5: Documentation & Examples (PR #5)
  • Update README.md
  • Create OBSERVABILITY.md
  • Update SECURITY.md
  • Add Docker Compose examples
  • Export Grafana dashboard JSON

Offer to Contribute

I am happy to implement this feature! I have:

  • ✅ Working Grafana dashboard that demonstrates the value
  • ✅ Experience with the codebase (just submitted PR #56 for retention policy fix)
  • ✅ Deep understanding of InfluxDB 3.x Enterprise architecture
  • ✅ Detailed design for pluggable, extensible architecture

What I need from maintainers:

  1. ✅ Approval that this feature aligns with project goals
  2. ❓ Answers to open questions above
  3. ❓ Any architectural preferences or constraints
  4. ❓ Preferred PR structure (one big PR vs. phased PRs)

Please let me know if this approach works, and I'll start implementation!


References

Related Work
  • Original prototype: Query logging implementation (Jan-Feb 2026, not merged)
  • PR #56: Retention policy fix (demonstrates code contribution style)
Related Issues
  • Add support for write/query host routing - Separate write/query endpoints for cluster architectures
  • Improve error messages for Cloud Dedicated product type - Better error handling
Screenshots

Dashboard showing query logging in action (from original prototype):

  • Total queries, success rate, errors over time
  • Query duration breakdown
  • Correlated MCP + InfluxDB logs using query_id
  • Performance waterfall (MCP duration vs InfluxDB planning/compute/compaction)

Labels: enhancement, observability, audit, good-first-issue (Phase 1 only), help-wanted

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by inspecting the existing MCP tool entry points and the proposed src/services/query-logger.service.ts and src/services/logging/backend.interface.ts locations. Review how execute_query, write_line_protocol, and database-management tools currently execute, then determine the logging scope and backend configuration needed. Done means the agreed design covers correlation, success and error capture, privacy settings, and the listed backend options with tests or validation paths.

Written by the indexing model from the issue text.

Assessment

Tech stack
grafana, typescript
Domain
api, backend, observability
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.