Batteries Plus Mcp — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited Batteries Plus Mcp (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
A production-ready Model Context Protocol (MCP) server for the Batteries Plus Service Workflow demo. This server connects Salesforce Agentforce agents to Batteries Plus product catalog, store inventory, and service handoff capabilities.
This MCP server enables Salesforce Agentforce agents to:
Demo Story: A customer's car won't start. The agent identifies the right replacement battery, checks local availability, and creates a store visit summary—all without human handoff.
This is a service workflow demo, not a transactional system. It explicitly does NOT:
@modelcontextprotocol/sdk v1.0.4none mode for fast testing/tmp for handoffs)batteries-plus-mcp/
├── src/
│ ├── server.ts # Express + MCP SDK + tool registration
│ ├── auth.ts # OAuth 2.0 implementation
│ ├── data/
│ │ ├── batteries.ts # Vehicle fit database
│ │ └── stores.ts # Store + inventory database
│ ├── services/
│ │ ├── handoffStore.ts # In-memory handoff storage
│ │ └── salesforceWriter.ts # Placeholder for Salesforce integration
│ ├── tools/
│ │ ├── findCompatibleReplacement.ts # MCP tool 1
│ │ ├── checkStoreAvailability.ts # MCP tool 2
│ │ └── createStoreHandoff.ts # MCP tool 3
│ └── utils/
│ ├── ids.ts # Handoff ID generation
│ └── validation.ts # Input validation utilities
├── test/
│ └── smoke.test.js # Basic health checks
├── package.json
├── tsconfig.json
├── render.yaml # Render deployment config
└── .env.example # Environment template cd batteries-plus-mcp
npm install cp .env.example .envFor fast local testing, use MCP_AUTH_MODE=none:
PORT=3000
NODE_ENV=development
MCP_AUTH_MODE=none
WRITE_MODE=memory npm run devThe server starts at http://localhost:3000 with hot-reload enabled.
curl http://localhost:3000/healthExpected response:
{
"status": "healthy",
"service": "batteries-plus-service-mcp",
"version": "1.0.0",
"auth_mode": "none",
"write_mode": "memory",
"uptime_seconds": 12.4,
"handoffs_created": 0
}npm run build # Compile TypeScript to ./dist
npm start # Run compiled server| Variable | Required | Default | Description |
|---|---|---|---|
PORT | No | 3000 | Server port |
NODE_ENV | No | development | Runtime environment |
MCP_AUTH_MODE | No | none | Auth mode: none or oauth |
MCP_CLIENT_ID | OAuth only | — | OAuth client ID |
MCP_CLIENT_SECRET | OAuth only | — | OAuth client secret |
MCP_TOKEN_TTL_SECONDS | No | 3600 | Token lifetime (1 hour) |
WRITE_MODE | No | memory | Handoff storage: memory or salesforce |
For Render deployment, set MCP_AUTH_MODE=oauth and configure MCP_CLIENT_ID and MCP_CLIENT_SECRET in the Render dashboard.
Health check endpoint. Returns server status, auth mode, uptime, and handoff count.
OAuth 2.0 token endpoint (only active when MCP_AUTH_MODE=oauth).
Request:
curl -X POST https://your-server.onrender.com/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET"Response:
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "mcp.tools"
}MCP protocol endpoint. Agentforce sends tool requests here via Streamable HTTP transport.
View all store visit summaries created by the agent. Returns HTML in browsers, JSON for API clients.
Finds a compatible replacement battery for a customer's vehicle.
Input:
{
"vehicle_year": 2019,
"vehicle_make": "Honda",
"vehicle_model": "CR-V",
"vehicle_engine": "1.5L L4",
"postal_code": "53202"
}Output:
{
"fit_status": "compatible",
"fit_confidence": "high",
"vehicle": {
"year": 2019,
"make": "Honda",
"model": "CR-V",
"engine": "1.5L L4"
},
"recommended_product": {
"sku": "SLI51RAGM",
"name": "X2Power Premium AGM Battery - Group 51R",
"group_size": "51R",
"cold_cranking_amps": 500,
"reserve_capacity_minutes": 90,
"warranty_months": 36,
"install_eligible": true
},
"recommendation_reason": "This battery matches the vehicle's group size and cold-cranking amp requirements."
}Checks nearby Batteries Plus stores for a specific SKU.
Input:
{
"sku": "SLI51RAGM",
"postal_code": "53202",
"radius_miles": 15
}Output:
{
"sku": "SLI51RAGM",
"postal_code": "53202",
"availability_status": "available_nearby",
"stores": [
{
"store_id": "BP-MKE-001",
"store_name": "Batteries Plus - Milwaukee East",
"address": "2401 S. Kinnickinnic Ave, Milwaukee, WI 53207",
"distance_miles": 2.3,
"phone": "(414) 555-0101",
"today_hours": "8:00 AM - 7:00 PM",
"quantity_available": 4,
"service_context": {
"battery_testing_available": true,
"installation_available": true,
"estimated_service_time": "20-30 minutes",
"note": "Store can test the current battery before installation."
}
}
]
}Creates a store visit summary after the customer selects a store. This tool will block unless `customer_confirmed_store` is `true`.
Input:
{
"customer_name": "Jane Doe",
"customer_issue": "Car will not start",
"vehicle_year": 2019,
"vehicle_make": "Honda",
"vehicle_model": "CR-V",
"vehicle_engine": "1.5L L4",
"recommended_sku": "SLI51RAGM",
"recommended_product_name": "X2Power Premium AGM Battery - Group 51R",
"selected_store_id": "BP-MKE-001",
"selected_store_name": "Batteries Plus - Milwaukee East",
"availability_result": "4 units available",
"customer_confirmed_store": true
}Output:
{
"status": "created",
"handoff_id": "SVS-20260622-1430",
"created_at": "2026-06-22T14:30:12.456Z",
"service_workflow": "Store Visit Summary",
"summary": {
"customer_issue": "Car will not start",
"vehicle": "2019 Honda CR-V 1.5L L4",
"recommended_sku": "SLI51RAGM",
"recommended_product_name": "X2Power Premium AGM Battery - Group 51R",
"selected_store": "Batteries Plus - Milwaukee East",
"availability_result": "4 units available",
"store_note": "Customer may need battery testing before replacement. Store has installation available today."
},
"demo_record_url": "https://example.salesforce.com/lightning/r/Store_Visit_Summary__c/SVS-20260622-1430/view"
}npm testRuns basic health checks on /health and /demo/handoffs.
You can test MCP tools manually using curl (when MCP_AUTH_MODE=none):
Example: List Tools
curl -X POST http://localhost:3000/mcp \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list"
}'Example: Call Tool
curl -X POST http://localhost:3000/mcp \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "find_compatible_replacement",
"arguments": {
"vehicle_year": 2019,
"vehicle_make": "Honda",
"vehicle_model": "CR-V"
}
}
}' git init
git add .
git commit -m "Initial commit: Batteries Plus MCP server"
git remote add origin https://github.com/YOUR_USERNAME/batteries-plus-mcp.git
git push -u origin mainbatteries-plus-mcprender.yaml ✅MCP_CLIENT_ID = batteries-plus-agentforce-client (or your custom value)MCP_CLIENT_SECRET = Generate a strong secret (e.g., `openssl rand -base64 32`)Your server URL will be: https://batteries-plus-mcp.onrender.com
Your MCP Endpoint URL for Salesforce registration is:
https://batteries-plus-mcp.onrender.com/mcpcurl https://batteries-plus-mcp.onrender.com/healthIf you haven't already authenticated to your Salesforce org:
sf org login web --alias batteries-demoUse your admin credentials (not the Agentforce agent user credentials).
Manual steps (you will do this in the Salesforce UI):
| Field | Value |
|---|---|
| MCP Server Name | Batteries Plus Service |
| MCP Endpoint URL | https://batteries-plus-mcp.onrender.com/mcp |
| Authorization Token URL | https://batteries-plus-mcp.onrender.com/oauth/token |
| Client ID | batteries-plus-agentforce-client |
| Client Secret | Your `MCP_CLIENT_SECRET` from Render |
| Scope | mcp.tools |
Click Save & Test Connection. You should see "✅ Connection successful".
find_compatible_replacementcheck_store_availabilitycreate_store_handofffind_compatible_replacementcheck_store_availabilitycreate_store_handoffAdd this to your agent instructions:
You are the Batteries Plus Service Agent. You help customers find the right replacement battery, check local store availability, and create store visit summaries.
When a customer describes a vehicle issue (e.g., "car won't start"), follow this workflow:
1. Ask for vehicle details: year, make, model (and engine if possible)
2. Use find_compatible_replacement to identify the right battery
3. Ask for customer location (postal code)
4. Use check_store_availability to find nearby stores with inventory
5. Present store options with availability, distance, and services
6. IMPORTANT: Wait for the customer to confirm their store choice
7. Only after confirmation, use create_store_handoff with customer_confirmed_store=true
Do not create orders, reservations, or process payments. Your role is to prepare a service handoff for in-store battery testing and installation.Test Conversation Script:
Customer: My car won't start and I think I need a new battery. I drive a 2019 Honda CR-V and I'm near 53202. Can you help me find the right one nearby?
Expected Agent Behavior:
find_compatible_replacement → identifies SLI51RAGM (X2Power Premium AGM Battery - Group 51R)check_store_availability → finds stores near 53202create_store_handoff with customer_confirmed_store=trueProblem: MCP tools don't appear in Agentforce actions picker
Agentforce MCP Support Pilot permission is enabled on your orgProblem: Connection test fails with "401 Unauthorized"
MCP_CLIENT_ID and MCP_CLIENT_SECRET match between Render and SalesforceMCP_AUTH_MODE=oauth is set in Render environmentProblem: Tools return empty or error responses
batteries-plus-mcp → Logsx-sfdc-mcp-debug = 0x3fProblem: Agent doesn't use MCP tools
Edit src/data/batteries.ts and add entries to the vehicleFitDatabase array:
{
vehicle_year: 2022,
vehicle_make: 'Tesla',
vehicle_model: 'Model 3',
vehicle_engine: 'Electric',
recommended_sku: 'EV12V-AUX',
product_name: 'Auxiliary 12V Battery for Tesla',
group_size: 'Tesla OEM',
cold_cranking_amps: 340,
reserve_capacity_minutes: 50,
warranty_months: 24,
install_eligible: false
}Edit src/data/stores.ts and add entries to the storeDatabase array:
{
store_id: 'BP-CHI-004',
store_name: 'Batteries Plus - Chicago Loop',
postal_codes: ['60601', '60602'],
address: '123 State St, Chicago, IL 60601',
distance_miles: 0.5,
phone: '(312) 555-0200',
today_hours: '9:00 AM - 6:00 PM',
services: ['Battery testing', 'Battery installation', 'Curbside pickup'],
inventory: {
'SLI51RAGM': 3,
'SLI24FAGM': 2,
'SLI35AGM': 5
}
}This is for future integration. To write handoffs to Salesforce instead of memory:
WRITE_MODE=salesforce in .env SF_LOGIN_URL=https://login.salesforce.com
SF_CLIENT_ID=<connected_app_consumer_key>
SF_CLIENT_SECRET=<connected_app_consumer_secret>
SF_USERNAME=<integration_user_username>
SF_PASSWORD=<integration_user_password>
SF_INSTANCE_URL=https://yourorg.my.salesforce.comCurrent implementation throws "not yet implemented" when WRITE_MODE=salesforce.
This server implements MCP via Streamable HTTP transport (recommended for remote servers). Agentforce sends JSON-RPC 2.0 requests to the /mcp endpoint using Server-Sent Events (SSE) for streaming responses.
Supported Methods:
tools/list — Returns tool schemastools/call — Executes a tool with provided argumentsWhen MCP_AUTH_MODE=oauth:
/oauth/token using client credentials grantclient_id and client_secretMCP_CLIENT_SECRETAuthorization: Bearer <token> on subsequent /mcp requestsTokens expire after MCP_TOKEN_TTL_SECONDS (default: 1 hour).
/tmp/batteries-plus-handoffs.jsonFor production, replace with:
MIT
For issues or questions about this demo server, contact:
Built with [Model Context Protocol](https://modelcontextprotocol.io) SDK v1.0.4
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.