update agents md
Build Images / Select images (push) Successful in 16s
Lint / Lint (push) Successful in 1m16s
Build Images / Build changed images (push) Successful in 2m49s

This commit is contained in:
2026-10-05 16:45:21 -04:00
parent 6ceb78b00c
commit d39c2c8254
2 changed files with 52 additions and 10 deletions
+36 -10
View File
@@ -142,15 +142,41 @@ from a sibling repo — several were a major behind.
## Downstream consumers
`node-agent` backs the shell MCP server in the **`50W/kube-manifests`** repo. When
its toolset changes, update all three of these or agents will not know what they
can run:
`node-agent` backs **three** MCP servers in the **`50W/kube-manifests`** repo:
- `toolhive/mcpserver-shell.yaml` — the `WHAT'S IN THIS CONTAINER` comment block.
- `toolhive/mcptoolconfig-shell.yaml` — `toolsOverride.run_process.description`,
the tool description models actually read.
- `ai/kagent/remotemcpserver-shell.yaml` — `spec.description`.
- **`shell`** — an arbitrary command runner. When this image's toolset changes,
update all three of these or agents will not know what they can run:
- `toolhive/mcpserver-shell.yaml` — the `WHAT'S IN THIS CONTAINER` comment block.
- `toolhive/mcptoolconfig-shell.yaml` — `toolsOverride.run_process.description`,
the tool description models actually read.
- `ai/kagent/remotemcpserver-shell.yaml` — `spec.description`.
- **`yamllint`** — a small stdio MCP server shipped as a ConfigMap
(`toolhive/cm-yamllint-mcp.yaml`) that runs on this image and shells out to
`yamllint` and `kubectl` to expose `lint_yaml` / `lint_manifest`. This is why
`yamllint` is in the apk list; it is the only reason that package is here.
- **`fetch-jq`** — another ConfigMap-shipped stdio MCP server
(`toolhive/cm-fetch-jq-mcp.yaml`), exposing `fetch_json_jq` / `fetch_json`. It
pipes a fetched HTTP response straight into `jq`'s stdin (`spawnSync` with an
`input:` option, no temp file), so a model never has to scan a large raw JSON
array by eye to find one value. `jq` was already in the apk list before this
consumer existed — nothing had to be added for it, unlike `yamllint`.
That pod runs with no Kubernetes credentials, HTTPS-only egress, a read-only root
filesystem and all capabilities dropped, which is what `node-agent`'s smoke test
mirrors. Do not add a pull secret there — the registry is public.
Neither `shell` nor `yamllint` gets a pull secret — the registry is public. Same
for `fetch-jq`.
The three pods have very different privileges, so **do not assume `kubectl` in
this image implies cluster access** — that depends entirely on the consuming
pod's ServiceAccount:
| | `shell` | `yamllint` | `fetch-jq` |
| --- | --- | --- | --- |
| ServiceAccount | cluster-wide **read** (incl. pod logs) | **no role bindings at all** | **none mounted** |
| Egress | HTTPS + API server | API server only, no internet | HTTPS to whatever URL a caller passes — no API server |
| `kubectl` can | `get`/`list`/`watch` most kinds | only fetch the OpenAPI schema | n/a — never invoked |
`fetch-jq` is the odd one out: it's the only one of the three with open internet
egress and the only one with zero Kubernetes access of any kind — see
`toolhive/mcpserver-fetch-jq.yaml` for why it mounts no ServiceAccount at all.
`node-agent`'s smoke test mirrors the stricter shared parts of that contract —
non-root, read-only root filesystem, all capabilities dropped, `/tmp` a tmpfs.
+16
View File
@@ -58,6 +58,22 @@ Client-side validation needs no RBAC at all — it only fetches the OpenAPI sche
which every authenticated identity may do — but it does need to reach the API server.
With no API access it fails closed on valid manifests (`failed to download openapi`).
### Filtered JSON fetch
`jq` also backs the `fetch-jq` MCP server in `50W/kube-manifests`
(`toolhive/cm-fetch-jq-mcp.yaml`), which exposes `fetch_json_jq`: fetch a URL,
then filter the response with a jq expression before any of it reaches a
model's context. The body is piped straight into `jq`'s stdin, never written to
disk:
```sh
curl -s "$URL" | jq -c '[.[-24:][] | {time_tag, value}]'
```
Unlike `yamllint`'s consumer, `fetch-jq` needs real internet egress — the URLs
it fetches are external APIs, not in-cluster services — and mounts no
ServiceAccount at all, since it never touches the Kubernetes API.
## Environment
| Variable | Value | Why |