Command Palette

Search for a command to run...

UnylyUnyly
Весь каталог

Mydatavalue

БесплатноНе проверен

MCP server for querying MyDataValue's Booking.com and Airbnb property data, including pricing, promotions, reviews, and performance metrics, via a read-only con

GitHubEmbed

Описание

MCP server for querying MyDataValue's Booking.com and Airbnb property data, including pricing, promotions, reviews, and performance metrics, via a read-only connector with automatic OAuth token rotation.

README

A small remote MCP (Model Context Protocol) server that lets Claude query the MyDataValue API — Booking.com + Airbnb properties, pricing, promotions, ranking, reviews, demand, compsets, performance, and the change log — as a native connector, instead of copying curl commands around.

It is read-only by design (GET requests only), matching the scope of the MyDataValue API key it was issued.

Why this exists / how the OAuth dance is handled

MyDataValue issues a refresh_token that:

  • is exchanged for a 1-hour access_token via POST /oauth/token
  • rotates on every exchange — the old refresh_token stops working the instant a new one is issued
  • gets your whole integration shut off if an old, already-used refresh_token is replayed (their theft-detection)

That means the refresh token can never live only in a chat transcript, a .env file on a laptop, or this repo — it has to be persisted durably by whatever is running the service, updated atomically on every rotation, and never reused. src/tokenStore.js + src/mdvClient.js do exactly that:

  • the current refresh_token / access_token / expiry live in a JSON file at TOKEN_STORE_PATH (defaults to /data/token-store.json — point this at a mounted persistent volume in production)
  • writes are atomic (temp file + rename) so a crash mid-write can't corrupt the store or leave you holding a half-written token
  • concurrent requests are coalesced onto a single in-flight refresh, so two simultaneous tool calls can never race each other into burning the refresh token twice
  • 401s trigger exactly one forced refresh + retry; 429s honor Retry-After

A note on durability

