@dhcckb/mcp-server-douban 1.0.0

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 (42) hide show
  1. package/README.md +107 -0
  2. package/dist/citations/apa.d.ts +8 -0
  3. package/dist/citations/apa.d.ts.map +1 -0
  4. package/dist/citations/apa.js +78 -0
  5. package/dist/citations/apa.js.map +1 -0
  6. package/dist/citations/bibtex.d.ts +15 -0
  7. package/dist/citations/bibtex.d.ts.map +1 -0
  8. package/dist/citations/bibtex.js +82 -0
  9. package/dist/citations/bibtex.js.map +1 -0
  10. package/dist/citations/chicago.d.ts +8 -0
  11. package/dist/citations/chicago.d.ts.map +1 -0
  12. package/dist/citations/chicago.js +66 -0
  13. package/dist/citations/chicago.js.map +1 -0
  14. package/dist/citations/gb7714.d.ts +9 -0
  15. package/dist/citations/gb7714.d.ts.map +1 -0
  16. package/dist/citations/gb7714.js +39 -0
  17. package/dist/citations/gb7714.js.map +1 -0
  18. package/dist/citations/harvard.d.ts +8 -0
  19. package/dist/citations/harvard.d.ts.map +1 -0
  20. package/dist/citations/harvard.js +50 -0
  21. package/dist/citations/harvard.js.map +1 -0
  22. package/dist/citations/mla.d.ts +8 -0
  23. package/dist/citations/mla.d.ts.map +1 -0
  24. package/dist/citations/mla.js +62 -0
  25. package/dist/citations/mla.js.map +1 -0
  26. package/dist/index.d.ts +3 -0
  27. package/dist/index.d.ts.map +1 -0
  28. package/dist/index.js +23 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/tools/douban_cite.d.ts +3 -0
  31. package/dist/tools/douban_cite.d.ts.map +1 -0
  32. package/dist/tools/douban_cite.js +67 -0
  33. package/dist/tools/douban_cite.js.map +1 -0
  34. package/dist/tools/douban_detail.d.ts +24 -0
  35. package/dist/tools/douban_detail.d.ts.map +1 -0
  36. package/dist/tools/douban_detail.js +188 -0
  37. package/dist/tools/douban_detail.js.map +1 -0
  38. package/dist/tools/douban_search.d.ts +21 -0
  39. package/dist/tools/douban_search.d.ts.map +1 -0
  40. package/dist/tools/douban_search.js +163 -0
  41. package/dist/tools/douban_search.js.map +1 -0
  42. package/package.json +111 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"douban_cite.d.ts","sourceRoot":"","sources":["../../src/tools/douban_cite.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAwBpE,wBAAgB,cAAc,CAAC,MAAM,EAAE,SAAS,QAsD/C"}
