Skip to main content
Glama
brunoruyu

athena-mcp-server

by brunoruyu

Athena MCP Server

A remote Model Context Protocol server for AWS Athena, deployed as a Docker container.

Customers connect Claude Desktop (or any MCP client) directly to this server using their own AWS IAM credentials — no local installation required.


Architecture

Claude Desktop  ──HTTP POST /mcp──►  athena-mcp-server  ──►  AWS Athena
                  (credentials in headers)

The server is fully stateless. Each request carries credentials in HTTP headers; no sessions, no credential caching.


MCP Tools

Tool

Description

run_query

Execute a SQL query (waits up to timeoutMs, returns results or polling ID)

get_status

Poll the status of a running query

get_result

Fetch results of a completed query

list_saved_queries

List named queries in the workgroup

run_saved_query

Execute a named query by ID


HTTP Headers

Every request to POST /mcp must include:

Header

Required

Default

Description

x-aws-access-key-id

AWS Access Key ID

x-aws-secret-access-key

AWS Secret Access Key

x-s3-output-path

S3 path for query results, e.g. s3://bucket/prefix/

x-aws-region

us-east-1

AWS region

x-aws-session-token

Session token (temporary credentials)

x-athena-workgroup

primary

Athena workgroup

Missing required headers → 401 Unauthorized.


Running locally

Prerequisites

  • Docker + Docker Compose

  • AWS credentials with the required IAM permissions (see below)

Build and run

docker compose up --build

The server starts on http://localhost:3000.

Smoke test

# Health check
curl http://localhost:3000/health
# → {"status":"ok"}

# Run a query
curl -X POST http://localhost:3000/mcp \
  -H "Content-Type: application/json" \
  -H "x-aws-access-key-id: AKIA..." \
  -H "x-aws-secret-access-key: ..." \
  -H "x-aws-region: us-east-1" \
  -H "x-s3-output-path: s3://my-bucket/athena-results/" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "run_query",
      "arguments": {
        "database": "default",
        "query": "SELECT 1 AS test"
      }
    }
  }'

Configuring Claude Desktop

Add the following to your claude_desktop_config.json (~/Library/Application Support/Claude/claude_desktop_config.json on macOS):

{
  "mcpServers": {
    "teramot-athena": {
      "type": "http",
      "url": "https://athena-mcp.teramot.com/mcp",
      "headers": {
        "x-aws-access-key-id": "AKIA...",
        "x-aws-secret-access-key": "...",
        "x-aws-region": "us-east-1",
        "x-athena-workgroup": "primary",
        "x-s3-output-path": "s3://customer-bucket/athena-results/"
      }
    }
  }
}

Replace the URL with your deployed server URL and fill in the customer's credentials.


Deploying to AWS ECS

1. Push the image to ECR

AWS_ACCOUNT_ID=123456789012
AWS_REGION=us-east-1
REPO=athena-mcp-server

aws ecr create-repository --repository-name $REPO --region $AWS_REGION

aws ecr get-login-password --region $AWS_REGION \
  | docker login --username AWS --password-stdin \
    $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com

docker build -t $REPO .
docker tag $REPO:latest $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/$REPO:latest
docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/$REPO:latest

2. Create an ECS task definition

  • CPU / Memory: 256 CPU / 512 MB is sufficient for most workloads

  • Port mappings: container port 3000

  • Environment variables: none required (all config comes via headers)

  • Health check: CMD-SHELL wget -qO- http://localhost:3000/health || exit 1

3. Create an ECS service

  • Use Fargate launch type for zero infrastructure management

  • Attach to an Application Load Balancer (ALB) on HTTPS port 443

  • Enable HTTPS on the ALB listener with an ACM certificate

  • Target group: HTTP, port 3000, health check path /health

4. (Optional) Custom domain

Create a Route 53 alias record pointing to the ALB, e.g. athena-mcp.teramot.com.


Required IAM permissions

The customer's IAM credentials must have the following permissions:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AthenaAccess",
      "Effect": "Allow",
      "Action": [
        "athena:StartQueryExecution",
        "athena:GetQueryExecution",
        "athena:GetQueryResults",
        "athena:ListNamedQueries",
        "athena:GetNamedQuery",
        "athena:ListWorkGroups"
      ],
      "Resource": "*"
    },
    {
      "Sid": "S3ResultsBucket",
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:PutObject",
        "s3:ListBucket"
      ],
      "Resource": [
        "arn:aws:s3:::customer-results-bucket",
        "arn:aws:s3:::customer-results-bucket/*"
      ]
    },
    {
      "Sid": "GlueMetastore",
      "Effect": "Allow",
      "Action": [
        "glue:GetDatabase",
        "glue:GetDatabases",
        "glue:GetTable",
        "glue:GetTables"
      ],
      "Resource": "*"
    }
  ]
}

Replace customer-results-bucket with the actual S3 bucket name.


Development

npm install
npm run dev        # run with ts-node (hot-reload not included)
npm run build      # compile TypeScript → dist/
npm run typecheck  # type-check without emitting

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/brunoruyu/athena-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server