AGENTS.md
+62 −58
https://raw.githubusercontent.com/christianclaudio/mcp-server-sigma/HEAD/AGENTS.md
− This is `mcp-server-sigma` — an enterprise Python Model Context Protocol (MCP) server exposing 155 tools by default (157 with bulk-destructive operations enabled) covering the entire REST API surface (v2 and v3alpha) for **Sigma Computing**.− ## 🏗️ Architecture Blueprint− ```− mcp-server-sigma/− ├── src/sigma_mcp/− │ ├── __init__.py # Package version (__version__) and public exports− │ ├── server.py # FastMCP server instance, 155+ @mcp.tool() handlers, prompts, resources− │ ├── client.py # Async HTTP client (httpx.AsyncClient, retries, jitter, RFC 8693 token exchange)− │ ├── errors.py # Structured API exceptions and automatic secret redaction− │ └── webhooks.py # Webhook HMAC signature verification and event buffer− ├── scripts/− │ ├── check_tool_contract.py # AST/reflection contract testing total tool & annotation counts− │ ├── check_openapi_drift.py # AST visitor checking client methods against upstream OpenAPI specs− │ └── write_ops_check.py # Audit verifying all write operations have confirm parameter− ├── tests/− │ ├── test_client_internals.py # Unit tests for HTTP client, retries, headers, and error handling− │ ├── test_server_*.py # Tests for tool execution, parameter validation, and confirmation gating− │ ├── test_security_hardening.py# Tenant allowlist, token exchange, and credential sanitization tests− │ ├── test_webhooks.py # HMAC signature and replay protection tests− │ └── test_protocol.py # Wire-level stdio & stateless streamable HTTP protocol verification− ├── .github/workflows/− │ ├── ci.yml # Multi-job matrix: lint, py3.10-3.13 tests, contracts, CodeQL, docker build− │ ├── release.yml # Automated release on v* tags: wheels, sdist, CycloneDX SBOM, GHCR docker− │ └── drift-monitor.yml # Scheduled upstream schema drift check− ├── Dockerfile # Multi-stage container build running as non-root USER mcp− ├── server.json # MCP Registry catalog metadata (runtimeHint: uvx, stdio transport)− ├── pyproject.toml # Packaging metadata, entrypoint CLI, dependency pinning− ├── AGENTS.md # Agent guidance map, gotchas, and conventions (this file)− └── README.md # User-facing installation, quickstart, and tool index− ```− - URL path parameters **must** be safely quoted using `_encode_segment()` preserving colons on custom methods (e.g. `{id}:materialize`) while eliminating path traversal vulnerabilities (`..` $\rightarrow$ `%2E%2E`).− - Call `await self._request("METHOD", path, params=..., json=...)`.− ### 2. Tool Handler (`server.py`)− - Register the tool with `@mcp.tool()` and wrap with the server decorator (`@sigma_tool`).− - Destructive operations (`POST`, `PUT`, `PATCH`, `DELETE` mutating state) **must** accept `confirm: bool = False`.− - Apply MCP `ToolAnnotations` post-registration via `mcp._tool_manager._tools`:− - `readOnlyHint`: `True` for inspection/GET; `False` for mutations.− - `idempotentHint`: `True` for GET, PUT, idempotent operations; `False` for creations.− - Support `READONLY` mode (`SIGMA_MCP_READONLY=1` or `--readonly`) to filter out mutating tools.− - Support bulk protection (`SIGMA_MCP_ALLOW_BULK_DESTRUCTIVE=1`) for mass-destructive tools (`sigma_bulk_deactivate_users`, `sigma_bulk_remove_team_members`).+ ---+ vcs:+ system: github+ remote: https://github.com/christianclaudio/mcp-server-sigma+ owner: christianclaudio+ repo: mcp-server-sigma+ default_branch: main+ branch_policy: pr_only+ merge_method: squash+ delete_branch_on_merge: true+ ---+ This is `mcp-server-sigma` — an enterprise Python Model Context Protocol (MCP) server for **Sigma Computing**, built on its public REST API (v2 and v3alpha); `scripts/check_openapi_drift.py` lists the spec endpoints the client does not cover. Bulk-destructive tools are listed in `full` and refused at call time unless enabled; the expected per-profile tool counts live in `scripts/check_tool_contract.py`.+ ## 🏗️ Key Paths+ - `src/sigma_mcp/server.py` — root gateway: `create_server` mounts the domain sub-servers (`workbooks`, `datasets`, `elements`, `workspace`, `admin`) with matching namespaces, then applies the job allowlist, the read-only filter, and (on `full` only) Tool Search or Code Mode; prompts, resources.+ - `src/sigma_mcp/profiles.py` — `PROFILES` (`full`, `readonly`, and the job profiles `analyst`, `author`, `modeler`, `embed`, `access_admin`), their tool allowlists, `FULL_ONLY_TOOLS`, `BULK_DESTRUCTIVE_TOOLS`, and the `readOnlyHint` filter.+ - `src/sigma_mcp/tools/<domain>.py` — domain sub-servers (`admin`, `datasets`, `elements`, `workbooks`, `workspace`); `tools/common.py` holds the `ANNOTATION_*` constants and shared helpers.+ - `src/sigma_mcp/client.py` — async HTTP client (`SigmaClient`, `_encode_segment()`, RFC 8693 token exchange). `errors.py` — exceptions and secret redaction. `webhooks.py` — HMAC verification. `middleware.py` — read-only gate (`readOnlyHint` only, unwraps the Tool Search `call_tool` proxy) and the admin bulk-destructive gate. `config.py` — settings.+ - `scripts/check_tool_contract.py` — source of truth for expected tool counts and annotations. `README.md` and three test files repeat some of these counts (`SIGNED_OFF` in `tests/test_profiles.py`, the 172 in `tests/test_unit.py` and `tests/test_enterprise_assertion.py`), so change them together; do not add new copies.+ - `scripts/check_openapi_drift.py`, `scripts/write_ops_check.py` (live create-and-teardown against a Sigma org; needs `SIGMA_CLIENT_ID`, `SIGMA_CLIENT_SECRET`, and `SIGMA_API_BASE_URL`), `scripts/check_conformance.sh` + `conformance-baseline.yml`.+ - `scripts/release_notes.py` — release body from squash commits since the previous `v*` tag. `scripts/check_version.py` — runs after the build and reads the version from the single wheel in `dist/` (the file that ships, as release.yml's tag check does); fails on `0.0.0` (no git metadata) or `0.0.1.devN` (no reachable tag, a shallow checkout).+ - `tests/` — unit tests are offline; live network tests live in `tests/test_e2e_live.py` (marked `pytest.mark.e2e`, deselected by default pytest `addopts` `-m 'not e2e'`, run with `-m e2e`). That test sets no skip and no env check; tool calls use `get_client`, which requires `SIGMA_CLIENT_ID` and `SIGMA_CLIENT_SECRET`. The unmarked `test_dispatch_tool_call_offline` in that file stays in the default suite. `tests/test_integration_live.py` skips unless `SIGMA_LIVE_TESTS=1` and `SIGMA_CLIENT_ID` ar+ - `.github/workflows/` — `ci.yml`, `release.yml` (on a `v*` tag: build with full history, check the wheel version matches the tag, build the release notes, publish to PyPI, create the GitHub Release from `scripts/release_notes.py`, then push the Docker image only after the publish job succeeds, then stamp the tag version into `server.json` and publish to the MCP Registry in a last `registry` job that needs the Docker job), `sigma-drift-monitor.yml`, `dependabot-automerge.yml` (squash auto-merge + - `server.json` (MCP Registry metadata), `Dockerfile`, `pyproject.toml`.+ - URL path parameters are encoded per segment by `_encode_segment()` inside `_request()`, preserving colons on custom methods (e.g. `{id}:materialize`) while eliminating path traversal vulnerabilities (`..` $\rightarrow$ `%2E%2E`). Pass raw IDs in the path; do not pre-quote them, or they are encoded twice.+ - Call `await self._request("METHOD", path, params=..., json_data=...)`.+ ### 2. Tool Handler (`tools/<domain>.py`)+ - Register the tool on its domain sub-server with `@<domain>_server.tool(name=..., annotations=...)` and wrap with `@sigma_tool` (e.g. `tools/workbooks.py`). The root gateway in `server.py` mounts the domain with its namespace.+ - Destructive tools (delete, archive, deactivate, and bulk removal) **must** accept `confirm: bool = False`. Not every `POST`, `PUT`, or `PATCH` does (for example `workbooks_create_workbook` has no `confirm`).+ - Pass MCP `ToolAnnotations` at registration with the `ANNOTATION_*` constants from `tools/common.py`:+ - `readOnlyHint`: `True` for inspection/GET; `False` for mutations. Every tool sets it explicitly; the read-only gate reads nothing else (a missing hint is treated as a write).+ - `idempotentHint`: among the constants, `True` only on `ANNOTATION_IDEMPOTENT`; `ANNOTATION_READ_ONLY`, `ANNOTATION_WRITE_SAFE` and `ANNOTATION_DESTRUCTIVE` leave it unset. The Tool Search and Code Mode discovery tools get `READ_ONLY_ANNOTATIONS` from `profiles.py` (`readOnlyHint` and `idempotentHint` `True`, `openWorldHint` `False`).+ - Read-only mode (`SIGMA_MCP_READONLY=1` or profile `readonly`) keeps only tools annotated `readOnlyHint=True` and refuses every other call, directly or through `call_tool`, with a `SafetyViolationError` (a FastMCP `ToolError`, so `isError: true`).+ - Bulk protection: `admin_bulk_deactivate_members` and `admin_bulk_remove_team_members` are listed in `full` and refused at call time unless `SIGMA_MCP_ALLOW_BULK_DESTRUCTIVE=1`.+ - Profiles (`SIGMA_MCP_PROFILE` or `--profile`): `full`, `readonly`, `analyst`, `author`, `modeler`, `embed`, `access_admin`. A new tool goes into the job profiles in `profiles.py` or into `FULL_ONLY_TOOLS`; unknown names fail at build. Tool Search and Code Mode attach on `full` only and never together.+ - **Zero live network calls in the default suite.** Tests must run 100% offline in CI. Opt-in live modules are `tests/test_e2e_live.py` (`-m e2e`) and `tests/test_integration_live.py` (`SIGMA_LIVE_TESTS=1` plus `SIGMA_CLIENT_ID`).+ - Update expected tool counts (per profile) in `scripts/check_tool_contract.py`, the `README.md` tables, and the copies in `tests/test_profiles.py` (`SIGNED_OFF`), `tests/test_unit.py` and `tests/test_enterprise_assertion.py`. A full-only tool also goes in `EXPECTED_FULL_ONLY` in `scripts/check_tool_contract.py`.+ - Ensure test statement coverage remains at **100.0%** (`--cov-fail-under=100`). Branch coverage is not enabled.+ - Delete, archive, deactivate, and bulk-removal tools must accept `confirm: bool = False`. If `False`, do not execute the side-effect (`_invalid_request` refusal, or a dry-run preview on `admin_bulk_deactivate_members`).+ - Error messages, logs, and tracebacks must pass through regex redaction (`_redact_secrets`) stripping Bearer tokens, client secrets, access tokens, subject tokens, raw JWTs, and `ghs_` tokens.+ - Mass operations require `SIGMA_MCP_ALLOW_BULK_DESTRUCTIVE=1`. `admin_bulk_deactivate_members` defaults to `dry_run=True` and caps at 10 active members. `admin_bulk_remove_team_members` has no `dry_run` parameter, requires `confirm=True`, and caps at 50 emails.
Showing the first 40 of each.