Skip to content

v1.28

Choose a tag to compare

@hermanekt hermanekt released this 04 May 17:23
70a6188

v1.28 - 2026-05-04

OAuth 2.1 release. Three issues land together (#36, #38, #39) plus a full audit-trail of UI polish and security hardening discovered along the way. The headline change is the embedded OAuth 2.1 authorization server: ChatGPT custom apps, Claude Desktop remote connectors, MCP Inspector, and any MCP 2025-11-25 compliant client can now negotiate auth against a Zabbix MCP deployment without an external IdP, without a hardcoded bearer, and without operators learning OAuth library internals.

Added

  • Active-only problem filter (issue #39, original concept by @fenbays). Two doors into the same data:
    • problem_get(monitored=True) - new boolean parameter on the existing tool, matches the semantic of host_get/item_get's monitored flag. When set, problems whose trigger has status != 0 or whose host has status != 0 are dropped client-side after the API fetch (Zabbix has no native monitored flag on problem.get). Default false keeps backwards-compat: an unfiltered call still returns every problem on file.
    • problem_active_get - new extension tool that pre-bakes the right defaults for an LLM that just wants "what is wrong right now": severities=[2,3,4,5] (Warning and above), the monitored filter from above, and per-row enrichment with host, hostid, time (UTC, human-readable like "2026-04-28 17:30 UTC"), and severity_label. Returns {"problems": [...], "count": N, "filtered_out": M} so callers can tell how much got dropped vs. how much got kept. Tighter prompt budget than problem_get because the LLM does not have to know about disabled-trigger noise or numeric severity codes.
  • The monitored flag on problem_get and the problem_active_get enrichment share a single helper (_filter_active_problems) so the filter logic stays in one place.
  • Per-token tools/list filtering (issue #38, original concept by @fenbays). Until now, [tokens.X].scopes only gated tool invocation - the catalog returned by tools/list was always the full 232-tool surface, regardless of which token connected. That cost two real things: an LLM's initial handshake had to pay schemas for every admin / users / extensions tool it could not call (3 KB vs. 25 KB token cost on Claude Desktop / ChatGPT custom GPTs reported in #13), and the model would happily try host_create on a monitoring-only token, eating a round-trip to a 403. v1.28 wraps the FastMCP tools/list handler with _filter_tools_by_token: it reads the calling token's scopes from the existing current_token_info contextvar (no new auth surface), expands group names via _expand_tool_groups, and prunes the response to what the token may actually call. Tokens with scopes = ["*"] (or unset) keep the full list, so single-token / no-auth setups behave exactly as before. Read-only tokens additionally lose every *_create / *_update / *_delete / *_mass* tool plus action_prepare, action_confirm, and zabbix_raw_api_call from the catalog - the auto-detected write set is built once at server boot from MethodDef.read_only plus a small hand-rolled extension list. Field test on production: a monitoring-only read-only token's tools/list shrinks from 232 entries to 25.
  • problem_active_get registered in the extensions tool group AND the monitoring group, so monitoring-only tokens still see it after the per-token filter applies.
  • Embedded OAuth 2.1 authorization server (issue #36). New [oauth] enabled = true boots an in-process AS that ChatGPT custom apps, Claude Desktop remote connectors, and any MCP 2025-11-25 client can negotiate against - no external IdP, no shared OAuth provider needed. Implements the full discovery surface (RFC 8414 /.well-known/oauth-authorization-server, RFC 9728 /.well-known/oauth-protected-resource, WWW-Authenticate: Bearer ... resource_metadata="..." on 401), dynamic client registration (RFC 7591 /register), authorization code + PKCE S256, refresh-token rotation, and revocation (RFC 7009). Audience binding (RFC 8707) ties every issued token to [server].public_url so a leaked token cannot be replayed against a different MCP deployment.
    • Login UI reuses the existing admin-portal users ([admin.users.*], scrypt-hashed). Operators do not maintain a second identity store; if the admin portal already lets tomas in, that is the username they type into ChatGPT's "Advanced OAuth settings" sign-in dialog. The login + consent screen mirrors the admin portal's login surface (logo, theme switcher, light/dark variables, footer) so the flow does not feel like a third-party page bolted on top.
    • Authorization codes / access tokens / refresh tokens are in-memory (10-min / 1-h / 30-day TTLs). Registered clients persist in [oauth_clients.<client_id>] config sections so they survive restart; codes and tokens vanish on restart so any in-flight session re-authorizes via the client's auto-refresh logic.
    • Legacy bearer-token mode keeps working alongside OAuth. A client that already authenticates via [tokens.X] does not need to migrate; the OAuth provider's load_access_token falls back to the existing TokenStore when the bearer is not an OAuth-issued credential.
    • Full setup, security checklist, and ChatGPT / Claude Desktop integration walkthrough in docs/OAUTH.md.