guesty-mcp-server 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.dockerignore ADDED
@@ -0,0 +1,6 @@
1
+ node_modules
2
+ .git
3
+ .env
4
+ .token-cache.json
5
+ *.md
6
+ LICENSE
package/.env.example ADDED
@@ -0,0 +1,2 @@
1
+ GUESTY_CLIENT_ID=your-client-id-here
2
+ GUESTY_CLIENT_SECRET=your-client-secret-here
package/CHANGELOG.md ADDED
@@ -0,0 +1,32 @@
1
+ # Changelog
2
+
3
+ All notable changes to the Guesty MCP Server will be documented in this file.
4
+
5
+ ## [0.2.0] - 2026-03-26
6
+
7
+ ### Added
8
+ - `create_reservation` - Create direct bookings (website → Guesty)
9
+ - `get_reviews` - Fetch guest reviews from all channels
10
+ - `get_calendar` - Check availability and pricing by date range
11
+ - `update_calendar` - Block/unblock dates, set minimum nights
12
+ - `respond_to_review` - Post responses to guest reviews
13
+ - `get_owner_statements` - Owner revenue statements and reports
14
+ - `get_expenses` - Track operational expenses
15
+ - `get_channels` - List connected booking channels per property
16
+ - `get_tasks` - Fetch cleaning and maintenance tasks
17
+ - Rate limit retry with exponential backoff
18
+ - Token caching module
19
+
20
+ ## [0.1.0] - 2026-03-26
21
+
22
+ ### Added
23
+ - Initial release with 6 core tools
24
+ - `get_reservations` - Fetch reservations with date/listing/status filters
25
+ - `get_listing` - Get property details or list all properties
26
+ - `get_conversations` - Fetch guest message history
27
+ - `send_guest_message` - Send messages to guests in conversations
28
+ - `get_financials` - Revenue, payouts, and commission data
29
+ - `update_pricing` - Update base price or date-specific pricing
30
+ - OAuth2 authentication with automatic token refresh
31
+ - CONTRIBUTING.md for open source contributors
32
+ - MIT License
@@ -0,0 +1,66 @@
1
+ # Contributing to Guesty MCP Server
2
+
3
+ Thank you for your interest in contributing! This is the first MCP server for property management, and community contributions help make it better for everyone.
4
+
5
+ ## Getting Started
6
+
7
+ 1. Fork the repository
8
+ 2. Clone your fork: `git clone https://github.com/YOUR-USERNAME/guesty-mcp-server.git`
9
+ 3. Install dependencies: `npm install`
10
+ 4. Create a `.env` file with your Guesty API credentials (see `.env.example`)
11
+ 5. Run the server: `npm start`
12
+
13
+ ## Adding New Tools
14
+
15
+ Each tool wraps a Guesty API endpoint. To add a new tool:
16
+
17
+ 1. Identify the Guesty API endpoint from [Guesty Open API docs](https://open-api.guesty.com/api-docs)
18
+ 2. Add the tool in `src/server.js` using the `server.tool()` pattern
19
+ 3. Follow the existing naming convention: `verb_noun` (e.g., `get_reservations`, `update_pricing`)
20
+ 4. Include proper Zod schema validation for all parameters
21
+ 5. Return structured JSON in the response
22
+
23
+ ### Tool Template
24
+
25
+ ```javascript
26
+ server.tool(
27
+ "tool_name",
28
+ "Clear description of what this tool does",
29
+ {
30
+ param1: z.string().describe("What this parameter does"),
31
+ param2: z.number().optional().describe("Optional parameter"),
32
+ },
33
+ async (params) => {
34
+ const data = await guestyGet("/endpoint", { key: params.param1 });
35
+ return {
36
+ content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
37
+ };
38
+ }
39
+ );
40
+ ```
41
+
42
+ ## Desired Contributions
43
+
44
+ We'd love help with:
45
+ - **New tools**: Reviews management, task/cleaning scheduling, owner statements, channel management
46
+ - **Testing**: Integration tests, error handling edge cases
47
+ - **Documentation**: Usage examples, video tutorials, blog posts
48
+ - **PMS integrations**: Adapting this pattern for Hostaway, Lodgify, OwnerRez, etc.
49
+
50
+ ## Code Style
51
+
52
+ - ES modules (import/export)
53
+ - Async/await for all API calls
54
+ - Descriptive error messages
55
+ - Keep tools focused -- one API action per tool
56
+
57
+ ## Pull Requests
58
+
59
+ 1. Create a feature branch: `git checkout -b feature/new-tool`
60
+ 2. Make your changes
61
+ 3. Test against the Guesty API
62
+ 4. Submit a PR with a clear description of what the tool does and why
63
+
64
+ ## Questions?
65
+
66
+ Open an issue on GitHub or reach out to [DLJ Properties](https://tinyhomeboutiques.com).
package/Dockerfile ADDED
@@ -0,0 +1,13 @@
1
+ FROM node:18-alpine
2
+
3
+ WORKDIR /app
4
+ COPY package*.json ./
5
+ RUN npm ci --production
6
+ COPY . .
7
+
8
+ ENV GUESTY_CLIENT_ID=""
9
+ ENV GUESTY_CLIENT_SECRET=""
10
+
11
+ EXPOSE 3001 3002
12
+
13
+ CMD ["node", "src/server.js"]
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 DLJ Properties
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,106 @@
1
+ # Guesty MCP Server
2
+
3
+ The first MCP (Model Context Protocol) server for [Guesty](https://guesty.com) property management. Connect AI agents directly to your Guesty account to manage reservations, communicate with guests, track finances, and update pricing -- all autonomously.
4
+
5
+ ## Features
6
+
7
+ | Tool | Description |
8
+ |------|-------------|
9
+ | `get_reservations` | Fetch reservations with filters (dates, listing, status, guest) |
10
+ | `get_listing` | Get property details or list all properties |
11
+ | `get_conversations` | Fetch guest message history |
12
+ | `send_guest_message` | Send messages to guests in conversations |
13
+ | `get_financials` | Revenue, payouts, and commission data |
14
+ | `update_pricing` | Update base price or date-specific pricing |
15
+ | `create_reservation` | Create direct bookings (website → Guesty) |
16
+ | `get_reviews` | Fetch guest reviews from all channels |
17
+ | `get_calendar` | Check availability and pricing by date |
18
+ | `update_calendar` | Block/unblock dates, set minimum nights |
19
+ | `respond_to_review` | Post responses to guest reviews |
20
+ | `get_owner_statements` | Owner revenue statements and reports |
21
+ | `get_expenses` | Track operational expenses |
22
+ | `get_channels` | List connected booking channels per property |
23
+ | `get_tasks` | Fetch cleaning and maintenance tasks |
24
+
25
+ ## Quick Start
26
+
27
+ ### 1. Get Guesty API Credentials
28
+
29
+ 1. Log into [Guesty Dashboard](https://app.guesty.com)
30
+ 2. Go to **Settings > API** (or Marketplace > API Credentials)
31
+ 3. Create an API application with `open-api` scope
32
+ 4. Copy your **Client ID** and **Client Secret**
33
+
34
+ ### 2. Install
35
+
36
+ ```bash
37
+ git clone https://github.com/DLJRealty/guesty-mcp-server.git
38
+ cd guesty-mcp-server
39
+ npm install
40
+ ```
41
+
42
+ ### 3. Configure
43
+
44
+ Set your Guesty credentials as environment variables:
45
+
46
+ ```bash
47
+ export GUESTY_CLIENT_ID="your-client-id"
48
+ export GUESTY_CLIENT_SECRET="your-client-secret"
49
+ ```
50
+
51
+ ### 4. Add to Claude Code
52
+
53
+ Add to your Claude Code settings (`~/.claude/settings.json`):
54
+
55
+ ```json
56
+ {
57
+ "mcpServers": {
58
+ "guesty": {
59
+ "command": "node",
60
+ "args": ["/path/to/guesty-mcp-server/src/server.js"],
61
+ "env": {
62
+ "GUESTY_CLIENT_ID": "your-client-id",
63
+ "GUESTY_CLIENT_SECRET": "your-client-secret"
64
+ }
65
+ }
66
+ }
67
+ }
68
+ ```
69
+
70
+ ### 5. Use
71
+
72
+ Once connected, your AI agent can:
73
+
74
+ ```
75
+ "Show me all reservations checking in this week"
76
+ "What's the total revenue for March?"
77
+ "Send a welcome message to the guest checking in tomorrow"
78
+ "Update the base price for Unit Y to $159"
79
+ "List all my properties with their current status"
80
+ ```
81
+
82
+ ## Use Cases
83
+
84
+ - **Guest Communication**: AI agents auto-respond to guest inquiries using real reservation data
85
+ - **Revenue Management**: Pull financial reports, analyze occupancy, optimize pricing
86
+ - **Operations**: Track check-ins/outs, coordinate cleaning schedules, manage availability
87
+ - **Marketing**: Identify low-occupancy periods, create targeted promotions
88
+ - **Multi-Agent Teams**: Give your entire AI team (CEO, Marketing, CS, Ops) access to property data
89
+
90
+ ## Requirements
91
+
92
+ - Node.js 18+
93
+ - Guesty account with API access (Professional plan or higher)
94
+ - MCP-compatible AI client (Claude Code, OpenClaw, etc.)
95
+
96
+ ## API Reference
97
+
98
+ This server wraps the [Guesty Open API](https://open-api.guesty.com/api-docs). Authentication uses OAuth2 client credentials flow with automatic token caching and refresh.
99
+
100
+ ## Built By
101
+
102
+ [DLJ Properties](https://tinyhomeboutiques.com) -- Running 7 properties with a fully autonomous AI agent team. Built for our own use, shared with the STR community.
103
+
104
+ ## License
105
+
106
+ MIT
package/SECURITY.md ADDED
@@ -0,0 +1,25 @@
1
+ # Security
2
+
3
+ ## API Credentials
4
+
5
+ **Never commit API credentials to version control.**
6
+
7
+ - Store `GUESTY_CLIENT_ID` and `GUESTY_CLIENT_SECRET` as environment variables
8
+ - Use `.env` files locally (already in `.gitignore`)
9
+ - Use secrets management in production (Docker secrets, AWS SSM, etc.)
10
+
11
+ ## Token Handling
12
+
13
+ - OAuth2 tokens are cached in memory with automatic refresh
14
+ - Tokens expire after 24 hours
15
+ - Token cache file (`.token-cache.json`) is gitignored
16
+
17
+ ## API Access
18
+
19
+ - The server uses OAuth2 client credentials flow
20
+ - All API calls go through HTTPS
21
+ - Rate limiting is handled with automatic retry
22
+
23
+ ## Reporting Vulnerabilities
24
+
25
+ If you discover a security vulnerability, please email dljrealty@yahoo.com rather than opening a public issue.
@@ -0,0 +1,32 @@
1
+ # Multi-Account Support Design (v3)
2
+
3
+ ## Overview
4
+ Support managing multiple Guesty accounts from a single MCP server instance.
5
+
6
+ ## Configuration
7
+ ```json
8
+ {
9
+ "accounts": {
10
+ "default": { "clientId": "xxx", "clientSecret": "xxx", "label": "DLJ Properties" },
11
+ "client-abc": { "clientId": "yyy", "clientSecret": "yyy", "label": "ABC Vacation Rentals" }
12
+ }
13
+ }
14
+ ```
15
+
16
+ ## Usage
17
+ Every tool accepts optional `accountId`:
18
+ ```
19
+ get_reservations({ accountId: "client-abc", limit: 10 })
20
+ ```
21
+
22
+ ## Key Features
23
+ - Separate token cache per account
24
+ - Independent rate limit tracking
25
+ - Per-account health checks
26
+ - No cross-account data leakage
27
+ - Audit log per account
28
+
29
+ ## Enterprise Use Cases
30
+ - Property management companies with regional accounts
31
+ - White-label SaaS serving multiple clients
32
+ - Multi-brand hospitality groups
@@ -0,0 +1,12 @@
1
+ {
2
+ "mcpServers": {
3
+ "guesty": {
4
+ "command": "node",
5
+ "args": ["/path/to/guesty-mcp-server/src/server.js"],
6
+ "env": {
7
+ "GUESTY_CLIENT_ID": "your-client-id",
8
+ "GUESTY_CLIENT_SECRET": "your-client-secret"
9
+ }
10
+ }
11
+ }
12
+ }
@@ -0,0 +1,13 @@
1
+ version: '3.8'
2
+ services:
3
+ guesty-mcp:
4
+ build: .
5
+ environment:
6
+ - GUESTY_CLIENT_ID=${GUESTY_CLIENT_ID}
7
+ - GUESTY_CLIENT_SECRET=${GUESTY_CLIENT_SECRET}
8
+ - WEBHOOK_PORT=3001
9
+ - MCP_HTTP_PORT=3002
10
+ ports:
11
+ - "3001:3001"
12
+ - "3002:3002"
13
+ restart: unless-stopped
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "guesty-mcp-server",
3
+ "version": "0.3.0",
4
+ "description": "MCP Server for Guesty Property Management - The first Guesty MCP server",
5
+ "main": "src/server.js",
6
+ "bin": {
7
+ "guesty-mcp-server": "src/server.js",
8
+ "guesty-cli": "src/cli.js"
9
+ },
10
+ "type": "module",
11
+ "scripts": {
12
+ "start": "node src/server.js",
13
+ "test": "node tests/test-tools.js"
14
+ },
15
+ "keywords": [
16
+ "mcp",
17
+ "guesty",
18
+ "property-management",
19
+ "short-term-rental",
20
+ "airbnb",
21
+ "ai-agent"
22
+ ],
23
+ "author": "DLJ Properties",
24
+ "license": "MIT",
25
+ "dependencies": {
26
+ "@modelcontextprotocol/sdk": "latest"
27
+ },
28
+ "repository": {
29
+ "type": "git",
30
+ "url": "https://github.com/DLJRealty/guesty-mcp-server.git"
31
+ },
32
+ "homepage": "https://github.com/DLJRealty/guesty-mcp-server",
33
+ "engines": {
34
+ "node": ">=18.0.0"
35
+ }
36
+ }
package/src/cli.js ADDED
@@ -0,0 +1,101 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Guesty CLI - Command line tool for quick Guesty queries
4
+ * Usage: guesty-cli <command> [options]
5
+ */
6
+
7
+ const GUESTY_CLIENT_ID = process.env.GUESTY_CLIENT_ID;
8
+ const GUESTY_CLIENT_SECRET = process.env.GUESTY_CLIENT_SECRET;
9
+
10
+ if (!GUESTY_CLIENT_ID || !GUESTY_CLIENT_SECRET) {
11
+ console.error("Set GUESTY_CLIENT_ID and GUESTY_CLIENT_SECRET environment variables.");
12
+ process.exit(1);
13
+ }
14
+
15
+ let token = null;
16
+
17
+ async function auth() {
18
+ const res = await fetch("https://open-api.guesty.com/oauth2/token", {
19
+ method: "POST",
20
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
21
+ body: new URLSearchParams({
22
+ grant_type: "client_credentials", scope: "open-api",
23
+ client_id: GUESTY_CLIENT_ID, client_secret: GUESTY_CLIENT_SECRET,
24
+ }),
25
+ });
26
+ const d = await res.json();
27
+ if (!d.access_token) throw new Error("Auth failed");
28
+ token = d.access_token;
29
+ }
30
+
31
+ async function api(path) {
32
+ const res = await fetch(`https://open-api.guesty.com/v1${path}`, {
33
+ headers: { Authorization: `Bearer ${token}` },
34
+ });
35
+ if (!res.ok) throw new Error(`API ${res.status}`);
36
+ return res.json();
37
+ }
38
+
39
+ const commands = {
40
+ reservations: async () => {
41
+ const d = await api("/reservations?limit=10&sort=checkIn&order=desc");
42
+ console.log(`\nUpcoming Reservations (${d.count} total):\n`);
43
+ for (const r of d.results || []) {
44
+ const guest = r.guest?.fullName || "Unknown";
45
+ const dates = `${r.checkIn?.slice(0,10)} → ${r.checkOut?.slice(0,10)}`;
46
+ const listing = r.listing?.title?.slice(0,35) || "?";
47
+ console.log(` ${guest.padEnd(20)} | ${dates} | ${listing}`);
48
+ }
49
+ },
50
+ listings: async () => {
51
+ const d = await api("/listings?limit=25");
52
+ console.log(`\nProperties (${d.count} total):\n`);
53
+ for (const l of d.results || []) {
54
+ const status = l.active ? "ACTIVE" : "OFF";
55
+ console.log(` ${(l.nickname||"?").padEnd(25)} | ${status.padEnd(6)} | ${l.title?.slice(0,40)}`);
56
+ }
57
+ },
58
+ revenue: async () => {
59
+ const d = await api("/reservations?limit=100&fields=money%20guest%20checkIn%20listing%20status");
60
+ let total = 0;
61
+ for (const r of d.results || []) total += r.money?.totalPaid || 0;
62
+ console.log(`\nRevenue Summary:\n Reservations: ${d.count}\n Total Revenue: $${total.toLocaleString()}`);
63
+ },
64
+ reviews: async () => {
65
+ const d = await api("/reviews?limit=5");
66
+ console.log(`\nRecent Reviews (${d.count} total):\n`);
67
+ for (const r of d.results || []) {
68
+ console.log(` ⭐ ${r.rating}/5 | ${r.guest?.fullName || "?"} | ${r.comment?.slice(0,60) || ""}`);
69
+ }
70
+ },
71
+ help: () => {
72
+ console.log(`
73
+ Guesty CLI - Quick property management queries
74
+
75
+ Commands:
76
+ reservations Show upcoming reservations
77
+ listings List all properties
78
+ revenue Revenue summary
79
+ reviews Recent guest reviews
80
+ help Show this help
81
+
82
+ Usage: GUESTY_CLIENT_ID=xxx GUESTY_CLIENT_SECRET=xxx node src/cli.js <command>
83
+ `);
84
+ },
85
+ };
86
+
87
+ const cmd = process.argv[2] || "help";
88
+ if (!commands[cmd]) {
89
+ console.error(`Unknown command: ${cmd}. Run with 'help' for options.`);
90
+ process.exit(1);
91
+ }
92
+
93
+ (async () => {
94
+ try {
95
+ if (cmd !== "help") await auth();
96
+ await commands[cmd]();
97
+ } catch (e) {
98
+ console.error(`Error: ${e.message}`);
99
+ process.exit(1);
100
+ }
101
+ })();
package/src/health.js ADDED
@@ -0,0 +1,43 @@
1
+ import { createServer } from "http";
2
+
3
+ const startTime = Date.now();
4
+ const HEALTH_PORT = parseInt(process.env.HEALTH_PORT || "3003", 10);
5
+
6
+ export function startHealthCheck(guestyAuthFn) {
7
+ const server = createServer(async (req, res) => {
8
+ if (req.url !== "/health" && req.url !== "/") {
9
+ res.writeHead(404);
10
+ res.end("Not Found");
11
+ return;
12
+ }
13
+
14
+ const uptime = Math.floor((Date.now() - startTime) / 1000);
15
+ let guestyStatus = "unknown";
16
+
17
+ try {
18
+ await guestyAuthFn();
19
+ guestyStatus = "connected";
20
+ } catch (e) {
21
+ guestyStatus = `error: ${e.message}`;
22
+ }
23
+
24
+ const health = {
25
+ status: guestyStatus === "connected" ? "healthy" : "degraded",
26
+ uptime: `${Math.floor(uptime / 3600)}h ${Math.floor((uptime % 3600) / 60)}m ${uptime % 60}s`,
27
+ guestyApi: guestyStatus,
28
+ toolCount: 15,
29
+ version: "0.2.0",
30
+ transport: "stdio",
31
+ timestamp: new Date().toISOString(),
32
+ };
33
+
34
+ res.writeHead(200, { "Content-Type": "application/json" });
35
+ res.end(JSON.stringify(health, null, 2));
36
+ });
37
+
38
+ server.listen(HEALTH_PORT, () => {
39
+ console.log(`[health] Health check endpoint at http://localhost:${HEALTH_PORT}/health`);
40
+ });
41
+
42
+ return server;
43
+ }
@@ -0,0 +1,50 @@
1
+ import { createServer } from "http";
2
+
3
+ /**
4
+ * Streamable HTTP Transport for Guesty MCP Server
5
+ * Allows the MCP server to be accessed via HTTP instead of stdio.
6
+ * Useful for remote access, web integrations, and multi-client setups.
7
+ */
8
+
9
+ const HTTP_PORT = parseInt(process.env.MCP_HTTP_PORT || "3002", 10);
10
+
11
+ export function startHttpTransport(server) {
12
+ const httpServer = createServer(async (req, res) => {
13
+ // CORS headers
14
+ res.setHeader("Access-Control-Allow-Origin", "*");
15
+ res.setHeader("Access-Control-Allow-Methods", "POST, OPTIONS");
16
+ res.setHeader("Access-Control-Allow-Headers", "Content-Type");
17
+
18
+ if (req.method === "OPTIONS") {
19
+ res.writeHead(204);
20
+ res.end();
21
+ return;
22
+ }
23
+
24
+ if (req.method !== "POST" || req.url !== "/mcp") {
25
+ res.writeHead(404, { "Content-Type": "application/json" });
26
+ res.end(JSON.stringify({ error: "Use POST /mcp" }));
27
+ return;
28
+ }
29
+
30
+ let body = "";
31
+ for await (const chunk of req) body += chunk;
32
+
33
+ try {
34
+ const request = JSON.parse(body);
35
+ // Forward to MCP server and get response
36
+ // This is a simplified passthrough -- full SSE streaming would need more work
37
+ res.writeHead(200, { "Content-Type": "application/json" });
38
+ res.end(JSON.stringify({ received: true, request }));
39
+ } catch (e) {
40
+ res.writeHead(400, { "Content-Type": "application/json" });
41
+ res.end(JSON.stringify({ error: e.message }));
42
+ }
43
+ });
44
+
45
+ httpServer.listen(HTTP_PORT, () => {
46
+ console.log(`[http] MCP HTTP transport listening on port ${HTTP_PORT}`);
47
+ });
48
+
49
+ return httpServer;
50
+ }