node-csfd-api 4.3.4 → 5.0.0-next-2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/README.md +11 -11
  2. package/bin/export-ratings.mjs +62 -58
  3. package/bin/mcp-server.mjs +274 -182
  4. package/bin/server.mjs +239 -281
  5. package/cli.mjs +74 -78
  6. package/dto/creator.d.mts +1 -1
  7. package/dto/creator.d.ts +1 -1
  8. package/dto/global.d.mts +1 -1
  9. package/dto/global.d.ts +1 -1
  10. package/dto/movie.d.mts +22 -1
  11. package/dto/movie.d.ts +22 -1
  12. package/dto/user-reviews.d.mts +1 -1
  13. package/dto/user-reviews.d.ts +1 -1
  14. package/helpers/creator.helper.js +2 -2
  15. package/helpers/creator.helper.js.map +1 -1
  16. package/helpers/creator.helper.mjs +3 -3
  17. package/helpers/creator.helper.mjs.map +1 -1
  18. package/helpers/global.helper.js +52 -0
  19. package/helpers/global.helper.js.map +1 -1
  20. package/helpers/global.helper.mjs +50 -1
  21. package/helpers/global.helper.mjs.map +1 -1
  22. package/helpers/movie.helper.js +87 -3
  23. package/helpers/movie.helper.js.map +1 -1
  24. package/helpers/movie.helper.mjs +84 -5
  25. package/helpers/movie.helper.mjs.map +1 -1
  26. package/helpers/search.helper.js +2 -1
  27. package/helpers/search.helper.js.map +1 -1
  28. package/helpers/search.helper.mjs +3 -2
  29. package/helpers/search.helper.mjs.map +1 -1
  30. package/helpers/user-ratings.helper.js +1 -1
  31. package/helpers/user-ratings.helper.js.map +1 -1
  32. package/helpers/user-ratings.helper.mjs +2 -2
  33. package/helpers/user-ratings.helper.mjs.map +1 -1
  34. package/helpers/user-reviews.helper.js +2 -2
  35. package/helpers/user-reviews.helper.js.map +1 -1
  36. package/helpers/user-reviews.helper.mjs +3 -3
  37. package/helpers/user-reviews.helper.mjs.map +1 -1
  38. package/index.d.mts +2 -2
  39. package/index.d.ts +2 -2
  40. package/package.json +2 -4
  41. package/package.mjs +8 -0
  42. package/services/movie.service.js +15 -3
  43. package/services/movie.service.js.map +1 -1
  44. package/services/movie.service.mjs +16 -4
  45. package/services/movie.service.mjs.map +1 -1
package/README.md CHANGED
@@ -223,7 +223,7 @@ console.log(results.users); // Array of users
223
223
  title: 'Black Bart',
224
224
  year: '1975',
225
225
  url: 'https://www.csfd.cz/film/19653-black-bart/',
226
- type: 'TV film',
226
+ type: 'tv-film',
227
227
  colorRating: 'bad',
228
228
  poster: 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7',
229
229
  origins: ['USA'],
