#
tokens: 49708/50000 73/236 files (page 1/11)
lines: on (toggle) GitHub
raw markdown copy reset
This is page 1 of 11. Use http://codebase.md/sapientpants/sonarqube-mcp-server?lines=true&page={x} to view the full context.

# Directory Structure

```
├── .adr-dir
├── .changeset
│   ├── config.json
│   └── README.md
├── .claude
│   ├── commands
│   │   ├── analyze-and-fix-github-issue.md
│   │   ├── fix-sonarqube-issues.md
│   │   ├── implement-github-issue.md
│   │   ├── release.md
│   │   ├── spec-feature.md
│   │   └── update-dependencies.md
│   ├── hooks
│   │   └── block-git-no-verify.ts
│   └── settings.json
├── .dockerignore
├── .github
│   ├── actionlint.yaml
│   ├── changeset.yml
│   ├── dependabot.yml
│   ├── ISSUE_TEMPLATE
│   │   ├── bug_report.md
│   │   └── feature_request.md
│   ├── pull_request_template.md
│   ├── scripts
│   │   ├── determine-artifact.sh
│   │   └── version-and-release.js
│   ├── workflows
│   │   ├── codeql.yml
│   │   ├── main.yml
│   │   ├── pr.yml
│   │   ├── publish.yml
│   │   ├── reusable-docker.yml
│   │   ├── reusable-security.yml
│   │   └── reusable-validate.yml
│   └── WORKFLOWS.md
├── .gitignore
├── .husky
│   ├── commit-msg
│   └── pre-commit
├── .markdownlint.yaml
├── .markdownlintignore
├── .npmrc
├── .prettierignore
├── .prettierrc
├── .trivyignore
├── .yaml-lint.yml
├── .yamllintignore
├── CHANGELOG.md
├── changes.md
├── CLAUDE.md
├── CODE_OF_CONDUCT.md
├── commitlint.config.js
├── COMPATIBILITY.md
├── CONTRIBUTING.md
├── docker-compose.yml
├── Dockerfile
├── docs
│   ├── architecture
│   │   └── decisions
│   │       ├── 0001-record-architecture-decisions.md
│   │       ├── 0002-use-node-js-with-typescript.md
│   │       ├── 0003-adopt-model-context-protocol-for-sonarqube-integration.md
│   │       ├── 0004-use-sonarqube-web-api-client-for-all-sonarqube-interactions.md
│   │       ├── 0005-domain-driven-design-of-sonarqube-modules.md
│   │       ├── 0006-expose-sonarqube-features-as-mcp-tools.md
│   │       ├── 0007-support-multiple-authentication-methods-for-sonarqube.md
│   │       ├── 0008-use-environment-variables-for-configuration.md
│   │       ├── 0009-file-based-logging-to-avoid-stdio-conflicts.md
│   │       ├── 0010-use-stdio-transport-for-mcp-communication.md
│   │       ├── 0011-docker-containerization-for-deployment.md
│   │       ├── 0012-add-elicitation-support-for-interactive-user-input.md
│   │       ├── 0014-current-security-model-and-future-oauth2-considerations.md
│   │       ├── 0015-transport-architecture-refactoring.md
│   │       ├── 0016-http-transport-with-oauth-2-0-metadata-endpoints.md
│   │       ├── 0017-comprehensive-audit-logging-system.md
│   │       ├── 0018-add-comprehensive-monitoring-and-observability.md
│   │       ├── 0019-simplify-to-stdio-only-transport-for-mcp-gateway-deployment.md
│   │       ├── 0020-testing-framework-and-strategy-vitest-with-property-based-testing.md
│   │       ├── 0021-code-quality-toolchain-eslint-prettier-strict-typescript.md
│   │       ├── 0022-package-manager-choice-pnpm.md
│   │       ├── 0023-release-management-with-changesets.md
│   │       ├── 0024-ci-cd-platform-github-actions.md
│   │       ├── 0025-container-and-security-scanning-strategy.md
│   │       ├── 0026-circuit-breaker-pattern-with-opossum.md
│   │       ├── 0027-docker-image-publishing-strategy-ghcr-to-docker-hub.md
│   │       └── 0028-session-based-http-transport-with-server-sent-events.md
│   ├── architecture.md
│   ├── security.md
│   └── troubleshooting.md
├── eslint.config.js
├── examples
│   └── http-client.ts
├── jest.config.js
├── LICENSE
├── LICENSES.md
├── osv-scanner.toml
├── package.json
├── pnpm-lock.yaml
├── README.md
├── scripts
│   ├── actionlint.sh
│   ├── ci-local.sh
│   ├── load-test.sh
│   ├── README.md
│   ├── run-all-tests.sh
│   ├── scan-container.sh
│   ├── security-scan.sh
│   ├── setup.sh
│   ├── test-monitoring-integration.sh
│   └── validate-docs.sh
├── SECURITY.md
├── sonar-project.properties
├── src
│   ├── __tests__
│   │   ├── additional-coverage.test.ts
│   │   ├── advanced-index.test.ts
│   │   ├── assign-issue.test.ts
│   │   ├── auth-methods.test.ts
│   │   ├── boolean-string-transform.test.ts
│   │   ├── components.test.ts
│   │   ├── config
│   │   │   └── service-accounts.test.ts
│   │   ├── dependency-injection.test.ts
│   │   ├── direct-handlers.test.ts
│   │   ├── direct-lambdas.test.ts
│   │   ├── direct-schema-validation.test.ts
│   │   ├── domains
│   │   │   ├── components-domain-full.test.ts
│   │   │   ├── components-domain.test.ts
│   │   │   ├── hotspots-domain.test.ts
│   │   │   └── source-code-domain.test.ts
│   │   ├── environment-validation.test.ts
│   │   ├── error-handler.test.ts
│   │   ├── error-handling.test.ts
│   │   ├── errors.test.ts
│   │   ├── function-tests.test.ts
│   │   ├── handlers
│   │   │   ├── components-handler-integration.test.ts
│   │   │   └── projects-authorization.test.ts
│   │   ├── handlers.test.ts
│   │   ├── handlers.test.ts.skip
│   │   ├── index.test.ts
│   │   ├── issue-resolution-elicitation.test.ts
│   │   ├── issue-resolution.test.ts
│   │   ├── issue-transitions.test.ts
│   │   ├── issues-enhanced-search.test.ts
│   │   ├── issues-new-parameters.test.ts
│   │   ├── json-array-transform.test.ts
│   │   ├── lambda-functions.test.ts
│   │   ├── lambda-handlers.test.ts.skip
│   │   ├── logger.test.ts
│   │   ├── mapping-functions.test.ts
│   │   ├── mocked-environment.test.ts
│   │   ├── null-to-undefined.test.ts
│   │   ├── parameter-transformations-advanced.test.ts
│   │   ├── parameter-transformations.test.ts
│   │   ├── protocol-version.test.ts
│   │   ├── pull-request-transform.test.ts
│   │   ├── quality-gates.test.ts
│   │   ├── schema-parameter-transforms.test.ts
│   │   ├── schema-transformation-mocks.test.ts
│   │   ├── schema-transforms.test.ts
│   │   ├── schema-validators.test.ts
│   │   ├── schemas
│   │   │   ├── components-schema.test.ts
│   │   │   ├── hotspots-tools-schema.test.ts
│   │   │   └── issues-schema.test.ts
│   │   ├── sonarqube-elicitation.test.ts
│   │   ├── sonarqube.test.ts
│   │   ├── source-code.test.ts
│   │   ├── standalone-handlers.test.ts
│   │   ├── string-to-number-transform.test.ts
│   │   ├── tool-handler-lambdas.test.ts
│   │   ├── tool-handlers.test.ts
│   │   ├── tool-registration-schema.test.ts
│   │   ├── tool-registration-transforms.test.ts
│   │   ├── transformation-util.test.ts
│   │   ├── transports
│   │   │   ├── base.test.ts
│   │   │   ├── factory.test.ts
│   │   │   ├── http.test.ts
│   │   │   ├── session-manager.test.ts
│   │   │   └── stdio.test.ts
│   │   ├── utils
│   │   │   ├── retry.test.ts
│   │   │   └── transforms.test.ts
│   │   ├── zod-boolean-transform.test.ts
│   │   ├── zod-schema-transforms.test.ts
│   │   └── zod-transforms.test.ts
│   ├── config
│   │   ├── service-accounts.ts
│   │   └── versions.ts
│   ├── domains
│   │   ├── base.ts
│   │   ├── components.ts
│   │   ├── hotspots.ts
│   │   ├── index.ts
│   │   ├── issues.ts
│   │   ├── measures.ts
│   │   ├── metrics.ts
│   │   ├── projects.ts
│   │   ├── quality-gates.ts
│   │   ├── source-code.ts
│   │   └── system.ts
│   ├── errors.ts
│   ├── handlers
│   │   ├── components.ts
│   │   ├── hotspots.ts
│   │   ├── index.ts
│   │   ├── issues.ts
│   │   ├── measures.ts
│   │   ├── metrics.ts
│   │   ├── projects.ts
│   │   ├── quality-gates.ts
│   │   ├── source-code.ts
│   │   └── system.ts
│   ├── index.ts
│   ├── monitoring
│   │   ├── __tests__
│   │   │   └── circuit-breaker.test.ts
│   │   ├── circuit-breaker.ts
│   │   ├── health.ts
│   │   └── metrics.ts
│   ├── schemas
│   │   ├── common.ts
│   │   ├── components.ts
│   │   ├── hotspots-tools.ts
│   │   ├── hotspots.ts
│   │   ├── index.ts
│   │   ├── issues.ts
│   │   ├── measures.ts
│   │   ├── metrics.ts
│   │   ├── projects.ts
│   │   ├── quality-gates.ts
│   │   ├── source-code.ts
│   │   └── system.ts
│   ├── sonarqube.ts
│   ├── transports
│   │   ├── base.ts
│   │   ├── factory.ts
│   │   ├── http.ts
│   │   ├── index.ts
│   │   ├── session-manager.ts
│   │   └── stdio.ts
│   ├── types
│   │   ├── common.ts
│   │   ├── components.ts
│   │   ├── hotspots.ts
│   │   ├── index.ts
│   │   ├── issues.ts
│   │   ├── measures.ts
│   │   ├── metrics.ts
│   │   ├── projects.ts
│   │   ├── quality-gates.ts
│   │   ├── source-code.ts
│   │   └── system.ts
│   └── utils
│       ├── __tests__
│       │   ├── elicitation.test.ts
│       │   ├── pattern-matcher.test.ts
│       │   └── structured-response.test.ts
│       ├── client-factory.ts
│       ├── elicitation.ts
│       ├── error-handler.ts
│       ├── logger.ts
│       ├── parameter-mappers.ts
│       ├── pattern-matcher.ts
│       ├── retry.ts
│       ├── structured-response.ts
│       └── transforms.ts
├── test-http-transport.sh
├── tmp
│   └── .gitkeep
├── tsconfig.build.json
├── tsconfig.json
├── vitest.config.d.ts
├── vitest.config.js
├── vitest.config.js.map
└── vitest.config.ts
```

# Files

--------------------------------------------------------------------------------
/.adr-dir:
--------------------------------------------------------------------------------

```
1 | docs/architecture/decisions
2 | 
```

--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------

```
1 | dist/
2 | node_modules/
3 | coverage/
4 | pnpm-lock.yaml
5 | package-lock.json
6 | *.d.ts
7 | sbom.cdx.json 
```

--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------

```
1 | engine-strict=true
2 | save-exact=true
3 | fund=false
4 | audit=true
5 | @your-scope:registry=https://registry.npmjs.org/
6 | 
```

--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------

```
 1 | {
 2 |   "semi": true,
 3 |   "trailingComma": "es5",
 4 |   "singleQuote": true,
 5 |   "printWidth": 100,
 6 |   "tabWidth": 2,
 7 |   "useTabs": false,
 8 |   "endOfLine": "lf"
 9 | }
10 | 
```

--------------------------------------------------------------------------------
/.markdownlintignore:
--------------------------------------------------------------------------------

```
 1 | # Ignore CHANGELOG as it's auto-generated
 2 | CHANGELOG.md
 3 | 
 4 | # Ignore node_modules
 5 | node_modules/
 6 | 
 7 | # Ignore coverage reports
 8 | coverage/
 9 | 
10 | # Ignore build output
11 | dist/
```

--------------------------------------------------------------------------------
/.yamllintignore:
--------------------------------------------------------------------------------

```
 1 | # Ignore node_modules
 2 | node_modules/
 3 | 
 4 | # Ignore GitHub workflows (linted by actionlint)
 5 | .github/workflows/
 6 | 
 7 | # Ignore build output
 8 | dist/
 9 | coverage/
10 | 
11 | # Ignore lock files (auto-generated)
12 | pnpm-lock.yaml
13 | yarn.lock
14 | package-lock.json
```

--------------------------------------------------------------------------------
/.yaml-lint.yml:
--------------------------------------------------------------------------------

```yaml
 1 | # yaml-lint configuration
 2 | # https://github.com/rasshofer/yaml-lint
 3 | 
 4 | # Schema to use for validation
 5 | schema: 'FAILSAFE_SCHEMA'
 6 | 
 7 | # Ignore certain paths
 8 | ignore:
 9 |   - node_modules/**
10 |   - .github/workflows/**
11 |   - dist/**
12 |   - coverage/**
13 |   - pnpm-lock.yaml
14 |   - yarn.lock
15 |   - package-lock.json
16 | 
```

--------------------------------------------------------------------------------
/.trivyignore:
--------------------------------------------------------------------------------

```
 1 | # Trivy Ignore File
 2 | # This file contains CVEs to ignore during container security scanning
 3 | # Format: CVE-ID or CVE-ID with expiry date
 4 | # 
 5 | # Example entries:
 6 | # CVE-2022-12345
 7 | # CVE-2022-12345 exp:2025-01-01
 8 | #
 9 | # Add CVEs here that are false positives or accepted risks
10 | # Each exclusion should be documented with a comment explaining why
11 | 
12 | # Example: False positive in test dependency
13 | # CVE-2024-XXXXX
14 | 
15 | # Note: Regularly review and update this file to remove outdated exclusions
```

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
 1 | # Dependencies
 2 | node_modules/
 3 | .pnpm-store/
 4 | 
 5 | # Build output
 6 | dist/
 7 | coverage/
 8 | 
 9 | # IDE and editor files
10 | .vscode/
11 | .idea/
12 | *.swp
13 | *.swo
14 | 
15 | # Logs
16 | *.log
17 | npm-debug.log*
18 | pnpm-debug.log*
19 | 
20 | # Environment variables
21 | .env
22 | .env.local
23 | .env.*.local
24 | 
25 | # OS files
26 | .DS_Store
27 | Thumbs.db 
28 | **/.claude/settings.local.json
29 | 
30 | # Terraform
31 | terraform/.terraform/
32 | terraform/**/.terraform/
33 | terraform/**/terraform.tfstate
34 | terraform/**/terraform.tfstate.*
35 | terraform/**/*.tfvars
36 | !terraform/**/*.tfvars.example
37 | terraform/**/.terraform.lock.hcl
38 | 
39 | # Kubernetes secrets
40 | k8s/overlays/production/secrets.env
41 | 
42 | # Helm
43 | helm/**/charts/
44 | helm/**/Chart.lock
45 | 
```

--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------

```
 1 | # Git files
 2 | .git
 3 | .gitignore
 4 | .gitattributes
 5 | 
 6 | # GitHub files
 7 | .github
 8 | 
 9 | # Documentation
10 | *.md
11 | LICENSE
12 | docs
13 | doc
14 | 
15 | # Development files
16 | .husky
17 | .changeset
18 | .eslintrc.json
19 | .prettierrc
20 | .prettierignore
21 | .editorconfig
22 | .vscode
23 | .idea
24 | 
25 | # Test files
26 | tests
27 | test
28 | *.test.ts
29 | *.spec.ts
30 | coverage
31 | .nyc_output
32 | junit.xml
33 | 
34 | # Build artifacts that will be created during Docker build
35 | dist
36 | *.tsbuildinfo
37 | 
38 | # Logs
39 | logs
40 | *.log
41 | npm-debug.log*
42 | yarn-debug.log*
43 | yarn-error.log*
44 | pnpm-debug.log*
45 | 
46 | # OS files
47 | .DS_Store
48 | Thumbs.db
49 | 
50 | # Environment files (should not be in image)
51 | .env
52 | .env.*
53 | 
54 | # CI/CD files
55 | .travis.yml
56 | .gitlab-ci.yml
57 | Jenkinsfile
58 | 
59 | # Docker files
60 | Dockerfile
61 | .dockerignore
62 | docker-compose*.yml
63 | 
64 | # Temporary files
65 | tmp
66 | temp
67 | *.tmp
68 | *.bak
69 | *.swp
70 | 
71 | # SBOM and security scan results
72 | sbom.cdx.json
73 | trivy-results.sarif
74 | results.sarif
75 | 
76 | # Archives
77 | *.tar.gz
78 | *.zip
```

--------------------------------------------------------------------------------
/.markdownlint.yaml:
--------------------------------------------------------------------------------

```yaml
 1 | # Markdownlint configuration
 2 | # https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md
 3 | 
 4 | # Default state for all rules
 5 | default: true
 6 | 
 7 | # MD003/heading-style - Heading style
 8 | MD003:
 9 |   style: 'atx' # Use # style headers
