@cloudhal/mcp-server 0.0.0-stage → 0.1.1

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.
Files changed (105) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +18 -2
  3. package/dist/src/analytics-reports.d.ts +164 -0
  4. package/dist/src/analytics-reports.js +632 -0
  5. package/dist/src/analytics-tools.d.ts +4 -0
  6. package/dist/src/analytics-tools.js +597 -0
  7. package/dist/src/asset-tools.d.ts +5 -0
  8. package/dist/src/asset-tools.js +685 -0
  9. package/dist/src/body-tools.d.ts +46 -0
  10. package/dist/src/body-tools.js +708 -0
  11. package/dist/src/changes.d.ts +10 -0
  12. package/dist/src/changes.js +112 -0
  13. package/dist/src/chrome-tools.d.ts +8 -0
  14. package/dist/src/chrome-tools.js +207 -0
  15. package/dist/src/comment-tools.d.ts +9 -0
  16. package/dist/src/comment-tools.js +743 -0
  17. package/dist/src/comments.d.ts +184 -0
  18. package/dist/src/comments.js +408 -0
  19. package/dist/src/common.d.ts +258 -0
  20. package/dist/src/common.js +488 -0
  21. package/dist/src/content-shared.d.ts +50 -0
  22. package/dist/src/content-shared.js +102 -0
  23. package/dist/src/design-tools.d.ts +9 -0
  24. package/dist/src/design-tools.js +349 -0
  25. package/dist/src/elevation-tools.d.ts +3 -0
  26. package/dist/src/elevation-tools.js +331 -0
  27. package/dist/src/entry-terms.d.ts +14 -0
  28. package/dist/src/entry-terms.js +51 -0
  29. package/dist/src/entry-tools.d.ts +4 -0
  30. package/dist/src/entry-tools.js +442 -0
  31. package/dist/src/http.d.ts +48 -0
  32. package/dist/src/http.js +101 -0
  33. package/dist/src/index.d.ts +10 -0
  34. package/dist/src/index.js +10 -0
  35. package/dist/src/menu-tools.d.ts +41 -0
  36. package/dist/src/menu-tools.js +1058 -0
  37. package/dist/src/page-tools.d.ts +5 -0
  38. package/dist/src/page-tools.js +311 -0
  39. package/dist/src/preview-doc.d.ts +9 -0
  40. package/dist/src/preview-doc.js +56 -0
  41. package/dist/src/preview-view.d.ts +19 -0
  42. package/dist/src/preview-view.js +71 -0
  43. package/dist/src/publish-tools.d.ts +10 -0
  44. package/dist/src/publish-tools.js +248 -0
  45. package/dist/src/render/cdp.d.ts +29 -0
  46. package/dist/src/render/cdp.js +190 -0
  47. package/dist/src/render/checks/components.d.ts +5 -0
  48. package/dist/src/render/checks/components.js +95 -0
  49. package/dist/src/render/checks/content.d.ts +5 -0
  50. package/dist/src/render/checks/content.js +63 -0
  51. package/dist/src/render/checks/contrast.d.ts +5 -0
  52. package/dist/src/render/checks/contrast.js +72 -0
  53. package/dist/src/render/checks/index.d.ts +1 -0
  54. package/dist/src/render/checks/index.js +29 -0
  55. package/dist/src/render/checks/layout.d.ts +5 -0
  56. package/dist/src/render/checks/layout.js +44 -0
  57. package/dist/src/render/checks/motion.d.ts +5 -0
  58. package/dist/src/render/checks/motion.js +66 -0
  59. package/dist/src/render/checks/navigation.d.ts +5 -0
  60. package/dist/src/render/checks/navigation.js +78 -0
  61. package/dist/src/render/checks/prelude.d.ts +1 -0
  62. package/dist/src/render/checks/prelude.js +64 -0
  63. package/dist/src/render/limiter.d.ts +11 -0
  64. package/dist/src/render/limiter.js +29 -0
  65. package/dist/src/render/page.d.ts +19 -0
  66. package/dist/src/render/page.js +135 -0
  67. package/dist/src/render/types.d.ts +89 -0
  68. package/dist/src/render/types.js +140 -0
  69. package/dist/src/render-tools.d.ts +14 -0
  70. package/dist/src/render-tools.js +314 -0
  71. package/dist/src/render.d.ts +14 -0
  72. package/dist/src/render.js +33 -0
  73. package/dist/src/schedule-tools.d.ts +2 -0
  74. package/dist/src/schedule-tools.js +1596 -0
  75. package/dist/src/schedules.d.ts +292 -0
  76. package/dist/src/schedules.js +890 -0
  77. package/dist/src/schema-transforms.d.ts +14 -0
  78. package/dist/src/schema-transforms.js +50 -0
  79. package/dist/src/search-tools.d.ts +2 -0
  80. package/dist/src/search-tools.js +112 -0
  81. package/dist/src/server-approvals.d.ts +51 -0
  82. package/dist/src/server-approvals.js +273 -0
  83. package/dist/src/server-call.d.ts +28 -0
  84. package/dist/src/server-call.js +259 -0
  85. package/dist/src/server-instructions.d.ts +4 -0
  86. package/dist/src/server-instructions.js +74 -0
  87. package/dist/src/server-resources.d.ts +4 -0
  88. package/dist/src/server-resources.js +83 -0
  89. package/dist/src/server-schema.d.ts +20 -0
  90. package/dist/src/server-schema.js +82 -0
  91. package/dist/src/server.d.ts +80 -0
  92. package/dist/src/server.js +135 -0
  93. package/dist/src/stdio.d.ts +9 -0
  94. package/dist/src/stdio.js +18 -0
  95. package/dist/src/surface-tools.d.ts +4 -0
  96. package/dist/src/surface-tools.js +357 -0
  97. package/dist/src/taxonomy-tools.d.ts +16 -0
  98. package/dist/src/taxonomy-tools.js +1433 -0
  99. package/dist/src/terms.d.ts +47 -0
  100. package/dist/src/terms.js +271 -0
  101. package/dist/src/tools.d.ts +39 -0
  102. package/dist/src/tools.js +511 -0
  103. package/dist/src/translation-tools.d.ts +3 -0
  104. package/dist/src/translation-tools.js +422 -0
  105. package/package.json +86 -3
