@curless/clubmed-demo 0.2.0 → 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/dist/index.js +47 -21
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -3,24 +3,32 @@ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
|
3
3
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
4
|
import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
5
5
|
// @curless/clubmed-demo — a SIMULATED "Club Med" storefront MCP for the BUYER.
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
6
|
+
// Booking is end-to-end agentic:
|
|
7
|
+
// 1. browse + start a booking via Club Med's merchant backend
|
|
8
|
+
// (mcp.curless.ai/clubmed) — the merchant prices it and opens a
|
|
9
|
+
// merchant-quoted ACP checkout session with its own key;
|
|
10
|
+
// 2. THIS buyer agent completes the charge over ACP with its own payment
|
|
11
|
+
// credential (test card) — the merchant set the price, the agent pays.
|
|
12
|
+
// The storefront never sees the merchant's key; it holds only its OWN buyer
|
|
13
|
+
// token, exactly like a real agent buyer.
|
|
11
14
|
//
|
|
12
15
|
// Run (Claude Desktop / any MCP client):
|
|
13
16
|
// npx -y @curless/clubmed-demo
|
|
14
|
-
// with env
|
|
15
|
-
//
|
|
16
|
-
//
|
|
17
|
-
//
|
|
17
|
+
// with env:
|
|
18
|
+
// AGENTBANK_AGENT_TOKEN the buyer's agentbank agent key (agb_…, agent:execute).
|
|
19
|
+
// Use a TEST, no-org key (the demo org is shared).
|
|
20
|
+
// AGENTBANK_API_URL base URL (default https://mcp.curless.ai; set
|
|
21
|
+
// http://localhost:3000 for local dev).
|
|
22
|
+
// AGENTBANK_PAYMENT_TOKEN delegated card token (default pm_card_visa).
|
|
18
23
|
//
|
|
19
24
|
// IMPORTANT: only JSON-RPC may be written to stdout (the MCP stdio transport).
|
|
20
25
|
// Never console.log here — diagnostics go to stderr.
|
|
21
26
|
const API_BASE = (process.env.AGENTBANK_API_URL ?? 'https://mcp.curless.ai').replace(/\/$/, '');
|
|
22
27
|
const CLUBMED = `${API_BASE}/clubmed`;
|
|
23
|
-
const
|
|
28
|
+
const TOKEN = process.env.AGENTBANK_AGENT_TOKEN;
|
|
29
|
+
const PAYMENT_TOKEN = process.env.AGENTBANK_PAYMENT_TOKEN ?? 'pm_card_visa';
|
|
30
|
+
// Club Med backend (public — no buyer token; the merchant key lives there).
|
|
31
|
+
const backend = async (path, init = {}) => {
|
|
24
32
|
const res = await fetch(`${CLUBMED}${path}`, {
|
|
25
33
|
...init,
|
|
26
34
|
headers: { 'content-type': 'application/json', ...(init.headers ?? {}) },
|
|
@@ -53,7 +61,7 @@ const TOOLS = [
|
|
|
53
61
|
},
|
|
54
62
|
{
|
|
55
63
|
name: 'book_clubmed_resort',
|
|
56
|
-
description:
|
|
64
|
+
description: 'Book a Club Med resort — charges the full per-person/week price and confirms the booking (Stripe test mode). Club Med prices the resort; this agent completes the payment with its card credential. Returns the booked order.',
|
|
57
65
|
inputSchema: {
|
|
58
66
|
type: 'object',
|
|
59
67
|
required: ['sku'],
|
|
@@ -67,7 +75,7 @@ const TOOLS = [
|
|
|
67
75
|
const text = (value) => ({
|
|
68
76
|
content: [{ type: 'text', text: JSON.stringify(value, null, 2) }],
|
|
69
77
|
});
|
|
70
|
-
const server = new Server({ name: 'clubmed', version: '0.
|
|
78
|
+
const server = new Server({ name: 'clubmed', version: '0.3.0' }, { capabilities: { tools: {} } });
|
|
71
79
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS }));
|
|
72
80
|
server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
73
81
|
const args = (req.params.arguments ?? {});
|
|
@@ -75,27 +83,45 @@ server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
|
75
83
|
if (req.params.name === 'list_clubmed_resorts') {
|
|
76
84
|
const country = typeof args.country === 'string' ? args.country.toUpperCase() : undefined;
|
|
77
85
|
const kind = typeof args.kind === 'string' ? `?kind=${encodeURIComponent(args.kind)}` : '';
|
|
78
|
-
const { items } = await
|
|
86
|
+
const { items } = await backend(`/catalog${kind}`);
|
|
79
87
|
const resorts = country ? items.filter((r) => r.country === country) : items;
|
|
80
88
|
return text({ currency: 'EUR', count: resorts.length, resorts });
|
|
81
89
|
}
|
|
82
90
|
if (req.params.name === 'get_clubmed_resort') {
|
|
83
91
|
const sku = String(args.sku ?? '');
|
|
84
|
-
const resort = await
|
|
92
|
+
const resort = await backend(`/catalog/${encodeURIComponent(sku)}`);
|
|
85
93
|
return text(resort);
|
|
86
94
|
}
|
|
87
95
|
if (req.params.name === 'book_clubmed_resort') {
|
|
96
|
+
if (!TOKEN) {
|
|
97
|
+
return {
|
|
98
|
+
content: [{ type: 'text', text: 'set AGENTBANK_AGENT_TOKEN (a test agent:execute key)' }],
|
|
99
|
+
isError: true,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
88
102
|
const sku = String(args.sku ?? '');
|
|
89
103
|
const quantity = Math.max(Number(args.quantity) || 1, 1);
|
|
90
|
-
|
|
104
|
+
// 1. Club Med prices the resort + opens a merchant-quoted ACP session.
|
|
105
|
+
const session = await backend('/checkout', { method: 'POST', body: JSON.stringify({ sku, quantity }) });
|
|
106
|
+
// 2. This buyer agent completes the charge over ACP with its card token.
|
|
107
|
+
const url = `${API_BASE}/acp/${encodeURIComponent(session.merchantId)}/checkout_sessions/${encodeURIComponent(session.sessionId)}/complete`;
|
|
108
|
+
const res = await fetch(url, {
|
|
109
|
+
method: 'POST',
|
|
110
|
+
headers: { 'content-type': 'application/json', authorization: `Bearer ${TOKEN}` },
|
|
111
|
+
body: JSON.stringify({ payment_data: { token: PAYMENT_TOKEN, provider: 'stripe' } }),
|
|
112
|
+
});
|
|
113
|
+
if (!res.ok) {
|
|
114
|
+
throw new Error(`acp complete -> ${res.status}: ${await res.text().catch(() => '')}`);
|
|
115
|
+
}
|
|
116
|
+
const order = (await res.json());
|
|
91
117
|
return text({
|
|
92
|
-
|
|
93
|
-
resort:
|
|
118
|
+
booked: order.status === 'completed',
|
|
119
|
+
resort: session.name,
|
|
94
120
|
quantity,
|
|
95
|
-
total:
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
121
|
+
total: session.amountDisplay,
|
|
122
|
+
status: order.status,
|
|
123
|
+
orderId: order.order?.id,
|
|
124
|
+
message: `Booked ${session.name} × ${quantity} — ${session.amountDisplay} charged (${order.status}).`,
|
|
99
125
|
});
|
|
100
126
|
}
|
|
101
127
|
return { content: [{ type: 'text', text: `unknown tool: ${req.params.name}` }], isError: true };
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,oCAAoC,CAAC;AAEnG,+EAA+E;AAC/E,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@curless/clubmed-demo",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Demo Club Med storefront MCP — browse resorts worldwide and
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Demo Club Med storefront MCP — browse resorts worldwide and book them end-to-end: Club Med's merchant backend (mcp.curless.ai/clubmed) prices the resort and opens a merchant-quoted ACP session; the buyer agent completes the card payment.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|