@just-every/mcp-read-website-fast 0.1.9 → 0.1.11
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 +20 -2
- package/bin/mcp-read-website.js +2 -2
- package/dist/serve-restart.d.ts +2 -0
- package/dist/serve-restart.js +105 -0
- package/dist/serve.js +130 -48
- package/dist/utils/logger.js +2 -2
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -86,7 +86,7 @@ Drop this into your client’s mcp.json (e.g. .vscode/mcp.json, ~/.cursor/mcp.js
|
|
|
86
86
|
|
|
87
87
|
### Available Tools
|
|
88
88
|
|
|
89
|
-
- `
|
|
89
|
+
- `read_website` - Fetches a webpage and converts it to clean markdown
|
|
90
90
|
- Parameters:
|
|
91
91
|
- `url` (required): The HTTP/HTTPS URL to fetch
|
|
92
92
|
- `depth` (optional): Crawl depth (0 = single page)
|
|
@@ -144,6 +144,22 @@ npm run dev fetch https://example.com --output both
|
|
|
144
144
|
npm run dev clear-cache
|
|
145
145
|
```
|
|
146
146
|
|
|
147
|
+
## Auto-Restart Feature
|
|
148
|
+
|
|
149
|
+
The MCP server includes automatic restart capability by default for improved reliability:
|
|
150
|
+
|
|
151
|
+
- Automatically restarts the server if it crashes
|
|
152
|
+
- Handles unhandled exceptions and promise rejections
|
|
153
|
+
- Implements exponential backoff (max 10 attempts in 1 minute)
|
|
154
|
+
- Logs all restart attempts for monitoring
|
|
155
|
+
- Gracefully handles shutdown signals (SIGINT, SIGTERM)
|
|
156
|
+
|
|
157
|
+
For development/debugging without auto-restart:
|
|
158
|
+
```bash
|
|
159
|
+
# Run directly without restart wrapper
|
|
160
|
+
npm run serve:dev
|
|
161
|
+
```
|
|
162
|
+
|
|
147
163
|
## Architecture
|
|
148
164
|
|
|
149
165
|
```
|
|
@@ -153,7 +169,9 @@ mcp/
|
|
|
153
169
|
│ ├── parser/ # DOM parsing, Readability, Turndown conversion
|
|
154
170
|
│ ├── cache/ # Disk-based caching with SHA-256 keys
|
|
155
171
|
│ ├── utils/ # Logger, chunker utilities
|
|
156
|
-
│
|
|
172
|
+
│ ├── index.ts # CLI entry point
|
|
173
|
+
│ ├── serve.ts # MCP server entry point
|
|
174
|
+
│ └── serve-restart.ts # Auto-restart wrapper
|
|
157
175
|
```
|
|
158
176
|
|
|
159
177
|
## Development
|
package/bin/mcp-read-website.js
CHANGED
|
@@ -18,7 +18,7 @@ async function main() {
|
|
|
18
18
|
if (distExists) {
|
|
19
19
|
// Use compiled JavaScript for production (fast startup)
|
|
20
20
|
if (command === 'serve') {
|
|
21
|
-
const servePath = join(__dirname, '..', 'dist', 'serve.js');
|
|
21
|
+
const servePath = join(__dirname, '..', 'dist', 'serve-restart.js');
|
|
22
22
|
await import(servePath);
|
|
23
23
|
} else {
|
|
24
24
|
const cliPath = join(__dirname, '..', 'dist', 'index.js');
|
|
@@ -30,7 +30,7 @@ async function main() {
|
|
|
30
30
|
await import('tsx/esm');
|
|
31
31
|
|
|
32
32
|
if (command === 'serve') {
|
|
33
|
-
const servePath = join(__dirname, '..', 'src', 'serve.ts');
|
|
33
|
+
const servePath = join(__dirname, '..', 'src', 'serve-restart.ts');
|
|
34
34
|
await import(servePath);
|
|
35
35
|
} else {
|
|
36
36
|
const cliPath = join(__dirname, '..', 'src', 'index.ts');
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { spawn } from 'child_process';
|
|
3
|
+
import { dirname, join } from 'path';
|
|
4
|
+
import { fileURLToPath } from 'url';
|
|
5
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
6
|
+
const MAX_RESTART_ATTEMPTS = 10;
|
|
7
|
+
const RESTART_WINDOW_MS = 60000;
|
|
8
|
+
const INITIAL_BACKOFF_MS = 1000;
|
|
9
|
+
const MAX_BACKOFF_MS = 30000;
|
|
10
|
+
let restartAttempts = [];
|
|
11
|
+
let currentBackoff = INITIAL_BACKOFF_MS;
|
|
12
|
+
const log = (level, message, ...args) => {
|
|
13
|
+
const timestamp = new Date().toISOString();
|
|
14
|
+
console.error(`[${timestamp}] [${level}] [restart-wrapper]`, message, ...args);
|
|
15
|
+
};
|
|
16
|
+
const cleanupRestartAttempts = () => {
|
|
17
|
+
const now = Date.now();
|
|
18
|
+
restartAttempts = restartAttempts.filter(timestamp => now - timestamp < RESTART_WINDOW_MS);
|
|
19
|
+
};
|
|
20
|
+
const shouldRestart = () => {
|
|
21
|
+
cleanupRestartAttempts();
|
|
22
|
+
if (restartAttempts.length >= MAX_RESTART_ATTEMPTS) {
|
|
23
|
+
log('ERROR', `Reached maximum restart attempts (${MAX_RESTART_ATTEMPTS}) within ${RESTART_WINDOW_MS}ms`);
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
return true;
|
|
27
|
+
};
|
|
28
|
+
const getBackoffDelay = () => {
|
|
29
|
+
const delay = Math.min(currentBackoff, MAX_BACKOFF_MS);
|
|
30
|
+
currentBackoff = Math.min(currentBackoff * 2, MAX_BACKOFF_MS);
|
|
31
|
+
return delay;
|
|
32
|
+
};
|
|
33
|
+
const resetBackoff = () => {
|
|
34
|
+
currentBackoff = INITIAL_BACKOFF_MS;
|
|
35
|
+
};
|
|
36
|
+
const startServer = () => {
|
|
37
|
+
log('INFO', 'Starting MCP server...');
|
|
38
|
+
const serverPath = join(__dirname, 'serve.js');
|
|
39
|
+
const child = spawn(process.execPath, [serverPath], {
|
|
40
|
+
stdio: 'inherit',
|
|
41
|
+
env: process.env,
|
|
42
|
+
});
|
|
43
|
+
let shuttingDown = false;
|
|
44
|
+
let restartTimer = null;
|
|
45
|
+
let startupTimer = setTimeout(() => {
|
|
46
|
+
log('INFO', 'Server started successfully');
|
|
47
|
+
resetBackoff();
|
|
48
|
+
}, 5000);
|
|
49
|
+
child.on('exit', (code, signal) => {
|
|
50
|
+
clearTimeout(startupTimer);
|
|
51
|
+
if (shuttingDown) {
|
|
52
|
+
log('INFO', 'Server stopped gracefully');
|
|
53
|
+
process.exit(0);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
if (code === 0) {
|
|
57
|
+
log('INFO', 'Server exited cleanly');
|
|
58
|
+
process.exit(0);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
log('WARN', `Server exited with code ${code}, signal ${signal}`);
|
|
62
|
+
if (!shouldRestart()) {
|
|
63
|
+
log('ERROR', 'Too many restart attempts, giving up');
|
|
64
|
+
process.exit(1);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
const backoffDelay = getBackoffDelay();
|
|
68
|
+
restartAttempts.push(Date.now());
|
|
69
|
+
log('INFO', `Restarting server in ${backoffDelay}ms (attempt ${restartAttempts.length}/${MAX_RESTART_ATTEMPTS})...`);
|
|
70
|
+
restartTimer = setTimeout(() => {
|
|
71
|
+
startServer();
|
|
72
|
+
}, backoffDelay);
|
|
73
|
+
});
|
|
74
|
+
child.on('error', (error) => {
|
|
75
|
+
log('ERROR', 'Failed to start server:', error);
|
|
76
|
+
process.exit(1);
|
|
77
|
+
});
|
|
78
|
+
const shutdown = (signal) => {
|
|
79
|
+
if (shuttingDown)
|
|
80
|
+
return;
|
|
81
|
+
shuttingDown = true;
|
|
82
|
+
log('INFO', `Received ${signal}, shutting down...`);
|
|
83
|
+
if (restartTimer) {
|
|
84
|
+
clearTimeout(restartTimer);
|
|
85
|
+
}
|
|
86
|
+
child.kill(signal);
|
|
87
|
+
setTimeout(() => {
|
|
88
|
+
log('WARN', 'Force killing child process');
|
|
89
|
+
child.kill('SIGKILL');
|
|
90
|
+
}, 5000);
|
|
91
|
+
};
|
|
92
|
+
process.on('SIGINT', () => shutdown('SIGINT'));
|
|
93
|
+
process.on('SIGTERM', () => shutdown('SIGTERM'));
|
|
94
|
+
};
|
|
95
|
+
process.on('uncaughtException', (error) => {
|
|
96
|
+
log('ERROR', 'Uncaught exception in restart wrapper:', error);
|
|
97
|
+
process.exit(1);
|
|
98
|
+
});
|
|
99
|
+
process.on('unhandledRejection', (reason) => {
|
|
100
|
+
log('ERROR', 'Unhandled rejection in restart wrapper:', reason);
|
|
101
|
+
process.exit(1);
|
|
102
|
+
});
|
|
103
|
+
log('INFO', 'MCP server restart wrapper starting...');
|
|
104
|
+
log('INFO', `Configuration: max attempts=${MAX_RESTART_ATTEMPTS}, window=${RESTART_WINDOW_MS}ms`);
|
|
105
|
+
startServer();
|
package/dist/serve.js
CHANGED
|
@@ -1,13 +1,23 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
console.error('[serve.ts] Process started, PID:', process.pid);
|
|
3
|
+
console.error('[serve.ts] Node version:', process.version);
|
|
4
|
+
console.error('[serve.ts] Current directory:', process.cwd());
|
|
2
5
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
3
6
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
7
|
import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
|
|
8
|
+
import { logger, LogLevel } from './utils/logger.js';
|
|
9
|
+
logger.setLevel(LogLevel.DEBUG);
|
|
10
|
+
logger.info('MCP Server starting up...');
|
|
11
|
+
logger.debug('Node version:', process.version);
|
|
12
|
+
logger.debug('Working directory:', process.cwd());
|
|
13
|
+
logger.debug('Environment:', { LOG_LEVEL: process.env.LOG_LEVEL });
|
|
5
14
|
process.stdin.on('error', () => { });
|
|
6
15
|
process.stdout.on('error', () => { });
|
|
7
16
|
process.stderr.on('error', () => { });
|
|
8
17
|
let fetchMarkdownModule;
|
|
9
18
|
let fsPromises;
|
|
10
19
|
let pathModule;
|
|
20
|
+
logger.debug('Creating MCP server instance...');
|
|
11
21
|
const server = new Server({
|
|
12
22
|
name: 'read-website-fast',
|
|
13
23
|
version: '0.1.0',
|
|
@@ -17,12 +27,13 @@ const server = new Server({
|
|
|
17
27
|
resources: {},
|
|
18
28
|
},
|
|
19
29
|
});
|
|
30
|
+
logger.info('MCP server instance created successfully');
|
|
20
31
|
server.onerror = error => {
|
|
21
|
-
|
|
32
|
+
logger.error('MCP Server Error:', error);
|
|
22
33
|
};
|
|
23
34
|
const READ_WEBSITE_TOOL = {
|
|
24
|
-
name: '
|
|
25
|
-
description: '
|
|
35
|
+
name: 'read_website',
|
|
36
|
+
description: 'Fast, token-efficient web content extraction - ideal for reading documentation, analyzing content, and gathering information from websites. Converts to clean Markdown while preserving links and structure.',
|
|
26
37
|
inputSchema: {
|
|
27
38
|
type: 'object',
|
|
28
39
|
properties: {
|
|
@@ -43,6 +54,13 @@ const READ_WEBSITE_TOOL = {
|
|
|
43
54
|
},
|
|
44
55
|
required: ['url'],
|
|
45
56
|
},
|
|
57
|
+
annotations: {
|
|
58
|
+
title: 'Read Website',
|
|
59
|
+
readOnlyHint: true,
|
|
60
|
+
destructiveHint: false,
|
|
61
|
+
idempotentHint: true,
|
|
62
|
+
openWorldHint: true,
|
|
63
|
+
},
|
|
46
64
|
};
|
|
47
65
|
const RESOURCES = [
|
|
48
66
|
{
|
|
@@ -58,25 +76,44 @@ const RESOURCES = [
|
|
|
58
76
|
description: 'Clear the cache directory',
|
|
59
77
|
},
|
|
60
78
|
];
|
|
61
|
-
server.setRequestHandler(ListToolsRequestSchema, async () =>
|
|
62
|
-
|
|
63
|
-
|
|
79
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
80
|
+
logger.debug('Received ListTools request');
|
|
81
|
+
const response = {
|
|
82
|
+
tools: [READ_WEBSITE_TOOL],
|
|
83
|
+
};
|
|
84
|
+
logger.debug('Returning tools:', response.tools.map(t => t.name));
|
|
85
|
+
return response;
|
|
86
|
+
});
|
|
64
87
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
65
|
-
|
|
66
|
-
|
|
88
|
+
logger.info('Received CallTool request:', request.params.name);
|
|
89
|
+
logger.debug('Request params:', JSON.stringify(request.params, null, 2));
|
|
90
|
+
if (request.params.name !== 'read_website') {
|
|
91
|
+
const error = `Unknown tool: ${request.params.name}`;
|
|
92
|
+
logger.error(error);
|
|
93
|
+
throw new Error(error);
|
|
67
94
|
}
|
|
68
95
|
try {
|
|
69
96
|
if (!fetchMarkdownModule) {
|
|
97
|
+
logger.debug('Lazy loading fetchMarkdown module...');
|
|
70
98
|
fetchMarkdownModule = await import('./internal/fetchMarkdown.js');
|
|
99
|
+
logger.info('fetchMarkdown module loaded successfully');
|
|
71
100
|
}
|
|
72
101
|
const args = request.params.arguments;
|
|
73
102
|
if (!args.url || typeof args.url !== 'string') {
|
|
74
103
|
throw new Error('URL parameter is required and must be a string');
|
|
75
104
|
}
|
|
105
|
+
logger.info(`Processing read request for URL: ${args.url}`);
|
|
106
|
+
logger.debug('Read parameters:', {
|
|
107
|
+
url: args.url,
|
|
108
|
+
depth: args.depth,
|
|
109
|
+
respectRobots: args.respectRobots,
|
|
110
|
+
});
|
|
111
|
+
logger.debug('Calling fetchMarkdown...');
|
|
76
112
|
const result = await fetchMarkdownModule.fetchMarkdown(args.url, {
|
|
77
113
|
depth: args.depth ?? 0,
|
|
78
114
|
respectRobots: args.respectRobots ?? true,
|
|
79
115
|
});
|
|
116
|
+
logger.info('Content fetched successfully');
|
|
80
117
|
if (result.error && result.markdown) {
|
|
81
118
|
return {
|
|
82
119
|
content: [
|
|
@@ -95,14 +132,24 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
95
132
|
};
|
|
96
133
|
}
|
|
97
134
|
catch (error) {
|
|
98
|
-
|
|
135
|
+
logger.error('Error fetching content:', error.message);
|
|
136
|
+
logger.debug('Error stack:', error.stack);
|
|
137
|
+
logger.debug('Error details:', {
|
|
138
|
+
name: error.name,
|
|
139
|
+
code: error.code,
|
|
140
|
+
...error,
|
|
141
|
+
});
|
|
99
142
|
throw new Error(`Failed to fetch content: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
100
143
|
}
|
|
101
144
|
});
|
|
102
|
-
server.setRequestHandler(ListResourcesRequestSchema, async () =>
|
|
103
|
-
|
|
104
|
-
|
|
145
|
+
server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
146
|
+
logger.debug('Received ListResources request');
|
|
147
|
+
return {
|
|
148
|
+
resources: RESOURCES,
|
|
149
|
+
};
|
|
150
|
+
});
|
|
105
151
|
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
152
|
+
logger.debug('Received ReadResource request:', request.params);
|
|
106
153
|
const uri = request.params.uri;
|
|
107
154
|
if (!fsPromises) {
|
|
108
155
|
fsPromises = await import('fs/promises');
|
|
@@ -190,49 +237,84 @@ server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
|
190
237
|
throw new Error(`Unknown resource: ${uri}`);
|
|
191
238
|
});
|
|
192
239
|
async function runServer() {
|
|
193
|
-
const transport = new StdioServerTransport();
|
|
194
|
-
transport.onerror = error => {
|
|
195
|
-
console.error('[Transport Error]', error);
|
|
196
|
-
};
|
|
197
|
-
process.on('SIGINT', async () => {
|
|
198
|
-
console.error('Received SIGINT, shutting down gracefully...');
|
|
199
|
-
await server.close();
|
|
200
|
-
process.exit(0);
|
|
201
|
-
});
|
|
202
|
-
process.on('SIGTERM', async () => {
|
|
203
|
-
console.error('Received SIGTERM, shutting down gracefully...');
|
|
204
|
-
await server.close();
|
|
205
|
-
process.exit(0);
|
|
206
|
-
});
|
|
207
|
-
process.on('uncaughtException', error => {
|
|
208
|
-
console.error('Uncaught exception:', error);
|
|
209
|
-
if (error && error.message && error.message.includes('EPIPE')) {
|
|
210
|
-
console.error('Pipe error detected, keeping server alive');
|
|
211
|
-
return;
|
|
212
|
-
}
|
|
213
|
-
process.exit(1);
|
|
214
|
-
});
|
|
215
|
-
process.on('unhandledRejection', (reason, promise) => {
|
|
216
|
-
console.error('Unhandled rejection at:', promise, 'reason:', reason);
|
|
217
|
-
});
|
|
218
|
-
process.stdin.on('end', () => {
|
|
219
|
-
console.error('Stdin closed, shutting down...');
|
|
220
|
-
process.exit(0);
|
|
221
|
-
});
|
|
222
|
-
process.stdin.on('error', error => {
|
|
223
|
-
console.error('Stdin error:', error);
|
|
224
|
-
});
|
|
225
240
|
try {
|
|
241
|
+
logger.info('Starting MCP server...');
|
|
242
|
+
logger.debug('Creating StdioServerTransport...');
|
|
243
|
+
const transport = new StdioServerTransport();
|
|
244
|
+
logger.debug('Transport created, connecting to server...');
|
|
245
|
+
transport.onerror = error => {
|
|
246
|
+
logger.error('Transport Error:', error);
|
|
247
|
+
if (error?.message?.includes('Connection closed')) {
|
|
248
|
+
logger.info('Connection closed by client');
|
|
249
|
+
process.exit(0);
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
const cleanup = async (signal) => {
|
|
253
|
+
logger.info(`Received ${signal}, shutting down gracefully...`);
|
|
254
|
+
try {
|
|
255
|
+
await server.close();
|
|
256
|
+
logger.info('Server closed successfully');
|
|
257
|
+
process.exit(0);
|
|
258
|
+
}
|
|
259
|
+
catch (error) {
|
|
260
|
+
logger.error('Error during cleanup:', error);
|
|
261
|
+
process.exit(1);
|
|
262
|
+
}
|
|
263
|
+
};
|
|
264
|
+
process.on('SIGINT', () => cleanup('SIGINT'));
|
|
265
|
+
process.on('SIGTERM', () => cleanup('SIGTERM'));
|
|
266
|
+
process.on('uncaughtException', error => {
|
|
267
|
+
logger.error('Uncaught exception:', error.message);
|
|
268
|
+
logger.error('Stack trace:', error.stack);
|
|
269
|
+
logger.debug('Full error object:', error);
|
|
270
|
+
if (error && error.message && error.message.includes('EPIPE')) {
|
|
271
|
+
logger.warn('Pipe error detected, keeping server alive');
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
process.exit(1);
|
|
275
|
+
});
|
|
276
|
+
process.on('unhandledRejection', (reason, promise) => {
|
|
277
|
+
logger.error('Unhandled Rejection at:', promise);
|
|
278
|
+
logger.error('Rejection reason:', reason);
|
|
279
|
+
logger.debug('Full rejection details:', { reason, promise });
|
|
280
|
+
});
|
|
281
|
+
process.on('exit', code => {
|
|
282
|
+
logger.info(`Process exiting with code: ${code}`);
|
|
283
|
+
});
|
|
284
|
+
process.on('warning', warning => {
|
|
285
|
+
logger.warn('Process warning:', warning.message);
|
|
286
|
+
logger.debug('Warning details:', warning);
|
|
287
|
+
});
|
|
288
|
+
process.stdin.on('end', () => {
|
|
289
|
+
logger.info('Stdin closed, shutting down...');
|
|
290
|
+
setTimeout(() => process.exit(0), 100);
|
|
291
|
+
});
|
|
292
|
+
process.stdin.on('error', error => {
|
|
293
|
+
logger.warn('Stdin error:', error);
|
|
294
|
+
});
|
|
226
295
|
await server.connect(transport);
|
|
227
|
-
|
|
296
|
+
logger.info('MCP server connected and running successfully!');
|
|
297
|
+
logger.info('Ready to receive requests');
|
|
298
|
+
logger.debug('Server details:', {
|
|
299
|
+
name: 'read-website-fast',
|
|
300
|
+
version: '0.1.0',
|
|
301
|
+
pid: process.pid,
|
|
302
|
+
});
|
|
303
|
+
setInterval(() => {
|
|
304
|
+
logger.debug('Server heartbeat - still running...');
|
|
305
|
+
}, 30000);
|
|
228
306
|
process.stdin.resume();
|
|
229
307
|
}
|
|
230
308
|
catch (error) {
|
|
231
|
-
|
|
232
|
-
|
|
309
|
+
logger.error('Failed to start server:', error.message);
|
|
310
|
+
logger.debug('Startup error details:', error);
|
|
311
|
+
throw error;
|
|
233
312
|
}
|
|
234
313
|
}
|
|
314
|
+
logger.info('Initializing MCP server...');
|
|
235
315
|
runServer().catch(error => {
|
|
236
|
-
|
|
316
|
+
logger.error('Fatal server error:', error.message);
|
|
317
|
+
logger.error('Stack trace:', error.stack);
|
|
318
|
+
logger.debug('Full error:', error);
|
|
237
319
|
process.exit(1);
|
|
238
320
|
});
|
package/dist/utils/logger.js
CHANGED
|
@@ -23,10 +23,10 @@ export class Logger {
|
|
|
23
23
|
console.error(prefix, message, ...args);
|
|
24
24
|
break;
|
|
25
25
|
case LogLevel.WARN:
|
|
26
|
-
console.
|
|
26
|
+
console.error(prefix, message, ...args);
|
|
27
27
|
break;
|
|
28
28
|
default:
|
|
29
|
-
console.
|
|
29
|
+
console.error(prefix, message, ...args);
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
error(message, ...args) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@just-every/mcp-read-website-fast",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.11",
|
|
4
4
|
"description": "Markdown Content Preprocessor - Fetch web pages, extract content, convert to clean Markdown",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"build:dev": "tsc",
|
|
19
19
|
"dev": "tsx src/index.ts",
|
|
20
20
|
"start": "node dist/index.js",
|
|
21
|
-
"serve": "
|
|
21
|
+
"serve": "node dist/serve-restart.js",
|
|
22
22
|
"serve:dev": "tsx src/serve.ts",
|
|
23
23
|
"test": "vitest",
|
|
24
24
|
"test:deploy": "vitest run test/deployment.test.ts",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"homepage": "https://github.com/just-every/mcp-read-website-fast#readme",
|
|
51
51
|
"license": "MIT",
|
|
52
52
|
"dependencies": {
|
|
53
|
-
"@modelcontextprotocol/sdk": "^1.12.
|
|
53
|
+
"@modelcontextprotocol/sdk": "^1.12.3",
|
|
54
54
|
"@mozilla/readability": "^0.6.0",
|
|
55
55
|
"commander": "^14.0.0",
|
|
56
56
|
"jsdom": "^26.1.0",
|