@@ -0,0 +1,422 @@
1
+ /**
2
+ * RFC-0033 §6 / ADR-0035: translating pages and entries. The agent translates with its own model;
3
+ * the server keeps the rules. `get_translation_source` hands over the source, the glossary terms
4
+ * it uses and the current translation; `save_translation` writes a draft in the target locale,
5
+ * linked to the source revision, with its provenance and the deterministic checks
6
+ * (`checkTranslation`). Agents never review: only a person does, in Studio. A translation a person
7
+ * wrote or reviewed is never overwritten here.
8
+ */
9
+ import { forSite, holds } from "@cloudhal/agent-runtime";
10
+
11
+
12
+
13
+
14
+
15
+
16
+
17
+
18
+ import {
19
+ checkNames,
20
+ checkTranslation,
21
+ forEdition,
22
+ linkedLayout,
23
+
24
+ } from "@cloudhal/core-ts";
25
+ import {
26
+ autoSnapshot,
27
+ id,
28
+ mapError,
29
+ obj,
30
+ requireSite,
31
+ str,
32
+
33
+
34
+ ToolError,
35
+ } from "./common.js";
36
+ import { ENTRY, mcpWriter, PAGE, SNAPSHOT, sectionInput } from "./content-shared.js";
37
+
38
+
39
+
40
+ const READ = {
41
+ readOnlyHint: true,
42
+ destructiveHint: false,
43
+ idempotentHint: true,
44
+ openWorldHint: false,
45
+ } ;
46
+
47
+ /** A page or entry of the site by id. */
48
+ async function nodeOf(ctx , siteId , nodeId ) {
49
+ const node = (await ctx.store.getPage(nodeId)) ?? (await ctx.store.getContentEntry(nodeId));
50
+ if (!node || node.siteId !== siteId)
51
+ throw new ToolError("not_found", `page or entry ${nodeId} not found`);
52
+ return node;
53
+ }
54
+
55
+ /** The glossary entries a text uses (all of them for a short glossary). */
56
+ function glossaryFor(glossary , text , locale ) {
57
+ const lower = text.toLocaleLowerCase();
58
+ return (glossary?.entries ?? [])
59
+ .filter((e) =>
60
+ e.caseSensitive ? text.includes(e.term) : lower.includes(e.term.toLocaleLowerCase()),
61
+ )
62
+ .map((e) => ({
63
+ term: e.term,
64
+ ...(e.doNotTranslate ? { doNotTranslate: true } : {}),
65
+ ...(e.translations?.[locale] ? { translation: e.translations[locale]?.text } : {}),
66
+ ...(e.note ? { note: e.note } : {}),
67
+ }));
68
+ }
69
+
70
+ const GROUP = {
71
+ type: "object",
72
+ properties: {
73
+ group: { type: "string" },
74
+ members: { type: "array", items: { type: "object" } },
75
+ },
76
+ required: ["group", "members"],
77
+ };
78
+
79
+ const listTranslationsTool = {
80
+ name: "list_translations",
81
+ title: "List translations",
82
+ description:
83
+ "Every language version of a page or entry (its translation group): locale, status, method (original, human, machine, machine-reviewed), whether it is stale (its source changed since) and reviewed.",
84
+ inputSchema: obj({ siteId: id, nodeId: id }, ["siteId", "nodeId"]),
85
+ outputSchema: obj({ group: GROUP }, ["group"]),
86
+ annotations: READ,
87
+ scopes: ["content:read"],
88
+ handler: async (a, ctx) => {
89
+ const site = await requireSite(ctx, a.siteId );
90
+ const node = await nodeOf(ctx, site.id, a.nodeId );
91
+ const group = await ctx.store.translationGroup(
92
+ site,
93
+ node.translation?.group ?? node.id,
94
+ );
95
+ return { group };
96
+ },
97
+ };
98
+
99
+ const getSourceTool = {
100
+ name: "get_translation_source",
101
+ title: "Get translation source",
102
+ description:
103
+ "What you need to translate a page or entry into `locale`: the source (translate its title, text, summary and SEO; keep section ids, kinds, links, numbers, images and bindings), the glossary terms it uses (doNotTranslate terms stay as written, given translations are used), and the current translation in that locale if there is one (with `stale` when the source changed since, and for a linked page whose source changed its layout, `layout`: the translation's sections on the new layout, with the `untranslated` ones to translate). Then call save_translation.",
104
+ inputSchema: obj(
105
+ {
106
+ siteId: id,
107
+ nodeId: id,
108
+ locale: str("Target BCP 47 locale"),
109
+ targetSiteId: {
110
+ ...id,
111
+ description:
112
+ "A language edition: another site of the project the translation lives on (RFC-0034 §6); default siteId",
113
+ },
114
+ },
115
+ ["siteId", "nodeId", "locale"],
116
+ ),
117
+ outputSchema: obj(
118
+ {
119
+ source: { type: "object" },
120
+ glossary: { type: "array", items: { type: "object" } },
121
+ existing: { type: "object" },
122
+ stale: { type: "boolean" },
123
+ layout: {
124
+ type: "object",
125
+ description:
126
+ "A linked page translation rebuilt on the source's current layout: translate the sections named in `untranslated` and save these sections",
127
+ },
128
+ },
129
+ ["source", "glossary"],
130
+ ),
131
+ annotations: READ,
132
+ scopes: ["content:read"],
133
+ handler: async (a, ctx) => {
134
+ const site = await requireSite(ctx, a.siteId );
135
+ const target = await targetOf(ctx, site, a.targetSiteId);
136
+ const locale = a.locale ;
137
+ if (!target.locales.includes(locale))
138
+ throw new ToolError("locale_not_enabled", `${locale} is not one of the site's locales`);
139
+ const source = await nodeOf(ctx, site.id, a.nodeId );
140
+ const group = await ctx.store.translationGroup(site, source.translation?.group ?? source.id);
141
+ const member = group.members.find((m) => m.locale === locale && m.siteId === target.id);
142
+ const existing = member ? await nodeOf(ctx, target.id, member.id) : undefined;
143
+ const text = JSON.stringify("sections" in source ? source.sections : source.body.value);
144
+ // RFC-0033 §4a: a linked page translation follows the source's layout; nothing is written.
145
+ const layout =
146
+ existing &&
147
+ "sections" in existing &&
148
+ "sections" in source &&
149
+ existing.translation?.layout !== "independent"
150
+ ? linkedLayout(source, existing)
151
+ : undefined;
152
+ return {
153
+ source,
154
+ glossary: glossaryFor(
155
+ await ctx.store.glossary.get(site.id),
156
+ `${source.title} ${text}`,
157
+ locale,
158
+ ),
159
+ ...(existing ? { existing, stale: member?.stale === true } : {}),
160
+ ...(layout?.changed ? { layout } : {}),
161
+ };
162
+ },
163
+ };
164
+
165
+ const saveTranslationTool = {
166
+ name: "save_translation",
167
+ title: "Save translation",
168
+ description:
169
+ "Save your translation of a page or entry into `locale` as a draft linked to the source's current revision, with your model as its provenance. Pages: send title, path and sections (same ids, kinds and order as the source; translated text). Entries: title, slug, body and summary. The checks (structure, links, numbers, glossary, length) run and are returned; a failed check keeps it from being published until fixed. A person reviews it in Studio before it goes live where the site asks for review. Refused for a translation a person wrote or reviewed. Snapshots afterwards.",
170
+ inputSchema: obj(
171
+ {
172
+ siteId: id,
173
+ nodeId: { ...id, description: "The source page or entry" },
174
+ locale: str("Target BCP 47 locale"),
175
+ title: str("Translated title"),
176
+ path: str("Pages: the translated page's path in its locale, e.g. /acerca"),
177
+ slug: str("Entries: the translated entry's slug"),
178
+ sections: sectionInput,
179
+ body: str("Entries: the translated markdown body"),
180
+ summary: str("Entries: the translated summary"),
181
+ coverAlt: str(
182
+ "Entries: the cover image's alt text in `locale`. Without it a new translation leaves the cover alt empty, so the image's own alt text in `locale` (update_asset) is shown",
183
+ { maxLength: 500 },
184
+ ),
185
+ seo: { type: "object", description: "Pages: the translated SEO title and description" },
186
+ engine: str("The model that translated, e.g. claude-opus-5-5"),
187
+ targetSiteId: {
188
+ ...id,
189
+ description:
190
+ "A language edition: another site of the project to save the translation on (RFC-0034 §6). Its images are copied there and its categories and tags become the edition's terms with the same slugs (create missing ones there first). Default siteId",
191
+ },
192
+ },
193
+ ["siteId", "nodeId", "locale", "title"],
194
+ ),
195
+ outputSchema: obj(
196
+ {
197
+ node: { oneOf: [PAGE, ENTRY] },
198
+ checks: { type: "array", items: { type: "object" } },
199
+ snapshot: SNAPSHOT,
200
+ },
201
+ ["node", "checks", "snapshot"],
202
+ ),
203
+ annotations: {
204
+ readOnlyHint: false,
205
+ destructiveHint: false,
206
+ idempotentHint: false,
207
+ openWorldHint: false,
208
+ },
209
+ scopes: ["content:write"],
210
+ handler: async (a, ctx) => {
211
+ const site = await requireSite(ctx, a.siteId );
212
+ const target = await targetOf(ctx, site, a.targetSiteId);
213
+ const cross = target.id !== site.id;
214
+ const locale = a.locale ;
215
+ if (cross && !target.locales.includes(locale))
216
+ throw new ToolError("locale_not_enabled", `${locale} is not one of the edition's locales`);
217
+ let source = await nodeOf(ctx, site.id, a.nodeId );
218
+ if (source.locale === locale)
219
+ throw new ToolError("invalid", "the translation's locale differs from its source's");
220
+ // The source becomes the group's original the first time it is translated (a new revision).
221
+ if (!source.translation) source = await markOriginal(ctx, source);
222
+ const group = await ctx.store.translationGroup(site, source.translation?.group ?? source.id);
223
+ const self = group.members.find((m) => m.id === source.id);
224
+ const member = group.members.find((m) => m.locale === locale && m.siteId === target.id);
225
+ const existing = member ? await nodeOf(ctx, target.id, member.id) : undefined;
226
+ const t = existing?.translation;
227
+ if (t && (t.method === "human" || t.method === "original" || t.review))
228
+ throw new ToolError(
229
+ "denied",
230
+ `${existing?.id} was written or reviewed by a person; ask them to update it (or propose changes)`,
231
+ );
232
+ const translation = {
233
+ group: source.translation?.group ?? source.id,
234
+ method: "machine",
235
+ layout: t?.layout ?? "linked",
236
+ source: {
237
+ id: source.id,
238
+ ...(cross ? { siteId: site.id } : {}),
239
+ locale: source.locale,
240
+ rev: source.rev,
241
+ hash: self?.hash ?? "",
242
+ },
243
+ provenance: {
244
+ engine:
245
+ (a.engine ) ?? ctx.principal.actor.name ?? ctx.principal.actor.id,
246
+ at: (ctx.now?.() ?? new Date()).toISOString(),
247
+ },
248
+ };
249
+ try {
250
+ const made = translatedNode({ a, site: target.id, locale, source, existing, translation });
251
+ // RFC-0034 §6: on an edition, the images come along and the terms are the edition's.
252
+ const draft = cross
253
+ ? await forEdition(ctx.store, made, {
254
+ fromSiteId: site.id,
255
+ toSiteId: target.id,
256
+ actor: ctx.principal.actor,
257
+ })
258
+ : made;
259
+ const glossary = await ctx.store.glossary.get(target.id);
260
+ const checks = checkTranslation({ source, draft, locale, glossary });
261
+ const withChecks = {
262
+ ...translation,
263
+ provenance: {
264
+ ...(translation.provenance ),
265
+ checks: checkNames(checks),
266
+ ...(glossary ? { glossaryRev: glossary.rev } : {}),
267
+ },
268
+ };
269
+ const node = await writeTranslation(
270
+ ctx,
271
+ target.id,
272
+ { ...draft, translation: withChecks } ,
273
+ existing,
274
+ );
275
+ const snapshot = await autoSnapshot(ctx, target.id, "save_translation");
276
+ return { node, checks, snapshot };
277
+ } catch (e) {
278
+ mapError(e);
279
+ }
280
+ },
281
+ };
282
+
283
+ /**
284
+ * The site a translation lives on: `siteId`'s own, or with `targetSiteId` another site of the same
285
+ * project (a language edition, RFC-0034 §6) the caller may write to.
286
+ */
287
+ async function targetOf(ctx , site , targetSiteId ) {
288
+ if (typeof targetSiteId !== "string" || targetSiteId === site.id) return site;
289
+ const target = await ctx.store.getSite(targetSiteId);
290
+ const scoped = target ? forSite(ctx.principal, target.id) : undefined;
291
+ if (!target || target.projectId !== site.projectId || !scoped)
292
+ throw new ToolError("not_found", `no site ${targetSiteId} in this site's project`);
293
+ if (!holds(scoped.scopes, "content:write"))
294
+ throw new ToolError("denied", "missing scope content:write on the edition");
295
+ return target;
296
+ }
297
+
298
+ /** The source gains `translation: { group: its id, method: "original" }`. */
299
+ async function markOriginal(ctx , source ) {
300
+ const translation = { group: source.id, method: "original" };
301
+ try {
302
+ if ("sections" in source)
303
+ return await ctx.store.updatePage({ ...source, translation }, { writer: mcpWriter(ctx) });
304
+ return await ctx.store.updateContentEntry(
305
+ { ...source, translation },
306
+ { writer: mcpWriter(ctx) },
307
+ );
308
+ } catch (e) {
309
+ mapError(e);
310
+ }
311
+ }
312
+
313
+ /** The draft node: a new translation, or the existing machine one with the new text. */
314
+ function translatedNode(input
315
+
316
+
317
+
318
+
319
+
320
+
321
+ ) {
322
+ const { a, site, locale, source, existing, translation } = input;
323
+ const common = {
324
+ siteId: site,
325
+ locale,
326
+ status: "draft" ,
327
+ title: a.title ,
328
+ translation,
329
+ };
330
+ if ("sections" in source) {
331
+ const base = (existing ) ?? { ...source, id: "", rev: 0 };
332
+ return {
333
+ ...base,
334
+ ...common,
335
+ path: (a.path ) ?? base.path,
336
+ ...(a.seo ? { seo: a.seo } : {}),
337
+ sections: (a.sections ) ?? base.sections,
338
+ } ;
339
+ }
340
+ const base = (existing ) ?? { ...source, id: "", rev: 0 };
341
+ const cover = translatedCover(base.coverImage, a.coverAlt , !existing);
342
+ const { coverImage: _cover, ...rest } = base;
343
+ return {
344
+ ...rest,
345
+ ...common,
346
+ slug: (a.slug ) ?? base.slug,
347
+ body: { format: "markdown", value: (a.body ) ?? base.body.value },
348
+ ...(a.summary !== undefined ? { summary: a.summary } : {}),
349
+ ...(cover ? { coverImage: cover } : {}),
350
+ } ;
351
+ }
352
+
353
+ /**
354
+ * The cover of a translated entry: the given alt text in its language, or — for a new translation
355
+ * — no copy of the source's alt override, which is in the source's language.
356
+ */
357
+ function translatedCover(
358
+ cover ,
359
+ alt ,
360
+ fresh ,
361
+ ) {
362
+ if (!cover) return undefined;
363
+ if (alt !== undefined) return { ...cover, alt };
364
+ // An empty alt falls back to the image's own alt text in the entry's language.
365
+ return fresh ? { ...cover, alt: "" } : cover;
366
+ }
367
+
368
+ /** Creates the translation or updates the existing one (CAS on its `rev`). */
369
+ async function writeTranslation(
370
+ ctx ,
371
+ siteId ,
372
+ node ,
373
+ existing ,
374
+ ) {
375
+ const writer = { writer: mcpWriter(ctx) };
376
+ if (existing && "sections" in node) return ctx.store.updatePage(node, writer);
377
+ if (existing) return ctx.store.updateContentEntry(node , writer);
378
+ const { id: _id, rev: _rev, createdAt: _c, updatedAt: _u, schemaVersion: _s, ...fresh } = node;
379
+ if ("sections" in node) {
380
+ const site = await requireSite(ctx, siteId);
381
+ return (await ctx.store.createPage(site, fresh , writer)).page;
382
+ }
383
+ const { publishedAt: _p, corrections: _k, ...entry } = fresh ;
384
+ return ctx.store.createContentEntry(
385
+ { ...entry, author: ctx.principal.actor } ,
386
+ writer,
387
+ );
388
+ }
389
+
390
+ const listStaleTool = {
391
+ name: "list_stale_translations",
392
+ title: "List stale translations",
393
+ description:
394
+ "Translations whose source changed since they were made (or whose source is gone), optionally in one locale: the work queue for keeping languages in step. Re-translate each with get_translation_source and save_translation.",
395
+ inputSchema: obj({ siteId: id, locale: str("Only this locale") }, ["siteId"]),
396
+ outputSchema: obj({ stale: { type: "array", items: { type: "object" } } }, ["stale"]),
397
+ annotations: READ,
398
+ scopes: ["content:read"],
399
+ handler: async (a, ctx) => {
400
+ const site = await requireSite(ctx, a.siteId );
401
+ const nodes = [
402
+ ...(await ctx.store.listPages(site.id)),
403
+ ...(await ctx.store.listContentEntries(site.id)),
404
+ ];
405
+ const groups = [...new Set(nodes.flatMap((n) => (n.translation ? [n.translation.group] : [])))];
406
+ const stale = [];
407
+ for (const g of groups)
408
+ for (const m of (await ctx.store.translationGroup(site, g)).members)
409
+ if (
410
+ (m.stale || m.sourceMissing) &&
411
+ m.siteId === site.id &&
412
+ (!a.locale || m.locale === a.locale)
413
+ )
414
+ stale.push({ ...m, group: g });
415
+ return { stale };
416
+ },
417
+ };
418
+
419
+ /** list_translations, list_stale_translations, get_translation_source, save_translation. */
420
+ export function translationTools() {
421
+ return [listTranslationsTool, listStaleTool, getSourceTool, saveTranslationTool];
422
+ }
package/package.json CHANGED
@@ -1,6 +1,89 @@
1
1
  {
2
2
  "name": "@cloudhal/mcp-server",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.1.1",
4
+ "description": "Cloudhal MCP server: semantic site tools (pages, articles, snapshots, preview, publish) governed by the policy engine",
5
+ "license": "Apache-2.0",
6
+ "homepage": "https://cloudhal.dev",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/cloudhal-dev/cloudhal.git",
10
+ "directory": "packages/mcp-server"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/cloudhal-dev/cloudhal/issues"
14
+ },
15
+ "type": "module",
16
+ "exports": {
17
+ ".": {
18
+ "types": "./dist/src/index.d.ts",
19
+ "default": "./dist/src/index.js"
20
+ },
21
+ "./tools": {
22
+ "types": "./dist/src/tools.d.ts",
23
+ "default": "./dist/src/tools.js"
24
+ },
25
+ "./body": {
26
+ "types": "./dist/src/body-tools.d.ts",
27
+ "default": "./dist/src/body-tools.js"
28
+ },
29
+ "./analytics": {
30
+ "types": "./dist/src/analytics-reports.d.ts",
31
+ "default": "./dist/src/analytics-reports.js"
32
+ },
33
+ "./comments": {
34
+ "types": "./dist/src/comments.d.ts",
35
+ "default": "./dist/src/comments.js"
36
+ },
37
+ "./schedules": {
38
+ "types": "./dist/src/schedules.d.ts",
39
+ "default": "./dist/src/schedules.js"
40
+ },
41
+ "./render": {
42
+ "types": "./dist/src/render.d.ts",
43
+ "default": "./dist/src/render.js"
44
+ },
45
+ "./stdio": {
46
+ "types": "./dist/src/stdio.d.ts",
47
+ "default": "./dist/src/stdio.js"
48
+ },
49
+ "./http": {
50
+ "types": "./dist/src/http.d.ts",
51
+ "default": "./dist/src/http.js"
52
+ }
53
+ },
54
+ "files": [
55
+ "dist",
56
+ "README.md"
57
+ ],
58
+ "dependencies": {
59
+ "@cloudhal/analytics": "0.1.1",
60
+ "@cloudhal/agent-runtime": "0.1.1",
61
+ "@cloudhal/astro-renderer": "0.1.1",
62
+ "@cloudhal/comments": "0.1.1",
63
+ "@cloudhal/core-contracts": "0.1.1",
64
+ "@cloudhal/core-ts": "0.1.1",
65
+ "@cloudhal/storage": "0.1.1",
66
+ "@modelcontextprotocol/server": "2.3.1",
67
+ "@cloudhal/schedules": "0.1.1"
68
+ },
69
+ "devDependencies": {
70
+ "@cloudflare/workers-types": "^5.20261007.1",
71
+ "@modelcontextprotocol/client": "2.3.1",
72
+ "@types/node": "^26.6.5",
73
+ "better-sqlite3": "13.0.3",
74
+ "happy-dom": "^21.0.1",
75
+ "typescript": "7.0.2",
76
+ "vitest": "5.0.3"
77
+ },
78
+ "engines": {
79
+ "node": ">=24"
80
+ },
81
+ "publishConfig": {
82
+ "access": "public"
83
+ },
84
+ "scripts": {
85
+ "typecheck": "tsc --noEmit -p tsconfig.json",
86
+ "test": "vitest run",
87
+ "check": "pnpm typecheck && pnpm test"
88
+ }
6
89
  }