{"_id":"@aws/durable-execution-sdk-js-insight-mcp","name":"@aws/durable-execution-sdk-js-insight-mcp","dist-tags":{"beta":"0.1.0-alpha.0","latest":"0.1.0-alpha.0"},"versions":{"0.1.0-alpha.0":{"name":"@aws/durable-execution-sdk-js-insight-mcp","version":"0.1.0-alpha.0","license":"Apache-2.0","private":false,"repository":{"type":"git","url":"git+ssh://git@github.com/aws/aws-durable-execution-sdk-js.git","directory":"packages/aws-durable-execution-sdk-js-insight-mcp"},"engines":{"node":">=20"},"bin":{"durable-insight-mcp":"dist/server.js"},"scripts":{"typecheck":"tsc --noEmit","test":"npm run build && jest","build":"node esbuild.mjs"},"dependencies":{"@modelcontextprotocol/sdk":"^1.30.0","zod":"^4.4.3"},"devDependencies":{"@types/jest":"^29.5.0","esbuild":"^0.24.0","jest":"^29.7.0","ts-jest":"^29.2.0","typescript":"~5.8.0","@aws/durable-execution-sdk-js-insight-core":"0.1.0-alpha.0"},"jest":{"preset":"ts-jest","testEnvironment":"node","testMatch":["**/src/**/*.test.ts"],"transform":{"^.+\\.ts$":["ts-jest",{"tsconfig":"tsconfig.test.json"}]}},"_id":"@aws/durable-execution-sdk-js-insight-mcp@0.1.0-alpha.0","gitHead":"eb252ca0c58ef0f45efbfb030c56b04878b0229e","description":"Query the execution history that AWS Lambda durable functions emit, from any MCP client, over stdio.","bugs":{"url":"https://github.com/aws/aws-durable-execution-sdk-js/issues"},"homepage":"https://github.com/aws/aws-durable-execution-sdk-js#readme","_nodeVersion":"22.22.3","_npmVersion":"10.9.8","dist":{"integrity":"sha512-BmAhZT+TXHacwqppaxNCgK6Vg4kEZjSgGPwUnrQiRhkjc+0AIjZktrSGK/B5py1GQNtjnzgfqZN4H0w5xnDTJA==","shasum":"bf36df03701c957056b05176d2439ebd5e73c524","tarball":"https://registry.npmjs.org/@aws/durable-execution-sdk-js-insight-mcp/-/durable-execution-sdk-js-insight-mcp-0.1.0-alpha.0.tgz","fileCount":6,"unpackedSize":8189616,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIAIsU6L6Os5cR3/QZ52F1+u2nWghCcPkuwZ8ktLwTBbnAiASKx2qk4Xy9STHvCPu7u2Jc1NV1rWmKiJjB27RROAdsg=="}]},"_npmUser":{"name":"durable-execution-dev","email":"durable-execution-dev@amazon.com"},"directories":{},"maintainers":[{"name":"durable-execution-dev","email":"durable-execution-dev@amazon.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/durable-execution-sdk-js-insight-mcp_0.1.0-alpha.0_1786403390410_0.2774824896739432"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-10T23:09:50.259Z","0.1.0-alpha.0":"2026-08-10T23:09:50.577Z","modified":"2026-08-10T23:09:50.796Z"},"maintainers":[{"name":"durable-execution-dev","email":"durable-execution-dev@amazon.com"}],"description":"Query the execution history that AWS Lambda durable functions emit, from any MCP client, over stdio.","homepage":"https://github.com/aws/aws-durable-execution-sdk-js#readme","repository":{"type":"git","url":"git+ssh://git@github.com/aws/aws-durable-execution-sdk-js.git","directory":"packages/aws-durable-execution-sdk-js-insight-mcp"},"bugs":{"url":"https://github.com/aws/aws-durable-execution-sdk-js/issues"},"license":"Apache-2.0","readme":"# Workflow Insight — MCP Server\n\nQuery the execution history that AWS Lambda durable functions emit, from any MCP\nclient, over stdio.\n\nThis package is a **host adapter, not a second product**. It exposes the same\nread-only query capability the VS Code extension and desktop app provide —\ndestination resolution, query engines, read-only enforcement — but through the\n[Model Context Protocol](https://modelcontextprotocol.io) instead of a UI. The\nengine runners, the `assertReadOnly` validator, and the per-destination schema\nguidance all come from `durable-insight-core`; nothing is forked here, so the\nhosts cannot drift.\n\nConcretely, this server is **stdio in, JSON out, on your machine**. It reads a\nquery request from the agent driving it, runs it against the one destination it\nwas configured for, and returns machine-readable JSON. It makes no model calls\nof its own (see [Data handling and AI disclosure](#data-handling-and-ai-disclosure)).\n\n## Install\n\nThe package is published; you never clone or build it. Every client launches it\nthe same way — `npx -y @aws/durable-execution-sdk-js-insight-mcp` — and every client takes the\nsame `mcpServers` JSON shape. Only the file the config lives in differs.\n\n**Lead with the CLI helper for your client.** The config-file paths below move\nbetween client versions; the server shape does not, so a helper that writes the\nfile for you is the durable instruction.\n\n### Kiro\n\n```bash\nkiro-cli mcp add \\\n  --name durable-insight \\\n  --command npx \\\n  --args \"-y,@aws/durable-execution-sdk-js-insight-mcp\" \\\n  --env DURABLE_INSIGHT_DESTINATION_TYPE=dynamodb \\\n  --env DURABLE_INSIGHT_DYNAMODB_TABLE_NAME=my-workflow-table \\\n  --env DURABLE_INSIGHT_REGION=us-east-1 \\\n  --scope workspace\n```\n\n`--scope workspace` writes `.kiro/settings/mcp.json`; omit it (or use\n`--scope global`) to write `~/.kiro/settings/mcp.json`. Workspace scope wins when\nboth are present.\n\n### Claude Code\n\n```bash\nclaude mcp add durable-insight \\\n  --scope project \\\n  --env DURABLE_INSIGHT_DESTINATION_TYPE=dynamodb \\\n  --env DURABLE_INSIGHT_DYNAMODB_TABLE_NAME=my-workflow-table \\\n  --env DURABLE_INSIGHT_REGION=us-east-1 \\\n  -- npx -y @aws/durable-execution-sdk-js-insight-mcp\n```\n\n`--scope project` writes `.mcp.json` at the repo root; the default (user) scope\nwrites `~/.claude.json`. Project scope wins when both are present.\n\n### JSON reference (all clients)\n\nIf you prefer to edit the file directly, or your client has no helper, add this\nblock. The shape is identical everywhere:\n\n```json\n{\n  \"mcpServers\": {\n    \"durable-insight\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@aws/durable-execution-sdk-js-insight-mcp\"],\n      \"env\": {\n        \"DURABLE_INSIGHT_DESTINATION_TYPE\": \"dynamodb\",\n        \"DURABLE_INSIGHT_DYNAMODB_TABLE_NAME\": \"my-workflow-table\",\n        \"DURABLE_INSIGHT_REGION\": \"us-east-1\"\n      }\n    }\n  }\n}\n```\n\nWhere that block lives, per client:\n\n| Client      | Project scope (wins)      | User scope                  |\n| ----------- | ------------------------- | --------------------------- |\n| Kiro        | `.kiro/settings/mcp.json` | `~/.kiro/settings/mcp.json` |\n| Claude Code | `.mcp.json` (repo root)   | `~/.claude.json`            |\n| Cursor      | `.cursor/mcp.json`        | `~/.cursor/mcp.json`        |\n\n> **Project scope is a committed file.** Adding the server at project scope\n> (`.kiro/settings/mcp.json`, `.mcp.json`, `.cursor/mcp.json`) shares it — and\n> the destination it points at — with everyone who checks out the repo. Use user\n> scope if the destination is yours alone.\n\n## Configuration\n\nConfiguration is **environment-only** — there is no settings file and no mutable\nstate. Every knob is an environment variable named `DURABLE_INSIGHT_` + the\nSCREAMING_SNAKE form of its setting key (`athenaDatabase` →\n`DURABLE_INSIGHT_ATHENA_DATABASE`). Set them in the `env` block above.\n\nTwo standard AWS variables are honored as fallbacks when their prefixed form is\nunset: `AWS_REGION` fills in `DURABLE_INSIGHT_REGION`, and `AWS_PROFILE` fills in\n`DURABLE_INSIGHT_AWS_PROFILE`. The prefixed form wins when both are set. Region\nfalls back further to `AWS_DEFAULT_REGION`, then defaults to `us-east-1`.\n\n**Credentials need no configuration.** They come from the standard AWS SDK\nprovider chain — environment variables, `~/.aws/credentials`, SSO — honoring\n`DURABLE_INSIGHT_AWS_PROFILE` (or `AWS_PROFILE`) when set. The identity you use\nneeds read access to whichever destination you point at.\n\n### Destinations and their required variables\n\n`DURABLE_INSIGHT_DESTINATION_TYPE` selects the backend. Seven destination types\nare **queryable**; each requires the variables below (anything not listed has a\nworking default, shown in parentheses). If `DURABLE_INSIGHT_DESTINATION_TYPE` is\nunset it defaults to `cloudwatch-logs-exporter`. A value that is **set but not\nrecognized** (a typo such as `dynamo`, or wrong casing such as `DynamoDB`) also\nfalls back to that default, so the server warns on startup and names the valid\nvalues — otherwise it would report a CloudWatch variable as missing to someone who\nhad configured DynamoDB correctly.\n\n| `DURABLE_INSIGHT_DESTINATION_TYPE` | Required variables                                                                                                              | Notable defaults                                                                                                                                                                                                                      |\n| ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `dynamodb`                         | `DURABLE_INSIGHT_DYNAMODB_TABLE_NAME`                                                                                           | —                                                                                                                                                                                                                                     |\n| `s3` (Athena)                      | `DURABLE_INSIGHT_ATHENA_DATABASE`, **and** one of `DURABLE_INSIGHT_ATHENA_WORKGROUP` / `DURABLE_INSIGHT_ATHENA_OUTPUT_LOCATION` | `DURABLE_INSIGHT_ATHENA_TABLE` (`workflow_insight`)                                                                                                                                                                                   |\n| `aurora`                           | `DURABLE_INSIGHT_AURORA_RESOURCE_ARN`, `DURABLE_INSIGHT_AURORA_SECRET_ARN`                                                      | `DURABLE_INSIGHT_AURORA_DATABASE` (`postgres`), `DURABLE_INSIGHT_AURORA_TABLE` (`workflow_insight`)                                                                                                                                   |\n| `redshift`                         | one of `DURABLE_INSIGHT_REDSHIFT_WORKGROUP_NAME` / `DURABLE_INSIGHT_REDSHIFT_CLUSTER_IDENTIFIER`                                | `DURABLE_INSIGHT_REDSHIFT_DATABASE` (`dev`), `DURABLE_INSIGHT_REDSHIFT_TABLE` (`workflow_insight`), `DURABLE_INSIGHT_REDSHIFT_SCHEMA` (`public`); `DURABLE_INSIGHT_REDSHIFT_SECRET_ARN` / `DURABLE_INSIGHT_REDSHIFT_DB_USER` optional |\n| `opensearch`                       | `DURABLE_INSIGHT_OPENSEARCH_ENDPOINT`                                                                                           | `DURABLE_INSIGHT_OPENSEARCH_INDEX` (`workflow-insight`)                                                                                                                                                                               |\n| `cloudwatch-logs-exporter`         | `DURABLE_INSIGHT_LOG_GROUP_NAME` (comma-separated for multiple)                                                                 | —                                                                                                                                                                                                                                     |\n| `lambda-log-exporter`              | `DURABLE_INSIGHT_LOG_GROUP_NAME` (comma-separated for multiple)                                                                 | —                                                                                                                                                                                                                                     |\n\nFor Athena, note that `DURABLE_INSIGHT_ATHENA_S3_LOCATION` is **not** required:\nthat is the source-data location used only to create the table, which this server\nnever does. What it needs is somewhere to write query _results_ — a workgroup\nwith an output location configured, or an explicit\n`DURABLE_INSIGHT_ATHENA_OUTPUT_LOCATION`.\n\n`sqs` is **not queryable.** It is a tail-only destination — a message queue this\nserver can only long-poll, with no query engine behind it — so `query`,\n`get_execution`, and `list_executions` refuse it with an explanatory error rather\nthan pretend. Do not configure `sqs` for use with this server.\n\n## The tools\n\nThe server registers five tools. Call them roughly in this order.\n\n- **`test_destination`** — Run first. Read-only connectivity and completeness\n  checks against the configured destination. If required variables are unset it\n  names them and returns _without any AWS call_. Stop and fix if it reports a\n  problem.\n- **`describe_schema`** — **Call this before writing a `query`.** Returns the\n  configured destination's record schema, query engine/dialect, the table or log\n  group in play, and the row cap — sourced from the SDK for whatever destination\n  is actually configured. It makes no AWS call, so it is safe even before setup\n  is complete. Writing a query without it is guessing: field names, column\n  casing, and quoting genuinely differ across DynamoDB (PartiQL), Athena, Aurora,\n  Redshift, OpenSearch, and CloudWatch Logs.\n- **`list_executions`** — The common case. List execution records filtered by any\n  of `status`, `functionName`, `since`, and `until`, with a bounded `limit` — no\n  query language required. **Prefer this over a hand-written `query`:** it cannot\n  be got wrong and costs fewer tokens. Reach for `query` only when a question\n  cannot be expressed through these filters. On log destinations the scanned window\n  follows `since`, so filtering to last week scans last week.\n- **`get_execution`** — Fetch a single execution record by its execution ARN. A\n  record that does not exist is a success with `found: false`, not an error. For\n  the Athena/`s3` destination you may also pass `year`/`month`/`day` to prune to\n  one partition instead of scanning the whole table.\n- **`query`** — The escape hatch. Execute a single read-only query against the\n  destination. For the SQL destinations (`dynamodb`, `s3`, `aurora`, `redshift`,\n  `opensearch`) only `SELECT`/`WITH` is accepted; any data-modifying or DDL\n  statement is refused before any AWS call. For the CloudWatch Logs destinations\n  (`cloudwatch-logs-exporter`, `lambda-log-exporter`) pass a CloudWatch Logs\n  Insights pipe query, not SQL, and use `lookbackHours` to set the time window.\n\n### Result bounding\n\n- **Row cap.** Every result from every destination is capped at **1000 rows**\n  (`MAX_ROWS`). Pass a smaller `limit` when you only need a few rows: it is honored,\n  and rows you did not want still cost tokens to read. `limit` cannot raise the cap.\n- **`truncated` means \"there may be more matching data than this.\"** It does not\n  mean the returned array was trimmed. Reaching the cap sets it; on DynamoDB a\n  response that hit the service's ~1 MB limit also sets it, which can happen far\n  below 1000 rows. Either way, narrow your filters rather than assuming you saw\n  everything.\n- **Log lookback window.** CloudWatch Logs Insights has no \"all time\"; a query must\n  carry an explicit `[start, end]` window, and that window is separate from any\n  filtering inside the query. All three tools report the window they scanned as\n  `searchedLookbackHours`, because a window narrower than your filters ask for returns\n  a partial answer that otherwise looks complete.\n  - `list_executions` **derives the window from `since`**, so filtering to last week\n    scans last week. Pass `lookbackHours` to widen a search that has no `since`.\n  - `query` defaults to the **last 24 hours**, `get_execution` to the **last 7 days**;\n    both accept `lookbackHours`.\n  - A `found: false` from `get_execution` therefore means \"not in that window\", not\n    \"does not exist\".\n  - This window is ignored by the SQL destinations, which are not time-windowed.\n\n## Prompts\n\nThe server ships two MCP prompts, so no separate install is needed — a client\nsuch as Kiro surfaces them under `/prompts` and `@name`, Claude Code as slash\ncommands. Each encodes the correct _order of operations_ (verify, describe\nschema, narrow, drill in) and defers all schema facts to `describe_schema` at\nruntime.\n\n- **`investigate_workflow_failure`** — Guided, correct-order investigation of a\n  durable function failure. Accepts optional `functionName` and `lookbackHours`\n  to scope the search.\n- **`explore_recent_executions`** — Guided overview of recent executions. Accepts\n  an optional `status` filter.\n\n## Skill\n\n`SKILL.md` (shipped in the package under `src/skill/`) is a progressively-loaded\nskill that teaches an agent the one rule that keeps its queries correct: ask the\nserver for the schema with `describe_schema` before writing a `query`. It\ncontains zero destination-specific schema facts on purpose, so it can never drift\nfrom the server.\n\nFor a client that supports skills, install it by placing the file where the\nclient looks for skills and referencing it from an agent. In Kiro, drop it under\n`.kiro/skills/` and let an agent load it via a `skill://` entry in that agent's\n`resources`, for example:\n\n```json\n{\n  \"resources\": [\"skill://.kiro/skills/**/SKILL.md\"]\n}\n```\n\nCustom Kiro agents inherit workspace skills by default, so a file under\n`.kiro/skills/` is typically picked up without any config change.\n\n## Settings this host does not accept\n\nThis host takes its model from the **agent** that drives it — the agent already\nhas an LLM — so eight provider/model/agent-loop settings that the VS Code\nextension and desktop app accept are deliberately ignored here. There is no\nprovider to choose, no local model to run, no agent loop of its own, and no\nAI-usage consent for it to record (that relationship belongs to the agent's own\nhost):\n\n- `llmProvider`\n- `bedrockModelId`\n- `localModel`\n- `localServerUrl`\n- `localServerModel`\n- `agenticMaxIterations`\n- `queryMode`\n- `aiDisclosureAcceptedVersion`\n\nIf you set the corresponding environment variable anyway (for instance, copied\nfrom VS Code settings), the server does not fail — it starts and emits a warning\nthat the variable is ignored.\n\n## Data handling and AI disclosure\n\nRead this before pointing the server at production data.\n\n- **Execution records carry `input` and `output` payloads, and this server\n  returns them verbatim** — not redacted, not summarized, not filtered. The\n  `get_execution`, `list_executions`, and `query` tools all return record data,\n  and `get_execution` and `query` can surface the full `input` and `output`\n  payloads of an execution. In plain terms: asking your agent to \"query my\n  workflow data\" means the production payloads your workflows process — whatever\n  that data is — enter the agent's context, and therefore the model behind it.\n- **Where the data goes is determined by the customer, not by this server.** Data\n  flows to the agent that requested it, and from there wherever that agent's own\n  configuration sends it (its model provider, its logs, its storage). This server\n  chooses none of that and cannot see past its own stdout.\n- **This server makes no model calls of its own.** It selects no model provider\n  and contacts none. It is stdio in, JSON out, running on your machine; the only\n  outbound calls it makes are the read-only AWS API calls needed to run your\n  query.\n- **Every query is read-only; the server cannot modify your data.** On the SQL\n  destinations any statement that is not `SELECT`/`WITH` is refused before a\n  single AWS call is made. On the CloudWatch Logs destinations the Logs Insights\n  query language has no write or DDL forms at all, and the only API used can only\n  read. There is no code path through this server that mutates the customer's\n  data.\n\nInstalling this server into an agent you chose is itself the opt-in; there is no\nseparate consent gate, acceptance flag, or version to accept.\n\n## Troubleshooting\n\n- **`test_destination` reports missing configuration.** When required variables\n  are unset, `test_destination` returns a successful result with `ok: false` and\n  a `missingEnvVars` array **naming the exact `DURABLE_INSIGHT_*` variables** that\n  are unset — it does not guess and does not call AWS. Set the named variables in\n  your client's `env` block and re-run it.\n- **The server starts even when misconfigured — on purpose.** Missing destination\n  configuration is not a startup error. A server that refused to launch would\n  surface in an MCP client as an unexplained failure; one that starts can tell\n  the agent, through `test_destination`, exactly what is wrong. So if tools are\n  listed but queries report incomplete config, run `test_destination` first — it\n  is the diagnostic.\n- **A query is refused as not read-only.** That is the security boundary working:\n  only `SELECT`/`WITH` reaches an AWS call on the SQL destinations. Rephrase as a\n  read.\n- **`query` against `sqs` errors out.** Expected — `sqs` is tail-only and has no\n  query engine. Point the server at a queryable destination.\n\n## From zero to a confirmed connection\n\nA complete path for a new user, using DynamoDB as the example:\n\n1. Have AWS credentials available to the standard SDK chain (an exported\n   `AWS_PROFILE`, `~/.aws/credentials`, or SSO) with read access to the table.\n2. Add the server to your client with the destination variables set — use the\n   [Kiro](#kiro) or [Claude Code](#claude-code) helper above, substituting your\n   real table name and region. Nothing to install: `npx -y` fetches the package.\n3. Restart / reload your client so it launches the server.\n4. Ask the agent to run **`test_destination`**. A result with `ok: true` confirms\n   the connection. If it returns `missingEnvVars`, set those exact variables and\n   repeat step 4.\n5. Then run **`describe_schema`**, and start querying with **`list_executions`**.\n","readmeFilename":"README.md","_rev":"1-b6820ee0ef9f3fd52f9551d0bf62ad30"}