rewind-mcp-server 0.1.1 → 0.3.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.
- package/README.md +84 -11
- package/dist/__tests__/helpers.test.d.ts +1 -0
- package/dist/__tests__/helpers.test.js +131 -0
- package/dist/__tests__/helpers.test.js.map +1 -0
- package/dist/__tests__/image-block.live.d.ts +1 -0
- package/dist/__tests__/image-block.live.js +41 -0
- package/dist/__tests__/image-block.live.js.map +1 -0
- package/dist/__tests__/server.test.js +710 -16
- package/dist/__tests__/server.test.js.map +1 -1
- package/dist/__tests__/stdio-e2e.live.d.ts +1 -0
- package/dist/__tests__/stdio-e2e.live.js +60 -0
- package/dist/__tests__/stdio-e2e.live.js.map +1 -0
- package/dist/__tests__/ui-resource.live.d.ts +1 -0
- package/dist/__tests__/ui-resource.live.js +71 -0
- package/dist/__tests__/ui-resource.live.js.map +1 -0
- package/dist/client.d.ts +9 -0
- package/dist/client.js +15 -0
- package/dist/client.js.map +1 -1
- package/dist/index.js +0 -0
- package/dist/prompts.js +101 -0
- package/dist/prompts.js.map +1 -1
- package/dist/resources/ui.d.ts +33 -0
- package/dist/resources/ui.js +14 -0
- package/dist/resources/ui.js.map +1 -0
- package/dist/resources.js +128 -0
- package/dist/resources.js.map +1 -1
- package/dist/server.js +55 -1
- package/dist/server.js.map +1 -1
- package/dist/tools/collecting.js +78 -37
- package/dist/tools/collecting.js.map +1 -1
- package/dist/tools/cross-domain.js +74 -17
- package/dist/tools/cross-domain.js.map +1 -1
- package/dist/tools/debug.d.ts +6 -0
- package/dist/tools/debug.js +26 -0
- package/dist/tools/debug.js.map +1 -0
- package/dist/tools/helpers.d.ts +81 -5
- package/dist/tools/helpers.js +138 -4
- package/dist/tools/helpers.js.map +1 -1
- package/dist/tools/listening.js +223 -52
- package/dist/tools/listening.js.map +1 -1
- package/dist/tools/reading.js +74 -22
- package/dist/tools/reading.js.map +1 -1
- package/dist/tools/running.js +87 -43
- package/dist/tools/running.js.map +1 -1
- package/dist/tools/watching.js +199 -32
- package/dist/tools/watching.js.map +1 -1
- package/dist/ui-bundles.d.ts +3 -0
- package/dist/ui-bundles.js +8 -0
- package/dist/ui-bundles.js.map +1 -0
- package/dist/worker.d.ts +2 -1
- package/dist/worker.js +55 -30
- package/dist/worker.js.map +1 -1
- package/package.json +13 -2
package/dist/resources.js
CHANGED
|
@@ -76,5 +76,133 @@ export function registerResources(server, client) {
|
|
|
76
76
|
],
|
|
77
77
|
};
|
|
78
78
|
});
|
|
79
|
+
// Movie entity
|
|
80
|
+
server.resource('movie', new ResourceTemplate('rewind://movie/{id}', { list: undefined }), {
|
|
81
|
+
description: 'Full detail for a single movie by internal Rewind id: metadata, watch history, ratings, and Letterboxd review URLs.',
|
|
82
|
+
}, async (uri, params) => {
|
|
83
|
+
const id = params.id;
|
|
84
|
+
const data = await client.get(`/watching/movies/${id}`);
|
|
85
|
+
return {
|
|
86
|
+
contents: [
|
|
87
|
+
{
|
|
88
|
+
uri: uri.href,
|
|
89
|
+
text: JSON.stringify(data, null, 2),
|
|
90
|
+
mimeType: 'application/json',
|
|
91
|
+
},
|
|
92
|
+
],
|
|
93
|
+
};
|
|
94
|
+
});
|
|
95
|
+
// Show entity
|
|
96
|
+
server.resource('show', new ResourceTemplate('rewind://show/{id}', { list: undefined }), {
|
|
97
|
+
description: 'Full detail for a single TV show by internal Rewind id: metadata, seasons, and watched-episode counts.',
|
|
98
|
+
}, async (uri, params) => {
|
|
99
|
+
const id = params.id;
|
|
100
|
+
const data = await client.get(`/watching/shows/${id}`);
|
|
101
|
+
return {
|
|
102
|
+
contents: [
|
|
103
|
+
{
|
|
104
|
+
uri: uri.href,
|
|
105
|
+
text: JSON.stringify(data, null, 2),
|
|
106
|
+
mimeType: 'application/json',
|
|
107
|
+
},
|
|
108
|
+
],
|
|
109
|
+
};
|
|
110
|
+
});
|
|
111
|
+
// Album entity
|
|
112
|
+
server.resource('album', new ResourceTemplate('rewind://album/{id}', { list: undefined }), {
|
|
113
|
+
description: 'Full detail for a single album by internal Rewind id: artist, play count, track listing, cover art metadata, and Apple Music URL.',
|
|
114
|
+
}, async (uri, params) => {
|
|
115
|
+
const id = params.id;
|
|
116
|
+
const data = await client.get(`/listening/albums/${id}`);
|
|
117
|
+
return {
|
|
118
|
+
contents: [
|
|
119
|
+
{
|
|
120
|
+
uri: uri.href,
|
|
121
|
+
text: JSON.stringify(data, null, 2),
|
|
122
|
+
mimeType: 'application/json',
|
|
123
|
+
},
|
|
124
|
+
],
|
|
125
|
+
};
|
|
126
|
+
});
|
|
127
|
+
// Artist entity
|
|
128
|
+
server.resource('artist', new ResourceTemplate('rewind://artist/{id}', { list: undefined }), {
|
|
129
|
+
description: 'Full detail for a single artist by internal Rewind id: play count, genre, top albums, top tracks, image metadata, and Apple Music URL.',
|
|
130
|
+
}, async (uri, params) => {
|
|
131
|
+
const id = params.id;
|
|
132
|
+
const data = await client.get(`/listening/artists/${id}`);
|
|
133
|
+
return {
|
|
134
|
+
contents: [
|
|
135
|
+
{
|
|
136
|
+
uri: uri.href,
|
|
137
|
+
text: JSON.stringify(data, null, 2),
|
|
138
|
+
mimeType: 'application/json',
|
|
139
|
+
},
|
|
140
|
+
],
|
|
141
|
+
};
|
|
142
|
+
});
|
|
143
|
+
// Vinyl record entity
|
|
144
|
+
server.resource('vinyl', new ResourceTemplate('rewind://vinyl/{id}', { list: undefined }), {
|
|
145
|
+
description: 'Full detail for a single vinyl record (or other Discogs collection item) by internal Rewind id: title, artists, formats, genres, cover art, Discogs URL, community stats.',
|
|
146
|
+
}, async (uri, params) => {
|
|
147
|
+
const id = params.id;
|
|
148
|
+
const data = await client.get(`/collecting/vinyl/${id}`);
|
|
149
|
+
return {
|
|
150
|
+
contents: [
|
|
151
|
+
{
|
|
152
|
+
uri: uri.href,
|
|
153
|
+
text: JSON.stringify(data, null, 2),
|
|
154
|
+
mimeType: 'application/json',
|
|
155
|
+
},
|
|
156
|
+
],
|
|
157
|
+
};
|
|
158
|
+
});
|
|
159
|
+
// Physical media entity
|
|
160
|
+
server.resource('physical-media', new ResourceTemplate('rewind://physical-media/{id}', { list: undefined }), {
|
|
161
|
+
description: 'Full detail for a single physical media item (Blu-ray / 4K UHD / HD DVD) by internal Rewind id: title, year, format, resolution, HDR, audio, watch history.',
|
|
162
|
+
}, async (uri, params) => {
|
|
163
|
+
const id = params.id;
|
|
164
|
+
const data = await client.get(`/collecting/media/${id}`);
|
|
165
|
+
return {
|
|
166
|
+
contents: [
|
|
167
|
+
{
|
|
168
|
+
uri: uri.href,
|
|
169
|
+
text: JSON.stringify(data, null, 2),
|
|
170
|
+
mimeType: 'application/json',
|
|
171
|
+
},
|
|
172
|
+
],
|
|
173
|
+
};
|
|
174
|
+
});
|
|
175
|
+
// Article entity
|
|
176
|
+
server.resource('article', new ResourceTemplate('rewind://article/{id}', { list: undefined }), {
|
|
177
|
+
description: 'Full detail for a saved Instapaper article by internal Rewind id: title, author, domain, word count, read progress, tags, source URL, and embedded highlights.',
|
|
178
|
+
}, async (uri, params) => {
|
|
179
|
+
const id = params.id;
|
|
180
|
+
const data = await client.get(`/reading/articles/${id}`);
|
|
181
|
+
return {
|
|
182
|
+
contents: [
|
|
183
|
+
{
|
|
184
|
+
uri: uri.href,
|
|
185
|
+
text: JSON.stringify(data, null, 2),
|
|
186
|
+
mimeType: 'application/json',
|
|
187
|
+
},
|
|
188
|
+
],
|
|
189
|
+
};
|
|
190
|
+
});
|
|
191
|
+
// Activity entity
|
|
192
|
+
server.resource('activity', new ResourceTemplate('rewind://activity/{id}', { list: undefined }), {
|
|
193
|
+
description: 'Full detail for a single running activity by internal Rewind id: distance, pace, elevation, HR, cadence, calories, location, and Strava URL.',
|
|
194
|
+
}, async (uri, params) => {
|
|
195
|
+
const id = params.id;
|
|
196
|
+
const data = await client.get(`/running/activities/${id}`);
|
|
197
|
+
return {
|
|
198
|
+
contents: [
|
|
199
|
+
{
|
|
200
|
+
uri: uri.href,
|
|
201
|
+
text: JSON.stringify(data, null, 2),
|
|
202
|
+
mimeType: 'application/json',
|
|
203
|
+
},
|
|
204
|
+
],
|
|
205
|
+
};
|
|
206
|
+
});
|
|
79
207
|
}
|
|
80
208
|
//# sourceMappingURL=resources.js.map
|
package/dist/resources.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resources.js","sourceRoot":"","sources":["../src/resources.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"resources.js","sourceRoot":"","sources":["../src/resources.ts"],"names":[],"mappings":"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"}
|
package/dist/server.js
CHANGED
|
@@ -10,12 +10,41 @@ import { registerWatchingTools } from './tools/watching.js';
|
|
|
10
10
|
import { registerCollectingTools } from './tools/collecting.js';
|
|
11
11
|
import { registerReadingTools } from './tools/reading.js';
|
|
12
12
|
import { registerCrossDomainTools } from './tools/cross-domain.js';
|
|
13
|
+
import { registerDebugTools } from './tools/debug.js';
|
|
13
14
|
import { registerResources } from './resources.js';
|
|
15
|
+
import { registerUiResource } from './resources/ui.js';
|
|
14
16
|
import { registerPrompts } from './prompts.js';
|
|
17
|
+
import { UI_BUNDLES } from './ui-bundles.js';
|
|
18
|
+
import { EXTENSION_ID as MCP_APPS_EXTENSION_ID, RESOURCE_MIME_TYPE as MCP_APPS_RESOURCE_MIME_TYPE, } from '@modelcontextprotocol/ext-apps/server';
|
|
19
|
+
const SERVER_INSTRUCTIONS = [
|
|
20
|
+
'Rewind is a personal data archive covering music listening (Last.fm + Apple Music),',
|
|
21
|
+
'running (Strava), watching (Plex + Letterboxd + manual movie entries), collecting',
|
|
22
|
+
'(vinyl via Discogs, physical media), and reading (Instapaper articles and',
|
|
23
|
+
'highlights). Use these tools when the user asks about their own listening, running,',
|
|
24
|
+
'watching, reading, or collecting history, stats, streaks, top lists, or',
|
|
25
|
+
'cross-domain feeds like "what did I do on <date>" or "on this day in past years".',
|
|
26
|
+
'Tools return human-readable text plus structured JSON and, for entity details,',
|
|
27
|
+
'cover art or posters as image content. External platform URLs (Letterboxd, Strava,',
|
|
28
|
+
'Discogs, Apple Music) are returned as clickable resource links.',
|
|
29
|
+
].join(' ');
|
|
15
30
|
export function createServer(client) {
|
|
16
31
|
const server = new McpServer({
|
|
17
32
|
name: 'rewind',
|
|
18
|
-
version: '0.
|
|
33
|
+
version: '0.3.0',
|
|
34
|
+
}, {
|
|
35
|
+
instructions: SERVER_INSTRUCTIONS,
|
|
36
|
+
// Advertise MCP Apps support during the initialize handshake.
|
|
37
|
+
// The ext-apps SDK helpers (registerAppResource/registerAppTool)
|
|
38
|
+
// do NOT auto-advertise -- without this, Claude Desktop sees our
|
|
39
|
+
// tools' _meta.ui.resourceUri but silently skips rendering the
|
|
40
|
+
// iframe because capability negotiation failed.
|
|
41
|
+
capabilities: {
|
|
42
|
+
extensions: {
|
|
43
|
+
[MCP_APPS_EXTENSION_ID]: {
|
|
44
|
+
mimeTypes: [MCP_APPS_RESOURCE_MIME_TYPE],
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
},
|
|
19
48
|
});
|
|
20
49
|
// System tool
|
|
21
50
|
server.tool('get_health', 'Check the health and sync status of the Rewind API. Returns API status and last sync times for each data domain.', {}, READ_ONLY_ANNOTATIONS, async () => {
|
|
@@ -54,6 +83,31 @@ export function createServer(client) {
|
|
|
54
83
|
// Register resources and prompts
|
|
55
84
|
registerResources(server, client);
|
|
56
85
|
registerPrompts(server);
|
|
86
|
+
// MCP Apps UI resources. HTML is inlined into the Worker bundle at build
|
|
87
|
+
// time (see scripts/inline-bundles.mjs) so this registration works in
|
|
88
|
+
// any host context without needing a Workers Static Assets binding.
|
|
89
|
+
registerUiResource(server, {
|
|
90
|
+
name: 'Rewind -- Recent Watches',
|
|
91
|
+
uri: 'ui://rewind/recent-watches.html',
|
|
92
|
+
html: UI_BUNDLES['recent-watches.html'],
|
|
93
|
+
description: 'Interactive poster grid for recently watched movies. Consumes get_recent_watches structuredContent.',
|
|
94
|
+
csp: {
|
|
95
|
+
// Allow poster <img> loads from the Rewind CDN. Without this the
|
|
96
|
+
// default sandbox CSP (`img-src 'self' data:`) blocks external
|
|
97
|
+
// images and the cards render as broken-image placeholders.
|
|
98
|
+
resourceDomains: ['https://cdn.rewind.rest'],
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
// Debug-only: reinstated alongside Phase 2 to A/B test whether Claude
|
|
102
|
+
// Desktop's "Failed to set up MCP app" is specific to the new resource
|
|
103
|
+
// or symptomatic of the whole rewind MCP server's sandbox state.
|
|
104
|
+
registerUiResource(server, {
|
|
105
|
+
name: 'Rewind -- Hello (debug)',
|
|
106
|
+
uri: 'ui://rewind/hello.html',
|
|
107
|
+
html: UI_BUNDLES['hello.html'],
|
|
108
|
+
description: 'Minimal diagnostic UI. Mirror of the Phase-1 app that rendered cleanly earlier today.',
|
|
109
|
+
});
|
|
110
|
+
registerDebugTools(server);
|
|
57
111
|
return server;
|
|
58
112
|
}
|
|
59
113
|
//# sourceMappingURL=server.js.map
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/C,MAAM,UAAU,YAAY,CAAC,MAAoB;IAC/C,MAAM,MAAM,GAAG,IAAI,SAAS,
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/collecting.js
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import {
|
|
2
|
+
import { withRichResponse, text, resourceLink, imageBlock, fmt, READ_ONLY_ANNOTATIONS, dateFilterParams, includeImagesParam, LIST_IMAGE_PX, } from './helpers.js';
|
|
3
|
+
const TOP_N = 5;
|
|
4
|
+
const FORMAT_LABEL = {
|
|
5
|
+
bluray: 'Blu-ray',
|
|
6
|
+
uhd_bluray: '4K UHD',
|
|
7
|
+
hddvd: 'HD DVD',
|
|
8
|
+
};
|
|
3
9
|
export function registerCollectingTools(server, client) {
|
|
4
|
-
// get_vinyl_collection
|
|
5
|
-
server.tool('get_vinyl_collection', 'Browse the vinyl record collection from Discogs. Returns records with artist, title, year, format, and label. Supports search
|
|
10
|
+
// get_vinyl_collection ───────────────────────────────────────────
|
|
11
|
+
server.tool('get_vinyl_collection', 'Browse the vinyl record collection from Discogs. Returns records with artist, title, year, format, and label, plus top-N cover art and Discogs resource links. Supports search, filters, sort, and pagination.', {
|
|
6
12
|
query: z
|
|
7
13
|
.string()
|
|
8
14
|
.optional()
|
|
@@ -29,7 +35,8 @@ export function registerCollectingTools(server, client) {
|
|
|
29
35
|
.describe('Number of records to return'),
|
|
30
36
|
page: z.number().min(1).default(1).describe('Page number for pagination'),
|
|
31
37
|
...dateFilterParams,
|
|
32
|
-
|
|
38
|
+
...includeImagesParam,
|
|
39
|
+
}, READ_ONLY_ANNOTATIONS, async ({ query, format, genre, artist, sort, order, limit, page, date, from, to, include_images, }) => withRichResponse(async () => {
|
|
33
40
|
const data = await client.get('/collecting/vinyl', {
|
|
34
41
|
q: query,
|
|
35
42
|
format,
|
|
@@ -43,28 +50,53 @@ export function registerCollectingTools(server, client) {
|
|
|
43
50
|
from,
|
|
44
51
|
to,
|
|
45
52
|
});
|
|
46
|
-
if (!data.data.length)
|
|
47
|
-
return
|
|
53
|
+
if (!data.data.length) {
|
|
54
|
+
return {
|
|
55
|
+
content: [text('No vinyl records found.')],
|
|
56
|
+
structuredContent: { items: [], pagination: data.pagination },
|
|
57
|
+
};
|
|
58
|
+
}
|
|
48
59
|
const lines = [
|
|
49
60
|
`Vinyl Collection (page ${data.pagination.page} of ${data.pagination.total_pages}, ${fmt(data.pagination.total)} total):`,
|
|
50
61
|
];
|
|
51
62
|
for (const [i, r] of data.data.entries()) {
|
|
52
63
|
const num = (data.pagination.page - 1) * data.pagination.limit + i + 1;
|
|
53
|
-
const
|
|
64
|
+
const artistStr = r.artists.join(', ');
|
|
54
65
|
const year = r.year ? ` (${r.year})` : '';
|
|
55
|
-
const
|
|
66
|
+
const formatStr = r.format_detail
|
|
56
67
|
? ` [${r.format_detail}]`
|
|
57
68
|
: ` [${r.format}]`;
|
|
58
|
-
lines.push(`${num}. ${
|
|
69
|
+
lines.push(`${num}. [ID: ${r.id}] ${artistStr} -- ${r.title}${year}${formatStr} (${r.label})`);
|
|
59
70
|
}
|
|
60
71
|
if (data.pagination.total_pages > data.pagination.page) {
|
|
61
72
|
lines.push(`\nPage ${data.pagination.page} of ${data.pagination.total_pages}. Use page=${data.pagination.page + 1} to see more.`);
|
|
62
73
|
}
|
|
63
|
-
|
|
74
|
+
const topN = data.data.slice(0, TOP_N);
|
|
75
|
+
const images = include_images
|
|
76
|
+
? await Promise.all(topN.map((r) => imageBlock(client, r.image, LIST_IMAGE_PX)))
|
|
77
|
+
: [];
|
|
78
|
+
const links = topN
|
|
79
|
+
.map((r) => resourceLink(r.discogs_url, `Discogs -- ${r.title}`, {
|
|
80
|
+
mimeType: 'text/html',
|
|
81
|
+
}))
|
|
82
|
+
.filter((b) => b !== null);
|
|
83
|
+
const content = [
|
|
84
|
+
text(lines.join('\n')),
|
|
85
|
+
...images.filter((b) => b !== null),
|
|
86
|
+
...links,
|
|
87
|
+
];
|
|
88
|
+
return {
|
|
89
|
+
content,
|
|
90
|
+
structuredContent: { items: data.data, pagination: data.pagination },
|
|
91
|
+
};
|
|
64
92
|
}));
|
|
65
|
-
// get_collecting_stats
|
|
66
|
-
server.tool('get_collecting_stats', 'Get overall collection statistics including total items, format breakdown (vinyl, CD, cassette), unique artists, genre data, and year range. Supports date filtering.', { ...dateFilterParams }, READ_ONLY_ANNOTATIONS, async ({ date, from, to }) =>
|
|
67
|
-
const { data } = await client.get('/collecting/stats', {
|
|
93
|
+
// get_collecting_stats ───────────────────────────────────────────
|
|
94
|
+
server.tool('get_collecting_stats', 'Get overall collection statistics including total items, format breakdown (vinyl, CD, cassette), unique artists, genre data, and year range. Supports date filtering.', { ...dateFilterParams }, READ_ONLY_ANNOTATIONS, async ({ date, from, to }) => withRichResponse(async () => {
|
|
95
|
+
const { data } = await client.get('/collecting/stats', {
|
|
96
|
+
date,
|
|
97
|
+
from,
|
|
98
|
+
to,
|
|
99
|
+
});
|
|
68
100
|
const lines = [
|
|
69
101
|
'Collection Stats:',
|
|
70
102
|
`- Total items: ${fmt(data.total_items)}`,
|
|
@@ -86,10 +118,10 @@ export function registerCollectingTools(server, client) {
|
|
|
86
118
|
}
|
|
87
119
|
if (data.added_this_year)
|
|
88
120
|
lines.push(`- Added this year: ${data.added_this_year}`);
|
|
89
|
-
return lines.join('\n');
|
|
121
|
+
return { content: [text(lines.join('\n'))], structuredContent: data };
|
|
90
122
|
}));
|
|
91
|
-
// get_physical_media
|
|
92
|
-
server.tool('get_physical_media', 'Browse the physical media collection (Blu-ray, 4K UHD, HD DVD). Search by title, filter by format.
|
|
123
|
+
// get_physical_media ─────────────────────────────────────────────
|
|
124
|
+
server.tool('get_physical_media', 'Browse the physical media collection (Blu-ray, 4K UHD, HD DVD). Search by title, filter by format. Returns top-N cover art and pagination.', {
|
|
93
125
|
query: z
|
|
94
126
|
.string()
|
|
95
127
|
.optional()
|
|
@@ -105,17 +137,17 @@ export function registerCollectingTools(server, client) {
|
|
|
105
137
|
.default(10)
|
|
106
138
|
.describe('Number of items to return'),
|
|
107
139
|
page: z.number().min(1).default(1).describe('Page number for pagination'),
|
|
108
|
-
|
|
140
|
+
...includeImagesParam,
|
|
141
|
+
}, READ_ONLY_ANNOTATIONS, async ({ query, media_type, limit, page, include_images }) => withRichResponse(async () => {
|
|
109
142
|
const data = await client.get('/collecting/media', { q: query, media_type, limit, page });
|
|
110
|
-
if (!data.data.length)
|
|
111
|
-
return
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
};
|
|
143
|
+
if (!data.data.length) {
|
|
144
|
+
return {
|
|
145
|
+
content: [text('No physical media found.')],
|
|
146
|
+
structuredContent: { items: [], pagination: data.pagination },
|
|
147
|
+
};
|
|
148
|
+
}
|
|
117
149
|
const header = media_type
|
|
118
|
-
? `${
|
|
150
|
+
? `${FORMAT_LABEL[media_type] ?? media_type} Collection`
|
|
119
151
|
: 'Physical Media Collection';
|
|
120
152
|
const lines = [
|
|
121
153
|
`${header} (page ${data.pagination.page} of ${data.pagination.total_pages}, ${fmt(data.pagination.total)} total):`,
|
|
@@ -123,20 +155,26 @@ export function registerCollectingTools(server, client) {
|
|
|
123
155
|
for (const [i, m] of data.data.entries()) {
|
|
124
156
|
const num = (data.pagination.page - 1) * data.pagination.limit + i + 1;
|
|
125
157
|
const year = m.year ? ` (${m.year})` : '';
|
|
126
|
-
const
|
|
158
|
+
const formatStr = ` [${FORMAT_LABEL[m.media_type] ?? m.media_type}]`;
|
|
127
159
|
const rating = m.tmdb_rating ? ` -- ${m.tmdb_rating}/10` : '';
|
|
128
|
-
lines.push(`${num}. ${m.title}${year}${
|
|
160
|
+
lines.push(`${num}. [ID: ${m.id}] ${m.title}${year}${formatStr}${rating}`);
|
|
129
161
|
}
|
|
130
|
-
|
|
162
|
+
const topN = data.data.slice(0, TOP_N);
|
|
163
|
+
const images = include_images
|
|
164
|
+
? await Promise.all(topN.map((m) => imageBlock(client, m.image, LIST_IMAGE_PX)))
|
|
165
|
+
: [];
|
|
166
|
+
const content = [
|
|
167
|
+
text(lines.join('\n')),
|
|
168
|
+
...images.filter((b) => b !== null),
|
|
169
|
+
];
|
|
170
|
+
return {
|
|
171
|
+
content,
|
|
172
|
+
structuredContent: { items: data.data, pagination: data.pagination },
|
|
173
|
+
};
|
|
131
174
|
}));
|
|
132
|
-
// get_physical_media_stats
|
|
133
|
-
server.tool('get_physical_media_stats', 'Get statistics for the physical media collection including total items and breakdown by format (Blu-ray, 4K UHD, HD DVD).', {}, READ_ONLY_ANNOTATIONS, async () =>
|
|
175
|
+
// get_physical_media_stats ───────────────────────────────────────
|
|
176
|
+
server.tool('get_physical_media_stats', 'Get statistics for the physical media collection including total items and breakdown by format (Blu-ray, 4K UHD, HD DVD).', {}, READ_ONLY_ANNOTATIONS, async () => withRichResponse(async () => {
|
|
134
177
|
const { data } = await client.get('/collecting/media/formats');
|
|
135
|
-
const formatLabel = {
|
|
136
|
-
bluray: 'Blu-ray',
|
|
137
|
-
uhd_bluray: '4K UHD',
|
|
138
|
-
hddvd: 'HD DVD',
|
|
139
|
-
};
|
|
140
178
|
const total = data.reduce((sum, f) => sum + f.count, 0);
|
|
141
179
|
const lines = [
|
|
142
180
|
'Physical Media Stats:',
|
|
@@ -145,9 +183,12 @@ export function registerCollectingTools(server, client) {
|
|
|
145
183
|
'By format:',
|
|
146
184
|
];
|
|
147
185
|
for (const f of data) {
|
|
148
|
-
lines.push(` ${
|
|
186
|
+
lines.push(` ${FORMAT_LABEL[f.name] ?? f.name}: ${fmt(f.count)}`);
|
|
149
187
|
}
|
|
150
|
-
return
|
|
188
|
+
return {
|
|
189
|
+
content: [text(lines.join('\n'))],
|
|
190
|
+
structuredContent: { total, formats: data },
|
|
191
|
+
};
|
|
151
192
|
}));
|
|
152
193
|
}
|
|
153
194
|
//# sourceMappingURL=collecting.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collecting.js","sourceRoot":"","sources":["../../src/tools/collecting.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EACL,
|
|
1
|
+
{"version":3,"file":"collecting.js","sourceRoot":"","sources":["../../src/tools/collecting.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,8 +1,29 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import {
|
|
2
|
+
import { withRichResponse, text, resourceLink, timeAgo, fmt, READ_ONLY_ANNOTATIONS, } from './helpers.js';
|
|
3
|
+
/**
|
|
4
|
+
* Map a cross-domain entity reference to a Rewind resource URI.
|
|
5
|
+
* Returns null when the entity type has no registered resource template.
|
|
6
|
+
*/
|
|
7
|
+
function rewindUri(domain, entityType, entityId) {
|
|
8
|
+
if (!entityId)
|
|
9
|
+
return null;
|
|
10
|
+
const map = {
|
|
11
|
+
'listening:artist': 'artist',
|
|
12
|
+
'listening:album': 'album',
|
|
13
|
+
'watching:movie': 'movie',
|
|
14
|
+
'watching:show': 'show',
|
|
15
|
+
'collecting:vinyl': 'vinyl',
|
|
16
|
+
'collecting:release': 'vinyl',
|
|
17
|
+
'collecting:media': 'physical-media',
|
|
18
|
+
'reading:article': 'article',
|
|
19
|
+
'running:activity': 'activity',
|
|
20
|
+
};
|
|
21
|
+
const kind = map[`${domain}:${entityType}`];
|
|
22
|
+
return kind ? `rewind://${kind}/${entityId}` : null;
|
|
23
|
+
}
|
|
3
24
|
export function registerCrossDomainTools(server, client) {
|
|
4
|
-
// search
|
|
5
|
-
server.tool('search', 'Search across all domains (listening, running, watching, collecting, reading) using full-text search. Returns matching artists, albums, movies, articles, runs,
|
|
25
|
+
// search ─────────────────────────────────────────────────────────
|
|
26
|
+
server.tool('search', 'Search across all domains (listening, running, watching, collecting, reading) using full-text search. Returns matching artists, albums, movies, articles, runs, etc., plus rewind:// resource links to fetch full detail on each.', {
|
|
6
27
|
query: z.string().describe('Search query text'),
|
|
7
28
|
domain: z
|
|
8
29
|
.enum(['listening', 'running', 'watching', 'collecting', 'reading'])
|
|
@@ -15,7 +36,7 @@ export function registerCrossDomainTools(server, client) {
|
|
|
15
36
|
.default(10)
|
|
16
37
|
.describe('Number of results to return'),
|
|
17
38
|
page: z.number().min(1).default(1).describe('Page number for pagination'),
|
|
18
|
-
}, READ_ONLY_ANNOTATIONS, async ({ query, domain, limit, page }) =>
|
|
39
|
+
}, READ_ONLY_ANNOTATIONS, async ({ query, domain, limit, page }) => withRichResponse(async () => {
|
|
19
40
|
const params = {
|
|
20
41
|
q: query,
|
|
21
42
|
limit,
|
|
@@ -24,8 +45,14 @@ export function registerCrossDomainTools(server, client) {
|
|
|
24
45
|
if (domain)
|
|
25
46
|
params.domain = domain;
|
|
26
47
|
const data = await client.get('/search', params);
|
|
27
|
-
if (!data.data.length)
|
|
28
|
-
return
|
|
48
|
+
if (!data.data.length) {
|
|
49
|
+
return {
|
|
50
|
+
content: [
|
|
51
|
+
text(`No results found for "${query}"${domain ? ` in ${domain}` : ''}.`),
|
|
52
|
+
],
|
|
53
|
+
structuredContent: { items: [], pagination: data.pagination },
|
|
54
|
+
};
|
|
55
|
+
}
|
|
29
56
|
const lines = [
|
|
30
57
|
`Search results for "${query}" (${fmt(data.pagination.total)} total):`,
|
|
31
58
|
];
|
|
@@ -33,9 +60,25 @@ export function registerCrossDomainTools(server, client) {
|
|
|
33
60
|
const sub = r.subtitle ? ` -- ${r.subtitle}` : '';
|
|
34
61
|
lines.push(`${i + 1}. [${r.domain}/${r.entity_type}] ${r.title}${sub}`);
|
|
35
62
|
}
|
|
36
|
-
|
|
63
|
+
// Emit one resource_link per result that maps to a known entity.
|
|
64
|
+
const links = data.data
|
|
65
|
+
.map((r) => {
|
|
66
|
+
const uri = rewindUri(r.domain, r.entity_type, r.entity_id);
|
|
67
|
+
if (!uri)
|
|
68
|
+
return null;
|
|
69
|
+
return resourceLink(uri, r.title, {
|
|
70
|
+
mimeType: 'application/json',
|
|
71
|
+
description: r.subtitle ?? undefined,
|
|
72
|
+
});
|
|
73
|
+
})
|
|
74
|
+
.filter((b) => b !== null);
|
|
75
|
+
const content = [text(lines.join('\n')), ...links];
|
|
76
|
+
return {
|
|
77
|
+
content,
|
|
78
|
+
structuredContent: { items: data.data, pagination: data.pagination },
|
|
79
|
+
};
|
|
37
80
|
}));
|
|
38
|
-
// get_feed
|
|
81
|
+
// get_feed ───────────────────────────────────────────────────────
|
|
39
82
|
server.tool('get_feed', 'Get the unified activity feed across all domains. Returns a chronological list of recent activities (listens, runs, watches, reads, collection adds). Supports date filtering.', {
|
|
40
83
|
limit: z
|
|
41
84
|
.number()
|
|
@@ -59,7 +102,7 @@ export function registerCrossDomainTools(server, client) {
|
|
|
59
102
|
.string()
|
|
60
103
|
.optional()
|
|
61
104
|
.describe('Optional: end of date range (ISO 8601)'),
|
|
62
|
-
}, READ_ONLY_ANNOTATIONS, async ({ limit, domain, date, from, to }) =>
|
|
105
|
+
}, READ_ONLY_ANNOTATIONS, async ({ limit, domain, date, from, to }) => withRichResponse(async () => {
|
|
63
106
|
const params = {
|
|
64
107
|
limit,
|
|
65
108
|
date,
|
|
@@ -68,8 +111,12 @@ export function registerCrossDomainTools(server, client) {
|
|
|
68
111
|
};
|
|
69
112
|
const path = domain ? `/feed/domain/${domain}` : '/feed';
|
|
70
113
|
const data = await client.get(path, params);
|
|
71
|
-
if (!data.data.length)
|
|
72
|
-
return
|
|
114
|
+
if (!data.data.length) {
|
|
115
|
+
return {
|
|
116
|
+
content: [text('No feed activity found for the given filters.')],
|
|
117
|
+
structuredContent: { items: [], pagination: data.pagination },
|
|
118
|
+
};
|
|
119
|
+
}
|
|
73
120
|
const lines = ['Activity Feed:'];
|
|
74
121
|
for (const item of data.data) {
|
|
75
122
|
const sub = item.subtitle ? ` -- ${item.subtitle}` : '';
|
|
@@ -78,9 +125,12 @@ export function registerCrossDomainTools(server, client) {
|
|
|
78
125
|
if (data.pagination.has_more) {
|
|
79
126
|
lines.push('\nMore items available. Increase limit or narrow date range.');
|
|
80
127
|
}
|
|
81
|
-
return
|
|
128
|
+
return {
|
|
129
|
+
content: [text(lines.join('\n'))],
|
|
130
|
+
structuredContent: { items: data.data, pagination: data.pagination },
|
|
131
|
+
};
|
|
82
132
|
}));
|
|
83
|
-
// get_on_this_day
|
|
133
|
+
// get_on_this_day ────────────────────────────────────────────────
|
|
84
134
|
server.tool('get_on_this_day', "Get historical 'on this day' items -- what happened on a given date in previous years across all domains. Defaults to today. Great for nostalgia and reflection.", {
|
|
85
135
|
month: z
|
|
86
136
|
.number()
|
|
@@ -94,11 +144,15 @@ export function registerCrossDomainTools(server, client) {
|
|
|
94
144
|
.max(31)
|
|
95
145
|
.optional()
|
|
96
146
|
.describe('Optional: day (1-31). Defaults to current day.'),
|
|
97
|
-
}, READ_ONLY_ANNOTATIONS, async ({ month, day }) =>
|
|
147
|
+
}, READ_ONLY_ANNOTATIONS, async ({ month, day }) => withRichResponse(async () => {
|
|
98
148
|
const params = { month, day };
|
|
99
149
|
const data = await client.get('/feed/on-this-day', params);
|
|
100
|
-
if (!data.years.length)
|
|
101
|
-
return
|
|
150
|
+
if (!data.years.length) {
|
|
151
|
+
return {
|
|
152
|
+
content: [text("No 'on this day' history found.")],
|
|
153
|
+
structuredContent: data,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
102
156
|
const lines = [`On This Day (${data.month}/${data.day}):`];
|
|
103
157
|
for (const yearGroup of data.years) {
|
|
104
158
|
lines.push('');
|
|
@@ -108,7 +162,10 @@ export function registerCrossDomainTools(server, client) {
|
|
|
108
162
|
lines.push(` - [${item.domain}] ${item.title}${sub}`);
|
|
109
163
|
}
|
|
110
164
|
}
|
|
111
|
-
return
|
|
165
|
+
return {
|
|
166
|
+
content: [text(lines.join('\n'))],
|
|
167
|
+
structuredContent: data,
|
|
168
|
+
};
|
|
112
169
|
}));
|
|
113
170
|
}
|
|
114
171
|
//# sourceMappingURL=cross-domain.js.map
|