A conversational chat interface for querying AWS pricing information. Ask questions in plain English and get accurate, up-to-date pricing data powered by Claude and the AWS Pricing MCP servers.
The app is a two-tier web application:
- Frontend — React + Vite + TypeScript SPA. Provides a chat UI with multi-line input, file attachments, and a conversation thread.
- Backend — Node.js + Express server that receives chat messages, maintains conversation history, and runs a Claude tool-call loop via Amazon Bedrock. Claude uses two MCP servers to fetch live AWS pricing data:
aws-pricing-calculator-mcp-server— AWS Pricing Calculator integrationawslabs.aws-pricing-mcp-server— AWS Price List API integration
Browser → Vite dev server (/api proxy) → Express backend → Claude API
↕
MCP servers (npx)
├── aws-pricing-calculator-mcp-server
└── awslabs.aws-pricing-mcp-server
- Node.js 18 or later
- npm 9 or later
- AWS credentials with Amazon Bedrock access — a Bedrock bearer token (
AWS_BEARER_TOKEN_BEDROCK). Get it from the Bedrock console. - Bedrock model access — enable
Claude Sonnetin your AWS account via the Bedrock console (Model access → Manage model access).
The MCP servers are fetched automatically via npx when the backend starts — no separate install needed.
npm run install:allThis installs packages for both the backend and frontend.
cp .env.example .envOpen .env and fill in your Bedrock bearer token:
# Required
AWS_BEARER_TOKEN_BEDROCK=ABSKQmVkcm9ja0FQSUtleS0...
AWS_REGION=us-east-1
# Optional — defaults shown
FRONTEND_ORIGIN=http://localhost:5173
PORT=3001You need two terminals — one for the backend and one for the frontend.
Terminal 1 — backend:
npm run dev:backendThe server starts on http://localhost:3001. It will spawn both MCP servers and log their tool lists before accepting requests.
Terminal 2 — frontend:
npm run dev:frontendThe Vite dev server starts on http://localhost:5173. Open that URL in your browser.
- Ask a pricing question — type in the input box and press Enter (or click Send). For example:
- "How much does an m5.xlarge instance cost per month in us-east-1?"
- "Compare Lambda vs EC2 for 10 million requests per month"
- "What's the cheapest RDS instance with at least 16 GB RAM?"
- Attach files — click the 📎 icon to attach documents or images (up to 10 MB each). Claude will include them in its context.
- Multi-line input — use Shift+Enter for a new line; Enter alone sends the message.
- Reset conversation — click New Chat to clear the conversation history on both the client and server.
aws-pricing-chat/
├── backend/
│ ├── src/
│ │ ├── server.ts # Entry point — env validation, MCP init, Express start
│ │ ├── app.ts # Express app with CORS and routes
│ │ ├── chatRouter.ts # POST /api/chat
│ │ ├── resetRouter.ts # POST /api/reset
│ │ ├── claudeOrchestrator.ts # Claude tool-call loop
│ │ ├── MCPManager.ts # MCP server lifecycle and tool routing
│ │ ├── SessionStore.ts # In-memory conversation history
│ │ └── types.ts # Shared TypeScript types
│ ├── package.json
│ └── tsconfig.json
├── frontend/
│ ├── src/
│ │ ├── App.tsx # Root component — state, submit, reset
│ │ ├── chatApi.ts # fetch wrapper for /api/chat
│ │ ├── types.ts # Frontend TypeScript types
│ │ ├── index.css # Layout and component styles
│ │ └── components/
│ │ ├── MessageThread.tsx
│ │ ├── MessageBubble.tsx
│ │ ├── InputBar.tsx
│ │ ├── FileChip.tsx
│ │ └── LoadingIndicator.tsx
│ ├── vite.config.ts # Vite config with /api proxy
│ ├── package.json
│ └── tsconfig.json
├── .env.example
└── package.json # Root scripts
npm run buildThis compiles the backend TypeScript to backend/dist/ and bundles the frontend to frontend/dist/.
To run the compiled backend:
node backend/dist/server.jsServe frontend/dist/ with any static file server, pointing it at the same origin or configuring FRONTEND_ORIGIN on the backend to match.
| Variable | Required | Default | Description |
|---|---|---|---|
AWS_BEARER_TOKEN_BEDROCK |
Yes | — | Bedrock bearer token (ABSKQmVkcm9ja0FQSUtleS0...) |
AWS_REGION |
Yes | — | AWS region where Bedrock is enabled (e.g. us-east-1) |
FRONTEND_ORIGIN |
No | http://localhost:5173 |
Allowed CORS origin for the frontend |
PORT |
No | 3001 |
Port the Express server listens on |
Deploy the application on a single EC2 instance (t4g.small, us-east-1) with nginx and SSM Session Manager. No Docker required.
npm run buildtar czf ~/source/app-runtime.tar.gz \
backend/dist backend/node_modules backend/package.json \
frontend/dist frontend/package.jsonaws s3 cp ~/source/app-runtime.tar.gz s3://awsquote-deploy/app-runtime.tar.gzaws cloudformation deploy \
--template-file infra/cloudformation-ec2.yaml \
--stack-name aws-pricing-chat-ec2 \
--parameter-overrides \
RuntimeS3Bucket=awsquote-deploy \
RuntimeS3Key=app-runtime.tar.gz \
SenseNovaApiKey=sk-xxxxxxxxxxxxxxxxxxxxx \
--capabilities CAPABILITY_NAMED_IAM \
--region us-east-1The stack creates a VPC, public subnet, security group, IAM role with SSM/ Bedrock permissions, an Elastic IP, and the EC2 instance. User data installs Node.js 22, uv, and nginx, then starts the backend (systemd) and nginx.
Access the app at the EIP shown in the stack outputs. Connect to the instance via:
aws ssm start-session --target <instance-id>Restart the backend after deploying a new bundle:
sudo systemctl restart aws-pricing-chatAfter making code changes, build and upload from your local machine:
npm run build
tar czf /tmp/app-runtime.tar.gz \
backend/dist backend/node_modules backend/package.json \
frontend/dist frontend/package.json
aws s3 cp /tmp/app-runtime.tar.gz s3://awsquote-deploy/Then SSH into the EC2 and apply:
sudo aws s3 cp s3://awsquote-deploy/app-runtime.tar.gz /tmp/app-runtime.tar.gz
sudo rm -rf /opt/aws-pricing-chat/frontend /opt/aws-pricing-chat/backend
sudo tar xzf /tmp/app-runtime.tar.gz -C /opt/aws-pricing-chat
# Edit .env if needed (e.g. FRONTEND_ORIGIN, SYSTEM_PROMPT)
sudo vim /opt/aws-pricing-chat/.env
sudo systemctl restart aws-pricing-chat