Skip to content

Commit 5aacadf

Browse files
masterkainqwencoder
andcommitted
feat: consolidate multiple updates and features for MCP server chart
- Add configurable MCP server chart with SSE/WS/stdio support and optional mcp-proxy - Add root-level 'unla.enabled' (default true) to gate Unla subchart and registration hooks - Add optional stdioBridge per server using mcp-proxy, generate SSE endpoint and register accordingly - Remove outdated NOTES.txt as port-forward note was redundant and potentially confusing - Default stdioBridge image to ghcr.io/icoretech/mcp-stdio-bridge:latest - Add TCP readiness/liveness probes on port 3000 for bridge, default bridge tag to v0.1.0 - Update stdioBridge example to v0.2.1 (Node 24 base) - Normalize and slim examples set, use public bridge v0.2.1, disable register for standalone testing - Drop flaky python stdio test, keep node SSE, node stdio bridge, python SSE - Add gateway-register config and job templates - Add server-specific templates (deployment, HPA, service) - Update examples with gateway configurations and other improvements - Update documentation and schema files accordingly Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
1 parent 0a70285 commit 5aacadf

37 files changed

+1078
-1309
lines changed
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
name: mcp-server e2e
2+
3+
on:
4+
pull_request:
5+
push:
6+
branches: [ main ]
7+
8+
jobs:
9+
e2e:
10+
runs-on: ubuntu-latest
11+
steps:
12+
- uses: actions/checkout@v5.0.0
13+
- name: Setup kubectl
14+
uses: azure/setup-kubectl@v4.0.1
15+
with:
16+
version: latest
17+
- name: Setup Helm
18+
uses: azure/setup-helm@v4.3.1
19+
with:
20+
version: latest
21+
- name: Setup kind
22+
uses: helm/kind-action@v1.12.0
23+
with:
24+
version: v0.24.0
25+
kubectl_version: v1.30.0
26+
- name: Run e2e
27+
run: |
28+
chmod +x hack/e2e/e2e.sh
29+
./hack/e2e/e2e.sh
30+

.github/workflows/release.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ jobs:
1313
runs-on: ubuntu-latest
1414
steps:
1515
- name: Checkout
16-
uses: actions/checkout@v4
16+
uses: actions/checkout@v5.0.0
1717
with:
1818
fetch-depth: 0
1919

@@ -24,7 +24,7 @@ jobs:
2424
2525
- name: Install Helm
2626
id: install
27-
uses: azure/setup-helm@v4.3.0
27+
uses: azure/setup-helm@v4.3.1
2828
env:
2929
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
3030

.github/workflows/test.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@ jobs:
77
runs-on: ubuntu-latest
88
steps:
99
- name: Checkout
10-
uses: actions/checkout@v4
10+
uses: actions/checkout@v5.0.0
1111
with:
1212
fetch-depth: 0
1313

1414
- name: Set up Helm
15-
uses: azure/setup-helm@v4.2.0
15+
uses: azure/setup-helm@v4.3.1
1616

1717
- uses: actions/setup-python@v5
1818
with:
@@ -36,7 +36,7 @@ jobs:
3636

3737
- name: Create kind cluster
3838
if: steps.list-changed.outputs.changed == 'true'
39-
uses: helm/kind-action@v1.10.0
39+
uses: helm/kind-action@v1.12.0
4040

4141
- name: Run chart-testing (install)
4242
if: steps.list-changed.outputs.changed == 'true'

charts/mcp-server/Chart.yaml

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
apiVersion: v2
22
name: mcp-server
3-
description: "Generic MCP server runner for Node (TypeScript) and Python servers. Supports three modes: direct container image, Node (npx), and Python (uvx/pip)."
3+
description: "Generic MCP server runner for Node (TypeScript) and Python servers. Supports four modes: direct container image, Node (npx), Python (uvx/pip), and OpenAPI (external URL registered in Unla)."
44

55
# A chart can be either an 'application' or a 'library' chart.
66
#
@@ -15,7 +15,7 @@ type: application
1515
# This is the chart version. This version number should be incremented each time you make changes
1616
# to the chart and its templates, including the app version.
1717
# Versions are expected to follow Semantic Versioning (https://semver.org/)
18-
version: 0.1.0
18+
version: 0.1.2
1919

2020
# This is the version number of the application being deployed. This version number should be
2121
# incremented each time you make changes to the application. Versions are not expected to
@@ -45,3 +45,10 @@ annotations:
4545
- kind: added
4646
description: Initial release with image, node (npx) and python (uvx/pip) modes
4747
artifacthub.io/prerelease: "false"
48+
49+
dependencies:
50+
- name: unla
51+
version: "0.9.0"
52+
repository: "https://amoylab.github.io/unla-helm-charts"
53+
# Allow turning the subchart on/off from root values via `unla.enabled`
54+
condition: unla.enabled

charts/mcp-server/README.md

Lines changed: 63 additions & 202 deletions
Large diffs are not rendered by default.

charts/mcp-server/README.md.gotmpl

Lines changed: 31 additions & 152 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,17 @@
11
# mcp-server Helm Chart
22

3-
Generic runner for Model Context Protocol (MCP) servers on
4-
Kubernetes.
3+
Generic runner for Model Context Protocol (MCP) servers on Kubernetes.
4+
This chart deploys one Deployment/Service per servers[] entry (Node via npx,
5+
Python via uv tool run, or a pre-built image), and can also register external
6+
OpenAPI specs without creating Pods. Everything is wired into an Unla MCP
7+
Gateway (subchart) that exposes a single aggregated endpoint.
58

6-
This chart supports three modes:
9+
## Stdio transport (not supported)
710

8-
- `image`: run a pre-built container image that already includes your MCP
9-
server (recommended for production).
10-
- `node`: run a Node/TypeScript MCP server package via `npx` inside a
11-
`node:alpine` container.
12-
- `python`: run a Python MCP server via `uvx` (or `pip`) inside a `uv`/`python`
13-
container.
14-
15-
## Named Servers (Spotlight)
16-
17-
Run many stdio‑based MCP servers behind a single HTTP(SSE) endpoint using the
18-
built‑in gateway option powered by `mcp-proxy`.
19-
20-
What it is
21-
22-
- One process exposes an SSE endpoint and spawns multiple stdio MCP servers as
23-
child processes.
24-
- Each server is reachable at `/servers/{name}/sse` (a default server can also
25-
be exposed at `/sse`).
26-
27-
Why it’s useful
28-
29-
- One Service/Ingress/Gateway for multiple stdio MCP servers.
30-
- Central place for long‑lived connection tuning (SSE/WS timeouts).
31-
- Great for internal hubs, demos, or small fleets.
32-
33-
When not to use
34-
35-
- If you need per‑server autoscaling/isolation, prefer multiple Deployments or
36-
an external reverse proxy.
37-
38-
How to enable
39-
40-
- Set `transport.type: stdio` and `transport.stdioGateway.enabled: true`.
41-
- Add entries under `transport.stdioGateway.servers` with `command`/`args`/`env`.
42-
- Or provide raw JSON via `transport.stdioGateway.namedServersJson`.
43-
- Use `transport.stdioGateway.preStart` for installing servers (e.g., pip
44-
install) or ship a custom image.
45-
46-
Endpoints
47-
48-
- Default: `/sse` (if you spawn a default server after `--`).
49-
- Named: `/servers/{name}/sse`.
50-
- Status: `/status`.
11+
This chart intentionally does not support stdio-only MCP servers. Kubernetes pods are designed for
12+
long‑lived network services; supervising interactive stdio processes reliably (signals, restarts,
13+
child lifecycles) is brittle. Pick servers that expose HTTP (SSE) or WebSocket natively. If you must
14+
translate stdio, run a dedicated gateway outside this chart and route to it with a normal Service.
5115

5216
## Prerequisites
5317

@@ -79,127 +43,42 @@ default values.
7943
{{ template "chart.valuesSection" . }}
8044
<!-- markdownlint-enable MD013 -->
8145

82-
## Transports and Exposure
46+
## Transports and Exposure (via Unla Gateway)
8347

8448
Transports
8549

86-
- `http-sse` (default): stream over a long‑lived HTTP connection.
87-
- `websocket`: stream over WebSocket.
88-
- `stdio`: intended for local clients; in Kubernetes it needs a gateway/bridge.
89-
This chart offers a stdio gateway mode using `mcp-proxy`.
50+
- HTTP (SSE/streamable HTTP): long‑lived HTTP connection.
51+
- WebSocket: use when your server exposes a WS endpoint.
9052

91-
Exposure options
53+
Exposure is handled by the Unla subchart. Port-forward the gateway Service:
9254

93-
- ClusterIP + port‑forward: simplest local testing.
94-
- Ingress (e.g., NGINX): add WS upgrade annotations and increase timeouts.
95-
- Gateway API (HTTPRoute): set `rules.timeouts.request/backendRequest` for
96-
long‑lived connections.
55+
```bash
56+
kubectl -n <ns> port-forward svc/<release> 8000:5235
57+
```
9758

9859
Timeout tips
9960

10061
- SSE: raise read/send/proxy timeouts (NGINX `proxy-read-timeout` and
10162
`proxy-send-timeout` to `3600`).
10263
- WebSocket: ensure upgrade support (NGINX: `enable-websocket: "true"`).
10364

104-
## Examples
105-
106-
Node mode (npx):
107-
108-
```yaml
109-
mode: node
110-
node:
111-
image: node:24-alpine
112-
package: mcp-remote
113-
version: latest
114-
args:
115-
- https://docs.mcp.cloudflare.com/sse
116-
- --port
117-
- "3000"
118-
container:
119-
port: 3000
120-
service:
121-
port: 3000
122-
```
123-
124-
Python mode (uvx):
125-
126-
```yaml
127-
mode: python
128-
python:
129-
image: ghcr.io/astral-sh/uv:latest
130-
package: awslabs.aws-documentation-mcp-server@latest
131-
args:
132-
- --port
133-
- "3000"
134-
container:
135-
port: 3000
136-
service:
137-
port: 3000
138-
```
65+
## Dependency Caching (per server)
13966

140-
Stdio gateway with named servers (mcp-proxy):
141-
142-
```yaml
143-
# Exposes /sse for default server and /servers/{name}/sse for named servers
144-
mode: python
145-
python:
146-
image: ghcr.io/astral-sh/uv:latest
147-
package: awslabs.aws-documentation-mcp-server@latest
148-
args:
149-
- --port
150-
- "3000"
151-
service:
152-
port: 3000
153-
transport:
154-
type: stdio
155-
stdioGateway:
156-
enabled: true
157-
image: ghcr.io/sparfenyuk/mcp-proxy:latest
158-
passEnvironment: true
159-
allowOrigins: ["*"]
160-
preStart:
161-
- pip install --no-cache-dir awslabs.aws-documentation-mcp-server awslabs.aws-pricing-mcp-server
162-
servers:
163-
docs:
164-
command: awslabs.aws-documentation-mcp-server
165-
pricing:
166-
command: awslabs.aws-pricing-mcp-server
167-
```
168-
169-
WebSocket via NGINX Ingress:
170-
171-
```yaml
172-
service:
173-
port: 3000
174-
container:
175-
port: 3000
176-
transport:
177-
type: websocket
178-
http:
179-
wsPath: /ws
180-
ingress:
181-
enabled: true
182-
className: nginx
183-
annotations:
184-
nginx.ingress.kubernetes.io/enable-websocket: "true"
185-
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
186-
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
187-
hosts:
188-
- host: mcp.example.local
189-
paths:
190-
- path: /
191-
pathType: Prefix
192-
```
67+
Enable servers[].cache to persist npm/uv caches between restarts. Set
68+
servers[].cache.pvc.existingClaim to bind an existing PVC or omit to let the
69+
chart create one per server.
19370

194-
Example values files are provided under `charts/mcp-server/examples/`:
71+
## Examples provided under `charts/mcp-server/examples/`
19572

196-
- `node-mcp-remote.yaml`: Node mode using `mcp-remote`.
197-
- `python-aws-docs.yaml`: Python mode using `awslabs.aws-documentation-mcp-server`.
198-
- `stdio-gateway-named-servers.yaml`: Stdio gateway with two named servers.
199-
- `ingress-websocket-nginx.yaml`: WebSocket transport behind NGINX Ingress.
200-
- `gateway-http.yaml`: Minimal Gateway (Gateway API) to attach HTTPRoutes.
201-
- `httproute-sse-gatewayapi.yaml`: HTTPRoute with timeouts for SSE/Streamable HTTP.
202-
- `httproute-websocket-gatewayapi.yaml`: HTTPRoute with timeouts for WebSocket.
73+
- `node-server-everything.yaml` - Node mode using
74+
`@modelcontextprotocol/server-everything` (streamable HTTP pinned to Node 22).
75+
- `python-aws-pricing.yaml` - Minimal Python mode example running the
76+
AWS Pricing MCP server (HTTP/SSE).
77+
- `python-fastmcp-http.yaml` - Advanced Python mode running the
78+
`mcp-server` sample with streamable HTTP arguments.
79+
- `openapi.yaml` - Register an external OpenAPI URL with Unla (no Pod created).
80+
81+
20382

20483
Gateway API quickstart:
20584

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Example: Microsoft MCP Gateway–centric deployment with two servers in one Pod.
2+
#
3+
# Why this example exists
4+
# - Demonstrates the new gateway-centric architecture: one gateway Pod aggregates
5+
# multiple MCP servers that run as sidecar containers in a single Deployment.
6+
# - Shows two Node HTTP-compatible MCP servers (as most MCP servers are stdio-only).
7+
# - Uses a public gateway image by default for out-of-the-box local testing. To
8+
# switch to Microsoft MCP Gateway, build/push your image and override
9+
# gateway.image.repository/tag accordingly.
10+
# - IMPORTANT: Only use confirmed HTTP-compatible servers. Most MCP servers are stdio-only.
11+
# - This example uses the same working server twice as reliable HTTP-compatible examples.
12+
13+
# Gateway is provided by the Unla subchart; default ports are used (5235)
14+
15+
# Run two servers in a single Pod
16+
servers:
17+
- name: everything
18+
type: node
19+
port: 3001
20+
node:
21+
package: "@modelcontextprotocol/server-everything"
22+
version: "latest"
23+
args: ["streamableHttp"]
24+
# Only the tag should be customized in examples
25+
tag: 24-alpine
26+
27+
- name: everything-alt
28+
type: node
29+
port: 3002
30+
node:
31+
package: "@modelcontextprotocol/server-everything"
32+
version: "latest"
33+
args: ["streamableHttp"]
34+
tag: 24-alpine
35+
36+
# No parent Service; the subchart exposes Service named after the release, port 5235

charts/mcp-server/examples/httproute-sse-gatewayapi.yaml

Lines changed: 0 additions & 31 deletions
This file was deleted.

0 commit comments

Comments
 (0)