Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions src/timestream-for-influxdb-mcp-server/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ You can modify the settings of your MCP client to run your local server (e.g. fo
"INFLUXDB_URL": "https://your-influxdb-endpoint:8086",
"INFLUXDB_TOKEN": "your-influxdb-token",
"INFLUXDB_ORG": "your-influxdb-org",
"INFLUXDB_WRITE_MODE": "false",
"FASTMCP_LOG_LEVEL": "ERROR"
},
"disabled": false,
Expand Down Expand Up @@ -73,6 +74,7 @@ For Windows users, the MCP server configuration format is slightly different:
"INFLUXDB_URL": "https://your-influxdb-endpoint:8086",
"INFLUXDB_TOKEN": "your-influxdb-token",
"INFLUXDB_ORG": "your-influxdb-org",
"INFLUXDB_WRITE_MODE": "false",
"FASTMCP_LOG_LEVEL": "ERROR"
}
}
Expand Down Expand Up @@ -152,3 +154,32 @@ The Timestream for InfluxDB MCP server provides the following tools:
##### Organization Management
- `InfluxDBListOrgs`: List all organizations in InfluxDB
- `InfluxDBCreateOrg`: Create a new organization in InfluxDB

## Configuration

### Environment Variables

| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| `AWS_PROFILE` | No | — | AWS profile for control-plane operations |
| `AWS_REGION` | No | `us-east-1` | AWS region |
| `INFLUXDB_URL` | No | — | InfluxDB v2 endpoint URL (e.g. `https://host:8086`) |
| `INFLUXDB_TOKEN` | No | — | InfluxDB v2 authentication token |
| `INFLUXDB_ORG` | No | — | InfluxDB v2 organization name |
| `INFLUXDB_ALLOWED_URLS` | No | — | Comma-separated list of additional approved InfluxDB URLs |
| `INFLUXDB_WRITE_MODE` | No | `false` | Enable write-producing Flux operations in queries (see below) |
| `FASTMCP_LOG_LEVEL` | No | — | Logging level (`ERROR`, `WARNING`, `INFO`, `DEBUG`) |

### Write Mode

By default, the `InfluxDBQuery` tool rejects Flux queries that contain write-producing operations such as `to()`, `experimental.to()`, and `wideTo()`. This ensures that the query tool behaves as read-only, even when the configured InfluxDB token has write permissions.

To enable write-producing Flux operations through the query tool, set:

```
INFLUXDB_WRITE_MODE=true
```

This setting is operator-controlled and cannot be overridden by tool callers.

> **Best practice:** For deployments that need both read and write capabilities, configure a **read-only InfluxDB token** for general use and enable the explicit write tools (`InfluxDBWritePoints`, `InfluxDBWriteLP`) with `tool_write_mode=True` only when needed. This provides the strongest data integrity guarantee regardless of the MCP server's write-mode setting.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import boto3
import os
import re
from awslabs.timestream_for_influxdb_mcp_server import __version__
from botocore.config import Config
from influxdb_client.client.influxdb_client import InfluxDBClient
Expand All @@ -40,6 +41,7 @@
INFLUXDB_URL = os.environ.get('INFLUXDB_URL')
INFLUXDB_ORG = os.environ.get('INFLUXDB_ORG')
INFLUXDB_ALLOWED_URLS = os.environ.get('INFLUXDB_ALLOWED_URLS', '')
INFLUXDB_WRITE_MODE = os.environ.get('INFLUXDB_WRITE_MODE', 'false').lower() == 'true'

# Define Field parameters as global variables to avoid duplication
# Common fields
Expand Down Expand Up @@ -437,6 +439,63 @@ def get_influxdb_client(url, token, org=None, timeout=10000, verify_ssl: bool =
)


def validate_flux_query(query: str) -> None:
"""Validate that a Flux query does not contain write-producing operations.

When INFLUXDB_WRITE_MODE is disabled (default), this function rejects Flux
queries that contain functions capable of writing data to InfluxDB. This
provides defense-in-depth protection against data modification through
the query interface.

The following write-producing Flux functions are blocked:
- to() — standard write function (influxdata/influxdb/to)
- experimental.to() — experimental write function
- wideTo() / influxdb.wideTo() — writes wide/pivoted data

Args:
query: The Flux query string to validate.

Raises:
ValueError: If the query contains write-producing operations and
INFLUXDB_WRITE_MODE is not enabled.
"""
if INFLUXDB_WRITE_MODE:
return

# Strip single-line comments (// ...) to avoid false positives from commented-out code.
# Preserve line structure so that multi-line patterns still work.
stripped = re.sub(r'//[^\n]*', '', query)

# Patterns to detect write-producing Flux functions.
# These cover:
# - Pipe-forward to `to(` — e.g. `|> to(bucket: "x")`
# - Standalone or qualified calls — e.g. `to(bucket: "x")`,
# `experimental.to(`, `influxdb.wideTo(`
# - Aliased imports — e.g. `import ex "experimental"` then `ex.to(`
# The word-boundary and parenthesis requirements minimize false positives
# from identifiers like `toString` or field names containing "to".
write_patterns = [
# Pipe-forward into to(): |> to(
r'\|>\s*to\s*\(',
# Qualified calls: experimental.to( or <alias>.to( preceded by word char + dot
r'\w+\.to\s*\(',
# wideTo as standalone or qualified: wideTo( or <qualifier>.wideTo(
r'(?:\w+\.)?wideTo\s*\(',
# Standalone to() at statement level — preceded by start-of-line or semicolon
# but NOT preceded by a dot (which would be a method on something else).
r'(?:^|;\s*)to\s*\(',
]

for pattern in write_patterns:
if re.search(pattern, stripped, re.MULTILINE):
raise ValueError(
'Query contains a write-producing Flux operation (to(), experimental.to(), '
'or wideTo()) which is not allowed when INFLUXDB_WRITE_MODE is not enabled. '
'Set the INFLUXDB_WRITE_MODE=true environment variable to allow write '
'operations through Flux queries.'
)


@mcp.tool(
name='CreateDbCluster', description='Create a new Timestream for InfluxDB database cluster.'
)
Expand Down Expand Up @@ -1365,6 +1424,9 @@ async def influxdb_query(
Returns:
Query results in the specified format.
"""
# Validate query does not contain write-producing operations in read-only mode
validate_flux_query(query)

resolved_url, resolved_token, resolved_org = resolve_influxdb_config(url, token, org)

try:
Expand Down
Loading
Loading