ai-agents-mcp-itsops
Provides a tool to retrieve a bounded pod-status summary for approved clusters and namespaces, using a server-side mapping of logical cluster names to kubeconfig files, contexts, and allowed namespaces.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@ai-agents-mcp-itsopscheck pod status in the rke-lab default namespace"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
ai-agents-mcp-itsops
A small, local Model Context Protocol (MCP) server for learning MCP server design, tool discovery, tool execution and operational security boundaries.
Part of the AI Agents Lab. This is a learning project, not a production service. Read the Safety notice before pointing it at any real infrastructure.
What this demonstrates
The server exposes a deliberately narrow set of read-only-style operations tools to an MCP-compatible client:
search_runbooks(query)searches an approved local folder of Markdown runbooks.host_health(host)returns selected health information for the local host: disk, memory and failed systemd units. Thehostargument defaults to"local"; other hosts are rejected.k8s_pod_status(cluster, namespace)returns a pod-status summary for approved clusters and namespaces, limited to the first 50 pods.slow_probe(seconds)is a deliberately slow, lab-only tool for timeout and tracing tests. It defaults to 10 seconds and accepts values between 0 and 10 inclusive.
The operations tools are intentionally restricted. They demonstrate exposing specific capabilities rather than general shell, filesystem, SSH or Kubernetes access. slow_probe is a test fixture, not an operations capability.
Related MCP server: kubernetes-runbooks-mcp-server
Safety notice
The server process runs with the permissions of the local user and any kubeconfig you configure. Use a lab cluster and a least-privilege, read-only identity.
Use only non-sensitive runbooks and data. Do not point it at production clusters or confidential documents.
There is no authentication or per-user authorisation. Do not expose it to an untrusted network.
HTTP defaults to
127.0.0.1. SettingMCP_HOST=0.0.0.0exposes the listener on all IPv4 interfaces; check your firewall before doing this for the container-based gateway lab.Tool results can enter a model's context when the client passes them to a model. Inspector can exercise tools without a model.
A client timeout does not establish that server-side work has stopped. Use
slow_probeonly in the lab.
Concepts explored
MCP server and client interaction.
Tool discovery through
tools/listand invocation throughtools/call.Typed tool arguments, with schemas generated from Python function signatures.
Stdio for local, client-managed processes and Streamable HTTP for the gateway lab.
Safe subprocess invocation using argument lists rather than shell strings.
Allowlists for clusters and namespaces.
Output limits to reduce how much data enters an agent's context.
Logging to standard error while reserving standard output for stdio MCP messages.
Requirements
Python 3.12 or later.
uv.
Node.js 20 or later, for MCP Inspector.
Linux diagnostic commands (
df,freeandsystemctl) forhost_health. Environments without systemd may return an error for the systemd check.kubectland a valid local kubeconfig, only if you use the Kubernetes tool.
Use the project's dependency configuration and lockfile to reproduce the SDK environment. MCP client and server versions matter; do not assume that any Inspector or SDK release will work with every protocol revision.
Installation
git clone https://github.com/albeus/ai-agents-mcp-itsops.git
cd ai-agents-mcp-itsops
uv syncRun all commands below from this repository's root. The standard invocation is:
uv run python -m mcp_itsops.serverConfiguration
The server uses a server-side mapping of approved logical cluster names to kubeconfig files, Kubernetes contexts and allowed namespaces. Edit the mapping in the source to match your lab. Example:
CLUSTERS = {
"rke-lab": {
"kubeconfig": Path.home() / "kubeconfigs" / "rke_cluster.yml",
"context": "rke-lab",
"namespaces": {"default", "monitoring", "lab"},
},
}The server, not the client, owns these boundaries. Do not expose arbitrary kubeconfig paths, contexts, namespaces, shell commands or SSH targets as unrestricted tool inputs.
For runbook search, create the folder and add a sample file:
mkdir -p ~/agent-lab/readable
printf '%s\n' \
'# SSH Runbook' \
'Check failed units with systemctl --failed.' \
> ~/agent-lab/readable/ssh.mdTransport settings
The entry point selects the transport through environment variables:
Variable | Default | Purpose |
|
| Set to |
|
| HTTP bind address; not used in stdio mode. |
|
| HTTP port; not used in stdio mode. |
HTTP mode uses stateless_http=True and json_response=True. The lab endpoint is /mcp.
Use only the documented transport values. The current entry point falls back to stdio for values other than streamable-http, so a typo can make an intended HTTP server wait on stdin instead.
Running the server
Stdio (default)
uv run python -m mcp_itsops.serverThe server appears idle. That is expected: a stdio MCP server waits for JSON-RPC requests on standard input. It is not an interactive chat prompt. Stop it with Ctrl+C.
Normally, a stdio client such as Inspector launches its own server process; do not start a separate process first.
Streamable HTTP (local testing)
MCP_TRANSPORT=streamable-http \
MCP_HOST=127.0.0.1 \
MCP_PORT=8000 \
uv run python -m mcp_itsops.serverKeep this terminal running. Connect an HTTP-capable client to the local MCP endpoint.
Streamable HTTP (LiteLLM container)
In the gateway lab, the LiteLLM container reaches the host through host.docker.internal. Start the server with an explicitly wider bind:
MCP_TRANSPORT=streamable-http \
MCP_HOST=0.0.0.0 \
MCP_PORT=8000 \
uv run python -m mcp_itsops.serverThis is not loopback-only and does not add authentication. Restrict access with the host firewall and stop the server when you finish. See the LiteLLM gateway lab for the corresponding gateway configuration and its recorded limitations.
Testing with MCP Inspector
Stdio workflow
Inspector launches the server as a child process. Explicitly select stdio so a previously exported HTTP setting cannot change the transport:
MCP_TRANSPORT=stdio \
npx @modelcontextprotocol/inspector \
uv run python -m mcp_itsops.serverOpen the local URL Inspector prints, select the stdio connection if needed, and connect. Use the Tools tab to discover and call tools.
HTTP workflow
Start the server in HTTP mode in one terminal using the local-testing command above. In another terminal, start Inspector without a child-process command:
npx @modelcontextprotocol/inspectorOpen the URL Inspector prints. Select Streamable HTTP, enter http://127.0.0.1:8000/mcp as the server URL and connect. Use the proxy connection mode if Inspector offers a choice; direct browser connections may require additional CORS configuration.
Do not use the stdio launch command to connect to an HTTP server. In HTTP mode the server is started independently, and Inspector connects to its URL.
Tool checks
Run List Tools and check names, descriptions and input schemas. The current source includes four tools, including the lab-only
slow_probe.Call
search_runbookswith{"query": "systemctl"}.Call
host_healthwith{}to use the default local host.If you have configured a lab cluster, call
k8s_pod_statuswith{"cluster": "rke-lab", "namespace": "default"}.Optionally call
slow_probewith{"seconds": 1}. Reserve longer delays for the timeout/tracing exercise.
Inspector discovery and tool calls do not require Ollama or another model. Kubernetes is needed only for the Kubernetes check.
Stdio safety rule
In the stdio transport, standard output is reserved for MCP JSON-RPC messages. Do not use print() for diagnostics, because ordinary text can corrupt the protocol stream. Use Python logging instead:
logger.info(
"Reading pod status: cluster=%s namespace=%s",
cluster,
namespace,
)The default logging handler writes to standard error, which leaves standard output free for MCP communication. Keep this convention in both transport modes so switching back to stdio remains safe.
Troubleshooting
Symptom | Check |
Inspector's stdio connection hangs | Ensure |
HTTP connection refused | Ensure the server is running in HTTP mode and that the URL's host and port match its bind settings. |
HTTP 404 | Check that the URL includes |
Address already in use | Stop the previous HTTP server or choose another |
Inspector fails while another client works | Compare client/server SDK and protocol versions; transport selection alone does not guarantee protocol compatibility. |
LiteLLM cannot reach the server | Check the bind address, |
| Run |
A bare browser visit or GET to /mcp is not a substitute for a complete MCP client test.
Security decisions
No arbitrary shell-command tool and no
shell=Truesubprocess calls.No arbitrary hostnames, SSH targets or kubeconfig paths.
Explicit cluster and namespace allowlists.
Fixed
kubectlargument structure.Command timeouts.
Diagnostic command output truncated to 2,000 characters; runbook search limited to 20 matches; pod summaries limited to 50 pods. These are partial limits, not a universal response-size cap.
Expected command and validation errors returned as tool results.
These controls reduce broad infrastructure access. They have not been independently reviewed or validated by an automated test suite.
Current limitations
This local learning server does not yet provide:
Authentication or per-user authorisation.
Gateway enforcement within the server itself.
Audit logging suitable for production.
Workload identity or isolated Kubernetes credentials.
Container sandboxing or network egress restrictions.
Automated tests.
A uniform output-size limit or structured error handling across all tools.
For a remotely exposed service, transport alone is not a security boundary. Authenticated access, authorisation, audit logs and network controls would need to be designed and tested separately.
Learning outcomes
Explain the difference between an MCP client, server, host and tool.
Inspect tool schemas and raw JSON-RPC messages.
Explain why stdio servers must not write diagnostics to standard output.
Recognise why arbitrary infrastructure identifiers should not become unrestricted tool inputs.
Compare a client-launched stdio server with an independently started HTTP server.
Distinguish a client timeout from evidence of server-side cancellation.
Relationship to the rest of the lab
This project publishes tools for MCP clients. It differs from ai-agents-miniagent, which owns its own agent loop and runs its tools locally; miniagent is not currently an MCP client.
The LiteLLM lab uses this server over Streamable HTTP. Its recorded success was tool discovery with the gateway master key; per-team MCP authorisation was not established.
The trace-probe lab uses the server directly for MCP calls, including slow_probe. It does not prove end-to-end tracing through LiteLLM's MCP gateway.
See the lab index for the suggested reading order.
Licence
Released under the MIT Licence. This is a learning lab, provided as is, without warranty.
Available Tools
4 toolshost_healthB
Return read-only disk, memory, and failed-systemd-unit status for the local lab host.
| Name | Required | Description | Default |
|---|---|---|---|
| host | No | local |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden, and it does disclose the key trait: the operation is 'read-only'. However it says nothing about permissions, failure behavior, or how the host parameter affects reach (local vs remote), leaving meaningful behavioral gaps.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
One sentence, front-loaded with the verb and the resources inspected, with zero padding. Nothing could be removed without losing content.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be documented, and the tool is simple. But the sole input parameter is undocumented and no usage context is given, so the definition is adequate rather than complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There is one parameter ('host') with 0% schema description coverage, and the description only references a 'local lab host' default. It does not explain what values the host parameter accepts or that it selects a non-local target, so the single parameter is largely uninterpretable from the definition.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (Return) and concrete resources (disk, memory, failed-systemd-unit status) scoped to 'the local lab host'. The host-level scope implicitly separates it from siblings like k8s_pod_status and slow_probe, though it never names an alternative explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The scope phrase 'for the local lab host' implies the diagnostic context in which to use it, but there is no explicit when-to-use, when-not-to-use, or routing against the sibling tools. An agent must infer the usage scenario.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
k8s_pod_statusB
Return a bounded pod-status summary from an approved cluster and namespace.
| Name | Required | Description | Default |
|---|---|---|---|
| cluster | No | rke-lab | |
| namespace | No | default |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries full burden. It does disclose two useful traits: the output is 'bounded' (no unbounded dumps) and only 'approved' clusters/namespaces are accepted, which signals a governance constraint. It still omits whether this is strictly read-only, what permissions are needed, and what 'bounded' concretely caps.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single front-loaded sentence with the verb first and zero filler. It is tight, though the brevity contributes to the gaps in the other dimensions rather than being purely efficient.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be explained. However, for a tool with two undocumented parameters and no annotations, the description leaves an agent without enough to know when to invoke it or how to populate its arguments.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0% and the two parameters (cluster, namespace) have only defaults, no semantics. The description references both indirectly via 'approved cluster and namespace' but adds no format, expected values, or default behavior, so it fails to compensate for the empty schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific verb and resource ('Return a bounded pod-status summary') scoped to a cluster and namespace, so the agent knows what it produces. It does not distinguish itself from siblings like host_health or slow_probe, leaving the agent to infer the boundary between pod-level and host-level diagnostics.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no statement of when to choose this tool over host_health, slow_probe, or search_runbooks. The phrase 'approved cluster and namespace' hints at an access precondition but never spells out a usage scenario or exclusion.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_runbooksB
Search approved Markdown runbooks for a text query.
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full behavioral burden. It does disclose that only 'approved' Markdown runbooks are searched, which is a useful filter trait, but it says nothing about ranking, result limits, permissions, or how matches are returned.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single front-loaded sentence with zero filler. Every word earns its place and the core action is stated immediately.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be explained, and the tool is simple with one required parameter. However, with no annotations and no behavioral detail about scope enforcement or result handling, the definition is only minimally complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Only one parameter exists and schema description coverage is 0%, so the schema adds no meaning. The phrase 'for a text query' clarifies that the parameter is free-form text rather than an ID or filter, which is marginally useful but largely inferable from the parameter name.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('Search') and resource ('approved Markdown runbooks') plus the query modality. The sibling tools (host_health, k8s_pod_status, slow_probe) are unrelated diagnostics, so no differentiation is needed or expected. Clear and unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No when-to-use, when-not-to-use, or alternative-tool guidance is given. The word 'approved' hints at a scoping constraint, but nothing tells the agent when this tool is the right choice versus other lookup mechanisms. Usage is only implied.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
slow_probeA
Deliberately slow lab-only probe for timeout and tracing tests.
| Name | Required | Description | Default |
|---|---|---|---|
| seconds | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden. It usefully discloses the key trait (intentionally slow) and the safety constraint (lab-only), but says nothing about expected duration, whether it has side effects, or what it returns. It adds real context but leaves notable behavioral gaps.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single tight sentence with the purpose and the most important constraint (lab-only) front-loaded. No filler, though the terseness is part of why behavioral detail is thin.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values do not need describing, and the tool is low-stakes. Still, for a timing-sensitive probe with zero annotations and an undocumented parameter, more detail on duration and effects would round out the definition.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0% and the single 'seconds' parameter is undocumented in the schema. The description's emphasis on slowness lets an agent infer that 'seconds' governs the delay, but it never states the unit relationship or default behavior explicitly, so the compensation is only partial.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific function: a deliberately slow probe used for timeout and tracing tests. The 'lab-only' qualifier and the emphasis on slowness clearly separate it from diagnostic siblings like host_health and k8s_pod_status, though no sibling is named explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Names the intended scenarios (timeout and tracing tests) and gives an implicit exclusion via 'lab-only', signaling it should not be run against production systems. It stops short of stating alternative tools to use instead, but the context is clear enough to act on.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
4 tool updates
v0.1.0- First observed
host_health - First observed
k8s_pod_status - First observed
search_runbooks - First observed
slow_probe
TDQS
Scored across 4 tools
Each tool targets a clearly different resource: runbook search, local host health, k8s pod status, and a deliberate timeout probe. The only mild overlap is host_health vs k8s_pod_status, but the scope distinction (local lab host vs approved cluster/namespace) is stated explicitly, so confusion is unlikely.
All four names use consistent snake_case, which is the most important signal. Verb-led (search_runbooks) and noun-led (host_health, k8s_pod_status, slow_probe) patterns are mixed, but all names are readable and predictable within the set.
Four tools is on the thin side for an IT-ops server, with only read-only diagnostics and a synthetic probe. Each tool earns its place and nothing is redundant, but the surface feels minimal for the apparent domain.
The server provides a coherent read-only diagnostic surface (runbooks, host, pods) plus a timeout test, but omits common ops needs like logs, events, metrics, or any remediation/action tools. As a lab/read-only harness this may be intentional, yet agents will hit dead ends for anything beyond status checks.
Maintenance
Related MCP Connectors
Guarded MCP server for agent-readable business truth, provenance, readiness, and discovery.
Agent-native registry to discover APIs, MCP servers and CLIs, with live health checks.
Read-only MCP server for the OrchestKit docs: full-text search + Markdown fetch. No auth.
Read-only MCP server for AIStatusDashboard status, incidents, metrics, and fallback recommendations.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceEnables MCP clients to access and read mdbook documentation, including structure, content, and search.4 npm3MIT
- AlicenseAqualityDmaintenanceProvides access to Kubernetes troubleshooting runbooks, enabling search, discovery, and retrieval of guides for common issues like pod crashes, node problems, and network failures.3MIT
- FlicenseNot gradedqualityBmaintenanceEnables read-only Kubernetes incident investigation through MCP tools for listing pods, describing resources, fetching logs, and searching runbooks.1-
- AlicenseNot gradedqualityCmaintenanceEnables MCP-compatible clients to semantically search, retrieve, and list engineering runbooks, providing relevant runbooks in response to natural language queries.MIT