@burdenoff/mcp-libs 2026.627.6 → 2026.629.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.
- package/dist/modules/adaptercloud/index.cjs +1841 -0
- package/dist/modules/adaptercloud/index.cjs.map +1 -0
- package/dist/modules/adaptercloud/index.d.cts +8 -0
- package/dist/modules/adaptercloud/index.d.ts +8 -0
- package/dist/modules/adaptercloud/index.js +1780 -0
- package/dist/modules/adaptercloud/index.js.map +1 -0
- package/dist/modules/atheletebridge/index.cjs +1707 -0
- package/dist/modules/atheletebridge/index.cjs.map +1 -0
- package/dist/modules/atheletebridge/index.d.cts +8 -0
- package/dist/modules/atheletebridge/index.d.ts +8 -0
- package/dist/modules/atheletebridge/index.js +1646 -0
- package/dist/modules/atheletebridge/index.js.map +1 -0
- package/dist/modules/coolandlovely/index.cjs +1935 -0
- package/dist/modules/coolandlovely/index.cjs.map +1 -0
- package/dist/modules/coolandlovely/index.d.cts +8 -0
- package/dist/modules/coolandlovely/index.d.ts +8 -0
- package/dist/modules/coolandlovely/index.js +1874 -0
- package/dist/modules/coolandlovely/index.js.map +1 -0
- package/dist/modules/hookmovies/index.cjs +2024 -0
- package/dist/modules/hookmovies/index.cjs.map +1 -0
- package/dist/modules/hookmovies/index.d.cts +8 -0
- package/dist/modules/hookmovies/index.d.ts +8 -0
- package/dist/modules/hookmovies/index.js +1963 -0
- package/dist/modules/hookmovies/index.js.map +1 -0
- package/dist/modules/labsofscience/index.cjs +2039 -0
- package/dist/modules/labsofscience/index.cjs.map +1 -0
- package/dist/modules/labsofscience/index.d.cts +8 -0
- package/dist/modules/labsofscience/index.d.ts +8 -0
- package/dist/modules/labsofscience/index.js +1978 -0
- package/dist/modules/labsofscience/index.js.map +1 -0
- package/dist/modules/subscriberbot/index.cjs +2037 -0
- package/dist/modules/subscriberbot/index.cjs.map +1 -0
- package/dist/modules/subscriberbot/index.d.cts +8 -0
- package/dist/modules/subscriberbot/index.d.ts +8 -0
- package/dist/modules/subscriberbot/index.js +1976 -0
- package/dist/modules/subscriberbot/index.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,2024 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var zod = require('zod');
|
|
4
|
+
require('graphql-request');
|
|
5
|
+
require('cross-fetch');
|
|
6
|
+
require('@modelcontextprotocol/sdk/server/mcp.js');
|
|
7
|
+
require('@modelcontextprotocol/sdk/types.js');
|
|
8
|
+
|
|
9
|
+
// src/modules/hookmovies/tools/titles.ts
|
|
10
|
+
|
|
11
|
+
// src/core/errors.ts
|
|
12
|
+
var McpInternalError = class extends Error {
|
|
13
|
+
cause;
|
|
14
|
+
constructor(message, cause) {
|
|
15
|
+
super(message);
|
|
16
|
+
this.name = "McpInternalError";
|
|
17
|
+
this.cause = cause;
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
// src/core/result.ts
|
|
22
|
+
function jsonResult(data, structured) {
|
|
23
|
+
const result = {
|
|
24
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
|
|
25
|
+
};
|
|
26
|
+
return result;
|
|
27
|
+
}
|
|
28
|
+
function errorResult(message, hint) {
|
|
29
|
+
const text = hint ? `${message}
|
|
30
|
+
|
|
31
|
+
Hint: ${hint}` : message;
|
|
32
|
+
return { content: [{ type: "text", text }], isError: true };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// src/core/tool-name.ts
|
|
36
|
+
var MAX_TOOL_NAME_LENGTH = 63;
|
|
37
|
+
function assertSafeName(name, kind) {
|
|
38
|
+
if (name.length > MAX_TOOL_NAME_LENGTH) {
|
|
39
|
+
throw new McpInternalError(
|
|
40
|
+
`Tool name '${name}' exceeds ${MAX_TOOL_NAME_LENGTH} characters (some MCP clients truncate at 64).`
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
return name;
|
|
44
|
+
}
|
|
45
|
+
function mcpToolName(productName, ...parts) {
|
|
46
|
+
if (!productName) {
|
|
47
|
+
throw new McpInternalError("mcpToolName: productName is required");
|
|
48
|
+
}
|
|
49
|
+
const name = [productName, ...parts].filter(Boolean).join("_");
|
|
50
|
+
return assertSafeName(name);
|
|
51
|
+
}
|
|
52
|
+
function mcpResourceUri(productName, ...parts) {
|
|
53
|
+
if (!productName) {
|
|
54
|
+
throw new McpInternalError("mcpResourceUri: productName is required");
|
|
55
|
+
}
|
|
56
|
+
return `${productName}://${parts.filter(Boolean).join("/")}`;
|
|
57
|
+
}
|
|
58
|
+
function mcpPromptName(productName, ...parts) {
|
|
59
|
+
if (!productName) {
|
|
60
|
+
throw new McpInternalError("mcpPromptName: productName is required");
|
|
61
|
+
}
|
|
62
|
+
return [productName, ...parts].filter(Boolean).join("-");
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// src/modules/hookmovies/operations.ts
|
|
66
|
+
var PAGE_INFO = `pageInfo { cursor hasMore }`;
|
|
67
|
+
var TITLE_FIELDS = `
|
|
68
|
+
id title slug type status synopsis genres tags originalLanguage originCountry
|
|
69
|
+
releaseDate releaseYear runtimeMinutes certification aiDisclosure externalIds
|
|
70
|
+
studioId workspaceId createdAt updatedAt
|
|
71
|
+
`;
|
|
72
|
+
var STUDIO_FIELDS = `
|
|
73
|
+
id name slug description country websiteUrl isVerified tags
|
|
74
|
+
workspaceId createdAt updatedAt
|
|
75
|
+
`;
|
|
76
|
+
var PERSON_FIELDS = `
|
|
77
|
+
id name biography knownFor primaryLanguage portfolioRef tags
|
|
78
|
+
workspaceId createdAt updatedAt
|
|
79
|
+
`;
|
|
80
|
+
var CREDIT_FIELDS = `
|
|
81
|
+
id titleId personId role characterName billingOrder
|
|
82
|
+
workspaceId createdAt updatedAt
|
|
83
|
+
`;
|
|
84
|
+
var SEASON_FIELDS = `
|
|
85
|
+
id titleId number name synopsis airDate workspaceId createdAt updatedAt
|
|
86
|
+
`;
|
|
87
|
+
var EPISODE_FIELDS = `
|
|
88
|
+
id titleId seasonId number name synopsis runtimeMinutes airDate
|
|
89
|
+
file { id } workspaceId createdAt updatedAt
|
|
90
|
+
`;
|
|
91
|
+
var PRODUCTION_FIELDS = `
|
|
92
|
+
id title status logline synopsis tags studioId producerId currency
|
|
93
|
+
budgetMinorUnits startDate endDate resultingTitleId artistrybaseProjectRef
|
|
94
|
+
workspaceId createdAt updatedAt
|
|
95
|
+
`;
|
|
96
|
+
var AUDITION_FIELDS = `
|
|
97
|
+
id productionId roleName description status isMinorRole language location
|
|
98
|
+
currency payMinorUnits submissionDeadline workspaceId createdAt updatedAt
|
|
99
|
+
`;
|
|
100
|
+
var APPLICATION_FIELDS = `
|
|
101
|
+
id auditionId applicantId coverNote status score selfTape { id }
|
|
102
|
+
workspaceId createdAt updatedAt
|
|
103
|
+
`;
|
|
104
|
+
var REVIEW_FIELDS = `
|
|
105
|
+
id titleId authorId score body aspectScores hasSpoilers verifiedWatch
|
|
106
|
+
helpfulCount status workspaceId createdAt updatedAt
|
|
107
|
+
`;
|
|
108
|
+
var RIGHTS_WINDOW_FIELDS = `
|
|
109
|
+
id titleId licenseeId modes territories exclusive priceMinorUnits currency
|
|
110
|
+
startsAt endsAt status contractFileId workspaceId createdAt updatedAt
|
|
111
|
+
`;
|
|
112
|
+
var ENTITLEMENT_FIELDS = `
|
|
113
|
+
id titleId userId mode source status territory expiresAt
|
|
114
|
+
workspaceId createdAt updatedAt
|
|
115
|
+
`;
|
|
116
|
+
var LIST_FIELDS = `
|
|
117
|
+
id name description kind visibility itemCount items ownerId
|
|
118
|
+
workspaceId createdAt updatedAt
|
|
119
|
+
`;
|
|
120
|
+
var WATCH_PROGRESS_FIELDS = `
|
|
121
|
+
id titleId episodeId userId positionSeconds completed lastDevice
|
|
122
|
+
workspaceId createdAt updatedAt
|
|
123
|
+
`;
|
|
124
|
+
var GET_TITLE = `
|
|
125
|
+
query HookmoviesGetTitle($id: ID!) {
|
|
126
|
+
hokTitle(id: $id) {
|
|
127
|
+
${TITLE_FIELDS}
|
|
128
|
+
studio { id name slug }
|
|
129
|
+
credits { ${CREDIT_FIELDS} }
|
|
130
|
+
seasons { ${SEASON_FIELDS} }
|
|
131
|
+
episodes { ${EPISODE_FIELDS} }
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
`;
|
|
135
|
+
var LIST_TITLES = `
|
|
136
|
+
query HookmoviesListTitles(
|
|
137
|
+
$pagination: PaginationInput
|
|
138
|
+
$status: HokTitleStatus
|
|
139
|
+
$studioId: ID
|
|
140
|
+
$type: HokTitleType
|
|
141
|
+
) {
|
|
142
|
+
hokListTitles(pagination: $pagination, status: $status, studioId: $studioId, type: $type) {
|
|
143
|
+
items { ${TITLE_FIELDS} }
|
|
144
|
+
${PAGE_INFO}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
`;
|
|
148
|
+
var CREATE_TITLE = `
|
|
149
|
+
mutation HookmoviesCreateTitle($input: HokCreateTitleInput!) {
|
|
150
|
+
hokCreateTitle(input: $input) {
|
|
151
|
+
${TITLE_FIELDS}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
`;
|
|
155
|
+
var UPDATE_TITLE = `
|
|
156
|
+
mutation HookmoviesUpdateTitle($id: ID!, $input: HokUpdateTitleInput!) {
|
|
157
|
+
hokUpdateTitle(id: $id, input: $input) {
|
|
158
|
+
${TITLE_FIELDS}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
`;
|
|
162
|
+
var TRANSITION_TITLE = `
|
|
163
|
+
mutation HookmoviesTransitionTitle($id: ID!, $status: HokTitleStatus!) {
|
|
164
|
+
hokTransitionTitle(id: $id, status: $status) {
|
|
165
|
+
${TITLE_FIELDS}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
`;
|
|
169
|
+
var ARCHIVE_TITLE = `
|
|
170
|
+
mutation HookmoviesArchiveTitle($id: ID!) {
|
|
171
|
+
hokArchiveTitle(id: $id)
|
|
172
|
+
}
|
|
173
|
+
`;
|
|
174
|
+
var LIST_STUDIOS = `
|
|
175
|
+
query HookmoviesListStudios($pagination: PaginationInput) {
|
|
176
|
+
hokListStudios(pagination: $pagination) {
|
|
177
|
+
items { ${STUDIO_FIELDS} }
|
|
178
|
+
${PAGE_INFO}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
`;
|
|
182
|
+
var CREATE_STUDIO = `
|
|
183
|
+
mutation HookmoviesCreateStudio($input: HokCreateStudioInput!) {
|
|
184
|
+
hokCreateStudio(input: $input) {
|
|
185
|
+
${STUDIO_FIELDS}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
`;
|
|
189
|
+
var LIST_PEOPLE = `
|
|
190
|
+
query HookmoviesListPeople($pagination: PaginationInput) {
|
|
191
|
+
hokListPeople(pagination: $pagination) {
|
|
192
|
+
items {
|
|
193
|
+
${PERSON_FIELDS}
|
|
194
|
+
credits { ${CREDIT_FIELDS} }
|
|
195
|
+
}
|
|
196
|
+
${PAGE_INFO}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
`;
|
|
200
|
+
var CREATE_PERSON = `
|
|
201
|
+
mutation HookmoviesCreatePerson($input: HokCreatePersonInput!) {
|
|
202
|
+
hokCreatePerson(input: $input) {
|
|
203
|
+
${PERSON_FIELDS}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
`;
|
|
207
|
+
var ADD_CREDIT = `
|
|
208
|
+
mutation HookmoviesAddCredit($input: HokCreateCreditInput!) {
|
|
209
|
+
hokAddCredit(input: $input) {
|
|
210
|
+
${CREDIT_FIELDS}
|
|
211
|
+
person { id name }
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
`;
|
|
215
|
+
var CREATE_SEASON = `
|
|
216
|
+
mutation HookmoviesCreateSeason($input: HokCreateSeasonInput!) {
|
|
217
|
+
hokCreateSeason(input: $input) {
|
|
218
|
+
${SEASON_FIELDS}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
`;
|
|
222
|
+
var LIST_EPISODES = `
|
|
223
|
+
query HookmoviesListEpisodes($titleId: ID!) {
|
|
224
|
+
hokListEpisodes(titleId: $titleId) {
|
|
225
|
+
${EPISODE_FIELDS}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
`;
|
|
229
|
+
var CREATE_EPISODE = `
|
|
230
|
+
mutation HookmoviesCreateEpisode($input: HokCreateEpisodeInput!) {
|
|
231
|
+
hokCreateEpisode(input: $input) {
|
|
232
|
+
${EPISODE_FIELDS}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
`;
|
|
236
|
+
var GET_PRODUCTION = `
|
|
237
|
+
query HookmoviesGetProduction($id: ID!) {
|
|
238
|
+
hokProduction(id: $id) {
|
|
239
|
+
${PRODUCTION_FIELDS}
|
|
240
|
+
auditions { ${AUDITION_FIELDS} }
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
`;
|
|
244
|
+
var LIST_PRODUCTIONS = `
|
|
245
|
+
query HookmoviesListProductions(
|
|
246
|
+
$pagination: PaginationInput
|
|
247
|
+
$status: HokProductionStatus
|
|
248
|
+
$studioId: ID
|
|
249
|
+
) {
|
|
250
|
+
hokListProductions(pagination: $pagination, status: $status, studioId: $studioId) {
|
|
251
|
+
items { ${PRODUCTION_FIELDS} }
|
|
252
|
+
${PAGE_INFO}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
`;
|
|
256
|
+
var CREATE_PRODUCTION = `
|
|
257
|
+
mutation HookmoviesCreateProduction($input: HokCreateProductionInput!) {
|
|
258
|
+
hokCreateProduction(input: $input) {
|
|
259
|
+
${PRODUCTION_FIELDS}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
`;
|
|
263
|
+
var TRANSITION_PRODUCTION = `
|
|
264
|
+
mutation HookmoviesTransitionProduction($id: ID!, $status: HokProductionStatus!) {
|
|
265
|
+
hokTransitionProduction(id: $id, status: $status) {
|
|
266
|
+
${PRODUCTION_FIELDS}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
`;
|
|
270
|
+
var LIST_AUDITIONS = `
|
|
271
|
+
query HookmoviesListAuditions(
|
|
272
|
+
$pagination: PaginationInput
|
|
273
|
+
$productionId: ID
|
|
274
|
+
$status: HokAuditionStatus
|
|
275
|
+
) {
|
|
276
|
+
hokListAuditions(pagination: $pagination, productionId: $productionId, status: $status) {
|
|
277
|
+
items { ${AUDITION_FIELDS} }
|
|
278
|
+
${PAGE_INFO}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
`;
|
|
282
|
+
var CREATE_AUDITION = `
|
|
283
|
+
mutation HookmoviesCreateAudition($input: HokCreateAuditionInput!) {
|
|
284
|
+
hokCreateAudition(input: $input) {
|
|
285
|
+
${AUDITION_FIELDS}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
`;
|
|
289
|
+
var CLOSE_AUDITION = `
|
|
290
|
+
mutation HookmoviesCloseAudition($id: ID!) {
|
|
291
|
+
hokCloseAudition(id: $id) {
|
|
292
|
+
${AUDITION_FIELDS}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
`;
|
|
296
|
+
var LIST_APPLICATIONS = `
|
|
297
|
+
query HookmoviesListApplications($auditionId: ID!) {
|
|
298
|
+
hokListApplications(auditionId: $auditionId) {
|
|
299
|
+
${APPLICATION_FIELDS}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
`;
|
|
303
|
+
var APPLY_TO_AUDITION = `
|
|
304
|
+
mutation HookmoviesApplyToAudition($input: HokApplyToAuditionInput!) {
|
|
305
|
+
hokApplyToAudition(input: $input) {
|
|
306
|
+
${APPLICATION_FIELDS}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
`;
|
|
310
|
+
var SCORE_APPLICATION = `
|
|
311
|
+
mutation HookmoviesScoreApplication($id: ID!, $score: Int!) {
|
|
312
|
+
hokScoreApplication(id: $id, score: $score) {
|
|
313
|
+
${APPLICATION_FIELDS}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
`;
|
|
317
|
+
var LIST_REVIEWS = `
|
|
318
|
+
query HookmoviesListReviews(
|
|
319
|
+
$pagination: PaginationInput
|
|
320
|
+
$status: HokReviewStatus
|
|
321
|
+
$titleId: ID
|
|
322
|
+
) {
|
|
323
|
+
hokListReviews(pagination: $pagination, status: $status, titleId: $titleId) {
|
|
324
|
+
items { ${REVIEW_FIELDS} }
|
|
325
|
+
${PAGE_INFO}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
`;
|
|
329
|
+
var CREATE_REVIEW = `
|
|
330
|
+
mutation HookmoviesCreateReview($input: HokCreateReviewInput!) {
|
|
331
|
+
hokCreateReview(input: $input) {
|
|
332
|
+
${REVIEW_FIELDS}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
`;
|
|
336
|
+
var DELETE_REVIEW = `
|
|
337
|
+
mutation HookmoviesDeleteReview($id: ID!) {
|
|
338
|
+
hokDeleteReview(id: $id)
|
|
339
|
+
}
|
|
340
|
+
`;
|
|
341
|
+
var LIST_RIGHTS_WINDOWS = `
|
|
342
|
+
query HookmoviesListRightsWindows(
|
|
343
|
+
$pagination: PaginationInput
|
|
344
|
+
$status: HokRightsWindowStatus
|
|
345
|
+
$titleId: ID
|
|
346
|
+
) {
|
|
347
|
+
hokListRightsWindows(pagination: $pagination, status: $status, titleId: $titleId) {
|
|
348
|
+
items { ${RIGHTS_WINDOW_FIELDS} }
|
|
349
|
+
${PAGE_INFO}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
`;
|
|
353
|
+
var CREATE_RIGHTS_WINDOW = `
|
|
354
|
+
mutation HookmoviesCreateRightsWindow($input: HokCreateRightsWindowInput!) {
|
|
355
|
+
hokCreateRightsWindow(input: $input) {
|
|
356
|
+
${RIGHTS_WINDOW_FIELDS}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
`;
|
|
360
|
+
var TRANSITION_RIGHTS_WINDOW = `
|
|
361
|
+
mutation HookmoviesTransitionRightsWindow($id: ID!, $status: HokRightsWindowStatus!) {
|
|
362
|
+
hokTransitionRightsWindow(id: $id, status: $status) {
|
|
363
|
+
${RIGHTS_WINDOW_FIELDS}
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
`;
|
|
367
|
+
var GRANT_ENTITLEMENT = `
|
|
368
|
+
mutation HookmoviesGrantEntitlement($input: HokGrantEntitlementInput!) {
|
|
369
|
+
hokGrantEntitlement(input: $input) {
|
|
370
|
+
${ENTITLEMENT_FIELDS}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
`;
|
|
374
|
+
var REVOKE_ENTITLEMENT = `
|
|
375
|
+
mutation HookmoviesRevokeEntitlement($id: ID!) {
|
|
376
|
+
hokRevokeEntitlement(id: $id)
|
|
377
|
+
}
|
|
378
|
+
`;
|
|
379
|
+
var MY_ENTITLEMENTS = `
|
|
380
|
+
query HookmoviesMyEntitlements($titleId: ID) {
|
|
381
|
+
hokMyEntitlements(titleId: $titleId) {
|
|
382
|
+
${ENTITLEMENT_FIELDS}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
`;
|
|
386
|
+
var CHECK_ENTITLEMENT = `
|
|
387
|
+
query HookmoviesCheckEntitlement($titleId: ID!) {
|
|
388
|
+
hokCheckEntitlement(titleId: $titleId) {
|
|
389
|
+
entitled
|
|
390
|
+
modes
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
`;
|
|
394
|
+
var GET_LIST = `
|
|
395
|
+
query HookmoviesGetList($id: ID!) {
|
|
396
|
+
hokList(id: $id) {
|
|
397
|
+
${LIST_FIELDS}
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
`;
|
|
401
|
+
var MY_LISTS = `
|
|
402
|
+
query HookmoviesMyLists($kind: HokListKind, $pagination: PaginationInput) {
|
|
403
|
+
hokMyLists(kind: $kind, pagination: $pagination) {
|
|
404
|
+
items { ${LIST_FIELDS} }
|
|
405
|
+
${PAGE_INFO}
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
`;
|
|
409
|
+
var CREATE_LIST = `
|
|
410
|
+
mutation HookmoviesCreateList($input: HokCreateListInput!) {
|
|
411
|
+
hokCreateList(input: $input) {
|
|
412
|
+
${LIST_FIELDS}
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
`;
|
|
416
|
+
var UPDATE_LIST = `
|
|
417
|
+
mutation HookmoviesUpdateList($id: ID!, $input: HokUpdateListInput!) {
|
|
418
|
+
hokUpdateList(id: $id, input: $input) {
|
|
419
|
+
${LIST_FIELDS}
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
`;
|
|
423
|
+
var DELETE_LIST = `
|
|
424
|
+
mutation HookmoviesDeleteList($id: ID!) {
|
|
425
|
+
hokDeleteList(id: $id)
|
|
426
|
+
}
|
|
427
|
+
`;
|
|
428
|
+
var RECORD_PROGRESS = `
|
|
429
|
+
mutation HookmoviesRecordProgress($input: HokRecordProgressInput!) {
|
|
430
|
+
hokRecordProgress(input: $input) {
|
|
431
|
+
${WATCH_PROGRESS_FIELDS}
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
`;
|
|
435
|
+
var MY_WATCH_PROGRESS = `
|
|
436
|
+
query HookmoviesMyWatchProgress($titleId: ID) {
|
|
437
|
+
hokMyWatchProgress(titleId: $titleId) {
|
|
438
|
+
${WATCH_PROGRESS_FIELDS}
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
`;
|
|
442
|
+
var HEALTH = `
|
|
443
|
+
query HookmoviesHealth {
|
|
444
|
+
hokHealth
|
|
445
|
+
}
|
|
446
|
+
`;
|
|
447
|
+
var TitleTypeEnum = zod.z.enum([
|
|
448
|
+
"ANIME",
|
|
449
|
+
"COLLECTION",
|
|
450
|
+
"DOCUMENTARY",
|
|
451
|
+
"FAST_CHANNEL",
|
|
452
|
+
"LIVE_EVENT",
|
|
453
|
+
"LONG_FORM",
|
|
454
|
+
"MOVIE",
|
|
455
|
+
"SERIES",
|
|
456
|
+
"SHORT_FILM",
|
|
457
|
+
"SHORT_FORM",
|
|
458
|
+
"TRAILER"
|
|
459
|
+
]).describe("Kind of catalog title");
|
|
460
|
+
var TitleStatusEnum = zod.z.enum(["ARCHIVED", "DRAFT", "IN_REVIEW", "PUBLISHED", "SCHEDULED", "UNPUBLISHED"]).describe("Publication lifecycle status of a title");
|
|
461
|
+
var CreditRoleEnum = zod.z.enum([
|
|
462
|
+
"ACTOR",
|
|
463
|
+
"CINEMATOGRAPHER",
|
|
464
|
+
"COMPOSER",
|
|
465
|
+
"CREW",
|
|
466
|
+
"DIRECTOR",
|
|
467
|
+
"EDITOR",
|
|
468
|
+
"PRODUCER",
|
|
469
|
+
"VOICE_ACTOR",
|
|
470
|
+
"WRITER"
|
|
471
|
+
]).describe("Role of a person credited on a title");
|
|
472
|
+
var ProductionStatusEnum = zod.z.enum(["DEVELOPMENT", "GREENLIT", "IN_PRODUCTION", "POST_PRODUCTION", "RELEASED", "SHELVED"]).describe("Lifecycle status of a production");
|
|
473
|
+
var AuditionStatusEnum = zod.z.enum(["CALLBACKS", "CANCELLED", "CLOSED", "OPEN", "REVIEWING"]).describe("Lifecycle status of an audition");
|
|
474
|
+
zod.z.enum(["CALLBACK", "OFFERED", "REJECTED", "SHORTLISTED", "SUBMITTED", "WITHDRAWN"]).describe("Status of an audition application");
|
|
475
|
+
var ReviewStatusEnum = zod.z.enum(["HIDDEN", "PENDING", "PUBLISHED", "REMOVED"]).describe("Moderation status of a review");
|
|
476
|
+
var RightsWindowStatusEnum = zod.z.enum(["ACTIVE", "DRAFT", "EXPIRED", "PENDING", "REVOKED"]).describe("Lifecycle status of a rights window");
|
|
477
|
+
var MonetizationModeEnum = zod.z.enum(["FAST", "FREE_AVOD", "PPV", "SVOD", "TVOD_BUY", "TVOD_RENT"]).describe("Monetization / distribution mode for a title");
|
|
478
|
+
var EntitlementSourceEnum = zod.z.enum(["FREE", "PROMO", "PURCHASE", "RENTAL", "SUBSCRIPTION"]).describe("How an entitlement was acquired");
|
|
479
|
+
var ListKindEnum = zod.z.enum(["PLAYLIST", "WATCHLIST"]).describe("Whether a user list is a PLAYLIST or a WATCHLIST");
|
|
480
|
+
var ListVisibilityEnum = zod.z.enum(["PRIVATE", "PUBLIC", "UNLISTED"]).describe("Visibility of a user list");
|
|
481
|
+
var JsonObject = zod.z.record(zod.z.string(), zod.z.unknown());
|
|
482
|
+
var JsonValue = zod.z.union([JsonObject, zod.z.array(zod.z.unknown())]).describe("Arbitrary JSON value (object or array)");
|
|
483
|
+
|
|
484
|
+
// src/modules/hookmovies/tools/titles.ts
|
|
485
|
+
function registerTitleTools(server, ctx, track) {
|
|
486
|
+
server.registerTool(
|
|
487
|
+
track(mcpToolName(ctx.productName, "titles_get")),
|
|
488
|
+
{
|
|
489
|
+
title: "Get Title",
|
|
490
|
+
description: "Fetch a single HookMovies title by ID, including its studio, credits, seasons, and episodes.",
|
|
491
|
+
inputSchema: { id: zod.z.string().describe("Title ID") }
|
|
492
|
+
},
|
|
493
|
+
async ({ id }) => {
|
|
494
|
+
try {
|
|
495
|
+
const data = await ctx.gql.workspace.request(GET_TITLE, { id });
|
|
496
|
+
if (!data.hokTitle) return errorResult(`Title ${id} not found`);
|
|
497
|
+
return jsonResult(data.hokTitle);
|
|
498
|
+
} catch (error) {
|
|
499
|
+
ctx.logger.error("hookmovies titles_get failed", { error: String(error) });
|
|
500
|
+
return errorResult(
|
|
501
|
+
`Failed to get title: ${error instanceof Error ? error.message : String(error)}`
|
|
502
|
+
);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
);
|
|
506
|
+
server.registerTool(
|
|
507
|
+
track(mcpToolName(ctx.productName, "titles_list")),
|
|
508
|
+
{
|
|
509
|
+
title: "List Titles",
|
|
510
|
+
description: "List catalog titles in the bound workspace, optionally filtered by status, studio, and/or title type, with pagination.",
|
|
511
|
+
inputSchema: {
|
|
512
|
+
status: TitleStatusEnum.optional().describe("Filter by publication status"),
|
|
513
|
+
studioId: zod.z.string().optional().describe("Filter by owning studio ID"),
|
|
514
|
+
type: TitleTypeEnum.optional().describe("Filter by title type"),
|
|
515
|
+
limit: zod.z.number().int().optional().describe("Page size (default 50)"),
|
|
516
|
+
offset: zod.z.number().int().optional().describe("Pagination offset (default 0)"),
|
|
517
|
+
cursor: zod.z.string().optional().describe("Opaque pagination cursor")
|
|
518
|
+
}
|
|
519
|
+
},
|
|
520
|
+
async ({ status, studioId, type, limit, offset, cursor }) => {
|
|
521
|
+
try {
|
|
522
|
+
const data = await ctx.gql.workspace.request(LIST_TITLES, {
|
|
523
|
+
status,
|
|
524
|
+
studioId,
|
|
525
|
+
type,
|
|
526
|
+
pagination: { limit: limit ?? 50, offset: offset ?? 0, cursor }
|
|
527
|
+
});
|
|
528
|
+
return jsonResult(data.hokListTitles);
|
|
529
|
+
} catch (error) {
|
|
530
|
+
ctx.logger.error("hookmovies titles_list failed", { error: String(error) });
|
|
531
|
+
return errorResult(
|
|
532
|
+
`Failed to list titles: ${error instanceof Error ? error.message : String(error)}`
|
|
533
|
+
);
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
);
|
|
537
|
+
server.registerTool(
|
|
538
|
+
track(mcpToolName(ctx.productName, "titles_create")),
|
|
539
|
+
{
|
|
540
|
+
title: "Create Title",
|
|
541
|
+
description: "Create a catalog title (movie/series/etc.). `title` is required; defaults: type=MOVIE, aiDisclosure=false. Optionally attach to a studio.",
|
|
542
|
+
inputSchema: {
|
|
543
|
+
title: zod.z.string().min(1).describe("Display title"),
|
|
544
|
+
type: TitleTypeEnum.optional().describe("Title type (default MOVIE)"),
|
|
545
|
+
slug: zod.z.string().optional().describe("URL slug, unique within the workspace"),
|
|
546
|
+
synopsis: zod.z.string().optional().describe("Synopsis / description"),
|
|
547
|
+
genres: zod.z.array(zod.z.string()).optional().describe("Genre tags"),
|
|
548
|
+
tags: zod.z.array(zod.z.string()).optional().describe("Discovery tags"),
|
|
549
|
+
originalLanguage: zod.z.string().optional().describe("Original language code"),
|
|
550
|
+
originCountry: zod.z.string().optional().describe("Country of origin code"),
|
|
551
|
+
releaseDate: zod.z.string().optional().describe("Release date (ISO-8601 DateTime)"),
|
|
552
|
+
releaseYear: zod.z.number().int().optional().describe("Release year"),
|
|
553
|
+
runtimeMinutes: zod.z.number().int().optional().describe("Runtime in minutes"),
|
|
554
|
+
certification: zod.z.string().optional().describe("Content certification / rating"),
|
|
555
|
+
aiDisclosure: zod.z.boolean().optional().describe("Whether AI involvement is disclosed"),
|
|
556
|
+
studioId: zod.z.string().optional().describe("Owning studio ID")
|
|
557
|
+
}
|
|
558
|
+
},
|
|
559
|
+
async ({
|
|
560
|
+
title,
|
|
561
|
+
type,
|
|
562
|
+
slug,
|
|
563
|
+
synopsis,
|
|
564
|
+
genres,
|
|
565
|
+
tags,
|
|
566
|
+
originalLanguage,
|
|
567
|
+
originCountry,
|
|
568
|
+
releaseDate,
|
|
569
|
+
releaseYear,
|
|
570
|
+
runtimeMinutes,
|
|
571
|
+
certification,
|
|
572
|
+
aiDisclosure,
|
|
573
|
+
studioId
|
|
574
|
+
}) => {
|
|
575
|
+
try {
|
|
576
|
+
const input = { title };
|
|
577
|
+
if (type !== void 0) input.type = type;
|
|
578
|
+
if (slug !== void 0) input.slug = slug;
|
|
579
|
+
if (synopsis !== void 0) input.synopsis = synopsis;
|
|
580
|
+
if (genres !== void 0) input.genres = genres;
|
|
581
|
+
if (tags !== void 0) input.tags = tags;
|
|
582
|
+
if (originalLanguage !== void 0) input.originalLanguage = originalLanguage;
|
|
583
|
+
if (originCountry !== void 0) input.originCountry = originCountry;
|
|
584
|
+
if (releaseDate !== void 0) input.releaseDate = releaseDate;
|
|
585
|
+
if (releaseYear !== void 0) input.releaseYear = releaseYear;
|
|
586
|
+
if (runtimeMinutes !== void 0) input.runtimeMinutes = runtimeMinutes;
|
|
587
|
+
if (certification !== void 0) input.certification = certification;
|
|
588
|
+
if (aiDisclosure !== void 0) input.aiDisclosure = aiDisclosure;
|
|
589
|
+
if (studioId !== void 0) input.studioId = studioId;
|
|
590
|
+
const data = await ctx.gql.workspace.request(CREATE_TITLE, { input });
|
|
591
|
+
return jsonResult(data.hokCreateTitle);
|
|
592
|
+
} catch (error) {
|
|
593
|
+
ctx.logger.error("hookmovies titles_create failed", { error: String(error) });
|
|
594
|
+
return errorResult(
|
|
595
|
+
`Failed to create title: ${error instanceof Error ? error.message : String(error)}`
|
|
596
|
+
);
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
);
|
|
600
|
+
server.registerTool(
|
|
601
|
+
track(mcpToolName(ctx.productName, "titles_update")),
|
|
602
|
+
{
|
|
603
|
+
title: "Update Title",
|
|
604
|
+
description: "Update a catalog title. At least one mutable field must be provided. Use titles_transition for status changes and titles_archive to archive.",
|
|
605
|
+
inputSchema: {
|
|
606
|
+
id: zod.z.string().describe("Title ID"),
|
|
607
|
+
title: zod.z.string().optional().describe("Updated display title"),
|
|
608
|
+
type: TitleTypeEnum.optional().describe("Updated title type"),
|
|
609
|
+
slug: zod.z.string().optional().describe("Updated URL slug"),
|
|
610
|
+
synopsis: zod.z.string().optional().describe("Updated synopsis"),
|
|
611
|
+
genres: zod.z.array(zod.z.string()).optional().describe("Updated genres"),
|
|
612
|
+
tags: zod.z.array(zod.z.string()).optional().describe("Updated tags"),
|
|
613
|
+
originalLanguage: zod.z.string().optional().describe("Updated original language"),
|
|
614
|
+
originCountry: zod.z.string().optional().describe("Updated origin country"),
|
|
615
|
+
releaseDate: zod.z.string().optional().describe("Updated release date (ISO-8601 DateTime)"),
|
|
616
|
+
releaseYear: zod.z.number().int().optional().describe("Updated release year"),
|
|
617
|
+
runtimeMinutes: zod.z.number().int().optional().describe("Updated runtime in minutes"),
|
|
618
|
+
certification: zod.z.string().optional().describe("Updated certification"),
|
|
619
|
+
aiDisclosure: zod.z.boolean().optional().describe("Updated AI-disclosure flag"),
|
|
620
|
+
studioId: zod.z.string().optional().describe("Updated owning studio ID")
|
|
621
|
+
}
|
|
622
|
+
},
|
|
623
|
+
async ({
|
|
624
|
+
id,
|
|
625
|
+
title,
|
|
626
|
+
type,
|
|
627
|
+
slug,
|
|
628
|
+
synopsis,
|
|
629
|
+
genres,
|
|
630
|
+
tags,
|
|
631
|
+
originalLanguage,
|
|
632
|
+
originCountry,
|
|
633
|
+
releaseDate,
|
|
634
|
+
releaseYear,
|
|
635
|
+
runtimeMinutes,
|
|
636
|
+
certification,
|
|
637
|
+
aiDisclosure,
|
|
638
|
+
studioId
|
|
639
|
+
}) => {
|
|
640
|
+
try {
|
|
641
|
+
const input = {};
|
|
642
|
+
if (title !== void 0) input.title = title;
|
|
643
|
+
if (type !== void 0) input.type = type;
|
|
644
|
+
if (slug !== void 0) input.slug = slug;
|
|
645
|
+
if (synopsis !== void 0) input.synopsis = synopsis;
|
|
646
|
+
if (genres !== void 0) input.genres = genres;
|
|
647
|
+
if (tags !== void 0) input.tags = tags;
|
|
648
|
+
if (originalLanguage !== void 0) input.originalLanguage = originalLanguage;
|
|
649
|
+
if (originCountry !== void 0) input.originCountry = originCountry;
|
|
650
|
+
if (releaseDate !== void 0) input.releaseDate = releaseDate;
|
|
651
|
+
if (releaseYear !== void 0) input.releaseYear = releaseYear;
|
|
652
|
+
if (runtimeMinutes !== void 0) input.runtimeMinutes = runtimeMinutes;
|
|
653
|
+
if (certification !== void 0) input.certification = certification;
|
|
654
|
+
if (aiDisclosure !== void 0) input.aiDisclosure = aiDisclosure;
|
|
655
|
+
if (studioId !== void 0) input.studioId = studioId;
|
|
656
|
+
if (Object.keys(input).length === 0) {
|
|
657
|
+
return errorResult("No updates specified \u2014 provide at least one mutable title field");
|
|
658
|
+
}
|
|
659
|
+
const data = await ctx.gql.workspace.request(UPDATE_TITLE, { id, input });
|
|
660
|
+
return jsonResult(data.hokUpdateTitle);
|
|
661
|
+
} catch (error) {
|
|
662
|
+
ctx.logger.error("hookmovies titles_update failed", { error: String(error) });
|
|
663
|
+
return errorResult(
|
|
664
|
+
`Failed to update title: ${error instanceof Error ? error.message : String(error)}`
|
|
665
|
+
);
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
);
|
|
669
|
+
server.registerTool(
|
|
670
|
+
track(mcpToolName(ctx.productName, "titles_transition")),
|
|
671
|
+
{
|
|
672
|
+
title: "Transition Title",
|
|
673
|
+
description: "Move a title through its publication lifecycle (validated transitions), e.g. DRAFT \u2192 IN_REVIEW \u2192 SCHEDULED \u2192 PUBLISHED \u2192 UNPUBLISHED.",
|
|
674
|
+
inputSchema: {
|
|
675
|
+
id: zod.z.string().describe("Title ID"),
|
|
676
|
+
status: TitleStatusEnum.describe("Target publication status")
|
|
677
|
+
}
|
|
678
|
+
},
|
|
679
|
+
async ({ id, status }) => {
|
|
680
|
+
try {
|
|
681
|
+
const data = await ctx.gql.workspace.request(TRANSITION_TITLE, { id, status });
|
|
682
|
+
return jsonResult(data.hokTransitionTitle);
|
|
683
|
+
} catch (error) {
|
|
684
|
+
ctx.logger.error("hookmovies titles_transition failed", { error: String(error) });
|
|
685
|
+
return errorResult(
|
|
686
|
+
`Failed to transition title: ${error instanceof Error ? error.message : String(error)}`
|
|
687
|
+
);
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
);
|
|
691
|
+
server.registerTool(
|
|
692
|
+
track(mcpToolName(ctx.productName, "titles_archive")),
|
|
693
|
+
{
|
|
694
|
+
title: "Archive Title",
|
|
695
|
+
description: "Archive (soft-delete) a catalog title. Returns true on success.",
|
|
696
|
+
inputSchema: { id: zod.z.string().describe("Title ID") }
|
|
697
|
+
},
|
|
698
|
+
async ({ id }) => {
|
|
699
|
+
try {
|
|
700
|
+
const data = await ctx.gql.workspace.request(
|
|
701
|
+
ARCHIVE_TITLE,
|
|
702
|
+
{ id }
|
|
703
|
+
);
|
|
704
|
+
return jsonResult({ archived: data.hokArchiveTitle });
|
|
705
|
+
} catch (error) {
|
|
706
|
+
ctx.logger.error("hookmovies titles_archive failed", { error: String(error) });
|
|
707
|
+
return errorResult(
|
|
708
|
+
`Failed to archive title: ${error instanceof Error ? error.message : String(error)}`
|
|
709
|
+
);
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
);
|
|
713
|
+
}
|
|
714
|
+
function registerStudioTools(server, ctx, track) {
|
|
715
|
+
server.registerTool(
|
|
716
|
+
track(mcpToolName(ctx.productName, "studios_list")),
|
|
717
|
+
{
|
|
718
|
+
title: "List Studios",
|
|
719
|
+
description: "List studios/distributors in the bound workspace, with pagination.",
|
|
720
|
+
inputSchema: {
|
|
721
|
+
limit: zod.z.number().int().optional().describe("Page size (default 50)"),
|
|
722
|
+
offset: zod.z.number().int().optional().describe("Pagination offset (default 0)"),
|
|
723
|
+
cursor: zod.z.string().optional().describe("Opaque pagination cursor")
|
|
724
|
+
}
|
|
725
|
+
},
|
|
726
|
+
async ({ limit, offset, cursor }) => {
|
|
727
|
+
try {
|
|
728
|
+
const data = await ctx.gql.workspace.request(LIST_STUDIOS, {
|
|
729
|
+
pagination: { limit: limit ?? 50, offset: offset ?? 0, cursor }
|
|
730
|
+
});
|
|
731
|
+
return jsonResult(data.hokListStudios);
|
|
732
|
+
} catch (error) {
|
|
733
|
+
ctx.logger.error("hookmovies studios_list failed", { error: String(error) });
|
|
734
|
+
return errorResult(
|
|
735
|
+
`Failed to list studios: ${error instanceof Error ? error.message : String(error)}`
|
|
736
|
+
);
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
);
|
|
740
|
+
server.registerTool(
|
|
741
|
+
track(mcpToolName(ctx.productName, "studios_create")),
|
|
742
|
+
{
|
|
743
|
+
title: "Create Studio",
|
|
744
|
+
description: "Create a studio/distributor. `name` is required.",
|
|
745
|
+
inputSchema: {
|
|
746
|
+
name: zod.z.string().min(1).describe("Studio display name"),
|
|
747
|
+
slug: zod.z.string().optional().describe("URL slug, unique within the workspace"),
|
|
748
|
+
description: zod.z.string().optional().describe("Studio description"),
|
|
749
|
+
country: zod.z.string().optional().describe("Country code"),
|
|
750
|
+
websiteUrl: zod.z.string().optional().describe("Studio website URL"),
|
|
751
|
+
tags: zod.z.array(zod.z.string()).optional().describe("Discovery tags")
|
|
752
|
+
}
|
|
753
|
+
},
|
|
754
|
+
async ({ name, slug, description, country, websiteUrl, tags }) => {
|
|
755
|
+
try {
|
|
756
|
+
const input = { name };
|
|
757
|
+
if (slug !== void 0) input.slug = slug;
|
|
758
|
+
if (description !== void 0) input.description = description;
|
|
759
|
+
if (country !== void 0) input.country = country;
|
|
760
|
+
if (websiteUrl !== void 0) input.websiteUrl = websiteUrl;
|
|
761
|
+
if (tags !== void 0) input.tags = tags;
|
|
762
|
+
const data = await ctx.gql.workspace.request(CREATE_STUDIO, { input });
|
|
763
|
+
return jsonResult(data.hokCreateStudio);
|
|
764
|
+
} catch (error) {
|
|
765
|
+
ctx.logger.error("hookmovies studios_create failed", { error: String(error) });
|
|
766
|
+
return errorResult(
|
|
767
|
+
`Failed to create studio: ${error instanceof Error ? error.message : String(error)}`
|
|
768
|
+
);
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
);
|
|
772
|
+
}
|
|
773
|
+
function registerPeopleTools(server, ctx, track) {
|
|
774
|
+
server.registerTool(
|
|
775
|
+
track(mcpToolName(ctx.productName, "people_list")),
|
|
776
|
+
{
|
|
777
|
+
title: "List People",
|
|
778
|
+
description: "List talent (cast/crew) in the bound workspace, including each person\u2019s credits, with pagination.",
|
|
779
|
+
inputSchema: {
|
|
780
|
+
limit: zod.z.number().int().optional().describe("Page size (default 50)"),
|
|
781
|
+
offset: zod.z.number().int().optional().describe("Pagination offset (default 0)"),
|
|
782
|
+
cursor: zod.z.string().optional().describe("Opaque pagination cursor")
|
|
783
|
+
}
|
|
784
|
+
},
|
|
785
|
+
async ({ limit, offset, cursor }) => {
|
|
786
|
+
try {
|
|
787
|
+
const data = await ctx.gql.workspace.request(LIST_PEOPLE, {
|
|
788
|
+
pagination: { limit: limit ?? 50, offset: offset ?? 0, cursor }
|
|
789
|
+
});
|
|
790
|
+
return jsonResult(data.hokListPeople);
|
|
791
|
+
} catch (error) {
|
|
792
|
+
ctx.logger.error("hookmovies people_list failed", { error: String(error) });
|
|
793
|
+
return errorResult(
|
|
794
|
+
`Failed to list people: ${error instanceof Error ? error.message : String(error)}`
|
|
795
|
+
);
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
);
|
|
799
|
+
server.registerTool(
|
|
800
|
+
track(mcpToolName(ctx.productName, "people_create")),
|
|
801
|
+
{
|
|
802
|
+
title: "Create Person",
|
|
803
|
+
description: "Create a talent (cast/crew) record. `name` is required.",
|
|
804
|
+
inputSchema: {
|
|
805
|
+
name: zod.z.string().min(1).describe("Person display name"),
|
|
806
|
+
biography: zod.z.string().optional().describe("Short biography"),
|
|
807
|
+
knownFor: zod.z.string().optional().describe("Notable work / known-for blurb"),
|
|
808
|
+
primaryLanguage: zod.z.string().optional().describe("Primary working language"),
|
|
809
|
+
portfolioRef: zod.z.string().optional().describe("Stable Artistrybase portfolio id (reference only)"),
|
|
810
|
+
tags: zod.z.array(zod.z.string()).optional().describe("Discovery tags")
|
|
811
|
+
}
|
|
812
|
+
},
|
|
813
|
+
async ({ name, biography, knownFor, primaryLanguage, portfolioRef, tags }) => {
|
|
814
|
+
try {
|
|
815
|
+
const input = { name };
|
|
816
|
+
if (biography !== void 0) input.biography = biography;
|
|
817
|
+
if (knownFor !== void 0) input.knownFor = knownFor;
|
|
818
|
+
if (primaryLanguage !== void 0) input.primaryLanguage = primaryLanguage;
|
|
819
|
+
if (portfolioRef !== void 0) input.portfolioRef = portfolioRef;
|
|
820
|
+
if (tags !== void 0) input.tags = tags;
|
|
821
|
+
const data = await ctx.gql.workspace.request(CREATE_PERSON, { input });
|
|
822
|
+
return jsonResult(data.hokCreatePerson);
|
|
823
|
+
} catch (error) {
|
|
824
|
+
ctx.logger.error("hookmovies people_create failed", { error: String(error) });
|
|
825
|
+
return errorResult(
|
|
826
|
+
`Failed to create person: ${error instanceof Error ? error.message : String(error)}`
|
|
827
|
+
);
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
);
|
|
831
|
+
server.registerTool(
|
|
832
|
+
track(mcpToolName(ctx.productName, "credits_add")),
|
|
833
|
+
{
|
|
834
|
+
title: "Add Credit",
|
|
835
|
+
description: "Credit a person on a title with a role (default ACTOR). Optionally set the character name and billing order.",
|
|
836
|
+
inputSchema: {
|
|
837
|
+
titleId: zod.z.string().min(1).describe("Title the credit is on"),
|
|
838
|
+
personId: zod.z.string().min(1).describe("Person being credited"),
|
|
839
|
+
role: CreditRoleEnum.optional().describe("Credited role (default ACTOR)"),
|
|
840
|
+
characterName: zod.z.string().optional().describe("Character name (for ACTOR/VOICE_ACTOR)"),
|
|
841
|
+
billingOrder: zod.z.number().int().optional().describe("Billing order (lower = higher billing)")
|
|
842
|
+
}
|
|
843
|
+
},
|
|
844
|
+
async ({ titleId, personId, role, characterName, billingOrder }) => {
|
|
845
|
+
try {
|
|
846
|
+
const input = { titleId, personId };
|
|
847
|
+
if (role !== void 0) input.role = role;
|
|
848
|
+
if (characterName !== void 0) input.characterName = characterName;
|
|
849
|
+
if (billingOrder !== void 0) input.billingOrder = billingOrder;
|
|
850
|
+
const data = await ctx.gql.workspace.request(ADD_CREDIT, { input });
|
|
851
|
+
return jsonResult(data.hokAddCredit);
|
|
852
|
+
} catch (error) {
|
|
853
|
+
ctx.logger.error("hookmovies credits_add failed", { error: String(error) });
|
|
854
|
+
return errorResult(
|
|
855
|
+
`Failed to add credit: ${error instanceof Error ? error.message : String(error)}`
|
|
856
|
+
);
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
);
|
|
860
|
+
}
|
|
861
|
+
function registerEpisodeTools(server, ctx, track) {
|
|
862
|
+
server.registerTool(
|
|
863
|
+
track(mcpToolName(ctx.productName, "seasons_create")),
|
|
864
|
+
{
|
|
865
|
+
title: "Create Season",
|
|
866
|
+
description: "Create a season under a title. `titleId` and `number` are required; name/synopsis/airDate are optional.",
|
|
867
|
+
inputSchema: {
|
|
868
|
+
titleId: zod.z.string().min(1).describe("Parent title ID"),
|
|
869
|
+
number: zod.z.number().int().describe("Season number"),
|
|
870
|
+
name: zod.z.string().optional().describe("Season name"),
|
|
871
|
+
synopsis: zod.z.string().optional().describe("Season synopsis"),
|
|
872
|
+
airDate: zod.z.string().optional().describe("Air date (ISO-8601 DateTime)")
|
|
873
|
+
}
|
|
874
|
+
},
|
|
875
|
+
async ({ titleId, number, name, synopsis, airDate }) => {
|
|
876
|
+
try {
|
|
877
|
+
const input = { titleId, number };
|
|
878
|
+
if (name !== void 0) input.name = name;
|
|
879
|
+
if (synopsis !== void 0) input.synopsis = synopsis;
|
|
880
|
+
if (airDate !== void 0) input.airDate = airDate;
|
|
881
|
+
const data = await ctx.gql.workspace.request(CREATE_SEASON, { input });
|
|
882
|
+
return jsonResult(data.hokCreateSeason);
|
|
883
|
+
} catch (error) {
|
|
884
|
+
ctx.logger.error("hookmovies seasons_create failed", { error: String(error) });
|
|
885
|
+
return errorResult(
|
|
886
|
+
`Failed to create season: ${error instanceof Error ? error.message : String(error)}`
|
|
887
|
+
);
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
);
|
|
891
|
+
server.registerTool(
|
|
892
|
+
track(mcpToolName(ctx.productName, "episodes_list")),
|
|
893
|
+
{
|
|
894
|
+
title: "List Episodes",
|
|
895
|
+
description: "List all episodes for a title (across seasons).",
|
|
896
|
+
inputSchema: { titleId: zod.z.string().describe("Title ID") }
|
|
897
|
+
},
|
|
898
|
+
async ({ titleId }) => {
|
|
899
|
+
try {
|
|
900
|
+
const data = await ctx.gql.workspace.request(LIST_EPISODES, { titleId });
|
|
901
|
+
return jsonResult(data.hokListEpisodes);
|
|
902
|
+
} catch (error) {
|
|
903
|
+
ctx.logger.error("hookmovies episodes_list failed", { error: String(error) });
|
|
904
|
+
return errorResult(
|
|
905
|
+
`Failed to list episodes: ${error instanceof Error ? error.message : String(error)}`
|
|
906
|
+
);
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
);
|
|
910
|
+
server.registerTool(
|
|
911
|
+
track(mcpToolName(ctx.productName, "episodes_create")),
|
|
912
|
+
{
|
|
913
|
+
title: "Create Episode",
|
|
914
|
+
description: "Create an episode under a title (and optionally a season). `titleId`, `name`, and `number` are required. Set `fileId` to attach the master/mezzanine file.",
|
|
915
|
+
inputSchema: {
|
|
916
|
+
titleId: zod.z.string().min(1).describe("Parent title ID"),
|
|
917
|
+
name: zod.z.string().min(1).describe("Episode name"),
|
|
918
|
+
number: zod.z.number().int().describe("Episode number within the season"),
|
|
919
|
+
seasonId: zod.z.string().optional().describe("Parent season ID"),
|
|
920
|
+
synopsis: zod.z.string().optional().describe("Episode synopsis"),
|
|
921
|
+
runtimeMinutes: zod.z.number().int().optional().describe("Runtime in minutes"),
|
|
922
|
+
airDate: zod.z.string().optional().describe("Air date (ISO-8601 DateTime)"),
|
|
923
|
+
fileId: zod.z.string().optional().describe("wspace-files-svc File ID (master/mezzanine)")
|
|
924
|
+
}
|
|
925
|
+
},
|
|
926
|
+
async ({ titleId, name, number, seasonId, synopsis, runtimeMinutes, airDate, fileId }) => {
|
|
927
|
+
try {
|
|
928
|
+
const input = { titleId, name, number };
|
|
929
|
+
if (seasonId !== void 0) input.seasonId = seasonId;
|
|
930
|
+
if (synopsis !== void 0) input.synopsis = synopsis;
|
|
931
|
+
if (runtimeMinutes !== void 0) input.runtimeMinutes = runtimeMinutes;
|
|
932
|
+
if (airDate !== void 0) input.airDate = airDate;
|
|
933
|
+
if (fileId !== void 0) input.fileId = fileId;
|
|
934
|
+
const data = await ctx.gql.workspace.request(CREATE_EPISODE, { input });
|
|
935
|
+
return jsonResult(data.hokCreateEpisode);
|
|
936
|
+
} catch (error) {
|
|
937
|
+
ctx.logger.error("hookmovies episodes_create failed", { error: String(error) });
|
|
938
|
+
return errorResult(
|
|
939
|
+
`Failed to create episode: ${error instanceof Error ? error.message : String(error)}`
|
|
940
|
+
);
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
);
|
|
944
|
+
}
|
|
945
|
+
function registerProductionTools(server, ctx, track) {
|
|
946
|
+
server.registerTool(
|
|
947
|
+
track(mcpToolName(ctx.productName, "productions_get")),
|
|
948
|
+
{
|
|
949
|
+
title: "Get Production",
|
|
950
|
+
description: "Fetch a single production by ID, including its auditions.",
|
|
951
|
+
inputSchema: { id: zod.z.string().describe("Production ID") }
|
|
952
|
+
},
|
|
953
|
+
async ({ id }) => {
|
|
954
|
+
try {
|
|
955
|
+
const data = await ctx.gql.workspace.request(GET_PRODUCTION, { id });
|
|
956
|
+
if (!data.hokProduction) return errorResult(`Production ${id} not found`);
|
|
957
|
+
return jsonResult(data.hokProduction);
|
|
958
|
+
} catch (error) {
|
|
959
|
+
ctx.logger.error("hookmovies productions_get failed", { error: String(error) });
|
|
960
|
+
return errorResult(
|
|
961
|
+
`Failed to get production: ${error instanceof Error ? error.message : String(error)}`
|
|
962
|
+
);
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
);
|
|
966
|
+
server.registerTool(
|
|
967
|
+
track(mcpToolName(ctx.productName, "productions_list")),
|
|
968
|
+
{
|
|
969
|
+
title: "List Productions",
|
|
970
|
+
description: "List productions in the bound workspace, optionally filtered by status and/or studio, with pagination.",
|
|
971
|
+
inputSchema: {
|
|
972
|
+
status: ProductionStatusEnum.optional().describe("Filter by production status"),
|
|
973
|
+
studioId: zod.z.string().optional().describe("Filter by studio ID"),
|
|
974
|
+
limit: zod.z.number().int().optional().describe("Page size (default 50)"),
|
|
975
|
+
offset: zod.z.number().int().optional().describe("Pagination offset (default 0)"),
|
|
976
|
+
cursor: zod.z.string().optional().describe("Opaque pagination cursor")
|
|
977
|
+
}
|
|
978
|
+
},
|
|
979
|
+
async ({ status, studioId, limit, offset, cursor }) => {
|
|
980
|
+
try {
|
|
981
|
+
const data = await ctx.gql.workspace.request(LIST_PRODUCTIONS, {
|
|
982
|
+
status,
|
|
983
|
+
studioId,
|
|
984
|
+
pagination: { limit: limit ?? 50, offset: offset ?? 0, cursor }
|
|
985
|
+
});
|
|
986
|
+
return jsonResult(data.hokListProductions);
|
|
987
|
+
} catch (error) {
|
|
988
|
+
ctx.logger.error("hookmovies productions_list failed", { error: String(error) });
|
|
989
|
+
return errorResult(
|
|
990
|
+
`Failed to list productions: ${error instanceof Error ? error.message : String(error)}`
|
|
991
|
+
);
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
);
|
|
995
|
+
server.registerTool(
|
|
996
|
+
track(mcpToolName(ctx.productName, "productions_create")),
|
|
997
|
+
{
|
|
998
|
+
title: "Create Production",
|
|
999
|
+
description: 'Open a new production. `title` is required. Budget is expressed in minor units as a string (e.g. "150000000" for \u20B915,00,000.00).',
|
|
1000
|
+
inputSchema: {
|
|
1001
|
+
title: zod.z.string().min(1).describe("Production title"),
|
|
1002
|
+
logline: zod.z.string().optional().describe("One-line logline"),
|
|
1003
|
+
synopsis: zod.z.string().optional().describe("Synopsis"),
|
|
1004
|
+
tags: zod.z.array(zod.z.string()).optional().describe("Discovery tags"),
|
|
1005
|
+
studioId: zod.z.string().optional().describe("Producing studio ID"),
|
|
1006
|
+
producerId: zod.z.string().optional().describe("Lead producer user ID"),
|
|
1007
|
+
currency: zod.z.string().optional().describe("Budget currency code"),
|
|
1008
|
+
budgetMinorUnits: zod.z.string().optional().describe("Budget in minor units (string)"),
|
|
1009
|
+
startDate: zod.z.string().optional().describe("Start date (ISO-8601 DateTime)"),
|
|
1010
|
+
endDate: zod.z.string().optional().describe("End date (ISO-8601 DateTime)"),
|
|
1011
|
+
artistrybaseProjectRef: zod.z.string().optional().describe("Stable Artistrybase project id this production is promoted from")
|
|
1012
|
+
}
|
|
1013
|
+
},
|
|
1014
|
+
async ({
|
|
1015
|
+
title,
|
|
1016
|
+
logline,
|
|
1017
|
+
synopsis,
|
|
1018
|
+
tags,
|
|
1019
|
+
studioId,
|
|
1020
|
+
producerId,
|
|
1021
|
+
currency,
|
|
1022
|
+
budgetMinorUnits,
|
|
1023
|
+
startDate,
|
|
1024
|
+
endDate,
|
|
1025
|
+
artistrybaseProjectRef
|
|
1026
|
+
}) => {
|
|
1027
|
+
try {
|
|
1028
|
+
const input = { title };
|
|
1029
|
+
if (logline !== void 0) input.logline = logline;
|
|
1030
|
+
if (synopsis !== void 0) input.synopsis = synopsis;
|
|
1031
|
+
if (tags !== void 0) input.tags = tags;
|
|
1032
|
+
if (studioId !== void 0) input.studioId = studioId;
|
|
1033
|
+
if (producerId !== void 0) input.producerId = producerId;
|
|
1034
|
+
if (currency !== void 0) input.currency = currency;
|
|
1035
|
+
if (budgetMinorUnits !== void 0) input.budgetMinorUnits = budgetMinorUnits;
|
|
1036
|
+
if (startDate !== void 0) input.startDate = startDate;
|
|
1037
|
+
if (endDate !== void 0) input.endDate = endDate;
|
|
1038
|
+
if (artistrybaseProjectRef !== void 0)
|
|
1039
|
+
input.artistrybaseProjectRef = artistrybaseProjectRef;
|
|
1040
|
+
const data = await ctx.gql.workspace.request(CREATE_PRODUCTION, { input });
|
|
1041
|
+
return jsonResult(data.hokCreateProduction);
|
|
1042
|
+
} catch (error) {
|
|
1043
|
+
ctx.logger.error("hookmovies productions_create failed", { error: String(error) });
|
|
1044
|
+
return errorResult(
|
|
1045
|
+
`Failed to create production: ${error instanceof Error ? error.message : String(error)}`
|
|
1046
|
+
);
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
);
|
|
1050
|
+
server.registerTool(
|
|
1051
|
+
track(mcpToolName(ctx.productName, "productions_transition")),
|
|
1052
|
+
{
|
|
1053
|
+
title: "Transition Production",
|
|
1054
|
+
description: "Advance a production through its lifecycle (validated transitions): DEVELOPMENT \u2192 GREENLIT \u2192 IN_PRODUCTION \u2192 POST_PRODUCTION \u2192 RELEASED (or SHELVED).",
|
|
1055
|
+
inputSchema: {
|
|
1056
|
+
id: zod.z.string().describe("Production ID"),
|
|
1057
|
+
status: ProductionStatusEnum.describe("Target production status")
|
|
1058
|
+
}
|
|
1059
|
+
},
|
|
1060
|
+
async ({ id, status }) => {
|
|
1061
|
+
try {
|
|
1062
|
+
const data = await ctx.gql.workspace.request(TRANSITION_PRODUCTION, { id, status });
|
|
1063
|
+
return jsonResult(data.hokTransitionProduction);
|
|
1064
|
+
} catch (error) {
|
|
1065
|
+
ctx.logger.error("hookmovies productions_transition failed", { error: String(error) });
|
|
1066
|
+
return errorResult(
|
|
1067
|
+
`Failed to transition production: ${error instanceof Error ? error.message : String(error)}`
|
|
1068
|
+
);
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
);
|
|
1072
|
+
}
|
|
1073
|
+
function registerAuditionTools(server, ctx, track) {
|
|
1074
|
+
server.registerTool(
|
|
1075
|
+
track(mcpToolName(ctx.productName, "auditions_list")),
|
|
1076
|
+
{
|
|
1077
|
+
title: "List Auditions",
|
|
1078
|
+
description: "List auditions in the bound workspace, optionally filtered by production and/or status, with pagination.",
|
|
1079
|
+
inputSchema: {
|
|
1080
|
+
productionId: zod.z.string().optional().describe("Filter by production ID"),
|
|
1081
|
+
status: AuditionStatusEnum.optional().describe("Filter by audition status"),
|
|
1082
|
+
limit: zod.z.number().int().optional().describe("Page size (default 50)"),
|
|
1083
|
+
offset: zod.z.number().int().optional().describe("Pagination offset (default 0)"),
|
|
1084
|
+
cursor: zod.z.string().optional().describe("Opaque pagination cursor")
|
|
1085
|
+
}
|
|
1086
|
+
},
|
|
1087
|
+
async ({ productionId, status, limit, offset, cursor }) => {
|
|
1088
|
+
try {
|
|
1089
|
+
const data = await ctx.gql.workspace.request(LIST_AUDITIONS, {
|
|
1090
|
+
productionId,
|
|
1091
|
+
status,
|
|
1092
|
+
pagination: { limit: limit ?? 50, offset: offset ?? 0, cursor }
|
|
1093
|
+
});
|
|
1094
|
+
return jsonResult(data.hokListAuditions);
|
|
1095
|
+
} catch (error) {
|
|
1096
|
+
ctx.logger.error("hookmovies auditions_list failed", { error: String(error) });
|
|
1097
|
+
return errorResult(
|
|
1098
|
+
`Failed to list auditions: ${error instanceof Error ? error.message : String(error)}`
|
|
1099
|
+
);
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
);
|
|
1103
|
+
server.registerTool(
|
|
1104
|
+
track(mcpToolName(ctx.productName, "auditions_create")),
|
|
1105
|
+
{
|
|
1106
|
+
title: "Create Audition",
|
|
1107
|
+
description: "Open an audition/casting call for a role on a production. `productionId` and `roleName` are required. `payMinorUnits` is a minor-units string.",
|
|
1108
|
+
inputSchema: {
|
|
1109
|
+
productionId: zod.z.string().min(1).describe("Production the audition belongs to"),
|
|
1110
|
+
roleName: zod.z.string().min(1).describe("Role being cast"),
|
|
1111
|
+
description: zod.z.string().optional().describe("Audition / role description"),
|
|
1112
|
+
isMinorRole: zod.z.boolean().optional().describe("Whether this is a minor role (default false)"),
|
|
1113
|
+
language: zod.z.string().optional().describe("Required language"),
|
|
1114
|
+
location: zod.z.string().optional().describe("Audition location"),
|
|
1115
|
+
currency: zod.z.string().optional().describe("Pay currency code"),
|
|
1116
|
+
payMinorUnits: zod.z.string().optional().describe("Pay in minor units (string)"),
|
|
1117
|
+
submissionDeadline: zod.z.string().optional().describe("Submission deadline (ISO-8601 DateTime)")
|
|
1118
|
+
}
|
|
1119
|
+
},
|
|
1120
|
+
async ({
|
|
1121
|
+
productionId,
|
|
1122
|
+
roleName,
|
|
1123
|
+
description,
|
|
1124
|
+
isMinorRole,
|
|
1125
|
+
language,
|
|
1126
|
+
location,
|
|
1127
|
+
currency,
|
|
1128
|
+
payMinorUnits,
|
|
1129
|
+
submissionDeadline
|
|
1130
|
+
}) => {
|
|
1131
|
+
try {
|
|
1132
|
+
const input = { productionId, roleName };
|
|
1133
|
+
if (description !== void 0) input.description = description;
|
|
1134
|
+
if (isMinorRole !== void 0) input.isMinorRole = isMinorRole;
|
|
1135
|
+
if (language !== void 0) input.language = language;
|
|
1136
|
+
if (location !== void 0) input.location = location;
|
|
1137
|
+
if (currency !== void 0) input.currency = currency;
|
|
1138
|
+
if (payMinorUnits !== void 0) input.payMinorUnits = payMinorUnits;
|
|
1139
|
+
if (submissionDeadline !== void 0) input.submissionDeadline = submissionDeadline;
|
|
1140
|
+
const data = await ctx.gql.workspace.request(CREATE_AUDITION, { input });
|
|
1141
|
+
return jsonResult(data.hokCreateAudition);
|
|
1142
|
+
} catch (error) {
|
|
1143
|
+
ctx.logger.error("hookmovies auditions_create failed", { error: String(error) });
|
|
1144
|
+
return errorResult(
|
|
1145
|
+
`Failed to create audition: ${error instanceof Error ? error.message : String(error)}`
|
|
1146
|
+
);
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
);
|
|
1150
|
+
server.registerTool(
|
|
1151
|
+
track(mcpToolName(ctx.productName, "auditions_close")),
|
|
1152
|
+
{
|
|
1153
|
+
title: "Close Audition",
|
|
1154
|
+
description: "Close an open audition (no further submissions accepted).",
|
|
1155
|
+
inputSchema: { id: zod.z.string().describe("Audition ID") }
|
|
1156
|
+
},
|
|
1157
|
+
async ({ id }) => {
|
|
1158
|
+
try {
|
|
1159
|
+
const data = await ctx.gql.workspace.request(CLOSE_AUDITION, { id });
|
|
1160
|
+
return jsonResult(data.hokCloseAudition);
|
|
1161
|
+
} catch (error) {
|
|
1162
|
+
ctx.logger.error("hookmovies auditions_close failed", { error: String(error) });
|
|
1163
|
+
return errorResult(
|
|
1164
|
+
`Failed to close audition: ${error instanceof Error ? error.message : String(error)}`
|
|
1165
|
+
);
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
);
|
|
1169
|
+
server.registerTool(
|
|
1170
|
+
track(mcpToolName(ctx.productName, "applications_list")),
|
|
1171
|
+
{
|
|
1172
|
+
title: "List Applications",
|
|
1173
|
+
description: "List the applications submitted to a given audition (casting-team view).",
|
|
1174
|
+
inputSchema: { auditionId: zod.z.string().describe("Audition ID") }
|
|
1175
|
+
},
|
|
1176
|
+
async ({ auditionId }) => {
|
|
1177
|
+
try {
|
|
1178
|
+
const data = await ctx.gql.workspace.request(LIST_APPLICATIONS, { auditionId });
|
|
1179
|
+
return jsonResult(data.hokListApplications);
|
|
1180
|
+
} catch (error) {
|
|
1181
|
+
ctx.logger.error("hookmovies applications_list failed", { error: String(error) });
|
|
1182
|
+
return errorResult(
|
|
1183
|
+
`Failed to list applications: ${error instanceof Error ? error.message : String(error)}`
|
|
1184
|
+
);
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1187
|
+
);
|
|
1188
|
+
server.registerTool(
|
|
1189
|
+
track(mcpToolName(ctx.productName, "applications_apply")),
|
|
1190
|
+
{
|
|
1191
|
+
title: "Apply to Audition",
|
|
1192
|
+
description: "Apply to an audition as the calling user (self-scoped). Optionally include a cover note and a self-tape file (selfTapeFileId references a wspace-files-svc File).",
|
|
1193
|
+
inputSchema: {
|
|
1194
|
+
auditionId: zod.z.string().min(1).describe("Audition to apply to"),
|
|
1195
|
+
coverNote: zod.z.string().optional().describe("Cover note / pitch"),
|
|
1196
|
+
selfTapeFileId: zod.z.string().optional().describe("wspace-files-svc File ID of the self-tape")
|
|
1197
|
+
}
|
|
1198
|
+
},
|
|
1199
|
+
async ({ auditionId, coverNote, selfTapeFileId }) => {
|
|
1200
|
+
try {
|
|
1201
|
+
const input = { auditionId };
|
|
1202
|
+
if (coverNote !== void 0) input.coverNote = coverNote;
|
|
1203
|
+
if (selfTapeFileId !== void 0) input.selfTapeFileId = selfTapeFileId;
|
|
1204
|
+
const data = await ctx.gql.workspace.request(APPLY_TO_AUDITION, { input });
|
|
1205
|
+
return jsonResult(data.hokApplyToAudition);
|
|
1206
|
+
} catch (error) {
|
|
1207
|
+
ctx.logger.error("hookmovies applications_apply failed", { error: String(error) });
|
|
1208
|
+
return errorResult(
|
|
1209
|
+
`Failed to apply to audition: ${error instanceof Error ? error.message : String(error)}`
|
|
1210
|
+
);
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
);
|
|
1214
|
+
server.registerTool(
|
|
1215
|
+
track(mcpToolName(ctx.productName, "applications_score")),
|
|
1216
|
+
{
|
|
1217
|
+
title: "Score Application",
|
|
1218
|
+
description: "Score an applicant (casting-team action; workspace-scoped).",
|
|
1219
|
+
inputSchema: {
|
|
1220
|
+
id: zod.z.string().describe("Application ID"),
|
|
1221
|
+
score: zod.z.number().int().describe("Score to assign the applicant")
|
|
1222
|
+
}
|
|
1223
|
+
},
|
|
1224
|
+
async ({ id, score }) => {
|
|
1225
|
+
try {
|
|
1226
|
+
const data = await ctx.gql.workspace.request(SCORE_APPLICATION, { id, score });
|
|
1227
|
+
return jsonResult(data.hokScoreApplication);
|
|
1228
|
+
} catch (error) {
|
|
1229
|
+
ctx.logger.error("hookmovies applications_score failed", { error: String(error) });
|
|
1230
|
+
return errorResult(
|
|
1231
|
+
`Failed to score application: ${error instanceof Error ? error.message : String(error)}`
|
|
1232
|
+
);
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
);
|
|
1236
|
+
}
|
|
1237
|
+
function registerReviewTools(server, ctx, track) {
|
|
1238
|
+
server.registerTool(
|
|
1239
|
+
track(mcpToolName(ctx.productName, "reviews_list")),
|
|
1240
|
+
{
|
|
1241
|
+
title: "List Reviews",
|
|
1242
|
+
description: "List reviews in the bound workspace, optionally filtered by title and/or moderation status, with pagination.",
|
|
1243
|
+
inputSchema: {
|
|
1244
|
+
titleId: zod.z.string().optional().describe("Filter by title ID"),
|
|
1245
|
+
status: ReviewStatusEnum.optional().describe("Filter by moderation status"),
|
|
1246
|
+
limit: zod.z.number().int().optional().describe("Page size (default 50)"),
|
|
1247
|
+
offset: zod.z.number().int().optional().describe("Pagination offset (default 0)"),
|
|
1248
|
+
cursor: zod.z.string().optional().describe("Opaque pagination cursor")
|
|
1249
|
+
}
|
|
1250
|
+
},
|
|
1251
|
+
async ({ titleId, status, limit, offset, cursor }) => {
|
|
1252
|
+
try {
|
|
1253
|
+
const data = await ctx.gql.workspace.request(LIST_REVIEWS, {
|
|
1254
|
+
titleId,
|
|
1255
|
+
status,
|
|
1256
|
+
pagination: { limit: limit ?? 50, offset: offset ?? 0, cursor }
|
|
1257
|
+
});
|
|
1258
|
+
return jsonResult(data.hokListReviews);
|
|
1259
|
+
} catch (error) {
|
|
1260
|
+
ctx.logger.error("hookmovies reviews_list failed", { error: String(error) });
|
|
1261
|
+
return errorResult(
|
|
1262
|
+
`Failed to list reviews: ${error instanceof Error ? error.message : String(error)}`
|
|
1263
|
+
);
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
);
|
|
1267
|
+
server.registerTool(
|
|
1268
|
+
track(mcpToolName(ctx.productName, "reviews_create")),
|
|
1269
|
+
{
|
|
1270
|
+
title: "Create Review",
|
|
1271
|
+
description: "Create a review for a title as the calling user (self-scoped). `score` and `titleId` are required.",
|
|
1272
|
+
inputSchema: {
|
|
1273
|
+
titleId: zod.z.string().min(1).describe("Title being reviewed"),
|
|
1274
|
+
score: zod.z.number().int().describe("Score for the title (e.g. 1\u201310)"),
|
|
1275
|
+
body: zod.z.string().optional().describe("Free-text review body"),
|
|
1276
|
+
hasSpoilers: zod.z.boolean().optional().describe("Whether the review has spoilers (default false)"),
|
|
1277
|
+
aspectScores: JsonObject.optional().describe(
|
|
1278
|
+
"Per-aspect scores JSON (e.g. { acting, story })"
|
|
1279
|
+
)
|
|
1280
|
+
}
|
|
1281
|
+
},
|
|
1282
|
+
async ({ titleId, score, body, hasSpoilers, aspectScores }) => {
|
|
1283
|
+
try {
|
|
1284
|
+
const input = { titleId, score };
|
|
1285
|
+
if (body !== void 0) input.body = body;
|
|
1286
|
+
if (hasSpoilers !== void 0) input.hasSpoilers = hasSpoilers;
|
|
1287
|
+
if (aspectScores !== void 0) input.aspectScores = aspectScores;
|
|
1288
|
+
const data = await ctx.gql.workspace.request(CREATE_REVIEW, { input });
|
|
1289
|
+
return jsonResult(data.hokCreateReview);
|
|
1290
|
+
} catch (error) {
|
|
1291
|
+
ctx.logger.error("hookmovies reviews_create failed", { error: String(error) });
|
|
1292
|
+
return errorResult(
|
|
1293
|
+
`Failed to create review: ${error instanceof Error ? error.message : String(error)}`
|
|
1294
|
+
);
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
);
|
|
1298
|
+
server.registerTool(
|
|
1299
|
+
track(mcpToolName(ctx.productName, "reviews_delete")),
|
|
1300
|
+
{
|
|
1301
|
+
title: "Delete Review",
|
|
1302
|
+
description: "Delete the calling user\u2019s own review (self-scoped). Returns true on success.",
|
|
1303
|
+
inputSchema: { id: zod.z.string().describe("Review ID") }
|
|
1304
|
+
},
|
|
1305
|
+
async ({ id }) => {
|
|
1306
|
+
try {
|
|
1307
|
+
const data = await ctx.gql.workspace.request(
|
|
1308
|
+
DELETE_REVIEW,
|
|
1309
|
+
{ id }
|
|
1310
|
+
);
|
|
1311
|
+
return jsonResult({ deleted: data.hokDeleteReview });
|
|
1312
|
+
} catch (error) {
|
|
1313
|
+
ctx.logger.error("hookmovies reviews_delete failed", { error: String(error) });
|
|
1314
|
+
return errorResult(
|
|
1315
|
+
`Failed to delete review: ${error instanceof Error ? error.message : String(error)}`
|
|
1316
|
+
);
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
);
|
|
1320
|
+
}
|
|
1321
|
+
function registerRightsTools(server, ctx, track) {
|
|
1322
|
+
server.registerTool(
|
|
1323
|
+
track(mcpToolName(ctx.productName, "rights_list")),
|
|
1324
|
+
{
|
|
1325
|
+
title: "List Rights Windows",
|
|
1326
|
+
description: "List rights/licensing windows in the bound workspace, optionally filtered by title and/or status, with pagination.",
|
|
1327
|
+
inputSchema: {
|
|
1328
|
+
titleId: zod.z.string().optional().describe("Filter by title ID"),
|
|
1329
|
+
status: RightsWindowStatusEnum.optional().describe("Filter by rights-window status"),
|
|
1330
|
+
limit: zod.z.number().int().optional().describe("Page size (default 50)"),
|
|
1331
|
+
offset: zod.z.number().int().optional().describe("Pagination offset (default 0)"),
|
|
1332
|
+
cursor: zod.z.string().optional().describe("Opaque pagination cursor")
|
|
1333
|
+
}
|
|
1334
|
+
},
|
|
1335
|
+
async ({ titleId, status, limit, offset, cursor }) => {
|
|
1336
|
+
try {
|
|
1337
|
+
const data = await ctx.gql.workspace.request(LIST_RIGHTS_WINDOWS, {
|
|
1338
|
+
titleId,
|
|
1339
|
+
status,
|
|
1340
|
+
pagination: { limit: limit ?? 50, offset: offset ?? 0, cursor }
|
|
1341
|
+
});
|
|
1342
|
+
return jsonResult(data.hokListRightsWindows);
|
|
1343
|
+
} catch (error) {
|
|
1344
|
+
ctx.logger.error("hookmovies rights_list failed", { error: String(error) });
|
|
1345
|
+
return errorResult(
|
|
1346
|
+
`Failed to list rights windows: ${error instanceof Error ? error.message : String(error)}`
|
|
1347
|
+
);
|
|
1348
|
+
}
|
|
1349
|
+
}
|
|
1350
|
+
);
|
|
1351
|
+
server.registerTool(
|
|
1352
|
+
track(mcpToolName(ctx.productName, "rights_create")),
|
|
1353
|
+
{
|
|
1354
|
+
title: "Create Rights Window",
|
|
1355
|
+
description: "Create a rights/licensing window for a title. `titleId` and at least one monetization `mode` are required. `priceMinorUnits` is a JSON map of per-mode prices.",
|
|
1356
|
+
inputSchema: {
|
|
1357
|
+
titleId: zod.z.string().min(1).describe("Title the window applies to"),
|
|
1358
|
+
modes: zod.z.array(MonetizationModeEnum).min(1).describe("Monetization modes covered by this window"),
|
|
1359
|
+
territories: zod.z.array(zod.z.string()).optional().describe("ISO territory codes (default global)"),
|
|
1360
|
+
exclusive: zod.z.boolean().optional().describe("Whether the license is exclusive (default false)"),
|
|
1361
|
+
licenseeId: zod.z.string().optional().describe("Licensee ID (for licensed-out windows)"),
|
|
1362
|
+
currency: zod.z.string().optional().describe("Price currency code"),
|
|
1363
|
+
priceMinorUnits: JsonObject.optional().describe("Per-mode price map JSON (minor units)"),
|
|
1364
|
+
startsAt: zod.z.string().optional().describe("Window start (ISO-8601 DateTime)"),
|
|
1365
|
+
endsAt: zod.z.string().optional().describe("Window end (ISO-8601 DateTime)"),
|
|
1366
|
+
contractFileId: zod.z.string().optional().describe("wspace-files-svc File ID of the contract")
|
|
1367
|
+
}
|
|
1368
|
+
},
|
|
1369
|
+
async ({
|
|
1370
|
+
titleId,
|
|
1371
|
+
modes,
|
|
1372
|
+
territories,
|
|
1373
|
+
exclusive,
|
|
1374
|
+
licenseeId,
|
|
1375
|
+
currency,
|
|
1376
|
+
priceMinorUnits,
|
|
1377
|
+
startsAt,
|
|
1378
|
+
endsAt,
|
|
1379
|
+
contractFileId
|
|
1380
|
+
}) => {
|
|
1381
|
+
try {
|
|
1382
|
+
const input = { titleId, modes };
|
|
1383
|
+
if (territories !== void 0) input.territories = territories;
|
|
1384
|
+
if (exclusive !== void 0) input.exclusive = exclusive;
|
|
1385
|
+
if (licenseeId !== void 0) input.licenseeId = licenseeId;
|
|
1386
|
+
if (currency !== void 0) input.currency = currency;
|
|
1387
|
+
if (priceMinorUnits !== void 0) input.priceMinorUnits = priceMinorUnits;
|
|
1388
|
+
if (startsAt !== void 0) input.startsAt = startsAt;
|
|
1389
|
+
if (endsAt !== void 0) input.endsAt = endsAt;
|
|
1390
|
+
if (contractFileId !== void 0) input.contractFileId = contractFileId;
|
|
1391
|
+
const data = await ctx.gql.workspace.request(CREATE_RIGHTS_WINDOW, { input });
|
|
1392
|
+
return jsonResult(data.hokCreateRightsWindow);
|
|
1393
|
+
} catch (error) {
|
|
1394
|
+
ctx.logger.error("hookmovies rights_create failed", { error: String(error) });
|
|
1395
|
+
return errorResult(
|
|
1396
|
+
`Failed to create rights window: ${error instanceof Error ? error.message : String(error)}`
|
|
1397
|
+
);
|
|
1398
|
+
}
|
|
1399
|
+
}
|
|
1400
|
+
);
|
|
1401
|
+
server.registerTool(
|
|
1402
|
+
track(mcpToolName(ctx.productName, "rights_transition")),
|
|
1403
|
+
{
|
|
1404
|
+
title: "Transition Rights Window",
|
|
1405
|
+
description: "Move a rights window through its lifecycle (validated transitions): DRAFT \u2192 PENDING \u2192 ACTIVE \u2192 EXPIRED (or REVOKED).",
|
|
1406
|
+
inputSchema: {
|
|
1407
|
+
id: zod.z.string().describe("Rights window ID"),
|
|
1408
|
+
status: RightsWindowStatusEnum.describe("Target rights-window status")
|
|
1409
|
+
}
|
|
1410
|
+
},
|
|
1411
|
+
async ({ id, status }) => {
|
|
1412
|
+
try {
|
|
1413
|
+
const data = await ctx.gql.workspace.request(TRANSITION_RIGHTS_WINDOW, { id, status });
|
|
1414
|
+
return jsonResult(data.hokTransitionRightsWindow);
|
|
1415
|
+
} catch (error) {
|
|
1416
|
+
ctx.logger.error("hookmovies rights_transition failed", { error: String(error) });
|
|
1417
|
+
return errorResult(
|
|
1418
|
+
`Failed to transition rights window: ${error instanceof Error ? error.message : String(error)}`
|
|
1419
|
+
);
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1422
|
+
);
|
|
1423
|
+
}
|
|
1424
|
+
function registerEntitlementTools(server, ctx, track) {
|
|
1425
|
+
server.registerTool(
|
|
1426
|
+
track(mcpToolName(ctx.productName, "entitlements_grant")),
|
|
1427
|
+
{
|
|
1428
|
+
title: "Grant Entitlement",
|
|
1429
|
+
description: "Grant a user access to a title (workspace-scoped admin action). `titleId`, `userId`, and `mode` are required; default source is SUBSCRIPTION.",
|
|
1430
|
+
inputSchema: {
|
|
1431
|
+
titleId: zod.z.string().min(1).describe("Title to grant access to"),
|
|
1432
|
+
userId: zod.z.string().min(1).describe("User receiving the entitlement"),
|
|
1433
|
+
mode: MonetizationModeEnum.describe("Monetization mode the entitlement covers"),
|
|
1434
|
+
source: EntitlementSourceEnum.optional().describe(
|
|
1435
|
+
"How it was acquired (default SUBSCRIPTION)"
|
|
1436
|
+
),
|
|
1437
|
+
territory: zod.z.string().optional().describe("Territory the entitlement is valid in"),
|
|
1438
|
+
expiresAt: zod.z.string().optional().describe("Expiry timestamp (ISO-8601 DateTime)")
|
|
1439
|
+
}
|
|
1440
|
+
},
|
|
1441
|
+
async ({ titleId, userId, mode, source, territory, expiresAt }) => {
|
|
1442
|
+
try {
|
|
1443
|
+
const input = { titleId, userId, mode };
|
|
1444
|
+
if (source !== void 0) input.source = source;
|
|
1445
|
+
if (territory !== void 0) input.territory = territory;
|
|
1446
|
+
if (expiresAt !== void 0) input.expiresAt = expiresAt;
|
|
1447
|
+
const data = await ctx.gql.workspace.request(GRANT_ENTITLEMENT, { input });
|
|
1448
|
+
return jsonResult(data.hokGrantEntitlement);
|
|
1449
|
+
} catch (error) {
|
|
1450
|
+
ctx.logger.error("hookmovies entitlements_grant failed", { error: String(error) });
|
|
1451
|
+
return errorResult(
|
|
1452
|
+
`Failed to grant entitlement: ${error instanceof Error ? error.message : String(error)}`
|
|
1453
|
+
);
|
|
1454
|
+
}
|
|
1455
|
+
}
|
|
1456
|
+
);
|
|
1457
|
+
server.registerTool(
|
|
1458
|
+
track(mcpToolName(ctx.productName, "entitlements_revoke")),
|
|
1459
|
+
{
|
|
1460
|
+
title: "Revoke Entitlement",
|
|
1461
|
+
description: "Revoke an existing entitlement by ID (workspace-scoped admin action). Returns true on success.",
|
|
1462
|
+
inputSchema: { id: zod.z.string().describe("Entitlement ID") }
|
|
1463
|
+
},
|
|
1464
|
+
async ({ id }) => {
|
|
1465
|
+
try {
|
|
1466
|
+
const data = await ctx.gql.workspace.request(
|
|
1467
|
+
REVOKE_ENTITLEMENT,
|
|
1468
|
+
{ id }
|
|
1469
|
+
);
|
|
1470
|
+
return jsonResult({ revoked: data.hokRevokeEntitlement });
|
|
1471
|
+
} catch (error) {
|
|
1472
|
+
ctx.logger.error("hookmovies entitlements_revoke failed", { error: String(error) });
|
|
1473
|
+
return errorResult(
|
|
1474
|
+
`Failed to revoke entitlement: ${error instanceof Error ? error.message : String(error)}`
|
|
1475
|
+
);
|
|
1476
|
+
}
|
|
1477
|
+
}
|
|
1478
|
+
);
|
|
1479
|
+
server.registerTool(
|
|
1480
|
+
track(mcpToolName(ctx.productName, "entitlements_my")),
|
|
1481
|
+
{
|
|
1482
|
+
title: "My Entitlements",
|
|
1483
|
+
description: "List the calling user\u2019s own entitlements (self-scoped), optionally filtered to a single title.",
|
|
1484
|
+
inputSchema: {
|
|
1485
|
+
titleId: zod.z.string().optional().describe("Filter to entitlements for a single title")
|
|
1486
|
+
}
|
|
1487
|
+
},
|
|
1488
|
+
async ({ titleId }) => {
|
|
1489
|
+
try {
|
|
1490
|
+
const data = await ctx.gql.workspace.request(MY_ENTITLEMENTS, { titleId });
|
|
1491
|
+
return jsonResult(data.hokMyEntitlements);
|
|
1492
|
+
} catch (error) {
|
|
1493
|
+
ctx.logger.error("hookmovies entitlements_my failed", { error: String(error) });
|
|
1494
|
+
return errorResult(
|
|
1495
|
+
`Failed to list my entitlements: ${error instanceof Error ? error.message : String(error)}`
|
|
1496
|
+
);
|
|
1497
|
+
}
|
|
1498
|
+
}
|
|
1499
|
+
);
|
|
1500
|
+
server.registerTool(
|
|
1501
|
+
track(mcpToolName(ctx.productName, "entitlements_check")),
|
|
1502
|
+
{
|
|
1503
|
+
title: "Check Entitlement",
|
|
1504
|
+
description: "Check whether the calling user can watch a title now (self-scoped). Returns whether entitled and the covered monetization modes.",
|
|
1505
|
+
inputSchema: { titleId: zod.z.string().describe("Title ID to check") }
|
|
1506
|
+
},
|
|
1507
|
+
async ({ titleId }) => {
|
|
1508
|
+
try {
|
|
1509
|
+
const data = await ctx.gql.workspace.request(CHECK_ENTITLEMENT, { titleId });
|
|
1510
|
+
return jsonResult(data.hokCheckEntitlement);
|
|
1511
|
+
} catch (error) {
|
|
1512
|
+
ctx.logger.error("hookmovies entitlements_check failed", { error: String(error) });
|
|
1513
|
+
return errorResult(
|
|
1514
|
+
`Failed to check entitlement: ${error instanceof Error ? error.message : String(error)}`
|
|
1515
|
+
);
|
|
1516
|
+
}
|
|
1517
|
+
}
|
|
1518
|
+
);
|
|
1519
|
+
}
|
|
1520
|
+
function registerListTools(server, ctx, track) {
|
|
1521
|
+
server.registerTool(
|
|
1522
|
+
track(mcpToolName(ctx.productName, "lists_get")),
|
|
1523
|
+
{
|
|
1524
|
+
title: "Get List",
|
|
1525
|
+
description: "Fetch a single user list (watchlist/playlist) by ID.",
|
|
1526
|
+
inputSchema: { id: zod.z.string().describe("List ID") }
|
|
1527
|
+
},
|
|
1528
|
+
async ({ id }) => {
|
|
1529
|
+
try {
|
|
1530
|
+
const data = await ctx.gql.workspace.request(GET_LIST, { id });
|
|
1531
|
+
if (!data.hokList) return errorResult(`List ${id} not found`);
|
|
1532
|
+
return jsonResult(data.hokList);
|
|
1533
|
+
} catch (error) {
|
|
1534
|
+
ctx.logger.error("hookmovies lists_get failed", { error: String(error) });
|
|
1535
|
+
return errorResult(
|
|
1536
|
+
`Failed to get list: ${error instanceof Error ? error.message : String(error)}`
|
|
1537
|
+
);
|
|
1538
|
+
}
|
|
1539
|
+
}
|
|
1540
|
+
);
|
|
1541
|
+
server.registerTool(
|
|
1542
|
+
track(mcpToolName(ctx.productName, "lists_my")),
|
|
1543
|
+
{
|
|
1544
|
+
title: "My Lists",
|
|
1545
|
+
description: "List the calling user\u2019s own lists (self-scoped), optionally filtered by kind, with pagination.",
|
|
1546
|
+
inputSchema: {
|
|
1547
|
+
kind: ListKindEnum.optional().describe("Filter by list kind (PLAYLIST/WATCHLIST)"),
|
|
1548
|
+
limit: zod.z.number().int().optional().describe("Page size (default 50)"),
|
|
1549
|
+
offset: zod.z.number().int().optional().describe("Pagination offset (default 0)"),
|
|
1550
|
+
cursor: zod.z.string().optional().describe("Opaque pagination cursor")
|
|
1551
|
+
}
|
|
1552
|
+
},
|
|
1553
|
+
async ({ kind, limit, offset, cursor }) => {
|
|
1554
|
+
try {
|
|
1555
|
+
const data = await ctx.gql.workspace.request(MY_LISTS, {
|
|
1556
|
+
kind,
|
|
1557
|
+
pagination: { limit: limit ?? 50, offset: offset ?? 0, cursor }
|
|
1558
|
+
});
|
|
1559
|
+
return jsonResult(data.hokMyLists);
|
|
1560
|
+
} catch (error) {
|
|
1561
|
+
ctx.logger.error("hookmovies lists_my failed", { error: String(error) });
|
|
1562
|
+
return errorResult(
|
|
1563
|
+
`Failed to list my lists: ${error instanceof Error ? error.message : String(error)}`
|
|
1564
|
+
);
|
|
1565
|
+
}
|
|
1566
|
+
}
|
|
1567
|
+
);
|
|
1568
|
+
server.registerTool(
|
|
1569
|
+
track(mcpToolName(ctx.productName, "lists_create")),
|
|
1570
|
+
{
|
|
1571
|
+
title: "Create List",
|
|
1572
|
+
description: "Create a list owned by the calling user (self-scoped). `name` is required; defaults: kind=PLAYLIST, visibility=PRIVATE.",
|
|
1573
|
+
inputSchema: {
|
|
1574
|
+
name: zod.z.string().min(1).describe("List name"),
|
|
1575
|
+
kind: ListKindEnum.optional().describe("List kind (default PLAYLIST)"),
|
|
1576
|
+
visibility: ListVisibilityEnum.optional().describe("Visibility (default PRIVATE)"),
|
|
1577
|
+
description: zod.z.string().optional().describe("List description"),
|
|
1578
|
+
items: JsonValue.optional().describe("Initial list items JSON (e.g. [{ titleId }])")
|
|
1579
|
+
}
|
|
1580
|
+
},
|
|
1581
|
+
async ({ name, kind, visibility, description, items }) => {
|
|
1582
|
+
try {
|
|
1583
|
+
const input = { name };
|
|
1584
|
+
if (kind !== void 0) input.kind = kind;
|
|
1585
|
+
if (visibility !== void 0) input.visibility = visibility;
|
|
1586
|
+
if (description !== void 0) input.description = description;
|
|
1587
|
+
if (items !== void 0) input.items = items;
|
|
1588
|
+
const data = await ctx.gql.workspace.request(CREATE_LIST, { input });
|
|
1589
|
+
return jsonResult(data.hokCreateList);
|
|
1590
|
+
} catch (error) {
|
|
1591
|
+
ctx.logger.error("hookmovies lists_create failed", { error: String(error) });
|
|
1592
|
+
return errorResult(
|
|
1593
|
+
`Failed to create list: ${error instanceof Error ? error.message : String(error)}`
|
|
1594
|
+
);
|
|
1595
|
+
}
|
|
1596
|
+
}
|
|
1597
|
+
);
|
|
1598
|
+
server.registerTool(
|
|
1599
|
+
track(mcpToolName(ctx.productName, "lists_update")),
|
|
1600
|
+
{
|
|
1601
|
+
title: "Update List",
|
|
1602
|
+
description: "Update the calling user\u2019s own list (self-scoped). At least one mutable field must be provided. Set `items` to replace the list contents.",
|
|
1603
|
+
inputSchema: {
|
|
1604
|
+
id: zod.z.string().describe("List ID"),
|
|
1605
|
+
name: zod.z.string().optional().describe("Updated name"),
|
|
1606
|
+
description: zod.z.string().optional().describe("Updated description"),
|
|
1607
|
+
visibility: ListVisibilityEnum.optional().describe("Updated visibility"),
|
|
1608
|
+
items: JsonValue.optional().describe("Replacement list items JSON")
|
|
1609
|
+
}
|
|
1610
|
+
},
|
|
1611
|
+
async ({ id, name, description, visibility, items }) => {
|
|
1612
|
+
try {
|
|
1613
|
+
const input = {};
|
|
1614
|
+
if (name !== void 0) input.name = name;
|
|
1615
|
+
if (description !== void 0) input.description = description;
|
|
1616
|
+
if (visibility !== void 0) input.visibility = visibility;
|
|
1617
|
+
if (items !== void 0) input.items = items;
|
|
1618
|
+
if (Object.keys(input).length === 0) {
|
|
1619
|
+
return errorResult(
|
|
1620
|
+
"No updates specified \u2014 provide at least one of name/description/visibility/items"
|
|
1621
|
+
);
|
|
1622
|
+
}
|
|
1623
|
+
const data = await ctx.gql.workspace.request(UPDATE_LIST, { id, input });
|
|
1624
|
+
return jsonResult(data.hokUpdateList);
|
|
1625
|
+
} catch (error) {
|
|
1626
|
+
ctx.logger.error("hookmovies lists_update failed", { error: String(error) });
|
|
1627
|
+
return errorResult(
|
|
1628
|
+
`Failed to update list: ${error instanceof Error ? error.message : String(error)}`
|
|
1629
|
+
);
|
|
1630
|
+
}
|
|
1631
|
+
}
|
|
1632
|
+
);
|
|
1633
|
+
server.registerTool(
|
|
1634
|
+
track(mcpToolName(ctx.productName, "lists_delete")),
|
|
1635
|
+
{
|
|
1636
|
+
title: "Delete List",
|
|
1637
|
+
description: "Delete the calling user\u2019s own list (self-scoped). Returns true on success.",
|
|
1638
|
+
inputSchema: { id: zod.z.string().describe("List ID") }
|
|
1639
|
+
},
|
|
1640
|
+
async ({ id }) => {
|
|
1641
|
+
try {
|
|
1642
|
+
const data = await ctx.gql.workspace.request(DELETE_LIST, {
|
|
1643
|
+
id
|
|
1644
|
+
});
|
|
1645
|
+
return jsonResult({ deleted: data.hokDeleteList });
|
|
1646
|
+
} catch (error) {
|
|
1647
|
+
ctx.logger.error("hookmovies lists_delete failed", { error: String(error) });
|
|
1648
|
+
return errorResult(
|
|
1649
|
+
`Failed to delete list: ${error instanceof Error ? error.message : String(error)}`
|
|
1650
|
+
);
|
|
1651
|
+
}
|
|
1652
|
+
}
|
|
1653
|
+
);
|
|
1654
|
+
}
|
|
1655
|
+
function registerProgressTools(server, ctx, track) {
|
|
1656
|
+
server.registerTool(
|
|
1657
|
+
track(mcpToolName(ctx.productName, "progress_record")),
|
|
1658
|
+
{
|
|
1659
|
+
title: "Record Watch Progress",
|
|
1660
|
+
description: "Upsert the calling user\u2019s watch progress for a title/episode (self-scoped). `titleId` and `positionSeconds` are required; set `completed` when finished.",
|
|
1661
|
+
inputSchema: {
|
|
1662
|
+
titleId: zod.z.string().min(1).describe("Title being watched"),
|
|
1663
|
+
positionSeconds: zod.z.number().int().describe("Current playback position in seconds"),
|
|
1664
|
+
episodeId: zod.z.string().optional().describe("Episode ID (for episodic titles)"),
|
|
1665
|
+
completed: zod.z.boolean().optional().describe("Whether playback is complete (default false)"),
|
|
1666
|
+
lastDevice: zod.z.string().optional().describe("Identifier of the device last used")
|
|
1667
|
+
}
|
|
1668
|
+
},
|
|
1669
|
+
async ({ titleId, positionSeconds, episodeId, completed, lastDevice }) => {
|
|
1670
|
+
try {
|
|
1671
|
+
const input = { titleId, positionSeconds };
|
|
1672
|
+
if (episodeId !== void 0) input.episodeId = episodeId;
|
|
1673
|
+
if (completed !== void 0) input.completed = completed;
|
|
1674
|
+
if (lastDevice !== void 0) input.lastDevice = lastDevice;
|
|
1675
|
+
const data = await ctx.gql.workspace.request(RECORD_PROGRESS, { input });
|
|
1676
|
+
return jsonResult(data.hokRecordProgress);
|
|
1677
|
+
} catch (error) {
|
|
1678
|
+
ctx.logger.error("hookmovies progress_record failed", { error: String(error) });
|
|
1679
|
+
return errorResult(
|
|
1680
|
+
`Failed to record watch progress: ${error instanceof Error ? error.message : String(error)}`
|
|
1681
|
+
);
|
|
1682
|
+
}
|
|
1683
|
+
}
|
|
1684
|
+
);
|
|
1685
|
+
server.registerTool(
|
|
1686
|
+
track(mcpToolName(ctx.productName, "progress_my")),
|
|
1687
|
+
{
|
|
1688
|
+
title: "My Watch Progress",
|
|
1689
|
+
description: "List the calling user\u2019s continue-watching / progress entries (self-scoped), optionally filtered to a single title.",
|
|
1690
|
+
inputSchema: {
|
|
1691
|
+
titleId: zod.z.string().optional().describe("Filter to progress for a single title")
|
|
1692
|
+
}
|
|
1693
|
+
},
|
|
1694
|
+
async ({ titleId }) => {
|
|
1695
|
+
try {
|
|
1696
|
+
const data = await ctx.gql.workspace.request(MY_WATCH_PROGRESS, { titleId });
|
|
1697
|
+
return jsonResult(data.hokMyWatchProgress);
|
|
1698
|
+
} catch (error) {
|
|
1699
|
+
ctx.logger.error("hookmovies progress_my failed", { error: String(error) });
|
|
1700
|
+
return errorResult(
|
|
1701
|
+
`Failed to list my watch progress: ${error instanceof Error ? error.message : String(error)}`
|
|
1702
|
+
);
|
|
1703
|
+
}
|
|
1704
|
+
}
|
|
1705
|
+
);
|
|
1706
|
+
}
|
|
1707
|
+
|
|
1708
|
+
// src/modules/hookmovies/tools/health.ts
|
|
1709
|
+
function registerHealthTools(server, ctx, track) {
|
|
1710
|
+
server.registerTool(
|
|
1711
|
+
track(mcpToolName(ctx.productName, "health")),
|
|
1712
|
+
{
|
|
1713
|
+
title: "HookMovies Health Check",
|
|
1714
|
+
description: "Public health probe for the HookMovies subgraph (hokHealth). Requires no authentication.",
|
|
1715
|
+
inputSchema: {}
|
|
1716
|
+
},
|
|
1717
|
+
async () => {
|
|
1718
|
+
try {
|
|
1719
|
+
const data = await ctx.gql.workspace.request(HEALTH, {});
|
|
1720
|
+
return jsonResult({ ok: true, status: data.hokHealth });
|
|
1721
|
+
} catch (error) {
|
|
1722
|
+
ctx.logger.error("hookmovies health failed", { error: String(error) });
|
|
1723
|
+
return errorResult(
|
|
1724
|
+
`HookMovies health check failed: ${error instanceof Error ? error.message : String(error)}`
|
|
1725
|
+
);
|
|
1726
|
+
}
|
|
1727
|
+
}
|
|
1728
|
+
);
|
|
1729
|
+
}
|
|
1730
|
+
|
|
1731
|
+
// src/modules/hookmovies/resources.ts
|
|
1732
|
+
function registerHookmoviesResources(server, ctx, track) {
|
|
1733
|
+
const schemaUri = track(mcpResourceUri(ctx.productName, "schema"));
|
|
1734
|
+
const catalogUri = track(mcpResourceUri(ctx.productName, "catalog"));
|
|
1735
|
+
const productionsUri = track(mcpResourceUri(ctx.productName, "productions"));
|
|
1736
|
+
const studiosUri = track(mcpResourceUri(ctx.productName, "studios"));
|
|
1737
|
+
server.registerResource(
|
|
1738
|
+
"hookmovies-schema",
|
|
1739
|
+
schemaUri,
|
|
1740
|
+
{
|
|
1741
|
+
title: "HookMovies Domain Schema",
|
|
1742
|
+
description: "Overview of the HookMovies streaming + production domain \u2014 entities, enums, and the per-entity tool surface.",
|
|
1743
|
+
mimeType: "text/plain"
|
|
1744
|
+
},
|
|
1745
|
+
async () => {
|
|
1746
|
+
ctx.logger.debug(`Resource ${schemaUri} requested`);
|
|
1747
|
+
const schema = `# HookMovies Domain (Overview)
|
|
1748
|
+
|
|
1749
|
+
Multi-language global streaming + production network.
|
|
1750
|
+
|
|
1751
|
+
## Entities
|
|
1752
|
+
- HokTitle (+HokSeason, HokEpisode, HokCredit) \u2014 catalog title and its structure
|
|
1753
|
+
- HokStudio \u2014 studio / distributor
|
|
1754
|
+
- HokPerson \u2014 talent (cast/crew), linked to titles via HokCredit
|
|
1755
|
+
- HokProduction \u2014 a production on the slate (can yield a Title)
|
|
1756
|
+
- HokAudition (+HokApplication) \u2014 casting call and its applications
|
|
1757
|
+
- HokReview \u2014 viewer rating + moderation
|
|
1758
|
+
- HokRightsWindow \u2014 licensing window (modes/territories/time)
|
|
1759
|
+
- HokEntitlement (+HokEntitlementCheck) \u2014 viewer access grants
|
|
1760
|
+
- HokList \u2014 user watchlist / playlist (self-scoped)
|
|
1761
|
+
- HokWatchProgress \u2014 continue-watching entries (self-scoped)
|
|
1762
|
+
|
|
1763
|
+
## Enums
|
|
1764
|
+
- TitleType: ANIME, COLLECTION, DOCUMENTARY, FAST_CHANNEL, LIVE_EVENT, LONG_FORM, MOVIE, SERIES, SHORT_FILM, SHORT_FORM, TRAILER
|
|
1765
|
+
- TitleStatus: ARCHIVED, DRAFT, IN_REVIEW, PUBLISHED, SCHEDULED, UNPUBLISHED
|
|
1766
|
+
- CreditRole: ACTOR, CINEMATOGRAPHER, COMPOSER, CREW, DIRECTOR, EDITOR, PRODUCER, VOICE_ACTOR, WRITER
|
|
1767
|
+
- ProductionStatus: DEVELOPMENT, GREENLIT, IN_PRODUCTION, POST_PRODUCTION, RELEASED, SHELVED
|
|
1768
|
+
- AuditionStatus: CALLBACKS, CANCELLED, CLOSED, OPEN, REVIEWING
|
|
1769
|
+
- ApplicationStatus: CALLBACK, OFFERED, REJECTED, SHORTLISTED, SUBMITTED, WITHDRAWN
|
|
1770
|
+
- ReviewStatus: HIDDEN, PENDING, PUBLISHED, REMOVED
|
|
1771
|
+
- RightsWindowStatus: ACTIVE, DRAFT, EXPIRED, PENDING, REVOKED
|
|
1772
|
+
- MonetizationMode: FAST, FREE_AVOD, PPV, SVOD, TVOD_BUY, TVOD_RENT
|
|
1773
|
+
- EntitlementSource: FREE, PROMO, PURCHASE, RENTAL, SUBSCRIPTION
|
|
1774
|
+
- ListKind: PLAYLIST, WATCHLIST
|
|
1775
|
+
- ListVisibility: PRIVATE, PUBLIC, UNLISTED
|
|
1776
|
+
|
|
1777
|
+
## Tool groups
|
|
1778
|
+
titles, studios, people (+credits), episodes (+seasons), productions,
|
|
1779
|
+
auditions (+applications), reviews, rights, entitlements, lists, progress, health.
|
|
1780
|
+
All run against the WORKSPACE gateway (workspace-scoped) except the public
|
|
1781
|
+
health probe and the self-scoped viewer surfaces (lists, progress,
|
|
1782
|
+
entitlements_my/check, applications_apply, reviews_create/delete).
|
|
1783
|
+
`;
|
|
1784
|
+
return {
|
|
1785
|
+
contents: [{ uri: schemaUri, text: schema, mimeType: "text/plain" }]
|
|
1786
|
+
};
|
|
1787
|
+
}
|
|
1788
|
+
);
|
|
1789
|
+
server.registerResource(
|
|
1790
|
+
"hookmovies-catalog",
|
|
1791
|
+
catalogUri,
|
|
1792
|
+
{
|
|
1793
|
+
title: "HookMovies Catalog",
|
|
1794
|
+
description: "The first 50 titles in the bound workspace.",
|
|
1795
|
+
mimeType: "application/json"
|
|
1796
|
+
},
|
|
1797
|
+
async () => {
|
|
1798
|
+
ctx.logger.debug(`Resource ${catalogUri} requested`);
|
|
1799
|
+
try {
|
|
1800
|
+
const data = await ctx.gql.workspace.request(LIST_TITLES, {
|
|
1801
|
+
pagination: { limit: 50, offset: 0 }
|
|
1802
|
+
});
|
|
1803
|
+
return {
|
|
1804
|
+
contents: [
|
|
1805
|
+
{
|
|
1806
|
+
uri: catalogUri,
|
|
1807
|
+
text: JSON.stringify(data.hokListTitles, null, 2),
|
|
1808
|
+
mimeType: "application/json"
|
|
1809
|
+
}
|
|
1810
|
+
]
|
|
1811
|
+
};
|
|
1812
|
+
} catch (error) {
|
|
1813
|
+
return {
|
|
1814
|
+
contents: [
|
|
1815
|
+
{
|
|
1816
|
+
uri: catalogUri,
|
|
1817
|
+
text: JSON.stringify({
|
|
1818
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1819
|
+
}),
|
|
1820
|
+
mimeType: "application/json"
|
|
1821
|
+
}
|
|
1822
|
+
]
|
|
1823
|
+
};
|
|
1824
|
+
}
|
|
1825
|
+
}
|
|
1826
|
+
);
|
|
1827
|
+
server.registerResource(
|
|
1828
|
+
"hookmovies-productions",
|
|
1829
|
+
productionsUri,
|
|
1830
|
+
{
|
|
1831
|
+
title: "HookMovies Production Slate",
|
|
1832
|
+
description: "The first 50 productions in the bound workspace.",
|
|
1833
|
+
mimeType: "application/json"
|
|
1834
|
+
},
|
|
1835
|
+
async () => {
|
|
1836
|
+
ctx.logger.debug(`Resource ${productionsUri} requested`);
|
|
1837
|
+
try {
|
|
1838
|
+
const data = await ctx.gql.workspace.request(
|
|
1839
|
+
LIST_PRODUCTIONS,
|
|
1840
|
+
{ pagination: { limit: 50, offset: 0 } }
|
|
1841
|
+
);
|
|
1842
|
+
return {
|
|
1843
|
+
contents: [
|
|
1844
|
+
{
|
|
1845
|
+
uri: productionsUri,
|
|
1846
|
+
text: JSON.stringify(data.hokListProductions, null, 2),
|
|
1847
|
+
mimeType: "application/json"
|
|
1848
|
+
}
|
|
1849
|
+
]
|
|
1850
|
+
};
|
|
1851
|
+
} catch (error) {
|
|
1852
|
+
return {
|
|
1853
|
+
contents: [
|
|
1854
|
+
{
|
|
1855
|
+
uri: productionsUri,
|
|
1856
|
+
text: JSON.stringify({
|
|
1857
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1858
|
+
}),
|
|
1859
|
+
mimeType: "application/json"
|
|
1860
|
+
}
|
|
1861
|
+
]
|
|
1862
|
+
};
|
|
1863
|
+
}
|
|
1864
|
+
}
|
|
1865
|
+
);
|
|
1866
|
+
server.registerResource(
|
|
1867
|
+
"hookmovies-studios",
|
|
1868
|
+
studiosUri,
|
|
1869
|
+
{
|
|
1870
|
+
title: "HookMovies Studio Directory",
|
|
1871
|
+
description: "The first 50 studios in the bound workspace.",
|
|
1872
|
+
mimeType: "application/json"
|
|
1873
|
+
},
|
|
1874
|
+
async () => {
|
|
1875
|
+
ctx.logger.debug(`Resource ${studiosUri} requested`);
|
|
1876
|
+
try {
|
|
1877
|
+
const data = await ctx.gql.workspace.request(LIST_STUDIOS, {
|
|
1878
|
+
pagination: { limit: 50, offset: 0 }
|
|
1879
|
+
});
|
|
1880
|
+
return {
|
|
1881
|
+
contents: [
|
|
1882
|
+
{
|
|
1883
|
+
uri: studiosUri,
|
|
1884
|
+
text: JSON.stringify(data.hokListStudios, null, 2),
|
|
1885
|
+
mimeType: "application/json"
|
|
1886
|
+
}
|
|
1887
|
+
]
|
|
1888
|
+
};
|
|
1889
|
+
} catch (error) {
|
|
1890
|
+
return {
|
|
1891
|
+
contents: [
|
|
1892
|
+
{
|
|
1893
|
+
uri: studiosUri,
|
|
1894
|
+
text: JSON.stringify({
|
|
1895
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1896
|
+
}),
|
|
1897
|
+
mimeType: "application/json"
|
|
1898
|
+
}
|
|
1899
|
+
]
|
|
1900
|
+
};
|
|
1901
|
+
}
|
|
1902
|
+
}
|
|
1903
|
+
);
|
|
1904
|
+
}
|
|
1905
|
+
function registerHookmoviesPrompts(server, ctx, track) {
|
|
1906
|
+
const p = ctx.productName;
|
|
1907
|
+
const releaseName = track(mcpPromptName(p, "title-release"));
|
|
1908
|
+
const castingName = track(mcpPromptName(p, "casting-ops"));
|
|
1909
|
+
server.registerPrompt(
|
|
1910
|
+
releaseName,
|
|
1911
|
+
{
|
|
1912
|
+
title: "Title Release",
|
|
1913
|
+
description: "Guide for cataloguing a HookMovies title end to end: create the studio (if needed) and title, add credits, structure seasons/episodes, declare rights, and publish.",
|
|
1914
|
+
argsSchema: {
|
|
1915
|
+
title: zod.z.string().optional().describe("Title name"),
|
|
1916
|
+
type: zod.z.string().optional().describe("Title type (MOVIE, SERIES, etc.)")
|
|
1917
|
+
}
|
|
1918
|
+
},
|
|
1919
|
+
({ title, type }) => {
|
|
1920
|
+
ctx.logger.debug(`Prompt ${releaseName} called`, { title, type });
|
|
1921
|
+
const titleNote = title ? `Use the title "${title}".` : "Ask the user for the title name.";
|
|
1922
|
+
const typeNote = type ? `Use type ${type}.` : "Help the user pick a TitleType.";
|
|
1923
|
+
return {
|
|
1924
|
+
messages: [
|
|
1925
|
+
{
|
|
1926
|
+
role: "user",
|
|
1927
|
+
content: {
|
|
1928
|
+
type: "text",
|
|
1929
|
+
text: `Help me catalogue and release a HookMovies title.
|
|
1930
|
+
|
|
1931
|
+
1. **Studio (optional)**: If the title needs a new studio, use ${p}_studios_create, else find one with ${p}_studios_list.
|
|
1932
|
+
2. **Create Title**: Use ${p}_titles_create. ${titleNote} ${typeNote} Set genres, synopsis, releaseYear, and (optionally) studioId.
|
|
1933
|
+
3. **Add Credits**: For each cast/crew member, ensure the person exists (${p}_people_create or ${p}_people_list) then credit them with ${p}_credits_add (role, characterName, billingOrder).
|
|
1934
|
+
4. **Structure (SERIES only)**: Use ${p}_seasons_create per season and ${p}_episodes_create per episode (attach a fileId for the master). Verify with ${p}_episodes_list.
|
|
1935
|
+
5. **Rights**: Use ${p}_rights_create to declare monetization modes + territories, then ${p}_rights_transition to ACTIVE.
|
|
1936
|
+
6. **Publish**: Use ${p}_titles_transition to move the title DRAFT \u2192 IN_REVIEW \u2192 PUBLISHED (or SCHEDULED).
|
|
1937
|
+
|
|
1938
|
+
Show results at each step and confirm before publishing.`
|
|
1939
|
+
}
|
|
1940
|
+
}
|
|
1941
|
+
]
|
|
1942
|
+
};
|
|
1943
|
+
}
|
|
1944
|
+
);
|
|
1945
|
+
server.registerPrompt(
|
|
1946
|
+
castingName,
|
|
1947
|
+
{
|
|
1948
|
+
title: "Casting Operations",
|
|
1949
|
+
description: "Workflow for running casting on a production: open auditions, triage applications, score applicants, and close out roles.",
|
|
1950
|
+
argsSchema: {
|
|
1951
|
+
productionId: zod.z.string().optional().describe("Production ID to cast")
|
|
1952
|
+
}
|
|
1953
|
+
},
|
|
1954
|
+
({ productionId }) => {
|
|
1955
|
+
ctx.logger.debug(`Prompt ${castingName} called`, { productionId });
|
|
1956
|
+
const prodNote = productionId ? `Operate production "${productionId}".` : `First list productions with ${p}_productions_list and pick one.`;
|
|
1957
|
+
return {
|
|
1958
|
+
messages: [
|
|
1959
|
+
{
|
|
1960
|
+
role: "user",
|
|
1961
|
+
content: {
|
|
1962
|
+
type: "text",
|
|
1963
|
+
text: `Run HookMovies casting operations. ${prodNote}
|
|
1964
|
+
|
|
1965
|
+
1. **Open Auditions**: Use ${p}_auditions_create for each role (roleName, pay, deadline). Review open ones with ${p}_auditions_list filtered by productionId and status=OPEN.
|
|
1966
|
+
2. **Triage Applications**: For each audition use ${p}_applications_list to review submissions and self-tapes.
|
|
1967
|
+
3. **Score Applicants**: Use ${p}_applications_score to rate promising applicants and shortlist/callback.
|
|
1968
|
+
4. **Close Roles**: When casting is decided, use ${p}_auditions_close to stop further submissions.
|
|
1969
|
+
5. **Advance Production**: Once cast, use ${p}_productions_transition to move the production forward (e.g. GREENLIT \u2192 IN_PRODUCTION).
|
|
1970
|
+
|
|
1971
|
+
Summarize what needs attention after each step.`
|
|
1972
|
+
}
|
|
1973
|
+
}
|
|
1974
|
+
]
|
|
1975
|
+
};
|
|
1976
|
+
}
|
|
1977
|
+
);
|
|
1978
|
+
}
|
|
1979
|
+
|
|
1980
|
+
// src/modules/hookmovies/index.ts
|
|
1981
|
+
var hookmoviesModule = {
|
|
1982
|
+
id: "hookmovies",
|
|
1983
|
+
version: "0.0.1",
|
|
1984
|
+
displayName: "HookMovies",
|
|
1985
|
+
dependsOn: ["auth"],
|
|
1986
|
+
capabilities: { tools: {}, resources: {}, prompts: {} },
|
|
1987
|
+
register(server, ctx) {
|
|
1988
|
+
const tools = [];
|
|
1989
|
+
const resources = [];
|
|
1990
|
+
const prompts = [];
|
|
1991
|
+
const trackTool = (n) => {
|
|
1992
|
+
tools.push(n);
|
|
1993
|
+
return n;
|
|
1994
|
+
};
|
|
1995
|
+
const trackResource = (uri) => {
|
|
1996
|
+
resources.push(uri);
|
|
1997
|
+
return uri;
|
|
1998
|
+
};
|
|
1999
|
+
const trackPrompt = (n) => {
|
|
2000
|
+
prompts.push(n);
|
|
2001
|
+
return n;
|
|
2002
|
+
};
|
|
2003
|
+
registerTitleTools(server, ctx, trackTool);
|
|
2004
|
+
registerStudioTools(server, ctx, trackTool);
|
|
2005
|
+
registerPeopleTools(server, ctx, trackTool);
|
|
2006
|
+
registerEpisodeTools(server, ctx, trackTool);
|
|
2007
|
+
registerProductionTools(server, ctx, trackTool);
|
|
2008
|
+
registerAuditionTools(server, ctx, trackTool);
|
|
2009
|
+
registerReviewTools(server, ctx, trackTool);
|
|
2010
|
+
registerRightsTools(server, ctx, trackTool);
|
|
2011
|
+
registerEntitlementTools(server, ctx, trackTool);
|
|
2012
|
+
registerListTools(server, ctx, trackTool);
|
|
2013
|
+
registerProgressTools(server, ctx, trackTool);
|
|
2014
|
+
registerHealthTools(server, ctx, trackTool);
|
|
2015
|
+
registerHookmoviesResources(server, ctx, trackResource);
|
|
2016
|
+
registerHookmoviesPrompts(server, ctx, trackPrompt);
|
|
2017
|
+
return { tools, resources, prompts };
|
|
2018
|
+
}
|
|
2019
|
+
};
|
|
2020
|
+
var hookmovies_default = hookmoviesModule;
|
|
2021
|
+
|
|
2022
|
+
module.exports = hookmovies_default;
|
|
2023
|
+
//# sourceMappingURL=index.cjs.map
|
|
2024
|
+
//# sourceMappingURL=index.cjs.map
|