guesty-mcp-server 0.9.1 → 0.9.2
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/README.md
CHANGED
|
@@ -11,6 +11,8 @@ The first MCP (Model Context Protocol) server for [Guesty](https://guesty.com) p
|
|
|
11
11
|
|
|
12
12
|
> **Stay updated:** [Sign up for release notes and new tool announcements](https://guestycopilot.com#signup)
|
|
13
13
|
|
|
14
|
+
> **v0.9.2 (2026-05-21) — Paid tiers launching v1.0 next week.** Free tier (23 read-only tools) is fully functional now: reservations, listings, guests, calendars, financial reports, operations, reviews, and webhook reads. Write operations (create/update/delete) and the full 43-tool surface ship in v1.0 with Stripe-backed paid-tier activation. Until then, paid-tier license keys return a `NOT YET WIRED — PAID TIERS LAUNCH v1.0` refusal — set or omit `GUESTY_MCP_LICENSE_KEY` to use the free tier.
|
|
15
|
+
|
|
14
16
|
## Quick Start
|
|
15
17
|
|
|
16
18
|
```bash
|
package/hero.png
ADDED
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "guesty-mcp-server",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.2",
|
|
4
4
|
"description": "MCP server for Guesty property management — 43 production tools + 7 addressable resource templates covering reservations, guests, messaging, pricing, revenue, tasks, webhooks, and IoT/property-health Enterprise tier.",
|
|
5
5
|
"main": "src/server.js",
|
|
6
6
|
"bin": {
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "guesty-mcp-server",
|
|
3
|
+
"version": "0.9.1",
|
|
4
|
+
"description": "MCP server for Guesty property management — 43 production tools + 7 addressable resource templates covering reservations, guests, messaging, pricing, revenue, tasks, webhooks, and IoT/property-health Enterprise tier.",
|
|
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-enterprise.js && node tests/test-iot.js"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"mcp",
|
|
17
|
+
"mcp-server",
|
|
18
|
+
"model-context-protocol",
|
|
19
|
+
"guesty",
|
|
20
|
+
"property-management",
|
|
21
|
+
"short-term-rental",
|
|
22
|
+
"airbnb",
|
|
23
|
+
"vrbo",
|
|
24
|
+
"vacation-rental",
|
|
25
|
+
"ai-agent",
|
|
26
|
+
"pms",
|
|
27
|
+
"iot",
|
|
28
|
+
"enterprise",
|
|
29
|
+
"hospitality",
|
|
30
|
+
"real-estate",
|
|
31
|
+
"automation"
|
|
32
|
+
],
|
|
33
|
+
"author": "DLJ Properties",
|
|
34
|
+
"license": "MIT",
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"@modelcontextprotocol/sdk": "latest",
|
|
37
|
+
"@vercel/analytics": "^2.0.1",
|
|
38
|
+
"express": "^5.2.1"
|
|
39
|
+
},
|
|
40
|
+
"repository": {
|
|
41
|
+
"type": "git",
|
|
42
|
+
"url": "https://github.com/DLJRealty/guesty-mcp-server.git"
|
|
43
|
+
},
|
|
44
|
+
"homepage": "https://github.com/DLJRealty/guesty-mcp-server",
|
|
45
|
+
"mcpName": "io.github.DLJRealty/guesty",
|
|
46
|
+
"engines": {
|
|
47
|
+
"node": ">=18.0.0"
|
|
48
|
+
}
|
|
49
|
+
}
|
package/src/license.js
CHANGED
|
@@ -1,20 +1,46 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Guesty MCP Server — License Key System (v2)
|
|
3
|
-
*
|
|
3
|
+
*
|
|
4
|
+
* v0.9.2 (2026-05-21): PAID_TIERS_LIVE=false. Paid-tier prefix keys
|
|
5
|
+
* (gmcp_pro_*, gmcp_biz_*, gmcp_ent_*, test_pro/biz/ent) are recognized
|
|
6
|
+
* but tool access is REFUSED with "NOT YET WIRED — PAID TIERS LAUNCH v1.0"
|
|
7
|
+
* message until v1.0 ships Stripe-backed activation. Free tier
|
|
8
|
+
* (23 read-only tools) is fully functional and unchanged. Closes the
|
|
9
|
+
* prefix-match self-mint exploit window for pre-launch OSS readers.
|
|
10
|
+
*
|
|
4
11
|
* 3-Layer Monetization Model (Danny-approved 2026-04-06):
|
|
5
12
|
* - Layer 1: MCP Server = operations/data tool (FREE, lead gen)
|
|
6
|
-
* - Layer 2: Guesty Copilot = SaaS platform (PAID)
|
|
13
|
+
* - Layer 2: Guesty Copilot = SaaS platform (PAID — v1.0)
|
|
7
14
|
* - Layer 3: DLJ Managed AI = premium service (our real IP)
|
|
8
|
-
*
|
|
15
|
+
*
|
|
9
16
|
* FREE tier: Read-only operations data — reservations, listings, calendar,
|
|
10
17
|
* financials, tasks, guest lookup, pricing, occupancy, channels, photos.
|
|
11
|
-
* PRO+ tier: Guest communication — messaging, review responses,
|
|
12
|
-
* creation, reservation writes, listing updates.
|
|
13
|
-
*
|
|
18
|
+
* PRO+ tier (v1.0): Guest communication — messaging, review responses,
|
|
19
|
+
* webhook creation, reservation writes, listing updates. Stripe-backed.
|
|
20
|
+
*
|
|
14
21
|
* Reads GUESTY_MCP_LICENSE_KEY from env.
|
|
15
22
|
* No key or invalid key = free tier (operations data only).
|
|
23
|
+
* Paid-prefix key with PAID_TIERS_LIVE=false = free tools + refusal message
|
|
24
|
+
* on any paid-tier tool call.
|
|
16
25
|
*/
|
|
17
26
|
|
|
27
|
+
// v0.9.2 paid-tier kill-switch.
|
|
28
|
+
// Flip to true ONLY when Stripe webhook + signed-key validation ships in v1.0.
|
|
29
|
+
// While false: paid-prefix keys are accepted as "paid_not_yet_wired" tier,
|
|
30
|
+
// which has the same tool access as free + emits a refusal message on any
|
|
31
|
+
// paid-tier tool call. Prevents prefix-match self-mint exploit.
|
|
32
|
+
const PAID_TIERS_LIVE = false;
|
|
33
|
+
|
|
34
|
+
// Verbatim refusal message — matches HN launch body and README callout.
|
|
35
|
+
// Keep wording stable; HN/Marketing reference this exact string.
|
|
36
|
+
const PAID_TIERS_NOT_WIRED_MSG =
|
|
37
|
+
"NOT YET WIRED — PAID TIERS LAUNCH v1.0\n\n" +
|
|
38
|
+
"The license key you provided is recognized as a paid-tier prefix, but " +
|
|
39
|
+
"paid-tier validation is not yet active in v0.9.2. Free tier (23 read-only " +
|
|
40
|
+
"tools) remains fully functional and unchanged. Paid tiers " +
|
|
41
|
+
"(Pro/Business/Enterprise) ship in v1.0 next week with full Stripe-backed " +
|
|
42
|
+
"activation. Track: https://github.com/DLJRealty/guesty-mcp-server";
|
|
43
|
+
|
|
18
44
|
// Free tier: read-only operations and data tools
|
|
19
45
|
const FREE_TOOLS = [
|
|
20
46
|
// Reservations (read-only)
|
|
@@ -50,6 +76,23 @@ const FREE_TOOLS = [
|
|
|
50
76
|
"get_webhooks",
|
|
51
77
|
];
|
|
52
78
|
|
|
79
|
+
// Enterprise tier: IoT + property aggregator tools (4 total)
|
|
80
|
+
// These ship in active validation per data-integrity gate; require Enterprise license.
|
|
81
|
+
const ENT_TOOLS = [
|
|
82
|
+
"get_readiness_score",
|
|
83
|
+
"get_property_health",
|
|
84
|
+
"submit_checkout_photos",
|
|
85
|
+
"get_maintenance_alerts",
|
|
86
|
+
];
|
|
87
|
+
|
|
88
|
+
// Business tier: operational/SLA features the binary advertises (consumed by getTierInfo).
|
|
89
|
+
// No per-call tool gating — Business unlocks the same 39 base tools as Pro plus the
|
|
90
|
+
// multi-account license terms and priority support promised by guestycopilot.com pricing.
|
|
91
|
+
const BIZ_FEATURES = {
|
|
92
|
+
multiAccountLicense: true,
|
|
93
|
+
prioritySupport: true,
|
|
94
|
+
};
|
|
95
|
+
|
|
53
96
|
// PRO+ gated tools: guest communication, writes, and real-time events
|
|
54
97
|
// send_guest_message, respond_to_review, create_webhook, delete_webhook,
|
|
55
98
|
// create_reservation, update_reservation, create_reservation_note,
|
|
@@ -58,11 +101,21 @@ const FREE_TOOLS = [
|
|
|
58
101
|
// get_conversations (contains message content)
|
|
59
102
|
|
|
60
103
|
// Simple key-to-tier mapping
|
|
61
|
-
//
|
|
62
|
-
//
|
|
104
|
+
// v0.9.2: when PAID_TIERS_LIVE=false, any paid-prefix key resolves to
|
|
105
|
+
// "paid_not_yet_wired" — free tool access + refusal on paid tool calls.
|
|
106
|
+
// v1.0 (planned): Stripe webhook + signed-key DB lookup replaces prefix match.
|
|
63
107
|
function resolveTier(licenseKey) {
|
|
64
108
|
if (!licenseKey) return "free";
|
|
65
109
|
const key = licenseKey.trim();
|
|
110
|
+
const isPaidPrefix =
|
|
111
|
+
key.startsWith("gmcp_ent_") ||
|
|
112
|
+
key.startsWith("gmcp_biz_") ||
|
|
113
|
+
key.startsWith("gmcp_pro_") ||
|
|
114
|
+
key === "test_pro" ||
|
|
115
|
+
key === "test_biz" ||
|
|
116
|
+
key === "test_ent";
|
|
117
|
+
// v0.9.2 kill-switch: paid keys recognized but refused.
|
|
118
|
+
if (isPaidPrefix && !PAID_TIERS_LIVE) return "paid_not_yet_wired";
|
|
66
119
|
if (key.startsWith("gmcp_ent_")) return "enterprise";
|
|
67
120
|
if (key.startsWith("gmcp_biz_")) return "business";
|
|
68
121
|
if (key.startsWith("gmcp_pro_")) return "pro";
|
|
@@ -78,8 +131,16 @@ function getTier() {
|
|
|
78
131
|
|
|
79
132
|
function isToolAllowed(toolName) {
|
|
80
133
|
const tier = getTier();
|
|
81
|
-
|
|
82
|
-
|
|
134
|
+
// v0.9.2: "paid_not_yet_wired" has same tool surface as free.
|
|
135
|
+
if (tier === "free" || tier === "paid_not_yet_wired") {
|
|
136
|
+
return FREE_TOOLS.includes(toolName);
|
|
137
|
+
}
|
|
138
|
+
// Enterprise-tier tools require enterprise license
|
|
139
|
+
if (ENT_TOOLS.includes(toolName)) {
|
|
140
|
+
return tier === "enterprise";
|
|
141
|
+
}
|
|
142
|
+
// All other paid tools (Pro+) allowed for pro / business / enterprise
|
|
143
|
+
return true;
|
|
83
144
|
}
|
|
84
145
|
|
|
85
146
|
function getTierInfo() {
|
|
@@ -88,23 +149,51 @@ function getTierInfo() {
|
|
|
88
149
|
// (get_property_health, submit_checkout_photos, get_maintenance_alerts) = 43.
|
|
89
150
|
// Updated 2026-04-17 for Enterprise Tier MVP merge (Owner msg 6406).
|
|
90
151
|
const totalTools = 43;
|
|
152
|
+
const entToolCount = ENT_TOOLS.length;
|
|
153
|
+
const baseToolCount = totalTools - entToolCount; // 39
|
|
154
|
+
// v0.9.2: paid_not_yet_wired gets same accessible surface as free.
|
|
155
|
+
const accessibleCount =
|
|
156
|
+
tier === "free" || tier === "paid_not_yet_wired" ? FREE_TOOLS.length :
|
|
157
|
+
tier === "enterprise" ? totalTools :
|
|
158
|
+
baseToolCount; // pro / business
|
|
91
159
|
return {
|
|
92
160
|
tier,
|
|
93
161
|
hasKey: !!process.env.GUESTY_MCP_LICENSE_KEY,
|
|
94
162
|
freeToolCount: FREE_TOOLS.length,
|
|
95
|
-
|
|
96
|
-
|
|
163
|
+
baseToolCount,
|
|
164
|
+
entToolCount,
|
|
165
|
+
accessibleToolCount: accessibleCount,
|
|
166
|
+
gatedToolCount: totalTools - accessibleCount,
|
|
167
|
+
unlocked: tier !== "free" && tier !== "paid_not_yet_wired",
|
|
168
|
+
paidTiersLive: PAID_TIERS_LIVE,
|
|
169
|
+
paidKeyDetected: tier === "paid_not_yet_wired",
|
|
170
|
+
bizFeatures: tier === "business" || tier === "enterprise" ? BIZ_FEATURES : null,
|
|
97
171
|
};
|
|
98
172
|
}
|
|
99
173
|
|
|
100
174
|
function gatedHandler(toolName, handler) {
|
|
101
175
|
return async (params) => {
|
|
102
176
|
if (!isToolAllowed(toolName)) {
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
177
|
+
const tier = getTier();
|
|
178
|
+
let msg;
|
|
179
|
+
// v0.9.2: paid-key supplied but tiers not wired yet — refusal-with-context.
|
|
180
|
+
if (tier === "paid_not_yet_wired") {
|
|
181
|
+
msg = PAID_TIERS_NOT_WIRED_MSG;
|
|
182
|
+
} else if (tier === "free") {
|
|
183
|
+
msg = "This tool (" + toolName + ") requires a Pro or higher license. " +
|
|
184
|
+
"Free tier includes " + FREE_TOOLS.length + " operations and data tools. " +
|
|
185
|
+
"Guest messaging, review responses, and write operations require Pro+. " +
|
|
186
|
+
"Upgrade at https://guestycopilot.com/pricing -- " +
|
|
187
|
+
"Set GUESTY_MCP_LICENSE_KEY env var to unlock all 43 tools.";
|
|
188
|
+
} else if (ENT_TOOLS.includes(toolName)) {
|
|
189
|
+
msg = "This tool (" + toolName + ") requires an Enterprise license. " +
|
|
190
|
+
"Your current tier (" + tier + ") includes the 39 base Guesty tools. " +
|
|
191
|
+
"Enterprise adds IoT readiness, property health, checkout photo intake, " +
|
|
192
|
+
"and maintenance alerts (4 additional tools). " +
|
|
193
|
+
"Talk to us at https://guestycopilot.com/pricing";
|
|
194
|
+
} else {
|
|
195
|
+
msg = "This tool (" + toolName + ") is not available in your current tier (" + tier + ").";
|
|
196
|
+
}
|
|
108
197
|
return {
|
|
109
198
|
content: [{ type: "text", text: msg }],
|
|
110
199
|
isError: true,
|
|
@@ -114,4 +203,14 @@ function gatedHandler(toolName, handler) {
|
|
|
114
203
|
};
|
|
115
204
|
}
|
|
116
205
|
|
|
117
|
-
export {
|
|
206
|
+
export {
|
|
207
|
+
getTier,
|
|
208
|
+
isToolAllowed,
|
|
209
|
+
getTierInfo,
|
|
210
|
+
gatedHandler,
|
|
211
|
+
FREE_TOOLS,
|
|
212
|
+
ENT_TOOLS,
|
|
213
|
+
BIZ_FEATURES,
|
|
214
|
+
PAID_TIERS_LIVE,
|
|
215
|
+
PAID_TIERS_NOT_WIRED_MSG,
|
|
216
|
+
};
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Guesty MCP Server — License Key System (v2)
|
|
3
|
+
*
|
|
4
|
+
* 3-Layer Monetization Model (Danny-approved 2026-04-06):
|
|
5
|
+
* - Layer 1: MCP Server = operations/data tool (FREE, lead gen)
|
|
6
|
+
* - Layer 2: Guesty Copilot = SaaS platform (PAID)
|
|
7
|
+
* - Layer 3: DLJ Managed AI = premium service (our real IP)
|
|
8
|
+
*
|
|
9
|
+
* FREE tier: Read-only operations data — reservations, listings, calendar,
|
|
10
|
+
* financials, tasks, guest lookup, pricing, occupancy, channels, photos.
|
|
11
|
+
* PRO+ tier: Guest communication — messaging, review responses, webhook
|
|
12
|
+
* creation, reservation writes, listing updates.
|
|
13
|
+
*
|
|
14
|
+
* Reads GUESTY_MCP_LICENSE_KEY from env.
|
|
15
|
+
* No key or invalid key = free tier (operations data only).
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
// Free tier: read-only operations and data tools
|
|
19
|
+
const FREE_TOOLS = [
|
|
20
|
+
// Reservations (read-only)
|
|
21
|
+
"get_reservations",
|
|
22
|
+
"search_reservations",
|
|
23
|
+
"get_reservation_financials",
|
|
24
|
+
// Listings (read-only)
|
|
25
|
+
"get_listing",
|
|
26
|
+
"get_listing_occupancy",
|
|
27
|
+
"get_listing_pricing",
|
|
28
|
+
"get_photos",
|
|
29
|
+
// Guests (read-only)
|
|
30
|
+
"get_guests",
|
|
31
|
+
"get_guest_by_id",
|
|
32
|
+
// Calendar (read-only)
|
|
33
|
+
"get_calendar",
|
|
34
|
+
"get_calendar_blocks",
|
|
35
|
+
// Financials (read-only)
|
|
36
|
+
"get_financials",
|
|
37
|
+
"get_owner_statements",
|
|
38
|
+
"get_expenses",
|
|
39
|
+
"get_revenue_summary",
|
|
40
|
+
// Operations (read-only)
|
|
41
|
+
"get_tasks",
|
|
42
|
+
"get_channels",
|
|
43
|
+
"get_automation_rules",
|
|
44
|
+
"get_custom_fields",
|
|
45
|
+
"get_account_info",
|
|
46
|
+
"get_supported_languages",
|
|
47
|
+
// Reviews (read-only)
|
|
48
|
+
"get_reviews",
|
|
49
|
+
// Webhooks (read-only)
|
|
50
|
+
"get_webhooks",
|
|
51
|
+
];
|
|
52
|
+
|
|
53
|
+
// PRO+ gated tools: guest communication, writes, and real-time events
|
|
54
|
+
// send_guest_message, respond_to_review, create_webhook, delete_webhook,
|
|
55
|
+
// create_reservation, update_reservation, create_reservation_note,
|
|
56
|
+
// update_pricing, update_calendar, update_listing, update_photos,
|
|
57
|
+
// update_listing_pricing, create_expense, create_task,
|
|
58
|
+
// get_conversations (contains message content)
|
|
59
|
+
|
|
60
|
+
// Simple key-to-tier mapping
|
|
61
|
+
// Production: Stripe webhook or DB lookup
|
|
62
|
+
// For now: keys prefixed gmcp_pro_*, gmcp_biz_*, gmcp_ent_*
|
|
63
|
+
function resolveTier(licenseKey) {
|
|
64
|
+
if (!licenseKey) return "free";
|
|
65
|
+
const key = licenseKey.trim();
|
|
66
|
+
if (key.startsWith("gmcp_ent_")) return "enterprise";
|
|
67
|
+
if (key.startsWith("gmcp_biz_")) return "business";
|
|
68
|
+
if (key.startsWith("gmcp_pro_")) return "pro";
|
|
69
|
+
if (key === "test_pro") return "pro";
|
|
70
|
+
if (key === "test_biz") return "business";
|
|
71
|
+
if (key === "test_ent") return "enterprise";
|
|
72
|
+
return "free";
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function getTier() {
|
|
76
|
+
return resolveTier(process.env.GUESTY_MCP_LICENSE_KEY);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function isToolAllowed(toolName) {
|
|
80
|
+
const tier = getTier();
|
|
81
|
+
if (tier !== "free") return true;
|
|
82
|
+
return FREE_TOOLS.includes(toolName);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function getTierInfo() {
|
|
86
|
+
const tier = getTier();
|
|
87
|
+
// 39 Guesty core tools + 1 IoT (get_readiness_score) + 3 Enterprise aggregators
|
|
88
|
+
// (get_property_health, submit_checkout_photos, get_maintenance_alerts) = 43.
|
|
89
|
+
// Updated 2026-04-17 for Enterprise Tier MVP merge (Owner msg 6406).
|
|
90
|
+
const totalTools = 43;
|
|
91
|
+
return {
|
|
92
|
+
tier,
|
|
93
|
+
hasKey: !!process.env.GUESTY_MCP_LICENSE_KEY,
|
|
94
|
+
freeToolCount: FREE_TOOLS.length,
|
|
95
|
+
gatedToolCount: totalTools - FREE_TOOLS.length,
|
|
96
|
+
unlocked: tier !== "free",
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function gatedHandler(toolName, handler) {
|
|
101
|
+
return async (params) => {
|
|
102
|
+
if (!isToolAllowed(toolName)) {
|
|
103
|
+
const msg = "This tool (" + toolName + ") requires a Pro or higher license. " +
|
|
104
|
+
"Free tier includes " + FREE_TOOLS.length + " operations and data tools. " +
|
|
105
|
+
"Guest messaging, review responses, and write operations require Pro+. " +
|
|
106
|
+
"Upgrade at https://guestycopilot.com/pricing -- " +
|
|
107
|
+
"Set GUESTY_MCP_LICENSE_KEY env var to unlock all 43 tools.";
|
|
108
|
+
return {
|
|
109
|
+
content: [{ type: "text", text: msg }],
|
|
110
|
+
isError: true,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
return handler(params);
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export { getTier, isToolAllowed, getTierInfo, gatedHandler, FREE_TOOLS };
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Guesty MCP Server — License Key System (v2)
|
|
3
|
+
*
|
|
4
|
+
* 3-Layer Monetization Model (Danny-approved 2026-04-06):
|
|
5
|
+
* - Layer 1: MCP Server = operations/data tool (FREE, lead gen)
|
|
6
|
+
* - Layer 2: Guesty Copilot = SaaS platform (PAID)
|
|
7
|
+
* - Layer 3: DLJ Managed AI = premium service (our real IP)
|
|
8
|
+
*
|
|
9
|
+
* FREE tier: Read-only operations data — reservations, listings, calendar,
|
|
10
|
+
* financials, tasks, guest lookup, pricing, occupancy, channels, photos.
|
|
11
|
+
* PRO+ tier: Guest communication — messaging, review responses, webhook
|
|
12
|
+
* creation, reservation writes, listing updates.
|
|
13
|
+
*
|
|
14
|
+
* Reads GUESTY_MCP_LICENSE_KEY from env.
|
|
15
|
+
* No key or invalid key = free tier (operations data only).
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
// Free tier: read-only operations and data tools
|
|
19
|
+
const FREE_TOOLS = [
|
|
20
|
+
// Reservations (read-only)
|
|
21
|
+
"get_reservations",
|
|
22
|
+
"search_reservations",
|
|
23
|
+
"get_reservation_financials",
|
|
24
|
+
// Listings (read-only)
|
|
25
|
+
"get_listing",
|
|
26
|
+
"get_listing_occupancy",
|
|
27
|
+
"get_listing_pricing",
|
|
28
|
+
"get_photos",
|
|
29
|
+
// Guests (read-only)
|
|
30
|
+
"get_guests",
|
|
31
|
+
"get_guest_by_id",
|
|
32
|
+
// Calendar (read-only)
|
|
33
|
+
"get_calendar",
|
|
34
|
+
"get_calendar_blocks",
|
|
35
|
+
// Financials (read-only)
|
|
36
|
+
"get_financials",
|
|
37
|
+
"get_owner_statements",
|
|
38
|
+
"get_expenses",
|
|
39
|
+
"get_revenue_summary",
|
|
40
|
+
// Operations (read-only)
|
|
41
|
+
"get_tasks",
|
|
42
|
+
"get_channels",
|
|
43
|
+
"get_automation_rules",
|
|
44
|
+
"get_custom_fields",
|
|
45
|
+
"get_account_info",
|
|
46
|
+
"get_supported_languages",
|
|
47
|
+
// Reviews (read-only)
|
|
48
|
+
"get_reviews",
|
|
49
|
+
// Webhooks (read-only)
|
|
50
|
+
"get_webhooks",
|
|
51
|
+
];
|
|
52
|
+
|
|
53
|
+
// Enterprise tier: IoT + property aggregator tools (4 total)
|
|
54
|
+
// These ship in active validation per data-integrity gate; require Enterprise license.
|
|
55
|
+
const ENT_TOOLS = [
|
|
56
|
+
"get_readiness_score",
|
|
57
|
+
"get_property_health",
|
|
58
|
+
"submit_checkout_photos",
|
|
59
|
+
"get_maintenance_alerts",
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
// Business tier: operational/SLA features the binary advertises (consumed by getTierInfo).
|
|
63
|
+
// No per-call tool gating — Business unlocks the same 39 base tools as Pro plus the
|
|
64
|
+
// multi-account license terms and priority support promised by guestycopilot.com pricing.
|
|
65
|
+
const BIZ_FEATURES = {
|
|
66
|
+
multiAccountLicense: true,
|
|
67
|
+
prioritySupport: true,
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
// PRO+ gated tools: guest communication, writes, and real-time events
|
|
71
|
+
// send_guest_message, respond_to_review, create_webhook, delete_webhook,
|
|
72
|
+
// create_reservation, update_reservation, create_reservation_note,
|
|
73
|
+
// update_pricing, update_calendar, update_listing, update_photos,
|
|
74
|
+
// update_listing_pricing, create_expense, create_task,
|
|
75
|
+
// get_conversations (contains message content)
|
|
76
|
+
|
|
77
|
+
// Simple key-to-tier mapping
|
|
78
|
+
// Production: Stripe webhook or DB lookup
|
|
79
|
+
// For now: keys prefixed gmcp_pro_*, gmcp_biz_*, gmcp_ent_*
|
|
80
|
+
function resolveTier(licenseKey) {
|
|
81
|
+
if (!licenseKey) return "free";
|
|
82
|
+
const key = licenseKey.trim();
|
|
83
|
+
if (key.startsWith("gmcp_ent_")) return "enterprise";
|
|
84
|
+
if (key.startsWith("gmcp_biz_")) return "business";
|
|
85
|
+
if (key.startsWith("gmcp_pro_")) return "pro";
|
|
86
|
+
if (key === "test_pro") return "pro";
|
|
87
|
+
if (key === "test_biz") return "business";
|
|
88
|
+
if (key === "test_ent") return "enterprise";
|
|
89
|
+
return "free";
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function getTier() {
|
|
93
|
+
return resolveTier(process.env.GUESTY_MCP_LICENSE_KEY);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function isToolAllowed(toolName) {
|
|
97
|
+
const tier = getTier();
|
|
98
|
+
if (tier === "free") {
|
|
99
|
+
return FREE_TOOLS.includes(toolName);
|
|
100
|
+
}
|
|
101
|
+
// Enterprise-tier tools require enterprise license
|
|
102
|
+
if (ENT_TOOLS.includes(toolName)) {
|
|
103
|
+
return tier === "enterprise";
|
|
104
|
+
}
|
|
105
|
+
// All other paid tools (Pro+) allowed for pro / business / enterprise
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function getTierInfo() {
|
|
110
|
+
const tier = getTier();
|
|
111
|
+
// 39 Guesty core tools + 1 IoT (get_readiness_score) + 3 Enterprise aggregators
|
|
112
|
+
// (get_property_health, submit_checkout_photos, get_maintenance_alerts) = 43.
|
|
113
|
+
// Updated 2026-04-17 for Enterprise Tier MVP merge (Owner msg 6406).
|
|
114
|
+
const totalTools = 43;
|
|
115
|
+
const entToolCount = ENT_TOOLS.length;
|
|
116
|
+
const baseToolCount = totalTools - entToolCount; // 39
|
|
117
|
+
const accessibleCount =
|
|
118
|
+
tier === "free" ? FREE_TOOLS.length :
|
|
119
|
+
tier === "enterprise" ? totalTools :
|
|
120
|
+
baseToolCount; // pro / business
|
|
121
|
+
return {
|
|
122
|
+
tier,
|
|
123
|
+
hasKey: !!process.env.GUESTY_MCP_LICENSE_KEY,
|
|
124
|
+
freeToolCount: FREE_TOOLS.length,
|
|
125
|
+
baseToolCount,
|
|
126
|
+
entToolCount,
|
|
127
|
+
accessibleToolCount: accessibleCount,
|
|
128
|
+
gatedToolCount: totalTools - accessibleCount,
|
|
129
|
+
unlocked: tier !== "free",
|
|
130
|
+
bizFeatures: tier === "business" || tier === "enterprise" ? BIZ_FEATURES : null,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function gatedHandler(toolName, handler) {
|
|
135
|
+
return async (params) => {
|
|
136
|
+
if (!isToolAllowed(toolName)) {
|
|
137
|
+
const tier = getTier();
|
|
138
|
+
let msg;
|
|
139
|
+
if (tier === "free") {
|
|
140
|
+
msg = "This tool (" + toolName + ") requires a Pro or higher license. " +
|
|
141
|
+
"Free tier includes " + FREE_TOOLS.length + " operations and data tools. " +
|
|
142
|
+
"Guest messaging, review responses, and write operations require Pro+. " +
|
|
143
|
+
"Upgrade at https://guestycopilot.com/pricing -- " +
|
|
144
|
+
"Set GUESTY_MCP_LICENSE_KEY env var to unlock all 43 tools.";
|
|
145
|
+
} else if (ENT_TOOLS.includes(toolName)) {
|
|
146
|
+
msg = "This tool (" + toolName + ") requires an Enterprise license. " +
|
|
147
|
+
"Your current tier (" + tier + ") includes the 39 base Guesty tools. " +
|
|
148
|
+
"Enterprise adds IoT readiness, property health, checkout photo intake, " +
|
|
149
|
+
"and maintenance alerts (4 additional tools). " +
|
|
150
|
+
"Talk to us at https://guestycopilot.com/pricing";
|
|
151
|
+
} else {
|
|
152
|
+
msg = "This tool (" + toolName + ") is not available in your current tier (" + tier + ").";
|
|
153
|
+
}
|
|
154
|
+
return {
|
|
155
|
+
content: [{ type: "text", text: msg }],
|
|
156
|
+
isError: true,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
return handler(params);
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export { getTier, isToolAllowed, getTierInfo, gatedHandler, FREE_TOOLS, ENT_TOOLS, BIZ_FEATURES };
|