README.md•8.37 kB
# ProDisco (Progressive Disclosure Kuberentes MCP Server)
ProDisco gives MCP agents Kubernetes access that exactly follows Anthropic’s [Progressive Disclosure](https://www.anthropic.com/engineering/code-execution-with-mcp) pattern: the server exposes TypeScript modules, agents discover them through the filesystem, write code, and only the final console output returns to the chat.
## Why Progressive Disclosure Matters
Anthropic’s latest guidance explains why MCP servers should progressively reveal capabilities instead of dumping every tool definition into the model context. When agents explore a filesystem of TypeScript modules, as they do with ProDisco, they only load what they need and process data inside the execution environment, then return a concise result to the chat. This keeps token usage low, improves latency, and avoids copying large intermediate payloads through the model ([source](https://www.anthropic.com/engineering/code-execution-with-mcp)).
In practice that means:
- Agents only see a single advertised tool (`kubernetes.searchTools`); they call it on demand to discover the TypeScript modules (get pods, list nodes, fetch logs, etc.) that the server exposes, then write their own code to compose those modules without loading unused schemas.
- Letting the model issue one instruction instead of micromanaging dozens of sequential tool calls.
- Agents can mix and match multiple Kubernetes modules joining pod stats with node health, or correlating events with logs without shuttling raw outputs between tools in the chat loop, which dramatically cuts token usage.
ProDisco ships with this layout out of the box, so any Claude Code or MCP-enabled agent can immediately adopt the progressive-disclosure workflow.
---
## Quick Start
```bash
npm install
npm run build
npm run codegen
claude mcp add --transport stdio prodisco -- node dist/server.js
claude mcp remove prodisco # remove when you're done
```
Only **one tool** (`kubernetes.searchTools`) is advertised to the agent. Everything else is discovered via resources, so agents naturally stay in code mode.
### Scripts cache convention
Agents should write any helper scripts to `scripts/cache/<name>.ts` and execute them with `npx tsx scripts/cache/<name>.ts --flag=value --another=value2` (add as many flags as needed). Scripts must parse CLI args (or env vars) for every required value—never hardcode namespaces, pod names, etc.—and should print a brief usage message if arguments are missing. The `kubernetes.searchTools` response now lists any cached scripts so agents can reuse or update them instead of creating duplicates.
---
## What the Agent Actually Does
### Example 1 – “List nodes of this Kubernetes cluster”
1. `kubernetes.searchTools(query="node")` → finds `kubernetes.listNodes`
2. `kubernetes.searchTools(detailLevel="full")` → inspects schema
3. `listMcpResources` → sees `servers/kubernetes/listNodes.ts`
4. `readMcpResource("file:///servers/kubernetes/listNodes.ts")`
5. Reads `list-nodes-example.ts`, then runs `npx tsx list-nodes-example.ts`
6. Returns a human summary (roles, CPU/memory, kubelet version, pressure signals)
Result excerpt:
```
Node: kubemcp-control-plane
- Role: Control Plane
- CPU: 14 cores / Memory: ~7.7 GB / Pods: 110
- Health: Ready ✓ MemoryPressure False ✓ ...
```
Sample agent output:
```
> list nodes of this kubernetes cluster
⏺ I'll help you list the nodes in your Kubernetes cluster. Let me first search for available Kubernetes
tools.
⏺ prodisco - kubernetes.searchTools (MCP)(query: "node", detailLevel: "summary")
⎿ {
"summary": "Found 1 tool(s) matching "node":\n - kubernetes.listNodes",
"tools": [
… +7 lines (ctrl+o to expand)
⏺ prodisco - kubernetes.searchTools (MCP)(query: "listNodes", detailLevel: "full")
⎿ {
"summary": "Found 1 tool(s) matching "listnodes":\n - kubernetes.listNodes",
"tools": [
… +27 lines (ctrl+o to expand)
⏺ Let me check the example file in your repository to see how to properly list nodes:
⏺ Read(list-nodes-example.ts)
⎿ Read 23 lines
⏺ Perfect! Let me run this example script to list the nodes in your cluster:
⏺ Bash(npx tsx list-nodes-example.ts)
⎿ Fetching nodes...
{
… +87 lines (ctrl+o to expand)
⏺ Your Kubernetes cluster has 1 node:
Node: kubemcp-control-plane
- Role: Control Plane
- Status: Ready
- Internal IP: 172.18.0.8
- Kubelet Version: v1.34.0
- OS: Debian GNU/Linux 12 (bookworm)
- Container Runtime: containerd 2.1.3
- Architecture: arm64
Resources:
- CPU: 14 cores (14 allocatable)
- Memory: ~7.7 GB (8024876 Ki)
- Pods Capacity: 110
- Ephemeral Storage: ~910 GB
Health Status:
- Memory Pressure: False ✓
- Disk Pressure: False ✓
- PID Pressure: False ✓
- Ready: True ✓
The node is healthy and operational!
```
### Example 2 – “List all pods from all namespaces”
1. `kubernetes.searchTools(query="pod", detail="full")` → sees listPods/getPod/getPodLogs
2. `Search("**/servers/kubernetes/*.ts")` → enumerates modules
3. Reads `generated/servers/kubernetes/listPods.ts`
4. Creates `list-all-pods.ts`, imports `listPods`, and runs `npx tsx list-all-pods.ts`
5. Returns a curated summary (namespaces, readiness, IPs) instead of raw JSON
Result excerpt:
```
Found 11 pods across demo / kube-system / local-path-storage
- demo-nginx-6fb7c6888-gjhpn – Running, 1/1 ready, IP 10.244.0.5
- ...
All pods healthy; 0 restarts
```
Sample agent output:
```
> list all pods from all namespaces
⏺ prodisco - kubernetes.searchTools (MCP)(query: "pod", detailLevel: "full")
⎿ {
"summary": "Found 3 tool(s) matching "pod":\n - kubernetes.listPods\n - kubernetes.getPod\n - ku
bernetes.getPodLogs",
… +76 lines (ctrl+o to expand)
⏺ Let me check the available TypeScript modules to see how to list pods:
⏺ Search(pattern: "**/servers/kubernetes/*.ts")
⎿ Found 13 files (ctrl+o to expand)
⏺ Read(generated/servers/kubernetes/listPods.ts)
⎿ Read 20 lines
⏺ Let me create a script to list all pods from all namespaces:
⏺ Write(list-all-pods.ts)
⎿ Wrote 24 lines to list-all-pods.ts
#!/usr/bin/env tsx
/**
* List all pods from all namespaces
*/
import { listPods } from './generated/servers/kubernetes/index.js';
async function main() {
try {
… +14 lines (ctrl+o to expand)
⏺ Bash(npx tsx list-all-pods.ts)
⎿ Fetching pods from all namespaces...
{
… +245 lines (ctrl+o to expand)
⏺ Found 11 pods running across 3 namespaces:
demo (2 pods)
- demo-nginx-6fb7c6888-gjhpn - Running, 1/1 ready, IP: 10.244.0.5
- demo-nginx-6fb7c6888-rlwkp - Running, 1/1 ready, IP: 10.244.0.6
kube-system (8 pods)
- coredns-66bc5c9577-fxgf8 - Running, 1/1 ready, IP: 10.244.0.2
- coredns-66bc5c9577-lh6kt - Running, 1/1 ready, IP: 10.244.0.3
- etcd-kubemcp-control-plane - Running, 1/1 ready, IP: 172.18.0.8
- kindnet-x4qpb - Running, 1/1 ready, IP: 172.18.0.8
- kube-apiserver-kubemcp-control-plane - Running, 1/1 ready, IP: 172.18.0.8
- kube-controller-manager-kubemcp-control-plane - Running, 1/1 ready, IP: 172.18.0.8
- kube-proxy-qhmgq - Running, 1/1 ready, IP: 172.18.0.8
- kube-scheduler-kubemcp-control-plane - Running, 1/1 ready, IP: 172.18.0.8
local-path-storage (1 pod)
- local-path-provisioner-7b8c8ddbd6-rzj65 - Running, 1/1 ready, IP: 10.244.0.4
All pods are healthy with 0 restarts and no failing conditions.
```
These transcripts prove the progressive-disclosure workflow is live: the agent uses search → reads code → writes and executes TypeScript.
---
## Integration Tests
End-to-end testing instructions (KIND cluster + Claude Agent SDK driver) now live in `docs/integration-testing.md`. The workflow is manual-only for now and assumes your Anthropic credentials are already configured. Run it locally with:
```bash
npm run test:integration
```
---
## License
MIT