Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 64 additions & 2 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ on:
- main
- release-*
pull_request: {}
merge_group:
types: [checks_requested]
workflow_dispatch:
inputs:
save-output:
Expand All @@ -32,7 +34,7 @@ jobs:
uses: fkirc/skip-duplicate-actions@f75f66ce1886f00957d99748a42c724f4330bdcf # v5
with:
paths_ignore: '["**.md", "**.png", "**.jpg"]'
do_not_skip: '["workflow_dispatch", "schedule", "push"]'
do_not_skip: '["workflow_dispatch", "schedule", "push", "merge_group"]'
concurrent_skipping: false


Expand Down Expand Up @@ -102,7 +104,7 @@ jobs:
- name: Run Unit Tests
run: make test

publish-artifacts:
publish-image:
runs-on: ubuntu-latest
needs:
- detect-noop
Expand Down Expand Up @@ -156,3 +158,63 @@ jobs:
env:
XPKG_ACCESS_ID: ${{ secrets.XPKG_ACCESS_ID }}
XPKG_TOKEN: ${{ secrets.XPKG_TOKEN }}

publish-addon:
runs-on: ubuntu-latest
needs:
- detect-noop
- unit-tests
- lint
- publish-image
steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: true

- name: Install up
uses: upbound/action-up@v1
with:
skip-login: true
channel: main
version: v0.39.0-384.g0a0c8634

- name: Login to Upbound Marketplace
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3
with:
registry: xpkg.upbound.io/upbound
username: ${{ secrets.XPKG_ACCESS_ID }}
password: ${{ secrets.XPKG_ACCESS_TOKEN }}

- name: Build chart
run: |
make helm.build

- name: Create working directory
run: |
mkdir -p tmp-addon-xpkg
cd tmp-addon-xpkg

- name: Build and Publish
working-directory: tmp-addon-xpkg
if: env.XPKG_ACCESS_ID != ''
run: |
CHART_VERSION=$(make --no-print-directory -C ../ helm.version)
cp ../crossplane.yaml .

# Build resources
mkdir helm
mv ../_output/charts/marketplace-mcp-server-${CHART_VERSION}.tgz helm/chart.tgz

# Build artifact
up xpkg build

# Find artifact
XPKG_FILENAME=$(find . -name "*.xpkg" -type f -printf "%f\n")
echo $XPKG_FILENAME

# Publish artifact
export ADDON_NAME=addon-$(printf '%s' "$GITHUB_REPOSITORY" | sed 's/.*\///')
echo $ADDON_NAME

