.vscode — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited .vscode (MCP Server) and scored it 91/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 1 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 1 flagged
The text {match} is the classic direct prompt-injection phrasing. Placed in a skill body that the agent reads as trusted instructions, it tries to make the agent abandon its prior rules and follow whatever comes next — a full system-prompt override.
ignore/disregard/forget … previous instructions sentence.Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
<p align="center"> <strong>Read-only <a href="https://modelcontextprotocol.io">MCP</a> server for Amazon DynamoDB</strong><br> Safe exploration, querying, and schema discovery from your AI coding assistant. </p>
<p align="center"> <a href="https://pypi.org/project/ddb-explorer-mcp/"><img src="https://img.shields.io/pypi/v/ddb-explorer-mcp.svg" alt="PyPI"></a> <a href="https://pypi.org/project/ddb-explorer-mcp/"><img src="https://img.shields.io/pypi/pyversions/ddb-explorer-mcp.svg" alt="Python"></a> <a href="https://pypi.org/project/ddb-explorer-mcp/"><img src="https://img.shields.io/pypi/dm/ddb-explorer-mcp.svg" alt="Downloads"></a> <a href="https://github.com/mudassirgithub/ddb-explorer-mcp/actions/workflows/ci.yml"><img src="https://github.com/mudassirgithub/ddb-explorer-mcp/actions/workflows/ci.yml/badge.svg" alt="CI"></a> <a href="https://github.com/mudassirgithub/ddb-explorer-mcp/pkgs/container/ddb-explorer-mcp"><img src="https://img.shields.io/badge/GHCR-image-blue?logo=docker" alt="Docker"></a> <a href="LICENSE"><img src="https://img.shields.io/badge/License-Apache_2.0-blue.svg" alt="License: Apache-2.0"></a> <a href="https://smithery.ai/server/ddb-explorer-mcp"><img src="https://smithery.ai/badge/ddb-explorer-mcp" alt="Smithery"></a> </p>
Add ddb-explorer-mcp to your IDE in one click:
<img src="https://cursor.com/deeplink/mcp-install-dark.svg" alt="Install in Cursor" height="32"> <img src="https://img.shields.io/badge/VS_Code-Install_MCP-007ACC?logo=visual-studio-code&logoColor=white" alt="Install in VS Code" height="32"> <img src="https://img.shields.io/badge/Smithery-Install-orange" alt="Install via Smithery" height="32">
Or install from the command line:
# Smithery (auto-configures your client)
npx -y @smithery/cli install ddb-explorer-mcp --client cursor
# Claude Code CLI
claude mcp add ddb-explorer -- uvx ddb-explorer-mcp
# npm wrapper (delegates to uvx under the hood)
npx ddb-explorer-mcpWrite operations are structurally not exposed. The LLM cannot call PutItem, UpdateItem, DeleteItem, BatchWriteItem, TransactWriteItems, CreateTable, DeleteTable, or UpdateTable because those tools are not registered with the server. Not a config flag — they physically do not exist in the tool namespace.
| Safe by construction | Read-only tool surface; no writes possible |
| Eight practical tools | list / describe / get / batch-get / query / scan + schema discovery helpers |
| Two transports | stdio (local) or streamable-HTTP (hosted) |
| Works everywhere | Cursor, Claude Desktop, VS Code, Windsurf, Zed, Claude Code CLI, any MCP client |
| Standard AWS creds | Env vars, profiles, SSO, IMDS all just work |
| Guardrails for scans | Default max_pages=1, hard caps on limits (all configurable via env vars), auto-pagination for query |
| Smart batch ops | batch_get_item auto-chunks into 100s and retries UnprocessedKeys |
| JSON-clean output | Decimal, set, bytes coerced to JSON-native types |
uvx ddb-explorer-mcpThat's it. uv downloads, caches, and runs the server in an isolated environment on first use.
Clone the repo and the MCP server auto-registers in Cursor and VS Code:
git clone https://github.com/mudassirgithub/ddb-explorer-mcp.git
cd ddb-explorer-mcp
make setup # installs Python + all dependencies via uvOpen the cloned folder in your IDE:
.cursor/mcp.json automatically. Restart Cursor, thencheck Settings → Tools & MCP. The server appears as ddb-explorer.
.vscode/mcp.json automatically (native MCP support inVS Code 1.99+). No extension required.
claude mcp add ddb-explorer -- uv run --directory /path/to/ddb-explorer-mcp ddb-explorer-mcpexamples/cursor-local.json and replace the path with your clone directory.
Edit AWS_REGION / AWS_PROFILE in the relevant MCP config to match your environment. Changes to the Python source are picked up on the next server restart — no reinstall needed.
#### Makefile targets
| Target | What it does |
|---|---|
make setup | Install Python + dependencies via uv sync |
make run | Start the server in stdio mode |
make run-http | Start the server in HTTP mode on localhost:8765 |
make test | Run the test suite (uses moto — no real AWS creds needed) |
make lint | Lint with ruff |
make format | Auto-format with ruff |
make check | Run lint + format-check + tests (same as CI) |
make clean | Remove build/cache artifacts |
docker run --rm -p 8765:8765 \
-e MCP_TRANSPORT=http \
-e MCP_HOST=0.0.0.0 \
-e AWS_REGION=us-east-2 \
-e AWS_ACCESS_KEY_ID=... \
-e AWS_SECRET_ACCESS_KEY=... \
ghcr.io/mudassirgithub/ddb-explorer-mcp:latestSee HTTP deployment below.
Ready-to-paste configs are also available in the examples/ directory.
Add to ~/.cursor/mcp.json (global) or .cursor/mcp.json (per-project):
{
"mcpServers": {
"ddb-explorer": {
"command": "uvx",
"args": ["ddb-explorer-mcp"],
"env": {
"AWS_PROFILE": "default",
"AWS_REGION": "us-east-2"
}
}
}
}Restart Cursor (⌘Q on macOS). Open Settings → Tools & MCP to verify.
Add to ~/Library/Application Support/Claude/claude_desktop_config.json (macOS):
{
"mcpServers": {
"ddb-explorer": {
"command": "uvx",
"args": ["ddb-explorer-mcp"],
"env": {
"AWS_PROFILE": "default",
"AWS_REGION": "us-east-2"
}
}
}
}claude mcp add ddb-explorer \
--env AWS_PROFILE=default \
--env AWS_REGION=us-east-2 \
-- uvx ddb-explorer-mcpAdd to your VS Code settings.json:
{
"mcp": {
"servers": {
"ddb-explorer": {
"command": "uvx",
"args": ["ddb-explorer-mcp"],
"env": {
"AWS_PROFILE": "default",
"AWS_REGION": "us-east-2"
}
}
}
}
}Add to ~/.codeium/windsurf/mcp_config.json:
{
"mcpServers": {
"ddb-explorer": {
"command": "uvx",
"args": ["ddb-explorer-mcp"],
"env": {
"AWS_PROFILE": "default",
"AWS_REGION": "us-east-2"
}
}
}
}{
"mcpServers": {
"ddb-explorer": {
"type": "streamableHttp",
"url": "https://ddb-explorer.example.com/mcp",
"headers": {
"Authorization": "Bearer <your-token>"
}
}
}
}| Tool | Purpose |
|---|---|
list_tables(name_contains?) | List tables in the region, optionally filtered by substring |
describe_table(table_name) | Full description: keys, attrs, GSIs, LSIs, TTL, item count, size |
get_indexes(table_name) | Trimmed view — just the secondary indexes |
sample_items(table_name, n?) | Fetch a few items to discover the schemaless attribute shape |
get_item(table_name, key, consistent_read?) | Single-item read by primary key |
batch_get_item(table_name, keys[], consistent_read?) | Many items by PK, auto-chunked into 100s, retries UnprocessedKeys |
query(table_name, key_condition_expression, expression_attribute_values, ...) | Query base table or GSI/LSI with full DynamoDB expression syntax |
scan(table_name, filter_expression?, max_pages?, ...) | Scan with safe pagination caps (default max_pages=1, hard cap 20) |
"List all tables with order in the name and describe the newest one.""Queryprod-orderswhereuser_id = 'U123'andcreated_at > '2026-01-01', using theby_user_createdGSI, limit 20."
"Sample 5 items from prod-events and tell me which attributes are always present.""Compare the schemas ofprod-ordersandstaging-orders— are there attributes in one that don't exist in the other?"
See examples/PROMPTS.md for more.
All configuration is via environment variables.
The server uses the standard boto3 credential resolution chain. The first valid source wins:
AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY (+ optional AWS_SESSION_TOKEN) env varsAWS_PROFILE pointing to a profile in ~/.aws/credentials or ~/.aws/config| Variable | Default | Purpose |
|---|---|---|
AWS_REGION | us-east-2 | DynamoDB region |
AWS_DEFAULT_REGION | — | Fallback for region |
AWS_PROFILE | — | Named profile to use |
AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY / AWS_SESSION_TOKEN | — | Explicit credentials |
| Variable | Default | Purpose | ||
|---|---|---|---|---|
MCP_TRANSPORT | stdio | stdio \ | http \ | sse |
MCP_HOST | 127.0.0.1 | HTTP bind host (use 0.0.0.0 to expose) | ||
MCP_PORT | 8765 | HTTP bind port |
All tool safety caps are configurable via environment variables. Defaults match the original hardcoded values — existing deployments are unaffected unless you explicitly override them.
| Variable | Default | Purpose | Cost / data implications |
|---|---|---|---|
DDB_SCAN_MAX_LIMIT | 500 | Hard cap on items per scan page | Most impactful. Scans read every item in the table. On large prod tables (millions of items), high limits burn RCUs and can return sensitive data into the LLM context. Consider 50–100 for production. |
DDB_SCAN_DEFAULT_LIMIT | 50 | Default items per scan page (when caller omits limit) | Safety net — keeps casual/unparameterized scans small. |
DDB_SCAN_MAX_PAGES | 20 | Hard cap on pages per scan call | Combined with SCAN_MAX_LIMIT, this controls the maximum blast radius of a single scan. 20 pages × 500 items = 10,000 items worst case. Lower to 3–5 on production. |
DDB_SCAN_DEFAULT_MAX_PAGES | 1 | Default pages per scan (when caller omits max_pages) | Keep this at `1` for production. This single setting prevents the LLM from accidentally walking an entire table. |
DDB_QUERY_MAX_LIMIT | 500 | Hard cap on items per query | Queries are targeted (use a partition key), so cost is lower than scans. But a hot partition could still have thousands of items. 100–200 is safer for production. |
DDB_QUERY_DEFAULT_LIMIT | 50 | Default items per query | Safety net for unparameterized queries. |
DDB_SAMPLE_MAX_N | 20 | Max items returned by sample_items | Low risk — this is a schema discovery tool. Even at 20, cost is negligible. |
DDB_BATCH_CHUNK_SIZE | 100 | Keys per BatchGetItem API call | Matches the DynamoDB service maximum. Lowering this adds round-trips without saving cost. Leave at 100 unless you need to reduce per-request throughput spikes on provisioned tables. |
DDB_BATCH_MAX_RETRIES | 10 | Max retries for UnprocessedKeys | Only relevant under throttling. On provisioned-capacity tables, aggressive retries can amplify throttle pressure. On on-demand tables, this rarely triggers. |
DDB_SHOW_COST | false | When true, each data-plane tool response includes a consumed_capacity field with exact RCUs reported by DynamoDB | Zero overhead when disabled. When enabled, uses DynamoDB's native ReturnConsumedCapacity — no extra API calls, no estimation. Covers get_item, batch_get_item, query, scan, and sample_items. Control-plane tools (list_tables, describe_table, get_indexes) are always free and never report capacity. |
DDB_MAX_ITEMS_PER_SESSION | 0 (unlimited) | Cumulative cap on total items returned across all tool calls in a server session | Prevents data exfiltration by bounding how much data can be extracted before a server restart. Set to 500–2000 for production. Once exceeded, all data-plane calls return an error until the server is restarted. |
DDB_MAX_CALLS_PER_MINUTE | 0 (unlimited) | Max tool calls allowed per rolling 60-second window | Prevents rapid-fire automated extraction. Applies to all 8 tools. Rejected calls return a RateLimitExceeded error. Set to 30–60 for production. |
DDB_AUDIT_LOG | false | When true, every tool call is logged to stderr with timestamp, tool name, table, and item count | Enables post-incident investigation and real-time monitoring. Logs go to stderr so they don't interfere with MCP's stdio transport. Pair with a log aggregator in HTTP mode. |
DDB_ALLOWED_TABLES | (empty = all) | Comma-separated list of allowed table names/patterns (supports * globs) | App-level table restriction independent of IAM. list_tables only returns matching tables; all other tools reject non-matching tables. Examples: dev-*, dev-UserProfiles,dev-Orders, dev-*,staging-*. |
DDB_MAX_RESPONSE_BYTES | 0 (unlimited) | Cap the serialized JSON size of a single tool response | Prevents a few very large items (DynamoDB allows up to 400 KB/item) from token-bombing the LLM context window. When exceeded, items are progressively dropped and a truncated flag is added. For get_item (single item, no list), an error is returned instead. Set to 500000–1000000 for production. |
DDB_READ_TIMEOUT | 10 (seconds) | boto3 read timeout for every DynamoDB API call | Prevents slow or hung queries from tying up server resources (DoS vector in HTTP mode). A ReadTimeoutError is caught by the existing error handler and returned cleanly. Lower to 5 in latency-sensitive deployments; raise to 30 if scanning very large pages. |
#### Quick cost reference
| Scenario | RCUs consumed | Approximate cost |
|---|---|---|
| Scan 50 items × 1 KB (1 page, default settings) | ~13 | $0.000003 |
| Scan 500 items × 1 KB (1 page, max limit) | ~125 | $0.00003 |
| Scan 500 items × 20 pages × 1 KB (max everything) | ~2,500 | $0.0006 |
| Full table scan of 1M items × 1 KB | ~250,000 | $0.06 |
| Query 50 items × 1 KB | ~13 | $0.000003 |
| BatchGetItem 100 items × 1 KB | ~25 | $0.000006 |
Costs shown are for eventually consistent reads at $0.25 per million RCUs (on-demand pricing, us-east-2). Strongly consistent reads cost 2×.
Beyond DynamoDB cost, large result sets also increase LLM token usage — 500 items serialized as JSON can easily exceed 50K tokens.
#### Example: tightened production config
{
"mcpServers": {
"ddb-explorer": {
"command": "uvx",
"args": ["ddb-explorer-mcp"],
"env": {
"AWS_PROFILE": "prod-readonly",
"AWS_REGION": "us-east-2",
"DDB_SCAN_DEFAULT_LIMIT": "20",
"DDB_SCAN_MAX_LIMIT": "100",
"DDB_SCAN_DEFAULT_MAX_PAGES": "1",
"DDB_SCAN_MAX_PAGES": "3",
"DDB_QUERY_MAX_LIMIT": "200",
"DDB_SHOW_COST": "true",
"DDB_MAX_ITEMS_PER_SESSION": "1000",
"DDB_MAX_CALLS_PER_MINUTE": "30",
"DDB_AUDIT_LOG": "true",
"DDB_ALLOWED_TABLES": "prod-orders,prod-users,prod-events",
"DDB_MAX_RESPONSE_BYTES": "500000",
"DDB_READ_TIMEOUT": "10"
}
}
}
}HTTP mode is for hosted / team scenarios. A single server instance serves many remote clients; the server holds the AWS credentials, clients don't.
Internet ──► ALB (TLS + OIDC/JWT)
│
└─► ECS Fargate task
Image: ghcr.io/mudassirgithub/ddb-explorer-mcp:latest
Env: MCP_TRANSPORT=http, MCP_HOST=0.0.0.0
IAM: task role with read-only DynamoDB policyA ready-to-use docker-compose.yml is available in examples/.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"dynamodb:DescribeTable",
"dynamodb:DescribeTimeToLive",
"dynamodb:GetItem",
"dynamodb:BatchGetItem",
"dynamodb:Query",
"dynamodb:Scan",
"dynamodb:ListTables"
],
"Resource": "*"
}
]
}For extra isolation, scope Resource to specific table ARNs.
MCP_TRANSPORT=http MCP_PORT=8765 uvx ddb-explorer-mcpThen in another terminal:
curl -i http://127.0.0.1:8765/mcp
# Expect HTTP 406 — endpoint is live; MCP needs proper JSON-RPC POST + Accept.Connect an MCP client pointing at http://127.0.0.1:8765/mcp to actually exercise it.
This is a structural property, not a runtime flag.
dynamically execute arbitrary DynamoDB API calls on behalf of the LLM.
scan defaults to max_pages=1 (one page only). Hard cap 20 pages.query paginates internally with a limit; hard-capped at 500 items per call. All caps are configurable via environment variables — see Safety limits.
DDB_MAX_ITEMS_PER_SESSION bounds the total items a singleserver session can return across all tool calls. Once exceeded, all data-plane calls are rejected until the server is restarted. Prevents automated exfiltration loops.
DDB_MAX_CALLS_PER_MINUTE enforces a sliding-window callrate across all tools. Prevents rapid-fire extraction or accidental runaway loops.
DDB_ALLOWED_TABLES restricts which tables the server canaccess, independent of IAM permissions. Supports glob patterns (e.g. dev-*). list_tables only returns matching tables; all other tools reject non-matching ones.
DDB_AUDIT_LOG=true logs every tool call to stderr withtimestamp, tool name, table, and item count. Useful for monitoring and post-incident investigation, especially in HTTP mode with a log aggregator.
DDB_MAX_RESPONSE_BYTES limits the serialized JSON sizeof any single tool response. Large items (DynamoDB allows up to 400 KB each) can overwhelm the LLM context window and spike token costs. When exceeded, items are progressively dropped and a truncated flag is set.
DDB_READ_TIMEOUT (default 10 s) prevents slow orhung queries from tying up server resources. Applies to every boto3 call via botocore.config.Config. Timeout errors are caught and returned cleanly.
environment or IAM role. The LLM sees tool results, never config.
item could contain text designed to influence LLM behavior (e.g. "ignore previous instructions and..."). This is inherent to any system that feeds untrusted data into an LLM. Mitigations: restrict table access via DDB_ALLOWED_TABLES to trusted tables, enable human-in-the-loop approval for tool calls in your MCP client, and review DDB_AUDIT_LOG output for unexpected access patterns.
MCP_TRANSPORT=http), rate limits(DDB_MAX_CALLS_PER_MINUTE) and session caps (DDB_MAX_ITEMS_PER_SESSION) are per-server-process, not per-client. One client's usage counts against all clients sharing the same server instance. For multi-tenant isolation, run separate server instances per client/team, or proxy through an API gateway that enforces per-client quotas. The server's internal counters are thread-safe but intentionally shared to provide a global safety net.
the server's AWS identity to a read-only DynamoDB IAM policy. Never give it write or admin permissions, ever. Scope Resource in the IAM policy to specific table ARNs for maximum isolation.
git clone https://github.com/mudassirgithub/ddb-explorer-mcp.git
cd ddb-explorer-mcp
make setup # one-time: installs Python + deps
make test # run the full test suite
make check # lint + format-check + tests (same as CI)
make run # start the server in stdio modeOr without make:
uv sync --extra dev
uv run pytest
uv run ruff check .
uv run ruff format --check .
uv run ddb-explorer-mcpContributions welcome — see CONTRIBUTING.md.
This project follows the Contributor Covenant.
To report a security vulnerability, see SECURITY.md. Please do not open public issues for security matters.
Apache License 2.0 — see LICENSE.
This project is not affiliated with, endorsed by, or sponsored by Amazon Web Services, Inc. "AWS" and "Amazon DynamoDB" are trademarks of Amazon.com, Inc. or its affiliates.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.