@cyanheads/openlibrary-mcp-server 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/CLAUDE.md +391 -0
  2. package/Dockerfile +98 -0
  3. package/LICENSE +201 -0
  4. package/README.md +316 -0
  5. package/changelog/0.1.x/0.1.0.md +22 -0
  6. package/changelog/0.1.x/0.1.1.md +25 -0
  7. package/changelog/template.md +119 -0
  8. package/dist/config/server-config.d.ts +11 -0
  9. package/dist/config/server-config.d.ts.map +1 -0
  10. package/dist/config/server-config.js +20 -0
  11. package/dist/config/server-config.js.map +1 -0
  12. package/dist/index.d.ts +7 -0
  13. package/dist/index.d.ts.map +1 -0
  14. package/dist/index.js +38 -0
  15. package/dist/index.js.map +1 -0
  16. package/dist/mcp-server/resources/definitions/openlibrary-author.resource.d.ts +25 -0
  17. package/dist/mcp-server/resources/definitions/openlibrary-author.resource.d.ts.map +1 -0
  18. package/dist/mcp-server/resources/definitions/openlibrary-author.resource.js +48 -0
  19. package/dist/mcp-server/resources/definitions/openlibrary-author.resource.js.map +1 -0
  20. package/dist/mcp-server/resources/definitions/openlibrary-work.resource.d.ts +21 -0
  21. package/dist/mcp-server/resources/definitions/openlibrary-work.resource.d.ts.map +1 -0
  22. package/dist/mcp-server/resources/definitions/openlibrary-work.resource.js +42 -0
  23. package/dist/mcp-server/resources/definitions/openlibrary-work.resource.js.map +1 -0
  24. package/dist/mcp-server/tools/definitions/openlibrary-get-author-works.tool.d.ts +26 -0
  25. package/dist/mcp-server/tools/definitions/openlibrary-get-author-works.tool.d.ts.map +1 -0
  26. package/dist/mcp-server/tools/definitions/openlibrary-get-author-works.tool.js +68 -0
  27. package/dist/mcp-server/tools/definitions/openlibrary-get-author-works.tool.js.map +1 -0
  28. package/dist/mcp-server/tools/definitions/openlibrary-get-author.tool.d.ts +31 -0
  29. package/dist/mcp-server/tools/definitions/openlibrary-get-author.tool.d.ts.map +1 -0
  30. package/dist/mcp-server/tools/definitions/openlibrary-get-author.tool.js +86 -0
  31. package/dist/mcp-server/tools/definitions/openlibrary-get-author.tool.js.map +1 -0
  32. package/dist/mcp-server/tools/definitions/openlibrary-get-cover-url.tool.d.ts +26 -0
  33. package/dist/mcp-server/tools/definitions/openlibrary-get-cover-url.tool.d.ts.map +1 -0
  34. package/dist/mcp-server/tools/definitions/openlibrary-get-cover-url.tool.js +56 -0
  35. package/dist/mcp-server/tools/definitions/openlibrary-get-cover-url.tool.js.map +1 -0
  36. package/dist/mcp-server/tools/definitions/openlibrary-get-edition.tool.d.ts +45 -0
  37. package/dist/mcp-server/tools/definitions/openlibrary-get-edition.tool.d.ts.map +1 -0
  38. package/dist/mcp-server/tools/definitions/openlibrary-get-edition.tool.js +132 -0
  39. package/dist/mcp-server/tools/definitions/openlibrary-get-edition.tool.js.map +1 -0
  40. package/dist/mcp-server/tools/definitions/openlibrary-get-editions.tool.d.ts +32 -0
  41. package/dist/mcp-server/tools/definitions/openlibrary-get-editions.tool.d.ts.map +1 -0
  42. package/dist/mcp-server/tools/definitions/openlibrary-get-editions.tool.js +106 -0
  43. package/dist/mcp-server/tools/definitions/openlibrary-get-editions.tool.js.map +1 -0
  44. package/dist/mcp-server/tools/definitions/openlibrary-get-subject.tool.d.ts +29 -0
  45. package/dist/mcp-server/tools/definitions/openlibrary-get-subject.tool.d.ts.map +1 -0
  46. package/dist/mcp-server/tools/definitions/openlibrary-get-subject.tool.js +82 -0
  47. package/dist/mcp-server/tools/definitions/openlibrary-get-subject.tool.js.map +1 -0
  48. package/dist/mcp-server/tools/definitions/openlibrary-get-work.tool.d.ts +27 -0
  49. package/dist/mcp-server/tools/definitions/openlibrary-get-work.tool.d.ts.map +1 -0
  50. package/dist/mcp-server/tools/definitions/openlibrary-get-work.tool.js +90 -0
  51. package/dist/mcp-server/tools/definitions/openlibrary-get-work.tool.js.map +1 -0
  52. package/dist/mcp-server/tools/definitions/openlibrary-search-authors.tool.d.ts +31 -0
  53. package/dist/mcp-server/tools/definitions/openlibrary-search-authors.tool.d.ts.map +1 -0
  54. package/dist/mcp-server/tools/definitions/openlibrary-search-authors.tool.js +105 -0
  55. package/dist/mcp-server/tools/definitions/openlibrary-search-authors.tool.js.map +1 -0
  56. package/dist/mcp-server/tools/definitions/openlibrary-search-books.tool.d.ts +65 -0
  57. package/dist/mcp-server/tools/definitions/openlibrary-search-books.tool.d.ts.map +1 -0
  58. package/dist/mcp-server/tools/definitions/openlibrary-search-books.tool.js +217 -0
  59. package/dist/mcp-server/tools/definitions/openlibrary-search-books.tool.js.map +1 -0
  60. package/dist/services/open-library/open-library-service.d.ts +57 -0
  61. package/dist/services/open-library/open-library-service.d.ts.map +1 -0
  62. package/dist/services/open-library/open-library-service.js +347 -0
  63. package/dist/services/open-library/open-library-service.js.map +1 -0
  64. package/dist/services/open-library/types.d.ts +129 -0
  65. package/dist/services/open-library/types.d.ts.map +1 -0
  66. package/dist/services/open-library/types.js +6 -0
  67. package/dist/services/open-library/types.js.map +1 -0
  68. package/package.json +79 -0
  69. package/server.json +99 -0
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @fileoverview Resolve cover image URLs from Open Library's Covers API.
3
+ * @module mcp-server/tools/definitions/openlibrary-get-cover-url.tool
4
+ */
5
+ import { z } from '@cyanheads/mcp-ts-core';
6
+ export declare const openlibraryGetCoverUrl: import("@cyanheads/mcp-ts-core").ToolDefinition<z.ZodObject<{
7
+ identifier: z.ZodString;
8
+ id_type: z.ZodEnum<{
9
+ isbn: "isbn";
10
+ olid: "olid";
11
+ id: "id";
12
+ }>;
13
+ target: z.ZodDefault<z.ZodEnum<{
14
+ author: "author";
15
+ book: "book";
16
+ }>>;
17
+ size: z.ZodDefault<z.ZodEnum<{
18
+ S: "S";
19
+ M: "M";
20
+ L: "L";
21
+ }>>;
22
+ }, z.core.$strip>, z.ZodObject<{
23
+ url: z.ZodString;
24
+ note: z.ZodString;
25
+ }, z.core.$strip>, undefined>;
26
+ //# sourceMappingURL=openlibrary-get-cover-url.tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openlibrary-get-cover-url.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/openlibrary-get-cover-url.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAGjD,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;6BA+DjC,CAAC"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * @fileoverview Resolve cover image URLs from Open Library's Covers API.
3
+ * @module mcp-server/tools/definitions/openlibrary-get-cover-url.tool
4
+ */
5
+ import { tool, z } from '@cyanheads/mcp-ts-core';
6
+ import { getOpenLibraryService } from '../../../services/open-library/open-library-service.js';
7
+ export const openlibraryGetCoverUrl = tool('openlibrary_get_cover_url', {
8
+ title: 'Get Cover URL',
9
+ description: 'Resolve a cover image URL for a book or author photo. Returns a direct HTTPS URL in the requested size (S/M/L). The Covers API always returns HTTP 200 — missing covers return a 1×1 placeholder GIF, not a 404. URLs can be embedded in markdown as ![cover](url).',
10
+ annotations: { readOnlyHint: true, idempotentHint: true },
11
+ input: z.object({
12
+ identifier: z
13
+ .string()
14
+ .describe('The identifier value. For "id": numeric cover ID from work/edition data. For "isbn": 10 or 13 digits, hyphens stripped. For "olid": edition OLID (OL…M) or author OLID (OL…A) when target is "author".'),
15
+ id_type: z
16
+ .enum(['id', 'isbn', 'olid'])
17
+ .describe('"id" is the numeric cover_i / cover ID from search or work results. "isbn" and "olid" look up the cover from those identifiers.'),
18
+ target: z
19
+ .enum(['book', 'author'])
20
+ .default('book')
21
+ .describe('"book" returns a book cover from covers.openlibrary.org/b/. "author" returns an author photo from covers.openlibrary.org/a/ — use with id_type "id" (photo_id) or "olid" (author OLID).'),
22
+ size: z
23
+ .enum(['S', 'M', 'L'])
24
+ .default('M')
25
+ .describe('Image size. S = small (~45px tall), M = medium (~150px tall), L = large (~400px tall).'),
26
+ }),
27
+ output: z.object({
28
+ url: z
29
+ .string()
30
+ .describe('Direct HTTPS URL to the cover image. The Covers API returns HTTP 200 for all requests — a 1×1 placeholder GIF is returned when no cover exists for the identifier.'),
31
+ note: z
32
+ .string()
33
+ .describe('Reminder that the URL always returns HTTP 200; a placeholder GIF is served when no cover exists.'),
34
+ }),
35
+ handler(input, ctx) {
36
+ ctx.log.info('Resolving cover URL', {
37
+ identifier: input.identifier,
38
+ id_type: input.id_type,
39
+ target: input.target,
40
+ size: input.size,
41
+ });
42
+ const svc = getOpenLibraryService();
43
+ const url = svc.getCoverUrl(input.identifier, input.id_type, input.target, input.size);
44
+ return {
45
+ url,
46
+ note: 'The Covers API returns HTTP 200 for all requests — a 1×1 placeholder GIF is served if no cover exists for this identifier.',
47
+ };
48
+ },
49
+ format: (result) => {
50
+ const lines = [];
51
+ lines.push(`**Cover URL:** ${result.url}`);
52
+ lines.push(`**Note:** ${result.note}`);
53
+ return [{ type: 'text', text: lines.join('\n') }];
54
+ },
55
+ });
56
+ //# sourceMappingURL=openlibrary-get-cover-url.tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openlibrary-get-cover-url.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/openlibrary-get-cover-url.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,qBAAqB,EAAE,MAAM,iDAAiD,CAAC;AAExF,MAAM,CAAC,MAAM,sBAAsB,GAAG,IAAI,CAAC,2BAA2B,EAAE;IACtE,KAAK,EAAE,eAAe;IACtB,WAAW,EACT,qQAAqQ;IACvQ,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE;IACzD,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC;QACd,UAAU,EAAE,CAAC;aACV,MAAM,EAAE;aACR,QAAQ,CACP,wMAAwM,CACzM;QACH,OAAO,EAAE,CAAC;aACP,IAAI,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;aAC5B,QAAQ,CACP,iIAAiI,CAClI;QACH,MAAM,EAAE,CAAC;aACN,IAAI,CAAC,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;aACxB,OAAO,CAAC,MAAM,CAAC;aACf,QAAQ,CACP,yLAAyL,CAC1L;QACH,IAAI,EAAE,CAAC;aACJ,IAAI,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;aACrB,OAAO,CAAC,GAAG,CAAC;aACZ,QAAQ,CACP,wFAAwF,CACzF;KACJ,CAAC;IACF,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,GAAG,EAAE,CAAC;aACH,MAAM,EAAE;aACR,QAAQ,CACP,oKAAoK,CACrK;QACH,IAAI,EAAE,CAAC;aACJ,MAAM,EAAE;aACR,QAAQ,CACP,kGAAkG,CACnG;KACJ,CAAC;IAEF,OAAO,CAAC,KAAK,EAAE,GAAG;QAChB,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,qBAAqB,EAAE;YAClC,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,IAAI,EAAE,KAAK,CAAC,IAAI;SACjB,CAAC,CAAC;QACH,MAAM,GAAG,GAAG,qBAAqB,EAAE,CAAC;QACpC,MAAM,GAAG,GAAG,GAAG,CAAC,WAAW,CAAC,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QACvF,OAAO;YACL,GAAG;YACH,IAAI,EAAE,4HAA4H;SACnI,CAAC;IACJ,CAAC;IAED,MAAM,EAAE,CAAC,MAAM,EAAE,EAAE;QACjB,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,KAAK,CAAC,IAAI,CAAC,kBAAkB,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC;QAC3C,KAAK,CAAC,IAAI,CAAC,aAAa,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;QACvC,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACpD,CAAC;CACF,CAAC,CAAC"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * @fileoverview Fetch a single edition by identifier (ISBN, OCLC, LCCN, or OLID).
3
+ * @module mcp-server/tools/definitions/openlibrary-get-edition.tool
4
+ */
5
+ import { z } from '@cyanheads/mcp-ts-core';
6
+ import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
7
+ export declare const openlibraryGetEdition: import("@cyanheads/mcp-ts-core").ToolDefinition<z.ZodObject<{
8
+ identifier: z.ZodString;
9
+ id_type: z.ZodEnum<{
10
+ isbn: "isbn";
11
+ oclc: "oclc";
12
+ lccn: "lccn";
13
+ olid: "olid";
14
+ }>;
15
+ }, z.core.$strip>, z.ZodObject<{
16
+ edition_id: z.ZodString;
17
+ title: z.ZodString;
18
+ authors: z.ZodArray<z.ZodObject<{
19
+ name: z.ZodString;
20
+ author_id: z.ZodOptional<z.ZodString>;
21
+ }, z.core.$strip>>;
22
+ publish_date: z.ZodOptional<z.ZodString>;
23
+ publishers: z.ZodArray<z.ZodString>;
24
+ language: z.ZodOptional<z.ZodString>;
25
+ isbn_10: z.ZodArray<z.ZodString>;
26
+ isbn_13: z.ZodArray<z.ZodString>;
27
+ oclc: z.ZodArray<z.ZodString>;
28
+ lccn: z.ZodArray<z.ZodString>;
29
+ page_count: z.ZodOptional<z.ZodNumber>;
30
+ description: z.ZodOptional<z.ZodString>;
31
+ cover_ids: z.ZodArray<z.ZodNumber>;
32
+ work_id: z.ZodOptional<z.ZodString>;
33
+ ebook_url: z.ZodOptional<z.ZodString>;
34
+ }, z.core.$strip>, readonly [{
35
+ readonly reason: "not_found";
36
+ readonly code: JsonRpcErrorCode.NotFound;
37
+ readonly when: "No edition found for the given identifier.";
38
+ readonly recovery: "Verify the identifier value or try searching by title/author with openlibrary_search_books.";
39
+ }, {
40
+ readonly reason: "invalid_identifier";
41
+ readonly code: JsonRpcErrorCode.InvalidParams;
42
+ readonly when: "Identifier format is invalid for the specified id_type.";
43
+ readonly recovery: "Check the identifier format: ISBNs are 10 or 13 digits; OLIDs end in M (e.g., OL7353617M).";
44
+ }]>;
45
+ //# sourceMappingURL=openlibrary-get-edition.tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openlibrary-get-edition.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/openlibrary-get-edition.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAGjE,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuIhC,CAAC"}
@@ -0,0 +1,132 @@
1
+ /**
2
+ * @fileoverview Fetch a single edition by identifier (ISBN, OCLC, LCCN, or OLID).
3
+ * @module mcp-server/tools/definitions/openlibrary-get-edition.tool
4
+ */
5
+ import { tool, z } from '@cyanheads/mcp-ts-core';
6
+ import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
7
+ import { getOpenLibraryService } from '../../../services/open-library/open-library-service.js';
8
+ export const openlibraryGetEdition = tool('openlibrary_get_edition', {
9
+ title: 'Get Edition',
10
+ description: 'Fetch a single edition by identifier: ISBN-10, ISBN-13, OCLC, LCCN, or Open Library Edition ID (OL…M). Returns full edition metadata including authors, publisher, language, all identifier types, and the parent work ID. Use for ISBN lookups — pass id_type "isbn" for both ISBN-10 and ISBN-13.',
11
+ annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: true },
12
+ input: z.object({
13
+ identifier: z
14
+ .string()
15
+ .describe('The identifier value. For ISBN: 10 or 13 digits, hyphens stripped. For OCLC: numeric string. For LCCN: string as-is. For OLID: Open Library edition ID (e.g., OL7353617M).'),
16
+ id_type: z
17
+ .enum(['isbn', 'oclc', 'lccn', 'olid'])
18
+ .describe('Identifier type. "isbn" handles both ISBN-10 and ISBN-13. "olid" is the native Open Library edition ID (OL…M).'),
19
+ }),
20
+ output: z.object({
21
+ edition_id: z.string().describe('Open Library Edition ID (OL…M).'),
22
+ title: z.string().describe('Edition title.'),
23
+ authors: z
24
+ .array(z
25
+ .object({
26
+ name: z.string().describe('Author display name.'),
27
+ author_id: z
28
+ .string()
29
+ .optional()
30
+ .describe('Open Library Author ID (OL…A). Use openlibrary_get_author for bio and details.'),
31
+ })
32
+ .describe('An author contributor for this edition.'))
33
+ .describe('Authors of this edition.'),
34
+ publish_date: z
35
+ .string()
36
+ .optional()
37
+ .describe('Publication date string. Absent when not recorded.'),
38
+ publishers: z.array(z.string()).describe('Publisher names.'),
39
+ language: z
40
+ .string()
41
+ .optional()
42
+ .describe('3-letter ISO language code (e.g., "eng"). Absent when not recorded.'),
43
+ isbn_10: z.array(z.string()).describe('ISBN-10 identifiers.'),
44
+ isbn_13: z.array(z.string()).describe('ISBN-13 identifiers.'),
45
+ oclc: z.array(z.string()).describe('OCLC/WorldCat numbers.'),
46
+ lccn: z.array(z.string()).describe('Library of Congress Control Numbers.'),
47
+ page_count: z.number().optional().describe('Page count. Absent when not recorded.'),
48
+ description: z.string().optional().describe('Edition description. Absent when not provided.'),
49
+ cover_ids: z.array(z.number()).describe('Numeric cover IDs for openlibrary_get_cover_url.'),
50
+ work_id: z
51
+ .string()
52
+ .optional()
53
+ .describe('Parent Work ID (OL…W). Use openlibrary_get_work for work-level metadata.'),
54
+ ebook_url: z
55
+ .string()
56
+ .optional()
57
+ .describe('Internet Archive URL for reading/borrowing. Present when an IA item exists.'),
58
+ }),
59
+ errors: [
60
+ {
61
+ reason: 'not_found',
62
+ code: JsonRpcErrorCode.NotFound,
63
+ when: 'No edition found for the given identifier.',
64
+ recovery: 'Verify the identifier value or try searching by title/author with openlibrary_search_books.',
65
+ },
66
+ {
67
+ reason: 'invalid_identifier',
68
+ code: JsonRpcErrorCode.InvalidParams,
69
+ when: 'Identifier format is invalid for the specified id_type.',
70
+ recovery: 'Check the identifier format: ISBNs are 10 or 13 digits; OLIDs end in M (e.g., OL7353617M).',
71
+ },
72
+ ],
73
+ handler(input, ctx) {
74
+ ctx.log.info('Fetching edition', { identifier: input.identifier, id_type: input.id_type });
75
+ // Basic validation — return rejected Promise so callers can use await
76
+ if (input.id_type === 'isbn') {
77
+ const digits = input.identifier.replace(/-/g, '');
78
+ if (!/^\d{10}$/.test(digits) && !/^\d{13}$/.test(digits)) {
79
+ return Promise.reject(ctx.fail('invalid_identifier', `"${input.identifier}" is not a valid ISBN (must be 10 or 13 digits).`));
80
+ }
81
+ }
82
+ else if (input.id_type === 'olid') {
83
+ if (!/^OL\d+M$/i.test(input.identifier)) {
84
+ return Promise.reject(ctx.fail('invalid_identifier', `"${input.identifier}" is not a valid Open Library Edition ID. Expected format: OL…M (e.g., OL7353617M).`));
85
+ }
86
+ }
87
+ const svc = getOpenLibraryService();
88
+ return svc.getEditionByIdentifier(input.identifier, input.id_type, ctx);
89
+ },
90
+ format: (result) => {
91
+ const lines = [];
92
+ lines.push(`## ${result.title}`);
93
+ lines.push(`**Edition ID:** ${result.edition_id}`);
94
+ if (result.authors.length) {
95
+ const authorStr = result.authors
96
+ .map((a) => (a.author_id ? `${a.name} (${a.author_id})` : a.name))
97
+ .join(', ');
98
+ lines.push(`**Authors:** ${authorStr}`);
99
+ }
100
+ const meta = [];
101
+ if (result.publish_date)
102
+ meta.push(`Published: ${result.publish_date}`);
103
+ if (result.publishers.length)
104
+ meta.push(`Publisher: ${result.publishers.join(', ')}`);
105
+ if (result.language)
106
+ meta.push(`Language: ${result.language}`);
107
+ if (result.page_count != null)
108
+ meta.push(`Pages: ${result.page_count}`);
109
+ if (meta.length)
110
+ lines.push(meta.join(' | '));
111
+ if (result.isbn_13.length)
112
+ lines.push(`**ISBN-13:** ${result.isbn_13.join(', ')}`);
113
+ if (result.isbn_10.length)
114
+ lines.push(`**ISBN-10:** ${result.isbn_10.join(', ')}`);
115
+ if (result.oclc.length)
116
+ lines.push(`**OCLC:** ${result.oclc.join(', ')}`);
117
+ if (result.lccn.length)
118
+ lines.push(`**LCCN:** ${result.lccn.join(', ')}`);
119
+ if (result.description) {
120
+ lines.push('');
121
+ lines.push(result.description);
122
+ }
123
+ if (result.cover_ids.length)
124
+ lines.push(`**Cover IDs:** ${result.cover_ids.join(', ')}`);
125
+ if (result.work_id)
126
+ lines.push(`**Work ID:** ${result.work_id}`);
127
+ if (result.ebook_url)
128
+ lines.push(`**E-book:** ${result.ebook_url}`);
129
+ return [{ type: 'text', text: lines.join('\n') }];
130
+ },
131
+ });
132
+ //# sourceMappingURL=openlibrary-get-edition.tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openlibrary-get-edition.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/openlibrary-get-edition.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,qBAAqB,EAAE,MAAM,iDAAiD,CAAC;AAExF,MAAM,CAAC,MAAM,qBAAqB,GAAG,IAAI,CAAC,yBAAyB,EAAE;IACnE,KAAK,EAAE,aAAa;IACpB,WAAW,EACT,qSAAqS;IACvS,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE;IAC9E,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC;QACd,UAAU,EAAE,CAAC;aACV,MAAM,EAAE;aACR,QAAQ,CACP,4KAA4K,CAC7K;QACH,OAAO,EAAE,CAAC;aACP,IAAI,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;aACtC,QAAQ,CACP,gHAAgH,CACjH;KACJ,CAAC;IACF,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,iCAAiC,CAAC;QAClE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,gBAAgB,CAAC;QAC5C,OAAO,EAAE,CAAC;aACP,KAAK,CACJ,CAAC;aACE,MAAM,CAAC;YACN,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,sBAAsB,CAAC;YACjD,SAAS,EAAE,CAAC;iBACT,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CACP,gFAAgF,CACjF;SACJ,CAAC;aACD,QAAQ,CAAC,yCAAyC,CAAC,CACvD;aACA,QAAQ,CAAC,0BAA0B,CAAC;QACvC,YAAY,EAAE,CAAC;aACZ,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,oDAAoD,CAAC;QACjE,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,CAAC,kBAAkB,CAAC;QAC5D,QAAQ,EAAE,CAAC;aACR,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,qEAAqE,CAAC;QAClF,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,CAAC,sBAAsB,CAAC;QAC7D,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,CAAC,sBAAsB,CAAC;QAC7D,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,CAAC,wBAAwB,CAAC;QAC5D,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,CAAC,sCAAsC,CAAC;QAC1E,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,uCAAuC,CAAC;QACnF,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,gDAAgD,CAAC;QAC7F,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,CAAC,kDAAkD,CAAC;QAC3F,OAAO,EAAE,CAAC;aACP,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,0EAA0E,CAAC;QACvF,SAAS,EAAE,CAAC;aACT,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,6EAA6E,CAAC;KAC3F,CAAC;IACF,MAAM,EAAE;QACN;YACE,MAAM,EAAE,WAAW;YACnB,IAAI,EAAE,gBAAgB,CAAC,QAAQ;YAC/B,IAAI,EAAE,4CAA4C;YAClD,QAAQ,EACN,6FAA6F;SAChG;QACD;YACE,MAAM,EAAE,oBAAoB;YAC5B,IAAI,EAAE,gBAAgB,CAAC,aAAa;YACpC,IAAI,EAAE,yDAAyD;YAC/D,QAAQ,EACN,4FAA4F;SAC/F;KACF;IAED,OAAO,CAAC,KAAK,EAAE,GAAG;QAChB,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,kBAAkB,EAAE,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QAE3F,sEAAsE;QACtE,IAAI,KAAK,CAAC,OAAO,KAAK,MAAM,EAAE,CAAC;YAC7B,MAAM,MAAM,GAAG,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YAClD,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;gBACzD,OAAO,OAAO,CAAC,MAAM,CACnB,GAAG,CAAC,IAAI,CACN,oBAAoB,EACpB,IAAI,KAAK,CAAC,UAAU,kDAAkD,CACvE,CACF,CAAC;YACJ,CAAC;QACH,CAAC;aAAM,IAAI,KAAK,CAAC,OAAO,KAAK,MAAM,EAAE,CAAC;YACpC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC;gBACxC,OAAO,OAAO,CAAC,MAAM,CACnB,GAAG,CAAC,IAAI,CACN,oBAAoB,EACpB,IAAI,KAAK,CAAC,UAAU,qFAAqF,CAC1G,CACF,CAAC;YACJ,CAAC;QACH,CAAC;QAED,MAAM,GAAG,GAAG,qBAAqB,EAAE,CAAC;QACpC,OAAO,GAAG,CAAC,sBAAsB,CAAC,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IAC1E,CAAC;IAED,MAAM,EAAE,CAAC,MAAM,EAAE,EAAE;QACjB,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,KAAK,CAAC,IAAI,CAAC,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;QACjC,KAAK,CAAC,IAAI,CAAC,mBAAmB,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;QACnD,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;YAC1B,MAAM,SAAS,GAAG,MAAM,CAAC,OAAO;iBAC7B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;iBACjE,IAAI,CAAC,IAAI,CAAC,CAAC;YACd,KAAK,CAAC,IAAI,CAAC,gBAAgB,SAAS,EAAE,CAAC,CAAC;QAC1C,CAAC;QACD,MAAM,IAAI,GAAa,EAAE,CAAC;QAC1B,IAAI,MAAM,CAAC,YAAY;YAAE,IAAI,CAAC,IAAI,CAAC,cAAc,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC;QACxE,IAAI,MAAM,CAAC,UAAU,CAAC,MAAM;YAAE,IAAI,CAAC,IAAI,CAAC,cAAc,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACtF,IAAI,MAAM,CAAC,QAAQ;YAAE,IAAI,CAAC,IAAI,CAAC,aAAa,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;QAC/D,IAAI,MAAM,CAAC,UAAU,IAAI,IAAI;YAAE,IAAI,CAAC,IAAI,CAAC,UAAU,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;QACxE,IAAI,IAAI,CAAC,MAAM;YAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;QAC9C,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM;YAAE,KAAK,CAAC,IAAI,CAAC,gBAAgB,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACnF,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM;YAAE,KAAK,CAAC,IAAI,CAAC,gBAAgB,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACnF,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM;YAAE,KAAK,CAAC,IAAI,CAAC,aAAa,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC1E,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM;YAAE,KAAK,CAAC,IAAI,CAAC,aAAa,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC1E,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;YACvB,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACf,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QACjC,CAAC;QACD,IAAI,MAAM,CAAC,SAAS,CAAC,MAAM;YAAE,KAAK,CAAC,IAAI,CAAC,kBAAkB,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACzF,IAAI,MAAM,CAAC,OAAO;YAAE,KAAK,CAAC,IAAI,CAAC,gBAAgB,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;QACjE,IAAI,MAAM,CAAC,SAAS;YAAE,KAAK,CAAC,IAAI,CAAC,eAAe,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC;QACpE,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACpD,CAAC;CACF,CAAC,CAAC"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * @fileoverview List editions of a work.
3
+ * @module mcp-server/tools/definitions/openlibrary-get-editions.tool
4
+ */
5
+ import { z } from '@cyanheads/mcp-ts-core';
6
+ import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
7
+ export declare const openlibraryGetEditions: import("@cyanheads/mcp-ts-core").ToolDefinition<z.ZodObject<{
8
+ work_id: z.ZodString;
9
+ limit: z.ZodDefault<z.ZodNumber>;
10
+ offset: z.ZodDefault<z.ZodNumber>;
11
+ }, z.core.$strip>, z.ZodObject<{
12
+ total: z.ZodNumber;
13
+ work_id: z.ZodString;
14
+ editions: z.ZodArray<z.ZodObject<{
15
+ edition_id: z.ZodString;
16
+ title: z.ZodString;
17
+ publish_date: z.ZodOptional<z.ZodString>;
18
+ publishers: z.ZodArray<z.ZodString>;
19
+ languages: z.ZodArray<z.ZodString>;
20
+ isbn_10: z.ZodArray<z.ZodString>;
21
+ isbn_13: z.ZodArray<z.ZodString>;
22
+ page_count: z.ZodOptional<z.ZodNumber>;
23
+ cover_ids: z.ZodArray<z.ZodNumber>;
24
+ work_id: z.ZodOptional<z.ZodString>;
25
+ }, z.core.$strip>>;
26
+ }, z.core.$strip>, readonly [{
27
+ readonly reason: "not_found";
28
+ readonly code: JsonRpcErrorCode.NotFound;
29
+ readonly when: "Work ID does not exist on Open Library.";
30
+ readonly recovery: "Verify the Work ID format (e.g., \"OL45804W\") or use openlibrary_search_books first.";
31
+ }]>;
32
+ //# sourceMappingURL=openlibrary-get-editions.tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openlibrary-get-editions.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/openlibrary-get-editions.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAGjE,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;GAsGjC,CAAC"}
@@ -0,0 +1,106 @@
1
+ /**
2
+ * @fileoverview List editions of a work.
3
+ * @module mcp-server/tools/definitions/openlibrary-get-editions.tool
4
+ */
5
+ import { tool, z } from '@cyanheads/mcp-ts-core';
6
+ import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
7
+ import { getOpenLibraryService } from '../../../services/open-library/open-library-service.js';
8
+ export const openlibraryGetEditions = tool('openlibrary_get_editions', {
9
+ title: 'Get Editions',
10
+ description: 'List editions of a work — different publishers, languages, formats, and print runs. Returns ISBNs, publisher, language, page count, and edition OLIDs. Use after openlibrary_get_work or openlibrary_search_books to find a specific printing.',
11
+ annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: true },
12
+ input: z.object({
13
+ work_id: z
14
+ .string()
15
+ .describe('Open Library Work ID (OL…W). A leading "/works/" prefix is stripped if provided.'),
16
+ limit: z
17
+ .number()
18
+ .int()
19
+ .min(1)
20
+ .max(100)
21
+ .default(10)
22
+ .describe('Max editions to return. Prefer 10–20 for exploration.'),
23
+ offset: z.number().int().min(0).default(0).describe('Zero-based offset for pagination.'),
24
+ }),
25
+ output: z.object({
26
+ total: z.number().describe('Total editions for this work.'),
27
+ work_id: z.string().describe('Open Library Work ID.'),
28
+ editions: z
29
+ .array(z
30
+ .object({
31
+ edition_id: z
32
+ .string()
33
+ .describe('Open Library Edition ID (OL…M). Use for openlibrary_get_edition with id_type "olid".'),
34
+ title: z
35
+ .string()
36
+ .describe('Edition title (may differ from work title for translated editions).'),
37
+ publish_date: z
38
+ .string()
39
+ .optional()
40
+ .describe('Publication date string (e.g., "2003", "January 2003"). Absent when not recorded.'),
41
+ publishers: z.array(z.string()).describe('Publisher names.'),
42
+ languages: z
43
+ .array(z.string())
44
+ .describe('3-letter ISO language codes (e.g., "eng", "fre").'),
45
+ isbn_10: z.array(z.string()).describe('ISBN-10 identifiers.'),
46
+ isbn_13: z.array(z.string()).describe('ISBN-13 identifiers.'),
47
+ page_count: z.number().optional().describe('Page count. Absent when not recorded.'),
48
+ cover_ids: z
49
+ .array(z.number())
50
+ .describe('Numeric cover IDs for openlibrary_get_cover_url.'),
51
+ work_id: z
52
+ .string()
53
+ .optional()
54
+ .describe('Parent Work ID. Usually matches the requested work_id.'),
55
+ })
56
+ .describe('A single edition of the work.'))
57
+ .describe('Editions of the work, up to limit.'),
58
+ }),
59
+ errors: [
60
+ {
61
+ reason: 'not_found',
62
+ code: JsonRpcErrorCode.NotFound,
63
+ when: 'Work ID does not exist on Open Library.',
64
+ recovery: 'Verify the Work ID format (e.g., "OL45804W") or use openlibrary_search_books first.',
65
+ },
66
+ ],
67
+ handler(input, ctx) {
68
+ ctx.log.info('Fetching editions', {
69
+ work_id: input.work_id,
70
+ limit: input.limit,
71
+ offset: input.offset,
72
+ });
73
+ const svc = getOpenLibraryService();
74
+ return svc.getEditions(input.work_id, input.limit, input.offset, ctx);
75
+ },
76
+ format: (result) => {
77
+ const lines = [];
78
+ lines.push(`**Work ID:** ${result.work_id} | **Total editions:** ${result.total} | **Returned:** ${result.editions.length}`);
79
+ for (const ed of result.editions) {
80
+ lines.push('');
81
+ lines.push(`### ${ed.title}`);
82
+ lines.push(`**Edition ID:** ${ed.edition_id}`);
83
+ const meta = [];
84
+ if (ed.publish_date)
85
+ meta.push(`Published: ${ed.publish_date}`);
86
+ if (ed.publishers.length)
87
+ meta.push(`Publisher: ${ed.publishers.join(', ')}`);
88
+ if (ed.languages.length)
89
+ meta.push(`Language: ${ed.languages.join(', ')}`);
90
+ if (ed.page_count != null)
91
+ meta.push(`Pages: ${ed.page_count}`);
92
+ if (meta.length)
93
+ lines.push(meta.join(' | '));
94
+ if (ed.isbn_13.length)
95
+ lines.push(`**ISBN-13:** ${ed.isbn_13.join(', ')}`);
96
+ if (ed.isbn_10.length)
97
+ lines.push(`**ISBN-10:** ${ed.isbn_10.join(', ')}`);
98
+ if (ed.cover_ids.length)
99
+ lines.push(`**Cover IDs:** ${ed.cover_ids.join(', ')}`);
100
+ if (ed.work_id)
101
+ lines.push(`**Work ID:** ${ed.work_id}`);
102
+ }
103
+ return [{ type: 'text', text: lines.join('\n') }];
104
+ },
105
+ });
106
+ //# sourceMappingURL=openlibrary-get-editions.tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openlibrary-get-editions.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/openlibrary-get-editions.tool.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * @fileoverview Browse works by subject on Open Library.
3
+ * @module mcp-server/tools/definitions/openlibrary-get-subject.tool
4
+ */
5
+ import { z } from '@cyanheads/mcp-ts-core';
6
+ import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
7
+ export declare const openlibraryGetSubject: import("@cyanheads/mcp-ts-core").ToolDefinition<z.ZodObject<{
8
+ subject: z.ZodString;
9
+ limit: z.ZodDefault<z.ZodNumber>;
10
+ offset: z.ZodDefault<z.ZodNumber>;
11
+ ebooks_only: z.ZodDefault<z.ZodBoolean>;
12
+ }, z.core.$strip>, z.ZodObject<{
13
+ subject_name: z.ZodString;
14
+ subject_key: z.ZodString;
15
+ work_count: z.ZodNumber;
16
+ works: z.ZodArray<z.ZodObject<{
17
+ work_id: z.ZodString;
18
+ title: z.ZodString;
19
+ author_names: z.ZodArray<z.ZodString>;
20
+ edition_count: z.ZodNumber;
21
+ cover_id: z.ZodOptional<z.ZodNumber>;
22
+ }, z.core.$strip>>;
23
+ }, z.core.$strip>, readonly [{
24
+ readonly reason: "not_found";
25
+ readonly code: JsonRpcErrorCode.NotFound;
26
+ readonly when: "Subject not found or has no works.";
27
+ readonly recovery: "Try a broader or alternate subject term (e.g., \"fiction\" instead of a specific subgenre).";
28
+ }]>;
29
+ //# sourceMappingURL=openlibrary-get-subject.tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openlibrary-get-subject.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/openlibrary-get-subject.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAGjE,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;GAmFhC,CAAC"}
@@ -0,0 +1,82 @@
1
+ /**
2
+ * @fileoverview Browse works by subject on Open Library.
3
+ * @module mcp-server/tools/definitions/openlibrary-get-subject.tool
4
+ */
5
+ import { tool, z } from '@cyanheads/mcp-ts-core';
6
+ import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
7
+ import { getOpenLibraryService } from '../../../services/open-library/open-library-service.js';
8
+ export const openlibraryGetSubject = tool('openlibrary_get_subject', {
9
+ title: 'Get Subject',
10
+ description: 'Browse works by subject. Returns matching works with edition counts and cover IDs, plus the total work count for the subject. Subjects are user-contributed and may be inconsistent ("science fiction", "Science fiction", "SF" are separate tags). Try lowercase forms first.',
11
+ annotations: { readOnlyHint: true, openWorldHint: true },
12
+ input: z.object({
13
+ subject: z
14
+ .string()
15
+ .describe('Subject name. Spaces are converted to underscores internally (e.g., "science fiction" → "science_fiction"). Use lowercase for best results.'),
16
+ limit: z
17
+ .number()
18
+ .int()
19
+ .min(1)
20
+ .max(100)
21
+ .default(12)
22
+ .describe('Max works to return. Subject pages typically show 12 at a time.'),
23
+ offset: z.number().int().min(0).default(0).describe('Zero-based offset for pagination.'),
24
+ ebooks_only: z
25
+ .boolean()
26
+ .default(false)
27
+ .describe('Restrict to works with a readable or borrowable e-book on Internet Archive.'),
28
+ }),
29
+ output: z.object({
30
+ subject_name: z.string().describe('Canonical subject name as stored on Open Library.'),
31
+ subject_key: z.string().describe('Normalized subject key (lowercase, underscores).'),
32
+ work_count: z.number().describe('Total works tagged with this subject.'),
33
+ works: z
34
+ .array(z
35
+ .object({
36
+ work_id: z.string().describe('Open Library Work ID (OL…W).'),
37
+ title: z.string().describe('Work title.'),
38
+ author_names: z.array(z.string()).describe('Author display names.'),
39
+ edition_count: z.number().describe('Total editions for this work.'),
40
+ cover_id: z
41
+ .number()
42
+ .optional()
43
+ .describe('Numeric cover ID. Absent when no cover exists.'),
44
+ })
45
+ .describe('A work under this subject.'))
46
+ .describe('Works under this subject, up to limit.'),
47
+ }),
48
+ errors: [
49
+ {
50
+ reason: 'not_found',
51
+ code: JsonRpcErrorCode.NotFound,
52
+ when: 'Subject not found or has no works.',
53
+ recovery: 'Try a broader or alternate subject term (e.g., "fiction" instead of a specific subgenre).',
54
+ },
55
+ ],
56
+ handler(input, ctx) {
57
+ ctx.log.info('Fetching subject', {
58
+ subject: input.subject,
59
+ limit: input.limit,
60
+ ebooks_only: input.ebooks_only,
61
+ });
62
+ const svc = getOpenLibraryService();
63
+ return svc.getSubject(input.subject, input.limit, input.offset, input.ebooks_only, ctx);
64
+ },
65
+ format: (result) => {
66
+ const lines = [];
67
+ lines.push(`## Subject: ${result.subject_name}`);
68
+ lines.push(`**Key:** ${result.subject_key} | **Total works:** ${result.work_count} | **Returned:** ${result.works.length}`);
69
+ for (const work of result.works) {
70
+ lines.push('');
71
+ lines.push(`### ${work.title}`);
72
+ lines.push(`**Work ID:** ${work.work_id}`);
73
+ if (work.author_names.length)
74
+ lines.push(`**Authors:** ${work.author_names.join(', ')}`);
75
+ lines.push(`**Editions:** ${work.edition_count}`);
76
+ if (work.cover_id != null)
77
+ lines.push(`**Cover ID:** ${work.cover_id}`);
78
+ }
79
+ return [{ type: 'text', text: lines.join('\n') }];
80
+ },
81
+ });
82
+ //# sourceMappingURL=openlibrary-get-subject.tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openlibrary-get-subject.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/openlibrary-get-subject.tool.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * @fileoverview Fetch a work by Open Library Work ID.
3
+ * @module mcp-server/tools/definitions/openlibrary-get-work.tool
4
+ */
5
+ import { z } from '@cyanheads/mcp-ts-core';
6
+ import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
7
+ export declare const openlibraryGetWork: import("@cyanheads/mcp-ts-core").ToolDefinition<z.ZodObject<{
8
+ work_id: z.ZodString;
9
+ }, z.core.$strip>, z.ZodObject<{
10
+ work_id: z.ZodString;
11
+ title: z.ZodString;
12
+ description: z.ZodOptional<z.ZodString>;
13
+ subjects: z.ZodArray<z.ZodString>;
14
+ subject_places: z.ZodArray<z.ZodString>;
15
+ subject_times: z.ZodArray<z.ZodString>;
16
+ subject_people: z.ZodArray<z.ZodString>;
17
+ cover_ids: z.ZodArray<z.ZodNumber>;
18
+ author_ids: z.ZodArray<z.ZodString>;
19
+ created: z.ZodOptional<z.ZodString>;
20
+ last_modified: z.ZodOptional<z.ZodString>;
21
+ }, z.core.$strip>, readonly [{
22
+ readonly reason: "not_found";
23
+ readonly code: JsonRpcErrorCode.NotFound;
24
+ readonly when: "Work ID does not exist on Open Library.";
25
+ readonly recovery: "Verify the OLID format (e.g., \"OL45804W\") or use openlibrary_search_books to find the correct ID.";
26
+ }]>;
27
+ //# sourceMappingURL=openlibrary-get-work.tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openlibrary-get-work.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/openlibrary-get-work.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAGjE,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;GAqF7B,CAAC"}