@contentrain/mcp 1.9.0 → 1.10.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 (58) hide show
  1. package/README.md +10 -3
  2. package/dist/{annotations-DSzewhL4.mjs → annotations-D3tlsF38.mjs} +39 -4
  3. package/dist/annotations-D3tlsF38.mjs.map +1 -0
  4. package/dist/{apply-manager-BnPbPXFG.mjs → apply-manager-UXUTYFZn.mjs} +3 -3
  5. package/dist/{apply-manager-BnPbPXFG.mjs.map → apply-manager-UXUTYFZn.mjs.map} +1 -1
  6. package/dist/{availability-Bj9zOfEn.mjs → availability-sWWRz2W0.mjs} +8 -2
  7. package/dist/availability-sWWRz2W0.mjs.map +1 -0
  8. package/dist/branch-lifecycle-AwBJIheA.d.mts.map +1 -1
  9. package/dist/{branch-lifecycle-D7tXOE4f.mjs → branch-lifecycle-Dd84lx37.mjs} +61 -3
  10. package/dist/branch-lifecycle-Dd84lx37.mjs.map +1 -0
  11. package/dist/{content-manager-BExZy6Eu.d.mts → content-manager-DcmNwvmq.d.mts} +2 -2
  12. package/dist/{content-manager-BExZy6Eu.d.mts.map → content-manager-DcmNwvmq.d.mts.map} +1 -1
  13. package/dist/core/apply-manager.mjs +3 -3
  14. package/dist/core/config.d.mts +1 -1
  15. package/dist/core/content-manager.d.mts +1 -1
  16. package/dist/core/context.d.mts +1 -1
  17. package/dist/core/contracts/index.d.mts +2 -2
  18. package/dist/core/doctor.mjs +2 -2
  19. package/dist/core/model-manager.d.mts +1 -1
  20. package/dist/core/ops/index.d.mts +2 -2
  21. package/dist/core/overlay-reader.d.mts +1 -1
  22. package/dist/core/validator/index.d.mts +1 -1
  23. package/dist/{doctor-BTToHt0y.mjs → doctor-BwSJW1sS.mjs} +2 -2
  24. package/dist/{doctor-BTToHt0y.mjs.map → doctor-BwSJW1sS.mjs.map} +1 -1
  25. package/dist/git/branch-lifecycle.mjs +1 -1
  26. package/dist/git/transaction.d.mts.map +1 -1
  27. package/dist/git/transaction.mjs +2 -2
  28. package/dist/index-DDX-qYNw.d.mts +2 -0
  29. package/dist/index.mjs +7 -7
  30. package/dist/{local-BZEUWBoC.mjs → local-BIE23GuI.mjs} +3 -3
  31. package/dist/{local-BZEUWBoC.mjs.map → local-BIE23GuI.mjs.map} +1 -1
  32. package/dist/providers/github/index.d.mts +1 -1
  33. package/dist/providers/gitlab/index.d.mts +1 -1
  34. package/dist/providers/local/index.d.mts +1 -1
  35. package/dist/providers/local/index.mjs +3 -3
  36. package/dist/server/http/index.d.mts +1 -1
  37. package/dist/server/http/index.mjs +7 -7
  38. package/dist/{server-B6_fzRmK.mjs → server-BkDuFvVt.mjs} +139 -9
  39. package/dist/server-BkDuFvVt.mjs.map +1 -0
  40. package/dist/{server-B1KfvywF.d.mts → server-vA1tM7DA.d.mts} +2 -2
  41. package/dist/{server-B1KfvywF.d.mts.map → server-vA1tM7DA.d.mts.map} +1 -1
  42. package/dist/server.d.mts +1 -1
  43. package/dist/server.mjs +7 -7
  44. package/dist/tools/annotations.d.mts +3 -3
  45. package/dist/tools/annotations.d.mts.map +1 -1
  46. package/dist/tools/annotations.mjs +1 -1
  47. package/dist/tools/availability.d.mts +3 -0
  48. package/dist/tools/availability.d.mts.map +1 -1
  49. package/dist/tools/availability.mjs +1 -1
  50. package/dist/{transaction-qliKvBRL.mjs → transaction-DhVoGigz.mjs} +4 -22
  51. package/dist/transaction-DhVoGigz.mjs.map +1 -0
  52. package/package.json +4 -4
  53. package/dist/annotations-DSzewhL4.mjs.map +0 -1
  54. package/dist/availability-Bj9zOfEn.mjs.map +0 -1
  55. package/dist/branch-lifecycle-D7tXOE4f.mjs.map +0 -1
  56. package/dist/index-6yasXNLQ.d.mts +0 -2
  57. package/dist/server-B6_fzRmK.mjs.map +0 -1
  58. package/dist/transaction-qliKvBRL.mjs.map +0 -1
