beds24-mcp-server
v1.1.5
Published
MCP server + CLI + SDK for the Beds24 API — semantic search over cited docs, YAML schema validation, and a dependency-free TS SDK.
Maintainers
Readme
beds24-mcp-server
MCP server + CLI + SDK for the Beds24 API. Two complementary layers over the same source of truth:
- Semantic search — vector index over the cited markdown docs (
beds24-search). Answers "how does pricing propagate?", "what are channel source IDs?". - Schema validation — resolves
apiV2.yamland validates draft payloads (beds24-validate). Answers "what's wrong with my POST /bookings payload?".
The markdown facts in knowledge/ + knowledge/apiV2.yaml are the source of truth. The .beds24/ vector index is a regenerable cache (bun run index). The SDK (src/sdk/) has zero MCP dependency so it can be imported from other repos (data-plattform, workflows, etc.).
Install
Global (recommended — harness-available everywhere)
npm install -g beds24-mcp-serverThis publishes the beds24-mcp-server command. Then auto-configure your harness(es):
beds24-mcp-server setup # detects Claude Code / Cursor / Windsurf / VS Code, writes their MCP configThat's it — setup writes the config, runs bun install (if needed), and builds the vector index. Restart your harness; the tools appear.
Run beds24-mcp-server setup --dry-run to preview the writes without touching anything, or --harness claude --harness cursor to pick specific ones. Use --skip-index if you want to build the index later.
Local / from source
bun install
bun run index # build the vector index from knowledge/*.md (one-time, ~30s)
# or let it auto-index on first server startTo configure harnesses from a source checkout:
bun run setup # same detection + config writing as the global commandUsing the SDK from another repo
The SDK has no MCP dependency — just point it at the facts + yaml:
import { Beds24Validator, Beds24Search } from "beds24-mcp-server/sdk";
const validator = Beds24Validator.create({ factsDir: "path/to/knowledge" });
const result = await validator.validate("POST /bookings", "request", payload);
// result.valid, result.errors — feed errors back to your LLM to fix the callThis lets you run schema validation from a dagster asset, an inngest function, or a CLI — no MCP server needed.
Using the client
A dependency-free HTTP client (global fetch, Node 18+) with 24h-token auth, automatic token refresh on 401, request validation, and credit-limit tracking:
import { Beds24Client } from "beds24-mcp-server/client";
const client = new Beds24Client({ apiKey: "...", propKey: "..." });
const { data, credits } = await client.request("GET /bookings", {
arrival: "2026-08-01",
departure: "2026-08-05",
});
// credits.remaining / credits.resetsIn — the 5-minute rate-limit windowEvery METHOD /path in apiV2.yaml is reachable via client.request(key, body). Request bodies are validated against the schema before sending (fail fast, save a credit). Throws Beds24Error with status, code, retryable, and creditsRemaining.
Configure (your harness)
All harnesses speak the same MCP JSON shape; only the config file location differs.
The shared block (paste into command / args below). Prefer the global command if you installed via npm — it survives reinstalls and doesn't hard-code a checkout path:
{
"command": "beds24-mcp-server",
"args": ["serve"]
}Falling back to a source checkout (replaces /ABSOLUTE/PATH/to/beds24-mcp):
{
"command": "bun",
"args": ["run", "/ABSOLUTE/PATH/to/beds24-mcp/src/server.ts"]
}Run
beds24-mcp-server setup(orbun run setup) to write these files automatically — no hand-editing needed.
Claude Code
Project-level .mcp.json (committed, shared with the team) or user-level ~/.claude/.mcp.json (just you):
{
"mcpServers": {
"beds24": {
"command": "bun",
"args": ["run", "/ABSOLUTE/PATH/to/beds24-mcp/src/server.ts"]
}
}
}Restart Claude Code. Tools appear in every session.
Cursor
Global ~/.cursor/mcp.json (all projects) or project .cursor/mcp.json:
{
"mcpServers": {
"beds24": {
"command": "bun",
"args": ["run", "/ABSOLUTE/PATH/to/beds24-mcp/src/server.ts"]
}
}
}Open Cursor Settings → MCP; the server should show green. If not, click Restart all servers (it must resolve bun on your $PATH — launch Cursor from a shell or add the bun path to the config's env).
Windsurf
~/.codeium/windsurf/mcp_config.json:
{
"mcpServers": {
"beds24": {
"command": "bun",
"args": ["run", "/ABSOLUTE/PATH/to/beds24-mcp/src/server.ts"]
}
}
}Reload the window / restart Windsurf to pick it up.
VS Code (Copilot)
Project-level .vscode/mcp.json:
{
"servers": {
"beds24": {
"command": "bun",
"args": ["run", "/ABSOLUTE/PATH/to/beds24-mcp/src/server.ts"]
}
}
}Note: VS Code uses
servers(notmcpServers). Restart VS Code after editing.
Any other harness (OpenCode, goose, …)
The shape is the same — look in your harness's settings for "MCP servers" and register a server named beds24 with the command / args block above.
Troubleshooting
- "bun not found" — the harness doesn't inherit your shell
$PATH. Launch it from a terminal, or add the bun dir to the server'senv(e.g."env": { "PATH": "/Users/you/.bun/bin:/usr/bin:/bin" }). - No tools after restart — the server auto-indexes on first run and logs to stderr. Open the harness's MCP/output panel and look for
[beds24] MCP server connected on stdio.. If it shows an error, re-runbun install && bun run indexin the repo. - Stale facts — after updating
knowledge/, runbun run index(or just delete.beds24/and restart; it rebuilds).
Tools
| Tool | Input | Output |
|------|-------|--------|
| beds24_search | query: string, topK?: number | top section hits {text, sourceFile, headingPath, lines, score} |
| beds24_schema | endpoint: string, direction: "request"\|"response" | resolved field list {name, type, required, description, enum?} |
| beds24_validate | endpoint: string, direction, payload: object | {valid, errors: [{path, message, expected, actual}]} |
| beds24_howto | task: string | search hits + matching schema + steps summary |
| beds24_status | — | {factsFiles, chunksIndexed, dbSize} |
Source layout
.
├── knowledge/ # facts + OpenAPI spec (source of truth)
│ ├── index.md, api-v2/, pricing/, system-logic/ ...
│ └── apiV2.yaml
├── src/
│ ├── sdk/ # REUSABLE TS SDK (no MCP deps — import from other repos)
│ │ ├── index.ts # re-exports
│ │ ├── db.ts # libsql store + sqlite-vec cosine index
│ │ ├── embed.ts # local embedding model (Xenova/all-MiniLM-L6-v2)
│ │ ├── chunk.ts # markdown splitter (heading-aware, keeps citations)
│ │ ├── indexer.ts # walk facts → section chunks → embed → store
│ │ ├── search.ts # vector search + section lookup
│ │ ├── schema.ts # parse apiV2.yaml → resolve $ref/allOf/oneOf
│ │ └── validate.ts # draft payload → structured LLM-friendly errors
│ ├── server.ts # thin MCP wrapper over the SDK (MCP deps only here)
│ └── cli.ts # thin CLI wrapper over the SDK (`beds24-mcp-server index|status`)
├── .beds24/ # generated vector index (gitignored)
└── package.jsonIndexing strategy (important)
The facts are already split by statement + source + date. Do NOT shred into fixed-size chunks — that destroys citations and mixes unrelated facts ("vector soup").
Instead, split at section (##) / subsection (###) boundaries. Each index entry = one section, storing its heading path, full text (citations inline), source file, and line range. A query lands precisely on the relevant cited section.
Structured-table content (the schemas-*.md files and version-reference.md) is better served by the schema/validate tools (exact lookup) than by vector search — route precise field questions there, fuzzy "how does it work" questions to search.
Refresh
When facts change: bun run index rebuilds the index. The server auto-indexes on startup if .beds24/ is missing.
