Skip to content

[BUG]: Gateway Rejects Loki Query Tools Due to Backtick Validation #2576

@ajaysingh-sc30

Description

@ajaysingh-sc30

🐞 Bug Summary

IBM Context Forge Gateway rejects 5 critical Loki query tools during backend registration due to overly strict validation that flags backtick (`) characters in tool descriptions as "unsafe". This results in only 7 out of 12 tools being exposed through the gateway, blocking all primary log querying functionality.


🧩 Affected Component

Select the area of the project impacted:

  • mcpgateway - API (Gateway Service - Tool Validation)
  • mcpgateway - UI (admin panel)
  • mcpgateway.wrapper - stdio wrapper
  • Federation or Transports
  • CLI, Makefiles, or shell scripts
  • Container setup (Docker/Podman/Compose)
  • Other (explain below)

Specific Component: mcpgateway.services.gateway_service - Tool validation during backend registration


🔁 Steps to Reproduce

  1. Deploy Grafana MCP server (grafana/mcp-grafana:latest) with Loki datasource enabled:

    kubectl apply -f k8s/loki-mcp-server.yaml
  2. Register the Loki MCP server as a gateway backend:

    curl -X POST \
      -H "Authorization: Bearer $TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "name": "loki_ws4r1_streamable",
        "url": "http://<gateway-ip>/loki-mcp/mcp",
        "description": "WS4R1 Loki MCP Server",
        "transport": "STREAMABLEHTTP"
      }' \
      http://<gateway-ip>/mcp-gateway/gateways
  3. Query the MCP Gateway for available tools:

    curl -X POST "http://<gateway-ip>/mcp-gateway/mcp/" \
      -H "Authorization: Bearer $TOKEN" \
      -H "Content-Type: application/json" \
      -H "Accept: application/json" \
      -d '{"jsonrpc":"2.0","method":"tools/list","params":{},"id":1}'
  4. Observe only 7 tools returned instead of 12

  5. Check gateway logs for validation errors:

    kubectl logs -n common -l app=mcp-gateway | grep "Validation failed"

🤔 Expected Behavior

Expected: All 12 tools from Grafana MCP server should be registered and exposed:

Loki Query Tools (5) - MISSING:

  • query_loki_logs - Execute LogQL queries
  • list_loki_label_names - List available log labels
  • list_loki_label_values - List values for specific labels
  • query_loki_stats - Get log stream statistics
  • query_loki_patterns - Query detected log patterns

Non-Loki Tools (7) - Working:

  • get_annotations - Fetch Grafana annotations
  • get_annotation_tags - List annotation tags
  • get_datasource_by_name - Get datasource by name
  • get_datasource_by_uid - Get datasource by UID
  • list_datasources - List all datasources
  • search_dashboards - Search dashboards
  • search_folders - Search folders

Actual: Only 7 tools registered. All Loki query tools are rejected during validation.


📓 Logs / Error Output

2026-01-29T19:24:42 - mcpgateway.services.gateway_service - ERROR - Validation failed for tool 'list_loki_label_names': [{'type': 'value_error', 'loc': ('description',), 'msg': "Value error, Description contains unsafe characters: '`'", 'input': 'Lists all available label names (keys) found in logs within a specified Loki datasource and time range. Returns a list of unique label strings (e.g., `["app", "env", "pod"]`). If the time range is not provided, it defaults to the last hour.', 'ctx': {'error': ValueError("Description contains unsafe characters: '`'")}, 'url': 'https://errors.pydantic.dev/2.12/v/value_error'}]

2026-01-29T19:24:42 - mcpgateway.services.gateway_service - ERROR - Validation failed for tool 'list_loki_label_values': [{'type': 'value_error', 'loc': ('description',), 'msg': "Value error, Description contains unsafe characters: '`'", 'input': 'Retrieves all unique values associated with a specific `labelName` within a Loki datasource and time range. Returns a list of string values (e.g., for `labelName="env"`, might return `["prod", "staging", "dev"]`). Useful for discovering filter options. Defaults to the last hour if the time range is omitted.', 'ctx': {'error': ValueError("Description contains unsafe characters: '`'")}, 'url': 'https://errors.pydantic.dev/2.12/v/value_error'}]

2026-01-29T19:24:42 - mcpgateway.services.gateway_service - ERROR - 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'}]

2026-01-29T19:24:42 - mcpgateway.services.gateway_service - ERROR - Validation failed for tool 'query_loki_patterns': [{'type': 'value_error', 'loc': ('description',), 'msg': "Value error, Description contains unsafe characters: '`'", 'input': 'Retrieves detected log patterns from a Loki datasource for a given stream selector and time range. Returns a list of patterns, each containing a pattern string and a total count of occurrences. Patterns help identify common log structures and anomalies. The `logql` parameter must be a stream selector (e.g., `{job="nginx"}`) and does not support line filters or aggregations. Defaults to the last hour if the time range is omitted.', 'ctx': {'error': ValueError("Description contains unsafe characters: '`'")}, 'url': 'https://errors.pydantic.dev/2.12/v/value_error'}]

2026-01-29T19:24:42 - mcpgateway.services.gateway_service - ERROR - Validation failed for tool 'query_loki_stats': [{'type': 'value_error', 'loc': ('description',), 'msg': "Value error, Description contains unsafe characters: '`'", 'input': 'Retrieves statistics about log streams matching a given LogQL *selector* within a Loki datasource and time range. Returns an object containing the count of streams, chunks, entries, and total bytes (e.g., `{"streams": 5, "chunks": 50, "entries": 10000, "bytes": 512000}`). The `logql` parameter **must** be a simple label selector (e.g., `{app="nginx", env="prod"}`) and does not support line filters, parsers, or aggregations. Defaults to the last hour if the time range is omitted.', 'ctx': {'error': ValueError("Description contains unsafe characters: '`'")}, 'url': 'https://errors.pydantic.dev/2.12/v/value_error'}]

2026-01-29T19:24:42 - mcpgateway.services.gateway_service - WARNING - Tool validation completed with 5 error(s). Successfully validated 7 tool(s).
2026-01-29T19:24:42 - mcpgateway.services.gateway_service - INFO - Fetched 7 tools from gateway

Database verification:

$ kubectl exec -n common deployment/database -- psql -U postgres -d mcp \
  -c "SELECT COUNT(*) FROM tools WHERE name LIKE '%loki%';"
 
 total_tools 
-------------
           7
(1 row)

Direct Loki MCP server query shows all 12 tools:

$ curl -X POST "http://<gateway-ip>/loki-mcp/mcp" \
  -d '{"jsonrpc":"2.0","method":"tools/list","params":{},"id":2}' | \
  jq -r '.result.tools[] | .name' | wc -l

12

🧠 Environment Info

Key Value
Version or commit ghcr.io/ibm/mcp-context-forge:1.0.0-BETA-2
Runtime Python 3.11 (inferred from Pydantic v2.12)
Platform / OS Kubernetes/K3s on Ubuntu 22.04
Container Docker (deployed in K3s cluster)
Backend MCP Server grafana/mcp-grafana:latest (v0.9.0)
Backend Transport STREAMABLEHTTP
Gateway Deployment Namespace: common, LoadBalancer: <gateway-ip>

🧩 Additional Context

Root Cause Analysis

The validation error originates from Pydantic model validation in mcpgateway.services.gateway_service. The validator checks for "unsafe characters" in tool descriptions and rejects backticks (`).

