AWS Ops MCP Server
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., "@AWS Ops MCP ServerWhich Lambda functions errored in the last hour?"
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.
AWS Ops MCP Server
An MCP (Model Context Protocol) server that lets an LLM client — Claude Desktop, Claude Code, or any other MCP-compatible client — inspect the health of your AWS Lambda functions and S3 buckets using plain English:
"Which of my Lambda functions have errored in the last hour?"
"Show me the config for
my-api-handler.""How big is the
uploadsbucket and what storage classes is it using?""Give me invocation count, error rate, and average duration for
my-api-handlerover the last day."
Every tool is read-only — nothing here creates, modifies, or deletes an AWS resource. That's a deliberate design choice: it keeps the IAM policy tiny and makes the project safe to point at a real account.
Authentication
Claude's "custom connector" flow for remote MCP servers always performs an
OAuth handshake, even against servers that don't otherwise need auth --
connecting without one fails with "Couldn't register with [name]'s sign-in
service." This project implements a minimal, spec-compliant OAuth 2.1
authorization server (src/auth_provider.py) to satisfy that requirement:
Dynamic client registration, authorization-code + PKCE, and refresh token flows are all implemented per the MCP SDK's
OAuthAuthorizationServerProviderprotocol. PKCE verification itself is handled by the SDK; this provider just stores/retrieves the state around it.State is stored in DynamoDB, not in memory, because Lambda containers are ephemeral -- a login flow spans several separate HTTP requests (register → authorize → token) that can each land on a different container or a cold start, so whatever holds that state has to survive across invocations. A single pay-per-request table (
OAuthStateTableintemplate.yaml) with a TTL attribute covers clients, authorization codes, access tokens, and refresh tokens.Authorization is auto-approved (no login screen) rather than gated behind real user credentials, since this server has exactly one owner. That's a deliberate, documented tradeoff for a personal/portfolio project -- anyone holding the deployed URL and a valid token could call the tools. If you ever point this at something more sensitive, swap
authorize()inauth_provider.pyfor a real login step before issuing the authorization code.
Locally (local_run.py, stdio transport), none of this runs -- auth is
only enabled when MCP_BASE_URL is set, which the SAM template sets
automatically for the deployed Lambda.
Related MCP server: rds-mcp
Architecture
MCP Client (Claude Desktop / Claude Code)
│ OAuth handshake (register/authorize/token) + streamable-HTTP
▼
API Gateway ($default route) ──▶ Lambda (Mangum ▶ FastMCP ASGI app)
│ │
│ ▼
│ DynamoDB (OAuth state:
│ clients/codes/tokens)
▼
boto3 ▶ Lambda API / CloudWatch Logs & Metrics / S3src/server.py— the MCP server itself: tool definitions built withFastMCP, run instateless_httpmode (no in-memory session state, which matters because Lambda cold starts wipe memory between invocations anyway). Wires in the OAuth provider only when deployed (see "Authentication" below).src/auth_provider.py/src/oauth_store.py— the minimal OAuth authorization server and its DynamoDB-backed state store (see "Authentication" below).src/aws_clients.py— the actual boto3 calls, kept separate from the MCP layer so the AWS logic can be unit-tested on its own (seetests/).src/handler.py— the Lambda entry point. Mangum adapts API Gateway's event format to the ASGI interface FastMCP exposes.template.yaml— AWS SAM template: one Lambda function, one HTTP API route (ANY /mcp), and an inline least-privilege IAM policy scoped to exactly the six read-only actions the tools need.local_run.py— runs the same server over stdio for local testing with Claude Desktop, no AWS deployment required.
Tools exposed
Tool | Purpose |
| List all functions with runtime, memory, last-modified |
| Full config for one function |
| Tail recent ERROR/exception log lines via CloudWatch Logs Insights |
| Invocations, errors, error rate, throttles, avg duration |
| List all buckets with creation date |
| Object count, total size, storage-class breakdown |
Local setup
python -m venv venv
source venv/bin/activate
pip install -r requirements.txtMake sure valid AWS credentials are available in your environment (e.g.
aws configure, or exported AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY).
Test locally with Claude Desktop
Add this to your Claude Desktop MCP config
(~/Library/Application Support/Claude/claude_desktop_config.json on macOS):
{
"mcpServers": {
"aws-ops": {
"command": "/absolute/path/to/venv/bin/python",
"args": ["/absolute/path/to/aws-ops-mcp-server/local_run.py"]
}
}
}Restart Claude Desktop, then try: "List my Lambda functions."
Run the unit tests
pip install pytest
pytest tests/ -vThese mock boto3 directly, so they run without AWS credentials or network access.
Deploying to AWS (Lambda + API Gateway)
Requires the AWS SAM CLI.
sam build
sam deploy --guidedsam deploy --guided will prompt for a stack name and region, then print
the deployed API endpoint (also available afterwards via sam list stack-outputs). Point an MCP client that supports streamable-HTTP servers
at <endpoint>/mcp.
IAM permissions
The SAM template grants exactly these read-only actions, nothing more:
lambda:ListFunctions,lambda:GetFunctionConfigurationlogs:StartQuery,logs:GetQueryResults,logs:DescribeLogGroupscloudwatch:GetMetricDatas3:ListAllMyBuckets,s3:ListBucket
Extending it
Natural next steps if you want to keep building on this:
Add a
get_cost_by_servicetool using the Cost Explorer API.Add write-scoped tools behind an explicit confirmation step (e.g. "restart this Lambda's concurrency" ) — a good way to demonstrate you understand the difference between read-only and mutating tool design.
Swap the CloudWatch Logs Insights query in
get_lambda_recent_errorsfor a structured-logging-aware filter if your functions emit JSON logs.Add auth (the
FastMCPconstructor accepts atoken_verifierfor this) before exposing the endpoint outside a private network.
Why this project
This was built to demonstrate backend + AWS skills relevant to production engineering roles: serverless architecture (Lambda, API Gateway, SAM), least-privilege IAM design, structured use of CloudWatch Logs Insights and metrics APIs, and wiring up the emerging MCP protocol as a real, deployable service rather than a toy demo.
This server cannot be deployed
Maintenance
Related MCP Connectors
Query your org's data in natural language — read-only MCP access to SQL, NoSQL, files & warehouses.
Lowers your AWS bill by helping you clean up and optimize your setup
Read-only Amazon SES observability: search events, inspect bounces, pull delivery stats.
Ask data questions in natural language. Get SQL, insights, and charts from your databases.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceEnables natural language analysis of AWS costs, automated FinOps waste audits, and budget monitoring across multiple profiles and regions while keeping credentials secure locally.184MIT
- AlicenseNot gradedqualityDmaintenanceEnables monitoring and analysis of Amazon RDS (MySQL, PostgreSQL) instances, metrics, and slow query logs via natural language.8MIT
- AlicenseNot gradedqualityDmaintenanceEnables natural language analysis of AWS cloud costs, waste audits, and budget insights across multiple profiles and regions.MIT
- FlicenseBqualityCmaintenanceMonitors AWS infrastructure including EC2, RDS, S3, SQS, CloudWatch, and more through 19 tools, enabling natural language queries for infrastructure status.19-