Skip to main content
Glama
DataExplorerX

AWS Ops MCP Server

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 uploads bucket and what storage classes is it using?"

  • "Give me invocation count, error rate, and average duration for my-api-handler over 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 OAuthAuthorizationServerProvider protocol. 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 (OAuthStateTable in template.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() in auth_provider.py for 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 / S3
  • src/server.py — the MCP server itself: tool definitions built with FastMCP, run in stateless_http mode (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 (see tests/).

  • 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_lambda_functions

List all functions with runtime, memory, last-modified

get_lambda_function_config

Full config for one function

get_lambda_recent_errors

Tail recent ERROR/exception log lines via CloudWatch Logs Insights

get_lambda_metrics

Invocations, errors, error rate, throttles, avg duration

list_s3_buckets

List all buckets with creation date

get_s3_bucket_summary

Object count, total size, storage-class breakdown

Local setup

python -m venv venv
source venv/bin/activate
pip install -r requirements.txt

Make 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/ -v

These 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 --guided

sam 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:GetFunctionConfiguration

  • logs:StartQuery, logs:GetQueryResults, logs:DescribeLogGroups

  • cloudwatch:GetMetricData

  • s3:ListAllMyBuckets, s3:ListBucket

Extending it

Natural next steps if you want to keep building on this:

  • Add a get_cost_by_service tool 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_errors for a structured-logging-aware filter if your functions emit JSON logs.

  • Add auth (the FastMCP constructor accepts a token_verifier for 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.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables natural language analysis of AWS costs, automated FinOps waste audits, and budget monitoring across multiple profiles and regions while keeping credentials secure locally.
    184
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables monitoring and analysis of Amazon RDS (MySQL, PostgreSQL) instances, metrics, and slow query logs via natural language.
    8
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables natural language analysis of AWS cloud costs, waste audits, and budget insights across multiple profiles and regions.
    MIT
  • F
    license
    B
    quality
    C
    maintenance
    Monitors AWS infrastructure including EC2, RDS, S3, SQS, CloudWatch, and more through 19 tools, enabling natural language queries for infrastructure status.
    19
    -