10 | 
11 | # MD004/ul-style - Unordered list style
12 | MD004:
13 |   style: 'dash' # Use - for unordered lists
14 | 
15 | # MD007/ul-indent - Unordered list indentation
16 | MD007:
17 |   indent: 2 # 2 spaces for nested lists
18 | 
19 | # MD013/line-length - Line length
20 | # Disabled as many lines contain URLs or complex content
21 | MD013: false
22 | 
23 | # MD022/blanks-around-headings - Headings should be surrounded by blank lines
24 | # Allow some flexibility in heading spacing
25 | MD022: false
26 | 
27 | # MD024/no-duplicate-heading - Multiple headings with the same content
28 | MD024:
29 |   siblings_only: true # Allow same heading if not siblings
30 | 
31 | # MD026/no-trailing-punctuation - Trailing punctuation in heading
32 | # Allow colons in headings for clarity
33 | MD026: false
34 | 
35 | # MD031/blanks-around-fences - Fenced code blocks should be surrounded by blank lines
36 | # Sometimes inline code blocks make sense
37 | MD031: false
38 | 
39 | # MD034/no-bare-urls - Bare URLs
40 | # Sometimes bare URLs are intentional for clarity
41 | MD034: false
42 | 
43 | # MD025/single-title - Multiple top-level headings
44 | # Disabled because we might have multiple H1s in different sections
45 | MD025: false
46 | 
47 | # MD033/no-inline-html - Inline HTML
48 | MD033:
49 |   allowed_elements:
50 |     - details
51 |     - summary
52 |     - sub
53 |     - sup
54 |     - br
55 |     - img
56 |     - a
57 |     - code
58 |     - pre
59 |     - table
60 |     - thead
61 |     - tbody
62 |     - tr
63 |     - td
64 |     - th
65 |     - div
66 |     - span
67 |     - kbd
68 | 
69 | # MD040/fenced-code-language - Fenced code blocks should have a language specified
70 | # Disabled as we sometimes have plain text blocks
71 | MD040: false
72 | 
73 | # MD041/first-line-heading - First line in a file should be a top-level heading
74 | # Disabled as not all markdown files need to start with a heading
75 | MD041: false
76 | 
77 | # MD045/no-alt-text - Images should have alternate text
78 | # Disabled as decorative images don't always need alt text
79 | MD045: false
80 | 
81 | # MD046/code-block-style - Code block style
82 | MD046:
83 |   style: 'fenced' # Use ``` for code blocks
84 | 
85 | # MD048/code-fence-style - Code fence style
86 | MD048:
87 |   style: 'backtick' # Use backticks for code fences
88 | 
89 | # MD049/emphasis-style - Emphasis style
90 | MD049:
91 |   style: 'underscore' # Use _ for italic
92 | 
93 | # MD050/strong-style - Strong style
94 | MD050:
95 |   style: 'asterisk' # Use ** for bold
96 | 
```

--------------------------------------------------------------------------------
/.changeset/README.md:
--------------------------------------------------------------------------------

```markdown
1 | # Changesets
2 | 
3 | Use `pnpm changeset` to create version entries. On release, run `pnpm release`.
4 | 
```

--------------------------------------------------------------------------------
/scripts/README.md:
--------------------------------------------------------------------------------

```markdown
  1 | # SonarQube MCP Server Test Scripts
  2 | 
  3 | This directory contains comprehensive test scripts for validating the SonarQube MCP Server deployment artifacts, including Kubernetes manifests, Helm charts, Terraform modules, and documentation.
  4 | 
  5 | ## Overview
  6 | 
  7 | The test suite ensures that all deployment artifacts are:
  8 | 
  9 | - Syntactically correct
 10 | - Follow security best practices
 11 | - Work as expected in different configurations
 12 | - Scale properly under load
 13 | - Integrate correctly with monitoring systems
 14 | 
 15 | ## Test Scripts
 16 | 
 17 | ### 🚀 Master Test Runner
 18 | 
 19 | **Script:** `run-all-tests.sh`
 20 | 
 21 | Orchestrates all test suites in the correct order.
 22 | 
 23 | ```bash
 24 | # Run all tests
 25 | ./scripts/run-all-tests.sh
 26 | 
 27 | # Run specific test suite
 28 | ./scripts/run-all-tests.sh --only helm
 29 | 
 30 | # Skip cleanup for debugging
 31 | ./scripts/run-all-tests.sh --skip-cleanup
 32 | ```
 33 | 
 34 | ### 📚 Documentation Validation
 35 | 
 36 | **Script:** `validate-docs.sh`
 37 | 
 38 | Validates documentation for:
 39 | 
 40 | - Broken internal links
 41 | - Invalid code examples
 42 | - Missing required sections
 43 | - Orphaned images
 44 | - TODO markers
 45 | 
 46 | ```bash
 47 | ./scripts/validate-docs.sh
 48 | ```
 49 | 
 50 | ### 🔧 Terraform Validation
 51 | 
 52 | **Script:** `validate-terraform.sh`
 53 | 
 54 | Tests Terraform modules for:
 55 | 
 56 | - Syntax validation
 57 | - Formatting standards
 58 | - Security issues (hardcoded secrets)
 59 | - Required variables
 60 | - Plan generation
 61 | 
 62 | ```bash
 63 | ./scripts/validate-terraform.sh
 64 | ```
 65 | 
 66 | ### 🎯 Helm Chart Testing
 67 | 
 68 | **Script:** `test-helm-values.sh`
 69 | 
 70 | Tests Helm chart with various configurations:
 71 | 
 72 | - Minimal deployment
 73 | - Production settings
 74 | - High availability
 75 | - Monitoring enabled
 76 | - Ingress with TLS
 77 | 
 78 | ```bash
 79 | ./scripts/test-helm-values.sh
 80 | ```
 81 | 
 82 | ### ☸️ Kubernetes Deployment Testing
 83 | 
 84 | **Script:** `test-k8s-deployment.sh`
 85 | 
 86 | Basic Kubernetes deployment test using kind cluster.
 87 | 
 88 | ```bash
 89 | export SONARQUBE_TOKEN="your-token"
 90 | ./scripts/test-k8s-deployment.sh
 91 | ```
 92 | 
 93 | **Script:** `test-k8s-helm-deployment.sh`
 94 | 
 95 | Extended test that validates both Kustomize and Helm deployments.
 96 | 
 97 | ```bash
 98 | # Test both Kustomize and Helm
 99 | ./scripts/test-k8s-helm-deployment.sh
100 | 
101 | # Test only Helm
102 | ./scripts/test-k8s-helm-deployment.sh --skip-kustomize
103 | 
104 | # Keep cluster for debugging
105 | ./scripts/test-k8s-helm-deployment.sh --keep-cluster
106 | ```
107 | 
108 | ### 🔒 Security Scanning
109 | 
110 | **Script:** `security-scan.sh`
111 | 
112 | Comprehensive security scanning using:
113 | 
114 | - Kubesec for Kubernetes manifests
115 | - Trivy for container vulnerabilities
116 | - Polaris for policy violations
117 | - Custom security checks
118 | 
119 | ```bash
120 | ./scripts/security-scan.sh
121 | ```
122 | 
123 | ### 📊 Monitoring Integration Tests
124 | 
125 | **Script:** `test-monitoring-integration.sh`
126 | 
127 | Tests monitoring endpoints and integration:
128 | 
129 | - Health and readiness checks
130 | - Prometheus metrics format
131 | - Circuit breaker functionality
132 | - OpenTelemetry support
133 | - Performance metrics
134 | 
135 | ```bash
136 | # Requires running service
137 | npm run dev
138 | 
139 | # In another terminal
140 | ./scripts/test-monitoring-integration.sh
141 | ```
142 | 
143 | ### ⚡ Load Testing
144 | 
145 | **Script:** `load-test.sh`
146 | 
147 | Tests auto-scaling behavior under load using k6 or Apache Bench.
148 | 
149 | ```bash
150 | # Default configuration
151 | ./scripts/load-test.sh
152 | 
153 | # Custom parameters
154 | CONCURRENT_USERS=100 DURATION=600 ./scripts/load-test.sh
155 | ```
156 | 
157 | ### 🌐 Network Fixes
158 | 
159 | **Script:** `fix-kind-dns.sh`
160 | 
161 | Fixes DNS resolution issues in kind clusters (common on macOS).
162 | 
163 | ```bash
164 | ./scripts/fix-kind-dns.sh cluster-name
165 | ```
166 | 
167 | ## Helm Test Hooks
168 | 
169 | Located in `helm/sonarqube-mcp/templates/tests/`:
170 | 
171 | - `deployment-test.yaml` - Tests deployment readiness
172 | - `service-test.yaml` - Tests service connectivity
173 | - `config-test.yaml` - Tests configuration validity
174 | 
175 | Run with:
176 | 
177 | ```bash
178 | helm test release-name -n namespace
179 | ```
180 | 
181 | ## Prerequisites
182 | 
183 | ### Required Tools
184 | 
185 | - Docker
186 | - kubectl
187 | - Helm 3+
188 | 
189 | ### Optional Tools
190 | 
191 | - kind (for Kubernetes tests)
192 | - Terraform (for Terraform validation)
193 | - k6 or Apache Bench (for load testing)
194 | - trivy (for container scanning)
195 | - Node.js (for documentation validation)
196 | 
197 | ### Tool Installation
198 | 
199 | ```bash
200 | # macOS with Homebrew
201 | brew install kubectl helm kind terraform k6 trivy
202 | 
203 | # Install Polaris
204 | brew install FairwindsOps/tap/polaris
205 | 
206 | # Install kubesec (downloaded automatically if not present)
207 | ```
208 | 
209 | ## CI/CD Integration
210 | 
211 | These scripts are designed to be integrated into CI/CD pipelines:
212 | 
213 | ```yaml
214 | # Example GitHub Actions
215 | - name: Run all tests
216 |   run: ./scripts/run-all-tests.sh
217 | 
218 | # Example GitLab CI
219 | test:
220 |   script:
221 |     - ./scripts/validate-docs.sh
222 |     - ./scripts/validate-terraform.sh
223 |     - ./scripts/test-helm-values.sh
224 |     - ./scripts/security-scan.sh
225 | ```
226 | 
227 | ## Troubleshooting
228 | 
229 | ### Common Issues
230 | 
231 | 1. **Script not executable**
232 | 
233 |    ```bash
234 |    chmod +x scripts/*.sh
235 |    ```
236 | 
237 | 2. **Kind cluster issues**
238 | 
239 |    ```bash
240 |    kind delete cluster --name sonarqube-mcp-test
241 |    ./scripts/test-k8s-deployment.sh
242 |    ```
243 | 
244 | 3. **DNS resolution in kind**
245 | 
246 |    ```bash
247 |    ./scripts/fix-kind-dns.sh sonarqube-mcp-test
248 |    ```
249 | 
250 | 4. **Missing tools**
251 |    Check prerequisites and install required tools.
252 | 
253 | ## Best Practices
254 | 
255 | 1. **Run tests before commits**
256 | 
257 |    ```bash
258 |    ./scripts/run-all-tests.sh --only docs,helm,security
259 |    ```
260 | 
261 | 2. **Use in CI/CD**
262 |    Integrate appropriate tests in your pipeline.
263 | 
264 | 3. **Regular security scans**
265 | 
266 |    ```bash
267 |    ./scripts/security-scan.sh
268 |    ```
269 | 
270 | 4. **Test configuration changes**
271 |    Always test Helm values changes:
272 |    ```bash
273 |    ./scripts/test-helm-values.sh
274 |    ```
275 | 
276 | ## Contributing
277 | 
278 | When adding new deployment artifacts:
279 | 
280 | 1. Update relevant test scripts
281 | 2. Add new test cases if needed
282 | 3. Document in this README
283 | 4. Ensure tests pass before PR
284 | 
```

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
   1 | # SonarQube MCP Server
   2 | 
   3 | [![Main](https://github.com/sapientpants/sonarqube-mcp-server/actions/workflows/main.yml/badge.svg)](https://github.com/sapientpants/sonarqube-mcp-server/actions/workflows/main.yml)
   4 | [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=sonarqube-mcp-server&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=sonarqube-mcp-server)
   5 | [![Bugs](https://sonarcloud.io/api/project_badges/measure?project=sonarqube-mcp-server&metric=bugs)](https://sonarcloud.io/summary/new_code?id=sonarqube-mcp-server)
   6 | [![Code Smells](https://sonarcloud.io/api/project_badges/measure?project=sonarqube-mcp-server&metric=code_smells)](https://sonarcloud.io/summary/new_code?id=sonarqube-mcp-server)
   7 | [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=sonarqube-mcp-server&metric=coverage)](https://sonarcloud.io/summary/new_code?id=sonarqube-mcp-server)
   8 | [![Duplicated Lines (%)](https://sonarcloud.io/api/project_badges/measure?project=sonarqube-mcp-server&metric=duplicated_lines_density)](https://sonarcloud.io/summary/new_code?id=sonarqube-mcp-server)
   9 | [![npm version](https://img.shields.io/npm/v/sonarqube-mcp-server.svg)](https://www.npmjs.com/package/sonarqube-mcp-server)
  10 | [![npm downloads](https://img.shields.io/npm/dm/sonarqube-mcp-server.svg)](https://www.npmjs.com/package/sonarqube-mcp-server)
  11 | [![License](https://img.shields.io/npm/l/sonarqube-mcp-server.svg)](https://github.com/sapientpants/sonarqube-mcp-server/blob/main/LICENSE)
  12 | 
  13 | A Model Context Protocol (MCP) server that integrates with SonarQube to provide AI assistants with access to code quality metrics, issues, and analysis results.
  14 | 
  15 | ## Table of Contents
  16 | 
  17 | - [Overview](#overview)
  18 | - [Documentation](#documentation)
  19 | - [Compatibility](#compatibility)
  20 | - [Quick Start](#quick-start)
  21 | - [Installation](#installation)
  22 |   - [NPX](#npx-recommended)
  23 |   - [Docker](#docker-recommended-for-production)
  24 |   - [Local Development](#local-development)
  25 | - [Configuration](#configuration)
  26 |   - [Environment Variables](#environment-variables)
  27 |   - [Authentication Methods](#authentication-methods)
  28 | - [Available Tools](#available-tools)
  29 | - [Usage Examples](#usage-examples)
  30 | - [Architecture](#architecture)
  31 | - [Development](#development)
  32 | - [Troubleshooting](#troubleshooting)
  33 | - [Contributing](#contributing)
  34 | - [License](#license)
  35 | - [External Resources](#external-resources)
  36 | 
  37 | ## Overview
  38 | 
  39 | The SonarQube MCP Server enables AI assistants to interact with SonarQube's code quality analysis capabilities through the Model Context Protocol. This integration allows AI assistants to:
  40 | 
  41 | - 📊 **Retrieve code metrics and analysis results** - Access detailed quality metrics for your projects
  42 | - 🐛 **Access and filter issues** - Search and filter code issues by severity, type, status, and more
  43 | - 🔒 **Review security hotspots** - Find and manage security vulnerabilities with dedicated workflows
  44 | - 🌿 **Analyze branches and PRs** - Review code quality in feature branches and pull requests
  45 | - 📦 **Multi-project analysis** - Query issues and metrics across multiple projects simultaneously
  46 | - ✅ **Check quality gates** - Monitor whether projects meet quality standards
  47 | - 📈 **Analyze project quality over time** - Track metrics history and trends
  48 | - 🔍 **View source code with issues** - See problematic code with highlighted issues
  49 | - 🏥 **Monitor system health** - Check SonarQube instance status and availability
  50 | - 🔄 **Enhanced error handling** - Clear error messages with solutions and automatic retry for transient failures
  51 | 
  52 | ## Documentation
  53 | 
  54 | ### Core Guides
  55 | 
  56 | - **[Architecture Guide](docs/architecture.md)** - System architecture, design decisions, and component overview
  57 | - **[Troubleshooting Guide](docs/troubleshooting.md)** - Common issues, debugging, and solutions
  58 | 
  59 | ### Security & Authentication
  60 | 
  61 | - **[Security Guide](docs/security.md)** - Authentication, authorization, and security best practices
  62 | 
  63 | ## Compatibility
  64 | 
  65 | For detailed information about MCP protocol version support and SDK compatibility, see [COMPATIBILITY.md](COMPATIBILITY.md).
  66 | 
  67 | ## Quick Start
  68 | 
  69 | ### Prerequisites
  70 | 
  71 | - [Claude Desktop](https://claude.ai/download) installed
  72 | - A SonarQube instance or [SonarCloud](https://sonarcloud.io) account
  73 | - A SonarQube/SonarCloud authentication token
  74 | 
  75 | ### 1. Get Your SonarQube Token
  76 | 
  77 | **For SonarCloud:**
  78 | 
  79 | 1. Log in to [SonarCloud](https://sonarcloud.io)
  80 | 2. Go to **My Account** → **Security**
  81 | 3. Generate a new token
  82 | 
  83 | **For SonarQube:**
  84 | 
  85 | 1. Log in to your SonarQube instance
  86 | 2. Go to **My Account** → **Security**
  87 | 3. Generate a new token
  88 | 
  89 | ### 2. Configure Claude Desktop
  90 | 
  91 | 1. Open Claude Desktop
  92 | 2. Go to **Settings** → **Developer** → **Edit Config**
  93 | 3. Add the SonarQube server configuration:
  94 | 
  95 | ```json
  96 | {
  97 |   "mcpServers": {
  98 |     "sonarqube": {
  99 |       "command": "npx",
 100 |       "args": ["-y", "sonarqube-mcp-server@latest"],
 101 |       "env": {
 102 |         "SONARQUBE_URL": "https://sonarcloud.io",
 103 |         "SONARQUBE_TOKEN": "your-token-here",
 104 |         "SONARQUBE_ORGANIZATION": "your-org (for SonarCloud)"
 105 |       }
 106 |     }
 107 |   }
 108 | }
 109 | ```
 110 | 
 111 | **Alternative authentication methods:**
 112 | 
 113 | Using Basic Authentication:
 114 | 
 115 | ```json
 116 | {
 117 |   "mcpServers": {
 118 |     "sonarqube": {
 119 |       "command": "npx",
 120 |       "args": ["-y", "sonarqube-mcp-server@latest"],
 121 |       "env": {
 122 |         "SONARQUBE_URL": "https://your-sonarqube.com",
 123 |         "SONARQUBE_USERNAME": "your-username",
 124 |         "SONARQUBE_PASSWORD": "your-password"
 125 |       }
 126 |     }
 127 |   }
 128 | }
 129 | ```
 130 | 
 131 | Using System Passcode:
 132 | 
 133 | ```json
 134 | {
 135 |   "mcpServers": {
 136 |     "sonarqube": {
 137 |       "command": "npx",
 138 |       "args": ["-y", "sonarqube-mcp-server@latest"],
 139 |       "env": {
 140 |         "SONARQUBE_URL": "https://your-sonarqube.com",
 141 |         "SONARQUBE_PASSCODE": "your-system-passcode"
 142 |       }
 143 |     }
 144 |   }
 145 | }
 146 | ```
 147 | 
 148 | 1. Restart Claude Desktop
 149 | 
 150 | ### 3. Start Using
 151 | 
 152 | Ask Claude to analyze your SonarQube projects:
 153 | 
 154 | ```
 155 | "List all my SonarQube projects"
 156 | "Show me critical issues in project xyz"
 157 | "What's the code coverage for project xyz?"
 158 | "Check the quality gate status for project xyz"
 159 | "Retrieve security hotspots in project xyz and create a plan to address them"
 160 | "Retrieve the issues for pr 123 in project xyz and create a plan to address them"
 161 | ```
 162 | 
 163 | ## Installation
 164 | 
 165 | ### NPX (Recommended)
 166 | 
 167 | The simplest way to use the SonarQube MCP Server is through npx:
 168 | 
 169 | ```json
 170 | {
 171 |   "mcpServers": {
 172 |     "sonarqube": {
 173 |       "command": "npx",
 174 |       "args": ["-y", "sonarqube-mcp-server@latest"],
 175 |       "env": {
 176 |         "SONARQUBE_URL": "https://sonarqube.example.com",
 177 |         "SONARQUBE_TOKEN": "your-sonarqube-token",
 178 |         "SONARQUBE_ORGANIZATION": "your-organization-key"
 179 |       }
 180 |     }
 181 |   }
 182 | }
 183 | ```
 184 | 
 185 | ### Docker (Recommended for Production)
 186 | 
 187 | Docker provides the most reliable deployment method by packaging all dependencies and ensuring consistent behavior across different environments.
 188 | 
 189 | > **Enterprise Deployment**: For production deployments with Kubernetes, Helm charts, and cloud-specific configurations, see our comprehensive [Deployment Guide](docs/deployment.md).
 190 | 
 191 | #### Quick Start with Docker
 192 | 
 193 | **For stdio transport (Claude Desktop):**
 194 | 
 195 | ```json
 196 | {
 197 |   "mcpServers": {
 198 |     "sonarqube": {
 199 |       "command": "docker",
 200 |       "args": [
 201 |         "run",
 202 |         "-i",
 203 |         "--rm",
 204 |         "-e",
 205 |         "SONARQUBE_URL",
 206 |         "-e",
 207 |         "SONARQUBE_TOKEN",
 208 |         "-e",
 209 |         "SONARQUBE_ORGANIZATION",
 210 |         "sapientpants/sonarqube-mcp-server:latest"
 211 |       ],
 212 |       "env": {
 213 |         "SONARQUBE_URL": "https://sonarqube.example.com",
 214 |         "SONARQUBE_TOKEN": "your-sonarqube-token",
 215 |         "SONARQUBE_ORGANIZATION": "your-organization-key"
 216 |       }
 217 |     }
 218 |   }
 219 | }
 220 | ```
 221 | 
 222 | #### Docker Hub Images
 223 | 
 224 | Official images are available on Docker Hub: [`sapientpants/sonarqube-mcp-server`](https://hub.docker.com/r/sapientpants/sonarqube-mcp-server)
 225 | 
 226 | **Available tags:**
 227 | 
 228 | - `latest` - Latest stable release
 229 | - `1.6.0` - Specific version (recommended for production)
 230 | - `1.6` - Latest patch version of 1.6.x
 231 | - `1` - Latest minor version of 1.x.x
 232 | 
 233 | **Pull the image:**
 234 | 
 235 | ```bash
 236 | docker pull sapientpants/sonarqube-mcp-server:latest
 237 | ```
 238 | 
 239 | #### Advanced Docker Configuration
 240 | 
 241 | **With logging enabled:**
 242 | 
 243 | ```json
 244 | {
 245 |   "mcpServers": {
 246 |     "sonarqube": {
 247 |       "command": "docker",
 248 |       "args": [
 249 |         "run",
 250 |         "-i",
 251 |         "--rm",
 252 |         "-v",
 253 |         "/tmp/sonarqube-logs:/logs",
 254 |         "-e",
 255 |         "SONARQUBE_URL",
 256 |         "-e",
 257 |         "SONARQUBE_TOKEN",
 258 |         "-e",
 259 |         "SONARQUBE_ORGANIZATION",
 260 |         "-e",
 261 |         "LOG_FILE=/logs/sonarqube-mcp.log",
 262 |         "-e",
 263 |         "LOG_LEVEL=INFO",
 264 |         "sapientpants/sonarqube-mcp-server:latest"
 265 |       ],
 266 |       "env": {
 267 |         "SONARQUBE_URL": "https://sonarqube.example.com",
 268 |         "SONARQUBE_TOKEN": "your-sonarqube-token",
 269 |         "SONARQUBE_ORGANIZATION": "your-organization-key"
 270 |       }
 271 |     }
 272 |   }
 273 | }
 274 | ```
 275 | 
 276 | **Using Docker Compose:**
 277 | 
 278 | ```yaml
 279 | version: '3.8'
 280 | services:
 281 |   sonarqube-mcp:
 282 |     image: sapientpants/sonarqube-mcp-server:latest
 283 |     environment:
 284 |       - SONARQUBE_URL=https://sonarqube.example.com
 285 |       - SONARQUBE_TOKEN=${SONARQUBE_TOKEN}
 286 |       - SONARQUBE_ORGANIZATION=${SONARQUBE_ORGANIZATION}
 287 |       - LOG_FILE=/logs/sonarqube-mcp.log
 288 |       - LOG_LEVEL=INFO
 289 |     volumes:
 290 |       - ./logs:/logs
 291 |     stdin_open: true
 292 |     tty: true
 293 | ```
 294 | 
 295 | #### Building Your Own Docker Image
 296 | 
 297 | If you need to customize the server, you can build your own image:
 298 | 
 299 | ```bash
 300 | # Clone the repository
 301 | git clone https://github.com/sapientpants/sonarqube-mcp-server.git
 302 | cd sonarqube-mcp-server
 303 | 
 304 | # Build the Docker image
 305 | docker build -t my-sonarqube-mcp-server .
 306 | 
 307 | # Run your custom image
 308 | docker run -i --rm \
 309 |   -e SONARQUBE_URL="https://sonarqube.example.com" \
 310 |   -e SONARQUBE_TOKEN="your-token" \
 311 |   my-sonarqube-mcp-server
 312 | ```
 313 | 
 314 | #### Docker Best Practices
 315 | 
 316 | 1. **Version Pinning**: Always use specific version tags in production:
 317 | 
 318 |    ```bash
 319 |    sapientpants/sonarqube-mcp-server:1.6.0
 320 |    ```
 321 | 
 322 | 2. **Resource Limits**: Set appropriate resource limits:
 323 | 
 324 |    ```bash
 325 |    docker run -i --rm \
 326 |      --memory="256m" \
 327 |      --cpus="0.5" \
 328 |      sapientpants/sonarqube-mcp-server:1.6.0
 329 |    ```
 330 | 
 331 | 3. **Security**: Run as non-root user (default in our image):
 332 | 
 333 |    ```bash
 334 |    docker run -i --rm \
 335 |      --user node \
 336 |      sapientpants/sonarqube-mcp-server:1.6.0
 337 |    ```
 338 | 
 339 | 4. **Health Checks**: The container includes a health check that verifies the Node.js process is running
 340 | 
 341 | ### Local Development
 342 | 
 343 | For development or customization:
 344 | 
 345 | ```json
 346 | {
 347 |   "mcpServers": {
 348 |     "sonarqube": {
 349 |       "command": "node",
 350 |       "args": ["/path/to/sonarqube-mcp-server/dist/index.js"],
 351 |       "env": {
 352 |         "SONARQUBE_URL": "https://sonarqube.example.com",
 353 |         "SONARQUBE_TOKEN": "your-sonarqube-token",
 354 |         "SONARQUBE_ORGANIZATION": "your-organization-key"
 355 |       }
 356 |     }
 357 |   }
 358 | }
 359 | ```
 360 | 
 361 | ## Configuration
 362 | 
 363 | ### Environment Variables
 364 | 
 365 | #### Authentication (choose one method)
 366 | 
 367 | | Variable                 | Description                                   | Required | Default |
 368 | | ------------------------ | --------------------------------------------- | -------- | ------- |
 369 | | **Token Authentication** |                                               |          |         |
 370 | | `SONARQUBE_TOKEN`        | Authentication token for SonarQube API access | ✅ Yes\* | -       |
 371 | | **Basic Authentication** |                                               |          |         |
 372 | | `SONARQUBE_USERNAME`     | Username for Basic authentication             | ✅ Yes\* | -       |
 373 | | `SONARQUBE_PASSWORD`     | Password for Basic authentication             | ✅ Yes\* | -       |
 374 | | **System Passcode**      |                                               |          |         |
 375 | | `SONARQUBE_PASSCODE`     | System passcode for SonarQube authentication  | ✅ Yes\* | -       |
 376 | 
 377 | \*One authentication method is required. Token authentication takes priority if multiple methods are configured.
 378 | 
 379 | #### Connection Settings
 380 | 
 381 | | Variable                 | Description                                              | Required  | Default                 |
 382 | | ------------------------ | -------------------------------------------------------- | --------- | ----------------------- |
 383 | | `SONARQUBE_URL`          | URL of your SonarQube instance                           | ❌ No     | `https://sonarcloud.io` |
 384 | | `SONARQUBE_ORGANIZATION` | Organization key (required for SonarCloud)               | ❌ No\*\* | -                       |
 385 | | `LOG_FILE`               | Path to write log files (e.g., `/tmp/sonarqube-mcp.log`) | ❌ No     | -                       |
 386 | | `LOG_LEVEL`              | Minimum log level (DEBUG, INFO, WARN, ERROR)             | ❌ No     | `DEBUG`                 |
 387 | 
 388 | \*\*Required when using SonarCloud
 389 | 
 390 | #### HTTP Transport Settings (Advanced)
 391 | 
 392 | By default, the server uses stdio transport for communication with Claude Desktop. For programmatic access or running as a web service, HTTP transport is available:
 393 | 
 394 | | Variable                                   | Description                                  | Required | Default     |
 395 | | ------------------------------------------ | -------------------------------------------- | -------- | ----------- |
 396 | | `MCP_TRANSPORT_TYPE`                       | Transport type (`stdio` or `http`)           | ❌ No    | `stdio`     |
 397 | | `MCP_HTTP_PORT`                            | Port for HTTP server                         | ❌ No    | `3000`      |
 398 | | `MCP_HTTP_SESSION_TIMEOUT`                 | Session timeout in milliseconds              | ❌ No    | `1800000`   |
 399 | | `MCP_HTTP_ALLOWED_HOSTS`                   | Comma-separated list of allowed hosts        | ❌ No    | `localhost` |
 400 | | `MCP_HTTP_ALLOWED_ORIGINS`                 | Comma-separated list of allowed CORS origins | ❌ No    | `*`         |
 401 | | `MCP_HTTP_ENABLE_DNS_REBINDING_PROTECTION` | Enable DNS rebinding protection              | ❌ No    | `false`     |
 402 | 
 403 | ### Authentication Methods
 404 | 
 405 | The server supports three authentication methods, with important differences between SonarQube versions:
 406 | 
 407 | #### 1. Token Authentication (Recommended)
 408 | 
 409 | ##### SonarQube 10.0+ (Bearer Token)
 410 | 
 411 | - Starting with SonarQube 10.0, Bearer token authentication is the recommended approach
 412 | - Most secure and flexible option
 413 | - Tokens can have limited permissions
 414 | - Configuration:
 415 |   ```json
 416 |   {
 417 |     "env": {
 418 |       "SONARQUBE_TOKEN": "your-token-here"
 419 |     }
 420 |   }
 421 |   ```
 422 | 
 423 | ##### SonarQube < 10.0 (Token as Username)
 424 | 
 425 | - For versions before 10.0, tokens must be sent as the username in Basic authentication
 426 | - No password is required when using a token as username
 427 | - The server automatically handles this based on your SonarQube version
 428 | - Configuration remains the same - just use `SONARQUBE_USERNAME` with the token value:
 429 |   ```json
 430 |   {
 431 |     "env": {
 432 |       "SONARQUBE_USERNAME": "your-token-here"
 433 |     }
 434 |   }
 435 |   ```
 436 | 
 437 | #### 2. Basic Authentication
 438 | 
 439 | - Traditional username and password authentication
 440 | - Suitable for self-hosted SonarQube instances
 441 | - May not work with SonarCloud if 2FA is enabled
 442 | - Configuration:
 443 |   ```json
 444 |   {
 445 |     "env": {
 446 |       "SONARQUBE_USERNAME": "your-username",
 447 |       "SONARQUBE_PASSWORD": "your-password"
 448 |     }
 449 |   }
 450 |   ```
 451 | 
 452 | #### 3. System Passcode
 453 | 
 454 | - Special authentication for SonarQube system administration
 455 | - Typically used for automated deployment scenarios
 456 | - Configuration:
 457 |   ```json
 458 |   {
 459 |     "env": {
 460 |       "SONARQUBE_PASSCODE": "your-system-passcode"
 461 |     }
 462 |   }
 463 |   ```
 464 | 
 465 | **Note:** Token authentication takes priority if multiple authentication methods are configured. The server will automatically use the appropriate authentication strategy based on your SonarQube version.
 466 | 
 467 | ### SonarCloud vs SonarQube
 468 | 
 469 | **For SonarCloud:**
 470 | 
 471 | - Set `SONARQUBE_URL` to `https://sonarcloud.io`
 472 | - `SONARQUBE_ORGANIZATION` is required
 473 | - Token authentication is recommended
 474 | 
 475 | **For SonarQube Server:**
 476 | 
 477 | - Set `SONARQUBE_URL` to your instance URL
 478 | - `SONARQUBE_ORGANIZATION` is typically not needed
 479 | - All authentication methods are supported
 480 | 
 481 | ### HTTP Transport Mode
 482 | 
 483 | The server supports HTTP transport for programmatic access and web service deployments. This enables integration with custom clients and web applications.
 484 | 
 485 | #### Running as an HTTP Server
 486 | 
 487 | Start the server with HTTP transport:
 488 | 
 489 | ```bash
 490 | # Using environment variables
 491 | MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3000 npx sonarqube-mcp-server
 492 | 
 493 | # With Docker
 494 | docker run -i --rm \
 495 |   -p 3000:3000 \
 496 |   -e MCP_TRANSPORT_TYPE=http \
 497 |   -e MCP_HTTP_PORT=3000 \
 498 |   -e SONARQUBE_URL=https://sonarcloud.io \
 499 |   -e SONARQUBE_TOKEN=your-token \
 500 |   sapientpants/sonarqube-mcp-server:latest
 501 | ```
 502 | 
 503 | #### HTTP API Endpoints
 504 | 
 505 | When running in HTTP mode, the server exposes the following endpoints:
 506 | 
 507 | - `GET /health` - Health check endpoint
 508 | - `POST /session` - Create a new session
 509 | - `DELETE /session/:sessionId` - Close a session
 510 | - `POST /mcp` - Execute MCP requests
 511 | - `GET /events/:sessionId` - Server-sent events for notifications
 512 | 
 513 | #### Example HTTP Client
 514 | 
 515 | See [examples/http-client.ts](examples/http-client.ts) for a complete TypeScript client example.
 516 | 
 517 | Basic usage with curl:
 518 | 
 519 | ```bash
 520 | # Health check
 521 | curl http://localhost:3000/health
 522 | 
 523 | # Create session
 524 | SESSION_ID=$(curl -X POST http://localhost:3000/session | jq -r .sessionId)
 525 | 
 526 | # Execute MCP request
 527 | curl -X POST http://localhost:3000/mcp \
 528 |   -H "Content-Type: application/json" \
 529 |   -d "{
 530 |     \"sessionId\": \"$SESSION_ID\",
 531 |     \"method\": \"tools/list\",
 532 |     \"params\": {}
 533 |   }"
 534 | 
 535 | # Close session
 536 | curl -X DELETE http://localhost:3000/session/$SESSION_ID
 537 | ```
 538 | 
 539 | #### Security Considerations
 540 | 
 541 | When running in HTTP mode:
 542 | 
 543 | 1. **Enable DNS rebinding protection** for public deployments:
 544 | 
 545 |    ```bash
 546 |    MCP_HTTP_ENABLE_DNS_REBINDING_PROTECTION=true
 547 |    ```
 548 | 
 549 | 2. **Configure CORS** for browser-based clients:
 550 | 
 551 |    ```bash
 552 |    MCP_HTTP_ALLOWED_ORIGINS=https://yourapp.com,https://anotherapp.com
 553 |    ```
 554 | 
 555 | 3. **Set session timeouts** appropriately:
 556 | 
 557 |    ```bash
 558 |    MCP_HTTP_SESSION_TIMEOUT=900000  # 15 minutes
 559 |    ```
 560 | 
 561 | 4. **Use HTTPS** in production (configure through a reverse proxy like nginx)
 562 | 
 563 | ### Elicitation Configuration (Experimental)
 564 | 
 565 | The server supports interactive user input through MCP's elicitation capability. This feature is opt-in and requires compatible MCP clients.
 566 | 
 567 | **Environment Variables:**
 568 | 
 569 | - `SONARQUBE_MCP_ELICITATION`: Set to `true` to enable elicitation
 570 | - `SONARQUBE_MCP_BULK_THRESHOLD`: Number of items before confirmation (default: 5)
 571 | - `SONARQUBE_MCP_REQUIRE_COMMENTS`: Set to `true` to require comments for resolutions
 572 | - `SONARQUBE_MCP_INTERACTIVE_SEARCH`: Set to `true` for interactive disambiguation
 573 | 
 574 | **Example Configuration:**
 575 | 
 576 | ```json
 577 | {
 578 |   "mcpServers": {
 579 |     "sonarqube": {
 580 |       "command": "npx",
 581 |       "args": ["-y", "sonarqube-mcp-server@latest"],
 582 |       "env": {
 583 |         "SONARQUBE_URL": "https://sonarcloud.io",
 584 |         "SONARQUBE_TOKEN": "your-token",
 585 |         "SONARQUBE_MCP_ELICITATION": "true",
 586 |         "SONARQUBE_MCP_BULK_THRESHOLD": "10",
 587 |         "SONARQUBE_MCP_REQUIRE_COMMENTS": "true"
 588 |       }
 589 |     }
 590 |   }
 591 | }
 592 | ```
 593 | 
 594 | **Features When Enabled:**
 595 | 
 596 | 1. **Bulk Operation Confirmation**: Prompts for confirmation before marking multiple issues
 597 | 2. **Comment Collection**: Collects explanatory comments when marking issues as false positive or won't fix
 598 | 3. **Authentication Setup**: Guides through authentication setup when credentials are missing
 599 | 4. **Search Disambiguation**: Helps select from multiple matching components or projects
 600 | 
 601 | **Note:** This feature requires MCP clients that support elicitation. Not all clients may support this capability.
 602 | 
 603 | ### Logging Configuration
 604 | 
 605 | The server supports file-based logging for debugging and monitoring. Since MCP servers use stdout for protocol communication, logs are written to a file instead of stdout/stderr to avoid interference.
 606 | 
 607 | **Enable Logging:**
 608 | 
 609 | ```json
 610 | {
 611 |   "mcpServers": {
 612 |     "sonarqube": {
 613 |       "command": "npx",
 614 |       "args": ["-y", "sonarqube-mcp-server@latest"],
 615 |       "env": {
 616 |         "SONARQUBE_URL": "https://sonarcloud.io",
 617 |         "SONARQUBE_TOKEN": "your-token-here",
 618 |         "SONARQUBE_ORGANIZATION": "your-org",
 619 |         "LOG_FILE": "/tmp/sonarqube-mcp.log",
 620 |         "LOG_LEVEL": "INFO"
 621 |       }
 622 |     }
 623 |   }
 624 | }
 625 | ```
 626 | 
 627 | **Log Levels:**
 628 | 
 629 | - `DEBUG`: Detailed information for debugging
 630 | - `INFO`: General information about server operation
 631 | - `WARN`: Warning events that might lead to issues
 632 | - `ERROR`: Error events (server continues running)
 633 | 
 634 | **Example Log Output:**
 635 | 
 636 | ```
 637 | 2024-01-15T10:30:45.123Z INFO [index] Starting SonarQube MCP server
 638 | 2024-01-15T10:30:45.234Z INFO [index] Environment variables validated successfully
 639 | 2024-01-15T10:30:45.345Z INFO [index] SonarQube client created successfully
 640 | 2024-01-15T10:30:45.456Z INFO [index] SonarQube MCP server started successfully
 641 | 2024-01-15T10:30:50.123Z DEBUG [index] Handling SonarQube projects request
 642 | 2024-01-15T10:30:50.567Z INFO [index] Successfully retrieved projects {"count": 5}
 643 | ```
 644 | 
 645 | ## Available Tools
 646 | 
 647 | ### Permission Requirements
 648 | 
 649 | Different SonarQube tools require different permission levels:
 650 | 
 651 | **Tools requiring Admin permissions:**
 652 | 
 653 | - `projects` - Lists all SonarQube projects with metadata (visibility, lastAnalysisDate, revision)
 654 | 
 655 | **Tools accessible to all users:**
 656 | 
 657 | - `components` - Search and navigate projects, directories, and files (requires 'Browse' permission on at least one project)
 658 | - All other tools require appropriate permissions based on the resources being accessed
 659 | 
 660 | #### Listing Projects
 661 | 
 662 | **For Administrators:**
 663 | Use the `projects` tool to get full project metadata including visibility, last analysis date, and revision info.
 664 | 
 665 | **For All Users:**
 666 | Use the `components` tool with project qualifier:
 667 | 
 668 | - "List all projects I have access to" → `components` with `qualifiers: ['TRK']`
 669 | - "Search for projects containing 'mobile'" → `components` with `query: 'mobile', qualifiers: ['TRK']`
 670 | 
 671 | The `components` tool provides a more accessible alternative for non-admin users to discover projects they have access to.
 672 | 
 673 | ### Project Management
 674 | 
 675 | #### `projects`
 676 | 
 677 | List all SonarQube projects with pagination support.
 678 | 
 679 | **Parameters:**
 680 | 
 681 | - `page` (optional): Page number for results pagination
 682 | - `page_size` (optional): Number of items per page
 683 | 
 684 | ### Metrics and Measures
 685 | 
 686 | #### `metrics`
 687 | 
 688 | Get available metrics from SonarQube.
 689 | 
 690 | **Parameters:**
 691 | 
 692 | - `page` (optional): Page number for results pagination
 693 | - `page_size` (optional): Number of items per page
 694 | 
 695 | #### `measures_component`
 696 | 
 697 | Get measures for a specific component.
 698 | 
 699 | **Parameters:**
 700 | 
 701 | - `component` (required): Component key
 702 | - `metric_keys` (required): Array of metric keys
 703 | - `additional_fields` (optional): Additional fields to return
 704 | - `branch` (optional): Branch name
 705 | - `pull_request` (optional): Pull request key
 706 | - `period` (optional): Period index
 707 | 
 708 | #### `measures_components`
 709 | 
 710 | Get measures for multiple components.
 711 | 
 712 | **Parameters:**
 713 | 
 714 | - `component_keys` (required): Array of component keys
 715 | - `metric_keys` (required): Array of metric keys
 716 | - Additional parameters same as `measures_component`
 717 | - `page` (optional): Page number
 718 | - `page_size` (optional): Items per page
 719 | 
 720 | #### `measures_history`
 721 | 
 722 | Get measures history for a component.
 723 | 
 724 | **Parameters:**
 725 | 
 726 | - `component` (required): Component key
 727 | - `metrics` (required): Array of metric keys
 728 | - `from` (optional): Start date (YYYY-MM-DD)
 729 | - `to` (optional): End date (YYYY-MM-DD)
 730 | - `branch` (optional): Branch name
 731 | - `pull_request` (optional): Pull request key
 732 | - `page` (optional): Page number
 733 | - `page_size` (optional): Items per page
 734 | 
 735 | ### Issue Management
 736 | 
 737 | #### `issues`
 738 | 
 739 | Search and filter SonarQube issues by severity, status, assignee, tag, file path, and more. Critical for dashboards, targeted clean-up sprints, security audits, and regression testing. Supports faceted search for aggregations.
 740 | 
 741 | **Component/File Path Filters:**
 742 | 
 743 | - `project_key` (optional): Single project key (backward compatible)
 744 | - `projects` (optional): Array of project keys for multi-project analysis
 745 | - `component_keys` (optional): Array of component keys (file paths, directories, or modules) - use this to filter issues by specific files or folders
 746 | - `components` (optional): Alias for component_keys
 747 | - `on_component_only` (optional): Boolean to return only issues on specified components, not sub-components
 748 | 
 749 | **Branch/PR Support:**
 750 | 
 751 | - `branch` (optional): Branch name for branch analysis
 752 | - `pull_request` (optional): Pull request ID for PR analysis
 753 | 
 754 | **Issue Filters:**
 755 | 
 756 | - `issues` (optional): Array of specific issue keys to retrieve
 757 | - `severity` (optional): Single severity (deprecated, use severities)
 758 | - `severities` (optional): Array of severities (INFO, MINOR, MAJOR, CRITICAL, BLOCKER)
 759 | - `statuses` (optional): Array of statuses (OPEN, CONFIRMED, REOPENED, RESOLVED, CLOSED)
 760 | - `resolutions` (optional): Array of resolutions (FALSE-POSITIVE, WONTFIX, FIXED, REMOVED)
 761 | - `resolved` (optional): Boolean filter for resolved/unresolved
 762 | - `types` (optional): Array of types (CODE_SMELL, BUG, VULNERABILITY, SECURITY_HOTSPOT)
 763 | 
 764 | **Clean Code Taxonomy (SonarQube 10.x+):**
 765 | 
 766 | - `clean_code_attribute_categories` (optional): Array (ADAPTABLE, CONSISTENT, INTENTIONAL, RESPONSIBLE)
 767 | - `impact_severities` (optional): Array (HIGH, MEDIUM, LOW)
 768 | - `impact_software_qualities` (optional): Array (MAINTAINABILITY, RELIABILITY, SECURITY)
 769 | - `issue_statuses` (optional): Array of new issue status values
 770 | 
 771 | **Rules and Tags:**
 772 | 
 773 | - `rules` (optional): Array of rule keys
 774 | - `tags` (optional): Array of issue tags - essential for security audits, regression testing, and categorized analysis
 775 | 
 776 | **Date Filters:**
 777 | 
 778 | - `created_after` (optional): Issues created after date (YYYY-MM-DD)
 779 | - `created_before` (optional): Issues created before date (YYYY-MM-DD)
 780 | - `created_at` (optional): Issues created on date (YYYY-MM-DD)
 781 | - `created_in_last` (optional): Issues created in last period (e.g., "30d", "1m")
 782 | 
 783 | **Assignment:**
 784 | 
 785 | - `assigned` (optional): Boolean filter for assigned/unassigned
 786 | - `assignees` (optional): Array of assignee logins - critical for targeted clean-up sprints and workload analysis
 787 | - `author` (optional): Single author login
 788 | - `authors` (optional): Array of author logins
 789 | 
 790 | **Security Standards:**
 791 | 
 792 | - `cwe` (optional): Array of CWE identifiers
 793 | - `owasp_top10` (optional): Array of OWASP Top 10 categories
 794 | - `owasp_top10_v2021` (optional): Array of OWASP Top 10 2021 categories
 795 | - `sans_top25` (optional): Array of SANS Top 25 categories
 796 | - `sonarsource_security` (optional): Array of SonarSource security categories
 797 | - `sonarsource_security_category` (optional): Additional security categories
 798 | 
 799 | **Other Filters:**
 800 | 
 801 | - `languages` (optional): Array of programming languages
 802 | - `facets` (optional): Array of facets to aggregate
 803 | - `facet_mode` (optional): Facet aggregation mode ('effort' or 'count')
 804 | - `since_leak_period` (optional): Boolean for leak period filter (deprecated)
 805 | - `in_new_code_period` (optional): Boolean for new code period filter
 806 | 
 807 | **Sorting:**
 808 | 
 809 | - `s` (optional): Sort field (e.g., 'SEVERITY', 'CREATION_DATE', 'UPDATE_DATE')
 810 | - `asc` (optional): Boolean for ascending sort direction (default: false)
 811 | 
 812 | **Response Control:**
 813 | 
 814 | - `additional_fields` (optional): Array of additional fields to include
 815 | - `page` (optional): Page number for pagination
 816 | - `page_size` (optional): Number of items per page
 817 | 
 818 | **Faceted Search (Dashboard Support):**
 819 | 
 820 | - `facets` (optional): Array of facets to compute for aggregations. Available facets: severities, statuses, resolutions, rules, tags, types, authors, assignees, languages, etc.
 821 | - `facet_mode` (optional): Mode for facet computation: 'count' (number of issues) or 'effort' (remediation effort)
 822 | 
 823 | **Example Use Cases:**
 824 | 
 825 | 1. **Dashboard Query** - Get issue counts by severity and assignee:
 826 | 
 827 | ```json
 828 | {
 829 |   "project_key": "my-project",
 830 |   "facets": ["severities", "assignees", "tags"],
 831 |   "facet_mode": "count"
 832 | }
 833 | ```
 834 | 
 835 | 1. **Security Audit** - Find critical security issues in authentication modules:
 836 | 
 837 | ```json
 838 | {
 839 |   "project_key": "my-project",
 840 |   "component_keys": ["src/auth/", "src/security/"],
 841 |   "tags": ["security", "vulnerability"],
 842 |   "severities": ["CRITICAL", "BLOCKER"],
 843 |   "statuses": ["OPEN", "REOPENED"]
 844 | }
 845 | ```
 846 | 
 847 | 1. **Sprint Planning** - Get open issues for specific team members:
 848 | 
 849 | ```json
 850 | {
 851 |   "project_key": "my-project",
 852 |   "assignees": ["[email protected]", "[email protected]"],
 853 |   "statuses": ["OPEN", "CONFIRMED"],
 854 |   "facets": ["severities", "types"],
 855 |   "facet_mode": "effort"
 856 | }
 857 | ```
 858 | 
 859 | 1. **File-Specific Analysis** - Issues in a specific file:
 860 | 
 861 | ```json
 862 | {
 863 |   "project_key": "my-project",
 864 |   "component_keys": ["src/main/java/com/example/PaymentService.java"],
 865 |   "on_component_only": true
 866 | }
 867 | ```
 868 | 
 869 | ### Component Navigation
 870 | 
 871 | #### `components`
 872 | 
 873 | Search and navigate SonarQube components (projects, directories, files). Supports text search, filtering by type/language, and tree navigation.
 874 | 
 875 | **Search Parameters:**
 876 | 
 877 | - `query` (optional): Text search query
 878 | - `qualifiers` (optional): Array of component types (TRK, DIR, FIL, UTS, BRC, APP, VW, SVW, LIB)
 879 | - `language` (optional): Programming language filter
 880 | 
 881 | **Tree Navigation Parameters:**
 882 | 
 883 | - `component` (optional): Component key for tree navigation
 884 | - `strategy` (optional): Tree traversal strategy ('all', 'children', 'leaves')
 885 | 
 886 | **Common Parameters:**
 887 | 
 888 | - `asc` (optional): Sort ascending/descending
 889 | - `ps` (optional): Page size (default: 100, max: 500)
 890 | - `p` (optional): Page number
 891 | - `branch` (optional): Branch name
 892 | - `pullRequest` (optional): Pull request ID
 893 | 
 894 | **Component Qualifiers:**
 895 | 
 896 | - `TRK`: Project
 897 | - `DIR`: Directory
 898 | - `FIL`: File
 899 | - `UTS`: Unit Test
 900 | - `BRC`: Branch
 901 | - `APP`: Application
 902 | - `VW`: View
 903 | - `SVW`: Sub-view
 904 | - `LIB`: Library
 905 | 
 906 | **Example Use Cases:**
 907 | 
 908 | 1. **Find specific files:**
 909 | 
 910 | ```json
 911 | {
 912 |   "query": "UserService",
 913 |   "qualifiers": ["FIL"]
 914 | }
 915 | ```
 916 | 
 917 | 1. **List all test files in a project:**
 918 | 
 919 | ```json
 920 | {
 921 |   "component": "my-project",
 922 |   "qualifiers": ["UTS"]
 923 | }
 924 | ```
 925 | 
 926 | 1. **Navigate directory structure:**
 927 | 
 928 | ```json
 929 | {
 930 |   "component": "my-project:src/main",
 931 |   "strategy": "children",
 932 |   "qualifiers": ["DIR", "FIL"]
 933 | }
 934 | ```
 935 | 
 936 | 1. **Search for components by language:**
 937 | 
 938 | ```json
 939 | {
 940 |   "language": "java",
 941 |   "qualifiers": ["FIL"],
 942 |   "query": "Controller"
 943 | }
 944 | ```
 945 | 
 946 | 1. **Get project list:**
 947 | 
 948 | ```json
 949 | {
 950 |   "qualifiers": ["TRK"]
 951 | }
 952 | ```
 953 | 
 954 | ### Security Hotspots
 955 | 
 956 | #### `hotspots`
 957 | 
 958 | Search for security hotspots with specialized filters for security review workflows.
 959 | 
 960 | **Parameters:**
 961 | 
 962 | - `project_key` (optional): Project key to filter hotspots
 963 | - `branch` (optional): Branch name for branch analysis
 964 | - `pull_request` (optional): Pull request ID for PR analysis
 965 | - `status` (optional): Hotspot status (TO_REVIEW, REVIEWED)
 966 | - `resolution` (optional): Hotspot resolution (FIXED, SAFE)
 967 | - `files` (optional): Array of file paths to filter
 968 | - `assigned_to_me` (optional): Boolean to show only assigned hotspots
 969 | - `since_leak_period` (optional): Boolean for leak period filter
 970 | - `in_new_code_period` (optional): Boolean for new code period filter
 971 | - `page` (optional): Page number for pagination
 972 | - `page_size` (optional): Number of items per page
 973 | 
 974 | #### `hotspot`
 975 | 
 976 | Get detailed information about a specific security hotspot including security context.
 977 | 
 978 | **Parameters:**
 979 | 
 980 | - `hotspot_key` (required): The unique key of the hotspot
 981 | 
 982 | **Returns:**
 983 | 
 984 | - Detailed hotspot information including:
 985 |   - Security category and vulnerability probability
 986 |   - Rule information and security context
 987 |   - Changelog and comments
 988 |   - Code flows and locations
 989 | 
 990 | #### `update_hotspot_status`
 991 | 
 992 | Update the status of a security hotspot (requires appropriate permissions).
 993 | 
 994 | **Parameters:**
 995 | 
 996 | - `hotspot_key` (required): The unique key of the hotspot
 997 | - `status` (required): New status (TO_REVIEW, REVIEWED)
 998 | - `resolution` (optional): Resolution when status is REVIEWED (FIXED, SAFE)
 999 | - `comment` (optional): Comment explaining the status change
