@appaflytech/wappa-mcp 0.0.9 → 0.0.11
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 +40 -0
- package/dist/auth.d.ts +25 -0
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +35 -0
- package/dist/auth.js.map +1 -1
- package/dist/client.d.ts +34 -3
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +112 -8
- package/dist/client.js.map +1 -1
- package/dist/factory.d.ts +32 -0
- package/dist/factory.d.ts.map +1 -0
- package/dist/factory.js +248 -0
- package/dist/factory.js.map +1 -0
- package/dist/http/auth.d.ts +33 -0
- package/dist/http/auth.d.ts.map +1 -0
- package/dist/http/auth.js +55 -0
- package/dist/http/auth.js.map +1 -0
- package/dist/http/session.d.ts +30 -0
- package/dist/http/session.d.ts.map +1 -0
- package/dist/http/session.js +56 -0
- package/dist/http/session.js.map +1 -0
- package/dist/http/transport.d.ts +21 -0
- package/dist/http/transport.d.ts.map +1 -0
- package/dist/http/transport.js +101 -0
- package/dist/http/transport.js.map +1 -0
- package/dist/index.d.ts +5 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +26 -262
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts +25 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +94 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/dynamic-entities.d.ts +10 -0
- package/dist/tools/dynamic-entities.d.ts.map +1 -1
- package/dist/tools/dynamic-entities.js +77 -2
- package/dist/tools/dynamic-entities.js.map +1 -1
- package/dist/tools/entities.d.ts.map +1 -1
- package/dist/tools/entities.js +297 -4
- package/dist/tools/entities.js.map +1 -1
- package/dist/tools/layouts.d.ts.map +1 -1
- package/dist/tools/layouts.js +1 -2
- package/dist/tools/layouts.js.map +1 -1
- package/dist/tools/organizations.d.ts +178 -0
- package/dist/tools/organizations.d.ts.map +1 -0
- package/dist/tools/organizations.js +158 -0
- package/dist/tools/organizations.js.map +1 -0
- package/dist/tools/pages.d.ts +8 -0
- package/dist/tools/pages.d.ts.map +1 -1
- package/dist/tools/pages.js +348 -24
- package/dist/tools/pages.js.map +1 -1
- package/dist/tools/plans.d.ts +293 -0
- package/dist/tools/plans.d.ts.map +1 -0
- package/dist/tools/plans.js +213 -0
- package/dist/tools/plans.js.map +1 -0
- package/dist/tools/push-notifications.d.ts +261 -0
- package/dist/tools/push-notifications.d.ts.map +1 -0
- package/dist/tools/push-notifications.js +246 -0
- package/dist/tools/push-notifications.js.map +1 -0
- package/dist/tools/queries.d.ts +29 -0
- package/dist/tools/queries.d.ts.map +1 -1
- package/dist/tools/queries.js +106 -14
- package/dist/tools/queries.js.map +1 -1
- package/dist/tools/subscriptions.d.ts +166 -0
- package/dist/tools/subscriptions.d.ts.map +1 -0
- package/dist/tools/subscriptions.js +144 -0
- package/dist/tools/subscriptions.js.map +1 -0
- package/package.json +20 -4
package/dist/index.js
CHANGED
|
@@ -1,283 +1,47 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* WAPPA Admin API MCP Server
|
|
3
|
+
* WAPPA Admin API MCP Server — stdio entry point
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
5
|
+
* Supports two auth modes controlled by environment variables:
|
|
6
|
+
* 1. Email/password — WAP_EMAIL + WAP_PASSWORD (legacy, default)
|
|
7
|
+
* 2. API Key — WAP_API_KEY (Organisation API Key, no sign-in needed)
|
|
7
8
|
*
|
|
9
|
+
* Provides Claude Code / Cursor with direct access to WAPPA Admin API tools.
|
|
8
10
|
*/
|
|
9
|
-
import { McpServer, ResourceTemplate, } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
10
11
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
11
|
-
import { z } from "zod";
|
|
12
12
|
import { config as loadDotenv } from "dotenv";
|
|
13
|
-
import {
|
|
14
|
-
import { WapClient } from "./client.js";
|
|
15
|
-
import { getComponentTools } from "./tools/components.js";
|
|
16
|
-
import { getPageTools } from "./tools/pages.js";
|
|
17
|
-
import { getWidgetTools } from "./tools/widgets.js";
|
|
18
|
-
import { getGeneralTools } from "./tools/general.js";
|
|
19
|
-
import { getSiteTools } from "./tools/sites.js";
|
|
20
|
-
import { getEntityTools } from "./tools/entities.js";
|
|
21
|
-
import { getDynamicEntityTools } from "./tools/dynamic-entities.js";
|
|
22
|
-
import { getLayoutTools } from "./tools/layouts.js";
|
|
23
|
-
import { getQueryTools } from "./tools/queries.js";
|
|
24
|
-
import { getMenuTools } from "./tools/menus.js";
|
|
25
|
-
import { getThemeTools } from "./tools/themes.js";
|
|
26
|
-
import { getLanguageTools } from "./tools/languages.js";
|
|
27
|
-
// ─── Configuration ─────────────────────────────────────────
|
|
13
|
+
import { buildMcpServerForSession } from "./factory.js";
|
|
28
14
|
// Load .env file when running locally (no-op if vars already set by MCP client)
|
|
29
15
|
// quiet:true prevents dotenvx from writing to stdout (which breaks MCP stdio protocol)
|
|
30
16
|
loadDotenv({ quiet: true, override: false });
|
|
31
17
|
function getConfig() {
|
|
32
18
|
const required = (key) => {
|
|
33
19
|
const value = process.env[key];
|
|
34
|
-
if (!value)
|
|
20
|
+
if (!value)
|
|
35
21
|
throw new Error(`Missing required environment variable: ${key}`);
|
|
36
|
-
}
|
|
37
22
|
return value;
|
|
38
23
|
};
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
// ─── Server Setup ──────────────────────────────────────────
|
|
48
|
-
async function main() {
|
|
49
|
-
const config = getConfig();
|
|
50
|
-
const tokenManager = new TokenManager({
|
|
51
|
-
adminApiUrl: config.adminApiUrl,
|
|
52
|
-
email: config.email,
|
|
53
|
-
password: config.password,
|
|
54
|
-
});
|
|
55
|
-
const client = new WapClient({
|
|
56
|
-
adminApiUrl: config.adminApiUrl,
|
|
57
|
-
siteKey: config.siteKey,
|
|
58
|
-
language: config.language,
|
|
59
|
-
tokenManager,
|
|
60
|
-
});
|
|
61
|
-
// Collect all tools
|
|
62
|
-
const componentTools = getComponentTools(client);
|
|
63
|
-
const pageTools = getPageTools(client);
|
|
64
|
-
const widgetTools = getWidgetTools(client);
|
|
65
|
-
const generalTools = getGeneralTools(client);
|
|
66
|
-
const siteTools = getSiteTools(client);
|
|
67
|
-
const entityTools = getEntityTools(client);
|
|
68
|
-
const dynamicEntityTools = getDynamicEntityTools(client);
|
|
69
|
-
const layoutTools = getLayoutTools(client);
|
|
70
|
-
const queryTools = getQueryTools(client);
|
|
71
|
-
const menuTools = getMenuTools(client);
|
|
72
|
-
const themeTools = getThemeTools(client);
|
|
73
|
-
const languageTools = getLanguageTools(client);
|
|
74
|
-
const allTools = {
|
|
75
|
-
...componentTools,
|
|
76
|
-
...pageTools,
|
|
77
|
-
...widgetTools,
|
|
78
|
-
...generalTools,
|
|
79
|
-
...siteTools,
|
|
80
|
-
...entityTools,
|
|
81
|
-
...dynamicEntityTools,
|
|
82
|
-
...layoutTools,
|
|
83
|
-
...queryTools,
|
|
84
|
-
...menuTools,
|
|
85
|
-
...themeTools,
|
|
86
|
-
...languageTools,
|
|
87
|
-
};
|
|
88
|
-
// Create MCP Server
|
|
89
|
-
const server = new McpServer({
|
|
90
|
-
name: "wappa-mcp",
|
|
91
|
-
version: "1.0.0",
|
|
92
|
-
});
|
|
93
|
-
// Register each tool with the MCP server
|
|
94
|
-
for (const [toolName, toolDef] of Object.entries(allTools)) {
|
|
95
|
-
const { description, inputSchema, handler } = toolDef;
|
|
96
|
-
// Convert JSON Schema properties to Zod schema
|
|
97
|
-
const zodShape = {};
|
|
98
|
-
const props = inputSchema.properties || {};
|
|
99
|
-
const required = inputSchema.required || [];
|
|
100
|
-
for (const [propName, propDef] of Object.entries(props)) {
|
|
101
|
-
let zodType;
|
|
102
|
-
switch (propDef.type) {
|
|
103
|
-
case "string":
|
|
104
|
-
zodType = propDef.enum ? z.enum(propDef.enum) : z.string();
|
|
105
|
-
break;
|
|
106
|
-
case "number":
|
|
107
|
-
zodType = z.number();
|
|
108
|
-
break;
|
|
109
|
-
case "boolean":
|
|
110
|
-
zodType = z.boolean();
|
|
111
|
-
break;
|
|
112
|
-
case "object":
|
|
113
|
-
zodType = z.record(z.string(), z.unknown());
|
|
114
|
-
break;
|
|
115
|
-
case "array":
|
|
116
|
-
zodType = z.array(z.unknown());
|
|
117
|
-
break;
|
|
118
|
-
default:
|
|
119
|
-
zodType = z.unknown();
|
|
120
|
-
}
|
|
121
|
-
if (propDef.description) {
|
|
122
|
-
zodType = zodType.describe(propDef.description);
|
|
123
|
-
}
|
|
124
|
-
if (!required.includes(propName)) {
|
|
125
|
-
zodType = zodType.optional();
|
|
126
|
-
}
|
|
127
|
-
zodShape[propName] = zodType;
|
|
128
|
-
}
|
|
129
|
-
server.tool(`wappa_${toolName}`, description, zodShape, async (args) => {
|
|
130
|
-
try {
|
|
131
|
-
return await handler(args);
|
|
132
|
-
}
|
|
133
|
-
catch (error) {
|
|
134
|
-
return {
|
|
135
|
-
content: [
|
|
136
|
-
{
|
|
137
|
-
type: "text",
|
|
138
|
-
text: `Error: ${error.message}`,
|
|
139
|
-
},
|
|
140
|
-
],
|
|
141
|
-
isError: true,
|
|
142
|
-
};
|
|
143
|
-
}
|
|
144
|
-
});
|
|
24
|
+
const adminApiUrl = required("WAP_ADMIN_API_URL").replace(/\/+$/, "");
|
|
25
|
+
const siteKey = process.env.WAP_SITE_KEY || process.env.WAP_SITE_ID || "";
|
|
26
|
+
const language = process.env.WAP_LANGUAGE || "en-us";
|
|
27
|
+
let auth;
|
|
28
|
+
if (process.env.WAP_API_KEY) {
|
|
29
|
+
auth = { kind: "apiKey", apiKey: process.env.WAP_API_KEY };
|
|
145
30
|
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
contents: [
|
|
153
|
-
{
|
|
154
|
-
uri: uri.href,
|
|
155
|
-
mimeType: "application/json",
|
|
156
|
-
text: JSON.stringify({
|
|
157
|
-
adminApiUrl: config.adminApiUrl,
|
|
158
|
-
siteKey: config.siteKey,
|
|
159
|
-
language: config.language,
|
|
160
|
-
}, null, 2),
|
|
161
|
-
},
|
|
162
|
-
],
|
|
163
|
-
}));
|
|
164
|
-
// Dynamic: site listesi
|
|
165
|
-
server.resource("wappa-sites", "wappa://sites", {
|
|
166
|
-
description: "WAPPA'daki tüm site listesi (canlı veri)",
|
|
167
|
-
mimeType: "application/json",
|
|
168
|
-
}, async (uri) => {
|
|
169
|
-
const result = await client.getSites({});
|
|
170
|
-
return {
|
|
171
|
-
contents: [
|
|
172
|
-
{
|
|
173
|
-
uri: uri.href,
|
|
174
|
-
mimeType: "application/json",
|
|
175
|
-
text: JSON.stringify(result, null, 2),
|
|
176
|
-
},
|
|
177
|
-
],
|
|
178
|
-
};
|
|
179
|
-
});
|
|
180
|
-
// Dynamic: aktif sitenin sayfaları
|
|
181
|
-
server.resource("wappa-pages", "wappa://pages", {
|
|
182
|
-
description: "Aktif sitedeki tüm sayfalar (canlı veri)",
|
|
183
|
-
mimeType: "application/json",
|
|
184
|
-
}, async (uri) => {
|
|
185
|
-
const result = await client.getPages({});
|
|
186
|
-
return {
|
|
187
|
-
contents: [
|
|
188
|
-
{
|
|
189
|
-
uri: uri.href,
|
|
190
|
-
mimeType: "application/json",
|
|
191
|
-
text: JSON.stringify(result, null, 2),
|
|
192
|
-
},
|
|
193
|
-
],
|
|
194
|
-
};
|
|
195
|
-
});
|
|
196
|
-
// Dynamic: bileşenler
|
|
197
|
-
server.resource("wappa-components", "wappa://components", {
|
|
198
|
-
description: "Aktif sitedeki tüm bileşenler (canlı veri)",
|
|
199
|
-
mimeType: "application/json",
|
|
200
|
-
}, async (uri) => {
|
|
201
|
-
const result = await client.getComponents({});
|
|
202
|
-
return {
|
|
203
|
-
contents: [
|
|
204
|
-
{
|
|
205
|
-
uri: uri.href,
|
|
206
|
-
mimeType: "application/json",
|
|
207
|
-
text: JSON.stringify(result, null, 2),
|
|
208
|
-
},
|
|
209
|
-
],
|
|
210
|
-
};
|
|
211
|
-
});
|
|
212
|
-
// Dynamic: entityler
|
|
213
|
-
server.resource("wappa-entities", "wappa://entities", {
|
|
214
|
-
description: "Tanımlı tüm entity şemaları (canlı veri)",
|
|
215
|
-
mimeType: "application/json",
|
|
216
|
-
}, async (uri) => {
|
|
217
|
-
const result = await client.getEntities({});
|
|
218
|
-
return {
|
|
219
|
-
contents: [
|
|
220
|
-
{
|
|
221
|
-
uri: uri.href,
|
|
222
|
-
mimeType: "application/json",
|
|
223
|
-
text: JSON.stringify(result, null, 2),
|
|
224
|
-
},
|
|
225
|
-
],
|
|
31
|
+
else {
|
|
32
|
+
auth = {
|
|
33
|
+
kind: "emailPwd",
|
|
34
|
+
adminApiUrl,
|
|
35
|
+
email: required("WAP_EMAIL"),
|
|
36
|
+
password: required("WAP_PASSWORD"),
|
|
226
37
|
};
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
return {
|
|
235
|
-
contents: [
|
|
236
|
-
{
|
|
237
|
-
uri: uri.href,
|
|
238
|
-
mimeType: "application/json",
|
|
239
|
-
text: JSON.stringify(result, null, 2),
|
|
240
|
-
},
|
|
241
|
-
],
|
|
242
|
-
};
|
|
243
|
-
});
|
|
244
|
-
// Dynamic: sorgu şablonları
|
|
245
|
-
server.resource("wappa-queries", "wappa://queries", {
|
|
246
|
-
description: "Kayıtlı tüm query/sorgu şablonları (canlı veri)",
|
|
247
|
-
mimeType: "application/json",
|
|
248
|
-
}, async (uri) => {
|
|
249
|
-
const result = await client.getQueries({});
|
|
250
|
-
return {
|
|
251
|
-
contents: [
|
|
252
|
-
{
|
|
253
|
-
uri: uri.href,
|
|
254
|
-
mimeType: "application/json",
|
|
255
|
-
text: JSON.stringify(result, null, 2),
|
|
256
|
-
},
|
|
257
|
-
],
|
|
258
|
-
};
|
|
259
|
-
});
|
|
260
|
-
// Dynamic Resource Template: belirli bir entity'nin kayıtları
|
|
261
|
-
server.resource("wappa-entity-records", new ResourceTemplate("wappa://entities/{entityId}/records", {
|
|
262
|
-
list: undefined,
|
|
263
|
-
}), {
|
|
264
|
-
description: "Belirli bir entity'nin tüm kayıtları. URI: wappa://entities/{entityId}/records",
|
|
265
|
-
mimeType: "application/json",
|
|
266
|
-
}, async (uri, { entityId }) => {
|
|
267
|
-
const result = await client.getDynamicEntities(entityId, {});
|
|
268
|
-
return {
|
|
269
|
-
contents: [
|
|
270
|
-
{
|
|
271
|
-
uri: uri.href,
|
|
272
|
-
mimeType: "application/json",
|
|
273
|
-
text: JSON.stringify(result, null, 2),
|
|
274
|
-
},
|
|
275
|
-
],
|
|
276
|
-
};
|
|
277
|
-
});
|
|
278
|
-
// Start the server
|
|
279
|
-
const transport = new StdioServerTransport();
|
|
280
|
-
await server.connect(transport);
|
|
38
|
+
}
|
|
39
|
+
return { adminApiUrl, siteKey, language, auth };
|
|
40
|
+
}
|
|
41
|
+
async function main() {
|
|
42
|
+
const cfg = getConfig();
|
|
43
|
+
const { server } = buildMcpServerForSession(cfg);
|
|
44
|
+
await server.connect(new StdioServerTransport());
|
|
281
45
|
console.error("WAPPA MCP Server running on stdio");
|
|
282
46
|
}
|
|
283
47
|
main().catch((error) => {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;;;;GAQG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,wBAAwB,EAAoB,MAAM,cAAc,CAAC;AAE1E,gFAAgF;AAChF,uFAAuF;AACvF,UAAU,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;AAE7C,SAAS,SAAS;IAChB,MAAM,QAAQ,GAAG,CAAC,GAAW,EAAU,EAAE;QACvC,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC/B,IAAI,CAAC,KAAK;YACR,MAAM,IAAI,KAAK,CAAC,0CAA0C,GAAG,EAAE,CAAC,CAAC;QACnE,OAAO,KAAK,CAAC;IACf,CAAC,CAAC;IAEF,MAAM,WAAW,GAAG,QAAQ,CAAC,mBAAmB,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACtE,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,EAAE,CAAC;IAC1E,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,OAAO,CAAC;IAErD,IAAI,IAAiB,CAAC;IACtB,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;QAC5B,IAAI,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;IAC7D,CAAC;SAAM,CAAC;QACN,IAAI,GAAG;YACL,IAAI,EAAE,UAAU;YAChB,WAAW;YACX,KAAK,EAAE,QAAQ,CAAC,WAAW,CAAC;YAC5B,QAAQ,EAAE,QAAQ,CAAC,cAAc,CAAC;SACnC,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AAClD,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,GAAG,GAAG,SAAS,EAAE,CAAC;IACxB,MAAM,EAAE,MAAM,EAAE,GAAG,wBAAwB,CAAC,GAAG,CAAC,CAAC;IACjD,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,oBAAoB,EAAE,CAAC,CAAC;IACjD,OAAO,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAC;AACrD,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,mCAAmC,EAAE,KAAK,CAAC,CAAC;IAC1D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* WAPPA MCP HTTP Server
|
|
4
|
+
*
|
|
5
|
+
* Exposes the same MCP tools as the stdio entry point but over HTTP using
|
|
6
|
+
* the Streamable-HTTP transport (MCP spec §HTTP Transport).
|
|
7
|
+
*
|
|
8
|
+
* Admin UI and external clients can use this server by:
|
|
9
|
+
* 1. Sending POST /mcp with an initialize request + auth headers
|
|
10
|
+
* 2. Continuing the session with the returned Mcp-Session-Id header
|
|
11
|
+
*
|
|
12
|
+
* Auth headers (required on every request):
|
|
13
|
+
* Authorization: Bearer <jwt> — Admin UI passthrough
|
|
14
|
+
* X-API-Key: <key> — Backend Organisation API Key
|
|
15
|
+
* X-Wappa-Site-Key: <slug> — target site slug
|
|
16
|
+
* X-Wappa-Admin-Api: <url> — backend Admin API base URL
|
|
17
|
+
* X-Wappa-Language: <locale> — optional, default "en-us"
|
|
18
|
+
*
|
|
19
|
+
* Environment variables:
|
|
20
|
+
* PORT — HTTP port (default 4100)
|
|
21
|
+
* ALLOWED_ORIGINS — comma-separated CORS origins (default "*")
|
|
22
|
+
* RATE_LIMIT_RPM — requests per minute per IP (default 120)
|
|
23
|
+
*/
|
|
24
|
+
export {};
|
|
25
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;;;;;;;;;;GAqBG"}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* WAPPA MCP HTTP Server
|
|
4
|
+
*
|
|
5
|
+
* Exposes the same MCP tools as the stdio entry point but over HTTP using
|
|
6
|
+
* the Streamable-HTTP transport (MCP spec §HTTP Transport).
|
|
7
|
+
*
|
|
8
|
+
* Admin UI and external clients can use this server by:
|
|
9
|
+
* 1. Sending POST /mcp with an initialize request + auth headers
|
|
10
|
+
* 2. Continuing the session with the returned Mcp-Session-Id header
|
|
11
|
+
*
|
|
12
|
+
* Auth headers (required on every request):
|
|
13
|
+
* Authorization: Bearer <jwt> — Admin UI passthrough
|
|
14
|
+
* X-API-Key: <key> — Backend Organisation API Key
|
|
15
|
+
* X-Wappa-Site-Key: <slug> — target site slug
|
|
16
|
+
* X-Wappa-Admin-Api: <url> — backend Admin API base URL
|
|
17
|
+
* X-Wappa-Language: <locale> — optional, default "en-us"
|
|
18
|
+
*
|
|
19
|
+
* Environment variables:
|
|
20
|
+
* PORT — HTTP port (default 4100)
|
|
21
|
+
* ALLOWED_ORIGINS — comma-separated CORS origins (default "*")
|
|
22
|
+
* RATE_LIMIT_RPM — requests per minute per IP (default 120)
|
|
23
|
+
*/
|
|
24
|
+
import express from "express";
|
|
25
|
+
import helmet from "helmet";
|
|
26
|
+
import cors from "cors";
|
|
27
|
+
import rateLimit from "express-rate-limit";
|
|
28
|
+
import { config as loadDotenv } from "dotenv";
|
|
29
|
+
import { wappaAuthMiddleware } from "./http/auth.js";
|
|
30
|
+
import { handleMcpPost, handleMcpGet, handleMcpDelete, } from "./http/transport.js";
|
|
31
|
+
import { closeAllSessions } from "./http/session.js";
|
|
32
|
+
loadDotenv({ quiet: true, override: false });
|
|
33
|
+
const PORT = Number(process.env.PORT ?? 4100);
|
|
34
|
+
const allowedOrigins = process.env.ALLOWED_ORIGINS
|
|
35
|
+
? process.env.ALLOWED_ORIGINS.split(",").map((s) => s.trim())
|
|
36
|
+
: ["*"];
|
|
37
|
+
const rateLimitRpm = Number(process.env.RATE_LIMIT_RPM ?? 120);
|
|
38
|
+
// ─── App setup ──────────────────────────────────────────────
|
|
39
|
+
const app = express();
|
|
40
|
+
// Security headers
|
|
41
|
+
app.use(helmet());
|
|
42
|
+
// CORS
|
|
43
|
+
app.use(cors({
|
|
44
|
+
origin: allowedOrigins.includes("*") ? "*" : allowedOrigins,
|
|
45
|
+
exposedHeaders: ["Mcp-Session-Id"],
|
|
46
|
+
}));
|
|
47
|
+
// Rate limiting
|
|
48
|
+
app.use(rateLimit({
|
|
49
|
+
windowMs: 60_000,
|
|
50
|
+
max: rateLimitRpm,
|
|
51
|
+
standardHeaders: true,
|
|
52
|
+
legacyHeaders: false,
|
|
53
|
+
}));
|
|
54
|
+
// JSON body (2 MB limit)
|
|
55
|
+
app.use(express.json({ limit: "2mb" }));
|
|
56
|
+
// ─── Routes ─────────────────────────────────────────────────
|
|
57
|
+
app.get("/health", (_req, res) => {
|
|
58
|
+
res.json({ status: "ok", transport: "streamable-http" });
|
|
59
|
+
});
|
|
60
|
+
// MCP endpoint — auth middleware applied only to /mcp
|
|
61
|
+
app.post("/mcp", wappaAuthMiddleware, (req, res) => {
|
|
62
|
+
handleMcpPost(req, res).catch((err) => {
|
|
63
|
+
console.error("MCP POST error:", err);
|
|
64
|
+
if (!res.headersSent)
|
|
65
|
+
res.status(500).json({ error: "Internal server error" });
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
app.get("/mcp", wappaAuthMiddleware, (req, res) => {
|
|
69
|
+
handleMcpGet(req, res).catch((err) => {
|
|
70
|
+
console.error("MCP GET error:", err);
|
|
71
|
+
if (!res.headersSent)
|
|
72
|
+
res.status(500).json({ error: "Internal server error" });
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
app.delete("/mcp", wappaAuthMiddleware, (req, res) => {
|
|
76
|
+
handleMcpDelete(req, res).catch((err) => {
|
|
77
|
+
console.error("MCP DELETE error:", err);
|
|
78
|
+
if (!res.headersSent)
|
|
79
|
+
res.status(500).json({ error: "Internal server error" });
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
// ─── Start ──────────────────────────────────────────────────
|
|
83
|
+
const httpServer = app.listen(PORT, () => {
|
|
84
|
+
console.log(`WAPPA MCP HTTP Server listening on port ${PORT}`);
|
|
85
|
+
});
|
|
86
|
+
// Graceful shutdown
|
|
87
|
+
async function shutdown(signal) {
|
|
88
|
+
console.log(`Received ${signal} — shutting down gracefully`);
|
|
89
|
+
await closeAllSessions();
|
|
90
|
+
httpServer.close(() => process.exit(0));
|
|
91
|
+
}
|
|
92
|
+
process.on("SIGTERM", () => void shutdown("SIGTERM"));
|
|
93
|
+
process.on("SIGINT", () => void shutdown("SIGINT"));
|
|
94
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -161,18 +161,28 @@ export declare function getDynamicEntityTools(client: WapClient): {
|
|
|
161
161
|
type: string;
|
|
162
162
|
description: string;
|
|
163
163
|
};
|
|
164
|
+
historyId: {
|
|
165
|
+
type: string;
|
|
166
|
+
description: string;
|
|
167
|
+
};
|
|
164
168
|
status: {
|
|
165
169
|
type: string;
|
|
166
170
|
description: string;
|
|
167
171
|
enum: string[];
|
|
168
172
|
};
|
|
173
|
+
columns: {
|
|
174
|
+
type: string;
|
|
175
|
+
description: string;
|
|
176
|
+
};
|
|
169
177
|
};
|
|
170
178
|
required: string[];
|
|
171
179
|
};
|
|
172
180
|
handler: (args: {
|
|
173
181
|
entityId: string;
|
|
174
182
|
id: string;
|
|
183
|
+
historyId?: string;
|
|
175
184
|
status: string;
|
|
185
|
+
columns?: unknown[];
|
|
176
186
|
}) => Promise<{
|
|
177
187
|
content: {
|
|
178
188
|
type: "text";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dynamic-entities.d.ts","sourceRoot":"","sources":["../../src/tools/dynamic-entities.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AASzC,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBAgC3B;YACpB,QAAQ,EAAE,MAAM,CAAC;YACjB,MAAM,CAAC,EAAE,MAAM,CAAC;YAChB,SAAS,CAAC,EAAE,MAAM,CAAC;YACnB,UAAU,CAAC,EAAE,MAAM,CAAC;YACpB,KAAK,CAAC,EAAE,MAAM,CAAC;YACf,YAAY,CAAC,EAAE,OAAO,CAAC;SACxB;;;;;;;;;;;;;;;;;;;;;;;wBA+BqB;YAAE,QAAQ,EAAE,MAAM,CAAC;YAAC,EAAE,EAAE,MAAM,CAAA;SAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBAwChC;YACpB,QAAQ,EAAE,MAAM,CAAC;YACjB,MAAM,CAAC,EAAE,MAAM,CAAC;YAChB,OAAO,EAAE,OAAO,EAAE,CAAC;SACpB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBAmCqB;YACpB,QAAQ,EAAE,MAAM,CAAC;YACjB,EAAE,EAAE,MAAM,CAAC;YACX,MAAM,CAAC,EAAE,MAAM,CAAC;YAChB,OAAO,EAAE,OAAO,EAAE,CAAC;SACpB
|
|
1
|
+
{"version":3,"file":"dynamic-entities.d.ts","sourceRoot":"","sources":["../../src/tools/dynamic-entities.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AASzC,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBAgC3B;YACpB,QAAQ,EAAE,MAAM,CAAC;YACjB,MAAM,CAAC,EAAE,MAAM,CAAC;YAChB,SAAS,CAAC,EAAE,MAAM,CAAC;YACnB,UAAU,CAAC,EAAE,MAAM,CAAC;YACpB,KAAK,CAAC,EAAE,MAAM,CAAC;YACf,YAAY,CAAC,EAAE,OAAO,CAAC;SACxB;;;;;;;;;;;;;;;;;;;;;;;wBA+BqB;YAAE,QAAQ,EAAE,MAAM,CAAC;YAAC,EAAE,EAAE,MAAM,CAAA;SAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBAwChC;YACpB,QAAQ,EAAE,MAAM,CAAC;YACjB,MAAM,CAAC,EAAE,MAAM,CAAC;YAChB,OAAO,EAAE,OAAO,EAAE,CAAC;SACpB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBAmCqB;YACpB,QAAQ,EAAE,MAAM,CAAC;YACjB,EAAE,EAAE,MAAM,CAAC;YACX,MAAM,CAAC,EAAE,MAAM,CAAC;YAChB,OAAO,EAAE,OAAO,EAAE,CAAC;SACpB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBA4CqB;YACpB,QAAQ,EAAE,MAAM,CAAC;YACjB,EAAE,EAAE,MAAM,CAAC;YACX,SAAS,CAAC,EAAE,MAAM,CAAC;YACnB,MAAM,EAAE,MAAM,CAAC;YACf,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC;SACrB;;;;;;;;;;;;;;;;;;;;;;;wBA0GqB;YAAE,QAAQ,EAAE,MAAM,CAAC;YAAC,EAAE,EAAE,MAAM,CAAA;SAAE;;;;;;;;;;;;;;;;;;;;;;;wBAsBhC;YAAE,QAAQ,EAAE,MAAM,CAAC;YAAC,EAAE,EAAE,MAAM,CAAA;SAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBA8BhC;YACpB,QAAQ,EAAE,MAAM,CAAC;YACjB,EAAE,EAAE,MAAM,CAAC;YACX,gBAAgB,EAAE,MAAM,CAAC;YACzB,eAAe,CAAC,EAAE,OAAO,CAAC;SAC3B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBA8BqB;YACpB,QAAQ,EAAE,MAAM,CAAC;YACjB,EAAE,EAAE,MAAM,CAAC;YACX,SAAS,CAAC,EAAE,MAAM,CAAC;YACnB,UAAU,CAAC,EAAE,MAAM,CAAC;SACrB;;;;;;;EAmBN"}
|
|
@@ -157,22 +157,97 @@ Her kolon: { key: "kolonAdı", value: "değer" } formatında.
|
|
|
157
157
|
},
|
|
158
158
|
// ─── Update Record Status ─────────────────────────────
|
|
159
159
|
update_dynamic_entity_status: {
|
|
160
|
-
description: "Bir entity kaydının yayın durumunu değiştirir (yayınla/taslağa al).",
|
|
160
|
+
description: "Bir entity kaydının yayın durumunu değiştirir (yayınla/taslağa al). 'id' kayıt ID'si yeterli; gerekli historyId otomatik çözülür.",
|
|
161
161
|
inputSchema: {
|
|
162
162
|
type: "object",
|
|
163
163
|
properties: {
|
|
164
164
|
entityId: { type: "string", description: "Entity şema ID (GUID)" },
|
|
165
165
|
id: { type: "string", description: "Kayıt ID" },
|
|
166
|
+
historyId: {
|
|
167
|
+
type: "string",
|
|
168
|
+
description: "Opsiyonel version (history) ID. Verilmezse get_record ile otomatik çözülür.",
|
|
169
|
+
},
|
|
166
170
|
status: {
|
|
167
171
|
type: "string",
|
|
168
172
|
description: "Yeni durum: Published | Draft | Deleted",
|
|
169
173
|
enum: ["Published", "Draft", "Deleted"],
|
|
170
174
|
},
|
|
175
|
+
columns: {
|
|
176
|
+
type: "array",
|
|
177
|
+
description: "Opsiyonel: durum değişikliğiyle birlikte gönderilecek kolon değerleri",
|
|
178
|
+
},
|
|
171
179
|
},
|
|
172
180
|
required: ["entityId", "id", "status"],
|
|
173
181
|
},
|
|
174
182
|
handler: async (args) => {
|
|
175
|
-
|
|
183
|
+
let targetId = args.historyId ?? args.id;
|
|
184
|
+
const shouldSendStatusOnly = !args.historyId && !args.columns && args.status !== "Published";
|
|
185
|
+
if (shouldSendStatusOnly) {
|
|
186
|
+
const result = await client.updateDynamicEntityStatus(args.entityId, targetId, args.status);
|
|
187
|
+
return {
|
|
188
|
+
content: [
|
|
189
|
+
{ type: "text", text: JSON.stringify(result, null, 2) },
|
|
190
|
+
],
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
// For Published, the backend reads a version record (history) by id.
|
|
194
|
+
// For Draft, it operates on the live record id directly.
|
|
195
|
+
if (!args.historyId && args.status === "Published") {
|
|
196
|
+
try {
|
|
197
|
+
const versions = await client.getDynamicEntityVersions(args.entityId, args.id, { pageLength: "1", pageIndex: "0" });
|
|
198
|
+
const list = versions?.data?.data ?? versions?.data ?? versions?.Data ?? [];
|
|
199
|
+
const first = Array.isArray(list) ? list[0] : null;
|
|
200
|
+
// Prefer the dedicated history pointer; some endpoints surface
|
|
201
|
+
// a synthetic wrapper `id` that is NOT the history row's PK.
|
|
202
|
+
const hid = first?.historyId ?? first?.HistoryId ?? first?.id ?? first?.Id;
|
|
203
|
+
if (hid)
|
|
204
|
+
targetId = hid;
|
|
205
|
+
}
|
|
206
|
+
catch {
|
|
207
|
+
/* fall back to provided id */
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
const body = { status: args.status };
|
|
211
|
+
// When the caller doesn't supply columns, harvest existing values
|
|
212
|
+
// so the backend's CreateVersion (Draft) / Create (Published) paths
|
|
213
|
+
// have a full payload — otherwise it throws KeyNotFound on
|
|
214
|
+
// localization lookups or "Column value cannot be null".
|
|
215
|
+
if (args.columns) {
|
|
216
|
+
body.columns = mapColumnsForApi(args.columns);
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
let cols = [];
|
|
220
|
+
// For Published, the live record was already removed by a previous
|
|
221
|
+
// Draft transition — read columns from the most recent version
|
|
222
|
+
// instead. For Draft, read from the live record.
|
|
223
|
+
if (args.status === "Published") {
|
|
224
|
+
try {
|
|
225
|
+
const ver = await client.getDynamicEntityVersions(args.entityId, args.id, { pageLength: "1", pageIndex: "0" });
|
|
226
|
+
const list = ver?.data?.data ?? ver?.data ?? ver?.Data ?? [];
|
|
227
|
+
cols = list?.[0]?.columns ?? list?.[0]?.Columns ?? [];
|
|
228
|
+
}
|
|
229
|
+
catch {
|
|
230
|
+
/* best-effort */
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
try {
|
|
235
|
+
const rec = await client.getDynamicEntity(args.entityId, args.id);
|
|
236
|
+
const data = rec?.data ?? rec;
|
|
237
|
+
cols = data?.columns ?? data?.Columns ?? [];
|
|
238
|
+
}
|
|
239
|
+
catch {
|
|
240
|
+
/* best-effort */
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
if (Array.isArray(cols) && cols.length > 0) {
|
|
244
|
+
body.columns = cols.map((c) => ({
|
|
245
|
+
name: c.name ?? c.Name ?? c.key,
|
|
246
|
+
data: c.data ?? c.Data ?? { refs: [], value: c.value ?? null },
|
|
247
|
+
}));
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
const result = await client.updateDynamicEntityStatus(args.entityId, targetId, body);
|
|
176
251
|
return {
|
|
177
252
|
content: [
|
|
178
253
|
{ type: "text", text: JSON.stringify(result, null, 2) },
|