The first version of this service persisted the rotating refresh_token to a Railway volume mounted at /data. In testing, that turned out not to reliably survive redeploys on this service — a plain redeploy with zero code or config changes came back up unable to find the file it had written seconds earlier, twice in a row. Railway's own docs say this shouldn't happen for a volume-attached service, so the exact cause is unconfirmed (possibly an interaction with this service's multiRegionConfig), but it's reproducible here, and reusing a stale refresh_token is exactly the failure mode MyDataValue treats as a stolen-token replay and locks accounts over — so this service does not rely on the volume for correctness.

Instead, MDV_SEED_REFRESH_TOKEN is the durable source of truth, and it's kept current in place: every time the service rotates the token, it calls Railway's public API (variableUpsert, with skipDeploys: true so it doesn't force a redeploy) to overwrite MDV_SEED_REFRESH_TOKEN with the new value. Env vars have reliably round-tripped through every redeploy in testing, unlike the volume. The next boot - whenever that happens - reads the current value straight from that env var. src/railwayVariable.js implements this; it needs RAILWAY_PROJECT_TOKEN, RAILWAY_PROJECT_ID, and RAILWAY_ENVIRONMENT_ID (RAILWAY_SERVICE_ID optional) to be set. Without those, the service still runs (rotations just live only in memory), but it logs a loud warning on every rotation, because a restart before persistence succeeds means the next boot replays a now-stale token.

The local file at TOKEN_STORE_PATH is still written on a best-effort basis (useful for poking at from Railway's file browser while debugging), but nothing in this service depends on it being there.

Endpoints wired up

Confirmed against MyDataValue's own OpenAPI reference (Booking.com uses property_id path params under /booking/...; Airbnb uses listing_id path params under /airbnb/..., and its collection is specifically named listings, not properties):

  • list_properties/booking/properties/, /airbnb/listings/
  • get_property — single property/listing detail, by id
  • get_pricing/{channel}/pricing/{id}/
  • get_compset/{channel}/compset/{id}/
  • get_promotions/{channel}/promotions/, filterable by id, paginated
  • get_ranking/{channel}/ranking/
  • get_reviews/{channel}/reviews/
  • get_performance/{channel}/performance/
  • get_demand/booking/demand/ (Booking.com only — MyDataValue doesn't expose an Airbnb demand endpoint)
  • get_change_log/change-log/ (a single team-wide feed, not per-channel)
  • get_cancellation_policy_options/airbnb/cancellation-policy-options/{listing_id}/ (Airbnb only)
  • mdv_raw_get — a generic, read-only passthrough for anything above that's missing a param, plus endpoints intentionally left out of scope (auto-refresh state, sync-jobs, tags, webhooks — these are either write-oriented or not part of what this connector's token was issued to read)

A note on MyDataValue's own hosted MCP server

MyDataValue's docs mention they also run an official hosted MCP server at https://mcp.mydatavalue.com/mcp — sign in with your MyDataValue account directly, no Railway service needed. It's a legitimate alternative, but per their own docs it only covers properties, pricing, promotions, and the write levers to act on them; it doesn't expose ranking, reviews, demand, compsets, or the change log the way the REST API (and this connector) does. Worth knowing about if you ever want to act on pricing/promotions from chat, not just read — this connector is deliberately read-only.

Running locally

cp .env.example .env   # fill in MDV_CLIENT_SECRET, MDV_SEED_REFRESH_TOKEN, MCP_ACCESS_TOKEN
npm install
npm start

Deploying

Designed to run on Railway (or any host that gives you a persistent volume):

  1. Deploy this repo.
  2. Attach a persistent volume, mounted at /data.
  3. Set env vars: MDV_CLIENT_ID, MDV_CLIENT_SECRET, MDV_SEED_REFRESH_TOKEN (kept current automatically after the first rotation - see "A note on durability" above), TOKEN_STORE_PATH=/data/token-store.json (best-effort only), MCP_PUBLIC_URL (the exact public HTTPS URL Railway gives the service, no trailing slash), MCP_OAUTH_CLIENT_ID, MCP_OAUTH_CLIENT_SECRET (generate with openssl rand -hex 32), and MCP_ACCESS_TOKEN (also openssl rand -hex 32 — this is now the one-time consent passphrase, see below, not a request header).
  4. For durable refresh-token persistence, create a Railway Project Token (Project Settings → Tokens, scoped to this project) and set it as RAILWAY_PROJECT_TOKEN, plus RAILWAY_PROJECT_ID and RAILWAY_ENVIRONMENT_ID (and RAILWAY_SERVICE_ID if you want variable updates scoped to just this service). Skipping this makes rotations memory-only - fine for a quick test, risky for anything left running.
  5. Generate a public domain.

Connecting it in Claude

Claude's "Add custom connector" dialog only takes a server URL plus, optionally, an OAuth Client ID and OAuth Client Secret in Advanced settings — there's no field for a raw bearer header. So this server implements a minimal (but spec-following) OAuth 2.1 authorization server in front of /mcp: RFC 9728 protected resource metadata, RFC 8414 authorization server metadata, and the authorization_code + PKCE grant plus refresh_token, per the MCP Authorization spec. There's exactly one pre-shared client (this connector) - no Dynamic Client Registration, which the spec allows as an alternative.

To connect:

  1. In Claude, add a custom connector with URL https://<your-domain>/ (either the bare domain or https://<your-domain>/mcp works - both are handled, since it's easy to paste one or the other into that one field).
  2. In Advanced settings, enter MCP_OAUTH_CLIENT_ID as the OAuth Client ID and MCP_OAUTH_CLIENT_SECRET as the OAuth Client Secret.
  3. Claude will open /authorize in a browser tab. Enter the MCP_ACCESS_TOKEN value as the passphrase to approve the connection. This is a one-time step (until the issued token expires/is revoked).

MCP_OAUTH_ALLOWED_REDIRECT_URIS defaults to * (accept any redirect_uri) on first deploy, since Claude's exact callback URL isn't documented. Once you've connected once, check the deploy logs for the redirect_uri that was actually used ([oauthServer] /authorize request - redirect_uri=...) and set MCP_OAUTH_ALLOWED_REDIRECT_URIS to that exact value (comma-separate if there's more than one) to close the open-redirect surface.

Security notes

  • MCP_ACCESS_TOKEN gates the one-time /authorize consent step — anyone who has it (and the client ID) can complete the OAuth flow and mint a token. Treat it like a password. It is no longer sent as a request header.
  • MCP_OAUTH_CLIENT_SECRET and the issued access/refresh tokens are the keys to /mcp itself going forward - keep them as secret as MCP_ACCESS_TOKEN.
  • MDV_CLIENT_SECRET and the rotating MyDataValue refresh_token never leave the server process, Railway's env var store, and (best-effort) its volume. They are not logged in full (only the last 6 characters, for audit purposes).
  • RAILWAY_PROJECT_TOKEN can rewrite this project's env vars - treat it with the same care as the other secrets here.
  • If MyDataValue ever locks you out for a suspected replayed token, contact them to get re-issued, then set a fresh MDV_SEED_REFRESH_TOKEN before redeploying.

from github.com/Elev8-OS/mydatavalue-mcp

Установка Mydatavalue

У этого сервера нет опубликованного пакета — он собирается из исходников. Открой репозиторий и следуй инструкции в README.

▸ github.com/Elev8-OS/mydatavalue-mcp

FAQ

Mydatavalue MCP бесплатный?

Да, Mydatavalue MCP бесплатный — установка в пару кликов через Unyly без оплаты.

Нужен ли API-ключ для Mydatavalue?

Нет, Mydatavalue работает без API-ключей и переменных окружения.

Mydatavalue — hosted или self-hosted?

Доступен hosted-вариант: Unyly запускает сервер в облаке, локальная установка не обязательна.

Как установить Mydatavalue в Claude Desktop, Claude Code или Cursor?

Открой Mydatavalue на unyly.org, выбери вкладку своего клиента (Claude Desktop, Claude Code, Cursor) и нажми Install — конфиг сгенерируется автоматически, без правки JSON.

Похожие MCP

Compare Mydatavalue with

Не уверен что выбрать?

Найди свой стек за 60 секунд

Автор?

Embed-бейдж для README

Похожее

Все в категории development