# Reported issues for OTC Pricing MCP

Pod holds 16 of 36 problems reported by people outside the maintainer team. Issues filed by the project's own owners, members and collaborators are excluded entirely — a maintainer's release checklist is not a warning to a prospective user.

Back to [OTC Pricing MCP](/mcp/otc-pricing-mcp).

## Most discussed

### eu-ch2 (Swiss OTC) coverage limitation: upstream Calculator API doesn't expose ECS/EVS/RDS/NAT/ELB/AOM — needs doc + optional patch hook

## Summary

The MCP correctly proxies upstream data, but the **t-systems Price Calculator API** (`https://calculator.otc-service.com/en/open-telekom-price-api/`) exposes **only a subset of services for `eu-ch2` (Swiss Open Telekom Cloud)**. Several core IaaS services (ECS, EVS, RDS, NAT, ELB, AOM) return `stats.count = 0` from the upstream for `filterBy[region]=eu-ch2` — even though those services are sold in eu-ch2 according to the public T-Systems CH product pages and confirmed by users with i

[Read the thread](https://github.com/seaser0/otc-pricing-mcp/issues/50) · 2026-05-11 · closed · 4 comments

### swiss-otc / eu-ch2 catalog unreachable: productType hardcoded to OTC; no SOTC variant accepted by upstream

## Bug: swiss-otc / eu-ch2 catalog unreachable via MCP (productType hardcoded to `OTC`)

### Symptom
Queries against the MCP for `region=eu-ch2` (Swiss OTC, CHF-priced subset) return empty results for most services. Example:

```python
query_pricing(['evs'], region='eu-ch2')  # → 0 items
query_pricing(['ecs'], region='eu-ch2')  # → 0 items
```

Discovery.py:10-12 acknowledges the gap:
> `eu-ch2 (Swiss OTC, CHF) only carries a subset of services (obs, kms, lts, hss, ito, apig, etc.)`

…but in pra

[Read the thread](https://github.com/seaser0/otc-pricing-mcp/issues/59) · 2026-05-24 · closed · 1 comment

### security.yml pip-audit blocks every version bump (--strict + editable local project)

**Severity: MEDIUM** — CI workflow blocker

## Symptom

After bumping the project version (e.g. 0.1.8 → 0.1.9 in PR #46) the \`Dependency Audit (pip-audit)\` job in \`security.yml\` fails with:

\`\`\`
ERROR:pip_audit._cli:otc-pricing-mcp: Dependency not found on PyPI and could not be audited: otc-pricing-mcp (0.1.9)
\`\`\`

The same audit in \`ci.yml\`'s \`Security - Dependency Audit (pip-audit)\` job passes for the same commit. \`security.yml\`'s \`Security Checks Summary\` aggregates the fail

[Read the thread](https://github.com/seaser0/otc-pricing-mcp/issues/47) · 2026-05-09 · closed · 1 comment

### get_otc_doc_section: section="" silently treated as 'no filter'

**Severity: LOW** — falsy-empty anti-pattern

## Reproduce

```
get_otc_doc_section(url=<valid_page>, section="")
→ all sections returned (same as section=None)
```

`tools/docs.py:233`: `if section:` is falsy on `""`, so an empty string is silently equivalent to omitting the parameter. A caller that builds the call dynamically and accidentally passes `section=""` won't see a "no match" — they'll get the entire page.

## Expected

Either reject empty string (`ValueError`) or document the equival

[Read the thread](https://github.com/seaser0/otc-pricing-mcp/issues/45) · 2026-05-09 · closed · 1 comment

### get_otc_doc_section: 'page exists, section missing' is indistinguishable from 'page not found'

**Severity: MEDIUM** — UX/correctness

## Reproduce

```
# Page does not exist
get_otc_doc_section(url="https://docs.otc.t-systems.com/nonexistent/page.html")
→ {matched: false, sections: [], title: "", service: "", ...}

# Page exists, section filter does not match
get_otc_doc_section(
    url="https://docs.otc.t-systems.com/elastic-cloud-server/umn/service_overview/permissions.html",
    section="this-section-does-not-exist"
)
→ {matched: false, sections: [], title: "", service: "", ...}
```

[Read the thread](https://github.com/seaser0/otc-pricing-mcp/issues/44) · 2026-05-09 · closed · 1 comment

### search_otc_docs: unknown 'service' filter silently returns []

**Severity: MEDIUM** — silent-empty anti-pattern (sister of #6, #35)

## Reproduce

```
search_otc_docs(query="VPC", service="nonexistent-service-xyz")
→ {hits: [], total_hits: 0, isError: false}
```

A typo'd service name returns empty results indistinguishable from a service that exists but has no matches.

## Expected

Validate `service` against the set of services actually indexed (already discoverable: `SELECT DISTINCT service FROM docs`). Unknown service → `ValueError` listing valid servic

[Read the thread](https://github.com/seaser0/otc-pricing-mcp/issues/43) · 2026-05-09 · closed · 1 comment

### search_otc_docs: top_k silently clamped (0/-5 → 1, 999 → 50, no warning)

**Severity: MEDIUM** — silent-clamp anti-pattern (sister of #33)

## Reproduce

```
search_otc_docs(query="VPC", top_k=0)   → returns 1 hit, isError=false
search_otc_docs(query="VPC", top_k=-5)  → returns 1 hit, isError=false
search_otc_docs(query="VPC", top_k=999) → returns 50 hits, isError=false
```

## Root cause

`tools/docs.py:138`: `top_k = max(1, min(50, int(top_k)))` clamps without surfacing the change. Caller has no signal that their requested cap was changed.

## Expected

- `top_k <= 

[Read the thread](https://github.com/seaser0/otc-pricing-mcp/issues/42) · 2026-05-09 · closed · 1 comment

### search_otc_docs: empty / whitespace-only query silently returns 0 hits

**Severity: HIGH** — silent-zero anti-pattern (same family as #4, #6, #31, #33)

## Reproduce

```
search_otc_docs(query="")    → {hits: [], total_hits: 0, isError: false}
search_otc_docs(query="   ") → {hits: [], total_hits: 0, isError: false}
```

A caller (LLM or human) typoing into an empty string gets no signal that the query was rejected.

## Root cause

`tools/docs.py:_escape_match` returns the empty FTS5 phrase `'""'` for empty input; the FTS5 syntax-error path then collapses to `rows = 

[Read the thread](https://github.com/seaser0/otc-pricing-mcp/issues/41) · 2026-05-09 · closed · 1 comment

## Most recent

### [Security Alert] Vulnerabilities detected in nightly scan

⚠️ **Security vulnerabilities detected in the nightly security scan**

## Details
- **Workflow Run**: [View Results](https://github.com/seaser0/otc-pricing-mcp/actions/runs/33372719589)
- **Branch**: `main`
- **Triggered**: Nightly security scan
- **Time**: 2026-08-31T08:24:53.992Z

## Failed Checks
- ❌ Container Scan (Trivy)

Please review the [workflow results](https://github.com/seaser0/otc-pricing-mcp/actions/runs/33372719589) for detailed vulnerability information.

---
*This issue was auto

[Read the thread](https://github.com/seaser0/otc-pricing-mcp/issues/77) · 2026-08-17 · open · external user · 0 comments

### query_pricing misses memory-optimized ECS (m4/m7n/m9) — v2 API / serviceName=memo not supported

## Summary
`query_pricing(services=['ecs'], region='eu-de')` returns only **general-purpose** flavors (s2/s3/s7n/s9, RAM ratios .1/.2/.4). **Memory-optimized ECS (m4/m7n/m9, ratio .8) is missing** — it lives in a separate API endpoint that the MCP does not query.

## Root cause
The MCP queries the **v1** API (`/en/open-telekom-price-api/`) with `serviceName=ecs`. Memory-optimized flavors are only exposed via the **v2** API (`/en/open-telekom-price-api/v2/`) with **`serviceName=memo`**.

Direct e

[Read the thread](https://github.com/seaser0/otc-pricing-mcp/issues/71) · 2026-07-14 · closed · 0 comments

### [Security Alert] Vulnerabilities detected in nightly scan

⚠️ **Security vulnerabilities detected in the nightly security scan**

## Details
- **Workflow Run**: [View Results](https://github.com/seaser0/otc-pricing-mcp/actions/runs/30880273736)
- **Branch**: `main`
- **Triggered**: Nightly security scan
- **Time**: 2026-08-04T05:19:08.084Z

## Failed Checks
- ❌ Dependency Audit (pip-audit)
- ❌ Container Scan (Trivy)

Please review the [workflow results](https://github.com/seaser0/otc-pricing-mcp/actions/runs/30880273736) for detailed vulnerability infor

[Read the thread](https://github.com/seaser0/otc-pricing-mcp/issues/57) · 2026-05-17 · closed · external user · 0 comments

### Ghost eu-ch2 rows in default catalog: misreport CHF prices as EUR

## Problem

The default OTC price-calculator catalog (`client=1`, public T-Cloud) contains 75 entries whose `region == "eu-ch2"` but `currency == "EUR"` — these are NOT real Swiss prices. The actual Swiss CHF prices live in `client=2` (resolved correctly by #50 / #51 when the caller supplies `region="eu-ch2"`).

Consequence: a caller that queries a service without a region filter today gets a silently misleading mix:

```python
# After PR #51, this works correctly (uses client=2):
query_pricing(

[Read the thread](https://github.com/seaser0/otc-pricing-mcp/issues/52) · 2026-05-12 · closed · 0 comments

### find_compute_flavor: response truncation when broad filters return many flavors + tighten tool description

## Summary
Broad `find_compute_flavor` queries (e.g. "GPU=true, region=eu-de") return so many full-detail flavor entries that the response exceeds the MCP tool-output limit on the consumer side. The result has to be greppe'd from the raw payload instead of read directly.

## Reproduction
Asking Claude to "find OTC ECS flavors with a single A100 GPU" caused `find_compute_flavor` to return enough flavors that the assistant logged:

> OTC-Antwort war zu groß — gegrept aus der Datei.

This happened 

[Read the thread](https://github.com/seaser0/otc-pricing-mcp/issues/49) · 2026-05-10 · closed · 0 comments

### get_otc_doc_section: URL LIKE-prefix matches ALL sections on empty/wildcard input, returns 3.5MB Frankenstein response

**Severity: HIGH** — correctness + token-DoS + LIKE-wildcard injection

## Reproduce (live MCP, 2026-05-09)

```
get_otc_doc_section(url="")           → sections=4714, 3.5MB, isError=false
get_otc_doc_section(url="%")          → sections=4714, 3.5MB
get_otc_doc_section(url="https://")   → sections=4714, 3.5MB
get_otc_doc_section(url="https://docs.otc.t-systems.com/_______________") → sections=4714, 3.5MB
```

## Root cause

`src/otc_pricing_mcp/tools/docs.py:231-232`:

```python
sql_parts = ["ur

[Read the thread](https://github.com/seaser0/otc-pricing-mcp/issues/40) · 2026-05-09 · closed · 0 comments

### get_service_schema returns the same generic catalog schema for every service

## Observation

Calling `get_service_schema` for `ecs`, `evs`, `obs` (and presumably others) returns **identical** column metadata — the upstream OTC API serves the union of all possible columns, not a per-service projection.

```
get_service_schema(ecs).columns == get_service_schema(evs).columns == get_service_schema(obs).columns
== {"id": "ID", "productId": "Service ID", ..., "vCpu": "vCpu", "ram": "RAM",
    "storageType": "Storage type", "storageVolume": "Storage volume",
    "R12": "Reserve

[Read the thread](https://github.com/seaser0/otc-pricing-mcp/issues/37) · 2026-05-08 · closed · 1 comment

### estimate_monthly_cost accepts negative quantity, returns negative totals

## Symptom

```
tools/call estimate_monthly_cost {"items":[{"id":"OTC_S3M1_LI","quantity":-1}]}

→ total_payg: -37.35775
  items[0].quantity: -1.0
  items[0].payg: -37.35775
isError: false
```

Negative quantity is accepted and produces a negative-cost "estimate". Same shape with very large quantities (`999999` → `~37 M EUR`, no upper sanity bound).

## Why it matters

LLMs assemble these calls from natural language and sometimes mis-extract a number. Reporting "-€37" for a workload makes a budg

[Read the thread](https://github.com/seaser0/otc-pricing-mcp/issues/36) · 2026-05-08 · closed · 1 comment

The remaining reports are on [the project's issue tracker](https://github.com/seaser0/otc-pricing-mcp/issues).
