Content
<!-- Generated by https://github.com/flowgent-labs/mcpfather -->
# sonatypeiq-mcp
[](https://go.dev/)
[](https://modelcontextprotocol.io/)
[](https://prometheus.io/)
[](https://opentelemetry.io/)
[](https://openid.net/connect/)
[](https://ldap.com/)
[](https://helm.sh/)
> An Enterprise-grade MCP server, specifically designed for AI to call Sonatype Lifecycle Public REST API APIs, generated from MCPFather — exposes **252 native tools**. Each API operation becomes an AI-callable tool with typed schemas and customized aggregate virtual tools, auth forwarding, and observability built-in, and even use as regular CLI.
## Quick Start
```sh
make
# Or with OpenTelemetry distributed tracing (gRPC or HTTP)
make build-with-otel-grpc # OTLP gRPC exporter
make build-with-otel-http # OTLP HTTP/protobuf exporter
```
### Start in `HTTP` mode (example)
```sh
# Configure your upstream API
export MCP__UPSTREAM__ENDPOINT=https://api.example.com
export MCP__AUTH__BACKEND__STATIC__BEARER_TOKEN=your-token
./bin/sonatypeiq-mcp --transport http --port 8080 &
```
- Inspection MCP frontend Authentication (OAuth2.1).
```bash
export MCP__AUTH__FRONTEND__OIDC__ENABLED=true
export MCP__AUTH__FRONTEND__OIDC__ISSUER="https://keycloak.example.com/realms/master"
export MCP__AUTH__FRONTEND__OIDC__AUDIENCE="sonatypeiq-mcp"
./bin/sonatypeiq-mcp -v 10 --transport http --port 8080
# Obtain the OAuth2.1 metadata.
curl -s https://iam.example.com/realms/master/.well-known/openid-configuration
curl -s localhost:8080/.well-known/oauth-protected-resource
#{"resource":"sonatypeiq-mcp","authorization_servers":["https://keycloak.example.com/realms/master"],"bearer_methods_supported":["header"]}
```
### Run in `CLI` mode (example)
```sh
./bin/sonatypeiq-mcp -v 1 -t cli list
./bin/sonatypeiq-mcp -v 1 -t cli <tool-name> [OPTIONS]
```
## Options
| Flag | Default | Description |
|------|---------|-------------|
| `-t, --transport` | `stdio` | `stdio` / `http` / `cli` |
| `-p, --port` | `8080` | HTTP server port |
| `--metrics-port` | `0` | Override mgmt port (0 = use config) |
| `-v, --verbose` | `0` | Log verbosity (0–10) |
| `--print-default-config` | — | Print default config.yaml to stdout |
## Authentication
Auth is split into two independent layers — neither shares credentials with the other:
| Layer | Config YAML path | Env var prefix | Role |
|---|---|---|---|
| **Frontend** | `auth.frontend.oidc` | `MCP__AUTH__FRONTEND__OIDC__*` | Validates AI agent bearer tokens (inbound) |
| **Backend OIDC** | `auth.backend.oidc` | `MCP__AUTH__BACKEND__OIDC__*` | Server's own OIDC client_credentials for upstream APIs |
| **Backend LDAP** | `auth.backend.ldap` | `MCP__AUTH__BACKEND__LDAP__*` | Server's own LDAP service-account bind for upstream APIs |
| **Backend Static** | `auth.backend.static` | `MCP__AUTH__BACKEND__STATIC__*` | Server's own static token/cookie for upstream APIs |
**Frontend (inbound)** — validates bearer tokens presented by AI agents (MCP clients).
Only applies to `--transport http`; stdio has no network boundary. Standard OIDC JWT
bearer validation per RFC 9728 / MCP Authorization spec.
**Backend (outbound)** — credentials the MCP server uses to call upstream APIs.
Token priority (first available wins):
1. **OIDC** client_credentials grant (`auth.backend.oidc.*`)
2. **LDAP** service account bind (`auth.backend.ldap.*`)
3. **Static** bearer token (`auth.backend.static.bearer_token`)
The AI agent's inbound token is **never** forwarded upstream (MCP spec: Token Passthrough Prohibition).
Cookie-based auth is also available via `auth.backend.static.cookie_token`.
## Configuration
Create `~/.sonatypeiq-mcp/config.yaml` (run `--print-default-config` for a full template):
```yaml
upstream:
endpoint: "" # upstream API base URL (e.g. https://api.example.com)
# When true, the MCP session ID is forwarded as X-MCP-Session-ID header.
enable_mcp_session_forward: true
runtime:
download_dir: ""
log_authorization: false
# ---- Authentication ----
# frontend = inbound: validates bearer tokens presented by MCP clients (AI agents).
# backend = outbound: credentials the server uses to call upstream APIs.
# The two are independent — the inbound token is never reused outbound
# (see MCP Authorization spec: Token Passthrough Prohibition).
auth:
frontend:
# Standard OAuth 2.1 / OIDC JWT bearer validation (Resource Server role, RFC 9728).
# Only enforced on the http transport; stdio has no network boundary.
oidc:
enabled: false
issuer: "" # e.g. https://idp.example.com/realms/myrealm
jwks_uri: "" # optional override (auto-discovered from issuer if empty)
audience: "" # expected JWT "aud" claim; also published as the RFC 9728 protected-resource identifier
# When true, validated frontend JWT claims (sub, email) are forwarded upstream
# as X-MCP-Client-Token-Sub and X-MCP-Client-Token-Email headers.
enable_client_token_claim_forward: true
# Additional JWT claims to forward as X-MCP-Client-Token-<Header-Name> headers.
# e.g. ["given_name", "family_name", "preferred_username"]
# additional_client_token_claim_forward: []
# Outbound: credentials the server uses to call upstream APIs.
backend:
oidc:
enabled: true
issuer: https://idp.example.com/realms/myrealm
client_id: my-client
client_secret: "${MCP__AUTH__BACKEND__OIDC__CLIENT_SECRET}"
scopes: openid
# token_url: "" # auto-discovered from issuer /.well-known
ldap:
enabled: false
url: ldaps://ldap.example.com
base_dn: dc=example,dc=com
bind_dn: cn=svc,dc=example,dc=com
bind_password: "${MCP__AUTH__BACKEND__LDAP__BIND_PASSWORD}"
static:
bearer_token: "${MCP__AUTH__BACKEND__STATIC__BEARER_TOKEN}" # or set cookie_token
nativeTools:
expose:
register_all_tools_by_default: true # expose all native tools
# includes: [Tool1, Tool2] # or whitelist specific tools
# excludes: [Tool3] # hide noisy tools
```
All values can be set via `MCP__`-prefixed environment variables (e.g. `MCP__AUTH__BACKEND__OIDC__CLIENT_ID`).
## Management — Metrics, Tracing, Pprof
```yaml
mgmt:
enabled: true
host: 0.0.0.0
port: 9991
otel:
enabled: false
endpoint: localhost:4317
protocol: grpc
sample_rate: 1.0
metrics:
enabled: true
prometheus: true
export_interval: 30s
pprof:
enabled: false
server_bind: 0.0.0.0:6669
```
```sh
./bin/sonatypeiq-mcp --transport http --port 8080
curl http://localhost:9991/metrics # Prometheus endpoint
curl http://localhost:9991/health # health check
```
Trace spans are named `mcp.tool.<name>`. W3C `traceparent` is propagated to upstream calls.
## Available Tools (252)
| Tool | Description |
|------|-------------|
| `Add` | Use this method to create a new user. Permissions required: Edit System Configuration and Users |
| `AddApplication` | Use this method to create an application under an organization. Use the Organization REST API to obtain organizationId. Permissions required: Add Application (on parent organization) |
| `AddArtifactoryConnection` | Use this method to add a new Artifactory connection. Permissions required: Edit IQ Elements |
| `AddAutoPolicyWaiveExclusion` | Use this method to create an auto policy waiver exclusion for a specified auto policy waiver. Permissions required: Waive Policy Violations |
| `AddAutoPolicyWaiver` | Use this method to create an auto policy waiver configuration. Only one configuration can exist at a time for a given application or organization. Permissions required: Waive Policy Violations |
| `AddAutoPolicyWaivers` | Use this method to create an auto policy waiver configuration. Only three configurations can exist at a time for a given application or organization. With different combinations for reachable/pathForward Permissions required: Waive Policy Violations |
| `AddBulkPolicyWaivers` | Use this method to create policy waivers for multiple policy violations. Permissions required: Waive Policy Violations |
| `AddLabel` | Use this method to create and assign a component label to an application, organization or repository. Permissions required: Edit IQ Elements |
| `AddLicenseOverride` | Use this method to add or update a license override to a component for a given owner scope. Permissions required: Change Licenses |
| `AddOrganization` | Use this method to add a new organization. Permissions required: Edit IQ Elements |
| `AddPolicyWaiverByPolicyViolationId` | Use this method to create a policy waiver. Permissions required: Waive Policy Violations |
| `AddPolicyWaiverRequestByPolicyViolationId` | Use this method to create a policy waiver request. Permissions required: View IQ Elements |
| `AddProprietaryComponentNames` | Adds a list of proprietary component namespaces for the specified format to prevent namespace confusion attacks. Permissions required: Evaluate Individual Components |
| `AddRepositoryManager` | Use this method to add a new repository manager. Permissions required: Edit IQ Elements |
| `AddRole` | Use this method to create a new custom role with specified permissions. Permissions required: Edit Roles |
| … | *237 more tools not shown* |
## Virtual Tools
Compose native tools via a declarative pipeline DSL:
```yaml
virtualTools:
- name: MyVirtualTool
description: Chain multiple native tools together
inputSchema:
type: object
properties:
appId: { type: string }
required: [appId]
pipeline:
- id: getApp
kind: call
spec: { tool: GetApplication, args: { applicationId: "$input.appId" } }
- id: appName
kind: jq
spec: { from: "$getApp", expr: .name }
- id: done
kind: return
spec: { from: "$appName" }
```
Pipeline kinds: `call`, `jq`, `foreach`, `emit`, `return`.
## Agent Integration
### OpenCode
- `~/.config/opencode/opencode.json`:
```json
{
"mcp": {
"sonatypeiq-mcp": {
"type": "local",
"command": ["bash", "-c", "/path/to/sonatypeiq-mcp"],
"args": ["--transport", "stdio"],
"env": {
"MCP__UPSTREAM__ENDPOINT": "https://api.example.com",
"MCP__AUTH__BACKEND__STATIC__BEARER_TOKEN": "your-token",
"MCP__AUTH__BACKEND__STATIC__BEARER_TOKEN_FILE": "/path/to/fallback/.credentials"
},
"enabled": true
}
}
}
```
### Claude Code
- `~/.claude.json`:
```json
{
"mcpServers": {
"sonatypeiq-mcp": {
"command": "/path/to/sonatypeiq-mcp",
"args": ["--transport", "stdio"],
"env": {
"MCP__UPSTREAM__ENDPOINT": "https://api.example.com",
"MCP__AUTH__BACKEND__STATIC__BEARER_TOKEN": "your-token",
"MCP__AUTH__BACKEND__STATIC__BEARER_TOKEN_FILE": "/path/to/fallback/.credentials"
}
}
}
}
```
### Codex CLI
- `~/.codex/config.toml`:
```toml
[mcp_servers.sonatypeiq-mcp]
url = "http://localhost:8080/mcp"
bearer_token_env_var = "MCP__AUTH__BACKEND__STATIC__BEARER_TOKEN"
```
### Cursor
- `~/.cursor/mcp.json`:
```json
{
"mcpServers": {
"sonatypeiq-mcp": {
"command": "/path/to/sonatypeiq-mcp",
"args": ["--transport", "stdio"],
"env": {
"MCP__UPSTREAM__ENDPOINT": "https://api.example.com",
"MCP__AUTH__BACKEND__STATIC__BEARER_TOKEN": "your-token",
"MCP__AUTH__BACKEND__STATIC__BEARER_TOKEN_FILE": "/path/to/fallback/.credentials"
}
}
}
}
```
### OpenCode (Remote)
- `~/.config/opencode/opencode.json`:
```json
{
"mcp": {
"sonatypeiq-mcp": {
"type": "remote",
"url": "http://localhost:8080/mcp",
"env": {
"MCP__UPSTREAM__ENDPOINT": "https://api.example.com",
"MCP__AUTH__BACKEND__STATIC__BEARER_TOKEN": "your-token",
"MCP__AUTH__BACKEND__STATIC__BEARER_TOKEN_FILE": "/path/to/fallback/.credentials"
}
}
}
}
```
### Claude Code (Remote)
- `~/.claude.json` (User MCPs):
```json
{
"mcpServers": {
"sonatypeiq-mcp": {
"url": "http://localhost:8080/mcp",
"env": {
"MCP__UPSTREAM__ENDPOINT": "https://api.example.com",
"MCP__AUTH__BACKEND__STATIC__BEARER_TOKEN": "your-token",
"MCP__AUTH__BACKEND__STATIC__BEARER_TOKEN_FILE": "/path/to/fallback/.credentials"
}
}
}
}
```
### Codex CLI (Remote)
- `~/.codex/config.toml`:
```toml
[mcp_servers.sonatypeiq-mcp]
url = "http://localhost:8080/mcp"
bearer_token_env_var = "MCP__AUTH__BACKEND__STATIC__BEARER_TOKEN"
```
### Cursor (Remote)
- `~/.cursor/mcp.json`:
```json
{
"mcpServers": {
"sonatypeiq-mcp": {
"url": "http://localhost:8080/mcp"
}
}
}
```
## Deployment — Docker
### Build
```sh
make build-image
```
Or manually:
```sh
docker build -t ghcr.io/<YOUR_ORG>/sonatypeiq-mcp:latest -f deploy/docker/Dockerfile .
docker push ghcr.io/<YOUR_ORG>/sonatypeiq-mcp:latest
```
### Run
Pull the pre-built image from GitHub Container Registry:
```sh
docker pull ghcr.io/<YOUR_ORG>/sonatypeiq-mcp:latest
```
First generate a default config, then mount it when running:
```sh
docker run --rm ghcr.io/<YOUR_ORG>/sonatypeiq-mcp:latest --print-default-config > ~/.sonatypeiq-mcp/config.yaml
```
- **Static bearer token**
```sh
docker run -d --name sonatypeiq-mcp \
-p 8080:8080 -p 9991:9991 \
-e MCP__UPSTREAM__ENDPOINT="https://api.example.com" \
-e MCP__AUTH__BACKEND__STATIC__BEARER_TOKEN="YOUR_BEARER_TOKEN" \
-v ~/.sonatypeiq-mcp:/home/mcp/.sonatypeiq-mcp \
ghcr.io/<YOUR_ORG>/sonatypeiq-mcp:latest \
--transport http --port 8080
```
- **OIDC backend auth**
```sh
docker run -d --name sonatypeiq-mcp \
-p 8080:8080 -p 9991:9991 \
-e MCP__UPSTREAM__ENDPOINT="https://api.example.com" \
-e MCP__AUTH__BACKEND__OIDC__ENABLED=true \
-e MCP__AUTH__BACKEND__OIDC__ISSUER="https://idp.example.com/realms/myrealm" \
-e MCP__AUTH__BACKEND__OIDC__CLIENT_ID="my-client" \
-e MCP__AUTH__BACKEND__OIDC__CLIENT_SECRET="YOUR_CLIENT_SECRET" \
-v ~/.sonatypeiq-mcp:/home/mcp/.sonatypeiq-mcp \
ghcr.io/<YOUR_ORG>/sonatypeiq-mcp:latest \
--transport http --port 8080
```
- **LDAP backend auth**
```sh
docker run -d --name sonatypeiq-mcp \
-p 8080:8080 -p 9991:9991 \
-e MCP__UPSTREAM__ENDPOINT="https://api.example.com" \
-e MCP__AUTH__BACKEND__LDAP__ENABLED=true \
-e MCP__AUTH__BACKEND__LDAP__URL="ldaps://ldap.example.com" \
-e MCP__AUTH__BACKEND__LDAP__BASE_DN="dc=example,dc=com" \
-e MCP__AUTH__BACKEND__LDAP__BIND_DN="cn=svc,dc=example,dc=com" \
-e MCP__AUTH__BACKEND__LDAP__BIND_PASSWORD="YOUR_BIND_PASSWORD" \
-v ~/.sonatypeiq-mcp:/home/mcp/.sonatypeiq-mcp \
ghcr.io/<YOUR_ORG>/sonatypeiq-mcp:latest \
--transport http --port 8080
```
### Test with mcpclient.sh
After the container starts, use the bundled `mcpclient.sh` to verify.
> **Note:** `mcpclient.sh` only supports **backend static** token auth. If the server requires
> **frontend OIDC/LDAP** authentication, use a real AI-agent MCP client instead.
```sh
# Point to the mapped host port (include /mcp path)
export MCP_SERVER_ENDPOINT=http://localhost:18080/mcp
# Call any tool (example: Add)
./mcpclient.sh call Add '{"<param>":"<value>"}'
# List all available tools
./mcpclient.sh list-tools
```
> **Tip:** Map the host config directory for persistent configuration:
> `-v ~/.sonatypeiq-mcp:/home/mcp/.sonatypeiq-mcp`
## Deployment — Kubernetes (Helm)
First generate a default config, then mount it when running:
```sh
docker run --rm ghcr.io/<YOUR_ORG>/sonatypeiq-mcp:latest --print-default-config > ~/.sonatypeiq-mcp/config.yaml
```
- **Static bearer token**
```sh
helm upgrade -i sonatypeiq-mcp deploy/helm \
--set image.repository=ghcr.io/<YOUR_ORG>/sonatypeiq-mcp \
--set image.tag=latest \
--set secret.static.create=true \
--set secret.static.bearerToken="YOUR_BEARER_TOKEN" \
--set config.upstream.endpoint="https://api.example.com"
```
- **OIDC authentication**
```sh
helm upgrade -i sonatypeiq-mcp deploy/helm \
--set image.repository=ghcr.io/<YOUR_ORG>/sonatypeiq-mcp \
--set image.tag=latest \
--set secret.static.create=true \
--set secret.static.oidcClientSecret="YOUR_OIDC_CLIENT_SECRET" \
--set config.auth.backend.oidc.enabled=true \
--set config.auth.backend.oidc.issuer="https://idp.example.com" \
--set config.auth.backend.oidc.clientId="my-client" \
--set config.upstream.endpoint="https://api.example.com"
```
- **LDAP authentication**
```sh
helm upgrade -i sonatypeiq-mcp deploy/helm \
--set image.repository=ghcr.io/<YOUR_ORG>/sonatypeiq-mcp \
--set image.tag=latest \
--set secret.static.create=true \
--set secret.static.ldapBindPassword="YOUR_LDAP_BIND_PASSWORD" \
--set config.auth.backend.ldap.enabled=true \
--set config.auth.backend.ldap.url="ldaps://ldap.example.com" \
--set config.auth.backend.ldap.bindDN="cn=svc,dc=example,dc=com" \
--set config.upstream.endpoint="https://api.example.com"
```
See `deploy/helm/values.yaml` for all configurable parameters.
## Contributing
We welcome contributions! Here's how you can help:
1. **Fork** the repository and create a feature branch
2. **Make your changes** — add features, fix bugs, or improve documentation
3. **Add tests** — every new feature or bug fix should include unit tests
4. **Run the test suite** — `make test` must pass with no regressions
5. **Submit a Pull Request** — describe what you changed and why
### Development Setup
```sh
git clone https://github.com/<YOUR_ORG>/sonatypeiq-mcp.git
cd sonatypeiq-mcp
make build
make test
```
### Code Style
- Follow standard Go conventions (`go fmt`, `go vet`)
- Keep functions small and focused
- Write clear commit messages
Please read [CONTRIBUTING.md](CONTRIBUTING.md) for detailed guidelines and our [Code of Conduct](CODE_OF_CONDUCT.md).
## License
This project is licensed under the MIT License — see the [LICENSE](LICENSE) file for details.
## Contact
For questions, suggestions, or support:
- **GitHub Issues**: [Create an issue](../../sonatypeiq-mcp/issues)
- **Discussions**: [Start a discussion](../../sonatypeiq-mcp/discussions)
- **Email**: <jameswong1376@gmail.com>
## Acknowledgments
This MCP server was generated by [MCPFather](https://github.com/flowgent-labs/mcpfather), an enterprise-grade OpenAPI-to-MCP code generator.
Built with these excellent open-source projects:
- [mcp-go](https://github.com/mark3labs/mcp-go) — Go SDK for the Model Context Protocol
- [OpenTelemetry](https://opentelemetry.io/) — observability framework for metrics and tracing
- [Prometheus](https://prometheus.io/) — metrics collection and alerting
- [Viper](https://github.com/spf13/viper) — Go configuration management
- [go-jq](https://github.com/itchyny/gojq) — Pure Go implementation of jq
- [Keycloak](https://www.keycloak.org/) — Open Source Identity and Access Management
MCP Config
Below is the configuration for this MCP Server. You can copy it directly to Cursor or other MCP clients.
mcp.json
Connection Info
You Might Also Like
No recommendations available