Skip to main content
Glama
AinsleyG5

Amplify MCP Proxy

by AinsleyG5
README.md
# Amplify MCP POC Proxy

A lightweight MCP server exposing two tools against a Salesforce org and BHA API.
Deployed as AWS Lambda + API Gateway (HTTP API).

## Tools

| Tool | Description |
|------|-------------|
| `find_candidate_by_name` | SOQL query against Salesforce Contacts (Candidate record type) by name |
| `send_candidate_to_screening` | POSTs to BHA API with candidate Id, returns screening URL |

---

## Prerequisites

- Node.js 18+
- AWS CLI configured (`aws configure`)
- AWS SAM CLI (`brew install aws-sam-cli` or see [docs](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/install-sam-cli.html))
- A Salesforce org with a Connected App configured for username/password OAuth
- BHA static API token

---

## Local Setup

```bash
# 1. Install dependencies
npm install

# 2. Copy and fill in env vars
cp .env.example .env
# Edit .env with your real credentials

# 3. Run local smoke test against your SF org
node test-local.js "Smith"
```

The smoke test runs the full MCP handshake locally without deploying anything.
If you see candidate names printed, the Salesforce connection is working.

---

## Salesforce Connected App Setup

In your trial org (Setup > App Manager > New Connected App):

1. Enable OAuth Settings
2. Callback URL: `https://login.salesforce.com/services/oauth2/success` (not used but required)
3. Selected OAuth Scopes:
   - Access and manage your data (api)
   - Perform requests at any time (refresh_token, offline_access)
4. Enable Client Credentials Flow: checked
5. Save -- note the Consumer Key (Client ID) and Consumer Secret

Also ensure the running user has API access and can read Contact records.

---

## Deploy to AWS

```bash
# 1. Build the deployment package
cd infra
sam build --template template.yaml --build-dir .aws-sam

# 2. Deploy (guided first time -- saves config to samconfig.toml)
sam deploy --guided \
  --template template.yaml \
  --stack-name amplify-mcp-poc \
  --capabilities CAPABILITY_IAM \
  --parameter-overrides \
    SfLoginUrl=https://test.salesforce.com \
    SfClientId=YOUR_CLIENT_ID \
    SfClientSecret=YOUR_CLIENT_SECRET \
    SfUsername=your.user@org.sandbox \
    SfPassword=yourpassword \
    SfSecurityToken=yourtoken \
    BhaApiBaseUrl=https://api.herefish.com/api/v1 \
    BhaApiToken=YOUR_BHA_TOKEN

# 3. Note the McpEndpoint output URL -- you'll need this for Claude Desktop
```

Subsequent deploys (after the first):
```bash
sam deploy --template template.yaml --stack-name amplify-mcp-poc
```

---

## Wire into Claude Desktop

Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "amplify-poc": {
      "url": "https://YOUR_API_ID.execute-api.eu-west-1.amazonaws.com/mcp",
      "transport": "http"
    }
  }
}
```

Replace `YOUR_API_ID` with the value from the `McpEndpoint` SAM output.
Restart Claude Desktop -- you should see `find_candidate_by_name` and
`send_candidate_to_screening` appear as available tools.

---

## Project Structure

```
amplify-mcp-proxy/
├── src/
│   ├── handler.js      # Lambda entry point -- MCP protocol router
│   ├── tools.js        # Tool definitions + handlers
│   ├── salesforce.js   # SF OAuth + SOQL query helper
│   └── bha.js          # BHA API client
├── infra/
│   └── template.yaml   # AWS SAM template
├── test-local.js       # Local smoke test
├── .env.example        # Environment variable template
└── package.json
```

---

## Extending

To add a new tool:

1. Add the definition + handler function in `src/tools.js`
2. Register it in the `TOOLS` map at the bottom of that file
3. That's it -- `tools/list` and `tools/call` routing pick it up automatically

---

## Notes

- The MCP session is stateless -- no server-side session storage. A fresh
  `mcp-session-id` is issued on every `initialize` call but no state is stored.
  This matches the production Bullhorn proxy pattern.

- The Salesforce access token is cached in Lambda memory for the lifetime of
  the execution context (warm invocations reuse it). Cold starts re-authenticate.
  This means one auth call per cold start, not per tool call.

- The BHA endpoint path (`/screening`) in `src/bha.js` may need adjusting to
  match your actual BHA API route. Check with your BHA/Herefish contact for
  the exact endpoint and payload shape.