up xpkg push xpkg.upbound.io/upbound/$ADDON_NAME:$CHART_VERSION -f $XPKG_FILENAME
2 changes: 0 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
*.dll
*.so
*.dylib
marketplace-mcp-server
marketplace-mcp-server-*
bin/*

# Test binary, built with `go test -c`
Expand Down
25 changes: 24 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,25 @@ GO_LINT_DIFF_TARGET ?= HEAD~
GO_LINT_ARGS ?= --fix
-include build/makelib/golang.mk

# ====================================================================================
# Setup Helm
USE_HELM3 = true
HELM_BASE_URL = https://charts.upbound.io
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

any reason we pushing to Chartmuseum? Can we use oci via xpkg ?

Copy link
Member Author

@tnthornton tnthornton Jul 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We shouldn't be pushing to chart museum - there's no creds for it. The build submodule will error without that though.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

 make helm.build
build/makelib/helm.mk:21: *** the variable HELM_BASE_URL must be set prior to including helm.mk.  Stop.

HELM_S3_BUCKET = upbound.charts
HELM_CHARTS = marketplace-mcp-server
HELM_VALUES_TEMPLATE_SKIPPED = true

-include build/makelib/k8s_tools.mk
-include build/makelib/helm.mk

# ====================================================================================
# CI
helm.version:
@echo $(HELM_CHART_VERSION)

# ====================================================================================
# General targets

# Default target
all: clean deps test build

Expand Down Expand Up @@ -103,7 +122,11 @@ publish-docker-stdio: docker-build-stdio
@docker tag $(DOCKER_IMAGE):latest $(REGISTRY_ORG)/$(DOCKER_IMAGE):$(VERSION)
@docker push $(REGISTRY_ORG)/$(DOCKER_IMAGE):$(VERSION)

publish: publish-docker-stdio
publish-docker-http: docker-build-http
@docker tag $(DOCKER_IMAGE)-http:latest $(REGISTRY_ORG)/$(DOCKER_IMAGE)-http:$(VERSION)
@docker push $(REGISTRY_ORG)/$(DOCKER_IMAGE)-http:$(VERSION)

publish: publish-docker-stdio publish-docker-http

# Run Docker containers
docker-run-stdio:
Expand Down
16 changes: 14 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -401,11 +401,23 @@ Browse and manage organization repositories:

## Configuration

The server automatically detects and loads UP CLI configuration from the following locations:
The server automatically detects and loads UP CLI configuration from the
following locations:
1. `/mcp/.up/config.json` (when running in Docker with mounted config)
2. `~/.up/config.json` (default UP CLI location)

No additional configuration is required if UP CLI is properly set up and authenticated.
No additional configuration is required if UP CLI is properly set up and
authenticated.

### As an Addon
Note, the marketplace-mcp-server does still need authentication as described in
the above section. In order to fulfill that need, you should provide a secret
with the contents of the ~/.up/config.json.

For example:
```bash
kubectl -n crossplane-system create secret generic up-config --from-file=config.json=path/to/up/config.json
```

## Development

Expand Down
23 changes: 23 additions & 0 deletions cluster/charts/marketplace-mcp-server/.helmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*.orig
*~
# Various IDEs
.project
.idea/
*.tmproj
.vscode/
9 changes: 9 additions & 0 deletions cluster/charts/marketplace-mcp-server/Chart.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
apiVersion: v2
name: marketplace-mcp-server
description: A Helm chart for Upbound's Marketplace MCP Server

type: application

version: 0.1.0

appVersion: "1.16.0"
62 changes: 62 additions & 0 deletions cluster/charts/marketplace-mcp-server/templates/_helpers.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
{{/*
Expand the name of the chart.
*/}}
{{- define "marketplace-mcp-server.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "marketplace-mcp-server.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}

{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "marketplace-mcp-server.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
Common labels
*/}}
{{- define "marketplace-mcp-server.labels" -}}
helm.sh/chart: {{ include "marketplace-mcp-server.chart" . }}
{{ include "marketplace-mcp-server.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}

{{/*
Selector labels
*/}}
{{- define "marketplace-mcp-server.selectorLabels" -}}
app.kubernetes.io/name: {{ include "marketplace-mcp-server.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}

{{/*
Create the name of the service account to use
*/}}
{{- define "marketplace-mcp-server.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "marketplace-mcp-server.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
apiVersion: pkg.crossplane.io/v1beta1
kind: DeploymentRuntimeConfig
metadata:
name: marketplace-mcp
spec:
serviceAccountTemplate:
metadata:
# We need to provide additional permissions to the function. In order to
# do that we create a deterministic ServiceAccount name.
name: {{ .Values.serviceAccount.name }}
deploymentTemplate:
spec:
selector: {}
template:
spec:
containers:
- name: package-runtime
args:
{{- with .Values.extraArgs.packageRuntime }}
{{- toYaml . | nindent 12 }}
{{- end }}
env:
# Inform the function of the CTP1 MCP Server.
# transport: http-stream indicates that we'll communicate with the
# MCP server over StreamableHTTP.
- name: MCP_SERVER_TOOL_CTP1_TRANSPORT
value: http-stream
# baseURL indicates which address and endpoint to reach out to for
# tooling.
- name: MCP_SERVER_TOOL_CTP1_BASEURL
value: http://localhost:8765/mcp
- name: marketplace-mcp-server
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default (ternary .Chart.AppVersion (printf "v%s" .Chart.AppVersion) (hasPrefix "v" .Chart.AppVersion)) }}"
args:
{{- with .Values.extraArgs.controlplaneMcpServer }}
{{- toYaml . | nindent 12 }}
{{- end }}
volumeMounts:
- mountPath: /mcp/.up/
name: up-config
readOnly: true
volumes:
- name: up-config
secret:
secretName: {{ .Values.upConfig.secretName }}
25 changes: 25 additions & 0 deletions cluster/charts/marketplace-mcp-server/values.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
image:
repository: xpkg.upbound.io/upbound/marketplace-mcp-server-http
# Overrides the image tag whose default is the chart appVersion.
tag: ""

# This section builds out the service account more information can be found here: https://kubernetes.io/docs/concepts/security/service-accounts/
serviceAccount:
# The name of the service account to use.
name: function-with-marketplace-mcp

# ExtraArgs to specify for the given container.
extraArgs:
# packageRuntime is the name of the crossplane function.
# example
# packageRuntime:
# - --debug
packageRuntime: []
# marketplaceMcpServer is the name of the marketplace-mcp-server sidecar.
# example
# marketplaceMcpServer:
# - --debug
marketplaceMcpServer: []

upConfig:
secretName: up-config
14 changes: 14 additions & 0 deletions crossplane.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
apiVersion: meta.pkg.upbound.io/v1beta1
kind: AddOn
metadata:
annotations:
friendly-name.meta.crossplane.io: AddOn Marketplace MCP Server
meta.crossplane.io/description: |
Upbound AddOn package that deploys a DeploymentRuntimeConfig including
the marketplace-mcp-server for use by an Upbound Intelligent Function.
meta.crossplane.io/maintainer: Upbound Maintainers <info@upbound.io>
name: marketplace-mcp-server
spec:
packagingType: Helm
helm:
releaseName: marketplace-mcp-server