@@ -5,19 +5,19 @@ import { n as readVocabulary, t as readConfig } from "./config-DlFcTxFG.mjs";
5
5
  import { S as writeContent, _ as resolveMdFilePath, a as fieldDefZodSchema, c as validateModelDefinition, d as listContent, g as resolveLocaleStrategy, h as resolveJsonFilePath, l as writeModel, m as resolveContentDir, n as checkReferences, o as listModels, r as countEntries, s as readModel, u as deleteContent } from "./model-manager-BhLsUgaB.mjs";
6
6
  import { n as readMeta, r as writeMeta } from "./meta-manager-C900rEyG.mjs";
7
7
  import { n as readContext } from "./context-CYN__o3Q.mjs";
8
- import { a as deleteRemoteBranch, c as pruneMergedRemoteBranches, i as cleanupMergedBranches, n as checkBranchHealth, s as listRemoteCrBranches } from "./branch-lifecycle-D7tXOE4f.mjs";
9
- import { i as mergeBranch, n as createTransaction, r as ensureContentBranch, t as buildBranchName } from "./transaction-qliKvBRL.mjs";
10
- import { n as isMerged, t as LocalProvider } from "./local-BZEUWBoC.mjs";
11
- import { n as isToolAvailable, t as TOOL_REQUIREMENTS } from "./availability-Bj9zOfEn.mjs";
8
+ import { a as deleteRemoteBranch, c as pruneMergedRemoteBranches, i as cleanupMergedBranches, n as checkBranchHealth, s as listRemoteCrBranches } from "./branch-lifecycle-Dd84lx37.mjs";
9
+ import { i as mergeBranch, n as createTransaction, r as ensureContentBranch, t as buildBranchName } from "./transaction-DhVoGigz.mjs";
10
+ import { n as isMerged, t as LocalProvider } from "./local-BIE23GuI.mjs";
11
+ import { n as isToolAvailable, t as TOOL_REQUIREMENTS } from "./availability-sWWRz2W0.mjs";
12
12
  import { t as detectStack } from "./detect-wVSI9VuY.mjs";
13
- import { t as TOOL_ANNOTATIONS } from "./annotations-DSzewhL4.mjs";
13
+ import { t as TOOL_ANNOTATIONS } from "./annotations-D3tlsF38.mjs";
14
14
  import { n as listTemplates, t as getTemplate } from "./templates-D6EllixQ.mjs";
15
15
  import { t as validateProject } from "./validator-8vaPxSba.mjs";
16
16
  import { t as OverlayReader } from "./overlay-reader-BOb105gS.mjs";
17
17
  import { t as buildGraph } from "./graph-builder-CRUX_8mA.mjs";
18
18
  import { n as scanSummary, t as scanCandidates } from "./scanner-VOwrKLGC.mjs";
19
- import { n as applyExtract, r as applyReuse } from "./apply-manager-BnPbPXFG.mjs";
20
- import { t as runDoctor } from "./doctor-BTToHt0y.mjs";
19
+ import { n as applyExtract, r as applyReuse } from "./apply-manager-UXUTYFZn.mjs";
20
+ import { t as runDoctor } from "./doctor-BwSJW1sS.mjs";
21
21
  import { join } from "node:path";
