-
Notifications
You must be signed in to change notification settings - Fork 593
Description
🐞 Bug Summary
When registering grafana/mcp-grafana as a Streamable HTTP backend, the gateway's tool description validator rejects the query_loki_logs tool because its description contains a pipe character (|) in a LogQL syntax example (|= "error"). This silently drops the primary log query tool — 4 of 5 Loki tools register successfully, but the one that actually executes queries is discarded.
The validate_description method in mcpgateway/schemas.py uses a hardcoded forbidden patterns list that includes "|":
# Note: backticks (`) are allowed as they are commonly used in Markdown
# for inline code examples in tool descriptions
forbidden_patterns = ["&&", ";", "||", "$(", "|", "> ", "< "]The single | matches the LogQL pipe operator in the tool description:
"Supports full LogQL syntax for log and metric queries (e.g.,
{app="foo"} |= "error",rate({app="bar"}[1m]))."
This is a false positive — the pipe appears inside a backtick-wrapped code example describing query syntax, not as a shell injection vector. The "||" pattern already covers the dangerous shell OR case separately.
🧩 Affected Component
-
mcpgateway- API
Specifically: mcpgateway/schemas.py → ToolCreate.validate_description() (field_validator)
🔁 Steps to Reproduce
- Deploy Context Forge gateway v1.0.0-RC2
- Deploy
grafana/mcp-grafana:latestas a Streamable HTTP backend with only Loki tools enabled:# mcp-grafana args: -t streamable-http --address 0.0.0.0:8091 --endpoint-path /mcp \ --disable-write --disable-dashboard --disable-prometheus \ --disable-alerting --disable-incident --disable-oncall \ --disable-admin --disable-sift --disable-pyroscope \ --disable-asserts --disable-rendering --disable-navigation \ --disable-folder --disable-datasource --disable-annotations \ --disable-search --disable-searchlogs --disable-clickhouse \ --disable-cloudwatch --disable-elasticsearch --disable-examples \ --disable-runpanelquery --disable-proxied - Register the backend with the gateway:
curl -X POST http://<gateway>/gateways \ -H "Authorization: Bearer <token>" \ -H "Content-Type: application/json" \ -d '{ "name": "loki-server", "url": "http://<backend>:8091/mcp", "transport": "STREAMABLEHTTP" }'
- Check registered tools — only 4 out of 5 are registered.
query_loki_logsis missing.
🤔 Expected Behavior
All 5 Loki tools should be registered:
list_loki_label_names✅list_loki_label_values✅query_loki_logs❌ REJECTEDquery_loki_stats✅query_loki_volume✅
📓 Logs / Error Output
Validation failed for tool 'query_loki_logs': [{'type': 'value_error', 'loc': ('description',),
'msg': "Value error, Description contains unsafe characters: '|'",
'input': 'Executes a LogQL query against a Loki datasource to retrieve log entries or metric
values. Returns a list of results, each containing a timestamp, labels, and either a log line
(`line`) or a numeric metric value (`value`). Defaults to the last hour, a limit of 10 entries,
and \'backward\' direction (newest first). Supports full LogQL syntax for log and metric queries
(e.g., `{app="foo"} |= "error"`, `rate({app="bar"}[1m])`). Prefer using `query_loki_stats`
first to check stream size and `list_loki_label_names` and `list_loki_label_values` to verify
labels exist.',
'ctx': {'error': ValueError("Description contains unsafe characters: '|'")},
'url': 'https://errors.pydantic.dev/2.12/v/value_error'}]
Tool validation completed with 1 error(s). Successfully validated 4 tool(s).
🧠 Environment Info
| Key | Value |
|---|---|
| Version or commit | v1.0.0-RC2 |
| Runtime | Python 3.12, uvicorn |
| Platform / OS | K3s on Ubuntu 20.04 |
| Container | K3s (containerd), image: ghcr.io/ibm/mcp-context-forge:1.0.0-RC-2 |
🧩 Additional Context
Why this is a false positive:
- The pipe appears inside a backtick-wrapped code example (
{app="foo"} |= "error") — it is LogQL syntax documentation, not a shell injection vector. - The code comment already acknowledges this class of issue: "backticks are allowed as they are commonly used in Markdown for inline code examples". Pipes are equally common in documentation (LogQL, PromQL, regex, Markdown tables).
- The
"||"pattern already covers the dangerous shell OR case. The single"|"is overly broad and creates false positives for any tool description containing query syntax, regex patterns, or Markdown tables. - Setting
VALIDATION_STRICT=falsedoes not help — it only changes behavior from "reject all tools" to "skip the failing tool". The tool is still dropped with no workaround.
Impact:
query_loki_logsis the primary tool for querying Loki logs — the entire purpose of the backend. Without it, the MCP server can list labels but cannot execute any log queries.- This will affect any MCP backend whose tool descriptions contain LogQL (
|=,|~,| json), PromQL, regex patterns, or Markdown tables. - Upstream tool descriptions are controlled by
grafana/mcp-grafanaand cannot be modified by gateway operators.
Suggested fix — remove "|" from the forbidden list:
# Before
forbidden_patterns = ["&&", ";", "||", "$(", "|", "> ", "< "]
# After — "||" already covers the dangerous shell OR case
forbidden_patterns = ["&&", ";", "||", "$(", "> ", "< "]Alternatively: make the forbidden patterns configurable via env var, or exempt patterns inside backtick-delimited code spans from validation.
Gateway settings used: VALIDATION_STRICT=false, SSRF_ALLOW_PRIVATE_NETWORKS=true