@collage-dam/mcp-server 0.1.9 → 0.1.10
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/CHANGELOG.md +39 -0
- package/dist/tools/search/cursor.d.ts +7 -0
- package/dist/tools/search/cursor.d.ts.map +1 -1
- package/dist/tools/search/cursor.js +33 -0
- package/dist/tools/search/cursor.js.map +1 -1
- package/dist/tools/view-category-contents.d.ts +23 -0
- package/dist/tools/view-category-contents.d.ts.map +1 -1
- package/dist/tools/view-category-contents.js +51 -13
- package/dist/tools/view-category-contents.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,45 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.1.10] — 2026-05-22
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
- **`view_category_contents` silently truncated folder listings** when
|
|
14
|
+
upstream paginated below the caller's `page_size`. Reported by Ross
|
|
15
|
+
2026-05-19 on the "lifestyle photography" folder (38 assets total,
|
|
16
|
+
27 returned, 11 unreachable; LLM treated the partial set as
|
|
17
|
+
complete). Root cause: the prior `next_cursor` math assumed upstream
|
|
18
|
+
returned `page_size` items per call (`offset + pageSize < total`)
|
|
19
|
+
but `digital-assets/category/view-files-with-category` paginates at
|
|
20
|
+
its own internal size (~25/page) regardless of `page_size`. The
|
|
21
|
+
inequality came out false on page 1 of small folders → `next_cursor:
|
|
22
|
+
null` → LLM saw "no more pages."
|
|
23
|
+
|
|
24
|
+
Fix: cursor is now a page-based opaque base64url JSON (matching the
|
|
25
|
+
`search_assets` cursor pattern). The handler decodes the cursor as
|
|
26
|
+
an upstream page number directly, fetches that page, and emits
|
|
27
|
+
`has_more` + `next_cursor` based on the upstream-reported `last_page`
|
|
28
|
+
field — which is the actual ground truth for "more pages exist."
|
|
29
|
+
Caller's `page_size` is now documented as advisory (upstream owns
|
|
30
|
+
page size).
|
|
31
|
+
|
|
32
|
+
### Added
|
|
33
|
+
- `view_category_contents` response now surfaces `page`, `total_pages`,
|
|
34
|
+
and `has_more` alongside the existing `next_cursor` and
|
|
35
|
+
`total_estimate`. LLM consumers no longer have to interpret cursor
|
|
36
|
+
presence — `has_more: true` is the explicit signal that walking
|
|
37
|
+
more pages is required to enumerate the folder.
|
|
38
|
+
|
|
39
|
+
- Live contract test in `folder-tools.contract.test.ts` walks the
|
|
40
|
+
cursor on a multi-page BREZ folder until `next_cursor` is null and
|
|
41
|
+
asserts `seenIds.size === total_estimate` — i.e. the documented
|
|
42
|
+
contract reaches every asset, with no duplicates or gaps.
|
|
43
|
+
|
|
44
|
+
- `encodePageCursor` / `decodePageCursor` in `src/tools/search/cursor.ts`
|
|
45
|
+
for tools where upstream owns the page size and only the page number
|
|
46
|
+
needs to round-trip in the cursor. Same opaque base64url JSON shape
|
|
47
|
+
as the search cursor (`{v, p}` rather than `{v, p, n}`).
|
|
48
|
+
|
|
10
49
|
## [0.1.9] — 2026-05-22
|
|
11
50
|
|
|
12
51
|
### Fixed
|
|
@@ -35,4 +35,11 @@ export declare function budgetMaxPerPage(projection: Projection): number;
|
|
|
35
35
|
* the projection-specific budget max.
|
|
36
36
|
*/
|
|
37
37
|
export declare function effectivePerPage(requested: number, projection: Projection): number;
|
|
38
|
+
/** Encode an upstream page number as an opaque continuation cursor. */
|
|
39
|
+
export declare function encodePageCursor(page: number): string;
|
|
40
|
+
/**
|
|
41
|
+
* Decode a page-only cursor. Returns null on malformed input so callers
|
|
42
|
+
* can fall back to page 1.
|
|
43
|
+
*/
|
|
44
|
+
export declare function decodePageCursor(cursor: string): number | null;
|
|
38
45
|
//# sourceMappingURL=cursor.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cursor.d.ts","sourceRoot":"","sources":["../../../src/tools/search/cursor.ts"],"names":[],"mappings":"AAuBA,kEAAkE;AAClE,eAAO,MAAM,cAAc,IAAI,CAAC;AAQhC,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM,CAOjE;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CASvE;AAkBD,eAAO,MAAM,sBAAsB;;;CAGzB,CAAC;AAEX,MAAM,MAAM,UAAU,GAAG,MAAM,OAAO,sBAAsB,CAAC;AAE7D;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,UAAU,GAAG,MAAM,CAE/D;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,UAAU,GACrB,MAAM,CAER"}
|
|
1
|
+
{"version":3,"file":"cursor.d.ts","sourceRoot":"","sources":["../../../src/tools/search/cursor.ts"],"names":[],"mappings":"AAuBA,kEAAkE;AAClE,eAAO,MAAM,cAAc,IAAI,CAAC;AAQhC,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM,CAOjE;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CASvE;AAkBD,eAAO,MAAM,sBAAsB;;;CAGzB,CAAC;AAEX,MAAM,MAAM,UAAU,GAAG,MAAM,OAAO,sBAAsB,CAAC;AAE7D;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,UAAU,GAAG,MAAM,CAE/D;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,UAAU,GACrB,MAAM,CAER;AAgBD,uEAAuE;AACvE,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAGrD;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAS9D"}
|
|
@@ -92,4 +92,37 @@ export function budgetMaxPerPage(projection) {
|
|
|
92
92
|
export function effectivePerPage(requested, projection) {
|
|
93
93
|
return Math.min(requested, budgetMaxPerPage(projection));
|
|
94
94
|
}
|
|
95
|
+
// ── Page-only cursor (for tools where upstream owns the page size) ──
|
|
96
|
+
//
|
|
97
|
+
// `view_category_contents` paginates through
|
|
98
|
+
// `digital-assets/category/view-files-with-category`, which uses
|
|
99
|
+
// upstream's own internal page size (~25 in production). Our caller
|
|
100
|
+
// can't control that, so we don't carry `per_page` in the cursor —
|
|
101
|
+
// just the upstream page number. Same opaque base64url-JSON shape as
|
|
102
|
+
// `encodeSearchCursor` for consistency, with `n: 0` as a sentinel.
|
|
103
|
+
const PageCursorPayloadSchema = z.object({
|
|
104
|
+
v: z.literal(1),
|
|
105
|
+
p: z.number().int().min(1),
|
|
106
|
+
});
|
|
107
|
+
/** Encode an upstream page number as an opaque continuation cursor. */
|
|
108
|
+
export function encodePageCursor(page) {
|
|
109
|
+
const json = JSON.stringify({ v: CURSOR_VERSION, p: page });
|
|
110
|
+
return Buffer.from(json, 'utf-8').toString('base64url');
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Decode a page-only cursor. Returns null on malformed input so callers
|
|
114
|
+
* can fall back to page 1.
|
|
115
|
+
*/
|
|
116
|
+
export function decodePageCursor(cursor) {
|
|
117
|
+
try {
|
|
118
|
+
const decoded = Buffer.from(cursor, 'base64url').toString('utf-8');
|
|
119
|
+
const parsed = PageCursorPayloadSchema.safeParse(JSON.parse(decoded));
|
|
120
|
+
if (!parsed.success)
|
|
121
|
+
return null;
|
|
122
|
+
return parsed.data.p;
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
95
128
|
//# sourceMappingURL=cursor.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cursor.js","sourceRoot":"","sources":["../../../src/tools/search/cursor.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,uEAAuE;AACvE,uEAAuE;AACvE,mEAAmE;AACnE,+DAA+D;AAC/D,uDAAuD;AACvD,EAAE;AACF,+CAA+C;AAC/C,oEAAoE;AACpE,4CAA4C;AAC5C,qEAAqE;AACrE,sEAAsE;AACtE,sCAAsC;AACtC,EAAE;AACF,gEAAgE;AAChE,uEAAuE;AACvE,qEAAqE;AACrE,sEAAsE;AACtE,kEAAkE;AAClE,6DAA6D;AAE7D,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,kEAAkE;AAClE,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC;AAEhC,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC;IACnC,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IACf,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1B,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;CAC3B,CAAC,CAAC;AAOH;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAAsB;IACvD,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC;QAC1B,CAAC,EAAE,cAAc;QACjB,CAAC,EAAE,OAAO,CAAC,IAAI;QACf,CAAC,EAAE,OAAO,CAAC,QAAQ;KACpB,CAAC,CAAC;IACH,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;AAC1D,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAc;IAC/C,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QACnE,MAAM,MAAM,GAAG,mBAAmB,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;QAClE,IAAI,CAAC,MAAM,CAAC,OAAO;YAAE,OAAO,IAAI,CAAC;QACjC,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;IAC1D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,wEAAwE;AACxE,EAAE;AACF,qEAAqE;AACrE,yEAAyE;AACzE,qEAAqE;AACrE,sDAAsD;AACtD,EAAE;AACF,wEAAwE;AACxE,oEAAoE;AACpE,wDAAwD;AACxD,EAAE;AACF,wEAAwE;AACxE,qEAAqE;AAErE,OAAO,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AAEvE,MAAM,CAAC,MAAM,sBAAsB,GAAG;IACpC,OAAO,EAAE,GAAG;IACZ,OAAO,EAAE,GAAG;CACJ,CAAC;AAIX;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,UAAsB;IACrD,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,eAAe,GAAG,sBAAsB,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AACvF,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAC9B,SAAiB,EACjB,UAAsB;IAEtB,OAAO,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,gBAAgB,CAAC,UAAU,CAAC,CAAC,CAAC;AAC3D,CAAC"}
|
|
1
|
+
{"version":3,"file":"cursor.js","sourceRoot":"","sources":["../../../src/tools/search/cursor.ts"],"names":[],"mappings":"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"}
|
|
@@ -99,12 +99,27 @@ export declare const ViewCategoryContentsOutputSchema: z.ZodObject<{
|
|
|
99
99
|
tag_name: string;
|
|
100
100
|
}>, "many">>;
|
|
101
101
|
}, z.ZodTypeAny, "passthrough">>, "many">;
|
|
102
|
+
/** Opaque continuation cursor. Pass back as `cursor` for the next page. */
|
|
102
103
|
next_cursor: z.ZodNullable<z.ZodString>;
|
|
104
|
+
/** Upstream's reported total asset count for this folder, or null when unknown. */
|
|
103
105
|
total_estimate: z.ZodNullable<z.ZodNumber>;
|
|
106
|
+
/**
|
|
107
|
+
* Number of upstream pages reported by the API. Useful for callers
|
|
108
|
+
* that want to know how many cursor round-trips they're committing to.
|
|
109
|
+
*/
|
|
110
|
+
total_pages: z.ZodNumber;
|
|
111
|
+
/** 1-based upstream page number returned in this response. */
|
|
112
|
+
page: z.ZodNumber;
|
|
113
|
+
/**
|
|
114
|
+
* True when `next_cursor !== null`. Surfaced explicitly so LLM
|
|
115
|
+
* consumers don't have to interpret cursor presence themselves.
|
|
116
|
+
*/
|
|
117
|
+
has_more: z.ZodBoolean;
|
|
104
118
|
request_id: z.ZodString;
|
|
105
119
|
}, "strip", z.ZodTypeAny, {
|
|
106
120
|
request_id: string;
|
|
107
121
|
category_id: string | number;
|
|
122
|
+
page: number;
|
|
108
123
|
assets: z.objectOutputType<{
|
|
109
124
|
id: z.ZodUnion<[z.ZodNumber, z.ZodString]>;
|
|
110
125
|
display_file_name: z.ZodOptional<z.ZodString>;
|
|
@@ -134,9 +149,12 @@ export declare const ViewCategoryContentsOutputSchema: z.ZodObject<{
|
|
|
134
149
|
category_path?: string | null | undefined;
|
|
135
150
|
integration_type?: number | undefined;
|
|
136
151
|
}[];
|
|
152
|
+
total_pages: number;
|
|
153
|
+
has_more: boolean;
|
|
137
154
|
}, {
|
|
138
155
|
request_id: string;
|
|
139
156
|
category_id: string | number;
|
|
157
|
+
page: number;
|
|
140
158
|
assets: z.objectInputType<{
|
|
141
159
|
id: z.ZodUnion<[z.ZodNumber, z.ZodString]>;
|
|
142
160
|
display_file_name: z.ZodOptional<z.ZodString>;
|
|
@@ -166,6 +184,8 @@ export declare const ViewCategoryContentsOutputSchema: z.ZodObject<{
|
|
|
166
184
|
category_path?: string | null | undefined;
|
|
167
185
|
integration_type?: number | undefined;
|
|
168
186
|
}[];
|
|
187
|
+
total_pages: number;
|
|
188
|
+
has_more: boolean;
|
|
169
189
|
}>;
|
|
170
190
|
export type ViewCategoryContentsOutput = z.infer<typeof ViewCategoryContentsOutputSchema>;
|
|
171
191
|
export type ViewCategoryContentsClient = Pick<CollageClient, 'listSubCategories' | 'listAssetsByCategory'>;
|
|
@@ -196,6 +216,7 @@ export declare function buildViewCategoryContentsHandler(client: ViewCategoryCon
|
|
|
196
216
|
structuredContent: {
|
|
197
217
|
request_id: string;
|
|
198
218
|
category_id: string | number;
|
|
219
|
+
page: number;
|
|
199
220
|
assets: z.objectOutputType<{
|
|
200
221
|
id: z.ZodUnion<[z.ZodNumber, z.ZodString]>;
|
|
201
222
|
display_file_name: z.ZodOptional<z.ZodString>;
|
|
@@ -225,6 +246,8 @@ export declare function buildViewCategoryContentsHandler(client: ViewCategoryCon
|
|
|
225
246
|
category_path?: string | null | undefined;
|
|
226
247
|
integration_type?: number | undefined;
|
|
227
248
|
}[];
|
|
249
|
+
total_pages: number;
|
|
250
|
+
has_more: boolean;
|
|
228
251
|
};
|
|
229
252
|
isError?: undefined;
|
|
230
253
|
}>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"view-category-contents.d.ts","sourceRoot":"","sources":["../../src/tools/view-category-contents.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"view-category-contents.d.ts","sourceRoot":"","sources":["../../src/tools/view-category-contents.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAalD,eAAO,MAAM,+BAA+B;;;;;;;;;;;;;;;;;;EAM1C,CAAC;AACH,MAAM,MAAM,yBAAyB,GAAG,CAAC,CAAC,KAAK,CAC7C,OAAO,+BAA+B,CACvC,CAAC;AAEF,eAAO,MAAM,gCAAgC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAI3C,2EAA2E;;IAE3E,mFAAmF;;IAEnF;;;OAGG;;IAEH,8DAA8D;;IAE9D;;;OAGG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAGH,CAAC;AACH,MAAM,MAAM,0BAA0B,GAAG,CAAC,CAAC,KAAK,CAC9C,OAAO,gCAAgC,CACxC,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG,IAAI,CAC3C,aAAa,EACb,mBAAmB,GAAG,sBAAsB,CAC7C,CAAC;AAEF,eAAO,MAAM,kCAAkC,QAQU,CAAC;AAE1D,wBAAgB,gCAAgC,CAC9C,MAAM,EAAE,0BAA0B,IAEpB,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgF9C"}
|
|
@@ -5,11 +5,22 @@
|
|
|
5
5
|
// - GET /digital-assets/category/view-files-with-category (paginated)
|
|
6
6
|
//
|
|
7
7
|
// Sub-categories are returned in full on every call (folder children are
|
|
8
|
-
// typically small). Assets are upstream-paginated (1-based pages)
|
|
9
|
-
//
|
|
10
|
-
//
|
|
8
|
+
// typically small). Assets are upstream-paginated (1-based pages) at the
|
|
9
|
+
// upstream's own internal page size, which we cannot control — the
|
|
10
|
+
// caller's `page_size` arg is honored only as a CAP on what we surface,
|
|
11
|
+
// not a guarantee the upstream will return that many. The cursor
|
|
12
|
+
// encodes the next *upstream* page directly, so a caller can walk to
|
|
13
|
+
// completion by round-tripping `next_cursor` until it's null.
|
|
14
|
+
//
|
|
15
|
+
// Previous shape (pre-0.1.10): offset-based cursor with the
|
|
16
|
+
// continuation math `offset + pageSize < total`. That math assumed
|
|
17
|
+
// upstream returned `pageSize` items per page, but upstream pages at
|
|
18
|
+
// ~25/page regardless of `pageSize`. Caller saw next_cursor=null when
|
|
19
|
+
// total=38, returned=27 — leaving 11 assets unreachable. Reported by
|
|
20
|
+
// Ross 2026-05-19 (lifestyle photography folder).
|
|
11
21
|
import { z } from 'zod';
|
|
12
|
-
import {
|
|
22
|
+
import { clampPageSize } from '../conventions/pagination.js';
|
|
23
|
+
import { decodePageCursor, encodePageCursor, } from './search/cursor.js';
|
|
13
24
|
import { CategorySchema, PaginatedAssetRowSchema, } from '../types.js';
|
|
14
25
|
export const ViewCategoryContentsInputSchema = z.object({
|
|
15
26
|
category_id: z.union([z.number().int().positive(), z.string().min(1)]),
|
|
@@ -22,18 +33,41 @@ export const ViewCategoryContentsOutputSchema = z.object({
|
|
|
22
33
|
category_id: z.union([z.number(), z.string()]),
|
|
23
34
|
subcategories: z.array(CategorySchema),
|
|
24
35
|
assets: z.array(PaginatedAssetRowSchema),
|
|
36
|
+
/** Opaque continuation cursor. Pass back as `cursor` for the next page. */
|
|
25
37
|
next_cursor: z.string().nullable(),
|
|
38
|
+
/** Upstream's reported total asset count for this folder, or null when unknown. */
|
|
26
39
|
total_estimate: z.number().nullable(),
|
|
40
|
+
/**
|
|
41
|
+
* Number of upstream pages reported by the API. Useful for callers
|
|
42
|
+
* that want to know how many cursor round-trips they're committing to.
|
|
43
|
+
*/
|
|
44
|
+
total_pages: z.number().int().nonnegative(),
|
|
45
|
+
/** 1-based upstream page number returned in this response. */
|
|
46
|
+
page: z.number().int().min(1),
|
|
47
|
+
/**
|
|
48
|
+
* True when `next_cursor !== null`. Surfaced explicitly so LLM
|
|
49
|
+
* consumers don't have to interpret cursor presence themselves.
|
|
50
|
+
*/
|
|
51
|
+
has_more: z.boolean(),
|
|
27
52
|
request_id: z.string(),
|
|
28
53
|
});
|
|
29
54
|
export const VIEW_CATEGORY_CONTENTS_DESCRIPTION = 'Browse one folder. Returns the folder\'s immediate sub-folders (full ' +
|
|
30
|
-
'list) and a
|
|
31
|
-
'
|
|
55
|
+
'list) and a page of assets that live directly inside it. ' +
|
|
56
|
+
'Pagination: upstream owns the page size (~25 assets/page). Pass back ' +
|
|
57
|
+
'`next_cursor` as `cursor` to fetch the next upstream page. Walk until ' +
|
|
58
|
+
'`has_more` is false or `next_cursor` is null. `total_estimate` is the ' +
|
|
59
|
+
'upstream-reported total assets for the folder; `total_pages` is how ' +
|
|
60
|
+
'many cursor round-trips you\'ll need to enumerate everything. ' +
|
|
61
|
+
'Pass `category_id` from `list_categories`. Read-only.';
|
|
32
62
|
export function buildViewCategoryContentsHandler(client) {
|
|
33
63
|
return async (args) => {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
64
|
+
// `page_size` is advisory — upstream controls actual page size.
|
|
65
|
+
// Clamp it so a hostile or careless caller can't ask for absurd
|
|
66
|
+
// values via the input schema.
|
|
67
|
+
clampPageSize(args.page_size);
|
|
68
|
+
const page = args.cursor !== undefined
|
|
69
|
+
? decodePageCursor(args.cursor) ?? 1
|
|
70
|
+
: 1;
|
|
37
71
|
const subResult = await client.listSubCategories(args.category_id);
|
|
38
72
|
if (!subResult.ok) {
|
|
39
73
|
return {
|
|
@@ -74,13 +108,17 @@ export function buildViewCategoryContentsHandler(client) {
|
|
|
74
108
|
const subcategories = subResult.data;
|
|
75
109
|
const assets = assetResult.data.assets;
|
|
76
110
|
const total = assetResult.data.total;
|
|
77
|
-
const
|
|
111
|
+
const lastPage = assetResult.data.lastPage;
|
|
112
|
+
const hasMore = page < lastPage;
|
|
78
113
|
const output = {
|
|
79
114
|
category_id: args.category_id,
|
|
80
115
|
subcategories,
|
|
81
|
-
assets
|
|
82
|
-
next_cursor:
|
|
83
|
-
total_estimate:
|
|
116
|
+
assets,
|
|
117
|
+
next_cursor: hasMore ? encodePageCursor(page + 1) : null,
|
|
118
|
+
total_estimate: total ?? null,
|
|
119
|
+
total_pages: lastPage,
|
|
120
|
+
page,
|
|
121
|
+
has_more: hasMore,
|
|
84
122
|
request_id: assetResult.request_id,
|
|
85
123
|
};
|
|
86
124
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"view-category-contents.js","sourceRoot":"","sources":["../../src/tools/view-category-contents.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,yEAAyE;AACzE,0BAA0B;AAC1B,uEAAuE;AACvE,wEAAwE;AACxE,EAAE;AACF,yEAAyE;AACzE,
|
|
1
|
+
{"version":3,"file":"view-category-contents.js","sourceRoot":"","sources":["../../src/tools/view-category-contents.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@collage-dam/mcp-server",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.10",
|
|
4
4
|
"description": "Model Context Protocol (MCP) server for the Collage Digital Asset Management platform. Exposes Collage workspaces — assets, folders, collections, share links, audit prompts — to AI clients (Claude Desktop, Cursor, ChatGPT) through a typed tool surface.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|