1000 | 
1001 | ### Quality Gates
1002 | 
1003 | #### `quality_gates`
1004 | 
1005 | List available quality gates.
1006 | 
1007 | No parameters required.
1008 | 
1009 | #### `quality_gate`
1010 | 
1011 | Get quality gate conditions.
1012 | 
1013 | **Parameters:**
1014 | 
1015 | - `id` (required): Quality gate ID
1016 | 
1017 | #### `quality_gate_status`
1018 | 
1019 | Get project quality gate status.
1020 | 
1021 | **Parameters:**
1022 | 
1023 | - `project_key` (required): Project key
1024 | - `branch` (optional): Branch name
1025 | - `pull_request` (optional): Pull request key
1026 | 
1027 | ### Source Code
1028 | 
1029 | #### `source_code`
1030 | 
1031 | View source code with issues highlighted.
1032 | 
1033 | **Parameters:**
1034 | 
1035 | - `key` (required): File key
1036 | - `from` (optional): Start line
1037 | - `to` (optional): End line
1038 | - `branch` (optional): Branch name
1039 | - `pull_request` (optional): Pull request key
1040 | 
1041 | #### `scm_blame`
1042 | 
1043 | Get SCM blame information for source code.
1044 | 
1045 | **Parameters:**
1046 | 
1047 | - Same as `source_code`
1048 | 
1049 | ### System Monitoring
1050 | 
1051 | #### `system_health`
1052 | 
1053 | Get the health status of the SonarQube instance.
1054 | 
1055 | No parameters required.
1056 | 
1057 | #### `system_status`
1058 | 
1059 | Get the status of the SonarQube instance.
1060 | 
1061 | No parameters required.
1062 | 
1063 | #### `system_ping`
1064 | 
1065 | Ping the SonarQube instance to check if it is up.
1066 | 
1067 | No parameters required.
1068 | 
1069 | ### Issue Resolution and Management
1070 | 
1071 | #### `markIssueFalsePositive`
1072 | 
1073 | Mark an issue as false positive.
1074 | 
1075 | **Parameters:**
1076 | 
1077 | - `issue_key` (required): The key of the issue to mark
1078 | - `comment` (optional): Comment explaining why it's a false positive
1079 | 
1080 | #### `markIssueWontFix`
1081 | 
1082 | Mark an issue as won't fix.
1083 | 
1084 | **Parameters:**
1085 | 
1086 | - `issue_key` (required): The key of the issue to mark
1087 | - `comment` (optional): Comment explaining why it won't be fixed
1088 | 
1089 | #### `markIssuesFalsePositive`
1090 | 
1091 | Mark multiple issues as false positive in bulk.
1092 | 
1093 | **Parameters:**
1094 | 
1095 | - `issue_keys` (required): Array of issue keys to mark
1096 | - `comment` (optional): Comment applying to all issues
1097 | 
1098 | #### `markIssuesWontFix`
1099 | 
1100 | Mark multiple issues as won't fix in bulk.
1101 | 
1102 | **Parameters:**
1103 | 
1104 | - `issue_keys` (required): Array of issue keys to mark
1105 | - `comment` (optional): Comment applying to all issues
1106 | 
1107 | #### `addCommentToIssue`
1108 | 
1109 | Add a comment to a SonarQube issue.
1110 | 
1111 | **Parameters:**
1112 | 
1113 | - `issue_key` (required): The key of the issue to comment on
1114 | - `text` (required): The comment text (supports markdown formatting)
1115 | 
1116 | #### `assignIssue`
1117 | 
1118 | Assign a SonarQube issue to a user or unassign it.
1119 | 
1120 | **Parameters:**
1121 | 
1122 | - `issueKey` (required): The key of the issue to assign
1123 | - `assignee` (optional): Username of the assignee. Leave empty to unassign the issue
1124 | 
1125 | **Example usage:**
1126 | 
1127 | ```json
1128 | {
1129 |   "issueKey": "PROJECT-123",
1130 |   "assignee": "john.doe"
1131 | }
1132 | ```
1133 | 
1134 | ## Usage Examples
1135 | 
1136 | ### Basic Project Analysis
1137 | 
1138 | ```
1139 | "List all my SonarQube projects"
1140 | "Show me the code coverage for project xyz"
1141 | "What metrics are available for analysis?"
1142 | ```
1143 | 
1144 | ### Issue Investigation
1145 | 
1146 | ```
1147 | "Show me all critical bugs in project abc"
1148 | "Find security vulnerabilities in the main branch"
1149 | "List all code smells created in the last week"
1150 | "Show unresolved issues assigned to john.doe"
1151 | "Analyze issues in the feature/new-login branch"
1152 | "Compare issues between main and develop branches"
1153 | "Find issues across multiple projects: proj1, proj2, proj3"
1154 | "Show me issues sorted by severity in descending order"
1155 | "Find all issues with clean code impact on reliability"
1156 | ```
1157 | 
1158 | ### Component Navigation
1159 | 
1160 | ```
1161 | "Find all files containing 'UserService' in their name"
1162 | "List all test files in my project"
1163 | "Show me the directory structure of src/main"
1164 | "Find all Java controller files"
1165 | "List all projects in SonarQube"
1166 | "Navigate to the authentication module"
1167 | "Search for TypeScript files in the frontend directory"
1168 | "Show me all directories under src/components"
1169 | ```
1170 | 
1171 | ### Issue Management
1172 | 
1173 | ```
1174 | "Assign issue PROJECT-123 to john.doe"
1175 | "Unassign issue PROJECT-456"
1176 | "Mark issue ABC-789 as false positive with comment: 'Test code only'"
1177 | "Add comment to issue XYZ-111: 'Fixed in commit abc123'"
1178 | "Bulk mark issues DEF-222, DEF-223 as won't fix"
1179 | ```
1180 | 
1181 | ### Quality Monitoring
1182 | 
1183 | ```
1184 | "Check the quality gate status for my main project"
1185 | "Show me the code coverage history for the last month"
1186 | "What are the quality gate conditions?"
1187 | "Compare metrics between develop and main branches"
1188 | ```
1189 | 
1190 | ### Security Hotspot Review
1191 | 
1192 | ```
1193 | "Find all security hotspots that need review in project xyz"
1194 | "Show me hotspots in the authentication module"
1195 | "Get details for hotspot HSP-12345"
1196 | "List all hotspots assigned to me"
1197 | "Mark hotspot HSP-12345 as safe with explanation"
1198 | "Find hotspots in the new code period"
1199 | "Show security hotspots in pull request #42"
1200 | ```
1201 | 
1202 | ### Source Code Analysis
1203 | 
1204 | ```
1205 | "Show me the source code for file xyz with issues highlighted"
1206 | "Get blame information for the problematic file"
1207 | "View issues in the authentication module"
1208 | ```
1209 | 
1210 | ### System Health
1211 | 
1212 | ```
1213 | "Check if SonarQube is running"
1214 | "What's the health status of the SonarQube instance?"
1215 | "Show me the system status"
1216 | ```
1217 | 
1218 | ## Architecture
1219 | 
1220 | The SonarQube MCP Server follows a modular architecture:
1221 | 
1222 | ```
1223 | ┌─────────────────┐     ┌──────────────────┐     ┌─────────────────┐
1224 | │  Claude Desktop │────▶│  MCP Server      │────▶│  SonarQube API  │
1225 | │  (MCP Client)   │◀────│  (index.ts)      │◀────│                 │
1226 | └─────────────────┘     └──────────────────┘     └─────────────────┘
1227 |                                │
1228 |                                ▼
1229 |                         ┌──────────────────┐
1230 |                         │  SonarQube       │
1231 |                         │  Client          │
1232 |                         │  (sonarqube.ts)  │
1233 |                         └──────────────────┘
1234 |                                │
1235 |                                ▼
1236 |                         ┌──────────────────┐
1237 |                         │  API Module      │
1238 |                         │  (api.ts)        │
1239 |                         └──────────────────┘
1240 | ```
1241 | 
1242 | ### Key Components
1243 | 
1244 | 1. **MCP Server (`index.ts`)**: Main entry point that initializes the MCP server and registers all available tools
1245 | 2. **SonarQube Client (`sonarqube.ts`)**: Handles business logic and parameter transformation
1246 | 3. **API Module (`api.ts`)**: Manages HTTP requests to the SonarQube API
1247 | 4. **Type Definitions**: TypeScript interfaces for type safety
1248 | 
1249 | ### Data Flow
1250 | 
1251 | 1. MCP clients make requests through registered tools
1252 | 2. Tool handlers validate and transform parameters
1253 | 3. SonarQube client methods process the requests
1254 | 4. API module executes HTTP requests
1255 | 5. Responses are formatted and returned to the client
1256 | 
1257 | ## Development
1258 | 
1259 | ### Prerequisites
1260 | 
1261 | - Node.js 22 or higher
1262 | - pnpm 10.17.0 or higher
1263 | - Docker (for container builds)
1264 | 
1265 | ### Setup
1266 | 
1267 | 1. Clone the repository:
1268 | 
1269 | ```bash
1270 | git clone https://github.com/sapientpants/sonarqube-mcp-server.git
1271 | cd sonarqube-mcp-server
1272 | ```
1273 | 
1274 | 1. Install dependencies:
1275 | 
1276 | ```bash
1277 | pnpm install
1278 | ```
1279 | 
1280 | 1. Build the project:
1281 | 
1282 | ```bash
1283 | pnpm build
1284 | ```
1285 | 
1286 | ### Development Commands
1287 | 
1288 | ```bash
1289 | # Install dependencies
1290 | pnpm install
1291 | 
1292 | # Build the project
1293 | pnpm build
1294 | 
1295 | # Run in development mode with auto-reload
1296 | pnpm dev
1297 | 
1298 | # Run tests
1299 | pnpm test
1300 | 
1301 | # Run tests with coverage
1302 | pnpm test:coverage
1303 | 
1304 | # Lint the code
1305 | pnpm lint
1306 | 
1307 | # Fix linting issues
1308 | pnpm lint:fix
1309 | 
1310 | # Check types
1311 | pnpm check-types
1312 | 
1313 | # Format code
1314 | pnpm format
1315 | 
1316 | # Run all validations
1317 | pnpm validate
1318 | 
1319 | # Inspect MCP schema
1320 | pnpm inspect
1321 | ```
1322 | 
1323 | ### Testing
1324 | 
1325 | The project uses Jest for testing with:
1326 | 
1327 | - Unit tests for all major components
1328 | - Mocked HTTP responses using `nock`
1329 | - Coverage reporting
1330 | - TypeScript support
1331 | 
1332 | Run specific test files:
1333 | 
1334 | ```bash
1335 | NODE_ENV=test NODE_OPTIONS='--experimental-vm-modules --no-warnings' jest src/__tests__/file-name.test.ts
1336 | ```
1337 | 
1338 | ### Code Quality
1339 | 
1340 | The project maintains high code quality through:
1341 | 
1342 | - TypeScript for type safety
1343 | - ESLint for code linting
1344 | - Prettier for code formatting
1345 | - Jest for testing
1346 | - SonarCloud for continuous code analysis
1347 | 
1348 | ## Common Issues and Solutions
1349 | 
1350 | ### Quick Fixes
1351 | 
1352 | #### "Authentication failed"
1353 | 
1354 | - **Cause**: Invalid or expired token
1355 | - **Solution**: Generate a new token in SonarQube/SonarCloud
1356 | 
1357 | #### "Project not found"
1358 | 
1359 | - **Cause**: Incorrect project key or insufficient permissions
1360 | - **Solution**: Verify the project key and check token permissions
1361 | 
1362 | #### "Organization required"
1363 | 
1364 | - **Cause**: Using SonarCloud without organization parameter
1365 | - **Solution**: Add `SONARQUBE_ORGANIZATION` to your configuration
1366 | 
1367 | #### "Connection refused"
1368 | 
1369 | - **Cause**: Incorrect URL or network issues
1370 | - **Solution**: Verify `SONARQUBE_URL` and network connectivity
1371 | 
1372 | #### "No output or errors visible"
1373 | 
1374 | - **Cause**: Errors might be happening but not visible in Claude Desktop
1375 | - **Solution**: Enable logging with `LOG_FILE` and check the log file for detailed error messages
1376 | 
1377 | ### FAQ
1378 | 
1379 | **Q: Can I use this with both SonarQube and SonarCloud?**
1380 | A: Yes! Set the appropriate `SONARQUBE_URL` and include `SONARQUBE_ORGANIZATION` for SonarCloud.
1381 | 
1382 | **Q: What permissions does my token need?**
1383 | A: The token needs "Execute Analysis" permission and access to the projects you want to analyze.
1384 | 
1385 | **Q: How do I filter issues by multiple criteria?**
1386 | A: The `issues` tool supports extensive filtering. You can combine multiple parameters like severity, type, status, and date ranges.
1387 | 
1388 | **Q: Can I analyze pull requests?**
1389 | A: Yes! Many tools support `branch` and `pull_request` parameters for branch and PR analysis.
1390 | 
1391 | ## Troubleshooting
1392 | 
1393 | ### Common Error Messages and Solutions
1394 | 
1395 | #### Authentication Errors
1396 | 
1397 | ##### Error: "Authentication failed"
1398 | 
1399 | - **Solution**: Check that your SONARQUBE_TOKEN is valid and not expired. Generate a new token from your SonarQube user profile.
1400 | 
1401 | ##### Error: "No SonarQube authentication configured"
1402 | 
1403 | - **Solution**: Set one of the following authentication methods:
1404 |   - `SONARQUBE_TOKEN` for token-based authentication (recommended)
1405 |   - `SONARQUBE_USERNAME` and `SONARQUBE_PASSWORD` for basic authentication
1406 |   - `SONARQUBE_PASSCODE` for system passcode authentication
1407 | 
1408 | #### Authorization Errors
1409 | 
1410 | ##### Error: "Access denied"
1411 | 
1412 | - **Solution**: Ensure your token has the required permissions for the operation. Common required permissions:
1413 |   - "Execute Analysis" for code analysis
1414 |   - "Browse" for reading project data
1415 |   - "Administer Issues" for issue management operations
1416 | 
1417 | #### Resource Not Found Errors
1418 | 
1419 | ##### Error: "Resource not found"
1420 | 
1421 | - **Solution**: Verify that:
1422 |   - The project key/component exists in SonarQube
1423 |   - You have access to the resource
1424 |   - The URL path is correct (no typos in project keys)
1425 | 
1426 | #### Network and Connection Errors
1427 | 
1428 | ##### Error: "Connection refused"
1429 | 
1430 | - **Solution**: Check that:
1431 |   - The SonarQube server is running
1432 |   - The SONARQUBE_URL is correct
1433 |   - There are no firewall rules blocking the connection
1434 | 
1435 | ##### Error: "Network error" or timeout errors
1436 | 
1437 | - **Solution**:
1438 |   - Verify your network connection
1439 |   - Check if the SonarQube server is accessible
1440 |   - Ensure the URL doesn't have a trailing slash
1441 |   - For self-hosted instances, verify SSL certificates
1442 | 
1443 | #### Rate Limiting
1444 | 
1445 | ##### Error: "Rate limit exceeded"
1446 | 
1447 | - **Solution**: The server automatically retries rate-limited requests with exponential backoff. If you continue to hit rate limits:
1448 |   - Reduce the frequency of your requests
1449 |   - Implement request batching where possible
1450 |   - Contact your SonarQube administrator to increase rate limits
1451 | 
1452 | #### Configuration Errors
1453 | 
1454 | ##### Error: "Invalid SONARQUBE_URL"
1455 | 
1456 | - **Solution**: Provide a valid URL including the protocol:
1457 |   - ✅ Correct: `https://sonarcloud.io`
1458 |   - ✅ Correct: `https://sonarqube.example.com`
1459 |   - ❌ Wrong: `sonarcloud.io` (missing protocol)
1460 |   - ❌ Wrong: `https://sonarqube.example.com/` (trailing slash)
1461 | 
1462 | ### Debugging Tips
1463 | 
1464 | 1. **Enable Debug Logging**:
1465 | 
1466 |    ```bash
1467 |    export LOG_LEVEL=DEBUG
1468 |    ```
1469 | 
1470 | 2. **Check Environment Variables**:
1471 | 
1472 |    ```bash
1473 |    echo $SONARQUBE_URL
1474 |    echo $SONARQUBE_TOKEN
1475 |    echo $SONARQUBE_ORGANIZATION
1476 |    ```
1477 | 
1478 | 3. **Test Connection**:
1479 |    Use the `ping` tool to verify connectivity:
1480 | 
1481 |    ```bash
1482 |    # In your MCP client
1483 |    sonarqube.ping
1484 |    ```
1485 | 
1486 | 4. **Verify Permissions**:
1487 |    Use the `projects` tool to list accessible projects:
1488 |    ```bash
1489 |    # In your MCP client
1490 |    sonarqube.projects
1491 |    ```
1492 | 
1493 | ### Retry Behavior
1494 | 
1495 | The server automatically retries failed requests for transient errors:
1496 | 
1497 | - **Network errors**: Retried up to 3 times
1498 | - **Rate limiting**: Retried with exponential backoff
1499 | - **Server errors (5xx)**: Retried up to 3 times
1500 | 
1501 | Retry delays: 1s → 2s → 4s (capped at 10s)
1502 | 
1503 | ### Getting Help
1504 | 
1505 | If you continue to experience issues:
1506 | 
1507 | 1. Check the [GitHub Issues](https://github.com/sapientpants/sonarqube-mcp-server/issues) for similar problems
1508 | 2. Enable debug logging and collect error details
1509 | 3. Create a new issue with:
1510 |    - Error messages
1511 |    - Environment details (OS, Node version)
1512 |    - SonarQube version
1513 |    - Steps to reproduce
1514 | 
1515 | ## Contributing
1516 | 
1517 | We welcome contributions! Please see our [Contributing Guidelines](CONTRIBUTING.md) for details.
1518 | 
1519 | ### How to Contribute
1520 | 
1521 | 1. Fork the repository
1522 | 2. Create a feature branch (`git checkout -b feature/amazing-feature`)
1523 | 3. Commit your changes (`git commit -m 'Add amazing feature'`)
1524 | 4. Push to the branch (`git push origin feature/amazing-feature`)
1525 | 5. Open a Pull Request
1526 | 
1527 | ### Development Guidelines
1528 | 
1529 | - Write tests for new features
1530 | - Update documentation as needed
1531 | - Follow the existing code style
1532 | - Ensure all tests pass
1533 | - Add appropriate error handling
1534 | 
1535 | ## License
1536 | 
1537 | This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
1538 | 
1539 | ## External Resources
1540 | 
1541 | ### SonarQube Documentation
1542 | 
1543 | - [SonarQube Documentation](https://docs.sonarqube.org/latest/)
1544 | - [SonarCloud Documentation](https://docs.sonarcloud.io/)
1545 | - [Web API Documentation](https://docs.sonarqube.org/latest/extend/web-api/)
1546 | 
1547 | ### Model Context Protocol
1548 | 
1549 | - [MCP Documentation](https://modelcontextprotocol.io/)
1550 | - [MCP Specification](https://github.com/modelcontextprotocol/specification)
1551 | - [MCP TypeScript SDK](https://github.com/modelcontextprotocol/typescript-sdk)
1552 | 
1553 | ---
1554 | 
1555 | Made with ❤️ by the SonarQube MCP Server community
1556 | 
```

--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------

```markdown
 1 | # Security Policy
 2 | 
 3 | ## Supported Versions
 4 | 
 5 | The latest minor release will receive support for security updates. Users of older versions are requested to upgrade to the latest minor version.
 6 | 
 7 | | Version | Supported          |
 8 | | ------- | ------------------ |
 9 | | 1.4.x   | :white_check_mark: |
10 | | < 1.4.0 | :x:                |
11 | 
12 | ## Authentication Security Best Practices
13 | 
14 | The SonarQube MCP Server uses environment variables for authentication, which is appropriate for its design as a single-user local tool. Follow these best practices to ensure secure usage:
15 | 
16 | ### 1. Use Token Authentication
17 | 
18 | Token authentication is the most secure option and is strongly recommended:
19 | 
20 | - **Generate dedicated tokens** for the MCP server rather than reusing existing tokens
21 | - **Use minimal permissions** - create tokens with only the necessary read permissions
22 | - **Rotate tokens regularly** - establish a schedule for token rotation
23 | - **Revoke unused tokens** - immediately revoke tokens that are no longer needed
24 | 
25 | ### 2. Protect Configuration Files
26 | 
27 | Since credentials are stored in the MCP client's configuration file:
28 | 
29 | - **Check file permissions** - ensure configuration files are readable only by your user account
30 | - **Use secure storage** - on macOS, Claude Desktop stores config in `~/Library/Application Support/Claude/claude_desktop_config.json`
31 | - **Don't commit configs** - never commit configuration files containing credentials to version control
32 | - **Use password managers** - store tokens in a password manager and copy them when needed
33 | 
34 | ### 3. Authentication Method Security
35 | 
36 | Listed from most to least secure:
37 | 
38 | 1. **Token Authentication** (Recommended)
39 |    - Tokens can be scoped with limited permissions
40 |    - Can be revoked without changing passwords
41 |    - Works with all SonarQube versions
42 | 
43 | 2. **Basic Authentication**
44 |    - Use only when token auth is not available
45 |    - Requires transmitting username and password
46 |    - May not work with SonarCloud if 2FA is enabled
47 | 
48 | 3. **System Passcode**
49 |    - Only for special administrative scenarios
50 |    - Provides system-level access
51 |    - Use with extreme caution
52 | 
53 | ### 4. SonarQube-Specific Considerations
54 | 
55 | - **SonarQube 10.0+**: Uses Bearer token authentication (most secure)
56 | - **SonarQube < 10.0**: Tokens sent as username in Basic auth
57 | - **SonarCloud**: Always use token authentication, especially with 2FA enabled
58 | 
59 | ### 5. Environment Variable Security
60 | 
61 | When setting environment variables:
62 | 
63 | - **Avoid command history** - Use configuration files instead of export commands
64 | - **Clear sensitive variables** - Unset variables after use if set temporarily
65 | - **Use dedicated shells** - Run the MCP server in a dedicated terminal session
66 | 
67 | ### 6. Network Security
68 | 
69 | - **Use HTTPS** - Always connect to SonarQube instances over HTTPS
70 | - **Verify certificates** - Ensure SSL certificates are valid
71 | - **Use VPN** - When accessing internal SonarQube instances, use VPN
72 | 
73 | ## Security Architecture
74 | 
75 | The SonarQube MCP Server operates with the following security model:
76 | 
77 | - **Single-user design**: Each instance runs with one user's credentials
78 | - **Local execution**: Runs on the user's machine, not as a shared service
79 | - **Direct authentication**: Uses SonarQube's native authentication mechanisms
80 | - **No credential storage**: The server itself doesn't store credentials
81 | 
82 | ## Enterprise Security Considerations
83 | 
84 | While the current model is appropriate for local usage, enterprise deployments using MCP gateways provide:
85 | 
86 | - OAuth 2.1 resource server implementation at the gateway layer
87 | - Token validation and scoping per RFC8707
88 | - Multi-client authorization mechanisms
89 | - Enterprise authentication and authorization
90 | 
91 | ## Reporting a Vulnerability
92 | 
93 | To report a security issue, please email [email protected] with a description of the issue, the steps you took to create the issue, affected versions, and if known, mitigations for the issue. Our vulnerability management team will acknowledge receiving your email within 3 working days. This project follows a 90 day disclosure timeline.
94 | 
```

--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------

```markdown
  1 | # Contributor Covenant Code of Conduct
  2 | 
  3 | ## Our Pledge
  4 | 
  5 | We as members, contributors, and leaders pledge to make participation in our
  6 | community a harassment-free experience for everyone, regardless of age, body
  7 | size, visible or invisible disability, ethnicity, sex characteristics, gender
  8 | identity and expression, level of experience, education, socio-economic status,
  9 | nationality, personal appearance, race, religion, or sexual identity
 10 | and orientation.
 11 | 
 12 | We pledge to act and interact in ways that contribute to an open, welcoming,
 13 | diverse, inclusive, and healthy community.
 14 | 
 15 | ## Our Standards
 16 | 
 17 | Examples of behavior that contributes to a positive environment for our
 18 | community include:
 19 | 
 20 | - Demonstrating empathy and kindness toward other people
 21 | - Being respectful of differing opinions, viewpoints, and experiences
 22 | - Giving and gracefully accepting constructive feedback
 23 | - Accepting responsibility and apologizing to those affected by our mistakes,
 24 |   and learning from the experience
 25 | - Focusing on what is best not just for us as individuals, but for the
 26 |   overall community
 27 | 
 28 | Examples of unacceptable behavior include:
 29 | 
 30 | - The use of sexualized language or imagery, and sexual attention or
 31 |   advances of any kind
 32 | - Trolling, insulting or derogatory comments, and personal or political attacks
 33 | - Public or private harassment
 34 | - Publishing others' private information, such as a physical or email
 35 |   address, without their explicit permission
 36 | - Other conduct which could reasonably be considered inappropriate in a
 37 |   professional setting
 38 | 
 39 | ## Enforcement Responsibilities
 40 | 
 41 | Community leaders are responsible for clarifying and enforcing our standards of
 42 | acceptable behavior and will take appropriate and fair corrective action in
 43 | response to any behavior that they deem inappropriate, threatening, offensive,
 44 | or harmful.
 45 | 
 46 | Community leaders have the right and responsibility to remove, edit, or reject
 47 | comments, commits, code, wiki edits, issues, and other contributions that are
 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation
 49 | decisions when appropriate.
 50 | 
 51 | ## Scope
 52 | 
 53 | This Code of Conduct applies within all community spaces, and also applies when
 54 | an individual is officially representing the community in public spaces.
 55 | Examples of representing our community include using an official e-mail address,
 56 | posting via an official social media account, or acting as an appointed
 57 | representative at an online or offline event.
 58 | 
 59 | ## Enforcement
 60 | 
 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
 62 | reported to the community leaders responsible for enforcement at
 63 | [email protected].
 64 | All complaints will be reviewed and investigated promptly and fairly.
 65 | 
 66 | All community leaders are obligated to respect the privacy and security of the
 67 | reporter of any incident.
 68 | 
 69 | ## Enforcement Guidelines
 70 | 
 71 | Community leaders will follow these Community Impact Guidelines in determining
 72 | the consequences for any action they deem in violation of this Code of Conduct:
 73 | 
 74 | ### 1. Correction
 75 | 
 76 | **Community Impact**: Use of inappropriate language or other behavior deemed
 77 | unprofessional or unwelcome in the community.
 78 | 
 79 | **Consequence**: A private, written warning from community leaders, providing
 80 | clarity around the nature of the violation and an explanation of why the
 81 | behavior was inappropriate. A public apology may be requested.
 82 | 
 83 | ### 2. Warning
 84 | 
 85 | **Community Impact**: A violation through a single incident or series
 86 | of actions.
 87 | 
 88 | **Consequence**: A warning with consequences for continued behavior. No
 89 | interaction with the people involved, including unsolicited interaction with
 90 | those enforcing the Code of Conduct, for a specified period of time. This
 91 | includes avoiding interactions in community spaces as well as external channels
 92 | like social media. Violating these terms may lead to a temporary or
 93 | permanent ban.
 94 | 
 95 | ### 3. Temporary Ban
 96 | 
 97 | **Community Impact**: A serious violation of community standards, including
 98 | sustained inappropriate behavior.
 99 | 
100 | **Consequence**: A temporary ban from any sort of interaction or public
101 | communication with the community for a specified period of time. No public or
102 | private interaction with the people involved, including unsolicited interaction
103 | with those enforcing the Code of Conduct, is allowed during this period.
104 | Violating these terms may lead to a permanent ban.
105 | 
106 | ### 4. Permanent Ban
107 | 
108 | **Community Impact**: Demonstrating a pattern of violation of community
109 | standards, including sustained inappropriate behavior, harassment of an
110 | individual, or aggression toward or disparagement of classes of individuals.
111 | 
112 | **Consequence**: A permanent ban from any sort of public interaction within
113 | the community.
114 | 
115 | ## Attribution
116 | 
117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage],
118 | version 2.0, available at
119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
120 | 
121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct
122 | enforcement ladder](https://github.com/mozilla/diversity).
123 | 
124 | [homepage]: https://www.contributor-covenant.org
125 | 
126 | For answers to common questions about this code of conduct, see the FAQ at
127 | https://www.contributor-covenant.org/faq. Translations are available at
128 | https://www.contributor-covenant.org/translations.
129 | 
```

--------------------------------------------------------------------------------
/docs/security.md:
--------------------------------------------------------------------------------

```markdown
  1 | # Security Guide
  2 | 
  3 | ## Overview
  4 | 
  5 | This guide covers security best practices for the SonarQube MCP Server, focusing on authentication, credential management, and secure deployment patterns.
  6 | 
  7 | ## Authentication Methods
  8 | 
  9 | The server supports three authentication methods for connecting to SonarQube:
 10 | 
 11 | ### 1. Token Authentication (Recommended)
 12 | 
 13 | The most secure method for API access.
 14 | 
 15 | ```json
 16 | {
 17 |   "env": {
 18 |     "SONARQUBE_TOKEN": "squ_xxxxxxxxxxxxxxxx"
 19 |   }
 20 | }
 21 | ```
 22 | 
 23 | **Benefits:**
 24 | 
 25 | - Tokens can be scoped with limited permissions
 26 | - Easy to revoke without changing passwords
 27 | - No password exposure in logs or configs
 28 | - Works with both SonarCloud and SonarQube
 29 | 
 30 | **SonarQube Version Differences:**
 31 | 
 32 | - **SonarQube 10.0+**: Uses Bearer token authentication
 33 | - **SonarQube < 10.0**: Automatically uses token as username in Basic auth
 34 | 
 35 | ### 2. Basic Authentication
 36 | 
 37 | Traditional username/password authentication.
 38 | 
 39 | ```json
 40 | {
 41 |   "env": {
 42 |     "SONARQUBE_USERNAME": "your-username",
 43 |     "SONARQUBE_PASSWORD": "your-password"
 44 |   }
 45 | }
 46 | ```
 47 | 
 48 | **Considerations:**
 49 | 
 50 | - Suitable for self-hosted SonarQube instances
 51 | - May not work with SonarCloud if 2FA is enabled
 52 | - Passwords visible in environment variables
 53 | 
 54 | ### 3. System Passcode
 55 | 
 56 | Special authentication for system administration.
 57 | 
 58 | ```json
 59 | {
 60 |   "env": {
 61 |     "SONARQUBE_PASSCODE": "system-passcode"
 62 |   }
 63 | }
 64 | ```
 65 | 
 66 | **Use Cases:**
 67 | 
 68 | - Automated deployment scenarios
 69 | - System-level operations
 70 | - Emergency access
 71 | 
 72 | ## Credential Security Best Practices
 73 | 
 74 | ### 1. Token Management
 75 | 
 76 | **Creating Secure Tokens:**
 77 | 
 78 | 1. Log into SonarQube/SonarCloud
 79 | 2. Navigate to **My Account** → **Security**
 80 | 3. Generate tokens with minimal required permissions:
 81 |    - Read-only tokens for analysis
 82 |    - Write tokens only when needed
 83 |    - Project-specific tokens when possible
 84 | 
 85 | **Token Rotation:**
 86 | 
 87 | - Rotate tokens every 90 days
 88 | - Immediately revoke compromised tokens
 89 | - Use different tokens for different environments
 90 | 
 91 | ### 2. Credential Storage
 92 | 
 93 | **Local Development (Claude Desktop):**
 94 | 
 95 | - Credentials stored in Claude Desktop's config file
 96 | - Ensure proper file permissions (600 on Unix)
 97 | - Consider using OS keychain integration
 98 | 
 99 | **Docker Deployment:**
100 | 
101 | ```bash
102 | # Use Docker secrets
103 | docker secret create sonarqube-token token.txt
104 | docker run --secret sonarqube-token ...
105 | 
106 | # Or use environment file with restricted permissions
107 | chmod 600 .env
108 | docker run --env-file .env ...
109 | ```
110 | 
111 | **MCP Gateway Deployment:**
112 | 
113 | - Use gateway's secret management
114 | - Leverage vault integration if available
115 | - Rotate credentials at gateway level
116 | 
117 | ### 3. Environment Variable Security
118 | 
119 | **DO:**
120 | 
121 | - Use `.env` files with restricted permissions
122 | - Load secrets from secure sources at runtime
123 | - Use placeholder values in version control
124 | 
125 | **DON'T:**
126 | 
127 | - Commit credentials to version control
128 | - Log environment variables
129 | - Pass secrets via command line arguments
130 | 
131 | ## Network Security
132 | 
133 | ### 1. TLS/SSL Configuration
134 | 
135 | Always use HTTPS for SonarQube connections:
136 | 
137 | ```json
138 | {
139 |   "env": {
140 |     "SONARQUBE_URL": "https://sonarqube.example.com",
141 |     "NODE_TLS_REJECT_UNAUTHORIZED": "1"
142 |   }
143 | }
144 | ```
145 | 
146 | ### 2. Certificate Validation
147 | 
148 | For self-signed certificates:
149 | 
150 | ```bash
151 | # Add CA certificate to trusted store
152 | export NODE_EXTRA_CA_CERTS=/path/to/ca-cert.pem
153 | ```
154 | 
155 | Never disable certificate validation in production:
156 | 
157 | ```bash
158 | # INSECURE - Development only
159 | NODE_TLS_REJECT_UNAUTHORIZED=0
160 | ```
161 | 
162 | ## Deployment Security
163 | 
164 | ### 1. Container Security
165 | 
166 | **Image Security:**
167 | 
168 | - Use specific version tags, not `latest`
169 | - Scan images for vulnerabilities
170 | - Use minimal base images (Alpine)
171 | 
172 | **Runtime Security:**
173 | 
174 | ```yaml
175 | # docker-compose.yml
176 | services:
177 |   sonarqube-mcp:
178 |     image: sapientpants/sonarqube-mcp-server:1.7.0
179 |     user: '1001:1001' # Non-root user
180 |     read_only: true # Read-only filesystem
181 |     tmpfs:
182 |       - /tmp
183 |     security_opt:
184 |       - no-new-privileges:true
185 |     cap_drop:
186 |       - ALL
187 | ```
188 | 
189 | ### 2. Resource Limits
190 | 
191 | Prevent resource exhaustion:
192 | 
193 | ```yaml
194 | resources:
195 |   limits:
196 |     memory: '256M'
197 |     cpus: '0.5'
198 |   requests:
199 |     memory: '128M'
200 |     cpus: '0.1'
201 | ```
202 | 
203 | ### 3. Network Isolation
204 | 
205 | For stdio transport, no network exposure needed:
206 | 
207 | ```yaml
208 | networks:
209 |   internal:
210 |     driver: bridge
211 |     internal: true # No external access
212 | ```
213 | 
214 | ## Logging and Monitoring
215 | 
216 | ### 1. Secure Logging
217 | 
218 | Configure logging to avoid credential exposure:
219 | 
220 | ```json
221 | {
222 |   "env": {
223 |     "LOG_LEVEL": "INFO",
224 |     "LOG_FILE": "/logs/sonarqube-mcp.log"
225 |   }
226 | }
227 | ```
228 | 
229 | **Log Security:**
230 | 
231 | - Never log authentication tokens
232 | - Redact sensitive data in logs
233 | - Rotate logs regularly
234 | - Restrict log file access
235 | 
236 | ### 2. Monitoring Access
237 | 
238 | Track usage patterns:
239 | 
240 | - Monitor failed authentication attempts
241 | - Track unusual API usage patterns
242 | - Alert on circuit breaker activations
243 | 
244 | ## Security Checklist
245 | 
246 | ### Pre-Deployment
247 | 
248 | - [ ] Use token authentication instead of passwords
249 | - [ ] Create tokens with minimal required permissions
250 | - [ ] Store credentials securely
251 | - [ ] Use HTTPS for all SonarQube connections
252 | - [ ] Review and apply container security settings
253 | 
254 | ### Deployment
255 | 
256 | - [ ] Use specific version tags for images
257 | - [ ] Run containers as non-root user
258 | - [ ] Apply resource limits
259 | - [ ] Enable secure logging
260 | - [ ] Restrict file permissions on configs
261 | 
262 | ### Post-Deployment
263 | 
264 | - [ ] Regularly rotate tokens
265 | - [ ] Monitor logs for security events
266 | - [ ] Keep server and dependencies updated
267 | - [ ] Review access patterns periodically
268 | - [ ] Test disaster recovery procedures
269 | 
270 | ## Incident Response
271 | 
272 | ### Compromised Credentials
273 | 
274 | 1. **Immediate Actions:**
275 |    - Revoke compromised tokens in SonarQube
276 |    - Generate new tokens
277 |    - Update all deployments
278 | 
279 | 2. **Investigation:**
280 |    - Review access logs
281 |    - Check for unauthorized changes
282 |    - Identify exposure source
283 | 
284 | 3. **Prevention:**
285 |    - Implement stricter access controls
286 |    - Increase rotation frequency
287 |    - Add additional monitoring
288 | 
289 | ### Security Updates
290 | 
291 | Stay informed about security updates:
292 | 
293 | - Watch the [GitHub repository](https://github.com/sapientpants/sonarqube-mcp-server)
294 | - Subscribe to security advisories
295 | - Test updates in non-production first
296 | 
297 | ## Compliance Considerations
298 | 
299 | ### Data Privacy
300 | 
301 | - The server doesn't store any SonarQube data
302 | - All data remains in SonarQube
303 | - Consider data residency requirements
304 | 
305 | ### Audit Requirements
306 | 
307 | When deployed with MCP gateways:
308 | 
309 | - Leverage gateway audit capabilities
310 | - Track all access at gateway level
311 | - Maintain audit logs per compliance needs
312 | 
313 | ## Support
314 | 
315 | For security concerns:
316 | 
317 | - Report vulnerabilities via GitHub Security Advisory
318 | - Contact maintainers for sensitive issues
319 | - Check documentation for updates
320 | 
```

--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------

```markdown
  1 | # Contributing to SonarQube MCP Server
  2 | 
  3 | Thank you for your interest in contributing to the SonarQube MCP Server! This document provides guidelines and instructions for contributing to the project.
  4 | 
  5 | ## Code of Conduct
  6 | 
  7 | By participating in this project, you agree to abide by our code of conduct: be respectful, inclusive, and constructive in all interactions.
  8 | 
  9 | ## How to Contribute
 10 | 
 11 | ### Reporting Issues
 12 | 
 13 | 1. **Check existing issues** first to avoid duplicates
 14 | 2. **Use issue templates** when available
 15 | 3. **Provide detailed information**:
 16 |    - Steps to reproduce
 17 |    - Expected behavior
 18 |    - Actual behavior
 19 |    - Environment details (OS, Node version, etc.)
 20 |    - Error messages and logs
 21 | 
 22 | ### Submitting Pull Requests
 23 | 
 24 | 1. **Fork the repository** and create your branch from `main`
 25 | 2. **Install dependencies** with `pnpm install`
 26 | 3. **Make your changes**:
 27 |    - Write clear, concise commit messages
 28 |    - Follow the existing code style
 29 |    - Add tests for new features
 30 |    - Update documentation as needed
 31 | 4. **Test your changes**:
 32 |    - Run `pnpm test` to ensure all tests pass
 33 |    - Run `pnpm lint` to check code style
 34 |    - Run `pnpm check-types` for TypeScript validation
 35 |    - Run `pnpm validate` to run all checks
 36 | 5. **Submit the pull request**:
 37 |    - Provide a clear description of the changes
 38 |    - Reference any related issues
 39 |    - Ensure CI checks pass
 40 | 
 41 | ## Development Setup
 42 | 
 43 | ### Prerequisites
 44 | 
 45 | - Node.js 22 or higher
 46 | - pnpm 10.17.0 or higher
 47 | - Git
 48 | 
 49 | ### Setup Steps
 50 | 
 51 | ```bash
 52 | # Clone your fork
 53 | git clone https://github.com/your-username/sonarqube-mcp-server.git
 54 | cd sonarqube-mcp-server
 55 | 
 56 | # Install dependencies
 57 | pnpm install
 58 | 
 59 | # Build the project
 60 | pnpm build
 61 | 
 62 | # Run tests
 63 | pnpm test
 64 | 
 65 | # Start development mode
 66 | pnpm dev
 67 | ```
 68 | 
 69 | ### Development Commands
 70 | 
 71 | ```bash
 72 | # Build the project
 73 | pnpm build
 74 | 
 75 | # Run in development mode with watch
 76 | pnpm dev
 77 | 
 78 | # Run all tests
 79 | pnpm test
 80 | 
 81 | # Run tests with coverage
 82 | pnpm test:coverage
 83 | 
 84 | # Run a specific test file
 85 | NODE_ENV=test NODE_OPTIONS='--experimental-vm-modules --no-warnings' jest src/__tests__/file-name.test.ts
 86 | 
 87 | # Lint code
 88 | pnpm lint
 89 | 
 90 | # Fix linting issues
 91 | pnpm lint:fix
 92 | 
 93 | # Check TypeScript types
 94 | pnpm check-types
 95 | 
 96 | # Format code
 97 | pnpm format
 98 | 
 99 | # Check formatting
100 | pnpm format:check
101 | 
102 | # Run all validations
103 | pnpm validate
104 | 
105 | # Inspect MCP schema
106 | pnpm inspect
107 | ```
108 | 
109 | ## Coding Standards
110 | 
111 | ### TypeScript
112 | 
113 | - Use TypeScript for all new code
114 | - Provide proper type definitions
115 | - Avoid using `any` type
116 | - Use interfaces for object shapes
117 | - Export types that might be used by consumers
118 | 
119 | ### Code Style
120 | 
121 | - Follow the existing code style
122 | - Use ESLint and Prettier configurations
123 | - Write self-documenting code
124 | - Add comments for complex logic
125 | - Keep functions small and focused
126 | 
127 | ### Testing
128 | 
129 | - Write tests for all new features
130 | - Maintain or improve code coverage
131 | - Use descriptive test names
132 | - Mock external dependencies
133 | - Test error cases and edge conditions
134 | 
135 | ### Git Commit Messages
136 | 
137 | Follow conventional commit format:
138 | 
139 | ```
140 | type(scope): subject
141 | 
142 | body
143 | 
144 | footer
145 | ```
146 | 
147 | Types:
148 | 
149 | - `feat`: New feature
150 | - `fix`: Bug fix
151 | - `docs`: Documentation changes
152 | - `style`: Code style changes (formatting, etc.)
153 | - `refactor`: Code refactoring
154 | - `test`: Test additions or changes
155 | - `chore`: Build process or auxiliary tool changes
156 | 
157 | Example:
158 | 
159 | ```
160 | feat(api): add support for branch filtering
161 | 
162 | Add branch parameter to issues endpoint to allow filtering
163 | issues by specific branch
164 | 
165 | Closes #123
166 | ```
167 | 
168 | ## Project Structure
169 | 
170 | ```
171 | sonarqube-mcp-server/
172 | ├── src/
173 | │   ├── __tests__/      # Test files
174 | │   ├── api.ts          # API module for HTTP requests
175 | │   ├── index.ts        # MCP server entry point
176 | │   └── sonarqube.ts    # SonarQube client implementation
177 | ├── dist/               # Compiled output
178 | ├── package.json        # Project configuration
179 | ├── tsconfig.json       # TypeScript configuration
180 | ├── jest.config.js      # Jest test configuration
181 | └── eslint.config.js    # ESLint configuration
182 | ```
183 | 
184 | ## Testing Guidelines
185 | 
186 | ### Unit Tests
187 | 
188 | - Test individual functions and methods
189 | - Mock external dependencies
190 | - Cover edge cases and error scenarios
191 | - Use descriptive test names
192 | 
193 | ### Integration Tests
194 | 
195 | - Test API endpoints with mocked HTTP responses
196 | - Verify parameter transformation
197 | - Test error handling and retries
198 | 
199 | ### Test Structure
200 | 
201 | ```typescript
202 | describe('ComponentName', () => {
203 |   describe('methodName', () => {
204 |     it('should handle normal case', () => {
205 |       // Test implementation
206 |     });
207 | 
208 |     it('should handle error case', () => {
209 |       // Test implementation
210 |     });
211 |   });
212 | });
213 | ```
214 | 
215 | ## Documentation
216 | 
217 | - Update README.md for user-facing changes
218 | - Add JSDoc comments for public APIs
219 | - Include examples for new features
220 | - Keep documentation clear and concise
221 | 
222 | ## MCP SDK Update Process
223 | 
224 | When updating the Model Context Protocol SDK (`@modelcontextprotocol/sdk`), follow these steps:
225 | 
226 | ### Before Updating
227 | 
228 | 1. **Check the SDK Release Notes**:
229 |    - Visit the [MCP SDK releases page](https://github.com/modelcontextprotocol/sdk/releases)
230 |    - Review the changelog for breaking changes
231 |    - Note any new protocol versions supported
232 | 
233 | 2. **Assess Impact**:
234 |    - Check if the new SDK version adds support for new protocol versions
235 |    - Review any deprecated features or APIs
236 |    - Evaluate compatibility with existing functionality
237 | 
238 | ### Update Process
239 | 
240 | 1. **Update the Dependency**:
241 | 
242 |    ```bash
243 |    pnpm add @modelcontextprotocol/sdk@latest
244 |    ```
245 | 
246 | 2. **Update Version References**:
247 |    - Update SDK version in `src/index.ts` startup logging
248 |    - Update supported protocol versions in `COMPATIBILITY.md`
249 |    - Update SDK version in `README.md` if referenced
250 | 
251 | 3. **Test Protocol Compatibility**:
252 | 
253 |    ```bash
254 |    # Run all tests
255 |    pnpm test
256 | 
257 |    # Test with Claude Desktop or other MCP clients
258 |    # Verify all tools work correctly
259 |    ```
260 | 
261 | 4. **Update Documentation**:
262 |    - Update `COMPATIBILITY.md` with new protocol versions
263 |    - Document any behavior changes
264 |    - Update examples if APIs have changed
265 | 
266 | 5. **Test with Multiple Clients**:
267 |    - Test with Claude Desktop
268 |    - Test with other MCP clients if available
269 |    - Verify backward compatibility with older protocol versions
270 | 
271 | ### Post-Update Checklist
272 | 
273 | - [ ] All tests pass (`pnpm test`)
274 | - [ ] Type checking passes (`pnpm check-types`)
275 | - [ ] Linting passes (`pnpm lint`)
276 | - [ ] Documentation is updated
277 | - [ ] COMPATIBILITY.md reflects new protocol support
278 | - [ ] Manual testing confirms all tools work
279 | - [ ] No deprecated SDK features are being used
280 | 
281 | ### Monitoring SDK Updates
282 | 
283 | To stay informed about SDK updates:
284 | 
285 | - Watch the [MCP SDK repository](https://github.com/modelcontextprotocol/sdk)
286 | - Subscribe to release notifications
287 | - Review the [MCP specification](https://modelcontextprotocol.io) for protocol changes
288 | 
289 | ## Release Process
290 | 
291 | 1. Ensure all tests pass
292 | 2. Update version in package.json
293 | 3. Create a pull request
294 | 4. After merge, create a release tag
295 | 5. GitHub Actions will automatically publish to npm and DockerHub
296 | 
297 | ## Need Help?
298 | 
299 | - Check the [README](README.md) for general information
300 | - Look at existing code for examples
301 | - Ask questions in GitHub issues
302 | - Review closed PRs for similar changes
303 | 
304 | ## Recognition
305 | 
306 | Contributors will be recognized in the project documentation. Thank you for helping improve the SonarQube MCP Server!
307 | 
```

--------------------------------------------------------------------------------
/CLAUDE.md:
--------------------------------------------------------------------------------

```markdown
  1 | # CLAUDE.md
  2 | 
  3 | This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
  4 | 
  5 | ## Project Overview
  6 | 
  7 | See [README.md](./README.md) for the complete project overview, features, and usage documentation.
  8 | 
  9 | ## Architecture Decision Records (ADRs)
 10 | 
 11 | This project uses adr-tools to document architectural decisions. ADRs are stored in `doc/architecture/decisions/`.
 12 | 
 13 | ```bash
 14 | # Create a new ADR without opening an editor (prevents timeout in Claude Code)
 15 | EDITOR=true adr-new "Title of the decision"
 16 | 
 17 | # Then edit the created file manually
 18 | ```
 19 | 
 20 | All architectural decisions are documented in Architecture Decision Records (ADRs) located in `doc/architecture/decisions/`. These ADRs are the single source of truth for understanding the design and architecture of this library.
 21 | 
 22 | Refer to the ADRs for detailed information about design rationale, implementation details, and consequences of each architectural decision.
 23 | 
 24 | ## Key Architectural Decisions
 25 | 
 26 | **Testing** (ADR-0020):
 27 | 
 28 | - Vitest as test framework with native ES modules support
 29 | - fast-check for property-based testing
 30 | - 80% minimum coverage required (lines, functions, branches, statements)
 31 | 
 32 | **Code Quality** (ADR-0021):
 33 | 
 34 | - TypeScript strict mode enabled (all strict flags)
 35 | - ESLint flat config with cognitive complexity limit (15)
 36 | - Prettier for consistent formatting
 37 | - Husky + lint-staged for pre-commit automation
 38 | 
 39 | **Package Manager** (ADR-0022):
 40 | 
 41 | - pnpm for disk efficiency and strict dependency management
 42 | - Version MUST match across: package.json, Dockerfile, all workflows
 43 | - Uses Corepack for automatic version management
 44 | 
 45 | **Release Management** (ADR-0023):
 46 | 
 47 | - Changesets for versioning and changelog generation
 48 | - Changeset validation enforced in CI/CD
 49 | - Automated GitHub releases via workflows
 50 | 
 51 | **CI/CD** (ADR-0024):
 52 | 
 53 | - GitHub Actions with 7 workflows (main, PR, publish, 4 reusable)
 54 | - Parallel execution for validation, security, build
 55 | - Quality gates block merge on failures
 56 | 
 57 | **Security** (ADR-0025):
 58 | 
 59 | - Multi-layered: Trivy (containers), CodeQL (SAST), OSV-Scanner (deps), SonarCloud
 60 | - SLSA provenance attestations on all artifacts
 61 | - SBOM (CycloneDX) generated for Docker images
 62 | 
 63 | **Resilience** (ADR-0026):
 64 | 
 65 | - Circuit breaker pattern via opossum library
 66 | - Default: 50% error threshold, 10s timeout, 30s reset
 67 | - Integrated with metrics/monitoring system
 68 | 
 69 | **Docker Publishing** (ADR-0027):
 70 | 
 71 | - Multi-platform: linux/amd64, linux/arm64
 72 | - Two-stage: build→GHCR (with security scan), copy→Docker Hub
 73 | - Build-once-deploy-many strategy
 74 | 
 75 | **Transport** (ADR-0010, ADR-0028):
 76 | 
 77 | - stdio: Default transport (recommended)
 78 | - HTTP: Optional session-based transport with SSE
 79 | - HTTP uses session management (not OAuth), delegates auth to gateways
 80 | 
 81 | ## Code Quality Conventions
 82 | 
 83 | Follow these conventions to maintain code quality:
 84 | 
 85 | ### TypeScript Best Practices
 86 | 
 87 | 1. **Use Type Aliases for Union Types**
 88 | 
 89 |    ```typescript
 90 |    // ❌ Avoid repeated union types
 91 |    function foo(param: 'option1' | 'option2' | 'option3') {}
 92 |    function bar(param: 'option1' | 'option2' | 'option3') {}
 93 | 
 94 |    // ✅ Use type alias
 95 |    type MyOptions = 'option1' | 'option2' | 'option3';
 96 |    function foo(param: MyOptions) {}
 97 |    function bar(param: MyOptions) {}
 98 |    ```
 99 | 
100 | 2. **Use Nullish Coalescing Operator**
101 | 
102 |    ```typescript
103 |    // ❌ Avoid logical OR for defaults (can fail with falsy values)
104 |    const value = input || 'default';
105 | 
106 |    // ✅ Use nullish coalescing (only replaces null/undefined)
107 |    const value = input ?? 'default';
108 |    ```
109 | 
110 | 3. **Use Object Spread Instead of Object.assign**
111 | 
112 |    ```typescript
113 |    // ❌ Avoid Object.assign
114 |    const merged = Object.assign({}, obj1, obj2);
115 | 
116 |    // ✅ Use object spread
117 |    const merged = { ...obj1, ...obj2 };
118 |    ```
119 | 
120 | 4. **Avoid Deprecated APIs**
121 |    - Check for deprecation warnings in the IDE
122 |    - Use recommended replacements (e.g., `getHealthV2()` instead of `health()`)
123 |    - Update to newer API versions when available
124 | 
125 | ### Code Complexity
126 | 
127 | 1. **Keep Cognitive Complexity Low**
128 |    - Maximum cognitive complexity: 15
129 |    - Break complex functions into smaller, focused functions
130 |    - Reduce nesting levels
131 |    - Simplify conditional logic
132 | 
133 | 2. **Remove Redundant Code**
134 |    - Don't create type aliases for primitive types
135 |    - Remove unused variable assignments
136 |    - Eliminate dead code
137 | 
138 | ### Regular Expressions
139 | 
140 | 1. **Make Regex Operator Precedence Explicit**
141 | 
142 |    ```typescript
143 |    // ❌ Ambiguous precedence
144 |    /abc|def+/
145 | 
146 |    // ✅ Clear precedence with grouping
147 |    /abc|(def+)/
148 |    ```
149 | 
150 | ### General Guidelines
151 | 
152 | 1. **Follow Existing Patterns**
153 |    - Check how similar functionality is implemented in the codebase
154 |    - Maintain consistency with existing code style
155 |    - Use the same libraries and utilities as the rest of the project
156 | 
157 | 2. **Run Validation Before Committing**
158 | 
159 |    ```bash
160 |    # Run all checks before committing
161 |    pnpm run precommit
162 | 
163 |    # This includes:
164 |    # - Format checking (prettier)
165 |    # - Linting (eslint)
166 |    # - Type checking (tsc)
167 |    # - Tests
168 |    ```
169 | 
170 | ## Claude-Specific Tips
171 | 
172 | - Remember to use the ADR creation command with `EDITOR=true` to prevent timeouts in Claude Code
173 | - Never use `--no-verify` when committing code. This bypasses pre-commit hooks which run important validation checks
174 | - Run `pnpm format` to format code before committing
175 | - Run `pnpm run precommit` before finalizing any code changes
176 | - Documentation for sonarqube-web-api-client can be retrieved from <https://raw.githubusercontent.com/sapientpants/sonarqube-web-api-client/refs/heads/main/docs/LLM.md>
177 | 
178 | ## Updating pnpm Version
179 | 
180 | When updating the pnpm version in this project, you MUST update it in ALL of the following locations to maintain consistency:
181 | 
182 | 1. **package.json**: Update the `packageManager` field (e.g., `"packageManager": "[email protected]"`)
183 | 2. **Dockerfile**: Update the version in `RUN npm install -g [email protected]`
184 | 3. **Documentation files**:
185 |    - **README.md**: Update the Prerequisites section
186 |    - **CONTRIBUTING.md**: Update the Prerequisites section
187 | 4. **Setup script**: Update `scripts/setup.sh` for mise installation
188 | 5. **GitHub Actions workflows** (CRITICAL - these must match package.json exactly):
189 |    - `.github/workflows/main.yml`: Line with `version: 10.17.0`
190 |    - `.github/workflows/pr.yml`: Line with `version: 10.17.0`
191 |    - `.github/workflows/publish.yml`: `PNPM_VERSION` environment variable
192 |    - `.github/workflows/reusable-security.yml`: Default value for `pnpm-version` input
193 |    - `.github/workflows/reusable-validate.yml`: Default value for `pnpm-version` input
194 | 
195 | **Important**: If package.json and GitHub workflows have different pnpm versions, the CI/CD pipeline will fail with an error like:
196 | 
197 | ```
198 | Error: Multiple versions of pnpm specified:
199 |   - version X in the GitHub Action config with the key "version"
200 |   - version pnpm@Y in the package.json with the key "packageManager"
201 | ```
202 | 
203 | Always search for the old version number across all files to ensure no location is missed.
204 | 
205 | ## Memory
206 | 
207 | Follow these steps for each interaction:
208 | 
209 | 1. User Identification:
210 |    - You should assume that you are interacting with default_user
211 |    - If you have not identified default_user, proactively try to do so.
212 | 
213 | 2. Memory Retrieval:
214 |    - Always begin your chat by saying only "Remembering..." and retrieve all relevant information from your knowledge graph
215 |    - Always refer to your knowledge graph as your "memory"
216 | 
217 | 3. Memory Gathering:
218 |    - While conversing with the user, be attentive to any new information that falls into these categories:
219 |      a) Basic Identity (age, gender, location, job title, education level, etc.)
220 |      b) Behaviors (interests, habits, etc.)
221 |      c) Preferences (communication style, preferred language, etc.)
222 |      d) Goals (goals, targets, aspirations, etc.)
223 |      e) Relationships (personal and professional relationships up to 3 degrees of separation)
224 | 
225 | 4. Memory Update:
226 |    - If any new information was gathered during the interaction, update your memory as follows:
227 |      a) Create entities for recurring entities (people, places, organizations, modules, concepts, etc.)
228 |      b) Connect them to the current entities using relations
229 |      c) Store facts about them as observations
230 | 
```

--------------------------------------------------------------------------------
/commitlint.config.js:
--------------------------------------------------------------------------------

```javascript
1 | export default {
2 |   extends: ['@commitlint/config-conventional'],
3 | };
4 | 
```

--------------------------------------------------------------------------------
/vitest.config.d.ts:
--------------------------------------------------------------------------------

```typescript
1 | declare const _default: import("vite").UserConfig;
2 | export default _default;
3 | 
```

--------------------------------------------------------------------------------
/tsconfig.build.json:
--------------------------------------------------------------------------------

```json
1 | {
2 |   "extends": "./tsconfig.json",
3 |   "compilerOptions": {
4 |     "noEmit": false,
5 |     "emitDeclarationOnly": false
6 |   },
7 |   "exclude": ["src/__tests__/**/*", "**/*.test.ts", "**/*.spec.ts"]
8 | }
9 | 
```

--------------------------------------------------------------------------------
/src/schemas/system.ts:
--------------------------------------------------------------------------------

```typescript
1 | /**
2 |  * Schemas for system tools
3 |  */
4 | 
5 | // Empty schemas for system tools that don't require parameters
6 | export const systemHealthToolSchema = {};
7 | export const systemStatusToolSchema = {};
8 | export const systemPingToolSchema = {};
9 | 
```

--------------------------------------------------------------------------------
/.claude/settings.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "hooks": {
 3 |     "PreToolUse": [
 4 |       {
 5 |         "matcher": "Bash",
 6 |         "hooks": [
 7 |           {
 8 |             "type": "command",
 9 |             "command": "./.claude/hooks/block-git-no-verify.ts"
10 |           }
11 |         ]
12 |       }
13 |     ]
14 |   }
15 | }
16 | 
```

--------------------------------------------------------------------------------
/src/types/common.ts:
--------------------------------------------------------------------------------

```typescript
 1 | /**
 2 |  * Type alias for severity levels
 3 |  */
 4 | export type SeverityLevel = 'HIGH' | 'MEDIUM' | 'LOW';
 5 | 
 6 | /**
 7 |  * Interface for pagination parameters
 8 |  */
 9 | export interface PaginationParams {
10 |   page: number | undefined;
11 |   pageSize: number | undefined;
12 | }
13 | 
```

--------------------------------------------------------------------------------
/src/schemas/hotspots.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { z } from 'zod';
 2 | 
 3 | /**
 4 |  * Schemas for security hotspots
 5 |  */
 6 | 
 7 | export const hotspotStatusSchema = z.enum(['TO_REVIEW', 'REVIEWED']).nullable().optional();
 8 | 
 9 | export const hotspotResolutionSchema = z.enum(['FIXED', 'SAFE']).nullable().optional();
10 | 
```

--------------------------------------------------------------------------------
/sonar-project.properties:
--------------------------------------------------------------------------------

```
1 | sonar.projectKey=sonarqube-mcp-server
2 | sonar.organization=sapientpants
3 | sonar.sources=src
4 | sonar.exclusions=node_modules/**,**/__tests__/**
5 | sonar.tests=src
6 | sonar.test.inclusions=**/__tests__/*.test.ts
7 | sonar.typescript.lcov.reportPaths=coverage/lcov.info
8 | 
```

--------------------------------------------------------------------------------
/src/schemas/metrics.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { z } from 'zod';
 2 | import { stringToNumberTransform } from '../utils/transforms.js';
 3 | 
 4 | /**
 5 |  * Schema for metrics tool
 6 |  */
 7 | export const metricsToolSchema = {
 8 |   page: z.string().optional().transform(stringToNumberTransform),
 9 |   page_size: z.string().optional().transform(stringToNumberTransform),
10 | };
11 | 
```

--------------------------------------------------------------------------------
/src/schemas/projects.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { z } from 'zod';
 2 | import { stringToNumberTransform } from '../utils/transforms.js';
 3 | 
 4 | /**
 5 |  * Schema for projects tool
 6 |  */
 7 | export const projectsToolSchema = {
 8 |   page: z.string().optional().transform(stringToNumberTransform),
 9 |   page_size: z.string().optional().transform(stringToNumberTransform),
10 | };
11 | 
```

--------------------------------------------------------------------------------
/.github/changeset.yml:
--------------------------------------------------------------------------------

```yaml
 1 | # Configuration for Changeset Bot
 2 | # This bot will comment on PRs to remind contributors to add changesets
 3 | 
 4 | # The message to display when a PR is missing a changeset
 5 | # Default message will be used if not specified
 6 | commit: false
 7 | # Whether to exclude certain PR labels from changeset requirements
 8 | # excluded:
 9 | #   - "dependencies"
10 | #   - "documentation"
11 | 
```

--------------------------------------------------------------------------------
/src/schemas/quality-gates.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { z } from 'zod';
 2 | import { pullRequestSchema } from './common.js';
 3 | 
 4 | /**
 5 |  * Schemas for quality gates tools
 6 |  */
 7 | 
 8 | export const qualityGatesToolSchema = {};
 9 | 
10 | export const qualityGateToolSchema = {
11 |   id: z.string(),
12 | };
13 | 
14 | export const qualityGateStatusToolSchema = {
15 |   project_key: z.string(),
16 |   branch: z.string().optional(),
17 |   pull_request: pullRequestSchema,
18 | };
19 | 
```

--------------------------------------------------------------------------------
/src/types/system.ts:
--------------------------------------------------------------------------------

```typescript
 1 | /**
 2 |  * Interface for SonarQube health status
 3 |  */
 4 | export interface SonarQubeHealthStatus {
 5 |   health: 'GREEN' | 'YELLOW' | 'RED';
 6 |   causes: string[];
 7 | }
 8 | 
 9 | /**
10 |  * Interface for SonarQube system status
11 |  */
12 | export interface SonarQubeSystemStatus {
13 |   id: string;
14 |   version: string;
15 |   status:
16 |     | 'UP'
17 |     | 'DOWN'
18 |     | 'STARTING'
19 |     | 'RESTARTING'
20 |     | 'DB_MIGRATION_NEEDED'
21 |     | 'DB_MIGRATION_RUNNING';
22 | }
23 | 
```

--------------------------------------------------------------------------------
/.changeset/config.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "$schema": "https://unpkg.com/@changesets/[email protected]/schema.json",
 3 |   "changelog": [
 4 |     "changelog-github-custom",
 5 |     {
 6 |       "repo": "sapientpants/sonarqube-mcp-server"
 7 |     }
 8 |   ],
 9 |   "commit": false,
10 |   "fixed": [],
11 |   "linked": [],
12 |   "access": "public",
13 |   "baseBranch": "main",
14 |   "updateInternalDependencies": "patch",
15 |   "ignore": [],
16 |   "privatePackages": {
17 |     "version": true,
18 |     "tag": false
19 |   }
20 | }
21 | 
```

--------------------------------------------------------------------------------
/osv-scanner.toml:
--------------------------------------------------------------------------------

```toml
 1 | # OSV Scanner Configuration
 2 | # Documentation: https://google.github.io/osv-scanner/configuration/
 3 | 
 4 | # Ignored vulnerabilities
 5 | # These vulnerabilities are acknowledged and accepted as risk
 6 | [[IgnoredVulns]]
 7 | id = "GHSA-9965-vmph-33xx"
 8 | # Reason: validator package is dev-only dependency (not in production)
 9 | # Impact: Medium severity (CVSS 6.1)
10 | # Status: No fix available yet
11 | # Review date: 2025-10-14
12 | reason = "Dev-only dependency, not exposed in production"
13 | 
```

--------------------------------------------------------------------------------
/src/types/metrics.ts:
--------------------------------------------------------------------------------

```typescript
 1 | /**
 2 |  * Interface for SonarQube metric
 3 |  */
 4 | export interface SonarQubeMetric {
 5 |   id: string;
 6 |   key: string;
 7 |   name: string;
 8 |   description: string;
 9 |   domain: string;
10 |   type: string;
11 |   direction: number;
12 |   qualitative: boolean;
13 |   hidden: boolean;
14 |   custom: boolean;
15 | }
16 | 
17 | /**
18 |  * Interface for SonarQube metrics result
19 |  */
20 | export interface SonarQubeMetricsResult {
21 |   metrics: SonarQubeMetric[];
22 |   paging: {
23 |     pageIndex: number;
24 |     pageSize: number;
25 |     total: number;
26 |   };
27 | }
28 | 
```

--------------------------------------------------------------------------------
/docs/architecture/decisions/0001-record-architecture-decisions.md:
--------------------------------------------------------------------------------

```markdown
 1 | # 1. Record architecture decisions
 2 | 
 3 | Date: 2025-06-13
 4 | 
 5 | ## Status
 6 | 
 7 | Accepted
 8 | 
 9 | ## Context
10 | 
11 | We need to record the architectural decisions made on this project.
12 | 
13 | ## Decision
14 | 
15 | We will use Architecture Decision Records, as [described by Michael Nygard](http://thinkrelevance.com/blog/2011/11/15/documenting-architecture-decisions).
16 | 
17 | ## Consequences
18 | 
19 | See Michael Nygard's article, linked above. For a lightweight ADR toolset, see Nat Pryce's [adr-tools](https://github.com/npryce/adr-tools).
20 | 
```

--------------------------------------------------------------------------------
/src/types/projects.ts:
--------------------------------------------------------------------------------

```typescript
 1 | /**
 2 |  * Interface for SonarQube project
 3 |  */
 4 | export interface SonarQubeProject {
 5 |   key: string;
 6 |   name: string;
 7 |   qualifier: string;
 8 |   visibility: string;
 9 |   lastAnalysisDate: string | undefined;
10 |   revision: string | undefined;
11 |   managed: boolean | undefined;
12 | }
13 | 
14 | /**
15 |  * Interface for SonarQube projects result - Clean abstraction for consumers
16 |  */
17 | export interface SonarQubeProjectsResult {
18 |   projects: SonarQubeProject[];
19 |   paging: {
20 |     pageIndex: number;
21 |     pageSize: number;
22 |     total: number;
23 |   };
24 | }
25 | 
```

--------------------------------------------------------------------------------
/src/domains/index.ts:
--------------------------------------------------------------------------------

```typescript
 1 | // Export all domain modules
 2 | export { BaseDomain } from './base.js';
 3 | export { ProjectsDomain } from './projects.js';
 4 | export { IssuesDomain } from './issues.js';
 5 | export { MetricsDomain } from './metrics.js';
 6 | export { MeasuresDomain } from './measures.js';
 7 | export { SystemDomain } from './system.js';
 8 | export { QualityGatesDomain } from './quality-gates.js';
 9 | export { SourceCodeDomain } from './source-code.js';
10 | export { HotspotsDomain } from './hotspots.js';
11 | export { ComponentsDomain } from './components.js';
12 | 
```

--------------------------------------------------------------------------------
/src/transports/index.ts:
--------------------------------------------------------------------------------

```typescript
 1 | /**
 2 |  * Transport module exports.
 3 |  * This module provides the transport abstraction layer for the MCP server.
 4 |  */
 5 | 
 6 | export type { ITransport, ITransportConfig, IHttpTransportConfig } from './base.js';
 7 | export { isStdioTransport } from './base.js';
 8 | export { StdioTransport } from './stdio.js';
 9 | export { HttpTransport } from './http.js';
10 | export { SessionManager } from './session-manager.js';
11 | export type { ISession, ISessionManagerConfig } from './session-manager.js';
12 | export { TransportFactory } from './factory.js';
13 | 
```

--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------

```yaml
 1 | # To get started with Dependabot version updates, you'll need to specify which
 2 | # package ecosystems to update and where the package manifests are located.
 3 | # Please see the documentation for all configuration options:
 4 | # https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
 5 | 
 6 | version: 2
 7 | updates:
 8 |   - package-ecosystem: 'npm' # See documentation for possible values
 9 |     directory: '/' # Location of package manifests
10 |     schedule:
11 |       interval: 'weekly'
12 | 
```

--------------------------------------------------------------------------------
/src/__tests__/null-to-undefined.test.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { describe, it, expect } from 'vitest';
 2 | import { nullToUndefined } from '../index.js';
 3 | describe('nullToUndefined', () => {
 4 |   it('should convert null to undefined', () => {
 5 |     expect(nullToUndefined(null)).toBeUndefined();
 6 |   });
 7 |   it('should pass through non-null values', () => {
 8 |     expect(nullToUndefined('value')).toBe('value');
 9 |     expect(nullToUndefined(123)).toBe(123);
10 |     expect(nullToUndefined(0)).toBe(0);
11 |     expect(nullToUndefined(false)).toBe(false);
12 |     expect(nullToUndefined(undefined)).toBeUndefined();
13 |   });
14 | });
15 | 
```

--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------

```markdown
 1 | ---
 2 | name: Feature request
 3 | about: Suggest an idea for this project
 4 | title: ''
 5 | labels: ''
 6 | assignees: ''
 7 | ---
 8 | 
 9 | **Is your feature request related to a problem? Please describe.**
10 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
11 | 
12 | **Describe the solution you'd like**
13 | A clear and concise description of what you want to happen.
14 | 
15 | **Describe alternatives you've considered**
16 | A clear and concise description of any alternative solutions or features you've considered.
17 | 
18 | **Additional context**
19 | Add any other context or screenshots about the feature request here.
20 | 
```

--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "compilerOptions": {
 3 |     "target": "ES2022",
 4 |     "lib": ["ES2022"],
 5 |     "module": "NodeNext",
 6 |     "moduleResolution": "NodeNext",
 7 |     "strict": true,
 8 |     "noUncheckedIndexedAccess": true,
 9 |     "exactOptionalPropertyTypes": true,
10 |     "noImplicitOverride": true,
11 |     "forceConsistentCasingInFileNames": true,
12 |     "noFallthroughCasesInSwitch": true,
13 |     "resolveJsonModule": true,
14 |     "declaration": true,
15 |     "sourceMap": true,
16 |     "rootDir": "./src",
17 |     "outDir": "dist",
18 |     "esModuleInterop": true,
19 |     "allowSyntheticDefaultImports": true,
20 |     "downlevelIteration": true
21 |   },
22 |   "include": ["src", "tests"]
23 | }
24 | 
```

--------------------------------------------------------------------------------
/src/schemas/source-code.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { z } from 'zod';
 2 | import { stringToNumberTransform } from '../utils/transforms.js';
 3 | import { pullRequestSchema } from './common.js';
 4 | 
 5 | /**
 6 |  * Schemas for source code tools
 7 |  */
 8 | 
 9 | export const sourceCodeToolSchema = {
10 |   key: z.string(),
11 |   from: z.string().optional().transform(stringToNumberTransform),
12 |   to: z.string().optional().transform(stringToNumberTransform),
13 |   branch: z.string().optional(),
14 |   pull_request: pullRequestSchema,
15 | };
16 | 
17 | export const scmBlameToolSchema = {
18 |   key: z.string(),
19 |   from: z.string().optional().transform(stringToNumberTransform),
20 |   to: z.string().optional().transform(stringToNumberTransform),
21 |   branch: z.string().optional(),
22 |   pull_request: pullRequestSchema,
23 | };
24 | 
```

--------------------------------------------------------------------------------
/.github/actionlint.yaml:
--------------------------------------------------------------------------------

```yaml
 1 | # actionlint configuration
 2 | # https://github.com/rhysd/actionlint/blob/main/docs/config.md
 3 | 
 4 | # Self-hosted runner labels used in this project
 5 | # Add any custom runner labels here if using self-hosted runners
 6 | self-hosted-runner:
 7 |   labels: []
 8 | 
 9 | # Configuration variables used in workflows
10 | # This helps actionlint validate variable references
11 | config-variables:
12 |   - ENABLE_DOCKER_RELEASE
13 |   - ENABLE_NPM_RELEASE
14 |   - ENABLE_GITHUB_PACKAGES
15 | 
16 | # Ignore specific shellcheck warnings
17 | # SC2086: Double quote to prevent globbing and word splitting
18 | # These are often false positives in GitHub Actions contexts
19 | paths:
20 |   .github/workflows/**/*.{yml,yaml}:
21 |     ignore:
22 |       - 'shellcheck reported issue in this script: SC2086:.+'
23 | 
```

--------------------------------------------------------------------------------
/src/__tests__/transports/base.test.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
 2 | import { isStdioTransport } from '../../transports/base.js';
 3 | 
 4 | describe('Transport Base', () => {
 5 |   describe('isStdioTransport', () => {
 6 |     it('should return true for StdioServerTransport instance', () => {
 7 |       const transport = new StdioServerTransport();
 8 |       expect(isStdioTransport(transport)).toBe(true);
 9 |     });
10 | 
11 |     it('should return false for non-StdioServerTransport instances', () => {
12 |       expect(isStdioTransport({})).toBe(false);
13 |       expect(isStdioTransport(null)).toBe(false);
14 |       expect(isStdioTransport(undefined)).toBe(false);
15 |       expect(isStdioTransport('string')).toBe(false);
16 |       expect(isStdioTransport(123)).toBe(false);
17 |     });
18 |   });
19 | });
20 | 
```

--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------

```markdown
 1 | ---
 2 | name: Bug report
 3 | about: Create a report to help us improve
 4 | title: ''
 5 | labels: ''
 6 | assignees: ''
 7 | ---
 8 | 
 9 | **Describe the bug**
10 | A clear and concise description of what the bug is.
11 | 
12 | **To Reproduce**
13 | Steps to reproduce the behavior:
14 | 
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 | 
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 | 
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 | 
26 | **Desktop (please complete the following information):**
27 | 
28 | - OS: [e.g. iOS]
29 | - Browser [e.g. chrome, safari]
30 | - Version [e.g. 22]
31 | 
32 | **Smartphone (please complete the following information):**
33 | 
34 | - Device: [e.g. iPhone6]
35 | - OS: [e.g. iOS8.1]
36 | - Browser [e.g. stock browser, safari]
37 | - Version [e.g. 22]
38 | 
39 | **Additional context**
40 | Add any other context about the problem here.
41 | 
```

--------------------------------------------------------------------------------
/vitest.config.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { defineConfig } from 'vitest/config';
 2 | 
 3 | export default defineConfig({
 4 |   test: {
 5 |     environment: 'node',
 6 |     globals: true,
 7 |     coverage: {
 8 |       provider: 'v8',
 9 |       reporter: ['text', 'html', 'json-summary', 'lcov'],
10 |       exclude: [
11 |         'coverage/**',
12 |         'dist/**',
13 |         '*.config.js',
14 |         '*.config.ts',
15 |         '.*.js',
16 |         '**/*.d.ts',
17 |         'tests/**',
18 |         'test/**',
19 |         '**/*.spec.ts',
20 |         '**/*.test.ts',
21 |         'docs/**',
22 |         '.github/**',
23 |         '.changeset/**',
24 |         '.claude/**',
25 |         'node_modules/**',
26 |         'src/dev/**', // Development utilities - no coverage required
27 |         '**/*.example.ts', // Example files - not part of production code
28 |       ],
29 |       thresholds: {
30 |         branches: 80,
31 |         functions: 80,
32 |         lines: 80,
33 |         statements: 80,
34 |       },
35 |     },
36 |   },
37 | });
38 | 
```

--------------------------------------------------------------------------------
/vitest.config.js:
--------------------------------------------------------------------------------

```javascript
 1 | import { defineConfig } from 'vitest/config';
 2 | export default defineConfig({
 3 |   test: {
 4 |     environment: 'node',
 5 |     globals: true,
 6 |     coverage: {
 7 |       provider: 'v8',
 8 |       reporter: ['text', 'html', 'json-summary', 'lcov'],
 9 |       exclude: [
10 |         'coverage/**',
11 |         'dist/**',
12 |         '*.config.js',
13 |         '*.config.ts',
14 |         '.*.js',
15 |         '**/*.d.ts',
16 |         'tests/**',
17 |         'test/**',
18 |         '**/*.spec.ts',
19 |         '**/*.test.ts',
20 |         'docs/**',
21 |         '.github/**',
22 |         '.changeset/**',
23 |         '.claude/**',
24 |         'node_modules/**',
25 |         'src/dev/**', // Development utilities - no coverage required
26 |         '**/*.example.ts', // Example files - not part of production code
27 |       ],
28 |       thresholds: {
29 |         branches: 80,
30 |         functions: 80,
31 |         lines: 80,
32 |         statements: 80,
33 |       },
34 |     },
35 |   },
36 | });
37 | //# sourceMappingURL=vitest.config.js.map
38 | 
```

--------------------------------------------------------------------------------
/.github/pull_request_template.md:
--------------------------------------------------------------------------------

```markdown
 1 | <!--- Please provide a general summary of your changes in the title above -->
 2 | 
 3 | ## Pull request type
 4 | 
 5 | <!-- Please try to limit your pull request to one type, submit multiple pull requests if needed. -->
 6 | 
 7 | Please check the type of change your PR introduces:
 8 | 
 9 | - [ ] Bugfix
10 | - [ ] Feature
11 | - [ ] Code style update (formatting, renaming)
12 | - [ ] Refactoring (no functional changes, no api changes)
13 | - [ ] Build related changes
14 | - [ ] Documentation content changes
15 | - [ ] Other (please describe):
16 | 
17 | ## What is the current behavior?
18 | 
19 | <!-- Please describe the current behavior that you are modifying, or link to a relevant issue. -->
20 | 
21 | Issue Number: N/A
22 | 
23 | ## What is the new behavior?
24 | 
25 | <!-- Please describe the behavior or changes that are being added by this PR. -->
26 | 
27 | -
28 | -
29 | -
30 | 
31 | ## Other information
32 | 
33 | <!-- Any other information that is important to this PR such as screenshots of how the component looks before and after the change. -->
34 | 
```

--------------------------------------------------------------------------------
/src/handlers/metrics.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import type { PaginationParams, ISonarQubeClient } from '../types/index.js';
 2 | import { getDefaultClient } from '../utils/client-factory.js';
 3 | import { createStructuredResponse } from '../utils/structured-response.js';
 4 | 
 5 | /**
 6 |  * Handler for getting SonarQube metrics
 7 |  * @param params Parameters for the metrics request
 8 |  * @param client Optional SonarQube client instance
 9 |  * @returns Promise with the metrics result
10 |  */
11 | export async function handleSonarQubeGetMetrics(
12 |   params: PaginationParams,
13 |   client: ISonarQubeClient = getDefaultClient()
14 | ) {
15 |   const result = await client.getMetrics(params);
16 | 
17 |   // Create a properly structured response matching the expected format
18 |   const response = {
19 |     metrics: result.metrics ?? [],
20 |     paging: result.paging ?? {
21 |       pageIndex: params.page ?? 1,
22 |       pageSize: params.pageSize ?? 100,
23 |       total: (result.metrics ?? []).length,
24 |     },
25 |   };
26 | 
27 |   return createStructuredResponse(response);
28 | }
29 | 
```

--------------------------------------------------------------------------------
/.claude/commands/analyze-and-fix-github-issue.md:
--------------------------------------------------------------------------------

```markdown
 1 | # Analyze and fix GitHub Issue
 2 | 
 3 | Please analyze and fix the GitHub issue: $ARGUMENTS.
 4 | 
 5 | Follow these steps:
 6 | 
 7 | 1. Use `gh issue view` to get the issue details
 8 | 2. Understand the problem described in the issue
 9 | 3. Search the codebase for relevant files
10 | 4. Create a detailed plan to address the issue
11 | 5. Create a new branch for the fix, e.g., `fix/issue-123`
12 | 6. Implement the necessary changes to fix the issue
13 | 7. Ensure that any new code is well-documented and follows the project's coding standards
14 | 8. Write tests to cover the changes made, if applicable
15 | 9. Ensure code passes formatting, linting, type checking, and tests using `pnpm run precommit`
16 | 10. Create a descriptive commit message
17 | 11. Push and create a PR
18 | 12. Wait for code review and address any feedback provided by reviewers.
19 | 13. Merge the pull request once it has been approved. Use the "Squash and merge" option to keep the commit history clean.
20 | 
21 | Remember to use the GitHub CLI (`gh`) for all GitHub-related tasks.
22 | 
```

--------------------------------------------------------------------------------
/src/handlers/source-code.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import type { SourceCodeParams, ScmBlameParams, ISonarQubeClient } from '../types/index.js';
 2 | import { getDefaultClient } from '../utils/client-factory.js';
 3 | import { createStructuredResponse } from '../utils/structured-response.js';
 4 | 
 5 | /**
 6 |  * Handler for getting source code
 7 |  * @param params Parameters for the source code request
 8 |  * @param client Optional SonarQube client instance
 9 |  * @returns Promise with the source code result
10 |  */
11 | export async function handleSonarQubeGetSourceCode(
12 |   params: SourceCodeParams,
13 |   client: ISonarQubeClient = getDefaultClient()
14 | ) {
15 |   const result = await client.getSourceCode(params);
16 | 
17 |   return createStructuredResponse(result);
18 | }
19 | 
20 | /**
21 |  * Handler for getting SCM blame information
22 |  * @param params Parameters for the SCM blame request
23 |  * @param client Optional SonarQube client instance
24 |  * @returns Promise with the SCM blame result
25 |  */
26 | export async function handleSonarQubeGetScmBlame(
27 |   params: ScmBlameParams,
28 |   client: ISonarQubeClient = getDefaultClient()
29 | ) {
30 |   const result = await client.getScmBlame(params);
31 | 
32 |   return createStructuredResponse(result);
33 | }
34 | 
```

--------------------------------------------------------------------------------
/src/config/versions.ts:
--------------------------------------------------------------------------------

```typescript
 1 | /**
 2 |  * Centralized version configuration for the SonarQube MCP Server
 3 |  */
 4 | 
 5 | /**
 6 |  * Server version - the version of the SonarQube MCP Server itself
 7 |  */
 8 | export const SERVER_VERSION = '1.7.0';
 9 | 
10 | /**
11 |  * MCP SDK version currently in use
12 |  */
13 | export const SDK_VERSION = '1.13.0';
14 | 
15 | /**
16 |  * MCP protocol versions supported by the current SDK
17 |  * Listed in order from newest to oldest
18 |  */
19 | export const SUPPORTED_PROTOCOL_VERSIONS = [
20 |   '2025-06-18',
21 |   '2025-03-26',
22 |   '2024-11-05',
23 |   '2024-10-07',
24 | ] as const;
25 | 
26 | /**
27 |  * Latest MCP protocol version
28 |  */
29 | export const LATEST_PROTOCOL_VERSION = SUPPORTED_PROTOCOL_VERSIONS[0];
30 | 
31 | /**
32 |  * Default negotiated protocol version (what most clients will use)
33 |  */
34 | export const DEFAULT_NEGOTIATED_PROTOCOL_VERSION = '2025-03-26';
35 | 
36 | /**
37 |  * Version information object for logging and display
38 |  */
39 | export const VERSION_INFO = {
40 |   serverVersion: SERVER_VERSION,
41 |   sdkVersion: SDK_VERSION,
42 |   supportedProtocolVersions: SUPPORTED_PROTOCOL_VERSIONS,
43 |   latestProtocolVersion: LATEST_PROTOCOL_VERSION,
44 |   defaultNegotiatedProtocolVersion: DEFAULT_NEGOTIATED_PROTOCOL_VERSION,
45 | } as const;
46 | 
```

--------------------------------------------------------------------------------
/src/handlers/index.ts:
--------------------------------------------------------------------------------

```typescript
 1 | /**
 2 |  * Re-export all handlers from their respective modules
 3 |  */
 4 | 
 5 | export { handleSonarQubeProjects } from './projects.js';
 6 | 
 7 | export {
 8 |   handleSonarQubeGetIssues,
 9 |   handleMarkIssueFalsePositive,
10 |   handleMarkIssueWontFix,
11 |   handleMarkIssuesFalsePositive,
12 |   handleMarkIssuesWontFix,
13 |   handleAddCommentToIssue,
14 |   handleAssignIssue,
15 |   handleConfirmIssue,
16 |   handleUnconfirmIssue,
17 |   handleResolveIssue,
18 |   handleReopenIssue,
19 |   setElicitationManager,
20 | } from './issues.js';
21 | 
22 | export { handleSonarQubeGetMetrics } from './metrics.js';
23 | 
24 | export {
25 |   handleSonarQubeGetHealth,
26 |   handleSonarQubeGetStatus,
27 |   handleSonarQubePing,
28 | } from './system.js';
29 | 
30 | export {
31 |   handleSonarQubeComponentMeasures,
32 |   handleSonarQubeComponentsMeasures,
33 |   handleSonarQubeMeasuresHistory,
34 | } from './measures.js';
35 | 
36 | export {
37 |   handleSonarQubeListQualityGates,
38 |   handleSonarQubeGetQualityGate,
39 |   handleSonarQubeQualityGateStatus,
40 | } from './quality-gates.js';
41 | 
42 | export { handleSonarQubeGetSourceCode, handleSonarQubeGetScmBlame } from './source-code.js';
43 | 
44 | export {
45 |   handleSonarQubeHotspots,
46 |   handleSonarQubeHotspot,
47 |   handleSonarQubeUpdateHotspotStatus,
48 | } from './hotspots.js';
49 | 
50 | export { handleSonarQubeComponents } from './components.js';
51 | 
```

--------------------------------------------------------------------------------
/src/config/service-accounts.ts:
--------------------------------------------------------------------------------

```typescript
 1 | /**
 2 |  * Service account configuration utilities
 3 |  */
 4 | 
 5 | export interface ServiceAccountConfig {
 6 |   id: string;
 7 |   token: string;
 8 |   url: string | undefined;
 9 |   organization: string | undefined;
10 | }
11 | 
12 | /**
13 |  * Get service account configuration
14 |  */
15 | export function getServiceAccountConfig(accountId: string): ServiceAccountConfig | null {
16 |   // For default account, check standard environment variables
17 |   if (accountId === 'default') {
18 |     const token = process.env.SONARQUBE_TOKEN;
19 |     if (!token) {
20 |       return null;
21 |     }
22 | 
23 |     const config: ServiceAccountConfig = {
24 |       id: 'default',
25 |       token,
26 |       url: process.env.SONARQUBE_URL,
27 |       organization: process.env.SONARQUBE_ORGANIZATION,
28 |     };
29 |     return config;
30 |   }
31 | 
32 |   // For numbered accounts (SA1-SA10)
33 |   const regex = /^SA(\d+)$/;
34 |   const match = regex.exec(accountId);
35 |   if (match) {
36 |     const num = match[1];
37 |     const token = process.env[`SONARQUBE_SA${num}_TOKEN`];
38 |     if (!token) {
39 |       return null;
40 |     }
41 | 
42 |     const config: ServiceAccountConfig = {
43 |       id: accountId,
44 |       token,
45 |       url: process.env[`SONARQUBE_SA${num}_URL`],
46 |       organization: process.env[`SONARQUBE_SA${num}_ORGANIZATION`],
47 |     };
48 |     return config;
49 |   }
50 | 
51 |   return null;
52 | }
53 | 
```

--------------------------------------------------------------------------------
/src/schemas/index.ts:
--------------------------------------------------------------------------------

```typescript
 1 | // Re-export all schemas from their respective files
 2 | 
 3 | // Common schemas
 4 | export * from './common.js';
 5 | 
 6 | // Domain schemas
 7 | export * from './hotspots.js';
 8 | 
 9 | // Tool schemas
10 | export { projectsToolSchema } from './projects.js';
11 | export { metricsToolSchema } from './metrics.js';
12 | export {
13 |   issuesToolSchema,
14 |   markIssueFalsePositiveToolSchema,
15 |   markIssueWontFixToolSchema,
16 |   markIssuesFalsePositiveToolSchema,
17 |   markIssuesWontFixToolSchema,
18 |   addCommentToIssueToolSchema,
19 |   assignIssueToolSchema,
20 |   confirmIssueToolSchema,
21 |   unconfirmIssueToolSchema,
22 |   resolveIssueToolSchema,
23 |   reopenIssueToolSchema,
24 | } from './issues.js';
25 | export { systemHealthToolSchema, systemStatusToolSchema, systemPingToolSchema } from './system.js';
26 | export {
27 |   componentMeasuresToolSchema,
28 |   componentsMeasuresToolSchema,
29 |   measuresHistoryToolSchema,
30 | } from './measures.js';
31 | export {
32 |   qualityGatesToolSchema,
33 |   qualityGateToolSchema,
34 |   qualityGateStatusToolSchema,
35 | } from './quality-gates.js';
36 | export { sourceCodeToolSchema, scmBlameToolSchema } from './source-code.js';
37 | export {
38 |   hotspotsToolSchema,
39 |   hotspotToolSchema,
40 |   updateHotspotStatusToolSchema,
41 | } from './hotspots-tools.js';
42 | export { componentsToolSchema } from './components.js';
43 | 
```

--------------------------------------------------------------------------------
/src/schemas/measures.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { z } from 'zod';
 2 | import { stringToNumberTransform } from '../utils/transforms.js';
 3 | import { pullRequestSchema } from './common.js';
 4 | 
 5 | /**
 6 |  * Schemas for measures tools
 7 |  */
 8 | 
 9 | export const componentMeasuresToolSchema = {
10 |   component: z.string(),
11 |   metric_keys: z.array(z.string()),
12 |   additional_fields: z.array(z.string()).optional(),
13 |   branch: z.string().optional(),
14 |   pull_request: pullRequestSchema,
15 |   period: z.string().optional(),
16 | };
17 | 
18 | export const componentsMeasuresToolSchema = {
19 |   component_keys: z.array(z.string()),
20 |   metric_keys: z.array(z.string()),
21 |   additional_fields: z.array(z.string()).optional(),
22 |   branch: z.string().optional(),
23 |   pull_request: pullRequestSchema,
24 |   period: z.string().optional(),
25 |   page: z.string().optional().transform(stringToNumberTransform),
26 |   page_size: z.string().optional().transform(stringToNumberTransform),
27 | };
28 | 
29 | export const measuresHistoryToolSchema = {
30 |   component: z.string(),
31 |   metrics: z.array(z.string()),
32 |   from: z.string().optional(),
33 |   to: z.string().optional(),
34 |   branch: z.string().optional(),
35 |   pull_request: pullRequestSchema,
36 |   page: z.string().optional().transform(stringToNumberTransform),
37 |   page_size: z.string().optional().transform(stringToNumberTransform),
38 | };
39 | 
```

--------------------------------------------------------------------------------
/src/types/quality-gates.ts:
--------------------------------------------------------------------------------

```typescript
 1 | /**
 2 |  * Interface for SonarQube quality gate condition
 3 |  */
 4 | export interface SonarQubeQualityGateCondition {
 5 |   id: string;
 6 |   metric: string;
 7 |   op: string;
 8 |   error: string;
 9 | }
10 | 
11 | /**
12 |  * Interface for SonarQube quality gate
13 |  */
14 | export interface SonarQubeQualityGate {
15 |   id: string;
16 |   name: string;
17 |   isDefault: boolean | undefined;
18 |   isBuiltIn: boolean | undefined;
19 |   conditions: SonarQubeQualityGateCondition[] | undefined;
20 | }
21 | 
22 | /**
23 |  * Interface for SonarQube quality gates list result
24 |  */
25 | export interface SonarQubeQualityGatesResult {
26 |   qualitygates: SonarQubeQualityGate[];
27 |   default: string;
28 |   actions:
29 |     | {
30 |         create: boolean | undefined;
31 |       }
32 |     | undefined;
33 | }
34 | 
35 | /**
36 |  * Interface for SonarQube quality gate status
37 |  */
38 | export interface SonarQubeQualityGateStatus {
39 |   projectStatus: {
40 |     status: 'OK' | 'WARN' | 'ERROR' | 'NONE';
41 |     conditions: Array<{
42 |       status: 'OK' | 'WARN' | 'ERROR';
43 |       metricKey: string;
44 |       comparator: string;
45 |       errorThreshold: string;
46 |       actualValue: string;
47 |     }>;
48 |     periods?: Array<{
49 |       index: number;
50 |       mode: string;
51 |       date: string;
52 |       parameter?: string;
53 |     }>;
54 |     ignoredConditions: boolean;
55 |   };
56 | }
57 | 
58 | /**
59 |  * Interface for project quality gate params
60 |  */
61 | export interface ProjectQualityGateParams {
62 |   projectKey: string;
63 |   branch?: string;
64 |   pullRequest?: string;
65 | }
66 | 
```

--------------------------------------------------------------------------------
/src/utils/error-handler.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { SonarQubeAPIError, formatErrorForMCP } from '../errors.js';
 2 | import { createLogger } from './logger.js';
 3 | 
 4 | const logger = createLogger('utils/error-handler');
 5 | 
 6 | /**
 7 |  * Custom error class for MCP errors that includes a code property
 8 |  */
 9 | class MCPError extends Error {
10 |   code: number;
11 | 
12 |   constructor(message: string, code: number) {
13 |     super(message);
14 |     this.name = 'MCPError';
15 |     this.code = code;
16 |   }
17 | }
18 | 
19 | /**
20 |  * Wraps an async MCP handler function with error handling that converts
21 |  * SonarQubeAPIError instances to MCP-formatted errors
22 |  *
23 |  * @param fn The async function to wrap
24 |  * @returns A wrapped function that handles errors appropriately
25 |  */
26 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
27 | export function withMCPErrorHandling<T extends (...args: any[]) => Promise<any>>(fn: T): T {
28 |   return (async (
29 |     ...args: Parameters<T>
30 |   ): Promise<ReturnType<T> extends Promise<infer U> ? U : never> => {
31 |     try {
32 |       return (await fn(...args)) as ReturnType<T> extends Promise<infer U> ? U : never;
33 |     } catch (error) {
34 |       if (error instanceof SonarQubeAPIError) {
35 |         logger.error('SonarQube API error occurred', error);
36 |         const mcpError = formatErrorForMCP(error);
37 |         throw new MCPError(mcpError.message, mcpError.code);
38 |       }
39 |       // Re-throw non-SonarQubeAPIError errors as-is
40 |       throw error;
41 |     }
42 |   }) as T;
43 | }
44 | 
```

--------------------------------------------------------------------------------
/src/schemas/hotspots-tools.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { z } from 'zod';
 2 | import { stringToNumberTransform } from '../utils/transforms.js';
 3 | import { pullRequestNullableSchema } from './common.js';
 4 | import { hotspotStatusSchema, hotspotResolutionSchema } from './hotspots.js';
 5 | 
 6 | /**
 7 |  * Schemas for hotspot tools
 8 |  */
 9 | 
10 | export const hotspotsToolSchema = {
11 |   project_key: z.string().optional(),
12 |   branch: z.string().nullable().optional(),
13 |   pull_request: pullRequestNullableSchema,
14 |   status: hotspotStatusSchema,
15 |   resolution: hotspotResolutionSchema,
16 |   files: z.array(z.string()).nullable().optional(),
17 |   assigned_to_me: z
18 |     .union([z.boolean(), z.string().transform((val) => val === 'true')])
19 |     .nullable()
20 |     .optional(),
21 |   since_leak_period: z
22 |     .union([z.boolean(), z.string().transform((val) => val === 'true')])
23 |     .nullable()
24 |     .optional(),
25 |   in_new_code_period: z
26 |     .union([z.boolean(), z.string().transform((val) => val === 'true')])
27 |     .nullable()
28 |     .optional(),
29 |   page: z.string().optional().transform(stringToNumberTransform),
30 |   page_size: z.string().optional().transform(stringToNumberTransform),
31 | };
32 | 
33 | export const hotspotToolSchema = {
34 |   hotspot_key: z.string(),
35 | };
36 | 
37 | export const updateHotspotStatusToolSchema = {
38 |   hotspot_key: z.string(),
39 |   status: z.enum(['TO_REVIEW', 'REVIEWED']),
40 |   resolution: z.enum(['FIXED', 'SAFE']).nullable().optional(),
41 |   comment: z.string().nullable().optional(),
42 | };
43 | 
```

--------------------------------------------------------------------------------
/test-http-transport.sh:
--------------------------------------------------------------------------------

```bash
 1 | #!/bin/bash
 2 | 
 3 | echo "Starting SonarQube MCP Server with HTTP transport..."
 4 | 
 5 | # Start the server in the background with HTTP transport
 6 | MCP_TRANSPORT_TYPE=http \
 7 | MCP_HTTP_PORT=3000 \
 8 | SONARQUBE_URL=https://sonarcloud.io \
 9 | SONARQUBE_TOKEN=dummy_token \
10 | LOG_LEVEL=INFO \
11 | LOG_FILE=/tmp/http-transport-test.log \
12 | pnpm start &
13 | 
14 | SERVER_PID=$!
15 | echo "Server started with PID: $SERVER_PID"
16 | 
17 | # Wait for server to start
18 | echo "Waiting for server to start..."
19 | sleep 3
20 | 
21 | # Test health endpoint
22 | echo ""
23 | echo "Testing health endpoint..."
24 | curl -s http://localhost:3000/health | jq .
25 | 
26 | # Create a session
27 | echo ""
28 | echo "Creating session..."
29 | SESSION_RESPONSE=$(curl -s -X POST http://localhost:3000/session)
30 | SESSION_ID=$(echo "$SESSION_RESPONSE" | jq -r .sessionId)
31 | echo "Session created: $SESSION_ID"
32 | 
33 | # Test MCP endpoint (will fail with placeholder response, but tests the endpoint)
34 | echo ""
35 | echo "Testing MCP endpoint..."
36 | curl -s -X POST http://localhost:3000/mcp \
37 |   -H "Content-Type: application/json" \
38 |   -d "{\"sessionId\": \"$SESSION_ID\", \"method\": \"tools/list\", \"params\": {}}" | jq .
39 | 
40 | # Close session
41 | echo ""
42 | echo "Closing session..."
43 | curl -s -X DELETE "http://localhost:3000/session/$SESSION_ID" | jq .
44 | 
45 | # Kill the server
46 | echo ""
47 | echo "Stopping server..."
48 | kill $SERVER_PID
49 | wait $SERVER_PID 2>/dev/null
50 | 
51 | echo ""
52 | echo "Test completed!"
53 | echo "Check logs at /tmp/http-transport-test.log for server logs."
```

--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------

```javascript
 1 | /** @type {import('jest').Config} */
 2 | export default {
 3 |   preset: 'ts-jest/presets/default-esm',
 4 |   testEnvironment: 'node',
 5 |   testMatch: ['**/__tests__/**/*.test.ts'],
 6 |   moduleNameMapper: {
 7 |     '^(\\.{1,2}/.*)\\.js$': '$1',
 8 |     '^(\\.{1,2}/.*)\\.ts$': '$1',
 9 |   },
10 |   transform: {
11 |     '^.+\\.tsx?$': [
12 |       'ts-jest',
13 |       {
14 |         useESM: true,
15 |         tsconfig: {
16 |           moduleResolution: 'NodeNext',
17 |         },
18 |       },
19 |     ],
20 |   },
21 |   extensionsToTreatAsEsm: ['.ts'],
22 |   moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
23 |   transformIgnorePatterns: ['node_modules/(?!(@modelcontextprotocol)/)'],
24 |   collectCoverageFrom: [
25 |     'src/**/*.ts',
26 |     '!src/**/*.d.ts',
27 |     '!src/**/*.test.ts',
28 |     '!src/__tests__/mocks/**/*.ts',
29 |   ],
30 |   coverageReporters: ['text', 'lcov'],
31 |   testPathIgnorePatterns: [
32 |     '/node_modules/',
33 |     '/src/__tests__/lambda-functions.test.ts',
34 |     '/src/__tests__/handlers.test.ts',
35 |     '/src/__tests__/tool-handlers.test.ts',
36 |     '/src/__tests__/mocked-environment.test.ts',
37 |     '/src/__tests__/direct-lambdas.test.ts',
38 |   ],
39 |   // Focusing on total coverage, with sonarqube.ts at 100%
40 |   coverageThreshold: {
41 |     'src/sonarqube.ts': {
42 |       statements: 81,
43 |       branches: 60,
44 |       functions: 100,
45 |       lines: 81,
46 |     },
47 |     global: {
48 |       statements: 68,
49 |       branches: 8,
50 |       functions: 40,
51 |       lines: 68,
52 |     },
53 |   },
54 |   bail: 0, // Run all tests regardless of failures
55 | };
56 | 
```

--------------------------------------------------------------------------------
/src/__tests__/transports/stdio.test.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { describe, it, expect, vi } from 'vitest';
 2 | import { Server } from '@modelcontextprotocol/sdk/server/index.js';
 3 | import { StdioTransport } from '../../transports/stdio.js';
 4 | 
 5 | describe('StdioTransport', () => {
 6 |   it('should create instance with transport', () => {
 7 |     const transport = new StdioTransport();
 8 |     expect(transport).toBeDefined();
 9 |     expect(transport.getName()).toBe('stdio');
10 |   });
11 | 
12 |   it('should return underlying transport', () => {
13 |     const transport = new StdioTransport();
14 |     const underlying = transport.getUnderlyingTransport();
15 |     expect(underlying).toBeDefined();
16 |     expect(underlying.constructor.name).toBe('StdioServerTransport');
17 |   });
18 | 
19 |   it('should connect to server', async () => {
20 |     const transport = new StdioTransport();
21 |     const mockServer = {
22 |       connect: vi.fn<() => Promise<any>>().mockResolvedValue(undefined as never),
23 |     } as unknown as Server;
24 | 
25 |     await transport.connect(mockServer);
26 |     expect(mockServer.connect).toHaveBeenCalledWith(transport.getUnderlyingTransport());
27 |   });
28 | 
29 |   it('should add connect method to underlying transport', () => {
30 |     const transport = new StdioTransport();
31 |     const underlying = transport.getUnderlyingTransport();
32 |     // The transport should have a connect method added via our workaround
33 |     expect('connect' in underlying).toBe(true);
34 |     expect(typeof (underlying as { connect?: unknown }).connect).toBe('function');
35 |   });
36 | });
37 | 
```

--------------------------------------------------------------------------------
/.claude/commands/release.md:
--------------------------------------------------------------------------------

```markdown
 1 | # Release a new version
 2 | 
 3 | You are about to make a release of the project. Please follow these steps:
 4 | 
 5 | 1. **Create a new branch** for the release, e.g., `release/v1.0.0`.
 6 | 2. **Update the version number** in `package.json` according to [Semantic Versioning](https://semver.org/) and based on the changes made since the last release.
 7 | 3. **Update the changelog** in `CHANGELOG.md` to reflect the changes made in this release. Use the `date` command to get the current date in the format `YYYY-MM-DD`.
 8 |    Use the following format for the changelog entry:
 9 | 
10 |    ```
11 |    ## [v1.0.0] - YYYY-MM-DD
12 |    - Description of changes
13 |    - Another change
14 |    ```
15 | 
16 | 4. Update the README.md file if necessary, ensuring it reflects the latest changes and version number.
17 | 5. **Commit the changes** making sure that the pre-commit hook passes without warnings or errors. ^:wq
18 | 6. **Push the branch** to the remote repository.
19 | 7. **Create a pull request** to trigger the CI/CD pipeline.
20 | 8. **Wait for the CI/CD pipeline to complete** successfully. Ensure that all tests pass and the build is successful.
21 | 9. **Merge the pull request** into the main branch once the CI/CD pipeline has passed. The merge should be done using the "Squash and merge" option to keep the commit history clean and the branch should be deleted after merging.
22 | 10. **Make the release** by using the `gh` CLI tool:
23 | 
24 | ```bash
25 | gh release create v1.0.0 --title "Release v1.0.0" --notes "Release notes for v1.0.0"
26 | ```
27 | 
```

--------------------------------------------------------------------------------
/src/domains/metrics.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import type { PaginationParams, SonarQubeMetricsResult } from '../types/index.js';
 2 | import { BaseDomain } from './base.js';
 3 | 
 4 | /**
 5 |  * Domain module for metrics-related operations
 6 |  */
 7 | export class MetricsDomain extends BaseDomain {
 8 |   /**
 9 |    * Gets available metrics from SonarQube
10 |    * @param params Parameters including pagination
11 |    * @returns Promise with the list of metrics
12 |    */
13 |   async getMetrics(params?: PaginationParams): Promise<SonarQubeMetricsResult> {
14 |     const { page, pageSize } = params ?? {};
15 | 
16 |     const request: {
17 |       p?: number;
18 |       ps?: number;
19 |     } = {
20 |       ...(page && { p: page }),
21 |       ...(pageSize && { ps: pageSize }),
22 |     };
23 | 
24 |     const response = await this.webApiClient.metrics.search(request);
25 | 
26 |     // The API might return paging info
27 |     const paging = (
28 |       response as unknown as {
29 |         paging?: { pageIndex: number; pageSize: number; total: number };
30 |       }
31 |     ).paging;
32 | 
33 |     return {
34 |       metrics: response.metrics.map((metric) => ({
35 |         id: metric.id ?? '',
36 |         key: metric.key,
37 |         name: metric.name,
38 |         description: metric.description ?? '',
39 |         domain: metric.domain ?? '',
40 |         type: metric.type,
41 |         direction: metric.direction ?? 0,
42 |         qualitative: metric.qualitative ?? false,
43 |         hidden: metric.hidden ?? false,
44 |         custom: metric.custom ?? false,
45 |       })),
46 |       paging: paging ?? {
47 |         pageIndex: page ?? 1,
48 |         pageSize: pageSize ?? 100,
49 |         total: response.metrics.length,
50 |       },
51 |     };
52 |   }
53 | }
54 | 
```

--------------------------------------------------------------------------------
/src/handlers/quality-gates.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import type { ProjectQualityGateParams, ISonarQubeClient } from '../types/index.js';
 2 | import { getDefaultClient } from '../utils/client-factory.js';
 3 | import { createStructuredResponse } from '../utils/structured-response.js';
 4 | 
 5 | /**
 6 |  * Handler for listing quality gates
 7 |  * @param client Optional SonarQube client instance
 8 |  * @returns Promise with the quality gates list
 9 |  */
10 | export async function handleSonarQubeListQualityGates(
11 |   client: ISonarQubeClient = getDefaultClient()
12 | ) {
13 |   const result = await client.listQualityGates();
14 | 
15 |   return createStructuredResponse(result);
16 | }
17 | 
18 | /**
19 |  * Handler for getting a specific quality gate
20 |  * @param params Parameters containing the quality gate ID
21 |  * @param client Optional SonarQube client instance
22 |  * @returns Promise with the quality gate details
23 |  */
24 | export async function handleSonarQubeGetQualityGate(
25 |   params: { id: string },
26 |   client: ISonarQubeClient = getDefaultClient()
27 | ) {
28 |   const result = await client.getQualityGate(params.id);
29 | 
30 |   return createStructuredResponse(result);
31 | }
32 | 
33 | /**
34 |  * Handler for getting quality gate status for a project
35 |  * @param params Parameters for the quality gate status request
36 |  * @param client Optional SonarQube client instance
37 |  * @returns Promise with the quality gate status
38 |  */
39 | export async function handleSonarQubeQualityGateStatus(
40 |   params: ProjectQualityGateParams,
41 |   client: ISonarQubeClient = getDefaultClient()
42 | ) {
43 |   const result = await client.getProjectQualityGateStatus(params);
44 | 
45 |   return createStructuredResponse(result);
46 | }
47 | 
```

--------------------------------------------------------------------------------
/src/__tests__/string-to-number-transform.test.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { describe, it, expect } from 'vitest';
 2 | import { nullToUndefined, stringToNumberTransform } from '../index.js';
 3 | describe('String to Number Transform', () => {
 4 |   describe('nullToUndefined', () => {
 5 |     it('should transform null to undefined', () => {
 6 |       expect(nullToUndefined(null)).toBeUndefined();
 7 |     });
 8 |     it('should not transform undefined', () => {
 9 |       expect(nullToUndefined(undefined)).toBeUndefined();
10 |     });
11 |     it('should not transform non-null values', () => {
12 |       expect(nullToUndefined('test')).toBe('test');
13 |       expect(nullToUndefined(123)).toBe(123);
14 |       expect(nullToUndefined(true)).toBe(true);
15 |       expect(nullToUndefined(false)).toBe(false);
16 |       expect(nullToUndefined(0)).toBe(0);
17 |       expect(nullToUndefined('')).toBe('');
18 |     });
19 |   });
20 |   describe('stringToNumberTransform', () => {
21 |     it('should transform valid string numbers to integers', () => {
22 |       expect(stringToNumberTransform('123')).toBe(123);
23 |       expect(stringToNumberTransform('0')).toBe(0);
24 |       expect(stringToNumberTransform('-10')).toBe(-10);
25 |     });
26 |     it('should return null for invalid number strings', () => {
27 |       expect(stringToNumberTransform('abc')).toBeNull();
28 |       expect(stringToNumberTransform('')).toBeNull();
29 |       expect(stringToNumberTransform('123abc')).toBe(123); // parseInt behavior
30 |     });
31 |     it('should pass through null and undefined values', () => {
32 |       expect(stringToNumberTransform(null)).toBeNull();
33 |       expect(stringToNumberTransform(undefined)).toBeUndefined();
34 |     });
35 |   });
36 | });
37 | 
```

--------------------------------------------------------------------------------
/src/domains/projects.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import type { PaginationParams, SonarQubeProjectsResult } from '../types/index.js';
 2 | import { BaseDomain } from './base.js';
 3 | 
 4 | /**
 5 |  * Domain module for project-related operations
 6 |  */
 7 | export class ProjectsDomain extends BaseDomain {
 8 |   /**
 9 |    * Lists all projects in SonarQube
10 |    * @param params Pagination and organization parameters
11 |    * @returns Promise with the list of projects
12 |    */
13 |   async listProjects(params?: PaginationParams): Promise<SonarQubeProjectsResult> {
14 |     const { page, pageSize } = params ?? {};
15 |     this.logger.debug('Listing projects', { page, pageSize, organization: this.organization });
16 | 
17 |     try {
18 |       const builder = this.webApiClient.projects.search();
19 | 
20 |       if (page !== undefined) {
21 |         builder.page(page);
22 |       }
23 |       if (pageSize !== undefined) {
24 |         builder.pageSize(pageSize);
25 |       }
26 | 
27 |       const response = await builder.execute();
28 |       this.logger.debug('Projects retrieved successfully', { count: response.components.length });
29 | 
30 |       // Transform to our interface
31 |       return {
32 |         projects: response.components.map((component) => ({
33 |           key: component.key,
34 |           name: component.name,
35 |           qualifier: component.qualifier,
36 |           visibility: component.visibility,
37 |           lastAnalysisDate: component.lastAnalysisDate,
38 |           revision: component.revision,
39 |           managed: component.managed,
40 |         })),
41 |         paging: response.paging,
42 |       };
43 |     } catch (error) {
44 |       this.logger.error('Failed to list projects', error);
45 |       throw error;
46 |     }
47 |   }
48 | }
49 | 
```

--------------------------------------------------------------------------------
/src/handlers/hotspots.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import type {
 2 |   HotspotSearchParams,
 3 |   HotspotStatusUpdateParams,
 4 |   ISonarQubeClient,
 5 | } from '../types/index.js';
 6 | import { getDefaultClient } from '../utils/client-factory.js';
 7 | import { createStructuredResponse, createTextResponse } from '../utils/structured-response.js';
 8 | 
 9 | /**
10 |  * Handler for searching security hotspots
11 |  * @param params Parameters for the hotspots search
12 |  * @param client Optional SonarQube client instance
13 |  * @returns Promise with the hotspots search result
14 |  */
15 | export async function handleSonarQubeHotspots(
16 |   params: HotspotSearchParams,
17 |   client: ISonarQubeClient = getDefaultClient()
18 | ) {
19 |   const result = await client.hotspots(params);
20 | 
21 |   return createStructuredResponse(result);
22 | }
23 | 
24 | /**
25 |  * Handler for getting hotspot details
26 |  * @param hotspotKey The key of the hotspot
27 |  * @param client Optional SonarQube client instance
28 |  * @returns Promise with the hotspot details
29 |  */
30 | export async function handleSonarQubeHotspot(
31 |   hotspotKey: string,
32 |   client: ISonarQubeClient = getDefaultClient()
33 | ) {
34 |   const result = await client.hotspot(hotspotKey);
35 | 
36 |   return createStructuredResponse(result);
37 | }
38 | 
39 | /**
40 |  * Handler for updating hotspot status
41 |  * @param params Parameters for the hotspot status update
42 |  * @param client Optional SonarQube client instance
43 |  * @returns Promise with success message
44 |  */
45 | export async function handleSonarQubeUpdateHotspotStatus(
46 |   params: HotspotStatusUpdateParams,
47 |   client: ISonarQubeClient = getDefaultClient()
48 | ) {
49 |   await client.updateHotspotStatus(params);
50 | 
51 |   return createTextResponse('Hotspot status updated successfully');
52 | }
53 | 
```

--------------------------------------------------------------------------------
/src/utils/structured-response.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
 2 | 
 3 | /**
 4 |  * Creates a structured response for MCP tools that includes both text content
 5 |  * (for backward compatibility) and structured content (for better machine readability)
 6 |  *
 7 |  * @param data The structured data to return
 8 |  * @returns A CallToolResult with both text and structured content
 9 |  */
10 | export function createStructuredResponse(data: unknown): CallToolResult {
11 |   return {
12 |     content: [
13 |       {
14 |         type: 'text' as const,
15 |         text: JSON.stringify(data, null, 2),
16 |       },
17 |     ],
18 |     structuredContent: data as Record<string, unknown>,
19 |   };
20 | }
21 | 
22 | /**
23 |  * Creates a simple text response without structured content
24 |  *
25 |  * @param text The text content to return
26 |  * @returns A CallToolResult with only text content
27 |  */
28 | export function createTextResponse(text: string): CallToolResult {
29 |   return {
30 |     content: [
31 |       {
32 |         type: 'text' as const,
33 |         text,
34 |       },
35 |     ],
36 |   };
37 | }
38 | 
39 | /**
40 |  * Creates an error response with optional structured error details
41 |  *
42 |  * @param message The error message
43 |  * @param details Optional structured error details
44 |  * @returns A CallToolResult marked as an error
45 |  */
46 | export function createErrorResponse(message: string, details?: unknown): CallToolResult {
47 |   const errorData: Record<string, unknown> = {
48 |     error: message,
49 |   };
50 | 
51 |   if (details !== undefined) {
52 |     errorData.details = details;
53 |   }
54 | 
55 |   return {
56 |     content: [
57 |       {
58 |         type: 'text' as const,
59 |         text: message,
60 |       },
61 |     ],
62 |     structuredContent: errorData,
63 |     isError: true,
64 |   };
65 | }
66 | 
```

--------------------------------------------------------------------------------
/src/handlers/system.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import type { ISonarQubeClient } from '../types/index.js';
 2 | import { getDefaultClient } from '../utils/client-factory.js';
 3 | import { createLogger } from '../utils/logger.js';
 4 | import { withErrorHandling } from '../errors.js';
 5 | import { withMCPErrorHandling } from '../utils/error-handler.js';
 6 | import { createStructuredResponse, createTextResponse } from '../utils/structured-response.js';
 7 | 
 8 | const logger = createLogger('handlers/system');
 9 | 
10 | /**
11 |  * Handler for getting SonarQube system health status
12 |  * @param client Optional SonarQube client instance
13 |  * @returns Promise with the health status result
14 |  */
15 | export const handleSonarQubeGetHealth = withMCPErrorHandling(
16 |   async (client: ISonarQubeClient = getDefaultClient()) => {
17 |     logger.debug('Handling get health request');
18 | 
19 |     const result = await withErrorHandling('Get SonarQube health status', () => client.getHealth());
20 |     logger.info('Successfully retrieved health status', { health: result.health });
21 | 
22 |     return createStructuredResponse(result);
23 |   }
24 | );
25 | 
26 | /**
27 |  * Handler for getting SonarQube system status
28 |  * @param client Optional SonarQube client instance
29 |  * @returns Promise with the system status result
30 |  */
31 | export async function handleSonarQubeGetStatus(client: ISonarQubeClient = getDefaultClient()) {
32 |   const result = await client.getStatus();
33 | 
34 |   return createStructuredResponse(result);
35 | }
36 | 
37 | /**
38 |  * Handler for pinging SonarQube system
39 |  * @param client Optional SonarQube client instance
40 |  * @returns Promise with the ping result
41 |  */
42 | export async function handleSonarQubePing(client: ISonarQubeClient = getDefaultClient()) {
43 |   const result = await client.ping();
44 | 
45 |   return createTextResponse(result);
46 | }
47 | 
```

--------------------------------------------------------------------------------
/src/schemas/components.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { z } from 'zod';
 2 | import { stringToNumberTransform } from '../utils/transforms.js';
 3 | import { pullRequestSchema } from './common.js';
 4 | 
 5 | /**
 6 |  * Valid component qualifiers based on SonarQube API
 7 |  */
 8 | const componentQualifierSchema = z.enum([
 9 |   'TRK', // Project
10 |   'DIR', // Directory
11 |   'FIL', // File
12 |   'UTS', // Unit Test
13 |   'BRC', // Branch
14 |   'APP', // Application
15 |   'VW', // View
16 |   'SVW', // Sub-view
17 |   'LIB', // Library
18 | ]);
19 | 
20 | /**
21 |  * Schema for components tool
22 |  */
23 | export const componentsToolSchema = {
24 |   // Search parameters
25 |   query: z.string().optional().describe('Text search query'),
26 |   qualifiers: z
27 |     .array(componentQualifierSchema)
28 |     .optional()
29 |     .describe('Component types: TRK, DIR, FIL, UTS, BRC, APP, VW, SVW, LIB'),
30 |   language: z.string().optional().describe('Programming language filter'),
31 | 
32 |   // Tree navigation parameters
33 |   component: z.string().optional().describe('Component key for tree navigation'),
34 |   strategy: z.enum(['all', 'children', 'leaves']).optional().describe('Tree traversal strategy'),
35 | 
36 |   // Show component parameter
37 |   key: z.string().optional().describe('Component key to show details for'),
38 | 
39 |   // Common parameters
40 |   asc: z
41 |     .union([z.boolean(), z.string().transform((val) => val === 'true')])
42 |     .optional()
43 |     .describe('Sort ascending/descending'),
44 |   ps: z
45 |     .string()
46 |     .optional()
47 |     .transform(stringToNumberTransform)
48 |     .describe('Page size (default: 100, max: 500)'),
49 |   p: z.string().optional().transform(stringToNumberTransform).describe('Page number'),
50 | 
51 |   // Additional filters
52 |   branch: z.string().optional().describe('Branch name'),
53 |   pullRequest: pullRequestSchema.describe('Pull request ID'),
54 | };
55 | 
```
Page 1/11FirstPrevNextLast