@j0hanz/superfetch 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.
- package/README.md +327 -0
- package/dist/config/index.d.ts +30 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +42 -0
- package/dist/config/index.js.map +1 -0
- package/dist/errors/app-error.d.ts +71 -0
- package/dist/errors/app-error.d.ts.map +1 -0
- package/dist/errors/app-error.js +103 -0
- package/dist/errors/app-error.js.map +1 -0
- package/dist/errors/index.d.ts +2 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +2 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +179 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware/error-handler.d.ts +7 -0
- package/dist/middleware/error-handler.d.ts.map +1 -0
- package/dist/middleware/error-handler.js +37 -0
- package/dist/middleware/error-handler.js.map +1 -0
- package/dist/middleware/rate-limiter.d.ts +33 -0
- package/dist/middleware/rate-limiter.d.ts.map +1 -0
- package/dist/middleware/rate-limiter.js +100 -0
- package/dist/middleware/rate-limiter.js.map +1 -0
- package/dist/prompts/index.d.ts +6 -0
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/index.js +81 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/resources/index.d.ts +6 -0
- package/dist/resources/index.d.ts.map +1 -0
- package/dist/resources/index.js +44 -0
- package/dist/resources/index.js.map +1 -0
- package/dist/server.d.ts +8 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +39 -0
- package/dist/server.js.map +1 -0
- package/dist/services/cache.d.ts +16 -0
- package/dist/services/cache.d.ts.map +1 -0
- package/dist/services/cache.js +63 -0
- package/dist/services/cache.js.map +1 -0
- package/dist/services/cache.service.d.ts +52 -0
- package/dist/services/cache.service.d.ts.map +1 -0
- package/dist/services/cache.service.js +113 -0
- package/dist/services/cache.service.js.map +1 -0
- package/dist/services/extractor.d.ts +32 -0
- package/dist/services/extractor.d.ts.map +1 -0
- package/dist/services/extractor.js +97 -0
- package/dist/services/extractor.js.map +1 -0
- package/dist/services/extractor.service.d.ts +18 -0
- package/dist/services/extractor.service.d.ts.map +1 -0
- package/dist/services/extractor.service.js +75 -0
- package/dist/services/extractor.service.js.map +1 -0
- package/dist/services/fetcher.d.ts +9 -0
- package/dist/services/fetcher.d.ts.map +1 -0
- package/dist/services/fetcher.js +100 -0
- package/dist/services/fetcher.js.map +1 -0
- package/dist/services/fetcher.service.d.ts +18 -0
- package/dist/services/fetcher.service.d.ts.map +1 -0
- package/dist/services/fetcher.service.js +122 -0
- package/dist/services/fetcher.service.js.map +1 -0
- package/dist/services/logger.d.ts +5 -0
- package/dist/services/logger.d.ts.map +1 -0
- package/dist/services/logger.js +48 -0
- package/dist/services/logger.js.map +1 -0
- package/dist/services/logger.service.d.ts +5 -0
- package/dist/services/logger.service.d.ts.map +1 -0
- package/dist/services/logger.service.js +57 -0
- package/dist/services/logger.service.js.map +1 -0
- package/dist/services/parser.d.ts +6 -0
- package/dist/services/parser.d.ts.map +1 -0
- package/dist/services/parser.js +152 -0
- package/dist/services/parser.js.map +1 -0
- package/dist/services/parser.service.d.ts +42 -0
- package/dist/services/parser.service.d.ts.map +1 -0
- package/dist/services/parser.service.js +209 -0
- package/dist/services/parser.service.js.map +1 -0
- package/dist/tools/handlers/fetch-links.tool.d.ts +20 -0
- package/dist/tools/handlers/fetch-links.tool.d.ts.map +1 -0
- package/dist/tools/handlers/fetch-links.tool.js +91 -0
- package/dist/tools/handlers/fetch-links.tool.js.map +1 -0
- package/dist/tools/handlers/fetch-markdown.tool.d.ts +17 -0
- package/dist/tools/handlers/fetch-markdown.tool.d.ts.map +1 -0
- package/dist/tools/handlers/fetch-markdown.tool.js +99 -0
- package/dist/tools/handlers/fetch-markdown.tool.js.map +1 -0
- package/dist/tools/handlers/fetch-url.tool.d.ts +17 -0
- package/dist/tools/handlers/fetch-url.tool.d.ts.map +1 -0
- package/dist/tools/handlers/fetch-url.tool.js +103 -0
- package/dist/tools/handlers/fetch-url.tool.js.map +1 -0
- package/dist/tools/index.d.ts +7 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +83 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/transformers/jsonl.transformer.d.ts +4 -0
- package/dist/transformers/jsonl.transformer.d.ts.map +1 -0
- package/dist/transformers/jsonl.transformer.js +42 -0
- package/dist/transformers/jsonl.transformer.js.map +1 -0
- package/dist/transformers/markdown.transformer.d.ts +4 -0
- package/dist/transformers/markdown.transformer.d.ts.map +1 -0
- package/dist/transformers/markdown.transformer.js +104 -0
- package/dist/transformers/markdown.transformer.js.map +1 -0
- package/dist/types/content.types.d.ts +63 -0
- package/dist/types/content.types.d.ts.map +1 -0
- package/dist/types/content.types.js +2 -0
- package/dist/types/content.types.js.map +1 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +3 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/schemas.d.ts +22 -0
- package/dist/types/schemas.d.ts.map +1 -0
- package/dist/types/schemas.js +5 -0
- package/dist/types/schemas.js.map +1 -0
- package/dist/utils/sanitizer.d.ts +9 -0
- package/dist/utils/sanitizer.d.ts.map +1 -0
- package/dist/utils/sanitizer.js +19 -0
- package/dist/utils/sanitizer.js.map +1 -0
- package/dist/utils/url-validator.d.ts +10 -0
- package/dist/utils/url-validator.d.ts.map +1 -0
- package/dist/utils/url-validator.js +69 -0
- package/dist/utils/url-validator.js.map +1 -0
- package/package.json +80 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import express from 'express';
|
|
3
|
+
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
|
4
|
+
import { isInitializeRequest } from '@modelcontextprotocol/sdk/types.js';
|
|
5
|
+
import { config } from './config/index.js';
|
|
6
|
+
import { createMcpServer } from './server.js';
|
|
7
|
+
import { errorHandler } from './middleware/error-handler.js';
|
|
8
|
+
import { rateLimiter } from './middleware/rate-limiter.js';
|
|
9
|
+
import { logInfo, logError } from './services/logger.js';
|
|
10
|
+
// Check if running in stdio mode
|
|
11
|
+
const isStdioMode = process.argv.includes('--stdio');
|
|
12
|
+
// CORS allowlist - empty means allow all origins
|
|
13
|
+
// For production, configure this in the CORS middleware below
|
|
14
|
+
const ALLOWED_ORIGINS = [];
|
|
15
|
+
/**
|
|
16
|
+
* Async error wrapper for Express route handlers
|
|
17
|
+
* Catches promise rejections and forwards to error middleware
|
|
18
|
+
*/
|
|
19
|
+
const asyncHandler = (fn) => {
|
|
20
|
+
return (req, res, next) => {
|
|
21
|
+
Promise.resolve(fn(req, res, next)).catch(next);
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
if (isStdioMode) {
|
|
25
|
+
// Run in stdio mode for direct integration
|
|
26
|
+
const { startStdioServer } = await import('./server.js');
|
|
27
|
+
await startStdioServer();
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
// Run HTTP server mode
|
|
31
|
+
const app = express();
|
|
32
|
+
// Middleware
|
|
33
|
+
app.use(express.json());
|
|
34
|
+
// Rate limiting for HTTP mode
|
|
35
|
+
app.use(rateLimiter.middleware());
|
|
36
|
+
// CORS headers for MCP clients
|
|
37
|
+
app.use((req, res, next) => {
|
|
38
|
+
const origin = req.headers.origin;
|
|
39
|
+
// Allow if no origin (same-origin/non-browser), no allowlist configured, or origin in allowlist
|
|
40
|
+
if (!origin ||
|
|
41
|
+
ALLOWED_ORIGINS.length === 0 ||
|
|
42
|
+
ALLOWED_ORIGINS.includes(origin)) {
|
|
43
|
+
res.header('Access-Control-Allow-Origin', origin ?? '*');
|
|
44
|
+
res.header('Access-Control-Allow-Methods', 'GET, POST, DELETE, OPTIONS');
|
|
45
|
+
res.header('Access-Control-Allow-Headers', 'Content-Type, mcp-session-id');
|
|
46
|
+
}
|
|
47
|
+
if (req.method === 'OPTIONS') {
|
|
48
|
+
res.sendStatus(200);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
next();
|
|
52
|
+
});
|
|
53
|
+
// Health check endpoint
|
|
54
|
+
app.get('/health', (_req, res) => {
|
|
55
|
+
res.json({
|
|
56
|
+
status: 'healthy',
|
|
57
|
+
name: config.server.name,
|
|
58
|
+
version: config.server.version,
|
|
59
|
+
uptime: process.uptime(),
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
// Session management for Streamable HTTP transport
|
|
63
|
+
// Store transports by session ID (following SDK pattern)
|
|
64
|
+
const transports = new Map();
|
|
65
|
+
// MCP Streamable HTTP endpoint (modern replacement for SSE)
|
|
66
|
+
app.post('/mcp', asyncHandler(async (req, res) => {
|
|
67
|
+
const sessionId = req.headers['mcp-session-id'];
|
|
68
|
+
let transport;
|
|
69
|
+
// Debug logging
|
|
70
|
+
const body = req.body;
|
|
71
|
+
logInfo('[MCP POST]', {
|
|
72
|
+
method: body?.method,
|
|
73
|
+
id: body?.id,
|
|
74
|
+
sessionId: sessionId ?? 'none',
|
|
75
|
+
isInitialize: isInitializeRequest(req.body),
|
|
76
|
+
sessionCount: transports.size,
|
|
77
|
+
});
|
|
78
|
+
const existingTransport = sessionId ? transports.get(sessionId) : undefined;
|
|
79
|
+
if (existingTransport) {
|
|
80
|
+
// Reuse existing session
|
|
81
|
+
transport = existingTransport;
|
|
82
|
+
}
|
|
83
|
+
else if (!sessionId && isInitializeRequest(req.body)) {
|
|
84
|
+
// New session initialization
|
|
85
|
+
transport = new StreamableHTTPServerTransport({
|
|
86
|
+
sessionIdGenerator: () => crypto.randomUUID(),
|
|
87
|
+
onsessioninitialized: (id) => {
|
|
88
|
+
transports.set(id, transport);
|
|
89
|
+
logInfo('Session initialized', { sessionId: id });
|
|
90
|
+
},
|
|
91
|
+
onsessionclosed: (id) => {
|
|
92
|
+
transports.delete(id);
|
|
93
|
+
logInfo('Session closed', { sessionId: id });
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
transport.onclose = () => {
|
|
97
|
+
if (transport.sessionId) {
|
|
98
|
+
transports.delete(transport.sessionId);
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
const mcpServer = createMcpServer();
|
|
102
|
+
await mcpServer.connect(transport);
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
// Invalid request - no session and not an initialize request
|
|
106
|
+
res.status(400).json({
|
|
107
|
+
jsonrpc: '2.0',
|
|
108
|
+
error: { code: -32000, message: 'Bad Request: Missing session ID or not an initialize request' },
|
|
109
|
+
id: null,
|
|
110
|
+
});
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
await transport.handleRequest(req, res, req.body);
|
|
114
|
+
}));
|
|
115
|
+
// GET endpoint for SSE stream (for server-initiated messages)
|
|
116
|
+
app.get('/mcp', asyncHandler(async (req, res) => {
|
|
117
|
+
const sessionId = req.headers['mcp-session-id'];
|
|
118
|
+
if (!sessionId) {
|
|
119
|
+
res.status(400).json({ error: 'Missing mcp-session-id header' });
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
const transport = transports.get(sessionId);
|
|
123
|
+
if (!transport) {
|
|
124
|
+
res.status(404).json({ error: 'Session not found' });
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
// Handle SSE stream for server-initiated messages
|
|
128
|
+
await transport.handleRequest(req, res);
|
|
129
|
+
}));
|
|
130
|
+
// DELETE endpoint for session cleanup
|
|
131
|
+
app.delete('/mcp', asyncHandler(async (req, res) => {
|
|
132
|
+
const sessionId = req.headers['mcp-session-id'];
|
|
133
|
+
const transport = sessionId ? transports.get(sessionId) : undefined;
|
|
134
|
+
if (transport) {
|
|
135
|
+
await transport.handleRequest(req, res);
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
res.status(204).end();
|
|
139
|
+
}
|
|
140
|
+
}));
|
|
141
|
+
// Error handling middleware (must be last)
|
|
142
|
+
app.use(errorHandler);
|
|
143
|
+
// Start server
|
|
144
|
+
const server = app
|
|
145
|
+
.listen(config.server.port, config.server.host, () => {
|
|
146
|
+
logInfo(`superFetch MCP server started`, {
|
|
147
|
+
host: config.server.host,
|
|
148
|
+
port: config.server.port,
|
|
149
|
+
});
|
|
150
|
+
process.stdout.write(`✓ superFetch MCP server running at http://${config.server.host}:${config.server.port}\n`);
|
|
151
|
+
process.stdout.write(` Health check: http://${config.server.host}:${config.server.port}/health\n`);
|
|
152
|
+
process.stdout.write(` MCP endpoint: http://${config.server.host}:${config.server.port}/mcp\n`);
|
|
153
|
+
process.stdout.write(`\nRun with --stdio flag for direct stdio integration\n`);
|
|
154
|
+
})
|
|
155
|
+
.on('error', (err) => {
|
|
156
|
+
logError('Failed to start server', err);
|
|
157
|
+
process.exit(1);
|
|
158
|
+
});
|
|
159
|
+
// Graceful shutdown for HTTP mode
|
|
160
|
+
const shutdown = (signal) => {
|
|
161
|
+
process.stdout.write(`\n${signal} received, shutting down gracefully...\n`);
|
|
162
|
+
// Close all MCP transport sessions
|
|
163
|
+
for (const transport of transports.values()) {
|
|
164
|
+
void transport.close();
|
|
165
|
+
}
|
|
166
|
+
server.close(() => {
|
|
167
|
+
logInfo('HTTP server closed');
|
|
168
|
+
process.exit(0);
|
|
169
|
+
});
|
|
170
|
+
// Force exit after timeout
|
|
171
|
+
setTimeout(() => {
|
|
172
|
+
logError('Forced shutdown after timeout');
|
|
173
|
+
process.exit(1);
|
|
174
|
+
}, 10000).unref();
|
|
175
|
+
};
|
|
176
|
+
process.on('SIGINT', () => shutdown('SIGINT'));
|
|
177
|
+
process.on('SIGTERM', () => shutdown('SIGTERM'));
|
|
178
|
+
}
|
|
179
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,OAA2D,MAAM,SAAS,CAAC;AAClF,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAC;AACnG,OAAO,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAC3D,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAEzD,iCAAiC;AACjC,MAAM,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;AAErD,iDAAiD;AACjD,8DAA8D;AAC9D,MAAM,eAAe,GAAa,EAAE,CAAC;AAErC;;;GAGG;AACH,MAAM,YAAY,GAAG,CACnB,EAAsE,EACtE,EAAE;IACF,OAAO,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB,EAAQ,EAAE;QAC/D,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAClD,CAAC,CAAC;AACJ,CAAC,CAAC;AAEF,IAAI,WAAW,EAAE,CAAC;IAChB,2CAA2C;IAC3C,MAAM,EAAE,gBAAgB,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;IACzD,MAAM,gBAAgB,EAAE,CAAC;AAC3B,CAAC;KAAM,CAAC;IACN,uBAAuB;IACvB,MAAM,GAAG,GAAG,OAAO,EAAE,CAAC;IAEtB,aAAa;IACb,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;IAExB,8BAA8B;IAC9B,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,UAAU,EAAE,CAAC,CAAC;IAElC,+BAA+B;IAC/B,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QACzB,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC;QAElC,gGAAgG;QAChG,IACE,CAAC,MAAM;YACP,eAAe,CAAC,MAAM,KAAK,CAAC;YAC5B,eAAe,CAAC,QAAQ,CAAC,MAAM,CAAC,EAChC,CAAC;YACD,GAAG,CAAC,MAAM,CAAC,6BAA6B,EAAE,MAAM,IAAI,GAAG,CAAC,CAAC;YACzD,GAAG,CAAC,MAAM,CAAC,8BAA8B,EAAE,4BAA4B,CAAC,CAAC;YACzE,GAAG,CAAC,MAAM,CAAC,8BAA8B,EAAE,8BAA8B,CAAC,CAAC;QAC7E,CAAC;QAED,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAC7B,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;YACpB,OAAO;QACT,CAAC;QACD,IAAI,EAAE,CAAC;IACT,CAAC,CAAC,CAAC;IAEH,wBAAwB;IACxB,GAAG,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE;QAC/B,GAAG,CAAC,IAAI,CAAC;YACP,MAAM,EAAE,SAAS;YACjB,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI;YACxB,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,OAAO;YAC9B,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE;SACzB,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,mDAAmD;IACnD,yDAAyD;IACzD,MAAM,UAAU,GAAG,IAAI,GAAG,EAAyC,CAAC;IAEpE,4DAA4D;IAC5D,GAAG,CAAC,IAAI,CACN,MAAM,EACN,YAAY,CAAC,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;QACjD,MAAM,SAAS,GAAG,GAAG,CAAC,OAAO,CAAC,gBAAgB,CAAuB,CAAC;QACtE,IAAI,SAAwC,CAAC;QAE7C,gBAAgB;QAChB,MAAM,IAAI,GAAG,GAAG,CAAC,IAA6D,CAAC;QAC/E,OAAO,CAAC,YAAY,EAAE;YACpB,MAAM,EAAE,IAAI,EAAE,MAAM;YACpB,EAAE,EAAE,IAAI,EAAE,EAAE;YACZ,SAAS,EAAE,SAAS,IAAI,MAAM;YAC9B,YAAY,EAAE,mBAAmB,CAAC,GAAG,CAAC,IAAI,CAAC;YAC3C,YAAY,EAAE,UAAU,CAAC,IAAI;SAC9B,CAAC,CAAC;QAEH,MAAM,iBAAiB,GAAG,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAC5E,IAAI,iBAAiB,EAAE,CAAC;YACtB,yBAAyB;YACzB,SAAS,GAAG,iBAAiB,CAAC;QAChC,CAAC;aAAM,IAAI,CAAC,SAAS,IAAI,mBAAmB,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YACvD,6BAA6B;YAC7B,SAAS,GAAG,IAAI,6BAA6B,CAAC;gBAC5C,kBAAkB,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,UAAU,EAAE;gBAC7C,oBAAoB,EAAE,CAAC,EAAE,EAAE,EAAE;oBAC3B,UAAU,CAAC,GAAG,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC;oBAC9B,OAAO,CAAC,qBAAqB,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,CAAC;gBACpD,CAAC;gBACD,eAAe,EAAE,CAAC,EAAE,EAAE,EAAE;oBACtB,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;oBACtB,OAAO,CAAC,gBAAgB,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,CAAC;gBAC/C,CAAC;aACF,CAAC,CAAC;YAEH,SAAS,CAAC,OAAO,GAAG,GAAG,EAAE;gBACvB,IAAI,SAAS,CAAC,SAAS,EAAE,CAAC;oBACxB,UAAU,CAAC,MAAM,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;gBACzC,CAAC;YACH,CAAC,CAAC;YAEF,MAAM,SAAS,GAAG,eAAe,EAAE,CAAC;YACpC,MAAM,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QACrC,CAAC;aAAM,CAAC;YACN,6DAA6D;YAC7D,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;gBACnB,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,8DAA8D,EAAE;gBAChG,EAAE,EAAE,IAAI;aACT,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QAED,MAAM,SAAS,CAAC,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;IACpD,CAAC,CAAC,CACH,CAAC;IAEF,8DAA8D;IAC9D,GAAG,CAAC,GAAG,CACL,MAAM,EACN,YAAY,CAAC,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;QACjD,MAAM,SAAS,GAAG,GAAG,CAAC,OAAO,CAAC,gBAAgB,CAAuB,CAAC;QAEtE,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,+BAA+B,EAAE,CAAC,CAAC;YACjE,OAAO;QACT,CAAC;QAED,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC5C,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAC,CAAC;YACrD,OAAO;QACT,CAAC;QAED,kDAAkD;QAClD,MAAM,SAAS,CAAC,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAC1C,CAAC,CAAC,CACH,CAAC;IAEF,sCAAsC;IACtC,GAAG,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;QACpE,MAAM,SAAS,GAAG,GAAG,CAAC,OAAO,CAAC,gBAAgB,CAAuB,CAAC;QACtE,MAAM,SAAS,GAAG,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAEpE,IAAI,SAAS,EAAE,CAAC;YACd,MAAM,SAAS,CAAC,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QAC1C,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;QACxB,CAAC;IACH,CAAC,CAAC,CAAC,CAAC;IAEJ,2CAA2C;IAC3C,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IAEtB,eAAe;IACf,MAAM,MAAM,GAAG,GAAG;SACf,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE;QACnD,OAAO,CAAC,+BAA+B,EAAE;YACvC,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI;YACxB,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI;SACzB,CAAC,CAAC;QAEH,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,6CAA6C,MAAM,CAAC,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,IAAI,CAC1F,CAAC;QACF,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,0BAA0B,MAAM,CAAC,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,WAAW,CAC9E,CAAC;QACF,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,0BAA0B,MAAM,CAAC,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,QAAQ,CAC3E,CAAC;QACF,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,wDAAwD,CACzD,CAAC;IACJ,CAAC,CAAC;SACD,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;QACnB,QAAQ,CAAC,wBAAwB,EAAE,GAAG,CAAC,CAAC;QACxC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;IAEL,kCAAkC;IAClC,MAAM,QAAQ,GAAG,CAAC,MAAc,EAAE,EAAE;QAClC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,MAAM,0CAA0C,CAAC,CAAC;QAE5E,mCAAmC;QACnC,KAAK,MAAM,SAAS,IAAI,UAAU,CAAC,MAAM,EAAE,EAAE,CAAC;YAC5C,KAAK,SAAS,CAAC,KAAK,EAAE,CAAC;QACzB,CAAC;QAED,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE;YAChB,OAAO,CAAC,oBAAoB,CAAC,CAAC;YAC9B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC,CAAC,CAAC;QAEH,2BAA2B;QAC3B,UAAU,CAAC,GAAG,EAAE;YACd,QAAQ,CAAC,+BAA+B,CAAC,CAAC;YAC1C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC,EAAE,KAAK,CAAC,CAAC,KAAK,EAAE,CAAC;IACpB,CAAC,CAAC;IAEF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC/C,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC;AACnD,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Request, Response, NextFunction } from 'express';
|
|
2
|
+
/**
|
|
3
|
+
* Error handling middleware for Express
|
|
4
|
+
* Note: Express error handlers require 4 parameters
|
|
5
|
+
*/
|
|
6
|
+
export declare function errorHandler(err: Error, _req: Request, res: Response, _next: NextFunction): void;
|
|
7
|
+
//# sourceMappingURL=error-handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-handler.d.ts","sourceRoot":"","sources":["../../src/middleware/error-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAc/D;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,GAAG,EAAE,KAAK,EACV,IAAI,EAAE,OAAO,EACb,GAAG,EAAE,QAAQ,EACb,KAAK,EAAE,YAAY,GAClB,IAAI,CAmCN"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { logError } from '../services/logger.js';
|
|
2
|
+
import { AppError, RateLimitError, ValidationError } from '../errors/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* Error handling middleware for Express
|
|
5
|
+
* Note: Express error handlers require 4 parameters
|
|
6
|
+
*/
|
|
7
|
+
export function errorHandler(err, _req, res, _next) {
|
|
8
|
+
// Determine error properties
|
|
9
|
+
const isAppError = err instanceof AppError;
|
|
10
|
+
const statusCode = isAppError ? err.statusCode : 500;
|
|
11
|
+
const code = isAppError ? err.code : 'INTERNAL_ERROR';
|
|
12
|
+
const message = isAppError && err.isOperational ? err.message : 'Internal Server Error';
|
|
13
|
+
// Log error (full details for non-operational errors)
|
|
14
|
+
logError(`HTTP ${statusCode}: ${err.message}`, err);
|
|
15
|
+
// Add retry-after header for rate limit errors
|
|
16
|
+
if (err instanceof RateLimitError) {
|
|
17
|
+
res.set('Retry-After', String(err.retryAfter));
|
|
18
|
+
}
|
|
19
|
+
// Build error response
|
|
20
|
+
const response = {
|
|
21
|
+
error: {
|
|
22
|
+
message,
|
|
23
|
+
code,
|
|
24
|
+
statusCode,
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
// Add validation details if present
|
|
28
|
+
if (err instanceof ValidationError && err.details) {
|
|
29
|
+
response.error.details = err.details;
|
|
30
|
+
}
|
|
31
|
+
// Add stack trace in development
|
|
32
|
+
if (process.env.NODE_ENV === 'development') {
|
|
33
|
+
response.error.stack = err.stack;
|
|
34
|
+
}
|
|
35
|
+
res.status(statusCode).json(response);
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=error-handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-handler.js","sourceRoot":"","sources":["../../src/middleware/error-handler.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAY/E;;;GAGG;AACH,MAAM,UAAU,YAAY,CAC1B,GAAU,EACV,IAAa,EACb,GAAa,EACb,KAAmB;IAEnB,6BAA6B;IAC7B,MAAM,UAAU,GAAG,GAAG,YAAY,QAAQ,CAAC;IAC3C,MAAM,UAAU,GAAG,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC;IACrD,MAAM,IAAI,GAAG,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,gBAAgB,CAAC;IACtD,MAAM,OAAO,GAAG,UAAU,IAAI,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,uBAAuB,CAAC;IAExF,sDAAsD;IACtD,QAAQ,CAAC,QAAQ,UAAU,KAAK,GAAG,CAAC,OAAO,EAAE,EAAE,GAAG,CAAC,CAAC;IAEpD,+CAA+C;IAC/C,IAAI,GAAG,YAAY,cAAc,EAAE,CAAC;QAClC,GAAG,CAAC,GAAG,CAAC,aAAa,EAAE,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC;IACjD,CAAC;IAED,uBAAuB;IACvB,MAAM,QAAQ,GAAkB;QAC9B,KAAK,EAAE;YACL,OAAO;YACP,IAAI;YACJ,UAAU;SACX;KACF,CAAC;IAEF,oCAAoC;IACpC,IAAI,GAAG,YAAY,eAAe,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC;QAClD,QAAQ,CAAC,KAAK,CAAC,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC;IACvC,CAAC;IAED,iCAAiC;IACjC,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,aAAa,EAAE,CAAC;QAC3C,QAAQ,CAAC,KAAK,CAAC,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC;IACnC,CAAC;IAED,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AACxC,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { Request, Response, NextFunction } from 'express';
|
|
2
|
+
interface RateLimiterOptions {
|
|
3
|
+
maxRequests: number;
|
|
4
|
+
windowMs: number;
|
|
5
|
+
cleanupIntervalMs: number;
|
|
6
|
+
}
|
|
7
|
+
declare class RateLimiter {
|
|
8
|
+
private readonly store;
|
|
9
|
+
private readonly maxRequests;
|
|
10
|
+
private readonly windowMs;
|
|
11
|
+
private cleanupInterval;
|
|
12
|
+
constructor(options?: Partial<RateLimiterOptions>);
|
|
13
|
+
/**
|
|
14
|
+
* Destroys the rate limiter and cleans up resources
|
|
15
|
+
*/
|
|
16
|
+
destroy(): void;
|
|
17
|
+
/**
|
|
18
|
+
* Rate limiting middleware
|
|
19
|
+
*/
|
|
20
|
+
middleware(): (req: Request, res: Response, next: NextFunction) => void;
|
|
21
|
+
/**
|
|
22
|
+
* Get key for request (IP address)
|
|
23
|
+
* Handles proxy configurations and provides fallback
|
|
24
|
+
*/
|
|
25
|
+
private getKey;
|
|
26
|
+
/**
|
|
27
|
+
* Clean up expired entries
|
|
28
|
+
*/
|
|
29
|
+
private cleanup;
|
|
30
|
+
}
|
|
31
|
+
export declare const rateLimiter: RateLimiter;
|
|
32
|
+
export {};
|
|
33
|
+
//# sourceMappingURL=rate-limiter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limiter.d.ts","sourceRoot":"","sources":["../../src/middleware/rate-limiter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAO/D,UAAU,kBAAkB;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAQD,cAAM,WAAW;IACf,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAqC;IAC3D,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,eAAe,CAA+C;gBAE1D,OAAO,GAAE,OAAO,CAAC,kBAAkB,CAAM;IAerD;;OAEG;IACH,OAAO,IAAI,IAAI;IAQf;;OAEG;IACH,UAAU,IAAI,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,KAAK,IAAI;IAqCvE;;;OAGG;IACH,OAAO,CAAC,MAAM;IAkBd;;OAEG;IACH,OAAO,CAAC,OAAO;CAQhB;AAID,eAAO,MAAM,WAAW,aAGtB,CAAC"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
const DEFAULT_OPTIONS = {
|
|
2
|
+
maxRequests: 100,
|
|
3
|
+
windowMs: 60000,
|
|
4
|
+
cleanupIntervalMs: 60000,
|
|
5
|
+
};
|
|
6
|
+
class RateLimiter {
|
|
7
|
+
store = new Map();
|
|
8
|
+
maxRequests;
|
|
9
|
+
windowMs;
|
|
10
|
+
cleanupInterval = null;
|
|
11
|
+
constructor(options = {}) {
|
|
12
|
+
const opts = { ...DEFAULT_OPTIONS, ...options };
|
|
13
|
+
this.maxRequests = opts.maxRequests;
|
|
14
|
+
this.windowMs = opts.windowMs;
|
|
15
|
+
// Start cleanup interval
|
|
16
|
+
this.cleanupInterval = setInterval(() => this.cleanup(), opts.cleanupIntervalMs);
|
|
17
|
+
// Ensure interval doesn't prevent process exit
|
|
18
|
+
this.cleanupInterval.unref();
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Destroys the rate limiter and cleans up resources
|
|
22
|
+
*/
|
|
23
|
+
destroy() {
|
|
24
|
+
if (this.cleanupInterval) {
|
|
25
|
+
clearInterval(this.cleanupInterval);
|
|
26
|
+
this.cleanupInterval = null;
|
|
27
|
+
}
|
|
28
|
+
this.store.clear();
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Rate limiting middleware
|
|
32
|
+
*/
|
|
33
|
+
middleware() {
|
|
34
|
+
return (req, res, next) => {
|
|
35
|
+
const key = this.getKey(req);
|
|
36
|
+
const now = Date.now();
|
|
37
|
+
// Get or create entry
|
|
38
|
+
let entry = this.store.get(key);
|
|
39
|
+
// Reset if window has passed
|
|
40
|
+
if (!entry || now > entry.resetTime) {
|
|
41
|
+
entry = { count: 0, resetTime: now + this.windowMs };
|
|
42
|
+
this.store.set(key, entry);
|
|
43
|
+
}
|
|
44
|
+
// Increment count
|
|
45
|
+
entry.count++;
|
|
46
|
+
// Check limit
|
|
47
|
+
if (entry.count > this.maxRequests) {
|
|
48
|
+
const retryAfter = Math.ceil((entry.resetTime - now) / 1000);
|
|
49
|
+
res.set('Retry-After', String(retryAfter));
|
|
50
|
+
res.status(429).json({
|
|
51
|
+
error: 'Too many requests',
|
|
52
|
+
retryAfter,
|
|
53
|
+
});
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
// Add rate limit headers
|
|
57
|
+
res.set('X-RateLimit-Limit', String(this.maxRequests));
|
|
58
|
+
res.set('X-RateLimit-Remaining', String(this.maxRequests - entry.count));
|
|
59
|
+
res.set('X-RateLimit-Reset', String(Math.ceil(entry.resetTime / 1000)));
|
|
60
|
+
next();
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Get key for request (IP address)
|
|
65
|
+
* Handles proxy configurations and provides fallback
|
|
66
|
+
*/
|
|
67
|
+
getKey(req) {
|
|
68
|
+
// Priority: X-Real-IP > first X-Forwarded-For > req.ip > socket
|
|
69
|
+
const realIp = req.headers['x-real-ip'];
|
|
70
|
+
if (typeof realIp === 'string' && realIp) {
|
|
71
|
+
return realIp;
|
|
72
|
+
}
|
|
73
|
+
const forwardedFor = req.headers['x-forwarded-for'];
|
|
74
|
+
if (typeof forwardedFor === 'string') {
|
|
75
|
+
const firstIp = forwardedFor.split(',')[0]?.trim();
|
|
76
|
+
if (firstIp) {
|
|
77
|
+
return firstIp;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return req.ip ?? req.socket.remoteAddress ?? 'unknown';
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Clean up expired entries
|
|
84
|
+
*/
|
|
85
|
+
cleanup() {
|
|
86
|
+
const now = Date.now();
|
|
87
|
+
for (const [key, entry] of this.store) {
|
|
88
|
+
if (entry.resetTime < now) {
|
|
89
|
+
this.store.delete(key);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
// Create default rate limiter instance
|
|
95
|
+
// Override via RateLimiter constructor if different values needed
|
|
96
|
+
export const rateLimiter = new RateLimiter({
|
|
97
|
+
maxRequests: 100,
|
|
98
|
+
windowMs: 60000,
|
|
99
|
+
});
|
|
100
|
+
//# sourceMappingURL=rate-limiter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limiter.js","sourceRoot":"","sources":["../../src/middleware/rate-limiter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/prompts/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAGzE;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA+FvD"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* Registers all prompts with the MCP server using the modern McpServer API
|
|
4
|
+
*/
|
|
5
|
+
export function registerPrompts(server) {
|
|
6
|
+
// Register analyze-web-content prompt
|
|
7
|
+
server.registerPrompt('analyze-web-content', {
|
|
8
|
+
title: 'Analyze Web Content',
|
|
9
|
+
description: 'Analyze fetched web content with optional focus area',
|
|
10
|
+
argsSchema: {
|
|
11
|
+
url: z.string().min(1).describe('URL of the content to analyze'),
|
|
12
|
+
focus: z
|
|
13
|
+
.string()
|
|
14
|
+
.optional()
|
|
15
|
+
.describe('Specific aspect to focus on (e.g., "technical details", "pricing")'),
|
|
16
|
+
},
|
|
17
|
+
}, ({ url, focus }) => {
|
|
18
|
+
const focusText = focus ? ` with focus on ${focus}` : '';
|
|
19
|
+
return {
|
|
20
|
+
messages: [
|
|
21
|
+
{
|
|
22
|
+
role: 'user',
|
|
23
|
+
content: {
|
|
24
|
+
type: 'text',
|
|
25
|
+
text: `Please fetch and analyze the content from ${url}${focusText}. Use the fetch-url tool to retrieve the content first, then provide your analysis.`,
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
};
|
|
30
|
+
});
|
|
31
|
+
// Register summarize-page prompt
|
|
32
|
+
server.registerPrompt('summarize-page', {
|
|
33
|
+
title: 'Summarize Page',
|
|
34
|
+
description: 'Fetch and summarize a web page concisely',
|
|
35
|
+
argsSchema: {
|
|
36
|
+
url: z.string().min(1).describe('URL of the page to summarize'),
|
|
37
|
+
maxLength: z
|
|
38
|
+
.number()
|
|
39
|
+
.positive()
|
|
40
|
+
.optional()
|
|
41
|
+
.describe('Maximum summary length in words'),
|
|
42
|
+
},
|
|
43
|
+
}, ({ url, maxLength }) => {
|
|
44
|
+
const lengthConstraint = maxLength
|
|
45
|
+
? ` Keep the summary under ${maxLength} words.`
|
|
46
|
+
: '';
|
|
47
|
+
return {
|
|
48
|
+
messages: [
|
|
49
|
+
{
|
|
50
|
+
role: 'user',
|
|
51
|
+
content: {
|
|
52
|
+
type: 'text',
|
|
53
|
+
text: `Please fetch the content from ${url} using the fetch-url tool, then provide a concise summary of the main points.${lengthConstraint}`,
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
};
|
|
58
|
+
});
|
|
59
|
+
// Register extract-data prompt
|
|
60
|
+
server.registerPrompt('extract-data', {
|
|
61
|
+
title: 'Extract Structured Data',
|
|
62
|
+
description: 'Extract specific structured data from a web page',
|
|
63
|
+
argsSchema: {
|
|
64
|
+
url: z.string().min(1).describe('URL of the page to extract data from'),
|
|
65
|
+
dataType: z
|
|
66
|
+
.string()
|
|
67
|
+
.describe('Type of data to extract (e.g., "contact info", "product details", "article metadata")'),
|
|
68
|
+
},
|
|
69
|
+
}, ({ url, dataType }) => ({
|
|
70
|
+
messages: [
|
|
71
|
+
{
|
|
72
|
+
role: 'user',
|
|
73
|
+
content: {
|
|
74
|
+
type: 'text',
|
|
75
|
+
text: `Please fetch the content from ${url} using the fetch-url tool, then extract and structure the ${dataType} found on the page. Present the extracted data in a clear, organized format.`,
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
}));
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/prompts/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,MAAiB;IAC/C,sCAAsC;IACtC,MAAM,CAAC,cAAc,CACnB,qBAAqB,EACrB;QACE,KAAK,EAAE,qBAAqB;QAC5B,WAAW,EAAE,sDAAsD;QACnE,UAAU,EAAE;YACV,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,+BAA+B,CAAC;YAChE,KAAK,EAAE,CAAC;iBACL,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CACP,oEAAoE,CACrE;SACJ;KACF,EACD,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE,EAAE;QACjB,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,kBAAkB,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAEzD,OAAO;YACL,QAAQ,EAAE;gBACR;oBACE,IAAI,EAAE,MAAM;oBACZ,OAAO,EAAE;wBACP,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,6CAA6C,GAAG,GAAG,SAAS,qFAAqF;qBACxJ;iBACF;aACF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,iCAAiC;IACjC,MAAM,CAAC,cAAc,CACnB,gBAAgB,EAChB;QACE,KAAK,EAAE,gBAAgB;QACvB,WAAW,EAAE,0CAA0C;QACvD,UAAU,EAAE;YACV,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,8BAA8B,CAAC;YAC/D,SAAS,EAAE,CAAC;iBACT,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,EAAE;iBACV,QAAQ,CAAC,iCAAiC,CAAC;SAC/C;KACF,EACD,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,EAAE,EAAE;QACrB,MAAM,gBAAgB,GAAG,SAAS;YAChC,CAAC,CAAC,2BAA2B,SAAS,SAAS;YAC/C,CAAC,CAAC,EAAE,CAAC;QAEP,OAAO;YACL,QAAQ,EAAE;gBACR;oBACE,IAAI,EAAE,MAAM;oBACZ,OAAO,EAAE;wBACP,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,iCAAiC,GAAG,gFAAgF,gBAAgB,EAAE;qBAC7I;iBACF;aACF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,+BAA+B;IAC/B,MAAM,CAAC,cAAc,CACnB,cAAc,EACd;QACE,KAAK,EAAE,yBAAyB;QAChC,WAAW,EAAE,kDAAkD;QAC/D,UAAU,EAAE;YACV,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,sCAAsC,CAAC;YACvE,QAAQ,EAAE,CAAC;iBACR,MAAM,EAAE;iBACR,QAAQ,CACP,uFAAuF,CACxF;SACJ;KACF,EACD,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC;QACtB,QAAQ,EAAE;YACR;gBACE,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE;oBACP,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE,iCAAiC,GAAG,6DAA6D,QAAQ,8EAA8E;iBAC9L;aACF;SACF;KACF,CAAC,CACH,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
/**
|
|
3
|
+
* Registers all resources with the MCP server using the modern McpServer API
|
|
4
|
+
*/
|
|
5
|
+
export declare function registerResources(server: McpServer): void;
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/resources/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIzE;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA2CzD"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import * as cache from '../services/cache.js';
|
|
2
|
+
import { config } from '../config/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* Registers all resources with the MCP server using the modern McpServer API
|
|
5
|
+
*/
|
|
6
|
+
export function registerResources(server) {
|
|
7
|
+
// Register server statistics resource
|
|
8
|
+
server.registerResource('stats', 'superfetch://stats', {
|
|
9
|
+
title: 'Server Statistics',
|
|
10
|
+
description: 'Fetch statistics and cache performance metrics',
|
|
11
|
+
mimeType: 'application/json',
|
|
12
|
+
}, async (uri) => {
|
|
13
|
+
const stats = {
|
|
14
|
+
server: {
|
|
15
|
+
name: config.server.name,
|
|
16
|
+
version: config.server.version,
|
|
17
|
+
uptime: process.uptime(),
|
|
18
|
+
nodeVersion: process.version,
|
|
19
|
+
memoryUsage: process.memoryUsage(),
|
|
20
|
+
},
|
|
21
|
+
cache: cache.getStats(),
|
|
22
|
+
config: {
|
|
23
|
+
fetcher: {
|
|
24
|
+
timeout: config.fetcher.timeout,
|
|
25
|
+
maxRedirects: config.fetcher.maxRedirects,
|
|
26
|
+
},
|
|
27
|
+
extraction: {
|
|
28
|
+
extractMainContent: config.extraction.extractMainContent,
|
|
29
|
+
includeMetadata: config.extraction.includeMetadata,
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
return {
|
|
34
|
+
contents: [
|
|
35
|
+
{
|
|
36
|
+
uri: uri.href,
|
|
37
|
+
mimeType: 'application/json',
|
|
38
|
+
text: JSON.stringify(stats, null, 2),
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
};
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/resources/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE5C;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAAiB;IACjD,sCAAsC;IACtC,MAAM,CAAC,gBAAgB,CACrB,OAAO,EACP,oBAAoB,EACpB;QACE,KAAK,EAAE,mBAAmB;QAC1B,WAAW,EAAE,gDAAgD;QAC7D,QAAQ,EAAE,kBAAkB;KAC7B,EACD,KAAK,EAAE,GAAG,EAAE,EAAE;QACZ,MAAM,KAAK,GAAG;YACZ,MAAM,EAAE;gBACN,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI;gBACxB,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,OAAO;gBAC9B,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE;gBACxB,WAAW,EAAE,OAAO,CAAC,OAAO;gBAC5B,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE;aACnC;YACD,KAAK,EAAE,KAAK,CAAC,QAAQ,EAAE;YACvB,MAAM,EAAE;gBACN,OAAO,EAAE;oBACP,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,OAAO;oBAC/B,YAAY,EAAE,MAAM,CAAC,OAAO,CAAC,YAAY;iBAC1C;gBACD,UAAU,EAAE;oBACV,kBAAkB,EAAE,MAAM,CAAC,UAAU,CAAC,kBAAkB;oBACxD,eAAe,EAAE,MAAM,CAAC,UAAU,CAAC,eAAe;iBACnD;aACF;SACF,CAAC;QAEF,OAAO;YACL,QAAQ,EAAE;gBACR;oBACE,GAAG,EAAE,GAAG,CAAC,IAAI;oBACb,QAAQ,EAAE,kBAAkB;oBAC5B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;iBACrC;aACF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
/**
|
|
3
|
+
* Creates and configures the MCP server instance
|
|
4
|
+
* Using McpServer (high-level API) instead of deprecated Server class
|
|
5
|
+
*/
|
|
6
|
+
export declare function createMcpServer(): McpServer;
|
|
7
|
+
export declare function startStdioServer(): Promise<void>;
|
|
8
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAQpE;;;GAGG;AACH,wBAAgB,eAAe,IAAI,SAAS,CAY3C;AAGD,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC,CAiBtD"}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
3
|
+
import { config } from './config/index.js';
|
|
4
|
+
import { registerTools } from './tools/index.js';
|
|
5
|
+
import { registerResources } from './resources/index.js';
|
|
6
|
+
import { registerPrompts } from './prompts/index.js';
|
|
7
|
+
import { logError, logInfo } from './services/logger.js';
|
|
8
|
+
/**
|
|
9
|
+
* Creates and configures the MCP server instance
|
|
10
|
+
* Using McpServer (high-level API) instead of deprecated Server class
|
|
11
|
+
*/
|
|
12
|
+
export function createMcpServer() {
|
|
13
|
+
const server = new McpServer({
|
|
14
|
+
name: config.server.name,
|
|
15
|
+
version: config.server.version,
|
|
16
|
+
});
|
|
17
|
+
// Register all features using the modern API
|
|
18
|
+
registerTools(server);
|
|
19
|
+
registerResources(server);
|
|
20
|
+
registerPrompts(server);
|
|
21
|
+
return server;
|
|
22
|
+
}
|
|
23
|
+
// Export function to start server with stdio transport
|
|
24
|
+
export async function startStdioServer() {
|
|
25
|
+
const server = createMcpServer();
|
|
26
|
+
const transport = new StdioServerTransport();
|
|
27
|
+
// Error handlers
|
|
28
|
+
server.server.onerror = (error) => {
|
|
29
|
+
logError('[MCP Error]', error instanceof Error ? error : { error });
|
|
30
|
+
};
|
|
31
|
+
process.on('SIGINT', async () => {
|
|
32
|
+
process.stdout.write('\nShutting down superFetch MCP server...\n');
|
|
33
|
+
await server.close();
|
|
34
|
+
process.exit(0);
|
|
35
|
+
});
|
|
36
|
+
await server.connect(transport);
|
|
37
|
+
logInfo('superFetch MCP server running on stdio');
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAEzD;;;GAGG;AACH,MAAM,UAAU,eAAe;IAC7B,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI;QACxB,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,OAAO;KAC/B,CAAC,CAAC;IAEH,6CAA6C;IAC7C,aAAa,CAAC,MAAM,CAAC,CAAC;IACtB,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAC1B,eAAe,CAAC,MAAM,CAAC,CAAC;IAExB,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,uDAAuD;AACvD,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,MAAM,MAAM,GAAG,eAAe,EAAE,CAAC;IACjC,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAE7C,iBAAiB;IACjB,MAAM,CAAC,MAAM,CAAC,OAAO,GAAG,CAAC,KAAK,EAAE,EAAE;QAChC,QAAQ,CAAC,aAAa,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;IACtE,CAAC,CAAC;IAEF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,KAAK,IAAI,EAAE;QAC9B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,4CAA4C,CAAC,CAAC;QACnE,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QACrB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;IAEH,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,OAAO,CAAC,wCAAwC,CAAC,CAAC;AACpD,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { CacheEntry } from '../types/index.js';
|
|
2
|
+
export declare function createCacheKey(namespace: string, url: string): string;
|
|
3
|
+
export declare function get(cacheKey: string): CacheEntry | undefined;
|
|
4
|
+
export declare function set(cacheKey: string, content: string): void;
|
|
5
|
+
export declare function clear(): void;
|
|
6
|
+
export declare function getStats(): {
|
|
7
|
+
size: number;
|
|
8
|
+
maxKeys: number;
|
|
9
|
+
ttl: number;
|
|
10
|
+
hits: number;
|
|
11
|
+
misses: number;
|
|
12
|
+
sets: number;
|
|
13
|
+
hitRate: string;
|
|
14
|
+
};
|
|
15
|
+
export declare function keys(): string[];
|
|
16
|
+
//# sourceMappingURL=cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/services/cache.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAapD,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAErE;AAED,wBAAgB,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAa5D;AAED,wBAAgB,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAe3D;AAED,wBAAgB,KAAK,IAAI,IAAI,CAE5B;AAED,wBAAgB,QAAQ;;;;;;;;EAavB;AAED,wBAAgB,IAAI,IAAI,MAAM,EAAE,CAE/B"}
|