# Infrawise

> MCP server for deterministic infrastructure analysis. Scans AWS services (DynamoDB, Lambda, SQS, SNS, Secrets Manager, SSM, CloudWatch, EventBridge, S3, API Gateway, RDS, Cognito, Kinesis, MSK, ElastiCache, CloudFront), databases (PostgreSQL, MySQL, MongoDB), Apache Kafka (any broker, via kafkajs or kafka-python/confluent-kafka producer/consumer code detection), application code (TypeScript, JavaScript, and Python AST scanning), and IaC (Terraform, CDK, CloudFormation) to surface findings and correct trigger event shapes — without reading secret values or raw logs.

## Problem it solves

When an AI coding assistant writes a Lambda handler, it doesn't know:
- What tables, queues, or topics the function already accesses
- The correct SQS / SNS / EventBridge trigger event shape for the handler
- Whether a GSI or index exists for a query pattern
- Which secrets are missing rotation or which DLQs are unconfigured
- Whether the Lambda execution role actually allows the services the function calls

Infrawise answers all of these via 22 MCP tools served over Streamable HTTP.

## Docs

- [README](https://github.com/Sidd27/infrawise/blob/main/README.md)
- [MCP tool reference](https://github.com/Sidd27/infrawise/blob/main/AGENTS.md)
- [AI agent instructions](https://github.com/Sidd27/infrawise/blob/main/AGENTS.md)
- release gate: `pnpm check:docs` keeps the version and this MCP tool list in sync with `src/server/index.ts`

## Quick start

```bash
# requires Node.js 22 or later
npm install -g infrawise
cd your-project
infrawise start --claude    # probe env + analyze + write .mcp.json + open Claude Code
# Also: --cursor (.cursor/mcp.json) or --vscode (.vscode/mcp.json, merges with existing servers)
# Every session after: just run "claude" — editor manages the rest
```

For CI/CD (no editor) — gate deploys on findings:
```bash
infrawise check --fail-on high    # exit 1 if any high-severity finding exists
```

For HTTP transport instead of stdio:
```bash
infrawise serve   # start MCP server at http://localhost:3000/mcp
```

Both server transports watch TS/JS and Python saves. After the first code refresh, scanning is incremental: changed files plus transitive TS/JS importers, with deleted operations removed. Saves are batched for two seconds and queued during refreshes; tsconfig changes rebuild the scanner. IaC extraction, graph construction, and analyzers still run in full using cached cloud metadata. No extra flags or configuration; run `infrawise analyze` to re-read infrastructure.

Stdio startup connects and lists tools before loading a snapshot. The first infrastructure tool call loads the 24-hour cache, or waits for a shared initial analysis if it is missing or expired. File watching begins after that load. Run `infrawise start` before opening the editor to prepare the cache. HTTP `serve` still loads before listening.

## MCP tools (22 total)

All tools are read-only (annotated `readOnlyHint: true`) and answer from the analysis snapshot, initialized on first use in stdio mode.

- `get_infra_overview` — full snapshot of all infrastructure, start here
- every response carries `dataHealth`: when the infra was read, per-source status, cdk.out synth state, and how to refresh
- every resource-state tool takes an optional `maxAgeSeconds`; it is advisory — the answer reports whether it met it and returns the data either way
- a running server rechecks the cache on every tool call, so a fresh `infrawise analyze` reaches the next call; no restart needed
- `dataHealth.suggestRefresh` flips past 6h by default, tunable via `freshness.suggestRefreshAfterHours` in infrawise.yaml — see https://sidd27.github.io/infrawise/guides/how-infrawise-handles-staleness/ for what age does and does not tell you
- `get_graph_summary` — complete graph: all nodes, edges, findings
- `get_table_schema` — column-level schema for named tables/collections: types, primary keys, foreign keys, indexes, DynamoDB keys/billing mode/cost signal (never row data)
- `analyze_function` — per-function analysis with trigger event shapes and missing IAM permissions, one match per file defining that name; optional `file` binds the answer to a single file (exact path or a trailing fragment on a segment boundary, so a bare `orders.ts` works), and while several files match, `accesses` is absent from every entry rather than empty; `unresolvedLambdas` names each Lambda refused a link to this function and why
- `suggest_gsi` — ready-to-use DynamoDB GSI definition
- `postgres_index_suggestions` — exact CREATE INDEX CONCURRENTLY SQL
- `suggest_mongo_index` — exact db.collection.createIndex command
- `mysql_index_suggestions` — exact ALTER TABLE ADD INDEX SQL
- `get_queue_details` — SQS queues with DLQ, encryption, FIFO type, and visibility timeout
- `get_topic_details` — SNS topics with subscription count and filter policies (required message attributes)
- `get_secrets_overview` — Secrets Manager rotation status + key names inferred from code (no values)
- `get_parameter_overview` — SSM parameter names and types (no values)
- `get_lambda_overview` — Lambda config, memory, timeout, execution role ARN, trigger event shapes, cost signal; `unresolvedLink` records why a Lambda was not linked to a source function (`no_match`, `multiple_functions`, `multiple_lambdas`) instead of linking nothing silently
- `get_eventbridge_details` — EventBridge rules, schedules, target functions
- `get_s3_overview` — S3 buckets, versioning, encryption, public access status
- `get_log_errors` — log group names and retention; errorCount null, patterns empty, errorsObserved false; message bodies never requested
- `get_api_routes` — API Gateway APIs (REST, HTTP, WebSocket) with routes, methods, and Lambda integrations
- `get_stack_outputs` — stack outputs and cross-stack exports from local IaC files (Terraform outputs, CFN/CDK Outputs), with per-stack staleness flags for orphaned cdk.out templates
- `get_cognito_overview` — Cognito user pools and app client config: auth flows, OAuth settings, token validity (secrets never included)
- `get_stream_details` — Kinesis streams (shards, retention, capacity mode) and MSK clusters (state, Kafka version, brokers)
- `get_cache_overview` — ElastiCache clusters: engine, encryption, replication, failover, cost signal (cached data never read)
- `get_cloudfront_overview` — CloudFront distributions: per-behavior path patterns, origins (S3 vs custom, resolved API Gateway name), cache policy, viewer protocol policy

## Works with

Claude Code, Cursor, VS Code (Copilot agent mode), and any MCP-compatible client.

## What infrawise never does

- Never reads secret values or parameter values
- Never reads raw log messages
- Never writes to AWS or your database
- Never executes DDL
- No telemetry — everything stays local

## Confidence and operations

CI: exit 0 = complete, below threshold; exit 1 = blocking findings; exit 2 = incomplete extraction or analyzer failures. Failed/partial sources block unless --allow-incomplete is explicit. --severity filters analyze output only.

get_table_schema includes relational index columns in key order, method, partial, and valid. SQL index findings compare supported filters against leading columns; they are not observed query plans. Partial/expression indexes and unsupported predicates require manual EXPLAIN verification.

dataHealth.codeCoverage reports recognized patterns only, with unresolved-reference and unsupported-SQL counts. get_graph_summary includes unresolvedReferences. Wrappers and dynamic code can still be missed; missing edges are not proof of no access.

freshness.refreshIntervalMinutes optionally runs serialized full background analysis after snapshot loading (1–1440 minutes; off by default). It bounds age, not drift. Run infrawise analyze after deployments for an immediate refresh. Config changes require restart.

get_log_errors is metadata only: errorCount null, topErrorPatterns empty, errorsObserved false. Log message bodies are never requested. Old caches are invalidated.

Assistant workflow: docs/assistant-workflow.md. Evaluate recorded editor runs: pnpm eval:assistant traces.json (evals/README.md). Performance/equivalence checks: pnpm benchmark (benchmarks/README.md). Synthetic controls are not actual model-quality measurements.

analyze_function found:false means no recognized graph node, not proof the source function does not exist. dataHealth.codeCoverage.refreshError exposes a failed session refresh while retaining the previous snapshot.

Incomplete runtime metric reads are recorded in source health and block `check` by default; they are not interpreted as zero activity.

Repeatable database/MCP regression: pnpm test:demo (after seeding demo/local); add --background for the one-minute refresh test.
