Connect PriceLabs to Claude
A read-only MCP server so Claude can query your PriceLabs listings and current dynamic prices.
This server only exposes GET endpoints. Claude can query your listings and current prices but can't push overrides or change pricing rules. Add POST handlers if you need writes.
What you'll be able to ask Claude
Prerequisites
- PriceLabs account with at least one listing synced. The Customer API is available on all PriceLabs plans but is billed at $1 per synced listing per month for usage.
- Claude Desktop installed, or the Claude Code CLI. Download Claude Desktop.
- Node.js 18 or later. Check with
node --version.
Enable the Customer API and generate an API key
PriceLabs has two separate APIs: the Customer API (what we want, self-serve, for your own listings) and the Dynamic Pricing API (partner-only, for PMS vendors). We're only touching the Customer API.
- Log in to app.pricelabs.co.
- Open Account Settings (click your name or avatar in the top right).
- Find the API Details section.
- Click Enable, then select I Need API Access from the pop-up.
- Copy your API key. It's a long random string.
Note on billing: PriceLabs charges $1 per synced listing per month for Customer API access. If you're on the free tier of PriceLabs with 0 listings, you won't get charged. If you have 50 listings, it's $50/month. Worth knowing before you enable.
Set up the Node.js project
Two dependencies: the MCP SDK and zod. PriceLabs doesn't have an official Node SDK so we make HTTP calls directly.
mkdir pricelabs-mcp
cd pricelabs-mcp
npm init -y
npm install @modelcontextprotocol/sdk zod
Add "type": "module" to package.json:
{
"name": "pricelabs-mcp",
"version": "1.0.0",
"type": "module",
"main": "index.js",
"dependencies": {
"@modelcontextprotocol/sdk": "^1.0.0",
"zod": "^3.22.0"
}
}
Create the MCP server file
Save the following as index.js. The server exposes three read-only tools: list-listings, get-listing-prices, and list-reservations.
#!/usr/bin/env node
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
const API_KEY = process.env.PRICELABS_API_KEY;
const BASE_URL = "https://api.pricelabs.co/v1";
if (!API_KEY) {
console.error("Missing PRICELABS_API_KEY environment variable");
process.exit(1);
}
async function pricelabsGet(path, params = {}) {
const url = new URL(`${BASE_URL}${path}`);
for (const [key, value] of Object.entries(params)) {
if (value !== undefined && value !== null && value !== "") {
url.searchParams.append(key, String(value));
}
}
const response = await fetch(url.toString(), {
method: "GET",
headers: {
"X-API-Key": API_KEY,
Accept: "application/json",
"User-Agent": "rapideye-pricelabs-mcp/1.0",
},
});
if (!response.ok) {
const body = await response.text();
throw new Error(`PriceLabs API ${response.status}: ${body}`);
}
return response.json();
}
const server = new McpServer({
name: "pricelabs",
version: "1.0.0",
});
// Tool 1: List synced listings
server.tool(
"list-listings",
"List all listings synced to PriceLabs across your connected PMSes. Returns listing ID, name, source PMS, sync status, and base price settings. Use this first to discover listing IDs for other queries.",
{},
async () => {
const data = await pricelabsGet("/listings");
return {
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
};
}
);
// Tool 2: Get current dynamic prices for a listing
server.tool(
"get-listing-prices",
"Fetch the current dynamic price recommendations for a specific listing across a date range. Returns date-by-date recommended nightly rate, minimum stay, and availability signals.",
{
listing_id: z
.string()
.describe("PriceLabs listing ID (get from list-listings)"),
pms: z
.string()
.optional()
.describe("Source PMS name if required by your account (e.g. 'hostaway', 'guesty', 'ownerrez')"),
date_from: z
.string()
.optional()
.describe("Start date in YYYY-MM-DD format. Defaults to today."),
date_to: z
.string()
.optional()
.describe("End date in YYYY-MM-DD format. Defaults to 30 days from today."),
},
async ({ listing_id, pms, date_from, date_to }) => {
const today = new Date();
const thirtyDaysOut = new Date(Date.now() + 30 * 24 * 60 * 60 * 1000);
const data = await pricelabsGet("/listing_prices", {
listing_id,
pms,
date_from: date_from || today.toISOString().slice(0, 10),
date_to: date_to || thirtyDaysOut.toISOString().slice(0, 10),
});
return {
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
};
}
);
// Tool 3: List reservations synced to PriceLabs
server.tool(
"list-reservations",
"List reservations that have been synced into PriceLabs from your connected PMSes. Useful for cross-referencing with dynamic price recommendations.",
{
listing_id: z
.string()
.optional()
.describe("Optional listing ID to filter by. Omit to return all."),
},
async ({ listing_id }) => {
const data = await pricelabsGet("/reservations", { listing_id });
return {
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
};
}
);
const transport = new StdioServerTransport();
await server.connect(transport);
If your account returns 404s on these paths, check the troubleshooting section below — PriceLabs' full Customer API Swagger is behind a SwaggerHub login, so exact paths may drift.
Register the server with Claude Desktop
Open your Claude Desktop config file:
~/Library/Application Support/Claude/claude_desktop_config.json
%APPDATA%\Claude\claude_desktop_config.json
Add the PriceLabs entry (merge it into your existing mcpServers block if you already set up other guides from this series):
{
"mcpServers": {
"pricelabs": {
"command": "node",
"args": ["/absolute/path/to/pricelabs-mcp/index.js"],
"env": {
"PRICELABS_API_KEY": "your_pricelabs_api_key_here"
}
}
}
}
Replace the path and API key with your real values. Then fully quit and reopen Claude Desktop.
Try it
"For each of my listings, what's the recommended price spread between minimum and maximum night over the next 30 days? Rank by biggest spread."
Troubleshooting
401 Unauthorized or "invalid API key"
Your API key is wrong or API access isn't enabled. Re-check Account Settings → API Details in PriceLabs. The key is only shown once; if you lost it, regenerate.
Also verify the header in the code is X-API-Key exactly (not x-api-key, not Authorization, not API-Key). PriceLabs is case-sensitive on the header name.
404 on /listings or /listing_prices
The endpoint paths in this guide are based on PriceLabs' public help articles. If your account's actual paths differ, log in to PriceLabs, go to Account Settings → API Details, and follow the link to the Customer API Swagger documentation on SwaggerHub. That spec has the exact paths. Update the strings in index.js accordingly.
Claude says it doesn't see any PriceLabs tools
Claude Desktop only reads the config file at startup. Fully quit Claude (Cmd+Q on macOS, right-click tray icon → Quit on Windows) and reopen it. Closing the window doesn't reload the config.
Still broken? Check Help → Open Logs Folder for a startup error. Common causes: invalid JSON in the config file, wrong absolute path to index.js, or node not being in your PATH.
"Cannot find module '@modelcontextprotocol/sdk/server/mcp.js'"
The dependency wasn't installed or you ran node index.js from outside the project directory. Run npm install inside pricelabs-mcp and make sure "type": "module" is in package.json.
I want to add write operations (price overrides, min-stay updates)
The guide ships read-only intentionally. To add write operations, copy the server.tool() pattern and swap the fetch call's method to POST with a JSON body. Consult your PriceLabs Customer API Swagger spec for the exact write endpoints and request shapes.
We'd recommend keeping a read-only server separate from a write server so Claude can't accidentally push pricing changes while you're exploring.
Other guides
Connect Safely to Claude
Verification status, claims, and damage coverage. The cleanest public API in the STR ancillary stack.
Connect OwnerRez to Claude
Bookings, properties, guests, and payments. Biggest US PMS Cole Rubin didn't cover.
Connect Seam to Claude
One connector wraps 12+ lock brands plus Minut, NoiseAware, and ecobee/Nest thermostats.