mcp-aws
Read-only AWS MCP server for discovering and running cataloged AWS read views over a fixed five-tool surface.
aws_list_accounts— list configured AWS profiles/accounts with account id, alias, default region, and credential status; optional refresh.aws_catalog— list available read-only view ids and summaries; filter by service prefix or search query.aws_describe_view— show one view's parameters, output shape, and backing AWS call.aws_query— run a view against a profile and region with view-specific params, pagination cursor, and item cap.aws_read_resource— describe one AWS resource from its ARN, optionally overriding the profile.All tools are read-only, open-world, non-destructive, and designed to keep AWS coverage in YAML rather than expanding the tool count.
Click on "Deploy 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., "@mcp-aws what EC2 instances are running in prod?"
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.
mcp-aws
A read-only AWS MCP server for stdio, designed to sit behind an MCP gateway.
The problem it solves
One tool per AWS API operation gives you hundreds of tools. Every tool schema is resent to the model on every turn, so a broad AWS server spends the context budget before the first question is asked.
mcp-aws registers five tools, permanently, over a catalog of read-only views
declared in YAML. Coverage grows by adding YAML; the tool surface does not move. The
catalog is discovered at runtime, so a model pays for the one view it needs instead of
carrying the whole of AWS.
aws_list_accounts which profiles (accounts) are configured and usable
aws_catalog view ids + one-line summaries, filterable by service or search
aws_describe_view one view's parameters and output shape, on demand
aws_query run a view against a profile and region
aws_read_resource ARN in, the matching detail view outTypical flow: aws_catalog(service="eks") → aws_describe_view("eks.nodegroups.list")
→ aws_query(...).
Related MCP server: AWS Security MCP Server
Install and run
uv sync
uv run mcp-aws # speaks MCP over stdioGateway / client config:
{
"mcpServers": {
"aws": {
"command": "uv",
"args": ["run", "--directory", "/path/to/mcp-aws", "mcp-aws"],
"env": { "AWS_CONFIG_FILE": "/Users/you/.aws/config" }
}
}
}Credentials
Each named profile in your AWS config is treated as an account. Nothing is assumed
or assume-roled on your behalf. aws_list_accounts resolves every profile concurrently
and reports per-profile status, so one expired SSO session degrades that row rather than
the call:
{"profile": "prod", "account_id": "123456789012", "account_alias": "acme-prod",
"default_region": "us-east-1", "status": "ok"}Read-only by construction
Read-only is enforced at catalog load, not at call time:
The operation name must match a read-only prefix (
describe_,list_,get_, …).The operation must exist in the botocore service model, and every declared parameter must be a real member of its request shape.
Read-shaped but sensitive operations (
s3:get_object,secretsmanager:get_secret_value,ssm:get_parameter,kms:decrypt, log and item reads …) are denylisted outright.
A view that fails any of these aborts startup. The engine can only ever invoke an operation that survived, so there is no code path from a tool call to a mutating API.
Adding coverage
Add an entry to a file in src/mcp_aws/catalog/views/. No Python, no new tool, no
change to the context cost:
- id: ec2.vpcs.list
summary: VPCs with CIDR blocks and default flag
client: ec2 # boto3 client name
operation: describe_vpcs # snake_case, must be read-only and real
paginate: true
params:
vpc_ids:
type: "string[]"
description: Specific VPC ids.
maps_to: VpcIds # request member, 'A.B' nesting, or 'Filters[vpc-id]'
project: | # JMESPath, applied per page
Vpcs[].{id: VpcId, cidr: CidrBlock, is_default: IsDefault}
returns: One object per VPC.
detail_of: ec2:vpc # optional: makes this the target of aws_read_resource
detail_param: vpc_idsuv run pytest tests/test_catalog.py validates every view against the real AWS models.
Two constructs cover the awkward APIs:
expand— a declarative fan-out for services that split a list from its detail (eks:list_clusters+describe_cluster).inheritcarries the parent's key into the child call, fordescribe_nodegroupand friends that needclusterNametoo. Bounded bymax_itemsand a small thread pool.Filters[$param]— a filter whose key is user data rather than part of the API contract, as the Resource Groups Tagging API needs.$selfmeans this parameter's own value is the key;$othertakes the key from a sibling parameter.
Point MCP_AWS_CATALOG_DIR at your own directory to add or override views without
forking the package.
Results and pagination
Every response uses one envelope:
{"view": "ec2.instances.list", "profile": "prod", "region": "us-east-1",
"count": 100, "truncated": true, "next_cursor": "eyJ0Ijo…", "items": [...]}Results are capped by item count and serialized size. Truncation is lossless: each item records the page it came from, so a cut landing in the middle of an AWS page still produces a cursor that resumes at exactly the first dropped item.
Resources
Tools are the path a model uses; resources are for humans and for clients that browse,
@-mention, or build a picker out of them.
Each listing is a JSON Schema enum fragment naming the template one of its values buys, which is what an MCP gateway needs to turn a set into clickable values. Listings are read whenever a client opens the server, so they never call AWS.
Listing | Values | Buys |
| configured profiles |
|
| every view id, labelled with its summary |
|
| services the catalog covers | narrows to |
| one service's view ids |
|
| regions, from bundled endpoint data |
|
Member | Contents | Cost |
| one profile resolved to account, alias, status | live STS/IAM |
| one view's parameters and output shape | free |
| partition, geography, profiles defaulting there | free |
| a view result ( | live AWS read |
aws://query/... pairs with no listing on purpose: a listing beside it would be read on
open, and reading it would mean running queries nobody asked for.
Breaking change in this release: the result template was
aws://{profile}/{region}/{view_id}. Its fixed prefix wasaws://, which shadowed every other URI. It is nowaws://query/{profile}/{region}/{view_id}, andaws://catalogreturns a vocabulary rather than a full dump — the dump isaws_catalogandaws://catalog/{view_id}.
Behind a gateway
Everything in this section is ordinary MCP; a client that ignores it loses nothing.
Injectable values. The listing/template pairs above publish the four argument names worth picking rather than typing —
profile,region,view_idandservice. A gateway's admin UI renders each as chips that fill the matching field.Completions.
completion/completeanswers for those same four, filtered by what has been typed and narrowed by the sibling fields already filled: aview_idasked for beside a chosenserviceoffers only that service's views.Prompts.
aws_account_overview(profile, region)andaws_investigate_resource(arn, profile). Their argument names are the vocabulary's variables, which is what lets the same chips fill them.
None of this touches the tool surface: resources, templates, completions and prompts are fetched on demand instead of being resent every turn.
Configuration
Variable | Default | Purpose |
|
| Namespace the tools behind a gateway |
| all | Comma-separated allowlist of visible profiles |
| – | Extra catalog directories (later wins) |
|
| Default item cap per response |
|
| Serialized size cap per response |
|
| Result cache seconds; |
|
| Parallel detail calls during |
|
| Logging level (stderr only) |
Coverage today
Twenty-six views across seven services. The prefix is a grouping label, not the AWS
client — account.regions calls ec2, and resources is not an AWS service at all.
account— identity, regionsresources— tagged-resource inventory across services, tag keys, tag valuesorg— accounts, roots, OUsec2— instances, security groups, VPCs, subnets, route tables, volumes, NAT gatewayselbv2— load balancers, target groups, listeners, target healthautoscaling— groupseks— clusters, node groups, add-ons, Fargate profiles
Development
uv run pytest # no network, no credentials; AWS is stubbedAvailable Tools
5 toolsaws_catalogARead-only
List the read-only views this server offers, as view ids with one-line summaries. Start here to find out what can be asked about AWS.
Args: service: Restrict to one service prefix, e.g. 'ec2', 'eks', 'account'. query: Space-separated terms matched against id, summary and description.
Inputs: query, service. Returns: object
aws_describe_viewARead-only
Show one view's parameters, output shape and the AWS call behind it.
Args: view_id: A view id from the catalog tool, e.g. 'ec2.instances.list'.
Inputs: view_id (required). Returns: object
aws_list_accountsARead-only
List the AWS accounts (named profiles) this server can read, with account id, alias, default region and whether the credentials currently work.
Args: refresh: Re-resolve identities instead of using the cached ones.
Inputs: refresh. Returns: object
aws_queryARead-only
Run a catalog view against one account and region.
Args:
view_id: A view id from the catalog tool.
profile: The AWS profile (account) to read, from the list-accounts tool.
region: AWS region; defaults to the profile's configured region.
params: View-specific parameters; see the describe-view tool.
cursor: next_cursor from a previous truncated result.
max_items: Cap on returned items for this call.
Inputs: profile (required), view_id (required), cursor, params, +2 more. Returns: object
aws_read_resourceARead-only
Describe a single AWS resource given its ARN, routing to the view that covers that resource type.
Args: arn: Full ARN, e.g. 'arn:aws:eks:us-east-1:123456789012:cluster/prod'. profile: Override the profile; by default it is matched from the ARN account.
Inputs: arn (required), profile. Returns: object
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 5 tools
Each tool has a clearly distinct role: account discovery, view cataloging, view schema inspection, ARN-based resource lookup, and executing queries. There is no meaningful overlap between them.
All tools share the aws_ prefix and follow a consistent verb-oriented pattern (list_accounts, catalog, describe_view, read_resource, query). The naming is uniform and predictable.
Five tools is well-scoped for a read-only AWS exploration server. Each tool serves a distinct step in the workflow without redundancy or bloat.
The tool surface covers the full read-only workflow: discover accounts, browse available views, inspect view parameters, query data, and resolve individual resources by ARN. No obvious gaps exist for the stated purpose.
Maintenance
Related MCP Connectors
Read-only MCP access to a documented IT fleet: state, changes, posture. 15 tools.
Cloud cost, inventory and governance on AWS/Azure/GCP. Read-only by default, optional scoped writes
Read-only AI/LLM cost tools with current MCP discovery and attributable Registry transport.
Governed MCP gateway: one endpoint for your tools, with credential custody and audit log.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceA read-only MCP server for safe, structured investigation of AWS serverless resources, providing curated tools for tracing dependencies, permissions, and failures without exposing raw SDK access.45 PyPIMIT
- AlicenseNot gradedqualityDmaintenanceEnables management and analysis of AWS security groups, S3 buckets, and VPC connections via MCP.7MIT
- AlicenseNot gradedqualityDmaintenanceA minimal, security-focused MCP gateway for connecting ChatGPT to AWS account data through explicit, read-only tools.MIT
- AlicenseNot gradedqualityDmaintenanceEnables read-only SQL querying and schema inspection across MSSQL, PostgreSQL, and MySQL databases via MCP tools.ISC