Skip to main content
Glama
tanishqjadhav-evo

S3 Reader MCP Server

README.md
# S3 Reader MCP Server (Streamable HTTP, Cloud Run)

A Model Context Protocol (MCP) server that exposes **read-only** tools for
browsing and reading Amazon S3 objects, served over the **streamable-http**
transport (MCP spec 2025-03-26), ready to deploy on **Google Cloud Run**.

## Tools exposed

| Tool | Description |
|---|---|
| `list_buckets` | List all S3 buckets visible to the AWS credentials in use |
| `list_objects` | List/paginate objects in a bucket, with optional prefix/delimiter |
| `get_object_metadata` | HEAD an object: size, content-type, last-modified, etag |
| `read_object_text` | Read an object's body as text (size-capped) |
| `read_object_base64` | Read an object's raw bytes as base64 (for binary files) |
| `read_pdf_text` | Extract readable text from a PDF (page-by-page, with page markers) |

The MCP endpoint is served at: `POST /mcp` (this is the default
`streamable_http_path` from the SDK).

All tools are read-only — nothing in this server can create, overwrite, or
delete S3 data.

## 1. Local setup

```bash
pip install -r requirements.txt
export AWS_ACCESS_KEY_ID=...
export AWS_SECRET_ACCESS_KEY=...
export AWS_REGION=us-east-1
export PORT=8080
python server.py
```

You should see a log line like:

```
Starting S3 MCP server on 0.0.0.0:8080 (region=us-east-1)
```

You can also put these values in a local `.env` file instead of exporting
them — `server.py` loads it automatically via `python-dotenv`. Never commit
`.env` to source control (it's already excluded in `.dockerignore`).

## 2. Test it with MCP Inspector

Before wiring this server up to any AI client, test it directly with the
official **MCP Inspector** — a small web UI that lets you call MCP tools by
hand and see the raw request/response. No install needed beyond Node:

```bash
npx @modelcontextprotocol/inspector
```

This opens a local UI (usually at `http://localhost:6274`). In the
connection panel:

1. **Transport type**: `Streamable HTTP`
2. **URL**: `http://localhost:8080/mcp` (or your Cloud Run URL + `/mcp` once deployed)
3. If your deployment requires auth (see step 6 below), add an
   `Authorization: Bearer <token>` header in the Inspector's headers section.
4. Click **Connect**, then open the **Tools** tab — you should see all six
   tools listed (`list_buckets`, `list_objects`, `get_object_metadata`,
   `read_object_text`, `read_object_base64`, `read_pdf_text`).
5. Pick a tool, fill in its arguments (e.g. `list_buckets` needs none;
   `list_objects` needs a `bucket`), and click **Run Tool** to see the
   live result against your actual AWS account.

This is the fastest way to confirm the server is reachable, credentials are
working, and each tool's schema/response shape looks right — before you
point a real MCP client (Claude, another agent, etc.) at it.

If you'd rather stay on the command line, `curl` also works for a basic
smoke test:

```bash
curl -X POST http://localhost:8080/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}'
```

## 3. AWS credentials & permissions

The server uses boto3's standard credential chain (env vars → shared config
→ IAM role). Grant the identity used at minimum:

```json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["s3:ListAllMyBuckets", "s3:ListBucket", "s3:GetObject"],
      "Resource": ["arn:aws:s3:::*"]
    }
  ]
}
```

Scope `Resource` down to specific bucket ARNs in production.

**Recommended for Cloud Run**: store AWS credentials in **Secret Manager**
rather than plain environment variables (see step 5 below). If you're
running entirely within AWS-adjacent infra, you could alternatively use
workload identity federation between GCP and AWS, but the simplest path is
an IAM user with an access key stored as a Cloud Run secret.

## 4. Build and push the container

```bash
export PROJECT_ID=your-gcp-project
export REGION=us-central1
export REPO=s3-mcp-server

gcloud auth login
gcloud config set project "$PROJECT_ID"

# One-time: create an Artifact Registry repo
gcloud artifacts repositories create "$REPO" \
  --repository-format=docker \
  --location="$REGION"

# Build with Cloud Build (no local Docker needed) and push
gcloud builds submit \
  --tag "$REGION-docker.pkg.dev/$PROJECT_ID/$REPO/s3-mcp-server:latest"
```

(Alternatively, build locally with `docker build -t ... .` and
`docker push ...` if you have Docker installed and are authenticated to
Artifact Registry via `gcloud auth configure-docker`.)

## 5. Store AWS credentials as secrets

```bash
printf '%s' "$AWS_ACCESS_KEY_ID" | gcloud secrets create aws-access-key-id --data-file=-
printf '%s' "$AWS_SECRET_ACCESS_KEY" | gcloud secrets create aws-secret-access-key --data-file=-
```

## 6. Deploy to Cloud Run

```bash
gcloud run deploy s3-mcp-server \
  --image "$REGION-docker.pkg.dev/$PROJECT_ID/$REPO/s3-mcp-server:latest" \
  --region "$REGION" \
  --platform managed \
  --port 8080 \
  --set-env-vars AWS_REGION=us-east-1 \
  --set-secrets AWS_ACCESS_KEY_ID=aws-access-key-id:latest,AWS_SECRET_ACCESS_KEY=aws-secret-access-key:latest \
  --min-instances 0 \
  --max-instances 5 \
  --no-allow-unauthenticated
```

Notes:
- `--no-allow-unauthenticated` requires callers to send a valid Google
  identity token (`Authorization: Bearer <token>`). Use
  `--allow-unauthenticated` only if you're deploying your own auth in front,
  since this server exposes read access to your S3 data.
- Cloud Run injects `PORT` automatically; `server.py` reads it via
  `os.environ["PORT"]`, so `--port 8080` above must match `EXPOSE 8080` in
  the Dockerfile and the container's listening port (already aligned).
- Because the server is stateless (`stateless_http=True`), it's safe for
  Cloud Run to route consecutive requests to different container instances
  — no sticky sessions required.

## 7. Connect an MCP client

Point any MCP client that supports the streamable-http transport (including
MCP Inspector — see step 2) at:

```
https://<your-cloud-run-url>/mcp
```

If the service requires authentication, include a Google-signed identity
token as a bearer token, e.g. for quick manual testing:

```bash
TOKEN=$(gcloud auth print-identity-token)
curl -X POST https://<your-cloud-run-url>/mcp \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
```

## Files

- `server.py` — MCP server implementation (FastMCP, streamable-http transport)
- `requirements.txt` — Python dependencies
- `Dockerfile` — container build for Cloud Run
- `.dockerignore` — build context excludes