mcp-sonarcloud 0.1.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.
@@ -0,0 +1,85 @@
1
+ name: Publish
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+
8
+ jobs:
9
+ publish:
10
+ runs-on: ubuntu-latest
11
+ permissions:
12
+ contents: read
13
+ id-token: write
14
+ environment:
15
+ name: pypi
16
+ url: https://pypi.org/p/mcp-sonarcloud
17
+
18
+ steps:
19
+ - name: Checkout code
20
+ uses: actions/checkout@v4
21
+
22
+ - name: Set up Python 3.12
23
+ uses: actions/setup-python@v5
24
+ with:
25
+ python-version: "3.12"
26
+
27
+ - name: Install uv
28
+ uses: astral-sh/setup-uv@v3
29
+ with:
30
+ version: "latest"
31
+
32
+ - name: Validate tag matches package version
33
+ run: |
34
+ package_version="$(python -c 'import tomllib; from pathlib import Path; print(tomllib.loads(Path("pyproject.toml").read_text(encoding="utf-8"))["project"]["version"])')"
35
+ tag_version="${GITHUB_REF_NAME#v}"
36
+
37
+ if [ "$package_version" != "$tag_version" ]; then
38
+ echo "Tag version $tag_version does not match pyproject.toml version $package_version" >&2
39
+ exit 1
40
+ fi
41
+
42
+ - name: Install dependencies
43
+ run: |
44
+ uv sync --extra dev
45
+
46
+ - name: Run tests
47
+ run: |
48
+ uv run pytest -q
49
+
50
+ - name: Build package artifacts
51
+ run: |
52
+ uv build
53
+
54
+ - name: Smoke test wheel
55
+ run: |
56
+ tmp_dir="$(mktemp -d)"
57
+ uvx --from dist/*.whl mcp-sonarcloud \
58
+ --config-dir "$tmp_dir/config" \
59
+ --state-dir "$tmp_dir/state" \
60
+ --cache-dir "$tmp_dir/cache" \
61
+ --write-sample-config
62
+ test -f "$tmp_dir/config/config.toml"
63
+ uvx --from dist/*.whl mcp-sonarcloud \
64
+ --config-dir "$tmp_dir/config" \
65
+ --state-dir "$tmp_dir/state" \
66
+ --cache-dir "$tmp_dir/cache" \
67
+ --print-paths
68
+
69
+ - name: Smoke test sdist
70
+ run: |
71
+ tmp_dir="$(mktemp -d)"
72
+ uvx --from dist/*.tar.gz mcp-sonarcloud \
73
+ --config-dir "$tmp_dir/config" \
74
+ --state-dir "$tmp_dir/state" \
75
+ --cache-dir "$tmp_dir/cache" \
76
+ --write-sample-config
77
+ test -f "$tmp_dir/config/config.toml"
78
+ uvx --from dist/*.tar.gz mcp-sonarcloud \
79
+ --config-dir "$tmp_dir/config" \
80
+ --state-dir "$tmp_dir/state" \
81
+ --cache-dir "$tmp_dir/cache" \
82
+ --print-paths
83
+
84
+ - name: Publish to PyPI
85
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,108 @@
1
+ name: Tests
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+ workflow_dispatch:
9
+
10
+ jobs:
11
+ test:
12
+ runs-on: ubuntu-latest
13
+ strategy:
14
+ matrix:
15
+ python-version: ["3.11", "3.12", "3.13", "3.14"]
16
+
17
+ steps:
18
+ - name: Checkout code
19
+ uses: actions/checkout@v4
20
+
21
+ - name: Set up Python ${{ matrix.python-version }}
22
+ uses: actions/setup-python@v5
23
+ with:
24
+ python-version: ${{ matrix.python-version }}
25
+
26
+ - name: Install uv
27
+ uses: astral-sh/setup-uv@v3
28
+ with:
29
+ version: "latest"
30
+
31
+ - name: Cache uv environment
32
+ uses: actions/cache@v4
33
+ with:
34
+ path: |
35
+ ~/.cache/uv
36
+ .venv
37
+ key: ${{ runner.os }}-uv-py${{ matrix.python-version }}-${{ hashFiles('uv.lock') }}
38
+ restore-keys: |
39
+ ${{ runner.os }}-uv-py${{ matrix.python-version }}-
40
+
41
+ - name: Install dependencies
42
+ run: |
43
+ uv sync --extra dev
44
+
45
+ - name: Run tests
46
+ run: |
47
+ uv run pytest --junitxml=test-results/junit.xml
48
+
49
+ - name: Upload test results
50
+ if: always()
51
+ uses: actions/upload-artifact@v4
52
+ with:
53
+ name: test-results-py${{ matrix.python-version }}
54
+ path: |
55
+ test-results/
56
+ if-no-files-found: ignore
57
+
58
+ package-smoke:
59
+ runs-on: ubuntu-latest
60
+ needs: test
61
+
62
+ steps:
63
+ - name: Checkout code
64
+ uses: actions/checkout@v4
65
+
66
+ - name: Set up Python 3.12
67
+ uses: actions/setup-python@v5
68
+ with:
69
+ python-version: "3.12"
70
+
71
+ - name: Install uv
72
+ uses: astral-sh/setup-uv@v3
73
+ with:
74
+ version: "latest"
75
+
76
+ - name: Build package artifacts
77
+ run: |
78
+ uv build
79
+
80
+ - name: Smoke test wheel
81
+ run: |
82
+ tmp_dir="$(mktemp -d)"
83
+ uvx --from dist/*.whl mcp-sonarcloud \
84
+ --config-dir "$tmp_dir/config" \
85
+ --state-dir "$tmp_dir/state" \
86
+ --cache-dir "$tmp_dir/cache" \
87
+ --write-sample-config
88
+ test -f "$tmp_dir/config/config.toml"
89
+ uvx --from dist/*.whl mcp-sonarcloud \
90
+ --config-dir "$tmp_dir/config" \
91
+ --state-dir "$tmp_dir/state" \
92
+ --cache-dir "$tmp_dir/cache" \
93
+ --print-paths
94
+
95
+ - name: Smoke test sdist
96
+ run: |
97
+ tmp_dir="$(mktemp -d)"
98
+ uvx --from dist/*.tar.gz mcp-sonarcloud \
99
+ --config-dir "$tmp_dir/config" \
100
+ --state-dir "$tmp_dir/state" \
101
+ --cache-dir "$tmp_dir/cache" \
102
+ --write-sample-config
103
+ test -f "$tmp_dir/config/config.toml"
104
+ uvx --from dist/*.tar.gz mcp-sonarcloud \
105
+ --config-dir "$tmp_dir/config" \
106
+ --state-dir "$tmp_dir/state" \
107
+ --cache-dir "$tmp_dir/cache" \
108
+ --print-paths
@@ -0,0 +1,47 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ .Python
7
+ build/
8
+ develop-eggs/
9
+ dist/
10
+ downloads/
11
+ eggs/
12
+ .eggs/
13
+ lib/
14
+ lib64/
15
+ parts/
16
+ sdist/
17
+ var/
18
+ wheels/
19
+ *.egg-info/
20
+ .installed.cfg
21
+ *.egg
22
+
23
+ # Virtual environments
24
+ venv/
25
+ ENV/
26
+ env/
27
+ .venv
28
+
29
+ # IDE
30
+ .vscode/
31
+ .idea/
32
+ *.swp
33
+ *.swo
34
+ *~
35
+
36
+ # Testing
37
+ .pytest_cache/
38
+ .coverage
39
+ htmlcov/
40
+
41
+ # Environment variables
42
+ .env
43
+ .env.local
44
+
45
+ # OS
46
+ .DS_Store
47
+ Thumbs.db
@@ -0,0 +1,184 @@
1
+ # Development Notes
2
+
3
+ ## Implementation Details
4
+
5
+ ### Architecture
6
+
7
+ This MCP server is built using the FastMCP framework from the MCP Python SDK. The architecture follows a simple, straightforward approach:
8
+
9
+ ```
10
+ src/mcp_sonarcloud/
11
+ ├── __init__.py # Package initialization
12
+ └── server.py # Main server with all tools
13
+ ```
14
+
15
+ ### API Endpoints Mapping
16
+
17
+ The server implements 15 tools that map to these SonarCloud API endpoints:
18
+
19
+ | Tool Name | API Endpoint | HTTP Method | Purpose |
20
+ |-----------|--------------|-------------|---------|
21
+ | **Components/Projects** | | | |
22
+ | `search_my_sonarqube_projects` | `/api/components/search` | GET | List projects |
23
+ | `show_component` | `/api/components/show` | GET | Show component metadata |
24
+ | `component_tree` | `/api/components/tree` | GET | Traverse component hierarchy |
25
+ | **Issues** | | | |
26
+ | `search_sonar_issues_in_projects` | `/api/issues/search` | GET | Search issues |
27
+ | `list_issue_authors` | `/api/issues/authors` | GET | List issue authors |
28
+ | `get_issue_changelog` | `/api/issues/changelog` | GET | Get issue change history |
29
+ | `list_issue_tags` | `/api/issues/tags` | GET | List issue tags |
30
+ | **Quality Gates** | | | |
31
+ | `get_project_quality_gate_status` | `/api/qualitygates/project_status` | GET | Get QG status |
32
+ | `list_quality_gates` | `/api/qualitygates/list` | GET | List quality gates |
33
+ | `show_quality_gate` | `/api/qualitygates/show` | GET | Show quality gate details |
34
+ | `search_quality_gates` | `/api/qualitygates/search` | GET | Search projects by QG |
35
+ | `get_quality_gate_by_project` | `/api/qualitygates/get_by_project` | GET | Get QG for project |
36
+ | **Security Hotspots** | | | |
37
+ | `search_hotspots` | `/api/hotspots/search` | GET | Search hotspots |
38
+ | `show_hotspot` | `/api/hotspots/show` | GET | Get hotspot details |
39
+ | `change_hotspot_status` | `/api/hotspots/change_status` | POST | Update hotspot status |
40
+
41
+ ### Authentication
42
+
43
+ The server uses Bearer token authentication:
44
+ - Token is provided via `SONARCLOUD_TOKEN` environment variable
45
+ - Each request includes: `Authorization: Bearer <token>` header
46
+ - Organization is automatically added to requests if `SONARCLOUD_ORGANIZATION` is set
47
+
48
+ ### Design Decisions
49
+
50
+ 1. **Single File Implementation**: All code is in one file for simplicity and easy understanding
51
+ 2. **Pydantic Models**: Used for type safety and automatic validation of responses
52
+ 3. **Pydantic Field Annotations**: All tool parameters use Field() with comprehensive descriptions, valid values, formats, and examples for optimal LLM consumption
53
+ 4. **Async/Await**: All API calls are asynchronous for better performance
54
+ 5. **Environment-Based Config**: No config files needed, just environment variables
55
+ 6. **Structured Responses**: Tools return structured data (Pydantic models or dicts) instead of raw JSON
56
+ 7. **LLM-First Documentation**: Every tool includes examples and explicit documentation of valid values to minimize trial-and-error by AI agents
57
+
58
+ ### Hotspots API Research
59
+
60
+ The hotspots API was not well-documented publicly, but through research:
61
+
62
+ 1. **Source**: Analyzed SonarLint Core Java implementation
63
+ 2. **Endpoints Found**:
64
+ - `/api/hotspots/search.protobuf` - Returns protobuf format
65
+ - `/api/hotspots/show.protobuf` - Returns protobuf format
66
+ - `/api/hotspots/change_status` - Form-encoded POST
67
+ - We use the JSON versions (without `.protobuf`)
68
+
69
+ 3. **Status Values**:
70
+ - `TO_REVIEW`: Hotspot needs review
71
+ - `REVIEWED`: Hotspot has been reviewed
72
+
73
+ 4. **Resolution Values** (when status=REVIEWED):
74
+ - `FIXED`: Vulnerability was fixed
75
+ - `SAFE`: Code is safe, not a vulnerability
76
+ - `ACKNOWLEDGED`: Risk is accepted
77
+
78
+ ### Testing Strategy
79
+
80
+ Tests use `pytest-httpx` to mock HTTP requests:
81
+ - Each test mocks the expected API response
82
+ - Tests verify both the request format and response parsing
83
+ - All tests run without requiring actual SonarCloud credentials
84
+
85
+ ### Comparison with Official Server
86
+
87
+ | Feature | This Implementation | Official SonarSource Server |
88
+ |---------|-------------------|---------------------------|
89
+ | Language | Python | Kotlin/Java |
90
+ | Lines of Code | ~730 | ~5000+ |
91
+ | Tools Count | 15 tools | ~10 tools |
92
+ | Hotspot Support | ✅ Full (search, show, change status) | ❌ Missing |
93
+ | Quality Gates | ✅ Full (5 tools) | ⚠️ Partial |
94
+ | Issues API | ✅ Good (4 tools) | ✅ Yes |
95
+ | LLM Documentation | ✅ Comprehensive Field annotations | ⚠️ Basic |
96
+ | Code Analysis | ❌ No | ✅ Yes |
97
+ | Dependency Risks | ❌ No | ✅ Yes |
98
+ | Metrics Search | ❌ No | ✅ Yes |
99
+ | Ease of Modification | ✅ Very Easy | ⚠️ Complex |
100
+
101
+ ### Future Enhancements
102
+
103
+ Potential additions:
104
+ 1. Add caching for frequently accessed data
105
+ 2. Support batch operations on hotspots
106
+ 3. Add more filtering options for issues/hotspots
107
+ 4. Support for SonarQube Server (not just SonarCloud)
108
+ 5. Add telemetry/metrics collection
109
+ 6. Support for SSE transport in addition to stdio
110
+
111
+ ### Known Limitations
112
+
113
+ 1. **No Pagination Automation**: Users must manually page through large result sets
114
+ 2. **Organization Required**: Works best with SonarCloud organizations
115
+ 3. **No Rate Limiting**: No built-in rate limiting protection
116
+ 4. **Limited Error Context**: HTTP errors could be more descriptive
117
+ 5. **No Retry Logic**: Failed requests are not automatically retried
118
+
119
+ ### Contributing Guidelines
120
+
121
+ When adding new tools:
122
+
123
+ 1. Add the tool function with `@mcp.tool()` decorator
124
+ 2. Use type hints and Pydantic `Field()` annotations for all parameters
125
+ 3. Document valid values, formats, and provide examples in Field descriptions
126
+ 4. Create a Pydantic model for structured responses if needed
127
+ 5. Add comprehensive docstring with examples and parameter relationships
128
+ 6. Write tests for the new tool in `tests/test_server.py`
129
+ 7. Update README.md and SONARCLOUD_API_SUPPORT.md
130
+
131
+ Example:
132
+ ```python
133
+ @mcp.tool()
134
+ async def new_tool(
135
+ param: str = Field(
136
+ description="Parameter description with example (e.g., 'my-value')"
137
+ ),
138
+ status: str = Field(
139
+ description="Status value. Valid values: 'OPEN', 'CLOSED', 'PENDING'"
140
+ ),
141
+ optional_param: Optional[int] = Field(
142
+ default=None,
143
+ description="Optional parameter (e.g., 123)"
144
+ ),
145
+ ) -> ResponseModel:
146
+ """Tool description explaining what it does and when to use it.
147
+
148
+ Provide context about the tool's purpose, what data it returns,
149
+ and any important constraints or requirements.
150
+
151
+ Example: new_tool(param="my-project", status="OPEN", optional_param=100)
152
+ """
153
+ result = await make_request("/api/endpoint", params={"param": param})
154
+ return ResponseModel(**result)
155
+ ```
156
+
157
+ **Key Documentation Requirements:**
158
+ - Use `Field()` for ALL parameters (including required ones)
159
+ - Document valid enum values explicitly (e.g., "Valid values: 'X', 'Y', 'Z'")
160
+ - Specify format for complex inputs (e.g., "comma-separated list")
161
+ - Include concrete examples in descriptions (e.g., "e.g., 'my-project'")
162
+ - Add usage example in docstring showing realistic parameters
163
+ - Explain parameter relationships (e.g., "required when X is Y")
164
+ - State what the tool returns in the docstring
165
+
166
+ ## Debugging
167
+
168
+ To debug the server:
169
+
170
+ ```bash
171
+ # Enable verbose logging
172
+ export SONARCLOUD_TOKEN=your-token
173
+ export SONARCLOUD_ORGANIZATION=your-org
174
+
175
+ # Run with MCP inspector for interactive debugging
176
+ uvx mcp-inspector uv run mcp-sonarcloud
177
+ ```
178
+
179
+ ## Performance Considerations
180
+
181
+ - All API calls use httpx's async client for concurrency
182
+ - Connection pooling is handled by httpx automatically
183
+ - Timeout is set to 30 seconds for all requests
184
+ - Consider implementing caching for frequently accessed data
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Lukas Lehner <lehner.lukas@gmail.com>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.