s3-mcp-server

s3-mcp-server

A remote, OAuth2-authenticated MCP server that provides read-only S3 tools (list buckets, list objects, check public access, get bucket size) designed to run on ECS Fargate with Auth0 as the identity provider.

Category
访问服务器

README

S3 MCP server on ECS Fargate

A remote, OAuth2-authenticated MCP server exposing read-only S3 tools (list_buckets, list_objects, get_bucket_public_access, get_bucket_size), designed to run as an ECS Fargate task behind an ALB and CloudFront, with Auth0 as the identity provider.

How it fits together

  • CloudFront terminates TLS at the edge and forwards every header (including Authorization) to an internal ALB over plain HTTP.
  • ALB hands the request to the ECS Fargate task on port 8080.
  • The task (server.py) validates the bearer token against Auth0 before running any tool, then talks to S3 using the task's IAM role — no static AWS credentials anywhere.
  • The task reaches both Auth0's JWKS endpoint and S3's public API through a NAT Gateway, since it runs in private subnets and no S3 VPC endpoint is configured.

The OAuth handshake (login, PKCE code exchange) happens entirely between the MCP client (e.g. Claude Desktop) and Auth0 — the server is only involved at the very start (serving its own discovery document) and the very end (validating the resulting token). Keep that in mind when debugging: a failed login never shows up in this server's logs, because the server was never part of that exchange.

Auth0 setup

You need an Auth0 tenant (the free tier is enough) with two things in it:

  1. An API — this is what makes Auth0 issue real JWT access tokens instead of opaque ones.

    • Dashboard → Applications → APIs → Create API
    • Identifier: the exact URL clients will connect to, e.g. https://your-domain.example.com/sse — this becomes AUTH0_AUDIENCE and must match byte-for-byte what you deploy behind.
    • Signing algorithm: RS256 (default)
  2. An Application — what the MCP client authenticates as.

    • Dashboard → Applications → Applications → Create Application
    • Type: Regular Web Application
    • In Settings, set Allowed Callback URLs to whatever redirect URI(s) your MCP client uses (for Claude Desktop: https://claude.ai/api/mcp/auth_callback)
    • Note the Domain, Client ID, and Client Secret — these become AUTH0_DOMAIN / AUTH0_CLIENT_ID / the client secret you give your MCP client (the server itself never needs the secret).
  3. Authorize the Application for the API — this step is easy to miss. Creating an API and an Application separately does not link them. Go to the API → Application Access tab → toggle your Application on. Skip this and every authorization attempt fails with invalid_request / "Client is not authorized to access resource server", before the client ever sees a login page.

Local test (no AWS needed for the transport layer)

cp .env.example .env
# edit .env with your Auth0 tenant details if you want to test auth locally
pip install -r requirements.txt
python server.py

Server listens on http://localhost:8080/sse. /health returns 200 ok with no auth required — that's the ALB target group health check path.

Every other route requires Authorization: Bearer <token> where the token is an Auth0 access token (JWT, aud matching AUTH0_AUDIENCE) for an app client matching AUTH0_CLIENT_ID.

Docker

docker build -t s3-mcp-server .
docker run -p 8080:8080 --env-file .env s3-mcp-server

Deploying to Fargate

cd infra
pip install -r requirements.txt   # into a venv
cdk bootstrap   # first time only, per account/region
cdk deploy \
  -c auth0_domain=your-tenant.us.auth0.com \
  -c auth0_client_id=your-application-client-id \
  -c auth0_audience=https://your-domain.example.com/sse

auth0_audience should match the CloudFront domain CDK is about to create, with /sse appended — you likely won't know it on the very first deploy. Deploy once to get the DistributionURL output, then redeploy with the real audience value (this only needs to happen once; the CloudFront domain is stable across subsequent deploys of the same stack).

Instead of passing -c flags every time, you can put them in a gitignored infra/cdk.context.json:

{
  "auth0_domain": "your-tenant.us.auth0.com",
  "auth0_client_id": "your-application-client-id",
  "auth0_audience": "https://your-domain.example.com/sse"
}

Things that bite people

  1. ALB idle timeout. SSE connections are long-lived. The ALB's default idle timeout (60s) will kill them. This stack sets it to 300 (5 min) — raise it further if your client doesn't send periodic pings.

  2. Health check path. Target group health check points at /health, not /sse/sse requires auth and is a streaming response, neither of which the ALB health checker expects.

  3. Credentials. The container never sets AWS credentials — boto3 picks them up automatically from the Fargate task's IAM role via the container credentials endpoint. Don't bake keys into the image or env vars.

  4. Egress. The task fetches Auth0's JWKS over HTTPS on first request (then caches for an hour), and calls S3's public API for every tool call — both go out through the NAT Gateway, since this stack doesn't configure an S3 VPC Gateway Endpoint. Make sure the task's subnet actually has a NAT route, or add a Gateway Endpoint for S3 (free, and keeps that traffic off the public internet).

  5. The MCP SDK's own DNS-rebinding protection will silently break this behind any real domain. FastMCP's TransportSecuritySettings defaults to an empty allowed-hosts list, which rejects every request that arrives with a real Host header (like your CloudFront domain) — even after auth succeeds — with 421 Misdirected Request. This happens after the OAuth flow completes, so it's easy to mistake for an auth bug. This server disables it in server.py, since Auth0AuthMiddleware already gates every route with bearer-token auth:

    mcp = FastMCP(
        "s3-mcp-server",
        transport_security=TransportSecuritySettings(enable_dns_rebinding_protection=False),
    )
    

Minimal IAM task role policy (read-only tools above)

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "S3ReadOnly",
      "Effect": "Allow",
      "Action": [
        "s3:ListAllMyBuckets",
        "s3:ListBucket",
        "s3:GetBucketAcl",
        "s3:GetBucketPolicyStatus",
        "s3:GetBucketPolicy"
      ],
      "Resource": "*"
    }
  ]
}

Scope Resource down to specific bucket ARNs once you know which buckets this agent should actually be allowed to see. If you later add a write tool (e.g. lifecycle policy changes), give it its own narrower statement rather than widening this one.

MCP client config

Point any MCP client that supports remote SSE servers at your deployed URL, with the Auth0 Application's Client ID and Secret from the setup steps above:

{
  "mcpServers": {
    "s3": {
      "url": "https://your-domain.example.com/sse",
      "oauth_client_id": "your-application-client-id",
      "oauth_client_secret": "your-application-client-secret"
    }
  }
}

The exact config shape depends on the client — Claude Desktop exposes these as form fields under its Connectors settings rather than raw JSON. Either way, the OAuth redirect/token exchange is handled by the client per the MCP authorization spec; this server only validates the resulting bearer token on each request.

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选