mcp-server-sigma 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mcp_server_sigma-1.0.0/.coderabbit.yaml +35 -0
- mcp_server_sigma-1.0.0/.dockerignore +22 -0
- mcp_server_sigma-1.0.0/.env.example +4 -0
- mcp_server_sigma-1.0.0/.github/CODEOWNERS +2 -0
- mcp_server_sigma-1.0.0/.github/ISSUE_TEMPLATE/bug_report.md +54 -0
- mcp_server_sigma-1.0.0/.github/ISSUE_TEMPLATE/feature_request.md +31 -0
- mcp_server_sigma-1.0.0/.github/PULL_REQUEST_TEMPLATE.md +19 -0
- mcp_server_sigma-1.0.0/.github/dependabot.yml +22 -0
- mcp_server_sigma-1.0.0/.github/workflows/ci.yml +173 -0
- mcp_server_sigma-1.0.0/.github/workflows/dependabot-automerge.yml +24 -0
- mcp_server_sigma-1.0.0/.github/workflows/release.yml +110 -0
- mcp_server_sigma-1.0.0/.gitignore +17 -0
- mcp_server_sigma-1.0.0/AGENTS.md +75 -0
- mcp_server_sigma-1.0.0/CHANGELOG.md +59 -0
- mcp_server_sigma-1.0.0/CODE_OF_CONDUCT.md +43 -0
- mcp_server_sigma-1.0.0/CONTRIBUTING.md +160 -0
- mcp_server_sigma-1.0.0/Dockerfile +33 -0
- mcp_server_sigma-1.0.0/LICENSE +21 -0
- mcp_server_sigma-1.0.0/PKG-INFO +403 -0
- mcp_server_sigma-1.0.0/README.md +365 -0
- mcp_server_sigma-1.0.0/SECURITY.md +64 -0
- mcp_server_sigma-1.0.0/TESTING.md +244 -0
- mcp_server_sigma-1.0.0/docs/architecture.md +118 -0
- mcp_server_sigma-1.0.0/docs/errors.md +167 -0
- mcp_server_sigma-1.0.0/docs/formulas.md +9 -0
- mcp_server_sigma-1.0.0/docs/multi-tenant.md +149 -0
- mcp_server_sigma-1.0.0/docs/recipes.md +41 -0
- mcp_server_sigma-1.0.0/examples/bulk_member_ops.py +107 -0
- mcp_server_sigma-1.0.0/examples/deploy_template.py +82 -0
- mcp_server_sigma-1.0.0/examples/export_and_download.py +59 -0
- mcp_server_sigma-1.0.0/examples/multi_tenant_sync.py +87 -0
- mcp_server_sigma-1.0.0/examples/onboard_team.py +106 -0
- mcp_server_sigma-1.0.0/examples/promote_workbook.py +111 -0
- mcp_server_sigma-1.0.0/pyproject.toml +81 -0
- mcp_server_sigma-1.0.0/scripts/check_openapi_drift.py +156 -0
- mcp_server_sigma-1.0.0/scripts/check_tool_contract.py +218 -0
- mcp_server_sigma-1.0.0/scripts/drift_allowlist.txt +6 -0
- mcp_server_sigma-1.0.0/scripts/write_ops_check.py +250 -0
- mcp_server_sigma-1.0.0/server.json +21 -0
- mcp_server_sigma-1.0.0/skills/sigma-mcp/SKILL.md +78 -0
- mcp_server_sigma-1.0.0/src/sigma_mcp/__init__.py +3 -0
- mcp_server_sigma-1.0.0/src/sigma_mcp/client.py +1130 -0
- mcp_server_sigma-1.0.0/src/sigma_mcp/errors.py +46 -0
- mcp_server_sigma-1.0.0/src/sigma_mcp/py.typed +1 -0
- mcp_server_sigma-1.0.0/src/sigma_mcp/reference/formulas.md +100 -0
- mcp_server_sigma-1.0.0/src/sigma_mcp/reference/sigma_api_index.txt +1052 -0
- mcp_server_sigma-1.0.0/src/sigma_mcp/server.py +2808 -0
- mcp_server_sigma-1.0.0/src/sigma_mcp/webhooks.py +100 -0
- mcp_server_sigma-1.0.0/tests/smoke_test.py +266 -0
- mcp_server_sigma-1.0.0/tests/test_additional_coverage.py +61 -0
- mcp_server_sigma-1.0.0/tests/test_all_tools_coverage.py +99 -0
- mcp_server_sigma-1.0.0/tests/test_client_internals.py +349 -0
- mcp_server_sigma-1.0.0/tests/test_enterprise_assertion.py +67 -0
- mcp_server_sigma-1.0.0/tests/test_full_100_coverage.py +215 -0
- mcp_server_sigma-1.0.0/tests/test_integration_live.py +428 -0
- mcp_server_sigma-1.0.0/tests/test_mcp_features.py +78 -0
- mcp_server_sigma-1.0.0/tests/test_no_transport_bypass.py +102 -0
- mcp_server_sigma-1.0.0/tests/test_pagination.py +144 -0
- mcp_server_sigma-1.0.0/tests/test_polling.py +133 -0
- mcp_server_sigma-1.0.0/tests/test_recipe_error_coverage.py +117 -0
- mcp_server_sigma-1.0.0/tests/test_safety.py +292 -0
- mcp_server_sigma-1.0.0/tests/test_security_hardening.py +71 -0
- mcp_server_sigma-1.0.0/tests/test_server_100_percent_final.py +184 -0
- mcp_server_sigma-1.0.0/tests/test_server_missing_lines.py +86 -0
- mcp_server_sigma-1.0.0/tests/test_server_uncovered_branches.py +233 -0
- mcp_server_sigma-1.0.0/tests/test_tools_mocked.py +261 -0
- mcp_server_sigma-1.0.0/tests/test_unit.py +472 -0
- mcp_server_sigma-1.0.0/tests/test_webhooks.py +235 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
language: "en-US"
|
|
2
|
+
|
|
3
|
+
reviews:
|
|
4
|
+
# 'chill' provides balanced feedback without nitpicky noise ('quiet' = critical only)
|
|
5
|
+
profile: "chill"
|
|
6
|
+
|
|
7
|
+
# Auto-Review Settings
|
|
8
|
+
auto_review:
|
|
9
|
+
enabled: true
|
|
10
|
+
drafts: false
|
|
11
|
+
# Skip automatic reviews when PR title contains 'dependabot' or 'bump'
|
|
12
|
+
ignore_title_keywords:
|
|
13
|
+
- "dependabot"
|
|
14
|
+
- "bump"
|
|
15
|
+
|
|
16
|
+
# Path Filters: Exclude lockfiles, virtualenvs, and log files from review
|
|
17
|
+
path_filters:
|
|
18
|
+
- "!poetry.lock"
|
|
19
|
+
- "!package-lock.json"
|
|
20
|
+
- "!.venv/**"
|
|
21
|
+
- "!**.log"
|
|
22
|
+
|
|
23
|
+
# Domain Path Instructions: Enforce project-specific architectural rules automatically
|
|
24
|
+
path_instructions:
|
|
25
|
+
- path: "src/sigma_mcp/server.py"
|
|
26
|
+
instructions: "Ensure all newly added tools declare read_only_hint, destructive_hint, or idempotent_hint annotations, and enforce explicit confirm=True parameters on all delete, archive, deactivate, and bulk-removal endpoints."
|
|
27
|
+
- path: "src/sigma_mcp/client.py"
|
|
28
|
+
instructions: "Verify HTTP 429 retry backoff includes jitter and preserves Retry-After minimum delay."
|
|
29
|
+
|
|
30
|
+
# Enables '🤖 Prompt for AI Agents' blocks in review comments for one-click resolution
|
|
31
|
+
enable_prompt_for_ai_agents: true
|
|
32
|
+
|
|
33
|
+
# Clean presentation settings
|
|
34
|
+
poem: false
|
|
35
|
+
collapse_walkthrough: true
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
.venv/
|
|
2
|
+
dist/
|
|
3
|
+
__pycache__/
|
|
4
|
+
*.pyc
|
|
5
|
+
.git/
|
|
6
|
+
.github/
|
|
7
|
+
tests/
|
|
8
|
+
docs/
|
|
9
|
+
examples/
|
|
10
|
+
scripts/
|
|
11
|
+
skills/
|
|
12
|
+
.env
|
|
13
|
+
.env.example
|
|
14
|
+
.coverage
|
|
15
|
+
htmlcov/
|
|
16
|
+
.mypy_cache/
|
|
17
|
+
.ruff_cache/
|
|
18
|
+
*.md
|
|
19
|
+
!README.md
|
|
20
|
+
.coderabbit.yaml
|
|
21
|
+
.dockerignore
|
|
22
|
+
Dockerfile
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Bug Report
|
|
3
|
+
about: Report a bug or unexpected behavior
|
|
4
|
+
title: "[Bug] "
|
|
5
|
+
labels: bug
|
|
6
|
+
assignees: ''
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Description
|
|
10
|
+
|
|
11
|
+
A clear description of the bug.
|
|
12
|
+
|
|
13
|
+
## Steps to Reproduce
|
|
14
|
+
|
|
15
|
+
1. Configure environment with `...`
|
|
16
|
+
2. Call tool `sigma_...` with parameters `...`
|
|
17
|
+
3. Observe error
|
|
18
|
+
|
|
19
|
+
## Expected Behavior
|
|
20
|
+
|
|
21
|
+
What you expected to happen.
|
|
22
|
+
|
|
23
|
+
## Actual Behavior
|
|
24
|
+
|
|
25
|
+
What actually happened. Include the JSON error response if available.
|
|
26
|
+
|
|
27
|
+
> **Before pasting:** redact any credentials, tokens, cookies, personal data,
|
|
28
|
+
> and private resource identifiers (member IDs, org IDs, etc.) from the response.
|
|
29
|
+
|
|
30
|
+
```json
|
|
31
|
+
{
|
|
32
|
+
"type": "sigma_api_error",
|
|
33
|
+
"status_code": ...,
|
|
34
|
+
"method": "...",
|
|
35
|
+
"path": "...",
|
|
36
|
+
"detail": ...,
|
|
37
|
+
"request_id": "..."
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
> If your report contains sensitive information that cannot be safely redacted,
|
|
42
|
+
> use the [private security advisory](https://github.com/christianclaudio/mcp-server-sigma/security/advisories/new)
|
|
43
|
+
> instead of a public issue.
|
|
44
|
+
|
|
45
|
+
## Environment
|
|
46
|
+
|
|
47
|
+
- Python version:
|
|
48
|
+
- OS:
|
|
49
|
+
- Sigma region (e.g., aws-us-east):
|
|
50
|
+
- MCP host (e.g., Claude Desktop, Cursor):
|
|
51
|
+
|
|
52
|
+
## Additional Context
|
|
53
|
+
|
|
54
|
+
Any other relevant information.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Feature Request
|
|
3
|
+
about: Suggest a new tool or enhancement
|
|
4
|
+
title: "[Feature] "
|
|
5
|
+
labels: enhancement
|
|
6
|
+
assignees: ''
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Summary
|
|
10
|
+
|
|
11
|
+
A concise description of the feature or enhancement.
|
|
12
|
+
|
|
13
|
+
## Use Case
|
|
14
|
+
|
|
15
|
+
Describe the problem this would solve or the workflow it would enable.
|
|
16
|
+
|
|
17
|
+
## Proposed Solution
|
|
18
|
+
|
|
19
|
+
How you envision this working. For new tools, include:
|
|
20
|
+
|
|
21
|
+
- Sigma API endpoint(s) involved
|
|
22
|
+
- Proposed tool name (e.g., `sigma_...`)
|
|
23
|
+
- Parameters and return value
|
|
24
|
+
|
|
25
|
+
## Alternatives Considered
|
|
26
|
+
|
|
27
|
+
Other approaches you've considered and why they're less ideal.
|
|
28
|
+
|
|
29
|
+
## Additional Context
|
|
30
|
+
|
|
31
|
+
Links to Sigma API docs, related issues, or examples.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
## What changed
|
|
2
|
+
|
|
3
|
+
<!-- One or two sentences. Focus on why, not just what. -->
|
|
4
|
+
|
|
5
|
+
## Checklist
|
|
6
|
+
|
|
7
|
+
- [ ] `mypy --strict src/` is clean
|
|
8
|
+
- [ ] `ruff check .` and `ruff format --check .` are clean
|
|
9
|
+
- [ ] `pytest tests/test_unit.py tests/test_tools_mocked.py tests/test_enterprise_assertion.py` passes **without a live Sigma org**
|
|
10
|
+
- [ ] `python scripts/check_openapi_drift.py` exits 0 (no wrong-path drift)
|
|
11
|
+
- [ ] If tools were added/removed: tool-count and annotation assertions updated
|
|
12
|
+
- [ ] If a tool writes or deletes: correct annotation (`destructiveHint`) and, where relevant, `dry_run`/`confirm` gating
|
|
13
|
+
- [ ] If behavior changed: README / `docs/` updated
|
|
14
|
+
- [ ] `CHANGELOG.md` updated
|
|
15
|
+
- [ ] No secrets, tokens, or real org IDs committed
|
|
16
|
+
|
|
17
|
+
## Verification
|
|
18
|
+
|
|
19
|
+
<!-- Paste the actual command output you ran. -->
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
updates:
|
|
3
|
+
- package-ecosystem: pip
|
|
4
|
+
directory: "/"
|
|
5
|
+
schedule:
|
|
6
|
+
interval: weekly
|
|
7
|
+
open-pull-requests-limit: 5
|
|
8
|
+
groups:
|
|
9
|
+
# Batch low-risk bumps into one PR to keep review noise down.
|
|
10
|
+
minor-and-patch:
|
|
11
|
+
patterns: ["*"]
|
|
12
|
+
update-types: ["minor", "patch"]
|
|
13
|
+
|
|
14
|
+
- package-ecosystem: github-actions
|
|
15
|
+
directory: "/"
|
|
16
|
+
schedule:
|
|
17
|
+
interval: weekly
|
|
18
|
+
open-pull-requests-limit: 5
|
|
19
|
+
groups:
|
|
20
|
+
actions-minor-and-patch:
|
|
21
|
+
patterns: ["*"]
|
|
22
|
+
update-types: ["minor", "patch"]
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
security-events: write
|
|
12
|
+
actions: read
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
lint:
|
|
16
|
+
name: Lint and types
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
20
|
+
- uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
|
|
21
|
+
with:
|
|
22
|
+
python-version: "3.12"
|
|
23
|
+
cache: "pip"
|
|
24
|
+
- name: Install
|
|
25
|
+
run: |
|
|
26
|
+
python -m pip install --upgrade pip
|
|
27
|
+
pip install -e ".[dev]" pip-licenses
|
|
28
|
+
- name: Ruff lint
|
|
29
|
+
run: ruff check .
|
|
30
|
+
- name: Ruff format
|
|
31
|
+
run: ruff format --check .
|
|
32
|
+
- name: Mypy strict
|
|
33
|
+
run: mypy --strict src/
|
|
34
|
+
- name: License compliance
|
|
35
|
+
run: pip-licenses --fail-on="GNU General Public License" --partial-match --order=license --ignore-packages docutils
|
|
36
|
+
|
|
37
|
+
test:
|
|
38
|
+
name: Tests (py${{ matrix.python-version }})
|
|
39
|
+
runs-on: ubuntu-latest
|
|
40
|
+
strategy:
|
|
41
|
+
fail-fast: false
|
|
42
|
+
matrix:
|
|
43
|
+
python-version: ["3.10", "3.11", "3.12", "3.13"]
|
|
44
|
+
steps:
|
|
45
|
+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
46
|
+
- uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
|
|
47
|
+
with:
|
|
48
|
+
python-version: ${{ matrix.python-version }}
|
|
49
|
+
cache: "pip"
|
|
50
|
+
- name: Install
|
|
51
|
+
run: |
|
|
52
|
+
python -m pip install --upgrade pip
|
|
53
|
+
pip install -e ".[dev]"
|
|
54
|
+
- name: Unit and mocked tests
|
|
55
|
+
run: pytest --cov=src/sigma_mcp --cov-report=term-missing --cov-fail-under=100 -q
|
|
56
|
+
|
|
57
|
+
contract:
|
|
58
|
+
name: Tool contract and env gating
|
|
59
|
+
runs-on: ubuntu-latest
|
|
60
|
+
steps:
|
|
61
|
+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
62
|
+
- uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
|
|
63
|
+
with:
|
|
64
|
+
python-version: "3.12"
|
|
65
|
+
cache: "pip"
|
|
66
|
+
- name: Install
|
|
67
|
+
run: |
|
|
68
|
+
python -m pip install --upgrade pip
|
|
69
|
+
pip install -e ".[dev]"
|
|
70
|
+
# Guards the counts published in README against silent drift, and proves
|
|
71
|
+
# the safety env vars actually change what gets registered.
|
|
72
|
+
- name: Assert tool counts and safety gating
|
|
73
|
+
run: python scripts/check_tool_contract.py
|
|
74
|
+
|
|
75
|
+
openapi-drift:
|
|
76
|
+
name: OpenAPI drift
|
|
77
|
+
runs-on: ubuntu-latest
|
|
78
|
+
steps:
|
|
79
|
+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
80
|
+
- uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
|
|
81
|
+
with:
|
|
82
|
+
python-version: "3.12"
|
|
83
|
+
cache: "pip"
|
|
84
|
+
- name: Install
|
|
85
|
+
run: |
|
|
86
|
+
python -m pip install --upgrade pip
|
|
87
|
+
pip install -e .
|
|
88
|
+
# Fails the build if any client path is absent from Sigma's published
|
|
89
|
+
# OpenAPI spec. This is the guard against the wrong-path class of bug.
|
|
90
|
+
- name: Check client paths against Sigma spec
|
|
91
|
+
run: python scripts/check_openapi_drift.py
|
|
92
|
+
|
|
93
|
+
build:
|
|
94
|
+
name: Build and package check
|
|
95
|
+
runs-on: ubuntu-latest
|
|
96
|
+
steps:
|
|
97
|
+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
98
|
+
- uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
|
|
99
|
+
with:
|
|
100
|
+
python-version: "3.12"
|
|
101
|
+
cache: "pip"
|
|
102
|
+
- name: Install build tooling
|
|
103
|
+
run: |
|
|
104
|
+
python -m pip install --upgrade pip
|
|
105
|
+
pip install build twine
|
|
106
|
+
- name: Build
|
|
107
|
+
run: python -m build
|
|
108
|
+
- name: Twine check
|
|
109
|
+
run: twine check dist/*
|
|
110
|
+
- name: Upload build artifacts
|
|
111
|
+
uses: actions/upload-artifact@v4
|
|
112
|
+
with:
|
|
113
|
+
name: dist-${{ github.sha }}
|
|
114
|
+
path: dist/
|
|
115
|
+
retention-days: 14
|
|
116
|
+
|
|
117
|
+
docker:
|
|
118
|
+
name: Docker build
|
|
119
|
+
runs-on: ubuntu-latest
|
|
120
|
+
steps:
|
|
121
|
+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
122
|
+
- name: Build Docker image
|
|
123
|
+
run: docker build -t mcp-server-sigma:ci-${{ github.sha }} .
|
|
124
|
+
- name: Verify entrypoint
|
|
125
|
+
run: docker run --rm mcp-server-sigma:ci-${{ github.sha }} --help
|
|
126
|
+
|
|
127
|
+
codeql:
|
|
128
|
+
name: CodeQL
|
|
129
|
+
runs-on: ubuntu-latest
|
|
130
|
+
permissions:
|
|
131
|
+
security-events: write
|
|
132
|
+
contents: read
|
|
133
|
+
steps:
|
|
134
|
+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
135
|
+
- uses: github/codeql-action/init@v3
|
|
136
|
+
with:
|
|
137
|
+
languages: python
|
|
138
|
+
- uses: github/codeql-action/analyze@v3
|
|
139
|
+
# SARIF upload may fail with "Resource not accessible by integration" on
|
|
140
|
+
# repos where the default GITHUB_TOKEN lacks security-events write access.
|
|
141
|
+
# The scan itself still runs; this only affects result visibility in the
|
|
142
|
+
# Security tab. Safe to suppress until GitHub fixes token propagation.
|
|
143
|
+
continue-on-error: true
|
|
144
|
+
|
|
145
|
+
live-smoke:
|
|
146
|
+
name: Live smoke (main only, requires secrets)
|
|
147
|
+
runs-on: ubuntu-latest
|
|
148
|
+
needs: [lint, test, contract, openapi-drift]
|
|
149
|
+
# Never runs on forks or PRs: it needs org credentials and touches a real
|
|
150
|
+
# Sigma organization.
|
|
151
|
+
if: github.event_name == 'push' && github.ref == 'refs/heads/main' && github.repository_owner == 'christianclaudio'
|
|
152
|
+
steps:
|
|
153
|
+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
154
|
+
- uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
|
|
155
|
+
with:
|
|
156
|
+
python-version: "3.12"
|
|
157
|
+
cache: "pip"
|
|
158
|
+
- name: Install
|
|
159
|
+
run: |
|
|
160
|
+
python -m pip install --upgrade pip
|
|
161
|
+
pip install -e ".[dev]"
|
|
162
|
+
- name: Live smoke test
|
|
163
|
+
env:
|
|
164
|
+
SIGMA_CLIENT_ID: ${{ secrets.SIGMA_CLIENT_ID }}
|
|
165
|
+
SIGMA_CLIENT_SECRET: ${{ secrets.SIGMA_CLIENT_SECRET }}
|
|
166
|
+
SIGMA_API_BASE_URL: ${{ secrets.SIGMA_API_BASE_URL }}
|
|
167
|
+
# Skips cleanly rather than failing when secrets are unavailable.
|
|
168
|
+
run: |
|
|
169
|
+
if [ -z "$SIGMA_CLIENT_ID" ] || [ -z "$SIGMA_CLIENT_SECRET" ] || [ -z "$SIGMA_API_BASE_URL" ]; then
|
|
170
|
+
echo "One or more Sigma secrets not set; skipping live smoke."
|
|
171
|
+
exit 0
|
|
172
|
+
fi
|
|
173
|
+
PYTHONPATH=src python tests/smoke_test.py
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
name: Dependabot Auto-Merge
|
|
2
|
+
|
|
3
|
+
on: pull_request_target
|
|
4
|
+
|
|
5
|
+
permissions:
|
|
6
|
+
contents: write
|
|
7
|
+
pull-requests: write
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
dependabot:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
if: github.actor == 'dependabot[bot]'
|
|
13
|
+
steps:
|
|
14
|
+
- name: Dependabot metadata
|
|
15
|
+
id: metadata
|
|
16
|
+
uses: dependabot/fetch-metadata@21025c705c08248db411dc16f3619e6b5f9ea21a # v2
|
|
17
|
+
with:
|
|
18
|
+
github-token: "${{ secrets.GITHUB_TOKEN }}"
|
|
19
|
+
|
|
20
|
+
- name: Enable auto-merge for Dependabot PRs
|
|
21
|
+
run: gh pr merge --auto --squash "$PR_URL"
|
|
22
|
+
env:
|
|
23
|
+
PR_URL: ${{ github.event.pull_request.html_url }}
|
|
24
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags: ["v*"]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
build:
|
|
12
|
+
name: Build distributions
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
16
|
+
- uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
|
|
17
|
+
with:
|
|
18
|
+
python-version: "3.12"
|
|
19
|
+
cache: "pip"
|
|
20
|
+
|
|
21
|
+
- name: Install build tooling & runtime dependencies
|
|
22
|
+
run: |
|
|
23
|
+
python -m pip install --upgrade pip
|
|
24
|
+
pip install build twine cyclonedx-bom
|
|
25
|
+
pip install .
|
|
26
|
+
|
|
27
|
+
- name: Verify tag matches package version
|
|
28
|
+
run: |
|
|
29
|
+
TAG="${GITHUB_REF_NAME#v}"
|
|
30
|
+
PKG=$(python -c "import tomllib,pathlib; print(tomllib.loads(pathlib.Path('pyproject.toml').read_text())['project']['version'])")
|
|
31
|
+
if [ "$TAG" != "$PKG" ]; then
|
|
32
|
+
echo "Tag $TAG does not match pyproject version $PKG" >&2
|
|
33
|
+
exit 1
|
|
34
|
+
fi
|
|
35
|
+
echo "Tag and version agree: $PKG"
|
|
36
|
+
|
|
37
|
+
- name: Build
|
|
38
|
+
run: python -m build
|
|
39
|
+
|
|
40
|
+
- name: Twine check
|
|
41
|
+
run: twine check dist/*
|
|
42
|
+
|
|
43
|
+
- name: Generate CycloneDX SBOM
|
|
44
|
+
run: cyclonedx-py environment -o sbom.cdx.json
|
|
45
|
+
|
|
46
|
+
- uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65822d53b0323c2227 # v4.4.3
|
|
47
|
+
with:
|
|
48
|
+
name: dist
|
|
49
|
+
path: |
|
|
50
|
+
dist/
|
|
51
|
+
sbom.cdx.json
|
|
52
|
+
|
|
53
|
+
publish:
|
|
54
|
+
name: Publish to PyPI
|
|
55
|
+
needs: build
|
|
56
|
+
runs-on: ubuntu-latest
|
|
57
|
+
environment: pypi
|
|
58
|
+
permissions:
|
|
59
|
+
id-token: write # Trusted Publishing (OIDC) — no API token stored
|
|
60
|
+
attestations: write # build provenance
|
|
61
|
+
contents: write # attach assets to the GitHub Release
|
|
62
|
+
steps:
|
|
63
|
+
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
|
64
|
+
with:
|
|
65
|
+
name: dist
|
|
66
|
+
|
|
67
|
+
- name: Attest build provenance
|
|
68
|
+
uses: actions/attest-build-provenance@0f67c3f4856b2e3261c31976d6725780e5e4c373 # v4.1.1
|
|
69
|
+
with:
|
|
70
|
+
subject-path: "dist/*"
|
|
71
|
+
|
|
72
|
+
# SHA-pinned deliberately: all actions in this workflow use immutable
|
|
73
|
+
# commit SHAs to protect against supply-chain tag mutations.
|
|
74
|
+
- name: Publish to PyPI
|
|
75
|
+
uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
|
|
76
|
+
|
|
77
|
+
- name: Attach SBOM to release
|
|
78
|
+
uses: softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # v3.0.2
|
|
79
|
+
with:
|
|
80
|
+
files: sbom.cdx.json
|
|
81
|
+
|
|
82
|
+
docker:
|
|
83
|
+
name: Publish Docker image
|
|
84
|
+
needs: build
|
|
85
|
+
runs-on: ubuntu-latest
|
|
86
|
+
permissions:
|
|
87
|
+
contents: read
|
|
88
|
+
packages: write
|
|
89
|
+
steps:
|
|
90
|
+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
91
|
+
|
|
92
|
+
- name: Log in to GHCR
|
|
93
|
+
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
|
|
94
|
+
with:
|
|
95
|
+
registry: ghcr.io
|
|
96
|
+
username: ${{ github.actor }}
|
|
97
|
+
password: ${{ secrets.GITHUB_TOKEN }}
|
|
98
|
+
|
|
99
|
+
- name: Extract version from tag
|
|
100
|
+
id: version
|
|
101
|
+
run: echo "version=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT"
|
|
102
|
+
|
|
103
|
+
- name: Build and push
|
|
104
|
+
uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75 # v6.9.0
|
|
105
|
+
with:
|
|
106
|
+
context: .
|
|
107
|
+
push: true
|
|
108
|
+
tags: |
|
|
109
|
+
ghcr.io/${{ github.repository }}:${{ steps.version.outputs.version }}
|
|
110
|
+
ghcr.io/${{ github.repository }}:latest
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
Instructions for AI coding agents (Claude Code, Copilot, Cursor, Windsurf, etc.) working on this repository.
|
|
4
|
+
|
|
5
|
+
## Project Overview
|
|
6
|
+
|
|
7
|
+
This is `mcp-server-sigma` — a Python MCP server exposing 155 tools for Sigma Computing's REST API. It runs over stdio and is consumed by AI clients (Claude Desktop, VS Code, etc.).
|
|
8
|
+
|
|
9
|
+
## Architecture
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
src/sigma_mcp/
|
|
13
|
+
├── server.py # MCP tool definitions (2600+ lines, all @mcp.tool() handlers)
|
|
14
|
+
├── client.py # Async HTTP client (OAuth2, retries, rate-limiting, tenant token exchange)
|
|
15
|
+
├── errors.py # Error formatting with secret redaction
|
|
16
|
+
├── webhooks.py # Webhook signature verification + in-memory event buffer
|
|
17
|
+
└── __init__.py # Version only
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Key Patterns
|
|
21
|
+
|
|
22
|
+
- **Every tool** is an `async def` decorated with `@mcp.tool()` and `@sigma_tool`
|
|
23
|
+
- `@sigma_tool` is a decorator that adds timing, structured logging, and error handling
|
|
24
|
+
- **Destructive tools** require `confirm: bool = False` — reject if not `True`
|
|
25
|
+
- **Composite tools** (promote, deploy, onboard) orchestrate multiple API calls
|
|
26
|
+
- **Annotations** are applied post-registration via `mcp._tool_manager._tools` (private API, pinned SDK version)
|
|
27
|
+
|
|
28
|
+
## Development Commands
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
# Install
|
|
32
|
+
pip install -e ".[dev]"
|
|
33
|
+
|
|
34
|
+
# Lint + format
|
|
35
|
+
ruff check . && ruff format --check .
|
|
36
|
+
|
|
37
|
+
# Type check
|
|
38
|
+
mypy --strict src/
|
|
39
|
+
|
|
40
|
+
# Tests (100% coverage required)
|
|
41
|
+
pytest --cov=src/sigma_mcp --cov-fail-under=100 -q
|
|
42
|
+
|
|
43
|
+
# Tool contract validation
|
|
44
|
+
python scripts/check_tool_contract.py
|
|
45
|
+
|
|
46
|
+
# OpenAPI drift check
|
|
47
|
+
python scripts/check_openapi_drift.py
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Testing Conventions
|
|
51
|
+
|
|
52
|
+
- Tests use `unittest.mock.AsyncMock` to mock `SigmaClient` methods
|
|
53
|
+
- Monkeypatch `srv._client` to inject a mock client
|
|
54
|
+
- No `conftest.py` — each test file is self-contained
|
|
55
|
+
- Coverage must stay at 100% — CI enforces this
|
|
56
|
+
|
|
57
|
+
## Adding a New Tool
|
|
58
|
+
|
|
59
|
+
1. Add the client method in `client.py` (async, typed)
|
|
60
|
+
2. Add the `@mcp.tool()` handler in `server.py` with proper docstring
|
|
61
|
+
3. Add the tool name to the appropriate annotation set (`_DESTRUCTIVE_NAMES`, `_IDEMPOTENT_NAMES`, or let it default to `_WRITE_SAFE`)
|
|
62
|
+
4. Update `scripts/check_tool_contract.py` expected counts
|
|
63
|
+
5. Update `README.md` tool count
|
|
64
|
+
6. Add test coverage (must maintain 100%)
|
|
65
|
+
|
|
66
|
+
## Safety Rules
|
|
67
|
+
|
|
68
|
+
- Never remove `confirm=True` gates from destructive tools
|
|
69
|
+
- Never expose credentials in error messages (secret redaction is automatic)
|
|
70
|
+
- Bulk-destructive tools are gated behind `SIGMA_MCP_ALLOW_BULK_DESTRUCTIVE=1`
|
|
71
|
+
- Read-only mode (`SIGMA_MCP_READONLY=1`) filters out all write tools at registration time
|
|
72
|
+
|
|
73
|
+
## CI Pipeline
|
|
74
|
+
|
|
75
|
+
The CI runs 7 jobs: lint, test (4 Python versions), contract validation, OpenAPI drift, build+twine, CodeQL, and live smoke (main-only with secrets). All must pass for merge.
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 1.0.0 (2026-08-02)
|
|
4
|
+
|
|
5
|
+
### Breaking Changes
|
|
6
|
+
- **Bulk-destructive tools are no longer registered by default.** `sigma_bulk_deactivate_members` and `sigma_bulk_remove_team_members` require `SIGMA_MCP_ALLOW_BULK_DESTRUCTIVE=1` to appear in the tool list. Without it, they do not exist from the model's perspective. This is intentional: an unprompted "clean up inactive users" from a model should not have access to bulk deactivation.
|
|
7
|
+
- **Single-Delete Confirmation Gating**: Mandatory `confirm: bool = False` opt-in parameter required on all atomic delete, archive, deactivate, and bulk-remove tools. Callers performing destructive operations must explicitly pass `confirm=True`.
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
- **Native MCP Resources**: Registered `sigma://reference/formulas`, `sigma://reference/capabilities`, `sigma://reference/docs-index`, and `sigma://webhooks/recent` native resources.
|
|
11
|
+
- **Native MCP Prompts**: Registered `provision_tenant_dashboard`, `audit_organization_permissions`, `prepare_data_model`, `onboard_team_member`, `swap_warehouse_source`, and `audit_tenant_connections` native prompts.
|
|
12
|
+
- **Documentation tools**: `sigma_search_docs` (AI-powered semantic search via Sigma's docs MCP) and `sigma_get_doc_page` (fetch any docs page as Markdown).
|
|
13
|
+
- **Structured JSON Logging**: Support for `SIGMA_MCP_LOG_FORMAT=json` with structured log records including execution duration (`duration_ms`).
|
|
14
|
+
- **Network Transport CLI Flags**: Added `--host` and `--port` CLI options for network transport server deployment.
|
|
15
|
+
- **Path Segment Sanitization**: Automated path parameter quoting (`quote(seg, safe="").replace("..", "%2E%2E")`) across all 217 client API methods to prevent path traversal attacks.
|
|
16
|
+
- **Secret & Token Redaction**: Multi-pattern regex scrubbing (`Bearer` tokens, `client_secret`, `access_token`, `subject_token`, and raw JWT `eyJ...`) across error responses and log payloads.
|
|
17
|
+
- **Multi-Tenant Security**: Added `SIGMA_ALLOWED_TENANTS` allowlist check and `SIGMA_STRICT_TENANT_ALLOWLIST=1` fail-closed enforcement for RFC 8693 token exchange.
|
|
18
|
+
- **Single-Delete Confirmation Gating**: Mandatory `confirm: bool = False` opt-in parameter required on all atomic delete, archive, deactivate, and bulk-remove tool calls.
|
|
19
|
+
- **Safety gating**: `SIGMA_MCP_READONLY=1` removes all non-read-only tools from registration (83 tools remain). Composes with profiles (e.g. `admin` + `readonly` = read-only subset of admin tools).
|
|
20
|
+
- **`embed` profile**: `SIGMA_MCP_PROFILE=embed` (55 tools) for embedded analytics workflows — core + embeds, user attributes, tenants, source swap, workspace grants.
|
|
21
|
+
- **Catch-all regex rejection** in `sigma_bulk_deactivate_members`: patterns like `.*`, `.+`, `^.*$`, `.`, or empty string are refused because they would match every member in the org.
|
|
22
|
+
- **10-member hard cap** on `sigma_bulk_deactivate_members`: if the pattern matches more than 10 members, the tool refuses and reports the match list. Prevents accidental org-wide deactivation.
|
|
23
|
+
- **`sigma_formula_pitfalls` tool**: returns a curated Sigma formula reference to prevent hallucinated function names and type errors. Backed by `src/sigma_mcp/reference/formulas.md`.
|
|
24
|
+
- **11 new endpoints**: reports (CRUD, schedules, elements, queries, lineage, sources, duplicate, export), source-swap policies, deployment documents, workbook version history, report schedules.
|
|
25
|
+
- **Tool count now 155** (default), 157 with bulk-destructive opt-in, 83 read-only.
|
|
26
|
+
- **Expanded test suite** covering profile composition, readonly filtering, bulk-gating, annotation completeness, and catch-all regex rejection.
|
|
27
|
+
- **OSS files**: SECURITY.md, CONTRIBUTING.md, CODE_OF_CONDUCT.md, LICENSE.
|
|
28
|
+
- **`scripts/check_tool_contract.py`**: validates counts, annotations, profiles, and gating. Runs in CI.
|
|
29
|
+
- **docs/formulas.md**: full Sigma formula reference for agent consumption.
|
|
30
|
+
|
|
31
|
+
### Fixed
|
|
32
|
+
- Annotation counts corrected: 83 read-only, 16 destructive, 8 idempotent.
|
|
33
|
+
- `sigma_promote_workbook` now creates the tag if it doesn't already exist (idempotent).
|
|
34
|
+
|
|
35
|
+
## 0.2.0 (2026-08-01)
|
|
36
|
+
|
|
37
|
+
### Breaking Changes
|
|
38
|
+
- Client is now fully async (`httpx.AsyncClient`). All methods are `async def`.
|
|
39
|
+
- All MCP tools are now `async def`. Requires MCP SDK >= 2.0.0.
|
|
40
|
+
|
|
41
|
+
### Added
|
|
42
|
+
- **Structured error handling**: `SigmaAPIError` class with status, path, method, detail, request_id. `@sigma_tool` decorator wraps all tools — no raw exceptions escape.
|
|
43
|
+
- **8 recipe tools**: export+download, ownership transfer, shared workbooks, input table scan, bulk deactivate, change email, bulk team remove, tenant connection sync.
|
|
44
|
+
- **Multi-tenant auth**: RFC 8693 token exchange via `SigmaClient.for_tenant()`. Per-tenant token cache with auto-refresh.
|
|
45
|
+
- **MCP 2.0 annotations**: All 141 tools annotated with `readOnlyHint`, `destructiveHint`, `idempotentHint`, `openWorldHint`.
|
|
46
|
+
- **Tool profiles**: `SIGMA_MCP_PROFILE=core|admin|full` to control tool registration.
|
|
47
|
+
- **OpenAPI drift detection**: `scripts/check_openapi_drift.py` compares client paths against official spec.
|
|
48
|
+
- **GitHub Actions CI**: Matrix on Python 3.10-3.13 with ruff + pytest.
|
|
49
|
+
- **Auto-pagination tools**: `sigma_list_all_*` tools that follow pagination tokens.
|
|
50
|
+
- **PyJWT dependency** for tenant token exchange.
|
|
51
|
+
- Secret redaction in all error messages.
|
|
52
|
+
|
|
53
|
+
### Fixed
|
|
54
|
+
- `download_query()` now routes through `_request()` for retry/rate-limit handling.
|
|
55
|
+
- `time.sleep` replaced with `await asyncio.sleep` throughout.
|
|
56
|
+
|
|
57
|
+
## 0.1.0 (2025-06-15)
|
|
58
|
+
|
|
59
|
+
Initial release. 131 tools covering the Sigma v2 API surface.
|