mr-magic-mcp-server 0.2.4 → 0.2.6
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/package.json
CHANGED
|
@@ -84,12 +84,25 @@ export function startHttpServer(options = {}) {
|
|
|
84
84
|
|
|
85
85
|
if (req.method === 'GET' && req.url.startsWith('/downloads/')) {
|
|
86
86
|
const segments = req.url.split('/');
|
|
87
|
-
const [, ,
|
|
88
|
-
|
|
89
|
-
//
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
87
|
+
const [, , idSegment, ...rest] = segments;
|
|
88
|
+
|
|
89
|
+
// Support two URL formats:
|
|
90
|
+
// flat: /downloads/export-xxx.srt → id=export-xxx, extension=srt
|
|
91
|
+
// compound: /downloads/export-xxx/romanized.srt → id=export-xxx, extension=romanized.srt
|
|
92
|
+
let downloadId, extension;
|
|
93
|
+
if (rest.length === 0 && idSegment && idSegment.includes('.')) {
|
|
94
|
+
// Flat format – extension is appended to the id with a dot.
|
|
95
|
+
const dotIdx = idSegment.lastIndexOf('.');
|
|
96
|
+
downloadId = idSegment.slice(0, dotIdx);
|
|
97
|
+
extension = idSegment.slice(dotIdx + 1);
|
|
98
|
+
} else {
|
|
99
|
+
// Compound / path-segment format.
|
|
100
|
+
downloadId = idSegment;
|
|
101
|
+
// Strip trailing human-readable filename (e.g. "artist-song.srt") when present.
|
|
102
|
+
const hasFilename = rest.length > 1 && rest[rest.length - 1].includes('.');
|
|
103
|
+
const extensionParts = hasFilename ? rest.slice(0, -1) : rest;
|
|
104
|
+
extension = extensionParts.join('/') || '';
|
|
105
|
+
}
|
|
93
106
|
if (!downloadId || !extension) {
|
|
94
107
|
logger.warn('Invalid download path', {
|
|
95
108
|
context: 'http-download',
|
|
@@ -134,8 +134,8 @@ export async function startMcpHttpServer(options = {}) {
|
|
|
134
134
|
});
|
|
135
135
|
|
|
136
136
|
// ── Export download endpoint ──────────────────────────────────────────────────
|
|
137
|
-
|
|
138
|
-
|
|
137
|
+
// Helper shared by both download route handlers.
|
|
138
|
+
async function serveDownload(downloadId, extension, res, url) {
|
|
139
139
|
if (!downloadId || !extension) {
|
|
140
140
|
res.status(400).json({ error: 'Invalid download path' });
|
|
141
141
|
return;
|
|
@@ -163,9 +163,28 @@ export async function startMcpHttpServer(options = {}) {
|
|
|
163
163
|
bytes: Buffer.byteLength(content)
|
|
164
164
|
});
|
|
165
165
|
} catch (error) {
|
|
166
|
-
logger.error('Download lookup failed', { error, url
|
|
166
|
+
logger.error('Download lookup failed', { error, url });
|
|
167
167
|
res.status(500).json({ error: 'Failed to fetch export' });
|
|
168
168
|
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Flat format: /downloads/export-xxx.srt → id=export-xxx, extension=srt
|
|
172
|
+
app.get('/downloads/:idWithExt', async (req, res) => {
|
|
173
|
+
const { idWithExt } = req.params;
|
|
174
|
+
if (!idWithExt || !idWithExt.includes('.')) {
|
|
175
|
+
res.status(400).json({ error: 'Invalid download path' });
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
const dotIdx = idWithExt.lastIndexOf('.');
|
|
179
|
+
const downloadId = idWithExt.slice(0, dotIdx);
|
|
180
|
+
const extension = idWithExt.slice(dotIdx + 1);
|
|
181
|
+
await serveDownload(downloadId, extension, res, req.originalUrl);
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
// Compound format: /downloads/export-xxx/romanized.srt → id=export-xxx, extension=romanized.srt
|
|
185
|
+
app.get('/downloads/:downloadId/:extension', async (req, res) => {
|
|
186
|
+
const { downloadId, extension } = req.params;
|
|
187
|
+
await serveDownload(downloadId, extension, res, req.originalUrl);
|
|
169
188
|
});
|
|
170
189
|
|
|
171
190
|
// ── Streamable HTTP transport (/mcp) ──────────────────────────────────────────
|
|
@@ -30,8 +30,11 @@ export default class RedisStorage {
|
|
|
30
30
|
|
|
31
31
|
const expiresAt = new Date(Date.now() + this.ttl * 1000).toISOString();
|
|
32
32
|
const base = this.downloadBaseUrl?.replace(/[\/]+$/, '') || '';
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
// Compound extensions (e.g. "romanized.srt") become a path segment;
|
|
34
|
+
// simple extensions (e.g. "srt") are appended directly to the id.
|
|
35
|
+
const url = extension.includes('.')
|
|
36
|
+
? `${base}/downloads/${id}/${extension}`
|
|
37
|
+
: `${base}/downloads/${id}.${extension}`;
|
|
35
38
|
return new ExportStorageResult({ url, expiresAt, skipped: false });
|
|
36
39
|
}
|
|
37
40
|
}
|