aipod
Click on "Install 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., "@aipodFetch the service contract and list the available tools."
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.
aipod — one binary, two modes
Purpose. aipod is a single program you can start as an MCP server or
as an agent, chosen by a subcommand:
Command | Mode | What it is | Publishes |
| MCP server | a reference implementation of every MCP feature, so client / gateway / runtime authors have one endpoint to test against | a service contract ( |
| agent | a pydantic-ai agent that connects to an | an agent card ( |
Built on FastMCP (server
mode) and pydantic-ai's MCP client (agent mode). Packaged as a single
FROM scratch container; the same image runs either mode.
Repo: https://github.com/bigg01/aipod ·
Latest release: v0.1.2 ·
Image: ghcr.io/bigg01/aipod ·
Chart: oci://ghcr.io/bigg01/charts/aipod
Live instance for remote MCP testing: a public aipod server runs at
https://aipod.guggenbuehl.net/ — MCP endpoint https://aipod.guggenbuehl.net/mcp,
contract at /contract.json. Open by default; point any MCP client at it without
installing anything. Shared and best-effort — treat state (incidents,
deployments) as scratch.
Wondering why a reference MCP server and agent are worth having around? See
docs/blog/contracts-and-agent-cards.md.
Server mode — feature surface
Area | Details |
Tools |
|
Marvel roster |
|
SRE / IT-application |
|
pydantic-ai tools |
|
Structured output |
|
Side effects |
|
Content blocks | text, image, embedded resource, resource links, priority / audience annotations |
Resources | static docs + templated |
Prompts |
|
Auth | open by default; add a key and |
Metrics | on by default (Prometheus |
Also | argument completion, resource subscriptions, progress, |
HTTP routes: GET / (landing), GET /health, GET|POST /mcp, GET /contract.json,
GET /metrics (Prometheus, on by default), and — when auth is enabled —
GET /.well-known/oauth-protected-resource.
GET / itself is a plain landing page listing every tool, resource, and
prompt above — open it in a browser once the server is running:

Related MCP server: Echo MCP Server
Agent mode
HTTP + JSON MCP (Streamable HTTP)
client ─────────────▶ aipod agent ────────────────────────▶ aipod server
pydantic-ai Agent + model provider tools / resources / promptsHTTP routes: GET /, GET /health, GET /.well-known/agent-card.json,
POST /ask ({"prompt": "..."} → {"output": "..."}).
Agent mode needs a model — AIPOD_MODEL (e.g. anthropic:claude-haiku-4-5) plus
the provider key. Without one it still serves the card and /health; /ask
returns 503.
Requirements
Python ≥ 3.11, uv
Docker + a Kubernetes cluster (optional)
Run locally
uv sync
# server mode
uv run aipod server # http://127.0.0.1:8000 (MCP at /mcp)
uv run aipod server --transport stdio # for subprocess clients (Claude Desktop, editors)
uv run aipod server --print contract # emit the service contract as JSON
uv run aipod server --auth-token s3cret # require 'Authorization: Bearer s3cret' on /mcp
# agent mode (needs a running server + a model)
export AIPOD_MCP_URL=http://127.0.0.1:8000/mcp
export AIPOD_MODEL=anthropic:claude-haiku-4-5
export ANTHROPIC_API_KEY=...
uv run aipod agent # http://127.0.0.1:8080
uv run aipod agent --ask "Write a poem about sockets, then summarise it."
uv run aipod agent --print agent-card # emit the agent card as JSONstdio vs. HTTP (server mode)
Streamable HTTP (default) — a long-running network service; clients connect to
/mcp, responses and notifications stream back as SSE. Use for anything shared or deployed.stdio — no network listener. The client launches
aipod serveras a child process and talks to it over that process's stdin/stdout. "Subprocess clients" are desktop / editor MCP hosts (Claude Desktop, Cursor, the VS Code MCP extension) that work this way; you never start the server yourself.
Authentication (optional)
The server runs open by default. Give it a key and the Streamable HTTP
/mcp route becomes an OAuth 2.1 protected resource:
uv run aipod server --auth-token s3cret # or: AIPOD_API_KEY=s3cret
export AIPOD_API_KEYS="key-a,key-b" # multiple keys (rotation / per-client)Env var | Effect |
| keys the server accepts ( |
| CSV of scopes a caller must hold (default: none) |
| authorization-server URL advertised in metadata (default: this server) |
| externally reachable base URL when behind a proxy / ingress |
With auth on:
requests to
/mcpwithoutAuthorization: Bearer <key>get401+ aWWW-Authenticateheader pointing atGET /.well-known/oauth-protected-resource(RFC 9728);that metadata document lists the authorization server(s) and scopes;
contract.json→securityswitches from{"scheme":"none"}to abearerblock, andclientRequirements.authentication.requiredbecomestrue.
Tokens are checked against the static key list — the resource-server half of the
spec without an identity provider. For full OAuth 2.1, point
AIPOD_AUTH_ISSUER at a real authorization server and replace
StaticTokenVerifier in src/aipod/server/auth.py with a JWT-validating one.
aipod agent reaches a protected server by setting AIPOD_MCP_TOKEN.
curl -s http://127.0.0.1:8000/mcp -X POST ... -H 'Authorization: Bearer s3cret'
curl -s http://127.0.0.1:8000/.well-known/oauth-protected-resource | jqFull walkthrough in docs/testing-mcp.md.
Observability (OpenTelemetry)
Both modes emit OpenTelemetry metrics, on by default with the Prometheus
exporter — aipod server serves GET /metrics with no configuration. The server
instruments its own MCP internals, not just the Python process:
Instrument | Type | Attributes |
| counter |
|
| histogram (s) | same |
| counter |
|
| histogram (s) | per tool name |
| counter | server → client sampling round-trips |
| gauges | the registered inventory |
| gauges | live per-connection state |
| counter / histogram |
|
# default: Prometheus scrape endpoint on the mode's HTTP port
uv run aipod server
curl -s localhost:8000/metrics | grep mcp_server_
# push to an OTLP/HTTP collector instead
AIPOD_METRICS=otlp OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 uv run aipod agent
# stdout, for a quick look
AIPOD_METRICS=console uv run aipod server
# turn it off
AIPOD_METRICS=none uv run aipod serverAIPOD_METRICS = prometheus (default) | otlp | console | none;
OTEL_METRICS_EXPORTER=none or OTEL_SDK_DISABLED=true also disable it;
a bare OTEL_EXPORTER_OTLP_ENDPOINT selects otlp. OTEL_SERVICE_NAME /
OTEL_RESOURCE_ATTRIBUTES set the resource. In k8s: metrics.exporter in the
Helm values, or AIPOD_METRICS in k8s/configmap.yaml.
Grafana dashboard — dashboards/aipod.json (import
it directly) covers the inventory gauges, per-method + per-tool rate / errors /
latency, sampling, and the agent /ask. On a kube-prometheus-stack cluster,
kubectl apply -k dashboards ships it as a sidecar-loaded ConfigMap.
The running version shows on the landing page (GET /) and in GET /health
({"status":"ok","version":"…"}).
Test
uv run pytestHermetic — server tests drive an in-memory MCP session with a stubbed sampling callback; agent tests need no running server and no API key.
Exercise the server with the MCP Inspector
@modelcontextprotocol/inspector
is the reference MCP client — it speaks the raw protocol, so no model or API key
is needed (except for the sampling-backed tools).
uv run aipod server # start a server (MCP at :8000/mcp)
# interactive UI (http://127.0.0.1:6274)
npx -y @modelcontextprotocol/inspector # or: make inspect
# scripted / CI — one request per call (transport auto-detected from /mcp)
npx -y @modelcontextprotocol/inspector --cli \
http://127.0.0.1:8000/mcp --method tools/list # or: make inspect-cli
npx -y @modelcontextprotocol/inspector --cli \
http://127.0.0.1:8000/mcp --method tools/call --tool-name add --tool-arg a=2 --tool-arg b=3
# or skip the local server and hit the live instance
npx -y @modelcontextprotocol/inspector --cli \
https://aipod.guggenbuehl.net/mcp --method tools/listFull walkthrough — every feature (structured output, resource templates,
completion, subscriptions, logging, progress, sampling), the --cli vs UI split,
stdio via an mcp.json, and a CI gate example — in
docs/testing-mcp.md.
Container (FROM scratch)
One image, either mode. PyInstaller bundles the app, staticx folds in libc,
the final image is FROM scratch (binary + /tmp + CA certs + /etc/passwd),
~34 MB.
Every release publishes it to the GitHub Container Registry (public, no login):
docker pull ghcr.io/bigg01/aipod:0.1.1 # or :latest, :0.1, :sha-<commit>
docker run --rm -p 8000:8000 ghcr.io/bigg01/aipod:latest # server (default CMD)
docker run --rm -p 8080:8080 \
-e AIPOD_MCP_URL=http://host.docker.internal:8000/mcp \
-e AIPOD_MODEL=anthropic:claude-haiku-4-5 -e ANTHROPIC_API_KEY=... \
ghcr.io/bigg01/aipod:latest agent --host 0.0.0.0 --port 8080 # agentOr build it yourself: docker build -t aipod:latest . (same result, make docker).
The binary self-extracts into TMPDIR (/tmp) on start, so the runtime needs a
writable /tmp even with a read-only root filesystem.
Kubernetes
Both modes deploy from the one image, two ways:
Kustomize — k8s/
kubectl apply -k k8s:
Deployment/aipod-server(+Service/aipod-server) —replicas: 1(per-session state + background tasks live in memory)Deployment/aipod-agent(+Service/aipod-agent,Ingress) —replicas: 2, stateless;AIPOD_MCP_URLpoints at the server ServiceConfigMap/aipod-config— governance labels +AIPOD_MODEL; provider key from a Secret you create (kubectl create secret generic aipod-model --from-literal=ANTHROPIC_API_KEY=...)Secret/aipod-auth(optional) —AIPOD_API_KEYturns on bearer auth for the server and is reused by the agent asAIPOD_MCP_TOKEN(kubectl create secret generic aipod-auth --from-literal=AIPOD_API_KEY=$(openssl rand -hex 16))
Helm — charts/aipod/
# from a checkout
helm install aipod ./charts/aipod
# or the published OCI chart
helm install aipod oci://ghcr.io/bigg01/charts/aipod --version 0.1.0 \
-f examples/helm-values.yamlSame objects, parameterised: server.enabled / agent.enabled, *.replicas,
*.ingress.*, *.resources, the config map, and auth / model (inline key ⇒
the chart makes the Secret, or point at *.existingSecret). Full list in
charts/aipod/values.yaml;
examples/helm-values.yaml is a TLS-ingress + bearer-auth
override. make helm-lint / helm-template / helm-install.
Both pods run non-root, no capabilities, read-only rootfs, RuntimeDefault
seccomp, with an emptyDir at /tmp.
On Azure Kubernetes Service (AKS)
Same manifests, no Azure-specific changes needed beyond getting the image into a registry AKS can pull from:
az acr create -g my-rg -n myacr --sku Basic
az acr build -r myacr -t aipod:latest . # builds in ACR, no local push needed
az aks create -g my-rg -n my-aks --attach-acr myacr
az aks get-credentials -g my-rg -n my-aks
# point k8s/kustomization.yaml's `images:` entry at myacr.azurecr.io/aipod, then:
kubectl apply -k k8s/--attach-acr wires AKS's kubelet identity to pull from that registry
without a separate imagePullSecret.
Agent platforms
Same server, same /mcp endpoint — different runtimes just point at it
differently.
kagent registers a remote MCP server as its own CRD — see
examples/kagent-remotemcpserver.yaml. Apply it and kagent discovers every tool the same way it discovers its own built-in tool server (kubectl get remotemcpserver aipod -o yaml→status.discoveredTools).kars (Microsoft's Kubernetes-native agent runtime) has its own
McpServerCRD — OAuth, per-tool allow-lists, and sandbox selectors included — seeexamples/kars-mcpserver.yaml.Azure AI Foundry (and anything else using the same Responses-API-shaped MCP tool) takes the endpoint straight in the agent/tool definition, no separate resource — see
examples/azure-ai-foundry-mcp-tool.json.
CI / releases
.github/workflows/ci.yml runs on every push / PR:
pytest on Python 3.11–3.13, uv build, uv lock --check, a check that
examples/ is in sync, helm lint + kubeconform on the rendered manifests, and
a FROM scratch image build with a /health + /contract.json smoke test.
.github/workflows/release.yml runs on a
vX.Y.Z tag (which must match the pyproject.toml version) and produces, for
that version:
Container —
ghcr.io/bigg01/aipodtaggedX.Y.Z+X.Y+latest+sha-<commit>, with an SBOM and build provenance attestation. Public —docker pullneeds no login.Helm chart —
oci://ghcr.io/bigg01/charts/aipod, version pinned to the tag.Binary — the static
aipod-linux-x86_64.GitHub Release — notes plus the binary and chart tarball attached.
Governance
Both modes carry the same labels from AIPOD_* env vars — a governance block in
the server contract, an x-governance block (plus a dependencies link to the
server's contract) in the agent card:
Env var | Field |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Per-tool the contract also has requiresSampling, sideEffects, and dataEgress
so a router / gateway can gate calls on data movement and state changes rather
than on tool names.
Layout
src/aipod/
__main__.py CLI - `aipod server` | `aipod agent`
governance.py shared AIPOD_* governance labels
telemetry.py OpenTelemetry metrics (both modes)
server/
build.py every MCP feature on one FastMCP instance
sampling_tools.py pydantic-ai tools (model via MCP sampling)
heroes.py Marvel roster data + models for the roster tools
sre.py IT-application / SRE estate: catalogue, incidents, deploys, metrics
auth.py optional bearer-token / OAuth 2.1 protected-resource auth
contract.py service contract builder
data.py, landing.py
agent/
runtime.py pydantic-ai Agent + MCP toolset -> the server
card.py agent card builder
http.py Starlette app: card, /health, /ask, /metrics
config.py AIPOD_MCP_URL, AIPOD_MODEL, ...
packaging/ PyInstaller entry + spec
examples/ generated contract.json + agent-card.json + helm-values.yaml
k8s/ both Deployments, Services, Ingress, ConfigMap, kustomization
charts/aipod/ Helm chart (same objects, parameterised)
.github/workflows/ ci.yml (test + build) + release.yml (image + chart + binary)
docs/ testing-mcp.md (Inspector walkthrough) + blog/ (contracts & agent cards)
tests/ test_server.py + test_agent.pyMaintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceA server implementation of the Model Context Protocol (MCP) that provides REST API endpoints for managing and interacting with MCP resources.
- FlicenseNot gradedqualityDmaintenanceA simple demonstration MCP server that provides an echo tool and resource for learning how to build MCP servers. Serves as a starting point and template for creating custom MCP server implementations.1
- AlicenseNot gradedqualityDmaintenanceA comprehensive reference implementation demonstrating all features of the Model Context Protocol (MCP) specification, serving as documentation, learning resource, and testing tool for MCP implementations.1MIT
- AlicenseNot gradedqualityDmaintenanceA test MCP server that exercises all MCP protocol features, including prompts, tools, resources, and sampling, for client builders.281,633Unlicense - libtelnet variant
Related MCP Connectors
An authenticated remote MCP server for user-owned devices and one-shot capability invocation.
MCP server providing access to the Scorecard API to evaluate and optimize LLM systems.
The official MCP Server from Mia-Platform to interact with Mia-Platform Console
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/bigg01/aipod'
If you have feedback or need assistance with the MCP directory API, please join our Discord server