22
22
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
23
23
  import { CONTENTRAIN_BRANCH } from "@contentrain/types";
@@ -2368,8 +2368,137 @@ function registerDoctorTools(server, _provider, projectRoot) {
2368
2368
  });
2369
2369
  }
2370
2370
  //#endregion
2371
+ //#region src/tools/media.ts
2372
+ /**
2373
+ * Media tools — a deterministic passthrough to the provider's optional
2374
+ * media facet (`RepoProvider.media`). Registration is capability-aware:
2375
+ * `createServer` skips all five tools when the provider has no media
2376
+ * stack, so the guard below is defense in depth only.
2377
+ *
2378
+ * The facet closes the discovery loop for external agents: list assets →
2379
+ * pick a `media/...` path → reference it via `contentrain_content_save`
2380
+ * (which normalizes it to an absolute delivery URL when `mediaBaseUrl`
2381
+ * is set). Ingest is URL-based — MCP has no binary channel — and the
2382
+ * provider implementation owns SSRF/MIME/size policy for the fetch.
2383
+ */
2384
+ function mediaUnavailable(tool) {
2385
+ return {
2386
+ content: [{
2387
+ type: "text",
2388
+ text: JSON.stringify({
2389
+ error: `${tool} requires a provider with a media stack.`,
2390
+ capability_required: "media",
2391
+ hint: "Media tools are available when MCP is driven by a media-capable provider (e.g. Studio MCP Cloud). Local and plain git providers do not expose one."
2392
+ })
2393
+ }],
2394
+ isError: true
2395
+ };
2396
+ }
2397
+ function mediaError(error, stage) {
2398
+ return {
2399
+ content: [{
2400
+ type: "text",
2401
+ text: JSON.stringify({ ...normalizeOperationError(error, stage) })
2402
+ }],
2403
+ isError: true
2404
+ };
2405
+ }
2406
+ function ok(payload) {
2407
+ return { content: [{
2408
+ type: "text",
2409
+ text: JSON.stringify(payload)
2410
+ }] };
2411
+ }
2412
+ function registerMediaTools(server, provider, _projectRoot) {
2413
+ server.tool("contentrain_media_list", "List media assets from the provider media stack. Returns storage paths (media/...) usable in media/image/file fields via contentrain_content_save, plus delivery URLs when available. Supports search, tag filter, and cursor pagination.", {
2414
+ search: z.string().optional().describe("Substring match on filename/path/alt"),
2415
+ tag: z.string().optional().describe("Only assets carrying this tag"),
2416
+ limit: z.number().int().min(1).max(100).optional().describe("Page size. Default: provider-defined"),
2417
+ cursor: z.string().optional().describe("Opaque cursor from a previous response")
2418
+ }, TOOL_ANNOTATIONS["contentrain_media_list"], async (input) => {
2419
+ if (!provider.media) return mediaUnavailable("contentrain_media_list");
2420
+ try {
2421
+ const result = await provider.media.list(input);
2422
+ return ok({
2423
+ assets: result.assets,
2424
+ next_cursor: result.nextCursor,
2425
+ total: result.total
2426
+ });
2427
+ } catch (error) {
2428
+ return mediaError(error, "media_list");
2429
+ }
2430
+ });
2431
+ server.tool("contentrain_media_get", "Get a single media asset by id, including its storage path, delivery URL, and metadata.", { id: z.string().describe("Asset id (from contentrain_media_list)") }, TOOL_ANNOTATIONS["contentrain_media_get"], async (input) => {
2432
+ if (!provider.media) return mediaUnavailable("contentrain_media_get");
2433
+ try {
2434
+ const asset = await provider.media.get(input.id);
2435
+ if (!asset) return {
2436
+ content: [{
2437
+ type: "text",
2438
+ text: JSON.stringify({
2439
+ error: `Media asset not found: ${input.id}`,
2440
+ hint: "Use contentrain_media_list to discover asset ids."
2441
+ })
2442
+ }],
2443
+ isError: true
2444
+ };
2445
+ return ok({ asset });
2446
+ } catch (error) {
2447
+ return mediaError(error, "media_get");
2448
+ }
2449
+ });
2450
+ server.tool("contentrain_media_ingest", "Ingest a media asset from a source URL. The provider fetches the URL server-side under its own SSRF/MIME/size policy and stores the asset in the media stack. Returns the stored asset with its media/... path.", {
2451
+ url: z.string().url().describe("Source URL to fetch server-side"),
2452
+ filename: z.string().optional().describe("Target filename override"),
2453
+ alt: z.string().optional().describe("Alt text for the asset"),
2454
+ tags: z.array(z.string()).max(20).optional().describe("Tags to attach")
2455
+ }, TOOL_ANNOTATIONS["contentrain_media_ingest"], async (input) => {
2456
+ if (!provider.media) return mediaUnavailable("contentrain_media_ingest");
2457
+ try {
2458
+ return ok({
2459
+ status: "ingested",
2460
+ asset: await provider.media.ingest(input)
2461
+ });
2462
+ } catch (error) {
2463
+ return mediaError(error, "media_ingest");
2464
+ }
2465
+ });
2466
+ server.tool("contentrain_media_update", "Update metadata (alt text, tags, filename) of an existing media asset. Does not touch the binary.", {
2467
+ id: z.string().describe("Asset id to update"),
2468
+ alt: z.string().optional().describe("New alt text"),
2469
+ tags: z.array(z.string()).max(20).optional().describe("Replacement tag list"),
2470
+ filename: z.string().optional().describe("New filename")
2471
+ }, TOOL_ANNOTATIONS["contentrain_media_update"], async (input) => {
2472
+ if (!provider.media) return mediaUnavailable("contentrain_media_update");
2473
+ try {
2474
+ const { id, ...patch } = input;
2475
+ return ok({
2476
+ status: "updated",
2477
+ asset: await provider.media.update(id, patch)
2478
+ });
2479
+ } catch (error) {
2480
+ return mediaError(error, "media_update");
2481
+ }
2482
+ });
2483
+ server.tool("contentrain_media_delete", "Delete a media asset from the media stack. Content entries referencing its path are NOT rewritten — check references before deleting.", {
2484
+ id: z.string().describe("Asset id to delete"),
2485
+ confirm: z.literal(true).describe("Must be true to confirm deletion")
2486
+ }, TOOL_ANNOTATIONS["contentrain_media_delete"], async (input) => {
2487
+ if (!provider.media) return mediaUnavailable("contentrain_media_delete");
2488
+ try {
2489
+ await provider.media.delete(input.id);
2490
+ return ok({
2491
+ status: "deleted",
2492
+ id: input.id
2493
+ });
2494
+ } catch (error) {
2495
+ return mediaError(error, "media_delete");
2496
+ }
2497
+ });
2498
+ }
2499
+ //#endregion
2371
2500
  //#region package.json
2372
- var version = "1.9.0";
2501
+ var version = "1.10.1";
2373
2502
  //#endregion
2374
2503
  //#region src/server.ts
2375
2504
  /**
@@ -2410,6 +2539,7 @@ function createServer(input) {
2410
2539
  registerNormalizeTools(server, provider, projectRoot);
2411
2540
  registerBulkTools(server, provider, projectRoot);
2412
2541
  registerDoctorTools(server, provider, projectRoot);
2542
+ registerMediaTools(server, provider, projectRoot);
2413
2543
  return server;
2414
2544
  }
2415
2545
  function resolveServerContext(input) {
@@ -2438,4 +2568,4 @@ function resolveServerContext(input) {
2438
2568
  //#endregion
2439
2569
  export { createServer as n, DEFAULT_INSTRUCTIONS as t };
2440
2570
 
2441
- //# sourceMappingURL=server-B6_fzRmK.mjs.map
2571
+ //# sourceMappingURL=server-BkDuFvVt.mjs.map