markdown-new-mcp 1.0.0 → 1.0.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.
@@ -0,0 +1 @@
1
+ 98229
@@ -127,3 +127,23 @@
127
127
  - README 中的 npx 使用方式不可用,因为包未发布到 npm,只推送到了 GitHub
128
128
  - 尝试用 npm token 发布失败,需要带有 bypass 2FA 权限的 Granular Access Token
129
129
 
130
+
131
+ ## Session 13:04
132
+
133
+ ### 13:04
134
+ <!-- session:e002accd-e739-4d6b-b854-87ea20879102 turn:f901dfd3-b7d1-4d72-887f-0cee0e74d7fb transcript:/Volumes/JJZ/jerryjiang/.claude/projects/-Volumes-JJZ-jerryjiang-unicom-dev-markdown-new-mcp/e002accd-e739-4d6b-b854-87ea20879102.jsonl -->
135
+ - 将 markdown-new-mcp MCP 服务器部署到 ms 服务器 (64.69.41.84),修改 `src/index.ts` 从 stdio 传输改为 SSE HTTP 传输
136
+ - 在服务器 `/opt/markdown-new-mcp` 目录部署项目,创建 systemd 服务监听端口 38721
137
+ - 创建本地包装脚本 `~/.local/bin/markdown-new-mcp`,通过 SSH 直接执行远程 stdio 模式 MCP
138
+ - 在 `~/.claude/settings.json` 添加 `mcpServers` 配置指向本地脚本
139
+ - SSE 支持修改已提交推送: `b4056e2 Add SSE transport support for remote deployment`
140
+ - README 中的 npx 使用方式不可用,因为包未发布到 npm,只推送到了 GitHub
141
+ - 尝试用 npm token 发布失败,需要带有 bypass 2FA 权限的 Granular Access Token
142
+ - 使用第二个 npm token 成功发布: `markdown-new-mcp@1.0.0`
143
+
144
+
145
+ ## Session 13:09
146
+
147
+
148
+ ## Session 13:09
149
+
package/README.md CHANGED
@@ -27,7 +27,7 @@ Add to your Claude Desktop config (`~/Library/Application Support/Claude/claude_
27
27
 
28
28
  ### With API Key (Optional)
29
29
 
30
- For higher rate limits, you can provide an API key:
30
+ For higher rate limits, you can provide an API key via environment variable:
31
31
 
32
32
  ```json
33
33
  {
@@ -43,6 +43,9 @@ For higher rate limits, you can provide an API key:
43
43
  }
44
44
  ```
45
45
 
46
+ Optional:
47
+ - `MARKDOWN_NEW_TIMEOUT_MS`: request timeout in milliseconds for upstream API calls (default: `30000`)
48
+
46
49
  ## Available Tools
47
50
 
48
51
  ### `convert_url_to_markdown`
@@ -51,7 +54,7 @@ Convert a remote file URL to Markdown.
51
54
 
52
55
  **Parameters:**
53
56
  - `url` (string, required): The URL of the remote file to convert
54
- - `api_key` (string, optional): API key for higher rate limits
57
+ - `api_key` (string, optional): API key for higher rate limits (if omitted, uses `MARKDOWN_NEW_API_KEY` when available)
55
58
 
56
59
  **Example:**
57
60
  ```
@@ -64,7 +67,7 @@ Convert a local file to Markdown.
64
67
 
65
68
  **Parameters:**
66
69
  - `file_path` (string, required): The absolute path to the local file
67
- - `api_key` (string, optional): API key for higher rate limits
70
+ - `api_key` (string, optional): API key for higher rate limits (if omitted, uses `MARKDOWN_NEW_API_KEY` when available)
68
71
 
69
72
  **Example:**
70
73
  ```
@@ -77,7 +80,7 @@ Convert a remote file URL to JSON with metadata (title, tokens, duration, etc).
77
80
 
78
81
  **Parameters:**
79
82
  - `url` (string, required): The URL of the remote file
80
- - `api_key` (string, optional): API key for higher rate limits
83
+ - `api_key` (string, optional): API key for higher rate limits (if omitted, uses `MARKDOWN_NEW_API_KEY` when available)
81
84
 
82
85
  ## Supported Formats
83
86
 
package/dist/index.js CHANGED
@@ -5,9 +5,51 @@ import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
5
5
  import { z } from "zod";
6
6
  import fs from "fs/promises";
7
7
  import path from "path";
8
- import { statSync } from "fs";
9
8
  import http from "http";
10
9
  const MARKDOWN_NEW_BASE_URL = "https://markdown.new";
10
+ const MAX_FILE_SIZE_BYTES = 10 * 1024 * 1024;
11
+ const DEFAULT_REQUEST_TIMEOUT_MS = 30000;
12
+ const REQUEST_TIMEOUT_MS = parsePositiveInteger(process.env.MARKDOWN_NEW_TIMEOUT_MS, DEFAULT_REQUEST_TIMEOUT_MS);
13
+ function parsePositiveInteger(value, fallback) {
14
+ if (!value) {
15
+ return fallback;
16
+ }
17
+ const parsed = Number.parseInt(value, 10);
18
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
19
+ }
20
+ function resolveApiKey(explicitApiKey) {
21
+ const apiKey = explicitApiKey?.trim() || process.env.MARKDOWN_NEW_API_KEY?.trim();
22
+ return apiKey ? apiKey : undefined;
23
+ }
24
+ function buildAuthHeaders(apiKey) {
25
+ const headers = {};
26
+ const resolvedApiKey = resolveApiKey(apiKey);
27
+ if (resolvedApiKey) {
28
+ headers["Authorization"] = `Bearer ${resolvedApiKey}`;
29
+ }
30
+ return headers;
31
+ }
32
+ async function fetchWithTimeout(input, init) {
33
+ const controller = new AbortController();
34
+ const timeout = setTimeout(() => {
35
+ controller.abort();
36
+ }, REQUEST_TIMEOUT_MS);
37
+ try {
38
+ return await fetch(input, {
39
+ ...init,
40
+ signal: controller.signal,
41
+ });
42
+ }
43
+ finally {
44
+ clearTimeout(timeout);
45
+ }
46
+ }
47
+ function toErrorMessage(error) {
48
+ if (error instanceof Error && error.name === "AbortError") {
49
+ return `Request timed out after ${REQUEST_TIMEOUT_MS}ms`;
50
+ }
51
+ return error instanceof Error ? error.message : String(error);
52
+ }
11
53
  function extractMarkdown(data) {
12
54
  if (typeof data === "string") {
13
55
  return data;
@@ -20,6 +62,17 @@ function extractMarkdown(data) {
20
62
  if (typeof obj.content === "string") {
21
63
  return obj.content;
22
64
  }
65
+ if (obj.data && typeof obj.data === "object") {
66
+ if (typeof obj.data.markdown === "string") {
67
+ return obj.data.markdown;
68
+ }
69
+ if (typeof obj.data.content === "string") {
70
+ return obj.data.content;
71
+ }
72
+ }
73
+ if (obj.success === false && typeof obj.error === "string") {
74
+ return `Conversion failed: ${obj.error}`;
75
+ }
23
76
  }
24
77
  return JSON.stringify(data, null, 2);
25
78
  }
@@ -30,18 +83,15 @@ function createServer() {
30
83
  });
31
84
  server.tool("convert_url_to_markdown", "Convert a remote file URL to Markdown. Supports PDF, DOCX, XLSX, images and 20+ formats. Maximum file size: 10MB.", {
32
85
  url: z.string().url().describe("The URL of the remote file to convert"),
33
- api_key: z.string().optional().describe("Optional API key for higher rate limits (format: mk_...)"),
86
+ api_key: z.string().optional().describe("Optional API key for higher rate limits (format: mk_..., falls back to MARKDOWN_NEW_API_KEY)"),
34
87
  }, async ({ url, api_key }) => {
35
88
  try {
36
- const headers = {
37
- "Content-Type": "application/json",
38
- };
39
- if (api_key) {
40
- headers["Authorization"] = `Bearer ${api_key}`;
41
- }
42
- const response = await fetch(MARKDOWN_NEW_BASE_URL, {
89
+ const response = await fetchWithTimeout(MARKDOWN_NEW_BASE_URL, {
43
90
  method: "POST",
44
- headers,
91
+ headers: {
92
+ "Content-Type": "application/json",
93
+ ...buildAuthHeaders(api_key),
94
+ },
45
95
  body: JSON.stringify({ url }),
46
96
  });
47
97
  if (!response.ok) {
@@ -68,7 +118,7 @@ function createServer() {
68
118
  };
69
119
  }
70
120
  catch (error) {
71
- const errorMessage = error instanceof Error ? error.message : String(error);
121
+ const errorMessage = toErrorMessage(error);
72
122
  return {
73
123
  content: [
74
124
  {
@@ -82,12 +132,23 @@ function createServer() {
82
132
  });
83
133
  server.tool("convert_file_to_markdown", "Convert a local file to Markdown. Supports PDF, DOCX, XLSX, images and 20+ formats. Maximum file size: 10MB.", {
84
134
  file_path: z.string().describe("The absolute path to the local file to convert"),
85
- api_key: z.string().optional().describe("Optional API key for higher rate limits (format: mk_...)"),
135
+ api_key: z.string().optional().describe("Optional API key for higher rate limits (format: mk_..., falls back to MARKDOWN_NEW_API_KEY)"),
86
136
  }, async ({ file_path, api_key }) => {
137
+ let fileHandle;
87
138
  try {
88
- let fileStats;
139
+ if (!path.isAbsolute(file_path)) {
140
+ return {
141
+ content: [
142
+ {
143
+ type: "text",
144
+ text: `file_path must be an absolute path: ${file_path}`,
145
+ },
146
+ ],
147
+ isError: true,
148
+ };
149
+ }
89
150
  try {
90
- fileStats = statSync(file_path);
151
+ fileHandle = await fs.open(file_path, "r");
91
152
  }
92
153
  catch {
93
154
  return {
@@ -100,8 +161,19 @@ function createServer() {
100
161
  isError: true,
101
162
  };
102
163
  }
103
- const MAX_FILE_SIZE = 10 * 1024 * 1024;
104
- if (fileStats.size > MAX_FILE_SIZE) {
164
+ const fileStats = await fileHandle.stat();
165
+ if (!fileStats.isFile()) {
166
+ return {
167
+ content: [
168
+ {
169
+ type: "text",
170
+ text: `Path is not a file: ${file_path}`,
171
+ },
172
+ ],
173
+ isError: true,
174
+ };
175
+ }
176
+ if (fileStats.size > MAX_FILE_SIZE_BYTES) {
105
177
  return {
106
178
  content: [
107
179
  {
@@ -112,18 +184,25 @@ function createServer() {
112
184
  isError: true,
113
185
  };
114
186
  }
115
- const fileContent = await fs.readFile(file_path);
187
+ const fileContent = await fileHandle.readFile();
188
+ if (fileContent.length > MAX_FILE_SIZE_BYTES) {
189
+ return {
190
+ content: [
191
+ {
192
+ type: "text",
193
+ text: `File too large after read: ${file_path} (${(fileContent.length / 1024 / 1024).toFixed(2)}MB). Maximum size is 10MB.`,
194
+ },
195
+ ],
196
+ isError: true,
197
+ };
198
+ }
116
199
  const fileName = path.basename(file_path);
117
200
  const formData = new FormData();
118
201
  const blob = new Blob([fileContent]);
119
202
  formData.append("file", blob, fileName);
120
- const headers = {};
121
- if (api_key) {
122
- headers["Authorization"] = `Bearer ${api_key}`;
123
- }
124
- const response = await fetch(`${MARKDOWN_NEW_BASE_URL}/convert`, {
203
+ const response = await fetchWithTimeout(`${MARKDOWN_NEW_BASE_URL}/convert`, {
125
204
  method: "POST",
126
- headers,
205
+ headers: buildAuthHeaders(api_key),
127
206
  body: formData,
128
207
  });
129
208
  if (!response.ok) {
@@ -150,7 +229,7 @@ function createServer() {
150
229
  };
151
230
  }
152
231
  catch (error) {
153
- const errorMessage = error instanceof Error ? error.message : String(error);
232
+ const errorMessage = toErrorMessage(error);
154
233
  return {
155
234
  content: [
156
235
  {
@@ -161,21 +240,24 @@ function createServer() {
161
240
  isError: true,
162
241
  };
163
242
  }
243
+ finally {
244
+ if (fileHandle) {
245
+ await fileHandle.close().catch(() => undefined);
246
+ }
247
+ }
164
248
  });
165
249
  server.tool("convert_url_to_json", "Convert a remote file URL to JSON with metadata (title, tokens, duration, etc). Supports PDF, DOCX, XLSX, images and 20+ formats.", {
166
250
  url: z.string().url().describe("The URL of the remote file to convert"),
167
- api_key: z.string().optional().describe("Optional API key for higher rate limits (format: mk_...)"),
251
+ api_key: z.string().optional().describe("Optional API key for higher rate limits (format: mk_..., falls back to MARKDOWN_NEW_API_KEY)"),
168
252
  }, async ({ url, api_key }) => {
169
253
  try {
170
- const encodedUrl = encodeURIComponent(url);
171
- const requestUrl = `${MARKDOWN_NEW_BASE_URL}/${encodedUrl}?format=json`;
172
- const headers = {};
173
- if (api_key) {
174
- headers["Authorization"] = `Bearer ${api_key}`;
175
- }
176
- const response = await fetch(requestUrl, {
177
- method: "GET",
178
- headers,
254
+ const response = await fetchWithTimeout(MARKDOWN_NEW_BASE_URL, {
255
+ method: "POST",
256
+ headers: {
257
+ "Content-Type": "application/json",
258
+ ...buildAuthHeaders(api_key),
259
+ },
260
+ body: JSON.stringify({ url, format: "json" }),
179
261
  });
180
262
  if (!response.ok) {
181
263
  const errorText = await response.text();
@@ -200,7 +282,7 @@ function createServer() {
200
282
  };
201
283
  }
202
284
  catch (error) {
203
- const errorMessage = error instanceof Error ? error.message : String(error);
285
+ const errorMessage = toErrorMessage(error);
204
286
  return {
205
287
  content: [
206
288
  {
@@ -220,33 +302,79 @@ async function runStdio() {
220
302
  await server.connect(transport);
221
303
  }
222
304
  async function runSSE(port) {
305
+ const transports = new Map();
306
+ const servers = new Map();
223
307
  const httpServer = http.createServer(async (req, res) => {
224
- if (req.method === "GET" && req.url === "/health") {
308
+ const baseUrl = `http://${req.headers.host ?? "127.0.0.1"}`;
309
+ let requestUrl;
310
+ try {
311
+ requestUrl = new URL(req.url ?? "/", baseUrl);
312
+ }
313
+ catch {
314
+ res.writeHead(400, { "Content-Type": "text/plain" });
315
+ res.end("Invalid request URL");
316
+ return;
317
+ }
318
+ const pathname = requestUrl.pathname;
319
+ if (req.method === "GET" && pathname === "/health") {
225
320
  res.writeHead(200, { "Content-Type": "application/json" });
226
321
  res.end(JSON.stringify({ status: "ok", service: "markdown-new-mcp" }));
227
322
  return;
228
323
  }
229
- if (req.method === "GET" && req.url === "/sse") {
324
+ if (req.method === "GET" && pathname === "/sse") {
230
325
  const server = createServer();
231
326
  const transport = new SSEServerTransport("/message", res);
232
- await server.connect(transport);
327
+ const sessionId = transport.sessionId;
328
+ transports.set(sessionId, transport);
329
+ servers.set(sessionId, server);
330
+ transport.onclose = () => {
331
+ transports.delete(sessionId);
332
+ servers.delete(sessionId);
333
+ };
334
+ try {
335
+ await server.connect(transport);
336
+ }
337
+ catch (error) {
338
+ transports.delete(sessionId);
339
+ servers.delete(sessionId);
340
+ if (!res.headersSent) {
341
+ res.writeHead(500, { "Content-Type": "text/plain" });
342
+ res.end("Failed to establish SSE session");
343
+ }
344
+ console.error("Failed to establish SSE session:", error);
345
+ }
233
346
  return;
234
347
  }
235
- if (req.method === "POST" && req.url === "/message") {
236
- let body = "";
237
- req.on("data", (chunk) => {
238
- body += chunk.toString();
239
- });
240
- req.on("end", () => {
241
- res.writeHead(200, { "Content-Type": "application/json" });
242
- res.end(JSON.stringify({ received: true }));
243
- });
348
+ if (req.method === "POST" && pathname === "/message") {
349
+ const sessionId = requestUrl.searchParams.get("sessionId");
350
+ if (!sessionId) {
351
+ res.writeHead(400, { "Content-Type": "text/plain" });
352
+ res.end("Missing sessionId");
353
+ return;
354
+ }
355
+ const transport = transports.get(sessionId);
356
+ if (!transport) {
357
+ res.writeHead(404, { "Content-Type": "text/plain" });
358
+ res.end("Session not found");
359
+ return;
360
+ }
361
+ try {
362
+ await transport.handlePostMessage(req, res);
363
+ }
364
+ catch (error) {
365
+ if (!res.headersSent) {
366
+ res.writeHead(500, { "Content-Type": "text/plain" });
367
+ res.end("Failed to handle message");
368
+ }
369
+ console.error("SSE message handling failed:", error);
370
+ }
244
371
  return;
245
372
  }
246
373
  res.writeHead(404);
247
374
  res.end("Not Found");
248
375
  });
249
- return new Promise((resolve) => {
376
+ return new Promise((resolve, reject) => {
377
+ httpServer.once("error", reject);
250
378
  httpServer.listen(port, "0.0.0.0", () => {
251
379
  console.log(`MCP SSE Server running on http://0.0.0.0:${port}`);
252
380
  console.log(`Health check: http://0.0.0.0:${port}/health`);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "markdown-new-mcp",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "MCP server for markdown.new file conversion API - convert PDF, DOCX, XLSX, images and 20+ formats to Markdown",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
package/src/index.ts CHANGED
@@ -4,26 +4,82 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
4
4
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5
5
  import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
6
6
  import { z } from "zod";
7
- import fs from "fs/promises";
7
+ import fs, { type FileHandle } from "fs/promises";
8
8
  import path from "path";
9
- import { statSync } from "fs";
10
9
  import http from "http";
11
10
 
12
11
  const MARKDOWN_NEW_BASE_URL = "https://markdown.new";
12
+ const MAX_FILE_SIZE_BYTES = 10 * 1024 * 1024;
13
+ const DEFAULT_REQUEST_TIMEOUT_MS = 30000;
14
+ const REQUEST_TIMEOUT_MS = parsePositiveInteger(process.env.MARKDOWN_NEW_TIMEOUT_MS, DEFAULT_REQUEST_TIMEOUT_MS);
13
15
 
14
16
  interface MarkdownResponse {
17
+ success?: boolean;
18
+ error?: string;
15
19
  markdown?: string;
16
20
  content?: string;
17
21
  title?: string;
18
22
  tokens?: number;
19
23
  duration?: number;
24
+ data?: {
25
+ markdown?: string;
26
+ content?: string;
27
+ [key: string]: unknown;
28
+ };
20
29
  [key: string]: unknown;
21
30
  }
22
31
 
32
+ function parsePositiveInteger(value: string | undefined, fallback: number): number {
33
+ if (!value) {
34
+ return fallback;
35
+ }
36
+
37
+ const parsed = Number.parseInt(value, 10);
38
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
39
+ }
40
+
41
+ function resolveApiKey(explicitApiKey?: string): string | undefined {
42
+ const apiKey = explicitApiKey?.trim() || process.env.MARKDOWN_NEW_API_KEY?.trim();
43
+ return apiKey ? apiKey : undefined;
44
+ }
45
+
46
+ function buildAuthHeaders(apiKey?: string): Record<string, string> {
47
+ const headers: Record<string, string> = {};
48
+ const resolvedApiKey = resolveApiKey(apiKey);
49
+ if (resolvedApiKey) {
50
+ headers["Authorization"] = `Bearer ${resolvedApiKey}`;
51
+ }
52
+ return headers;
53
+ }
54
+
55
+ async function fetchWithTimeout(input: string | URL, init: RequestInit): Promise<Response> {
56
+ const controller = new AbortController();
57
+ const timeout = setTimeout(() => {
58
+ controller.abort();
59
+ }, REQUEST_TIMEOUT_MS);
60
+
61
+ try {
62
+ return await fetch(input, {
63
+ ...init,
64
+ signal: controller.signal,
65
+ });
66
+ } finally {
67
+ clearTimeout(timeout);
68
+ }
69
+ }
70
+
71
+ function toErrorMessage(error: unknown): string {
72
+ if (error instanceof Error && error.name === "AbortError") {
73
+ return `Request timed out after ${REQUEST_TIMEOUT_MS}ms`;
74
+ }
75
+ return error instanceof Error ? error.message : String(error);
76
+ }
77
+
23
78
  function extractMarkdown(data: unknown): string {
24
79
  if (typeof data === "string") {
25
80
  return data;
26
81
  }
82
+
27
83
  if (typeof data === "object" && data !== null) {
28
84
  const obj = data as MarkdownResponse;
29
85
  if (typeof obj.markdown === "string") {
@@ -32,7 +88,19 @@ function extractMarkdown(data: unknown): string {
32
88
  if (typeof obj.content === "string") {
33
89
  return obj.content;
34
90
  }
91
+ if (obj.data && typeof obj.data === "object") {
92
+ if (typeof obj.data.markdown === "string") {
93
+ return obj.data.markdown;
94
+ }
95
+ if (typeof obj.data.content === "string") {
96
+ return obj.data.content;
97
+ }
98
+ }
99
+ if (obj.success === false && typeof obj.error === "string") {
100
+ return `Conversion failed: ${obj.error}`;
101
+ }
35
102
  }
103
+
36
104
  return JSON.stringify(data, null, 2);
37
105
  }
38
106
 
@@ -47,21 +115,16 @@ function createServer(): McpServer {
47
115
  "Convert a remote file URL to Markdown. Supports PDF, DOCX, XLSX, images and 20+ formats. Maximum file size: 10MB.",
48
116
  {
49
117
  url: z.string().url().describe("The URL of the remote file to convert"),
50
- api_key: z.string().optional().describe("Optional API key for higher rate limits (format: mk_...)"),
118
+ api_key: z.string().optional().describe("Optional API key for higher rate limits (format: mk_..., falls back to MARKDOWN_NEW_API_KEY)"),
51
119
  },
52
120
  async ({ url, api_key }) => {
53
121
  try {
54
- const headers: Record<string, string> = {
55
- "Content-Type": "application/json",
56
- };
57
-
58
- if (api_key) {
59
- headers["Authorization"] = `Bearer ${api_key}`;
60
- }
61
-
62
- const response = await fetch(MARKDOWN_NEW_BASE_URL, {
122
+ const response = await fetchWithTimeout(MARKDOWN_NEW_BASE_URL, {
63
123
  method: "POST",
64
- headers,
124
+ headers: {
125
+ "Content-Type": "application/json",
126
+ ...buildAuthHeaders(api_key),
127
+ },
65
128
  body: JSON.stringify({ url }),
66
129
  });
67
130
 
@@ -90,7 +153,7 @@ function createServer(): McpServer {
90
153
  ],
91
154
  };
92
155
  } catch (error) {
93
- const errorMessage = error instanceof Error ? error.message : String(error);
156
+ const errorMessage = toErrorMessage(error);
94
157
  return {
95
158
  content: [
96
159
  {
@@ -109,13 +172,26 @@ function createServer(): McpServer {
109
172
  "Convert a local file to Markdown. Supports PDF, DOCX, XLSX, images and 20+ formats. Maximum file size: 10MB.",
110
173
  {
111
174
  file_path: z.string().describe("The absolute path to the local file to convert"),
112
- api_key: z.string().optional().describe("Optional API key for higher rate limits (format: mk_...)"),
175
+ api_key: z.string().optional().describe("Optional API key for higher rate limits (format: mk_..., falls back to MARKDOWN_NEW_API_KEY)"),
113
176
  },
114
177
  async ({ file_path, api_key }) => {
178
+ let fileHandle: FileHandle | undefined;
179
+
115
180
  try {
116
- let fileStats;
181
+ if (!path.isAbsolute(file_path)) {
182
+ return {
183
+ content: [
184
+ {
185
+ type: "text" as const,
186
+ text: `file_path must be an absolute path: ${file_path}`,
187
+ },
188
+ ],
189
+ isError: true,
190
+ };
191
+ }
192
+
117
193
  try {
118
- fileStats = statSync(file_path);
194
+ fileHandle = await fs.open(file_path, "r");
119
195
  } catch {
120
196
  return {
121
197
  content: [
@@ -128,8 +204,20 @@ function createServer(): McpServer {
128
204
  };
129
205
  }
130
206
 
131
- const MAX_FILE_SIZE = 10 * 1024 * 1024;
132
- if (fileStats.size > MAX_FILE_SIZE) {
207
+ const fileStats = await fileHandle.stat();
208
+ if (!fileStats.isFile()) {
209
+ return {
210
+ content: [
211
+ {
212
+ type: "text" as const,
213
+ text: `Path is not a file: ${file_path}`,
214
+ },
215
+ ],
216
+ isError: true,
217
+ };
218
+ }
219
+
220
+ if (fileStats.size > MAX_FILE_SIZE_BYTES) {
133
221
  return {
134
222
  content: [
135
223
  {
@@ -141,22 +229,27 @@ function createServer(): McpServer {
141
229
  };
142
230
  }
143
231
 
144
- const fileContent = await fs.readFile(file_path);
145
- const fileName = path.basename(file_path);
232
+ const fileContent = await fileHandle.readFile();
233
+ if (fileContent.length > MAX_FILE_SIZE_BYTES) {
234
+ return {
235
+ content: [
236
+ {
237
+ type: "text" as const,
238
+ text: `File too large after read: ${file_path} (${(fileContent.length / 1024 / 1024).toFixed(2)}MB). Maximum size is 10MB.`,
239
+ },
240
+ ],
241
+ isError: true,
242
+ };
243
+ }
146
244
 
245
+ const fileName = path.basename(file_path);
147
246
  const formData = new FormData();
148
247
  const blob = new Blob([fileContent]);
149
248
  formData.append("file", blob, fileName);
150
249
 
151
- const headers: Record<string, string> = {};
152
-
153
- if (api_key) {
154
- headers["Authorization"] = `Bearer ${api_key}`;
155
- }
156
-
157
- const response = await fetch(`${MARKDOWN_NEW_BASE_URL}/convert`, {
250
+ const response = await fetchWithTimeout(`${MARKDOWN_NEW_BASE_URL}/convert`, {
158
251
  method: "POST",
159
- headers,
252
+ headers: buildAuthHeaders(api_key),
160
253
  body: formData,
161
254
  });
162
255
 
@@ -185,7 +278,7 @@ function createServer(): McpServer {
185
278
  ],
186
279
  };
187
280
  } catch (error) {
188
- const errorMessage = error instanceof Error ? error.message : String(error);
281
+ const errorMessage = toErrorMessage(error);
189
282
  return {
190
283
  content: [
191
284
  {
@@ -195,6 +288,10 @@ function createServer(): McpServer {
195
288
  ],
196
289
  isError: true,
197
290
  };
291
+ } finally {
292
+ if (fileHandle) {
293
+ await fileHandle.close().catch(() => undefined);
294
+ }
198
295
  }
199
296
  }
200
297
  );
@@ -204,22 +301,17 @@ function createServer(): McpServer {
204
301
  "Convert a remote file URL to JSON with metadata (title, tokens, duration, etc). Supports PDF, DOCX, XLSX, images and 20+ formats.",
205
302
  {
206
303
  url: z.string().url().describe("The URL of the remote file to convert"),
207
- api_key: z.string().optional().describe("Optional API key for higher rate limits (format: mk_...)"),
304
+ api_key: z.string().optional().describe("Optional API key for higher rate limits (format: mk_..., falls back to MARKDOWN_NEW_API_KEY)"),
208
305
  },
209
306
  async ({ url, api_key }) => {
210
307
  try {
211
- const encodedUrl = encodeURIComponent(url);
212
- const requestUrl = `${MARKDOWN_NEW_BASE_URL}/${encodedUrl}?format=json`;
213
-
214
- const headers: Record<string, string> = {};
215
-
216
- if (api_key) {
217
- headers["Authorization"] = `Bearer ${api_key}`;
218
- }
219
-
220
- const response = await fetch(requestUrl, {
221
- method: "GET",
222
- headers,
308
+ const response = await fetchWithTimeout(MARKDOWN_NEW_BASE_URL, {
309
+ method: "POST",
310
+ headers: {
311
+ "Content-Type": "application/json",
312
+ ...buildAuthHeaders(api_key),
313
+ },
314
+ body: JSON.stringify({ url, format: "json" }),
223
315
  });
224
316
 
225
317
  if (!response.ok) {
@@ -246,7 +338,7 @@ function createServer(): McpServer {
246
338
  ],
247
339
  };
248
340
  } catch (error) {
249
- const errorMessage = error instanceof Error ? error.message : String(error);
341
+ const errorMessage = toErrorMessage(error);
250
342
  return {
251
343
  content: [
252
344
  {
@@ -270,29 +362,82 @@ async function runStdio() {
270
362
  }
271
363
 
272
364
  async function runSSE(port: number) {
365
+ const transports = new Map<string, SSEServerTransport>();
366
+ const servers = new Map<string, McpServer>();
367
+
273
368
  const httpServer = http.createServer(async (req, res) => {
274
- if (req.method === "GET" && req.url === "/health") {
369
+ const baseUrl = `http://${req.headers.host ?? "127.0.0.1"}`;
370
+ let requestUrl: URL;
371
+
372
+ try {
373
+ requestUrl = new URL(req.url ?? "/", baseUrl);
374
+ } catch {
375
+ res.writeHead(400, { "Content-Type": "text/plain" });
376
+ res.end("Invalid request URL");
377
+ return;
378
+ }
379
+
380
+ const pathname = requestUrl.pathname;
381
+
382
+ if (req.method === "GET" && pathname === "/health") {
275
383
  res.writeHead(200, { "Content-Type": "application/json" });
276
384
  res.end(JSON.stringify({ status: "ok", service: "markdown-new-mcp" }));
277
385
  return;
278
386
  }
279
387
 
280
- if (req.method === "GET" && req.url === "/sse") {
388
+ if (req.method === "GET" && pathname === "/sse") {
281
389
  const server = createServer();
282
390
  const transport = new SSEServerTransport("/message", res);
283
- await server.connect(transport);
391
+ const sessionId = transport.sessionId;
392
+
393
+ transports.set(sessionId, transport);
394
+ servers.set(sessionId, server);
395
+
396
+ transport.onclose = () => {
397
+ transports.delete(sessionId);
398
+ servers.delete(sessionId);
399
+ };
400
+
401
+ try {
402
+ await server.connect(transport);
403
+ } catch (error) {
404
+ transports.delete(sessionId);
405
+ servers.delete(sessionId);
406
+
407
+ if (!res.headersSent) {
408
+ res.writeHead(500, { "Content-Type": "text/plain" });
409
+ res.end("Failed to establish SSE session");
410
+ }
411
+
412
+ console.error("Failed to establish SSE session:", error);
413
+ }
284
414
  return;
285
415
  }
286
416
 
287
- if (req.method === "POST" && req.url === "/message") {
288
- let body = "";
289
- req.on("data", (chunk) => {
290
- body += chunk.toString();
291
- });
292
- req.on("end", () => {
293
- res.writeHead(200, { "Content-Type": "application/json" });
294
- res.end(JSON.stringify({ received: true }));
295
- });
417
+ if (req.method === "POST" && pathname === "/message") {
418
+ const sessionId = requestUrl.searchParams.get("sessionId");
419
+ if (!sessionId) {
420
+ res.writeHead(400, { "Content-Type": "text/plain" });
421
+ res.end("Missing sessionId");
422
+ return;
423
+ }
424
+
425
+ const transport = transports.get(sessionId);
426
+ if (!transport) {
427
+ res.writeHead(404, { "Content-Type": "text/plain" });
428
+ res.end("Session not found");
429
+ return;
430
+ }
431
+
432
+ try {
433
+ await transport.handlePostMessage(req, res);
434
+ } catch (error) {
435
+ if (!res.headersSent) {
436
+ res.writeHead(500, { "Content-Type": "text/plain" });
437
+ res.end("Failed to handle message");
438
+ }
439
+ console.error("SSE message handling failed:", error);
440
+ }
296
441
  return;
297
442
  }
298
443
 
@@ -300,7 +445,8 @@ async function runSSE(port: number) {
300
445
  res.end("Not Found");
301
446
  });
302
447
 
303
- return new Promise<void>((resolve) => {
448
+ return new Promise<void>((resolve, reject) => {
449
+ httpServer.once("error", reject);
304
450
  httpServer.listen(port, "0.0.0.0", () => {
305
451
  console.log(`MCP SSE Server running on http://0.0.0.0:${port}`);
306
452
  console.log(`Health check: http://0.0.0.0:${port}/health`);