{
  "markdown": "<div align=\"center\">\n  <h1>infra-lens-mcp</h1>\n\n  <p><strong>Explain Linux incidents over SSH with baseline-aware MCP tooling.</strong></p>\n\n  <p>\n    A TypeScript MCP server for live Linux diagnostics, local SQLite history,<br />\n    review-first incident workflows, and secure observability exports.\n  </p>\n\n  <p>\n    <a href=\"https://github.com/oaslananka/infra-lens-mcp/actions/workflows/ci.yml\"><img src=\"https://github.com/oaslananka/infra-lens-mcp/actions/workflows/ci.yml/badge.svg\" alt=\"CI status\" /></a>\n    <a href=\"https://github.com/oaslananka/infra-lens-mcp/actions/workflows/codeql.yml\"><img src=\"https://github.com/oaslananka/infra-lens-mcp/actions/workflows/codeql.yml/badge.svg\" alt=\"CodeQL status\" /></a>\n    <a href=\"https://github.com/oaslananka/infra-lens-mcp/actions/workflows/security.yml\"><img src=\"https://github.com/oaslananka/infra-lens-mcp/actions/workflows/security.yml/badge.svg\" alt=\"Security Gates status\" /></a>\n    <a href=\"https://github.com/oaslananka/infra-lens-mcp/actions/workflows/osv-scanner-full.yml\"><img src=\"https://github.com/oaslananka/infra-lens-mcp/actions/workflows/osv-scanner-full.yml/badge.svg\" alt=\"OSV-Scanner status\" /></a>\n    <a href=\"https://codecov.io/gh/oaslananka/infra-lens-mcp\"><img src=\"https://codecov.io/gh/oaslananka/infra-lens-mcp/graph/badge.svg\" alt=\"Codecov coverage\" /></a>\n    <a href=\"https://securityscorecards.dev/viewer/?uri=github.com/oaslananka/infra-lens-mcp\"><img src=\"https://api.securityscorecards.dev/projects/github.com/oaslananka/infra-lens-mcp/badge\" alt=\"OpenSSF Scorecard\" /></a>\n  </p>\n\n  <p>\n    <a href=\"https://www.npmjs.com/package/infra-lens-mcp\"><img src=\"https://img.shields.io/npm/v/infra-lens-mcp.svg\" alt=\"npm version\" /></a>\n    <a href=\"https://www.npmjs.com/package/infra-lens-mcp\"><img src=\"https://img.shields.io/npm/dm/infra-lens-mcp.svg\" alt=\"npm downloads\" /></a>\n    <a href=\"https://nodejs.org/\"><img src=\"https://img.shields.io/badge/Node.js-%3E%3D22-339933.svg\" alt=\"Node.js 22 or newer\" /></a>\n    <a href=\"./docs/compliance/mcp-2025-11-25.md\"><img src=\"https://img.shields.io/badge/MCP-2025--11--25-6f42c1.svg\" alt=\"MCP 2025-11-25\" /></a>\n    <a href=\"https://github.com/oaslananka/infra-lens-mcp/pkgs/container/infra-lens-mcp\"><img src=\"https://img.shields.io/badge/GHCR-signed%20multi--arch-2496ED.svg\" alt=\"Signed multi-architecture GHCR image\" /></a>\n    <a href=\"./LICENSE\"><img src=\"https://img.shields.io/badge/license-MIT-blue.svg\" alt=\"MIT license\" /></a>\n  </p>\n\n  <p>\n    <a href=\"./docs/README.md\">Documentation</a> ·\n    <a href=\"./docs/usage.md\">Usage</a> ·\n    <a href=\"./docs/architecture.md\">Architecture</a> ·\n    <a href=\"./SECURITY.md\">Security</a> ·\n    <a href=\"./docs/governance.md\">Governance</a> ·\n    <a href=\"./ROADMAP.md\">Roadmap</a> ·\n    <a href=\"./SUPPORT.md\">Support</a> ·\n    <a href=\"https://github.com/oaslananka/infra-lens-mcp/releases\">Releases</a>\n  </p>\n\n  <p>\n    <a href=\"https://www.buymeacoffee.com/oaslananka\">\n      <img src=\"https://img.buymeacoffee.com/button-api/?text=Buy%20me%20a%20coffee&amp;emoji=%E2%98%95&amp;slug=oaslananka&amp;button_colour=FFDD00&amp;font_colour=000000&amp;font_family=Arial&amp;outline_colour=000000&amp;coffee_colour=ffffff\" alt=\"Buy me a coffee\" />\n    </a>\n  </p>\n</div>\n\n`infra-lens-mcp` connects to Linux hosts over SSH, captures bounded live metrics, stores observations and approved baselines in local SQLite, explains anomalies, and produces review-first incident artifacts. The npm package and signed container are release-ready; public connector publication remains intentionally blocked until an external OAuth/HTTPS deployment is verified.\n\n## Demo\n\n![infra-lens-mcp demo](docs/demo.gif)\n\nSee the [MCP 2025-11-25 compliance matrix](./docs/compliance/mcp-2025-11-25.md) for current protocol support, delegated behavior, and connector publication constraints.\n\n## Tools\n\n| Tool | Purpose |\n| --- | --- |\n| `analyze_server` | Analyze a bounded sampled window with progress/cancellation support, then store only the completed observation |\n| `analyze_server_snapshot` | Analyze and store one immediate snapshot without a sampling delay |\n| `snapshot` | Store a point-in-time observation without anomaly analysis |\n| `record_baseline` | Save a labeled healthy-state sample |\n| `compare_to_baseline` | Compare current state with a named baseline |\n| `get_history` | Return CPU, memory, or load history from SQLite |\n| `inspect_host_capabilities` | Check required Linux commands and proc files before collection |\n| `plan_remediation` | Propose evidence-backed, approval-required remediation without executing changes |\n| `draft_incident_report` | Draft an incident report and postmortem from persisted observations |\n| `compare_incident_windows` | Compare adjacent windows for one host or the same window across two hosts |\n\nAll tools return both readable JSON text and MCP `structuredContent` validated by declared `outputSchema` definitions, so clients and agents can consume responses without parsing the text block. Collection tools include a `warnings` array when optional sections cannot be collected but a partial snapshot is still usable. Use `analyze_server_snapshot` for interactive checks; use `analyze_server` only when a sampled window is required. Sampled analysis emits MCP progress when the client supplies a progress token and never persists a cancelled partial run.\n\n## Requirements\n\n- Node.js 24 LTS for CI, Docker, and release workflows\n- Node.js 22 or newer for package runtime compatibility\n- pnpm 11.15.1 through Corepack for development installs\n- Linux SSH targets with `/proc`, `free`, `df`, `ps`, and `uname`\n- Strict SSH host verification through `known_hosts` or pinned SHA256 host keys\n\n## Quick Start\n\nRun the stdio MCP server from npm:\n\n```bash\nnpx -y infra-lens-mcp\n```\n\nDesktop MCP client style configuration:\n\n```json\n{\n  \"mcpServers\": {\n    \"infra-lens\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"infra-lens-mcp\"],\n      \"env\": {\n        \"INFRA_LENS_DB\": \"/Users/you/.infra-lens-mcp/metrics.db\"\n      }\n    }\n  }\n}\n```\n\nLocal development:\n\n```bash\ncorepack enable\ncorepack prepare pnpm@11.15.1 --activate\npnpm install --frozen-lockfile\npnpm run build\nnode dist/mcp.js\n```\n\n## Configuration\n\nTransport is selected by the executable entry point, not by an environment variable: `npx -y infra-lens-mcp` or `node dist/mcp.js` starts stdio, while `node dist/server-http.js` starts Streamable HTTP.\n\n| Variable | Default | Description |\n| --- | --- | --- |\n| `INFRA_LENS_DB` | `~/.infra-lens-mcp/metrics.db` | SQLite database path |\n| `INFRA_LENS_RETENTION_DAYS` | `30` | Snapshot retention in days; `0` disables automatic pruning |\n| `MCP_HTTP_HOST` | `127.0.0.1` | HTTP bind host. `HOST` remains a deprecated alias |\n| `MCP_HTTP_PORT` | `3000` | HTTP bind port. `PORT` remains a deprecated alias |\n| `MCP_HTTP_ENDPOINT_PATH` | `/mcp` | Canonical Streamable HTTP MCP endpoint path |\n| `MCP_HTTP_ALLOWED_ORIGINS` | unset | Comma-separated allowed Origin values |\n| `MCP_HTTP_ALLOWED_HOSTS` | unset | Comma-separated allowed Host values |\n| `MCP_HTTP_AUTH_MODE` | `none` | `none`, `bearer`, or `oauth-gateway`; `oauth` is accepted as a compatibility alias |\n| `MCP_HTTP_BEARER_TOKEN` | unset | Local/dev bearer fallback token |\n| `MCP_HTTP_OAUTH_GATEWAY_HEADER` | `x-infra-lens-gateway-auth` | Header injected by a trusted OAuth gateway |\n| `MCP_HTTP_OAUTH_GATEWAY_SECRET` | unset | Shared backend secret required for `oauth-gateway` mode |\n| `MCP_HTTP_BODY_LIMIT_BYTES` | `1048576` | Maximum JSON request body size |\n| `MCP_HTTP_REQUEST_TIMEOUT_MS` | `30000` | Maximum time to receive and handle an HTTP request before the socket is closed |\n| `MCP_HTTP_MAX_CONCURRENT_REQUESTS` | `100` | Maximum concurrent HTTP requests accepted by the Node process |\n| `MCP_HTTP_RATE_LIMIT_PER_MINUTE` | `0` | Optional per-client in-memory rate limit; `0` disables it |\n| `MCP_HTTP_AUTHORIZATION_SERVERS` | unset | OAuth authorization server metadata URLs |\n| `MCP_PROFILE` | `full` | `full`, `remote-safe`, `chatgpt`, or `claude` |\n| `MCP_SSH_STRICT_HOST_CHECKING` | `true` | Strict host key verification toggle |\n| `MCP_SSH_KNOWN_HOSTS` | `~/.ssh/known_hosts` | Known hosts file |\n| `MCP_SSH_ALLOWED_HOSTS` | unset | Exact host/IP or IPv4 CIDR allowlist; required for remote-safe profiles and enforced in `full` profile when set |\n| `MCP_SSH_ALLOWED_USERS` | unset | Optional comma-separated SSH username allowlist |\n| `MCP_SSH_ALLOWED_PORTS` | unset | Optional comma-separated SSH port allowlist |\n| `MCP_SSH_MAX_SESSIONS_PER_HOST` | `0` | Optional active SSH session cap per host:port; `0` disables it |\n| `MCP_SSH_MAX_CONNECTION_ATTEMPTS_PER_MINUTE` | `0` | Optional SSH connection-attempt cap per host:port per minute; `0` disables it |\n\n`MCP_DB_PATH` from older examples is not used; use `INFRA_LENS_DB`.\n\n## SSH Security\n\nStrict host key checking is enabled by default. Provide either:\n\n- a `hostKeySha256` value in the connection input, such as `SHA256:...`\n- a `knownHostsPath` in the connection input\n- `MCP_SSH_KNOWN_HOSTS` pointing at an OpenSSH `known_hosts` file\n\nRaw passwords, private keys, and passphrases are accepted only in the default `full` profile for trusted local MCP contexts. `remote-safe`, `chatgpt`, and `claude` profiles reject raw SSH credentials in tool input and require `MCP_SSH_ALLOWED_HOSTS`. Production SSH policy can also restrict exact hosts or IPv4 CIDR ranges, users, ports, per-host active sessions, and per-host connection attempts.\n\nProcess command arguments are not collected by the default process command. Secret-like values in process data, SSH errors, and logs are redacted before storage or output.\n\n## HTTP Transport\n\nRun the Streamable HTTP transport locally. The canonical MCP endpoint is `http://127.0.0.1:3000/mcp` unless `MCP_HTTP_ENDPOINT_PATH` is changed. HTTP mode is stateless today: the server does not issue or accept `MCP-Session-Id`, and only POST JSON-RPC calls are supported on the MCP endpoint. `MCP_HTTP_REQUEST_TIMEOUT_MS` and any proxy timeout must exceed the requested sampled window; otherwise use `analyze_server_snapshot`. stdio has no server-owned wall-clock request timeout, so the client controls its timeout and MCP cancellation.\n\n```bash\nMCP_HTTP_HOST=127.0.0.1 MCP_HTTP_PORT=3000 node dist/server-http.js\n```\n\nLoopback HTTP can run without auth for local development. Any non-loopback bind, such as `0.0.0.0`, fails fast unless all of these are configured:\n\n- `MCP_PROFILE=remote-safe`, `chatgpt`, or `claude`\n- `MCP_HTTP_AUTH_MODE=bearer` or `oauth-gateway`\n- `MCP_HTTP_ALLOWED_ORIGINS`\n- `MCP_HTTP_ALLOWED_HOSTS`\n\nNative OAuth/JWT validation is not implemented inside this package. Public deployments should use `MCP_HTTP_AUTH_MODE=oauth-gateway` behind a production OAuth-aware gateway or reverse proxy, configure HTTPS `MCP_HTTP_RESOURCE_URL`, and block direct access to the Node process. Keep origin/host allowlists, body limits, request timeout, concurrency limit, and optional rate limit enabled at the Node process even when an upstream proxy also enforces them. See [ADR 0006](./docs/adr/0006-oauth-gateway-strategy.md). Connector publication readiness remains false until a full connector deployment is verified.\n\n## Docker\n\nThe Docker image defaults to stdio mode:\n\n```bash\ndocker build -t infra-lens-mcp .\ndocker volume create infra-lens-data\ndocker run --rm -i \\\n  --read-only \\\n  --cap-drop=ALL \\\n  --security-opt=no-new-privileges:true \\\n  --tmpfs /tmp:rw,noexec,nosuid,nodev,size=64m \\\n  --mount type=volume,src=infra-lens-data,dst=/home/appuser/.infra-lens-mcp \\\n  infra-lens-mcp\n```\n\nFor local HTTP testing, override the command and keep the bind host on loopback unless a remote-safe profile and auth controls are configured:\n\n```bash\ndocker run --rm -p 127.0.0.1:3000:3000 \\\n  --read-only \\\n  --cap-drop=ALL \\\n  --security-opt=no-new-privileges:true \\\n  --tmpfs /tmp:rw,noexec,nosuid,nodev,size=64m \\\n  --mount type=volume,src=infra-lens-data,dst=/home/appuser/.infra-lens-mcp \\\n  -e MCP_HTTP_HOST=0.0.0.0 \\\n  -e MCP_HTTP_ALLOWED_ORIGINS=http://localhost:3000 \\\n  -e MCP_HTTP_ALLOWED_HOSTS=localhost:3000 \\\n  -e MCP_HTTP_AUTH_MODE=bearer \\\n  -e MCP_HTTP_BEARER_TOKEN=local-dev-token \\\n  infra-lens-mcp node dist/server-http.js\n```\n\n\n## Observability exports\n\nObservability is a separate, disabled-by-default process that reads the latest persisted observations without initiating SSH collection:\n\n```bash\nINFRA_LENS_OBSERVABILITY_ENABLED=true infra-lens-observe\n```\n\nThe default OpenMetrics endpoint is `http://127.0.0.1:9464/metrics`. Optional OTLP/HTTP JSON export uses standard `OTEL_EXPORTER_OTLP_*` variables. See [Observability exports](./docs/observability.md) for Prometheus, OpenTelemetry, privacy, and remote-access guidance.\n\n## Development\n\n```bash\npnpm run format:check\npnpm run lint\npnpm test\npnpm run test:coverage\npnpm run build\npnpm run check:metadata\npnpm run package:dry-run\n```\n\nDocker-backed SSH e2e validation uses a self-contained fixture lifecycle:\n\n```bash\npnpm run test:e2e\n```\n\nIf a fixture is already running and you intentionally want to skip lifecycle management, use:\n\n```bash\nINFRA_LENS_E2E_SKIP_FIXTURE=1 pnpm run test:e2e:raw\n```\n\nStart with the [documentation index](./docs/README.md) for usage, client setup, operations, incident workflows, observability, storage, security, governance, testing, and release guidance. Generated API docs live in [docs/api](./docs/api/README.md), and reviewed incident examples live in [examples/incidents](./examples/incidents/README.md).\n\n## Community\n\nUse [SUPPORT.md](./SUPPORT.md) for support channels and response expectations. Active work is tracked in the [infra-lens-mcp Governance project](https://github.com/users/oaslananka/projects/7). Project conduct is defined in [CODE_OF_CONDUCT.md](./CODE_OF_CONDUCT.md), and maintainer triage policy lives in [docs/governance.md](./docs/governance.md).\n\n## Release\n\nReleases are managed through release-please manifest mode and the guarded GitHub Actions release workflow. Implementation PRs must not publish packages, containers, MCP Registry entries, marketplace artifacts, or production GitHub Releases.\n\nSee [docs/release.md](./docs/release.md) and [docs/release-state-machine.md](./docs/release-state-machine.md).\n\n## License\n\n[MIT](./LICENSE)\n\n## Agent plugin and runtime configuration\n\nThis repository owns the product-level agent plugin, MCP runtime configuration, and product-specific skills for `infra-lens-mcp`. The central [`agent-tools`](https://github.com/oaslananka/agent-tools) repository should catalog this plugin, but the manifest and workflow instructions live here so they stay synchronized with the actual MCP server package.\n\n| File | Purpose |\n| --- | --- |\n| [`.claude-plugin/plugin.json`](.claude-plugin/plugin.json) | Claude Code-valid product plugin manifest. |\n| [`.mcp.json`](.mcp.json) | Claude Code project-local MCP server configuration. |\n| [`.codex/config.example.toml`](.codex/config.example.toml) | Codex CLI MCP configuration example. |\n| [`.vscode/mcp.example.json`](.vscode/mcp.example.json) | VS Code / GitHub Copilot workspace MCP configuration example. |\n| [`opencode.example.jsonc`](opencode.example.jsonc) | OpenCode project MCP configuration example. |\n| `.opencode/skills/` | OpenCode-native mirrored skill definitions. |\n| [`docs/agent-runtime-config.md`](docs/agent-runtime-config.md) | Agent runtime setup and validation notes. |\n\nValidate plugin packaging locally:\n\n```bash\nclaude plugin validate .\n```\n\nFor review-first remediation plans, incident drafts, and host/time-window comparisons, see [Incident workflows](./docs/incident-workflows.md).\n",
  "bytes": 15638,
  "sha": "146c138d892c8394056e0510274e950774c894930036b9f748b695862829dc5a",
  "repo_slug": "oaslananka/infra-lens-mcp",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_oaslananka_infra_lens_mcp_9bb3e95a/readme"
}