Why Grafana MCP uses backticks:
Grafana MCP server uses backticks in descriptions for:

  • Code examples: `{app="foo"}`
  • JSON examples: `{"streams": 5}`
  • Array examples: `["app", "env"]`
  • Parameter references: `labelName`

This is standard Markdown/documentation formatting.

Impact

Critical: All primary Loki functionality is unavailable through the gateway:

  • ❌ Cannot query logs
  • ❌ Cannot discover labels
  • ❌ Cannot get stream statistics
  • ❌ Cannot analyze log patterns
  • ✅ Can only list datasources and search dashboards (limited utility)

Workarounds

Temporary workaround: Connect directly to Loki MCP server (bypasses gateway):

{
  "servers": {
    "loki-direct": {
      "type": "http",
      "url": "http://<gateway-ip>/loki-mcp/mcp"
    }
  }
}

This works but defeats the purpose of using the gateway for aggregation, authentication, and observability.

Proposed Solutions

Option 1: Relax validation to allow backticks (RECOMMENDED)

  • Backticks are safe in descriptions (not executed code)
  • Standard in documentation and Markdown
  • Matches MCP specification (no restriction on description content)

Option 2: Add configuration flag to disable strict validation

GATEWAY_STRICT_TOOL_VALIDATION: "false"

Option 3: Sanitize descriptions during registration

  • Strip or escape backticks before validation
  • Preserves security while allowing tool registration
  • May reduce description clarity

Related Documentation

Testing Commands

Verify Loki MCP server tools directly:

SESSION_ID=$(curl -s -X POST "http://<gateway-ip>/loki-mcp/mcp" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}},"id":1}' \
  -D - | grep -i "mcp-session-id" | cut -d' ' -f2 | tr -d '\r\n')

curl -s -X POST "http://<gateway-ip>/loki-mcp/mcp" \
  -H "Mcp-Session-Id: $SESSION_ID" \
  -d '{"jsonrpc":"2.0","method":"tools/list","params":{},"id":2}' | \
  jq -r '.result.tools[] | .name' | sort

Expected output: 12 tools including query_loki_logs, list_loki_label_names, etc.

Verify gateway-exposed tools:

SESSION_ID=$(curl -s -X POST "http://<gateway-ip>/mcp-gateway/mcp/" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Accept: application/json" \
  -d '{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}},"id":1}' \
  -D - | grep -i "mcp-session-id" | cut -d' ' -f2 | tr -d '\r')

curl -s -X POST "http://<gateway-ip>/mcp-gateway/mcp/" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Accept: application/json" \
  -H "Mcp-Session-Id: $SESSION_ID" \
  -d '{"jsonrpc":"2.0","method":"tools/list","params":{},"id":2}' | \
  jq -r '.result.tools[] | .name' | sort

Current output: 7 tools (missing all query_loki_* and list_loki_* tools)

Metadata

Metadata

Assignees

Labels

SHOULDP2: Important but not vital; high-value items that are not crucial for the immediate releasebugSomething isn't workinggood first issueGood for newcomerspythonPython / backend development (FastAPI)

Type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions