mirror of
https://github.com/lukaszraczylo/mcp-captcharesolver.git
synced 2026-10-12 00:45:28 +00:00
initial commit
This commit is contained in:
@@ -0,0 +1,137 @@
|
||||
# k8s manifests for `captcha-solver-mcp`
|
||||
|
||||
These manifests follow the conventions used by the other MCP servers in the
|
||||
home cluster's `agentgateway-system` namespace (compare
|
||||
`home-cluster/.../base/mcp-servers/time/` and `.../mcp-servers/web-search/`).
|
||||
|
||||
## Resources
|
||||
|
||||
| File | Resource |
|
||||
|------|----------|
|
||||
| `deployment.yaml` | `Deployment/mcp-captcha-solver` |
|
||||
| `service.yaml` | `Service/mcp-captcha-solver` (ClusterIP, port 8085) |
|
||||
| `agentgateway-backend.yaml` | `AgentgatewayBackend/mcp-captcha-solver` (per-server, hand-written) |
|
||||
| `external-secret.yaml` | `ExternalSecret/1p-mcp-captcha-solver` — **optional**, only if you point at a public LLM endpoint |
|
||||
|
||||
## Install
|
||||
|
||||
The Deployment talks to the LLM through the in-cluster **agentgateway-proxy**
|
||||
(ClusterIP `10.43.198.35`, port 80), which fronts the `minimax` AgentgatewayBackend
|
||||
and holds the upstream `api.minimax.io` auth in the `agentgateway-minimax-auth`
|
||||
secret. From the pod's perspective the endpoint is **keyless** — no
|
||||
`CAPTCHA_LLM_API_KEY` is set, and no `ExternalSecret` is needed.
|
||||
|
||||
### 1. Add the manifests to `home-cluster`
|
||||
|
||||
There are two equally good layouts. Pick **layout B** (chart-driven) for
|
||||
consistency with the existing per-server MCP backends unless you need a custom
|
||||
`AgentgatewayPolicy`.
|
||||
|
||||
#### Layout A — hand-written, fully self-contained
|
||||
|
||||
```sh
|
||||
mkdir -p ~/Documents/projects/home-cluster/kubernetes/namespaces/agentgateway-system/base/mcp-servers/captcha-solver
|
||||
cp deploy/k8s/{deployment,service,agentgateway-backend}.yaml \
|
||||
~/Documents/projects/home-cluster/kubernetes/namespaces/agentgateway-system/base/mcp-servers/captcha-solver/
|
||||
```
|
||||
|
||||
Then edit `home-cluster/.../base/mcp-servers/kustomization.yaml`:
|
||||
|
||||
```yaml
|
||||
- ./captcha-solver/deployment.yaml
|
||||
- ./captcha-solver/service.yaml
|
||||
- ./captcha-solver/agentgateway-backend.yaml
|
||||
```
|
||||
|
||||
#### Layout B — chart-driven (recommended, matches existing per-server MCPs)
|
||||
|
||||
Copy `deployment.yaml` and `service.yaml` exactly as in Layout A, **but skip
|
||||
`agentgateway-backend.yaml`** — the `agentgw-cfg` chart will generate it from
|
||||
`mcpServers` in values.
|
||||
|
||||
Edit `home-cluster/.../agentgw-cfg/values.yaml`:
|
||||
|
||||
```yaml
|
||||
mcpServers:
|
||||
- name: captcha-solver
|
||||
host: mcp-captcha-solver.agentgateway-system.svc.cluster.local
|
||||
port: 8085
|
||||
# path: /mcp (default)
|
||||
# protocol: StreamableHTTP (default)
|
||||
```
|
||||
|
||||
This produces:
|
||||
|
||||
- `AgentgatewayBackend/mcp-captcha-solver` (per-server, StreamableHTTP,
|
||||
Stateless — matches the other MCP backends)
|
||||
- `HTTPRoute/mcp-per-server` with a rule on
|
||||
`/mcp/captcha-solver` → that backend (per-server alias)
|
||||
|
||||
The same `values.yaml` entry also adds this server to the umbrella
|
||||
`mcp-servers` backend that the catch-all `/mcp` HTTPRoute uses.
|
||||
|
||||
### 2. (Only if you switch the BASE_URL) Add the ExternalSecret
|
||||
|
||||
Skip this section if you keep the default
|
||||
`http://agentgateway-proxy.agentgateway-system.svc.cluster.local/v1`. The
|
||||
in-cluster gateway is keyless for cluster callers.
|
||||
|
||||
If you change `CAPTCHA_LLM_BASE_URL` to a public endpoint (e.g.
|
||||
`https://llmgw.h.raczylo.com/v1` from outside the cluster, or
|
||||
`https://api.openai.com/v1`), append `external-secret.yaml` to
|
||||
`home-cluster/.../base/mcp-servers/eso.yaml` and re-add the
|
||||
`valueFrom: secretKeyRef` block in the Deployment for `CAPTCHA_LLM_API_KEY`.
|
||||
|
||||
### 3. Build & push the image
|
||||
|
||||
The manifests reference `ghcr.io/lukaszraczylo/mcp-captchasolver:latest`. Build
|
||||
and push from this repo:
|
||||
|
||||
```sh
|
||||
docker buildx build --builder multi-arch \
|
||||
--platform linux/amd64,linux/arm64 \
|
||||
-t ghcr.io/lukaszraczylo/mcp-captchasolver:latest \
|
||||
-t ghcr.io/lukaszraczylo/mcp-captchasolver:$(git rev-parse --short HEAD) \
|
||||
--push .
|
||||
```
|
||||
|
||||
(The `multi-registry-secret` patch in
|
||||
`home-cluster/.../base/mcp-servers/kustomization.yaml` already grants the
|
||||
service account permission to pull `ghcr.io/lukaszraczylo/mcp-*` images.)
|
||||
|
||||
### 4. Verify
|
||||
|
||||
```sh
|
||||
kubectl --context admin@home -n agentgateway-system \
|
||||
rollout status deploy/mcp-captcha-solver
|
||||
kubectl --context admin@home -n agentgateway-system \
|
||||
get agentgatewaybackend mcp-captcha-solver
|
||||
curl -s http://10.0.2.101/mcp/captcha-solver \
|
||||
-H 'Accept: application/json, text/event-stream' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}'
|
||||
```
|
||||
|
||||
The last call should respond with a `serverInfo` block naming
|
||||
`captcha-solver-mcp` v0.1.0 (or whatever `CAPTCHA_VERSION` was baked in at
|
||||
build time). From inside a debug pod:
|
||||
|
||||
```sh
|
||||
kubectl --context admin@home -n agentgateway-system exec -it deploy/mcp-captcha-solver -- \
|
||||
wget -qO- http://agentgateway-proxy.agentgateway-system.svc.cluster.local/v1/models | head
|
||||
```
|
||||
|
||||
should list `minimax/MiniMax-M3` (proving the in-cluster path works).
|
||||
|
||||
## Port choice
|
||||
|
||||
`8085` is the next free port in the 80xx range used by the other MCP servers
|
||||
(8081, 8083, 8084, 8087, 8088, 8089, 8092 are taken). Bump the `containerPort`,
|
||||
`Service.port`, `Deployment` env `CAPTCHA_HTTP_ADDR`, and the `mcpServers`
|
||||
`port:` if you want a different one.
|
||||
|
||||
## Resource sizing
|
||||
|
||||
Vision models can be heavier than text-only ones, so the limits (`1 CPU`,
|
||||
`512Mi`) are a step above `mcp-time` (`200m`, `128Mi`) and on par with
|
||||
`mcp-web-search`. Tune after observing real load.
|
||||
@@ -0,0 +1,41 @@
|
||||
# AgentgatewayBackend for captcha-solver-mcp.
|
||||
#
|
||||
# Two options for getting this into the cluster — pick one:
|
||||
#
|
||||
# A) Hand-written: drop this file into
|
||||
# home-cluster/kubernetes/namespaces/agentgateway-system/base/mcp-servers/captcha-solver/agentgateway-backend.yaml
|
||||
# and add it to the kustomization.yaml alongside deployment.yaml/service.yaml.
|
||||
#
|
||||
# B) Generated by the agentgw-cfg chart: add an entry to the `mcpServers` list
|
||||
# in home-cluster/kubernetes/namespaces/agentgateway-system/agentgw-cfg/values.yaml:
|
||||
#
|
||||
# mcpServers:
|
||||
# - name: captcha-solver
|
||||
# host: mcp-captcha-solver.agentgateway-system.svc.cluster.local
|
||||
# port: 8085
|
||||
# # path: /mcp (default)
|
||||
# # protocol: StreamableHTTP (default)
|
||||
#
|
||||
# This produces BOTH a per-server AgentgatewayBackend (matching the file
|
||||
# below) AND a per-server HTTPRoute at /mcp/captcha-solver. The chart
|
||||
# template lives at:
|
||||
# home-cluster/kubernetes/namespaces/agentgateway-system/agentgw-cfg/templates/mcp.yaml
|
||||
#
|
||||
# Option B is preferred (matches the existing per-server backends) unless you
|
||||
# also need to attach AgentgatewayPolicy/auth that the chart doesn't expose.
|
||||
---
|
||||
apiVersion: agentgateway.dev/v1alpha1
|
||||
kind: AgentgatewayBackend
|
||||
metadata:
|
||||
name: mcp-captcha-solver
|
||||
namespace: agentgateway-system
|
||||
spec:
|
||||
mcp:
|
||||
sessionRouting: Stateless
|
||||
targets:
|
||||
- name: captcha-solver
|
||||
static:
|
||||
host: mcp-captcha-solver.agentgateway-system.svc.cluster.local
|
||||
path: /mcp
|
||||
port: 8085
|
||||
protocol: StreamableHTTP
|
||||
@@ -0,0 +1,55 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: mcp-captcha-solver
|
||||
namespace: agentgateway-system
|
||||
labels:
|
||||
app.kubernetes.io/name: mcp-captcha-solver
|
||||
app.kubernetes.io/part-of: mcp-servers
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: mcp-captcha-solver
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: mcp-captcha-solver
|
||||
app.kubernetes.io/part-of: mcp-servers
|
||||
spec:
|
||||
automountServiceAccountToken: false
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
seccompProfile: { type: RuntimeDefault }
|
||||
containers:
|
||||
- name: mcp
|
||||
image: ghcr.io/lukaszraczylo/mcp-captchasolver:latest
|
||||
imagePullPolicy: IfNotPresent
|
||||
ports:
|
||||
- { name: http, containerPort: 8085 }
|
||||
env:
|
||||
- { name: CAPTCHA_TRANSPORT, value: "http" }
|
||||
- { name: CAPTCHA_HTTP_ADDR, value: ":8085" }
|
||||
- { name: CAPTCHA_HTTP_PATH, value: "/mcp" }
|
||||
- { name: CAPTCHA_LLM_PROVIDER, value: "openai-compatible" }
|
||||
- { name: CAPTCHA_LLM_BASE_URL, value: "http://agentgateway-proxy.agentgateway-system.svc.cluster.local/v1" }
|
||||
- { name: CAPTCHA_LLM_MODEL, value: "minimax/MiniMax-M3" }
|
||||
- { name: CAPTCHA_LLM_TIMEOUT, value: "120s" }
|
||||
- { name: CAPTCHA_LLM_MAX_TOKENS, value: "2048" }
|
||||
readinessProbe:
|
||||
httpGet: { path: /healthz, port: http }
|
||||
initialDelaySeconds: 2
|
||||
periodSeconds: 5
|
||||
livenessProbe:
|
||||
httpGet: { path: /healthz, port: http }
|
||||
initialDelaySeconds: 15
|
||||
periodSeconds: 15
|
||||
resources:
|
||||
requests: { cpu: 50m, memory: 64Mi }
|
||||
limits: { cpu: 1, memory: 512Mi }
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
readOnlyRootFilesystem: true
|
||||
runAsNonRoot: true
|
||||
capabilities: { drop: [ALL] }
|
||||
seccompProfile: { type: RuntimeDefault }
|
||||
@@ -0,0 +1,44 @@
|
||||
# Optional: ExternalSecret for the captcha-solver API key.
|
||||
#
|
||||
# The default Deployment points at the keyless in-cluster LLM gateway
|
||||
# (agentgateway-proxy → api.minimax.io via the `minimax` AgentgatewayBackend,
|
||||
# which holds the upstream auth in `agentgateway-minimax-auth`). No client
|
||||
# API key is needed in that case, and this file is **not** required.
|
||||
#
|
||||
# Only apply this if you change `CAPTCHA_LLM_BASE_URL` to a public endpoint
|
||||
# that needs an API key (e.g. https://llmgw.h.raczylo.com/v1 from outside the
|
||||
# cluster, or https://api.openai.com/v1). 1Password layout (matches the
|
||||
# convention in home-cluster/.../base/mcp-servers/eso.yaml):
|
||||
#
|
||||
# vault: <whatever stores ns_agentgateway>
|
||||
# item: ns_agentgateway/mcp_captcha_solver_llm_api_key
|
||||
# field: key (1Password item key)
|
||||
#
|
||||
# Append to home-cluster/kubernetes/namespaces/agentgateway-system/base/mcp-servers/eso.yaml.
|
||||
# The Secret is consumed by the Deployment as `mcp-captcha-solver` / `CAPTCHA_LLM_API_KEY`,
|
||||
# and the Deployment's `env:` block must be amended to re-add the
|
||||
# `valueFrom: secretKeyRef` lookup.
|
||||
---
|
||||
apiVersion: external-secrets.io/v1
|
||||
kind: ExternalSecret
|
||||
metadata:
|
||||
name: 1p-mcp-captcha-solver
|
||||
namespace: agentgateway-system
|
||||
spec:
|
||||
refreshInterval: 24h
|
||||
secretStoreRef:
|
||||
name: 1password-homecluster
|
||||
kind: ClusterSecretStore
|
||||
target:
|
||||
name: mcp-captcha-solver
|
||||
creationPolicy: Owner
|
||||
deletionPolicy: Retain
|
||||
template:
|
||||
engineVersion: v2
|
||||
type: Opaque
|
||||
data:
|
||||
CAPTCHA_LLM_API_KEY: "{{ .key }}"
|
||||
data:
|
||||
- secretKey: key
|
||||
remoteRef:
|
||||
key: ns_agentgateway/mcp_captcha_solver_llm_api_key
|
||||
@@ -0,0 +1,13 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: mcp-captcha-solver
|
||||
namespace: agentgateway-system
|
||||
labels:
|
||||
app.kubernetes.io/name: mcp-captcha-solver
|
||||
app.kubernetes.io/part-of: mcp-servers
|
||||
spec:
|
||||
selector:
|
||||
app.kubernetes.io/name: mcp-captcha-solver
|
||||
ports:
|
||||
- { name: http, port: 8085, targetPort: http }
|
||||
Reference in New Issue
Block a user