@@ -247,7 +247,7 @@ tvSeries: [
247
247
  title: 'Království',
248
248
  year: 1994,
249
249
  url: 'https://www.csfd.cz/film/71924-kralovstvi/',
250
- type: 'seriál',
250
+ type: 'series',
251
251
  colorRating: 'good',
252
252
  poster: 'https://image.pmgstatic.com/cache/resized/w60h85/files/images/film/posters/166/708/166708064_2da697.jpg',
253
253
  origins: ['Dánsko'],
@@ -398,7 +398,7 @@ const onlyMovies = await csfd.userRatings('912-bart', {
398
398
  });
399
399
 
400
400
  const excludeEpisodes = await csfd.userRatings('912-bart', {
401
- exclude: ['epizoda', 'série']
401
+ exclude: ['episode', 'season']
402
402
  });
403
403
  ```
404
404
 
@@ -434,13 +434,13 @@ const excludeEpisodes = await csfd.userRatings('912-bart', {
434
434
 
435
435
  #### UserRatingsOptions
436
436
 
437
- | Option | Type | Default | Description |
438
- | --------------- | ----------------- | ------- | ---------------------------------------------------------------- |
439
- | `includesOnly` | `CSFDFilmTypes[]` | `null` | Include only specific content types (e.g., `['film', 'seriál']`) |
440
- | `exclude` | `CSFDFilmTypes[]` | `null` | Exclude specific content types (e.g., `['epizoda']`) |
441
- | `allPages` | `boolean` | `false` | Fetch all pages of ratings |
442
- | `allPagesDelay` | `number` | `0` | Delay between page requests in milliseconds |
443
- | `page` | `number` | `1` | Fetch specific page number |
437
+ | Option | Type | Default | Description |
438
+ | --------------- | ----------------- | ------- | -------------------------------------------------------------------- |
439
+ | `includesOnly` | `CSFDFilmTypes[]` | `null` | Include only specific content types (e.g., `['film', 'series']`) |
440
+ | `exclude` | `CSFDFilmTypes[]` | `null` | Exclude specific content types (e.g., `['episode']`) |
441
+ | `allPages` | `boolean` | `false` | Fetch all pages of ratings |
442
+ | `allPagesDelay` | `number` | `0` | Delay between page requests in milliseconds |
443
+ | `page` | `number` | `1` | Fetch specific page number |
444
444
 
445
445
  > 📝 **Note**: `includesOnly` and `exclude` are mutually exclusive. If both are provided, `includesOnly` takes precedence.
446
446
  >
@@ -476,7 +476,7 @@ const allReviews = await csfd.userReviews(195357, {
476
476
  // Filter by content type
477
477
  const filtered = await csfd.userReviews(195357, {
478
478
  includesOnly: ['film'],
479
- exclude: ['epizoda']
479
+ exclude: ['episode']
480
480
  });
481
481
  ```
482
482
 
@@ -1,61 +1,65 @@
1
+ #!/usr/bin/env node
2
+ import { csfd } from "../index.mjs";
1
3
  import { writeFile } from "node:fs/promises";
2
- import { csfd } from "./../index.mjs";
4
+
5
+ //#region src/tools/export-ratings.ts
6
+ /**
7
+ * Runs the ratings export process for a given user.
8
+ * @param userId - The CSFD user ID.
9
+ * @param options - Export options (format, filters, language).
10
+ */
3
11
  async function runRatingsExport(userId, options) {
4
- try {
5
- if (options.format === "letterboxd") {
6
- csfd.setOptions({ language: "en" });
7
- }
8
- console.log(`Fetching ratings for user ${userId} (${options.format.toUpperCase()})...`);
9
- const ratings = await csfd.userRatings(userId, options.userRatingsOptions);
10
- console.log(`Fetched ${ratings.length} ratings.`);
11
- let content = "";
12
- let fileName = "";
13
- const escapeCsvField = (value) => {
14
- const needsQuotes = /[",\n\r]/.test(value);
15
- const escaped = value.replaceAll('"', '""');
16
- return needsQuotes ? `"${escaped}"` : escaped;
17
- };
18
- if (options.format === "letterboxd") {
19
- content = [
20
- "Title,Year,Rating,WatchedDate",
21
- ...ratings.map((r) => {
22
- const title = escapeCsvField(r.title ?? "");
23
- const year = r.year ?? "";
24
- const rating = r.userRating ?? "";
25
- const watchedDate = escapeCsvField(r.userDate ?? "");
26
- return `${title},${year},${rating},${watchedDate}`;
27
- })
28
- ].join("\n");
29
- fileName = `${userId}-for-letterboxd.csv`;
30
- } else if (options.format === "json") {
31
- content = JSON.stringify(ratings, null, 2);
32
- fileName = `${userId}-ratings.json`;
33
- } else {
34
- const headers = ["id", "title", "year", "rating", "date", "type", "url", "colorRating"];
35
- content = [
36
- headers.join(","),
37
- ...ratings.map((r) => {
38
- return [
39
- r.id,
40
- escapeCsvField(r.title ?? ""),
41
- r.year ?? "",
42
- r.userRating ?? "",
43
- escapeCsvField(r.userDate ?? ""),
44
- escapeCsvField(r.type ?? ""),
45
- escapeCsvField(r.url ?? ""),
46
- escapeCsvField(r.colorRating ?? "")
47
- ].join(",");
48
- })
49
- ].join("\n");
50
- fileName = `${userId}-ratings.csv`;
51
- }
52
- await writeFile(fileName, content);
53
- console.log("Saved in file:", `./${fileName}`);
54
- } catch (error) {
55
- console.error("Error exporting ratings:", error);
56
- throw error;
57
- }
12
+ try {
13
+ if (options.format === "letterboxd") csfd.setOptions({ language: "en" });
14
+ console.log(`Fetching ratings for user ${userId} (${options.format.toUpperCase()})...`);
15
+ const ratings = await csfd.userRatings(userId, options.userRatingsOptions);
16
+ console.log(`Fetched ${ratings.length} ratings.`);
17
+ let content = "";
18
+ let fileName = "";
19
+ const escapeCsvField = (value) => {
20
+ const needsQuotes = /[",\n\r]/.test(value);
21
+ const escaped = value.replaceAll("\"", "\"\"");
22
+ return needsQuotes ? `"${escaped}"` : escaped;
23
+ };
24
+ if (options.format === "letterboxd") {
25
+ content = ["Title,Year,Rating,WatchedDate", ...ratings.map((r) => {
26
+ return `${escapeCsvField(r.title ?? "")},${r.year ?? ""},${r.userRating ?? ""},${escapeCsvField(r.userDate ?? "")}`;
27
+ })].join("\n");
28
+ fileName = `${userId}-for-letterboxd.csv`;
29
+ } else if (options.format === "json") {
30
+ content = JSON.stringify(ratings, null, 2);
31
+ fileName = `${userId}-ratings.json`;
32
+ } else {
33
+ content = [[
34
+ "id",
35
+ "title",
36
+ "year",
37
+ "rating",
38
+ "date",
39
+ "type",
40
+ "url",
41
+ "colorRating"
42
+ ].join(","), ...ratings.map((r) => {
43
+ return [
44
+ r.id,
45
+ escapeCsvField(r.title ?? ""),
46
+ r.year ?? "",
47
+ r.userRating ?? "",
48
+ escapeCsvField(r.userDate ?? ""),
49
+ escapeCsvField(r.type ?? ""),
50
+ escapeCsvField(r.url ?? ""),
51
+ escapeCsvField(r.colorRating ?? "")
52
+ ].join(",");
53
+ })].join("\n");
54
+ fileName = `${userId}-ratings.csv`;
55
+ }
56
+ await writeFile(fileName, content);
57
+ console.log("Saved in file:", `./${fileName}`);
58
+ } catch (error) {
59
+ console.error("Error exporting ratings:", error);
60
+ throw error;
61
+ }
58
62
  }
59
- export {
60
- runRatingsExport
61
- };
63
+
64
+ //#endregion
65
+ export { runRatingsExport };
@@ -1,192 +1,284 @@
1
1
  #!/usr/bin/env node
2
+ import { csfd } from "../index.mjs";
3
+ import { name, version } from "../package.mjs";
2
4
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
5
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
6
  import { z } from "zod";
5
- import packageJson from "./../package.json" with { type: "json" };
6
- import { csfd } from "./../index.mjs";
7
+
8
+ //#region src/mcp-server/index.ts
7
9
  const server = new McpServer({
8
- name: packageJson.name,
9
- version: packageJson.version
10
+ name,
11
+ version
12
+ });
13
+ /**
14
+ * TOOL 1: Search
15
+ * Description: Essential first step to get IDs for movies or creators.
16
+ */
17
+ server.registerTool("search", {
18
+ title: "Search",
19
+ description: "Searches for a movie, TV series, or person on CSFD.cz. Returns a list of results with IDs. Use this tool FIRST to find the ID needed for other tools.",
20
+ inputSchema: { query: z.string().describe("Search query (movie title, series, or actor, director, etc. name)") },
21
+ annotations: {
22
+ readOnlyHint: true,
23
+ idempotentHint: true,
24
+ openWorldHint: false
25
+ }
26
+ }, async ({ query }) => {
27
+ try {
28
+ const results = await csfd.search(query);
29
+ return {
30
+ structuredContent: results,
31
+ content: [{
32
+ type: "text",
33
+ text: `Found ${results.movies.length} movies, ${results.tvSeries.length} TV series, and ${results.users.length} users.`
34
+ }]
35
+ };
36
+ } catch (error) {
37
+ return {
38
+ content: [{
39
+ type: "text",
40
+ text: `Error during search: ${error}`
41
+ }],
42
+ isError: true
43
+ };
44
+ }
45
+ });
46
+ /**
47
+ * TOOL 2: Movie Details
48
+ * Description: Returns detailed info about a specific movie/series.
49
+ */
50
+ server.registerTool("get_movie", {
51
+ title: "Get Movie",
52
+ description: "Retrieves detailed information about a specific movie or series, including rating, plot, genres, and actors. Requires a numeric CSFD ID.",
53
+ inputSchema: { id: z.number().describe("CSFD Movie ID (found using the 'search' tool)") },
54
+ annotations: {
55
+ readOnlyHint: true,
56
+ idempotentHint: true,
57
+ openWorldHint: false
58
+ }
59
+ }, async ({ id }) => {
60
+ try {
61
+ const movie = await csfd.movie(id);
62
+ return {
63
+ structuredContent: movie,
64
+ content: [{
65
+ type: "text",
66
+ text: `Movie ${movie.title} (${movie.year}) with rating ${movie.rating} retrieved successfully.`
67
+ }]
68
+ };
69
+ } catch (error) {
70
+ return {
71
+ content: [{
72
+ type: "text",
73
+ text: `Error retrieving movie details: ${error}`
74
+ }],
75
+ isError: true
76
+ };
77
+ }
78
+ });
79
+ /**
80
+ * TOOL 3: Creator Details
81
+ * Description: Returns detailed info about a person (actor, director).
82
+ */
83
+ server.registerTool("get_creator", {
84
+ title: "Get Creator",
85
+ description: "Retrieves information about a specific creator (actor, director, etc.), including their biography and filmography. Requires a numeric CSFD ID.",
86
+ inputSchema: { id: z.number().describe("CSFD Creator ID") },
87
+ annotations: {
88
+ readOnlyHint: true,
89
+ idempotentHint: true,
90
+ openWorldHint: false
91
+ }
92
+ }, async ({ id }) => {
93
+ try {
94
+ const creator = await csfd.creator(id);
95
+ return {
96
+ structuredContent: creator,
97
+ content: [{
98
+ type: "text",
99
+ text: `Creator ${creator.name} retrieved successfully.`
100
+ }]
101
+ };
102
+ } catch (error) {
103
+ return {
104
+ content: [{
105
+ type: "text",
106
+ text: `Error retrieving creator details: ${error}`
107
+ }],
108
+ isError: true
109
+ };
110
+ }
111
+ });
112
+ /**
113
+ * TOOL 4: User Ratings
114
+ * Description: Returns ratings from a specific CSFD user.
115
+ */
116
+ server.registerTool("get_user_ratings", {
117
+ title: "Get User Ratings",
118
+ description: "Retrieves movie ratings from a specific CSFD user. Returns a list of movies with their user rating (0-5 stars). Supports pagination and filtering by film type.",
119
+ inputSchema: {
120
+ user: z.union([z.string(), z.number()]).describe("CSFD User ID (numeric) or username"),
121
+ page: z.number().optional().describe("Page number to fetch (default: 1)"),
122
+ allPages: z.boolean().optional().describe("Fetch all pages at once (use wisely, may be slow)"),
123
+ allPagesDelay: z.number().optional().describe("Delay in ms between page requests when using allPages"),
124
+ excludes: z.array(z.string()).optional().describe("Film types to exclude (e.g. \"series\", \"tv-film\")"),
125
+ includesOnly: z.array(z.string()).optional().describe("Only include these film types (e.g. \"film\")")
126
+ },
127
+ annotations: {
128
+ readOnlyHint: true,
129
+ idempotentHint: true,
130
+ openWorldHint: false
131
+ }
132
+ }, async ({ user, page, allPages, allPagesDelay, excludes, includesOnly }) => {
133
+ try {
134
+ const results = await csfd.userRatings(user, {
135
+ page,
136
+ allPages,
137
+ allPagesDelay,
138
+ excludes,
139
+ includesOnly
140
+ });
141
+ return {
142
+ structuredContent: { results },
143
+ content: [{
144
+ type: "text",
145
+ text: `Retrieved ${results.length} user ratings successfully.`
146
+ }]
147
+ };
148
+ } catch (error) {
149
+ return {
150
+ content: [{
151
+ type: "text",
152
+ text: `Error retrieving user ratings: ${error}`
153
+ }],
154
+ isError: true
155
+ };
156
+ }
157
+ });
158
+ /**
159
+ * TOOL 5: User Reviews
160
+ * Description: Returns reviews written by a specific CSFD user.
161
+ */
162
+ server.registerTool("get_user_reviews", {
163
+ title: "Get User Reviews",
164
+ description: "Retrieves movie reviews written by a specific CSFD user. Returns a list of movies with their review text and rating.",
165
+ inputSchema: {
166
+ user: z.union([z.string(), z.number()]).describe("CSFD User ID (numeric) or username"),
167
+ page: z.number().optional().describe("Page number to fetch (default: 1)"),
168
+ allPages: z.boolean().optional().describe("Fetch all pages at once (use wisely, may be slow)"),
169
+ allPagesDelay: z.number().optional().describe("Delay in ms between page requests when using allPages"),
170
+ excludes: z.array(z.string()).optional().describe("Film types to exclude (e.g. \"series\", \"tv-film\")"),
171
+ includesOnly: z.array(z.string()).optional().describe("Only include these film types (e.g. \"film\")")
172
+ },
173
+ annotations: {
174
+ readOnlyHint: true,
175
+ idempotentHint: true,
176
+ openWorldHint: false
177
+ }
178
+ }, async ({ user, page, allPages, allPagesDelay, excludes, includesOnly }) => {
179
+ try {
180
+ const results = await csfd.userReviews(user, {
181
+ page,
182
+ allPages,
183
+ allPagesDelay,
184
+ excludes,
185
+ includesOnly
186
+ });
187
+ return {
188
+ structuredContent: { results },
189
+ content: [{
190
+ type: "text",
191
+ text: `Retrieved ${results.length} user reviews successfully.`
192
+ }]
193
+ };
194
+ } catch (error) {
195
+ return {
196
+ content: [{
197
+ type: "text",
198
+ text: `Error retrieving user reviews: ${error}`
199
+ }],
200
+ isError: true
201
+ };
202
+ }
203
+ });
204
+ /**
205
+ * TOOL 6: Cinemas
206
+ * Description: Returns cinema screenings for a given district and time period.
207
+ */
208
+ server.registerTool("get_cinemas", {
209
+ title: "Get Cinemas",
210
+ description: "Retrieves cinema screenings for a given district in Czech Republic. Returns a list of cinemas with their current screenings, showtimes, and movie names and ids.",
211
+ inputSchema: {
212
+ district: z.union([z.number(), z.string()]).describe("District ID (numeric) or name"),
213
+ period: z.enum([
214
+ "today",
215
+ "tomorrow",
216
+ "weekend",
217
+ "week",
218
+ "month"
219
+ ]).describe("Time period for screenings")
220
+ },
221
+ annotations: {
222
+ readOnlyHint: true,
223
+ idempotentHint: true,
224
+ openWorldHint: false
225
+ }
226
+ }, async ({ district, period }) => {
227
+ try {
228
+ const results = await csfd.cinema(district, period);
229
+ return {
230
+ structuredContent: { results },
231
+ content: [{
232
+ type: "text",
233
+ text: `Retrieved ${results.length} cinema screenings successfully.`
234
+ }]
235
+ };
236
+ } catch (error) {
237
+ return {
238
+ content: [{
239
+ type: "text",
240
+ text: `Error retrieving cinema data: ${error}`
241
+ }],
242
+ isError: true
243
+ };
244
+ }
245
+ });
246
+ /**
247
+ * PROMPT: Actor's Top Rated Works
248
+ * Example: "Find movies starring Mads Mikkelsen and give me the top 5 sorted by rating."
249
+ */
250
+ server.registerPrompt("actor-top-rated", {
251
+ title: "Actor Top Rated",
252
+ description: "Finds and ranks the best movies of a specific actor or creator.",
253
+ argsSchema: { actorName: z.string().describe("Name of the actor or director") }
254
+ }, async ({ actorName }) => {
255
+ return { messages: [{
256
+ role: "user",
257
+ content: {
258
+ type: "text",
259
+ text: `First, search for the person "${actorName}" to get their ID. Then, retrieve their full profile to see their filmography. From the results, identify the top 5 highest-rated movies they acted in. Finally, provide a bulleted list with the movie titles, years, and their CSFD ratings.`
260
+ }
261
+ }] };
10
262
  });
11
- server.tool(
12
- "search",
13
- "Searches for a movie, TV series, or person on CSFD.cz. Returns a list of results with IDs. Use this tool FIRST to find the ID needed for other tools.",
14
- {
15
- query: z.string().describe("Search query (movie title, series, or actor name)")
16
- },
17
- async ({ query }) => {
18
- try {
19
- const results = await csfd.search(query);
20
- return {
21
- content: [
22
- {
23
- type: "text",
24
- text: JSON.stringify(results, null, 2)
25
- }
26
- ]
27
- };
28
- } catch (error) {
29
- return {
30
- content: [{ type: "text", text: `Error during search: ${error}` }],
31
- isError: true
32
- };
33
- }
34
- }
35
- );
36
- server.tool(
37
- "get_movie",
38
- "Retrieves detailed information about a specific movie or series, including rating, plot, genres, and actors. Requires a numeric CSFD ID.",
39
- {
40
- id: z.number().describe("CSFD Movie ID (found using the 'search' tool)")
41
- },
42
- async ({ id }) => {
43
- try {
44
- const movie = await csfd.movie(id);
45
- return {
46
- content: [
47
- {
48
- type: "text",
49
- text: JSON.stringify(movie, null, 2)
50
- }
51
- ]
52
- };
53
- } catch (error) {
54
- return {
55
- content: [{ type: "text", text: `Error retrieving movie details: ${error}` }],
56
- isError: true
57
- };
58
- }
59
- }
60
- );
61
- server.tool(
62
- "get_creator",
63
- "Retrieves information about a specific creator (actor, director, etc.), including their biography and filmography. Requires a numeric CSFD ID.",
64
- {
65
- id: z.number().describe("CSFD Creator ID (found using the 'search' tool)")
66
- },
67
- async ({ id }) => {
68
- try {
69
- const creator = await csfd.creator(id);
70
- return {
71
- content: [
72
- {
73
- type: "text",
74
- text: JSON.stringify(creator, null, 2)
75
- }
76
- ]
77
- };
78
- } catch (error) {
79
- return {
80
- content: [{ type: "text", text: `Error retrieving creator details: ${error}` }],
81
- isError: true
82
- };
83
- }
84
- }
85
- );
86
- server.tool(
87
- "get_user_ratings",
88
- "Retrieves movie ratings from a specific CSFD user. Returns a list of movies with their user rating (0-5 stars). Supports pagination and filtering by film type.",
89
- {
90
- user: z.union([z.string(), z.number()]).describe("CSFD User ID (numeric) or username"),
91
- page: z.number().optional().describe("Page number to fetch (default: 1)"),
92
- allPages: z.boolean().optional().describe("Fetch all pages at once (use wisely, may be slow)"),
93
- allPagesDelay: z.number().optional().describe("Delay in ms between page requests when using allPages"),
94
- excludes: z.array(z.string()).optional().describe('Film types to exclude (e.g. "seri\xE1l", "TV film")'),
95
- includesOnly: z.array(z.string()).optional().describe('Only include these film types (e.g. "film")')
96
- },
97
- async ({ user, page, allPages, allPagesDelay, excludes, includesOnly }) => {
98
- try {
99
- const results = await csfd.userRatings(user, {
100
- page,
101
- allPages,
102
- allPagesDelay,
103
- excludes,
104
- includesOnly
105
- });
106
- return {
107
- content: [
108
- {
109
- type: "text",
110
- text: JSON.stringify(results, null, 2)
111
- }
112
- ]
113
- };
114
- } catch (error) {
115
- return {
116
- content: [{ type: "text", text: `Error retrieving user ratings: ${error}` }],
117
- isError: true
118
- };
119
- }
120
- }
121
- );
122
- server.tool(
123
- "get_user_reviews",
124
- "Retrieves movie reviews written by a specific CSFD user. Returns a list of movies with their review text and rating. Supports pagination and filtering by film type.",
125
- {
126
- user: z.union([z.string(), z.number()]).describe("CSFD User ID (numeric) or username"),
127
- page: z.number().optional().describe("Page number to fetch (default: 1)"),
128
- allPages: z.boolean().optional().describe("Fetch all pages at once (use wisely, may be slow)"),
129
- allPagesDelay: z.number().optional().describe("Delay in ms between page requests when using allPages"),
130
- excludes: z.array(z.string()).optional().describe('Film types to exclude (e.g. "seri\xE1l", "TV film")'),
131
- includesOnly: z.array(z.string()).optional().describe('Only include these film types (e.g. "film")')
132
- },
133
- async ({ user, page, allPages, allPagesDelay, excludes, includesOnly }) => {
134
- try {
135
- const results = await csfd.userReviews(user, {
136
- page,
137
- allPages,
138
- allPagesDelay,
139
- excludes,
140
- includesOnly
141
- });
142
- return {
143
- content: [
144
- {
145
- type: "text",
146
- text: JSON.stringify(results, null, 2)
147
- }
148
- ]
149
- };
150
- } catch (error) {
151
- return {
152
- content: [{ type: "text", text: `Error retrieving user reviews: ${error}` }],
153
- isError: true
154
- };
155
- }
156
- }
157
- );
158
- server.tool(
159
- "get_cinemas",
160
- "Retrieves cinema screenings for a given district in Czech Republic. Returns a list of cinemas with their current screenings, showtimes, and movie details.",
161
- {
162
- district: z.union([z.number(), z.string()]).describe("District ID (numeric) or name"),
163
- period: z.enum(["today", "tomorrow", "weekend", "week", "month"]).describe("Time period for screenings")
164
- },
165
- async ({ district, period }) => {
166
- try {
167
- const results = await csfd.cinema(district, period);
168
- return {
169
- content: [
170
- {
171
- type: "text",
172
- text: JSON.stringify(results, null, 2)
173
- }
174
- ]
175
- };
176
- } catch (error) {
177
- return {
178
- content: [{ type: "text", text: `Error retrieving cinema data: ${error}` }],
179
- isError: true
180
- };
181
- }
182
- }
183
- );
184
263
  async function main() {
185
- const transport = new StdioServerTransport();
186
- await server.connect(transport);
187
- console.error("CSFD MCP Server running on stdio...");
264
+ const transport = new StdioServerTransport();
265
+ await server.connect(transport);
266
+ console.error(`--- CSFD MCP Server (v${version}) ---`);
267
+ console.error("Status: Running via Stdio");
268
+ console.error("\nTo use this server in Claude Desktop, add this to your config:");
269
+ console.error(JSON.stringify({ "node-csfd-api": {
270
+ command: "npx",
271
+ args: [
272
+ "-y",
273
+ "node-csfd-api",
274
+ "mcp"
275
+ ]
276
+ } }, null, 2));
188
277
  }
189
278
  main().catch((error) => {
190
- console.error("Fatal error in MCP server:", error);
191
- process.exit(1);
279
+ console.error("Fatal error in MCP server:", error);
280
+ process.exit(1);
192
281
  });
282
+
283
+ //#endregion
284
+ export { };