@@ -0,0 +1,67 @@
1
+ import { z } from "zod";
2
+ import { formatGB7714 } from "../citations/gb7714.js";
3
+ import { formatAPA } from "../citations/apa.js";
4
+ import { formatMLA } from "../citations/mla.js";
5
+ import { formatChicago } from "../citations/chicago.js";
6
+ import { formatHarvard } from "../citations/harvard.js";
7
+ import { formatBibTeX } from "../citations/bibtex.js";
8
+ const FORMATTERS = {
9
+ gb7714: formatGB7714,
10
+ apa: formatAPA,
11
+ mla: formatMLA,
12
+ chicago: formatChicago,
13
+ harvard: formatHarvard,
14
+ bibtex: formatBibTeX,
15
+ };
16
+ export function doubanCiteTool(server) {
17
+ server.tool("douban_cite", "将书籍完整元数据格式化为指定参考文献引用字符串。支持 GB/T 7714、APA、MLA、Chicago、Harvard 和 BibTeX 六种主流规范。", {
18
+ book_data: z
19
+ .record(z.any())
20
+ .describe("douban_detail 返回的完整书籍元数据对象"),
21
+ style: z
22
+ .enum(["gb7714", "apa", "mla", "chicago", "harvard", "bibtex"])
23
+ .describe("目标参考文献格式: gb7714 (GB/T 7714-2015), apa (APA 7th), mla (MLA 9th), chicago (Chicago 17th Notes-Bibliography), harvard, bibtex"),
24
+ }, async ({ book_data, style }) => {
25
+ try {
26
+ const book = book_data;
27
+ const formatter = FORMATTERS[style];
28
+ const citation = formatter(book);
29
+ return {
30
+ content: [
31
+ {
32
+ type: "text",
33
+ text: JSON.stringify({
34
+ style,
35
+ style_label: getStyleLabel(style),
36
+ citation,
37
+ }, null, 2),
38
+ },
39
+ ],
40
+ };
41
+ }
42
+ catch (error) {
43
+ const message = error instanceof Error ? error.message : String(error);
44
+ return {
45
+ content: [
46
+ {
47
+ type: "text",
48
+ text: JSON.stringify({ error: "生成参考文献格式失败", detail: message }, null, 2),
49
+ },
50
+ ],
51
+ isError: true,
52
+ };
53
+ }
54
+ });
55
+ }
56
+ function getStyleLabel(style) {
57
+ const labels = {
58
+ gb7714: "GB/T 7714-2015",
59
+ apa: "APA 7th",
60
+ mla: "MLA 9th",
61
+ chicago: "Chicago 17th Notes-Bibliography",
62
+ harvard: "Harvard",
63
+ bibtex: "BibTeX",
64
+ };
65
+ return labels[style];
66
+ }
67
+ //# sourceMappingURL=douban_cite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"douban_cite.js","sourceRoot":"","sources":["../../src/tools/douban_cite.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAKtD,MAAM,UAAU,GAGZ;IACF,MAAM,EAAE,YAAY;IACpB,GAAG,EAAE,SAAS;IACd,GAAG,EAAE,SAAS;IACd,OAAO,EAAE,aAAa;IACtB,OAAO,EAAE,aAAa;IACtB,MAAM,EAAE,YAAY;CACrB,CAAC;AAEF,MAAM,UAAU,cAAc,CAAC,MAAiB;IAC9C,MAAM,CAAC,IAAI,CACT,aAAa,EACb,+EAA+E,EAC/E;QACE,SAAS,EAAE,CAAC;aACT,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;aACf,QAAQ,CAAC,4BAA4B,CAAC;QACzC,KAAK,EAAE,CAAC;aACL,IAAI,CAAC,CAAC,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;aAC9D,QAAQ,CACP,6HAA6H,CAC9H;KACJ,EACD,KAAK,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,EAAE;QAC7B,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,SAAwC,CAAC;YACtD,MAAM,SAAS,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;YACpC,MAAM,QAAQ,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;YAEjC,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAClB;4BACE,KAAK;4BACL,WAAW,EAAE,aAAa,CAAC,KAAK,CAAC;4BACjC,QAAQ;yBACT,EACD,IAAI,EACJ,CAAC,CACF;qBACF;iBACF;aACF,CAAC;QACJ,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACvE,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAClB,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,EACxC,IAAI,EACJ,CAAC,CACF;qBACF;iBACF;gBACD,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,KAAoB;IACzC,MAAM,MAAM,GAAkC;QAC5C,MAAM,EAAE,gBAAgB;QACxB,GAAG,EAAE,SAAS;QACd,GAAG,EAAE,SAAS;QACd,OAAO,EAAE,iCAAiC;QAC1C,OAAO,EAAE,SAAS;QAClB,MAAM,EAAE,QAAQ;KACjB,CAAC;IACF,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC"}
@@ -0,0 +1,24 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export interface DoubanBookDetail {
3
+ douban_id: string;
4
+ title: string;
5
+ subtitle: string;
6
+ original_title: string;
7
+ author: string[];
8
+ translator: string[];
9
+ publisher: string;
10
+ publish_date: string;
11
+ isbn: string;
12
+ pages: number;
13
+ price: string;
14
+ binding: string;
15
+ series: string;
16
+ rating: number;
17
+ rating_count: number;
18
+ summary: string;
19
+ author_intro: string;
20
+ cover_url: string;
21
+ url: string;
22
+ }
23
+ export declare function doubanDetailTool(server: McpServer): void;
24
+ //# sourceMappingURL=douban_detail.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"douban_detail.d.ts","sourceRoot":"","sources":["../../src/tools/douban_detail.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIpE,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;CACb;AA+MD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,QAuCjD"}
@@ -0,0 +1,188 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * 从豆瓣书籍详情页 HTML 解析完整元数据
4
+ */
5
+ async function fetchDoubanDetailHTML(doubanId) {
6
+ const detailUrl = `https://book.douban.com/subject/${doubanId}/`;
7
+ const response = await fetch(detailUrl, {
8
+ headers: {
9
+ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
10
+ Accept: "text/html,application/xhtml+xml",
11
+ },
12
+ });
13
+ if (!response.ok) {
14
+ throw new Error(`豆瓣详情页请求失败: HTTP ${response.status}`);
15
+ }
16
+ const html = await response.text();
17
+ return parseDetailHTML(html, doubanId);
18
+ }
19
+ /**
20
+ * 从 HTML 中提取书名(h1 标签中的 span)
21
+ */
22
+ function extractTitle(html) {
23
+ const match = html.match(/<span\s+property="v:itemreviewed">([^<]+)<\/span>/);
24
+ return match ? match[1].trim() : "";
25
+ }
26
+ /**
27
+ * 从 HTML 的 id="info" 区块中提取书籍信息
28
+ */
29
+ function extractInfoBlock(html) {
30
+ const match = html.match(/<div\s+id="info"[^>]*>([\s\S]*?)<\/div>\s*<div\s+id="interest_sectl"/);
31
+ if (!match)
32
+ return "";
33
+ // 有时候 info div 在别的模式中结束
34
+ const altMatch = html.match(/<div\s+id="info"[^>]*>([\s\S]*?)(<div\s+id="collector"|<\/div>\s*<\/div>)/);
35
+ return match ? match[1] : altMatch ? altMatch[1] : "";
36
+ }
37
+ /**
38
+ * 解析信息区块中的纯文本项
39
+ */
40
+ function parseInfoSpan(html, label) {
41
+ const pattern = new RegExp(`<span\\s+class="pl">${label}:?</span>\\s*([^<]*(?:<a[^>]*>[^<]*<\\/a>[^<]*)*)`, "i");
42
+ const match = html.match(pattern);
43
+ if (!match)
44
+ return "";
45
+ // 移除 HTML 标签保留文本
46
+ return match[1].replace(/<[^>]+>/g, "").trim();
47
+ }
48
+ /**
49
+ * 解析命名属性
50
+ */
51
+ function parseProperty(html, property) {
52
+ const pattern = new RegExp(`<[^>]*property="v:${property}"[^>]*>([^<]*)<`, "i");
53
+ const match = html.match(pattern);
54
+ return match ? match[1].trim() : "";
55
+ }
56
+ /**
57
+ * 解析多个值(如作者列表)
58
+ */
59
+ function parsePropertyList(html, property) {
60
+ const pattern = new RegExp(`<[^>]*property="v:${property}"[^>]*>([^<]*)<`, "gi");
61
+ const results = [];
62
+ let match;
63
+ while ((match = pattern.exec(html)) !== null) {
64
+ const val = match[1].trim();
65
+ if (val && !results.includes(val)) {
66
+ results.push(val);
67
+ }
68
+ }
69
+ return results;
70
+ }
71
+ /**
72
+ * 解析豆瓣详情页 HTML
73
+ */
74
+ function parseDetailHTML(html, doubanId) {
75
+ const title = extractTitle(html);
76
+ const infoBlock = extractInfoBlock(html);
77
+ // 副标题
78
+ let subtitle = "";
79
+ const subtitleMatch = html.match(/<span\s+property="v:itemreviewed">[^<]*<\/span>\s*(?:<span[^>]*>)?([^<:]+)(?:<\/span>)?\s*<\/h1>/);
80
+ if (subtitleMatch) {
81
+ subtitle = subtitleMatch[1].trim();
82
+ // 排除非副标题内容
83
+ if (subtitle.startsWith("(") || subtitle.startsWith("(")) {
84
+ subtitle = "";
85
+ }
86
+ }
87
+ const author = parsePropertyList(html, "author");
88
+ const translator = [];
89
+ const transMatch = infoBlock.match(/<span\s+class="pl">译者[::]?<\/span>\s*([^<]*(?:<a[^>]*>[^<]*<\/a>[^<]*)*)/i);
90
+ if (transMatch) {
91
+ const transText = transMatch[1].replace(/<[^>]+>/g, "").trim();
92
+ if (transText) {
93
+ translator.push(...transText.split("/").map((s) => s.trim()).filter(Boolean));
94
+ }
95
+ }
96
+ const publisher = parseProperty(html, "publisher");
97
+ const publish_date = parseProperty(html, "publish_date") || parseProperty(html, "published") || parseInfoSpan(infoBlock, "出版年");
98
+ const isbn = parseInfoSpan(infoBlock, "ISBN");
99
+ const pagesStr = parseProperty(html, "pages") || parseInfoSpan(infoBlock, "页数");
100
+ const pages = parseInt(pagesStr, 10) || 0;
101
+ const price = parseProperty(html, "price") || parseInfoSpan(infoBlock, "定价");
102
+ const binding = parseInfoSpan(infoBlock, "装帧");
103
+ const series = parseInfoSpan(infoBlock, "丛书");
104
+ // 评分
105
+ const ratingStr = parseProperty(html, "average");
106
+ const rating = parseFloat(ratingStr) || 0;
107
+ const ratingCountStr = parseProperty(html, "votes");
108
+ const rating_count = parseInt(ratingCountStr, 10) || 0;
109
+ // 内容简介
110
+ let summary = "";
111
+ const summaryMatch = html.match(/<div\s+class="intro"[^>]*>\s*(?:<p>)?([\s\S]*?)(?:<\/p>)?\s*<\/div>/i);
112
+ if (summaryMatch) {
113
+ summary = summaryMatch[1].replace(/<[^>]+>/g, "").trim();
114
+ }
115
+ // 作者简介
116
+ let author_intro = "";
117
+ const authorIntroDivs = html.match(/<div\s+class="intro"[^>]*>[\s\S]*?<\/div>/gi);
118
+ if (authorIntroDivs && authorIntroDivs.length >= 2) {
119
+ author_intro = authorIntroDivs[1]
120
+ .replace(/<[^>]+>/g, "")
121
+ .trim();
122
+ }
123
+ // 封面图
124
+ let cover_url = "";
125
+ const coverMatch = html.match(/<a\s+class="nbg"[^>]*href="([^"]*)"[^>]*>\s*<img\s+src="([^"]*)"/);
126
+ if (coverMatch) {
127
+ cover_url = coverMatch[2];
128
+ }
129
+ // 原作名
130
+ let original_title = "";
131
+ const origMatch = html.match(/<span\s+class="pl">原作名[::]?<\/span>\s*([^<]*)/);
132
+ if (origMatch) {
133
+ original_title = origMatch[1].trim();
134
+ }
135
+ return {
136
+ douban_id: doubanId,
137
+ title,
138
+ subtitle,
139
+ original_title,
140
+ author,
141
+ translator,
142
+ publisher,
143
+ publish_date,
144
+ isbn,
145
+ pages,
146
+ price,
147
+ binding,
148
+ series,
149
+ rating,
150
+ rating_count,
151
+ summary,
152
+ author_intro,
153
+ cover_url,
154
+ url: `https://book.douban.com/subject/${doubanId}/`,
155
+ };
156
+ }
157
+ export function doubanDetailTool(server) {
158
+ server.tool("douban_detail", "根据豆瓣书籍 ID 获取完整元数据。返回字段涵盖标题、副标题、作者、译者、出版社、出版日期、ISBN、页数、定价、装帧、丛书、评分、内容简介、作者简介等。", {
159
+ douban_id: z
160
+ .string()
161
+ .describe("豆瓣书籍 ID,来源于 douban_search 返回结果中的 douban_id 字段"),
162
+ }, async ({ douban_id }) => {
163
+ try {
164
+ const detail = await fetchDoubanDetailHTML(douban_id);
165
+ return {
166
+ content: [
167
+ {
168
+ type: "text",
169
+ text: JSON.stringify(detail, null, 2),
170
+ },
171
+ ],
172
+ };
173
+ }
174
+ catch (error) {
175
+ const message = error instanceof Error ? error.message : String(error);
176
+ return {
177
+ content: [
178
+ {
179
+ type: "text",
180
+ text: JSON.stringify({ error: "获取豆瓣书籍详情失败", detail: message }, null, 2),
181
+ },
182
+ ],
183
+ isError: true,
184
+ };
185
+ }
186
+ });
187
+ }
188
+ //# sourceMappingURL=douban_detail.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"douban_detail.js","sourceRoot":"","sources":["../../src/tools/douban_detail.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export interface DoubanSearchItem {
3
+ douban_id: string;
4
+ title: string;
5
+ author: string[];
6
+ year: string;
7
+ publisher: string;
8
+ cover_url: string;
9
+ url: string;
10
+ }
11
+ export interface DoubanSearchResponse {
12
+ books: DoubanSearchItem[];
13
+ total: number;
14
+ _disambiguation?: {
15
+ needed: boolean;
16
+ message: string;
17
+ available_filters: string[];
18
+ };
19
+ }
20
+ export declare function doubanSearchTool(server: McpServer): void;
21
+ //# sourceMappingURL=douban_search.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"douban_search.d.ts","sourceRoot":"","sources":["../../src/tools/douban_search.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIpE,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;CACb;AAGD,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,gBAAgB,EAAE,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,eAAe,CAAC,EAAE;QAChB,MAAM,EAAE,OAAO,CAAC;QAChB,OAAO,EAAE,MAAM,CAAC;QAChB,iBAAiB,EAAE,MAAM,EAAE,CAAC;KAC7B,CAAC;CACH;AAqID,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,QAgFjD"}
@@ -0,0 +1,163 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * 从豆瓣 HTML 页面解析搜索结果
4
+ */
5
+ async function fetchDoubanSearchHTML(title, limit) {
6
+ const searchUrl = `https://search.douban.com/book/subject_search?search_text=${encodeURIComponent(title)}`;
7
+ const response = await fetch(searchUrl, {
8
+ headers: {
9
+ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
10
+ Accept: "text/html,application/xhtml+xml",
11
+ },
12
+ });
13
+ if (!response.ok) {
14
+ throw new Error(`豆瓣搜索请求失败: HTTP ${response.status}`);
15
+ }
16
+ const html = await response.text();
17
+ return parseSearchResultHTML(html, limit);
18
+ }
19
+ /**
20
+ * 解析豆瓣搜索页面 HTML,提取书籍列表
21
+ */
22
+ function parseSearchResultHTML(html, limit) {
23
+ const results = [];
24
+ // 匹配搜索结果中的书籍条目 — 豆瓣 subject-item 模式
25
+ const itemRegex = /<a[^>]*href="https:\/\/book\.douban\.com\/subject\/(\d+)\/"[^>]*>[\s\S]*?<img[^>]*src="([^"]*)"[^>]*>[\s\S]*?<span[^>]*class="[^"]*title[^"]*"[^>]*>([^<]+)<\/span>/gi;
26
+ let match;
27
+ while ((match = itemRegex.exec(html)) !== null) {
28
+ const douban_id = match[1];
29
+ const cover_url = match[2];
30
+ const title = match[3].trim();
31
+ if (results.find((r) => r.douban_id === douban_id))
32
+ continue;
33
+ results.push({
34
+ douban_id,
35
+ title,
36
+ author: [],
37
+ year: "",
38
+ publisher: "",
39
+ cover_url,
40
+ url: `https://book.douban.com/subject/${douban_id}/`,
41
+ });
42
+ if (results.length >= limit)
43
+ break;
44
+ }
45
+ // 尝试解析评分、作者信息(豆瓣结果列表格式)
46
+ parseMetaInfo(html, results);
47
+ return results;
48
+ }
49
+ /**
50
+ * 从 HTML 中解析书籍的附加元信息(作者、出版年、出版社、评分)
51
+ */
52
+ function parseMetaInfo(html, results) {
53
+ // 豆瓣列表页的 meta 信息结构
54
+ const ratingRegex = /<span[^>]*class="[^"]*rating_nums[^"]*"[^>]*>([\d.]+)<\/span>/g;
55
+ const pubRegex = /<div[^>]*class="[^"]*pub[^"]*"[^>]*>\s*([^<]+)\s*<\/div>/gi;
56
+ const metaRegex = /<div[^>]*class="[^"]*meta[^"]*"[^>]*>([^<]*)<\/div>/gi;
57
+ // 通用方案: 从搜索结果卡片中提取 pub 信息
58
+ const pubMatches = html.match(pubRegex);
59
+ if (pubMatches) {
60
+ pubMatches.forEach((pubMatch, idx) => {
61
+ if (idx < results.length) {
62
+ const text = pubMatch.replace(/<[^>]+>/g, "").trim();
63
+ const parts = text.split("/").map((s) => s.trim());
64
+ // 格式通常是: 作者 / 出版社 / 出版日期 / 定价
65
+ if (parts.length >= 1) {
66
+ results[idx].author = [parts[0]];
67
+ }
68
+ if (parts.length >= 2) {
69
+ results[idx].publisher = parts[1];
70
+ }
71
+ if (parts.length >= 3) {
72
+ results[idx].year = parts[2].trim();
73
+ }
74
+ }
75
+ });
76
+ }
77
+ }
78
+ /**
79
+ * 根据可选的作者/出版年/出版社筛选结果
80
+ */
81
+ function filterResults(books, filters) {
82
+ let filtered = [...books];
83
+ if (filters.author) {
84
+ const q = filters.author.toLowerCase();
85
+ filtered = filtered.filter((b) => b.author.some((a) => a.toLowerCase().includes(q)));
86
+ }
87
+ if (filters.year) {
88
+ const q = filters.year.toLowerCase();
89
+ filtered = filtered.filter((b) => b.year.toLowerCase().includes(q));
90
+ }
91
+ if (filters.publisher) {
92
+ const q = filters.publisher.toLowerCase();
93
+ filtered = filtered.filter((b) => b.publisher.toLowerCase().includes(q));
94
+ }
95
+ return filtered;
96
+ }
97
+ export function doubanSearchTool(server) {
98
+ server.tool("douban_search", "按书名搜索豆瓣书籍,支持可选的作者/出版年/出版社筛选条件以缩小范围。返回匹配列表,每条含 douban_id、书名、作者、出版年、出版社、封面 URL。", {
99
+ title: z.string().describe("搜索关键词书名"),
100
+ author: z
101
+ .string()
102
+ .optional()
103
+ .describe("作者名,用于消歧筛选"),
104
+ year: z
105
+ .string()
106
+ .optional()
107
+ .describe("出版年份,用于消歧筛选"),
108
+ publisher: z
109
+ .string()
110
+ .optional()
111
+ .describe("出版社名,用于消歧筛选"),
112
+ limit: z
113
+ .number()
114
+ .optional()
115
+ .default(10)
116
+ .describe("返回结果数量上限"),
117
+ }, async ({ title, author, year, publisher, limit }) => {
118
+ try {
119
+ const searchResults = await fetchDoubanSearchHTML(title, limit);
120
+ // 应用筛选条件
121
+ let filtered = searchResults;
122
+ if (author || year || publisher) {
123
+ filtered = filterResults(searchResults, { author, year, publisher });
124
+ }
125
+ const response = {
126
+ books: filtered.slice(0, limit),
127
+ total: filtered.length,
128
+ };
129
+ // 如果结果数 > 1 且用户没有提供筛选条件,提示消歧
130
+ if (searchResults.length > 1 &&
131
+ !author &&
132
+ !year &&
133
+ !publisher) {
134
+ response._disambiguation = {
135
+ needed: true,
136
+ message: "找到多个匹配结果。请至少提供以下一项筛选条件以缩小范围:作者 (author)、出版年 (year)、出版社 (publisher)。然后使用带筛选参数的 douban_search 重新查询。",
137
+ available_filters: ["author", "year", "publisher"],
138
+ };
139
+ }
140
+ return {
141
+ content: [
142
+ {
143
+ type: "text",
144
+ text: JSON.stringify(response, null, 2),
145
+ },
146
+ ],
147
+ };
148
+ }
149
+ catch (error) {
150
+ const message = error instanceof Error ? error.message : String(error);
151
+ return {
152
+ content: [
153
+ {
154
+ type: "text",
155
+ text: JSON.stringify({ error: "搜索豆瓣书籍失败", detail: message }, null, 2),
156
+ },
157
+ ],
158
+ isError: true,
159
+ };
160
+ }
161
+ });
162
+ }
163
+ //# sourceMappingURL=douban_search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"douban_search.js","sourceRoot":"","sources":["../../src/tools/douban_search.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,111 @@
1
+ {
2
+ "name": "@dhcckb/mcp-server-douban",
3
+ "version": "1.0.0",
4
+ "description": "通过豆瓣数据自动补全书籍元数据并按多规范生成参考文献格式的 MCP Server",
5
+ "main": "dist/index.js",
6
+ "bin": {
7
+ "mcp-server-douban": "dist/index.js"
8
+ },
9
+ "type": "module",
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "start": "node dist/index.js",
13
+ "dev": "tsc --watch"
14
+ },
15
+ "files": [
16
+ "dist/",
17
+ "README.md"
18
+ ],
19
+ "keywords": [
20
+ "mcp",
21
+ "douban",
22
+ "book",
23
+ "reference",
24
+ "citation",
25
+ "bibliography"
26
+ ],
27
+ "repository": {
28
+ "type": "git",
29
+ "url": "https://github.com/dhcckb/mcp-server-douban"
30
+ },
31
+ "license": "MIT",
32
+ "engines": {
33
+ "node": ">=18"
34
+ },
35
+ "dependencies": {
36
+ "@modelcontextprotocol/sdk": "^1.0.0",
37
+ "zod": "^3.22.0"
38
+ },
39
+ "devDependencies": {
40
+ "@types/node": "^20.0.0",
41
+ "typescript": "^5.3.0"
42
+ },
43
+ "mcp": {
44
+ "tools": [
45
+ {
46
+ "name": "douban_search",
47
+ "description": "按书名搜索豆瓣书籍,支持可选的作者/出版年/出版社筛选条件以缩小范围。返回匹配列表,每条含 douban_id、书名、作者、出版年、出版社、封面 URL。",
48
+ "inputSchema": {
49
+ "type": "object",
50
+ "properties": {
51
+ "title": {
52
+ "type": "string",
53
+ "description": "搜索关键词书名"
54
+ },
55
+ "author": {
56
+ "type": "string",
57
+ "description": "作者名,用于消歧筛选"
58
+ },
59
+ "year": {
60
+ "type": "string",
61
+ "description": "出版年份,用于消歧筛选"
62
+ },
63
+ "publisher": {
64
+ "type": "string",
65
+ "description": "出版社名,用于消歧筛选"
66
+ },
67
+ "limit": {
68
+ "type": "number",
69
+ "description": "返回结果数量上限",
70
+ "default": 10
71
+ }
72
+ },
73
+ "required": ["title"]
74
+ }
75
+ },
76
+ {
77
+ "name": "douban_detail",
78
+ "description": "根据豆瓣书籍 ID 获取完整元数据。返回字段涵盖标题、副标题、作者、译者、出版社、出版日期、ISBN、页数、定价、装帧、丛书、评分、内容简介、作者简介等。",
79
+ "inputSchema": {
80
+ "type": "object",
81
+ "properties": {
82
+ "douban_id": {
83
+ "type": "string",
84
+ "description": "豆瓣书籍 ID,来源于 douban_search 返回结果中的 douban_id 字段"
85
+ }
86
+ },
87
+ "required": ["douban_id"]
88
+ }
89
+ },
90
+ {
91
+ "name": "douban_cite",
92
+ "description": "将书籍完整元数据格式化为指定参考文献引用字符串。支持 GB/T 7714、APA、MLA、Chicago、Harvard 和 BibTeX 六种主流规范。",
93
+ "inputSchema": {
94
+ "type": "object",
95
+ "properties": {
96
+ "book_data": {
97
+ "type": "object",
98
+ "description": "douban_detail 返回的完整书籍元数据对象"
99
+ },
100
+ "style": {
101
+ "type": "string",
102
+ "description": "目标参考文献格式",
103
+ "enum": ["gb7714", "apa", "mla", "chicago", "harvard", "bibtex"]
104
+ }
105
+ },
106
+ "required": ["book_data", "style"]
107
+ }
108
+ }
109
+ ]
110
+ }
111
+ }