Content
<!-- Generated by https://github.com/flowgent-labs/mcpfather -->
# nexus-mcp
[](https://go.dev/)
[](https://modelcontextprotocol.io/)
[](https://prometheus.io/)
[](https://opentelemetry.io/)
[](https://openid.net/connect/)
[](https://helm.sh/)
> An Enterprise-grade MCP server, specifically designed for AI to call Nexus Repository Manager REST API APIs, generated from MCPFather — exposes **202 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__WEB_TOKEN=your-token
./bin/nexus-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="nexus-mcp"
./bin/nexus-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":"nexus-mcp","authorization_servers":["https://keycloak.example.com/realms/master"],"bearer_methods_supported":["header"]}
```
### Run in `CLI` mode (example)
```sh
./bin/nexus-mcp -v 1 -t cli list
./bin/nexus-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 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. **Static** web token (`auth.backend.static.web_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 `~/.nexus-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
# Static credentials for legacy / simple APIs
static:
web_token: "${MCP__AUTH__BACKEND__STATIC__WEB_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/nexus-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 (202)
| Tool | Description |
|------|-------------|
| `CreateBlobstoresFile` | Create a file blob store |
| `CreateBlobstoresS3` | Create an S3 blob store |
| `CreateCleanupRun` | Run cleanup on a repository (dry run or async execution) - Runs cleanup on the specified `repository` against the policies attached to it. Behavior depends on the `dryRun` flag in the request body: - `dryRun: true` — Synchronously evaluates the policies and returns **200 OK** with a `CleanupExecutionStatusXO` whose `componentCount` is the number of components that *would* be deleted. No components are removed. - `dryRun: false` — Schedules an asynchronous deletion and returns **202 Accepted** immediately with a `CleanupExecutionStatusXO` containing the generated execution `id` and `status=RUNNING`. Poll `GET /service/rest/v1/cleanup/run/{id}` to observe the terminal `COMPLETED` or `FAILED` state and the final `componentsDeleted` count. Execution records are retained for 24 hours. At most one non-dry-run cleanup may be `RUNNING` per repository. A second non-dry-run submitted while one is in progress is rejected with **409 Conflict** and the body of the existing execution's status. |
| `CreateComponents` | Upload a single component |
| `CreateConfigurationAssetsImport` | Import assets to repository |
| `CreateConfigurationCipher` | Set migration cipher password for decrypting imported secrets |
| `CreateConfigurationTransferComplete` | Receive transfer complete notification from migrator |
| `CreateEmailVerify` | Send a test email to the email address provided in the request body |
| `CreateInternalCleanupPolicies` | Create a cleanup policy - Creates a new cleanup policy with the supplied name, format, and criteria. The policy name must be unique. At least one criterion (`criteriaLastBlobUpdated`, `criteriaLastDownloaded`, or `criteriaAssetRegex`) is required. Only criteria supported by the selected format are accepted; unsupported criteria are rejected. The created policy is returned with an `inUseCount` of 0. |
| `CreateInternalUiSecurityAccessCheck` | Check if a user or role has access to an API endpoint |
| `CreatePlan` | Create reconciliation plans with selected parameters |
| `CreateRecoveryMode` | Enables recovery mode and cancels conflicting tasks if running |
| `CreateRepositoriesAlpineGroup` | Create Alpine group repository |
| `CreateRepositoriesAlpineHosted` | Create Alpine hosted repository |
| `CreateRepositoriesAlpineProxy` | Create Alpine proxy repository |
| … | *187 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": {
"nexus-mcp": {
"type": "local",
"command": ["bash", "-c", "/path/to/nexus-mcp"],
"args": ["--transport", "stdio"],
"env": {
"MCP__UPSTREAM__ENDPOINT": "https://api.example.com",
"MCP__AUTH__BACKEND__STATIC__WEB_TOKEN": "your-token",
"MCP__AUTH__BACKEND__STATIC__WEB_TOKEN_FILE": "/path/to/fallback/.credentials"
},
"enabled": true
}
}
}
```
### Claude Code
- `~/.claude.json`:
```json
{
"mcpServers": {
"nexus-mcp": {
"command": "/path/to/nexus-mcp",
"args": ["--transport", "stdio"],
"env": {
"MCP__UPSTREAM__ENDPOINT": "https://api.example.com",
"MCP__AUTH__BACKEND__STATIC__WEB_TOKEN": "your-token",
"MCP__AUTH__BACKEND__STATIC__WEB_TOKEN_FILE": "/path/to/fallback/.credentials"
}
}
}
}
```
### Codex CLI
- `~/.codex/config.toml`:
```toml
[mcp_servers.nexus-mcp]
url = "http://localhost:8080/mcp"
web_token_env_var = "MCP__AUTH__BACKEND__STATIC__WEB_TOKEN"
```
### Cursor
- `~/.cursor/mcp.json`:
```json
{
"mcpServers": {
"nexus-mcp": {
"command": "/path/to/nexus-mcp",
"args": ["--transport", "stdio"],
"env": {
"MCP__UPSTREAM__ENDPOINT": "https://api.example.com",
"MCP__AUTH__BACKEND__STATIC__WEB_TOKEN": "your-token",
"MCP__AUTH__BACKEND__STATIC__WEB_TOKEN_FILE": "/path/to/fallback/.credentials"
}
}
}
}
```
### OpenCode (Remote)
- `~/.config/opencode/opencode.json`:
```json
{
"mcp": {
"nexus-mcp": {
"type": "remote",
"url": "http://localhost:8080/mcp",
"env": {
"MCP__UPSTREAM__ENDPOINT": "https://api.example.com",
"MCP__AUTH__BACKEND__STATIC__WEB_TOKEN": "your-token",
"MCP__AUTH__BACKEND__STATIC__WEB_TOKEN_FILE": "/path/to/fallback/.credentials"
}
}
}
}
```
### Claude Code (Remote)
- `~/.claude.json` (User MCPs):
```json
{
"mcpServers": {
"nexus-mcp": {
"url": "http://localhost:8080/mcp",
"env": {
"MCP__UPSTREAM__ENDPOINT": "https://api.example.com",
"MCP__AUTH__BACKEND__STATIC__WEB_TOKEN": "your-token",
"MCP__AUTH__BACKEND__STATIC__WEB_TOKEN_FILE": "/path/to/fallback/.credentials"
}
}
}
}
```
### Codex CLI (Remote)
- `~/.codex/config.toml`:
```toml
[mcp_servers.nexus-mcp]
url = "http://localhost:8080/mcp"
web_token_env_var = "MCP__AUTH__BACKEND__STATIC__WEB_TOKEN"
```
### Cursor (Remote)
- `~/.cursor/mcp.json`:
```json
{
"mcpServers": {
"nexus-mcp": {
"url": "http://localhost:8080/mcp"
}
}
}
```
## Deployment — Docker
### Build
```sh
make build-image
```
Or manually:
```sh
docker build -t ghcr.io/<YOUR_ORG>/nexus-mcp:latest -f deploy/docker/Dockerfile .
docker push ghcr.io/<YOUR_ORG>/nexus-mcp:latest
```
### Run
Pull the pre-built image from GitHub Container Registry:
```sh
docker pull ghcr.io/<YOUR_ORG>/nexus-mcp:latest
```
First generate a default config, then mount it when running:
```sh
docker run --rm ghcr.io/<YOUR_ORG>/nexus-mcp:latest --print-default-config > ~/.nexus-mcp/config.yaml
```
- **Static web token**
```sh
docker run -d --name nexus-mcp \
-p 8080:8080 -p 9991:9991 \
-e MCP__UPSTREAM__ENDPOINT="https://api.example.com" \
-e MCP__AUTH__BACKEND__STATIC__WEB_TOKEN="YOUR_WEB_TOKEN" \
-v ~/.nexus-mcp:/home/mcp/.nexus-mcp \
ghcr.io/<YOUR_ORG>/nexus-mcp:latest \
--transport http --port 8080
```
- **OIDC backend auth**
```sh
docker run -d --name nexus-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 ~/.nexus-mcp:/home/mcp/.nexus-mcp \
ghcr.io/<YOUR_ORG>/nexus-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** 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: CreateBlobstoresFile)
./mcpclient.sh call CreateBlobstoresFile '{"<param>":"<value>"}'
# List all available tools
./mcpclient.sh list-tools
```
> **Tip:** Map the host config directory for persistent configuration:
> `-v ~/.nexus-mcp:/home/mcp/.nexus-mcp`
## Deployment — Kubernetes (Helm)
First generate a default config, then mount it when running:
```sh
docker run --rm ghcr.io/<YOUR_ORG>/nexus-mcp:latest --print-default-config > ~/.nexus-mcp/config.yaml
```
- **Static web token**
```sh
helm upgrade -i nexus-mcp deploy/helm \
--set image.repository=ghcr.io/<YOUR_ORG>/nexus-mcp \
--set image.tag=latest \
--set secret.static.create=true \
--set secret.static.webToken="YOUR_WEB_TOKEN" \
--set config.upstream.endpoint="https://api.example.com"
```
- **OIDC authentication**
```sh
helm upgrade -i nexus-mcp deploy/helm \
--set image.repository=ghcr.io/<YOUR_ORG>/nexus-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"
```
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>/nexus-mcp.git
cd nexus-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](../../nexus-mcp/issues)
- **Discussions**: [Start a discussion](../../nexus-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