influxdata / influxdata/influxdb3_mcp_server
Feature Request: Pluggable Query & Tool Execution Logging for MCP Audit & Observability
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 (usesSHOW TABLES) - ✅
get_measurement_schema- Get schema (usesDESCRIBE) - ✅
list_databases- List databases (usesSHOW 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=falseto exclude query text - Option:
REDACT_QUERY_PARAMS=trueto redact parameter values
- Option:
-
Token Operations: Token values should NEVER be logged
- Redact:
tokenfield in all token management operations
- Redact:
-
Database Names: Generally safe but may reveal internal structure
- Option:
LOG_DATABASE_NAMES=false
- Option:
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 queriesLOG_MIN_DURATION_MS=100- Only log slow queries (> 100ms)
Testing Plan
Unit Tests
query-logger.service.test.ts- Service logicloki-backend.test.ts- Loki push logicfile-backend.test.ts- File rotation logicstdout-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
-
Should token management operations be logged?
- My recommendation: Yes, but redact token values
- Log: tool_name, success, error, but NOT the actual token string
-
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)
- My recommendation: No, or make it opt-in with
-
Query text truncation length?
- My recommendation: 10,000 characters (configurable)
- Reason: Some queries can be massive (large IN clauses, etc.)
-
Should we support multiple backends simultaneously?
- My recommendation: Yes
- Use case: Log to Loki for monitoring AND file for audit compliance
-
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.tsbase service - Create
LoggingBackendinterface - Implement
NullBackend(no-op) - Implement
StdoutBackend - Add configuration parsing
- Add unit tests
Phase 2: Query ID Injection (PR #2)
- Modify
query.service.tsto inject query IDs - Wrap
execute_querywith logging - Wrap
get_measurementswith logging - Wrap
get_measurement_schemawith logging - Add integration tests
Phase 3: Advanced Backends (PR #3)
- Implement
LokiBackendwith batching - Implement
FileBackendwith 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:
- ✅ Approval that this feature aligns with project goals
- ❓ Answers to open questions above
- ❓ Any architectural preferences or constraints
- ❓ 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
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- 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