@iflow-mcp/mcp-webresearch 0.1.7
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/LICENSE +21 -0
- package/README.md +131 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1016 -0
- package/dist/index.js.map +1 -0
- package/package.json +45 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 The Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# MCP Web Research Server
|
|
2
|
+
|
|
3
|
+
A Model Context Protocol (MCP) server for web research.
|
|
4
|
+
|
|
5
|
+
Bring real-time info into Claude and easily research any topic.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- Google search integration
|
|
10
|
+
- Webpage content extraction
|
|
11
|
+
- Research session tracking (list of visited pages, search queries, etc.)
|
|
12
|
+
- Screenshot capture
|
|
13
|
+
|
|
14
|
+
## Prerequisites
|
|
15
|
+
|
|
16
|
+
- [Node.js](https://nodejs.org/) >= 18 (includes `npm` and `npx`)
|
|
17
|
+
- [Claude Desktop app](https://claude.ai/download)
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
First, ensure you've downloaded and installed the [Claude Desktop app](https://claude.ai/download) and you have npm installed.
|
|
22
|
+
|
|
23
|
+
Next, add this entry to your `claude_desktop_config.json` (on Mac, found at `~/Library/Application\ Support/Claude/claude_desktop_config.json`):
|
|
24
|
+
|
|
25
|
+
```json
|
|
26
|
+
{
|
|
27
|
+
"mcpServers": {
|
|
28
|
+
"webresearch": {
|
|
29
|
+
"command": "npx",
|
|
30
|
+
"args": ["-y", "@mzxrai/mcp-webresearch@latest"]
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
This config allows Claude Desktop to automatically start the web research MCP server when needed.
|
|
37
|
+
|
|
38
|
+
## Usage
|
|
39
|
+
|
|
40
|
+
Simply start a chat with Claude and send a prompt that would benefit from web research. If you'd like a prebuilt prompt customized for deeper web research, you can use the `agentic-research` prompt that we provide through this package. Access that prompt in Claude Desktop by clicking the Paperclip icon in the chat input and then selecting `Choose an integration` → `webresearch` → `agentic-research`.
|
|
41
|
+
|
|
42
|
+
<img src="https://i.ibb.co/N6Y3C0q/Screenshot-2024-12-05-at-11-01-27-PM.png" alt="Example screenshot of web research" width="400"/>
|
|
43
|
+
|
|
44
|
+
### Tools
|
|
45
|
+
|
|
46
|
+
1. `search_google`
|
|
47
|
+
- Performs Google searches and extracts results
|
|
48
|
+
- Arguments: `{ query: string }`
|
|
49
|
+
|
|
50
|
+
2. `visit_page`
|
|
51
|
+
- Visits a webpage and extracts its content
|
|
52
|
+
- Arguments: `{ url: string, takeScreenshot?: boolean }`
|
|
53
|
+
|
|
54
|
+
3. `take_screenshot`
|
|
55
|
+
- Takes a screenshot of the current page
|
|
56
|
+
- No arguments required
|
|
57
|
+
|
|
58
|
+
### Prompts
|
|
59
|
+
|
|
60
|
+
#### `agentic-research`
|
|
61
|
+
A guided research prompt that helps Claude conduct thorough web research. The prompt instructs Claude to:
|
|
62
|
+
- Start with broad searches to understand the topic landscape
|
|
63
|
+
- Prioritize high-quality, authoritative sources
|
|
64
|
+
- Iteratively refine the research direction based on findings
|
|
65
|
+
- Keep you informed and let you guide the research interactively
|
|
66
|
+
- Always cite sources with URLs
|
|
67
|
+
|
|
68
|
+
### Resources
|
|
69
|
+
|
|
70
|
+
We expose two things as MCP resources: (1) captured webpage screenshots, and (2) the research session.
|
|
71
|
+
|
|
72
|
+
#### Screenshots
|
|
73
|
+
|
|
74
|
+
When you take a screenshot, it's saved as an MCP resource. You can access captured screenshots in Claude Desktop via the Paperclip icon.
|
|
75
|
+
|
|
76
|
+
#### Research Session
|
|
77
|
+
|
|
78
|
+
The server maintains a research session that includes:
|
|
79
|
+
- Search queries
|
|
80
|
+
- Visited pages
|
|
81
|
+
- Extracted content
|
|
82
|
+
- Screenshots
|
|
83
|
+
- Timestamps
|
|
84
|
+
|
|
85
|
+
### Suggestions
|
|
86
|
+
|
|
87
|
+
For the best results, if you choose not to use the `agentic-research` prompt when doing your research, it may be helpful to suggest high-quality sources for Claude to use when researching general topics. For example, you could prompt `news today from reuters or AP` instead of `news today`.
|
|
88
|
+
|
|
89
|
+
## Problems
|
|
90
|
+
|
|
91
|
+
This is very much pre-alpha code. And it is also AIGC, so expect bugs.
|
|
92
|
+
|
|
93
|
+
If you run into issues, it may be helpful to check Claude Desktop's MCP logs:
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
tail -n 20 -f ~/Library/Logs/Claude/mcp*.log
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Development
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
# Install dependencies
|
|
103
|
+
pnpm install
|
|
104
|
+
|
|
105
|
+
# Build the project
|
|
106
|
+
pnpm build
|
|
107
|
+
|
|
108
|
+
# Watch for changes
|
|
109
|
+
pnpm watch
|
|
110
|
+
|
|
111
|
+
# Run in development mode
|
|
112
|
+
pnpm dev
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Requirements
|
|
116
|
+
|
|
117
|
+
- Node.js >= 18
|
|
118
|
+
- Playwright (automatically installed as a dependency)
|
|
119
|
+
|
|
120
|
+
## Verified Platforms
|
|
121
|
+
|
|
122
|
+
- [x] macOS
|
|
123
|
+
- [ ] Linux
|
|
124
|
+
|
|
125
|
+
## License
|
|
126
|
+
|
|
127
|
+
MIT
|
|
128
|
+
|
|
129
|
+
## Author
|
|
130
|
+
|
|
131
|
+
[mzxrai](https://github.com/mzxrai)
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,1016 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Core dependencies for MCP server and protocol handling
|
|
3
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
4
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
5
|
+
import { CallToolRequestSchema, ListResourcesRequestSchema, ListToolsRequestSchema, ReadResourceRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, McpError, ErrorCode, } from "@modelcontextprotocol/sdk/types.js";
|
|
6
|
+
// Web scraping and content processing dependencies
|
|
7
|
+
import { chromium } from 'playwright';
|
|
8
|
+
import TurndownService from "turndown";
|
|
9
|
+
import * as fs from 'fs';
|
|
10
|
+
import * as path from 'path';
|
|
11
|
+
import * as os from 'os';
|
|
12
|
+
// Initialize temp directory for screenshots
|
|
13
|
+
const SCREENSHOTS_DIR = fs.mkdtempSync(path.join(os.tmpdir(), 'mcp-screenshots-'));
|
|
14
|
+
// Initialize Turndown service for converting HTML to Markdown
|
|
15
|
+
// Configure with specific formatting preferences
|
|
16
|
+
const turndownService = new TurndownService({
|
|
17
|
+
headingStyle: 'atx', // Use # style headings
|
|
18
|
+
hr: '---', // Horizontal rule style
|
|
19
|
+
bulletListMarker: '-', // List item marker
|
|
20
|
+
codeBlockStyle: 'fenced', // Use ``` for code blocks
|
|
21
|
+
emDelimiter: '_', // Italics style
|
|
22
|
+
strongDelimiter: '**', // Bold style
|
|
23
|
+
linkStyle: 'inlined', // Use inline links
|
|
24
|
+
});
|
|
25
|
+
// Custom Turndown rules for better content extraction
|
|
26
|
+
// Remove script and style tags completely
|
|
27
|
+
turndownService.addRule('removeScripts', {
|
|
28
|
+
filter: ['script', 'style', 'noscript'],
|
|
29
|
+
replacement: () => ''
|
|
30
|
+
});
|
|
31
|
+
// Preserve link elements with their href attributes
|
|
32
|
+
turndownService.addRule('preserveLinks', {
|
|
33
|
+
filter: 'a',
|
|
34
|
+
replacement: (content, node) => {
|
|
35
|
+
const element = node;
|
|
36
|
+
const href = element.getAttribute('href');
|
|
37
|
+
return href ? `[${content}](${href})` : content;
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
// Preserve image elements with their src and alt attributes
|
|
41
|
+
turndownService.addRule('preserveImages', {
|
|
42
|
+
filter: 'img',
|
|
43
|
+
replacement: (content, node) => {
|
|
44
|
+
const element = node;
|
|
45
|
+
const alt = element.getAttribute('alt') || '';
|
|
46
|
+
const src = element.getAttribute('src');
|
|
47
|
+
return src ? `` : '';
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
// Screenshot management functions
|
|
51
|
+
async function saveScreenshot(screenshot, title) {
|
|
52
|
+
// Convert screenshot from base64 to buffer
|
|
53
|
+
const buffer = Buffer.from(screenshot, 'base64');
|
|
54
|
+
// Check size before saving
|
|
55
|
+
const MAX_SIZE = 5 * 1024 * 1024; // 5MB
|
|
56
|
+
if (buffer.length > MAX_SIZE) {
|
|
57
|
+
throw new McpError(ErrorCode.InvalidRequest, `Screenshot too large: ${Math.round(buffer.length / (1024 * 1024))}MB exceeds ${MAX_SIZE / (1024 * 1024)}MB limit`);
|
|
58
|
+
}
|
|
59
|
+
// Generate a safe filename
|
|
60
|
+
const timestamp = new Date().getTime();
|
|
61
|
+
const safeTitle = title.replace(/[^a-z0-9]/gi, '_').toLowerCase();
|
|
62
|
+
const filename = `${safeTitle}-${timestamp}.png`;
|
|
63
|
+
const filepath = path.join(SCREENSHOTS_DIR, filename);
|
|
64
|
+
// Save the validated screenshot
|
|
65
|
+
await fs.promises.writeFile(filepath, buffer);
|
|
66
|
+
// Return the filepath to the saved screenshot
|
|
67
|
+
return filepath;
|
|
68
|
+
}
|
|
69
|
+
// Cleanup function to remove all screenshots from disk
|
|
70
|
+
async function cleanupScreenshots() {
|
|
71
|
+
try {
|
|
72
|
+
// Remove all files in the screenshots directory
|
|
73
|
+
const files = await fs.promises.readdir(SCREENSHOTS_DIR);
|
|
74
|
+
await Promise.all(files.map(file => fs.promises.unlink(path.join(SCREENSHOTS_DIR, file))));
|
|
75
|
+
// Remove the directory itself
|
|
76
|
+
await fs.promises.rmdir(SCREENSHOTS_DIR);
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
console.error('Error cleaning up screenshots:', error);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
// Available tools for web research functionality
|
|
83
|
+
const TOOLS = [
|
|
84
|
+
{
|
|
85
|
+
name: "search_google",
|
|
86
|
+
description: "Search Google for a query",
|
|
87
|
+
inputSchema: {
|
|
88
|
+
type: "object",
|
|
89
|
+
properties: {
|
|
90
|
+
query: { type: "string", description: "Search query" },
|
|
91
|
+
},
|
|
92
|
+
required: ["query"],
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
name: "visit_page",
|
|
97
|
+
description: "Visit a webpage and extract its content",
|
|
98
|
+
inputSchema: {
|
|
99
|
+
type: "object",
|
|
100
|
+
properties: {
|
|
101
|
+
url: { type: "string", description: "URL to visit" },
|
|
102
|
+
takeScreenshot: { type: "boolean", description: "Whether to take a screenshot" },
|
|
103
|
+
},
|
|
104
|
+
required: ["url"],
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
name: "take_screenshot",
|
|
109
|
+
description: "Take a screenshot of the current page",
|
|
110
|
+
inputSchema: {
|
|
111
|
+
type: "object",
|
|
112
|
+
properties: {}, // No parameters needed
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
];
|
|
116
|
+
// Configure available prompts with their specifications
|
|
117
|
+
const PROMPTS = {
|
|
118
|
+
// Agentic research prompt configuration
|
|
119
|
+
"agentic-research": {
|
|
120
|
+
name: "agentic-research", // Type-safe name
|
|
121
|
+
description: "Conduct iterative web research on a topic, exploring it thoroughly through multiple steps while maintaining a dialogue with the user",
|
|
122
|
+
arguments: [
|
|
123
|
+
{
|
|
124
|
+
name: "topic", // Topic argument specification
|
|
125
|
+
description: "The topic or question to research", // Description of the argument
|
|
126
|
+
required: true // Topic is mandatory
|
|
127
|
+
}
|
|
128
|
+
]
|
|
129
|
+
}
|
|
130
|
+
}; // Make object immutable
|
|
131
|
+
// Global state management for browser and research session
|
|
132
|
+
let browser; // Puppeteer browser instance
|
|
133
|
+
let page; // Current active page
|
|
134
|
+
let currentSession; // Current research session data
|
|
135
|
+
// Configuration constants for session management
|
|
136
|
+
const MAX_RESULTS_PER_SESSION = 100; // Maximum number of results to store per session
|
|
137
|
+
const MAX_RETRIES = 3; // Maximum retry attempts for operations
|
|
138
|
+
const RETRY_DELAY = 1000; // Delay between retries in milliseconds
|
|
139
|
+
// Generic retry mechanism for handling transient failures
|
|
140
|
+
async function withRetry(operation, // Operation to retry
|
|
141
|
+
retries = MAX_RETRIES, // Number of retry attempts
|
|
142
|
+
delay = RETRY_DELAY // Delay between retries
|
|
143
|
+
) {
|
|
144
|
+
let lastError;
|
|
145
|
+
// Attempt operation up to max retries
|
|
146
|
+
for (let i = 0; i < retries; i++) {
|
|
147
|
+
try {
|
|
148
|
+
return await operation();
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
lastError = error;
|
|
152
|
+
if (i < retries - 1) {
|
|
153
|
+
console.error(`Attempt ${i + 1} failed, retrying in ${delay}ms:`, error);
|
|
154
|
+
await new Promise(resolve => setTimeout(resolve, delay));
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
throw lastError; // Throw last error if all retries failed
|
|
159
|
+
}
|
|
160
|
+
// Add a new research result to the current session with data management
|
|
161
|
+
function addResult(result) {
|
|
162
|
+
// If no current session exists, initialize a new one
|
|
163
|
+
if (!currentSession) {
|
|
164
|
+
currentSession = {
|
|
165
|
+
query: "Research Session",
|
|
166
|
+
results: [],
|
|
167
|
+
lastUpdated: new Date().toISOString(),
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
// If the session has reached the maximum number of results, remove the oldest result
|
|
171
|
+
if (currentSession.results.length >= MAX_RESULTS_PER_SESSION) {
|
|
172
|
+
currentSession.results.shift();
|
|
173
|
+
}
|
|
174
|
+
// Add the new result to the session and update the last updated timestamp
|
|
175
|
+
currentSession.results.push(result);
|
|
176
|
+
currentSession.lastUpdated = new Date().toISOString();
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Specifically handles Google's consent dialog in regions that require it
|
|
180
|
+
* @param page - Playwright Page object
|
|
181
|
+
*/
|
|
182
|
+
async function dismissGoogleConsent(page) {
|
|
183
|
+
// Regions that commonly show cookie/consent banners
|
|
184
|
+
const regions = [
|
|
185
|
+
// Europe
|
|
186
|
+
'.google.de', '.google.fr', '.google.co.uk',
|
|
187
|
+
'.google.it', '.google.es', '.google.nl',
|
|
188
|
+
'.google.pl', '.google.ie', '.google.dk',
|
|
189
|
+
'.google.no', '.google.se', '.google.fi',
|
|
190
|
+
'.google.at', '.google.ch', '.google.be',
|
|
191
|
+
'.google.pt', '.google.gr', '.google.com.tr',
|
|
192
|
+
// Asia Pacific
|
|
193
|
+
'.google.co.id', '.google.com.sg', '.google.co.th',
|
|
194
|
+
'.google.com.my', '.google.com.ph', '.google.com.au',
|
|
195
|
+
'.google.co.nz', '.google.com.vn',
|
|
196
|
+
// Generic domains
|
|
197
|
+
'.google.com', '.google.co'
|
|
198
|
+
];
|
|
199
|
+
try {
|
|
200
|
+
// Get current URL
|
|
201
|
+
const currentUrl = page.url();
|
|
202
|
+
// Skip consent check if not in a supported region
|
|
203
|
+
if (!regions.some(domain => currentUrl.includes(domain))) {
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
// Quick check for consent dialog existence
|
|
207
|
+
const hasConsent = await page.$('form:has(button[aria-label]), div[aria-modal="true"], ' +
|
|
208
|
+
// Common dialog containers
|
|
209
|
+
'div[role="dialog"], div[role="alertdialog"], ' +
|
|
210
|
+
// Common cookie/consent specific elements
|
|
211
|
+
'div[class*="consent"], div[id*="consent"], ' +
|
|
212
|
+
'div[class*="cookie"], div[id*="cookie"], ' +
|
|
213
|
+
// Common modal/popup classes
|
|
214
|
+
'div[class*="modal"]:has(button), div[class*="popup"]:has(button), ' +
|
|
215
|
+
// Common banner patterns
|
|
216
|
+
'div[class*="banner"]:has(button), div[id*="banner"]:has(button)').then(Boolean);
|
|
217
|
+
// If no consent dialog is found, return
|
|
218
|
+
if (!hasConsent) {
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
// Handle the consent dialog using common consent button patterns
|
|
222
|
+
await page.evaluate(() => {
|
|
223
|
+
const consentPatterns = {
|
|
224
|
+
// Common accept button text patterns across languages
|
|
225
|
+
text: [
|
|
226
|
+
// English
|
|
227
|
+
'accept all', 'agree', 'consent',
|
|
228
|
+
// German
|
|
229
|
+
'alle akzeptieren', 'ich stimme zu', 'zustimmen',
|
|
230
|
+
// French
|
|
231
|
+
'tout accepter', 'j\'accepte',
|
|
232
|
+
// Spanish
|
|
233
|
+
'aceptar todo', 'acepto',
|
|
234
|
+
// Italian
|
|
235
|
+
'accetta tutto', 'accetto',
|
|
236
|
+
// Portuguese
|
|
237
|
+
'aceitar tudo', 'concordo',
|
|
238
|
+
// Dutch
|
|
239
|
+
'alles accepteren', 'akkoord',
|
|
240
|
+
// Polish
|
|
241
|
+
'zaakceptuj wszystko', 'zgadzam się',
|
|
242
|
+
// Swedish
|
|
243
|
+
'godkänn alla', 'godkänn',
|
|
244
|
+
// Danish
|
|
245
|
+
'accepter alle', 'accepter',
|
|
246
|
+
// Norwegian
|
|
247
|
+
'godta alle', 'godta',
|
|
248
|
+
// Finnish
|
|
249
|
+
'hyväksy kaikki', 'hyväksy',
|
|
250
|
+
// Indonesian
|
|
251
|
+
'terima semua', 'setuju', 'saya setuju',
|
|
252
|
+
// Malay
|
|
253
|
+
'terima semua', 'setuju',
|
|
254
|
+
// Thai
|
|
255
|
+
'ยอมรับทั้งหมด', 'ยอมรับ',
|
|
256
|
+
// Vietnamese
|
|
257
|
+
'chấp nhận tất cả', 'đồng ý',
|
|
258
|
+
// Filipino/Tagalog
|
|
259
|
+
'tanggapin lahat', 'sumang-ayon',
|
|
260
|
+
// Japanese
|
|
261
|
+
'すべて同意する', '同意する',
|
|
262
|
+
// Korean
|
|
263
|
+
'모두 동의', '동의'
|
|
264
|
+
],
|
|
265
|
+
// Common aria-label patterns
|
|
266
|
+
ariaLabels: [
|
|
267
|
+
'consent', 'accept', 'agree',
|
|
268
|
+
'cookie', 'privacy', 'terms',
|
|
269
|
+
'persetujuan', 'setuju', // Indonesian
|
|
270
|
+
'ยอมรับ', // Thai
|
|
271
|
+
'đồng ý', // Vietnamese
|
|
272
|
+
'同意' // Japanese/Chinese
|
|
273
|
+
]
|
|
274
|
+
};
|
|
275
|
+
// Finds the accept button by text or aria-label
|
|
276
|
+
const findAcceptButton = () => {
|
|
277
|
+
// Get all buttons on the page
|
|
278
|
+
const buttons = Array.from(document.querySelectorAll('button'));
|
|
279
|
+
// Find the accept button
|
|
280
|
+
return buttons.find(button => {
|
|
281
|
+
// Get the text content and aria-label of the button
|
|
282
|
+
const text = button.textContent?.toLowerCase() || '';
|
|
283
|
+
const label = button.getAttribute('aria-label')?.toLowerCase() || '';
|
|
284
|
+
// Check for matching text patterns
|
|
285
|
+
const hasMatchingText = consentPatterns.text.some(pattern => text.includes(pattern));
|
|
286
|
+
// Check for matching aria-labels
|
|
287
|
+
const hasMatchingLabel = consentPatterns.ariaLabels.some(pattern => label.includes(pattern));
|
|
288
|
+
// Return true if either text or aria-label matches
|
|
289
|
+
return hasMatchingText || hasMatchingLabel;
|
|
290
|
+
});
|
|
291
|
+
};
|
|
292
|
+
// Find the accept button
|
|
293
|
+
const acceptButton = findAcceptButton();
|
|
294
|
+
// If an accept button is found, click it
|
|
295
|
+
if (acceptButton) {
|
|
296
|
+
acceptButton.click();
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
catch (error) {
|
|
301
|
+
console.log('Consent handling failed:', error);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
// Safe page navigation with error handling and bot detection
|
|
305
|
+
async function safePageNavigation(page, url) {
|
|
306
|
+
try {
|
|
307
|
+
// Step 1: Set cookies to bypass consent banner
|
|
308
|
+
await page.context().addCookies([{
|
|
309
|
+
name: 'CONSENT',
|
|
310
|
+
value: 'YES+',
|
|
311
|
+
domain: '.google.com',
|
|
312
|
+
path: '/'
|
|
313
|
+
}]);
|
|
314
|
+
// Step 2: Initial navigation
|
|
315
|
+
const response = await page.goto(url, {
|
|
316
|
+
waitUntil: 'domcontentloaded',
|
|
317
|
+
timeout: 15000
|
|
318
|
+
});
|
|
319
|
+
// Step 3: Basic response validation
|
|
320
|
+
if (!response) {
|
|
321
|
+
throw new Error('Navigation failed: no response received');
|
|
322
|
+
}
|
|
323
|
+
// Check HTTP status code; if 400 or higher, throw an error
|
|
324
|
+
const status = response.status();
|
|
325
|
+
if (status >= 400) {
|
|
326
|
+
throw new Error(`HTTP ${status}: ${response.statusText()}`);
|
|
327
|
+
}
|
|
328
|
+
// Step 4: Wait for network to become idle or timeout
|
|
329
|
+
await Promise.race([
|
|
330
|
+
page.waitForLoadState('networkidle', { timeout: 5000 })
|
|
331
|
+
.catch(() => { }),
|
|
332
|
+
// Fallback timeout in case networkidle never occurs
|
|
333
|
+
new Promise(resolve => setTimeout(resolve, 5000))
|
|
334
|
+
]);
|
|
335
|
+
// Step 5: Security and content validation
|
|
336
|
+
const validation = await page.evaluate(() => {
|
|
337
|
+
const botProtectionExists = [
|
|
338
|
+
'#challenge-running', // Cloudflare
|
|
339
|
+
'#cf-challenge-running', // Cloudflare
|
|
340
|
+
'#px-captcha', // PerimeterX
|
|
341
|
+
'#ddos-protection', // Various
|
|
342
|
+
'#waf-challenge-html' // Various WAFs
|
|
343
|
+
].some(selector => document.querySelector(selector));
|
|
344
|
+
// Check for suspicious page titles
|
|
345
|
+
const suspiciousTitle = [
|
|
346
|
+
'security check',
|
|
347
|
+
'ddos protection',
|
|
348
|
+
'please wait',
|
|
349
|
+
'just a moment',
|
|
350
|
+
'attention required'
|
|
351
|
+
].some(phrase => document.title.toLowerCase().includes(phrase));
|
|
352
|
+
// Count words in the page content
|
|
353
|
+
const bodyText = document.body.innerText || '';
|
|
354
|
+
const words = bodyText.trim().split(/\s+/).length;
|
|
355
|
+
// Return validation results
|
|
356
|
+
return {
|
|
357
|
+
wordCount: words,
|
|
358
|
+
botProtection: botProtectionExists,
|
|
359
|
+
suspiciousTitle,
|
|
360
|
+
title: document.title
|
|
361
|
+
};
|
|
362
|
+
});
|
|
363
|
+
// If bot protection is detected, throw an error
|
|
364
|
+
if (validation.botProtection) {
|
|
365
|
+
throw new Error('Bot protection detected');
|
|
366
|
+
}
|
|
367
|
+
// If the page title is suspicious, throw an error
|
|
368
|
+
if (validation.suspiciousTitle) {
|
|
369
|
+
throw new Error(`Suspicious page title detected: "${validation.title}"`);
|
|
370
|
+
}
|
|
371
|
+
// If the page contains insufficient content, throw an error
|
|
372
|
+
if (validation.wordCount < 10) {
|
|
373
|
+
throw new Error('Page contains insufficient content');
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
catch (error) {
|
|
377
|
+
// If an error occurs during navigation, throw an error with the URL and the error message
|
|
378
|
+
throw new Error(`Navigation to ${url} failed: ${error.message}`);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
// Take and optimize a screenshot
|
|
382
|
+
async function takeScreenshotWithSizeLimit(page) {
|
|
383
|
+
const MAX_SIZE = 5 * 1024 * 1024;
|
|
384
|
+
const MAX_DIMENSION = 1920;
|
|
385
|
+
const MIN_DIMENSION = 800;
|
|
386
|
+
// Set viewport size
|
|
387
|
+
await page.setViewportSize({
|
|
388
|
+
width: 1600,
|
|
389
|
+
height: 900
|
|
390
|
+
});
|
|
391
|
+
// Take initial screenshot
|
|
392
|
+
let screenshot = await page.screenshot({
|
|
393
|
+
type: 'png',
|
|
394
|
+
fullPage: false
|
|
395
|
+
});
|
|
396
|
+
// Handle buffer conversion
|
|
397
|
+
let buffer = screenshot;
|
|
398
|
+
let attempts = 0;
|
|
399
|
+
const MAX_ATTEMPTS = 3;
|
|
400
|
+
// While screenshot is too large, reduce size
|
|
401
|
+
while (buffer.length > MAX_SIZE && attempts < MAX_ATTEMPTS) {
|
|
402
|
+
// Get current viewport size
|
|
403
|
+
const viewport = page.viewportSize();
|
|
404
|
+
if (!viewport)
|
|
405
|
+
continue;
|
|
406
|
+
// Calculate new dimensions
|
|
407
|
+
const scaleFactor = Math.pow(0.75, attempts + 1);
|
|
408
|
+
let newWidth = Math.round(viewport.width * scaleFactor);
|
|
409
|
+
let newHeight = Math.round(viewport.height * scaleFactor);
|
|
410
|
+
// Ensure dimensions are within bounds
|
|
411
|
+
newWidth = Math.max(MIN_DIMENSION, Math.min(MAX_DIMENSION, newWidth));
|
|
412
|
+
newHeight = Math.max(MIN_DIMENSION, Math.min(MAX_DIMENSION, newHeight));
|
|
413
|
+
// Update viewport with new dimensions
|
|
414
|
+
await page.setViewportSize({
|
|
415
|
+
width: newWidth,
|
|
416
|
+
height: newHeight
|
|
417
|
+
});
|
|
418
|
+
// Take new screenshot
|
|
419
|
+
screenshot = await page.screenshot({
|
|
420
|
+
type: 'png',
|
|
421
|
+
fullPage: false
|
|
422
|
+
});
|
|
423
|
+
// Update buffer with new screenshot
|
|
424
|
+
buffer = screenshot;
|
|
425
|
+
// Increment retry attempts
|
|
426
|
+
attempts++;
|
|
427
|
+
}
|
|
428
|
+
// Final attempt with minimum settings
|
|
429
|
+
if (buffer.length > MAX_SIZE) {
|
|
430
|
+
await page.setViewportSize({
|
|
431
|
+
width: MIN_DIMENSION,
|
|
432
|
+
height: MIN_DIMENSION
|
|
433
|
+
});
|
|
434
|
+
// Take final screenshot
|
|
435
|
+
screenshot = await page.screenshot({
|
|
436
|
+
type: 'png',
|
|
437
|
+
fullPage: false
|
|
438
|
+
});
|
|
439
|
+
// Update buffer with final screenshot
|
|
440
|
+
buffer = screenshot;
|
|
441
|
+
// Throw error if final screenshot is still too large
|
|
442
|
+
if (buffer.length > MAX_SIZE) {
|
|
443
|
+
throw new McpError(ErrorCode.InvalidRequest, `Failed to reduce screenshot to under 5MB even with minimum settings`);
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
// Convert Buffer to base64 string before returning
|
|
447
|
+
return buffer.toString('base64');
|
|
448
|
+
}
|
|
449
|
+
// Initialize MCP server with basic configuration
|
|
450
|
+
const server = new Server({
|
|
451
|
+
name: "webresearch", // Server name identifier
|
|
452
|
+
version: "0.1.7", // Server version number
|
|
453
|
+
}, {
|
|
454
|
+
capabilities: {
|
|
455
|
+
tools: {}, // Available tool configurations
|
|
456
|
+
resources: {}, // Resource handling capabilities
|
|
457
|
+
prompts: {} // Prompt processing capabilities
|
|
458
|
+
},
|
|
459
|
+
});
|
|
460
|
+
// Register handler for tool listing requests
|
|
461
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
462
|
+
tools: TOOLS // Return list of available research tools
|
|
463
|
+
}));
|
|
464
|
+
// Register handler for resource listing requests
|
|
465
|
+
server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
466
|
+
// Return empty list if no active session
|
|
467
|
+
if (!currentSession) {
|
|
468
|
+
return { resources: [] };
|
|
469
|
+
}
|
|
470
|
+
// Compile list of available resources
|
|
471
|
+
const resources = [
|
|
472
|
+
// Add session summary resource
|
|
473
|
+
{
|
|
474
|
+
uri: "research://current/summary", // Resource identifier
|
|
475
|
+
name: "Current Research Session Summary",
|
|
476
|
+
description: "Summary of the current research session including queries and results",
|
|
477
|
+
mimeType: "application/json"
|
|
478
|
+
},
|
|
479
|
+
// Add screenshot resources if available
|
|
480
|
+
...currentSession.results
|
|
481
|
+
.map((r, i) => r.screenshotPath ? {
|
|
482
|
+
uri: `research://screenshots/${i}`,
|
|
483
|
+
name: `Screenshot of ${r.title}`,
|
|
484
|
+
description: `Screenshot taken from ${r.url}`,
|
|
485
|
+
mimeType: "image/png"
|
|
486
|
+
} : undefined)
|
|
487
|
+
.filter((r) => r !== undefined)
|
|
488
|
+
];
|
|
489
|
+
// Return compiled list of resources
|
|
490
|
+
return { resources };
|
|
491
|
+
});
|
|
492
|
+
// Register handler for resource content requests
|
|
493
|
+
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
494
|
+
const uri = request.params.uri.toString();
|
|
495
|
+
// Handle session summary requests for research data
|
|
496
|
+
if (uri === "research://current/summary") {
|
|
497
|
+
if (!currentSession) {
|
|
498
|
+
throw new McpError(ErrorCode.InvalidRequest, "No active research session");
|
|
499
|
+
}
|
|
500
|
+
// Return compiled list of resources
|
|
501
|
+
return {
|
|
502
|
+
contents: [{
|
|
503
|
+
uri,
|
|
504
|
+
mimeType: "application/json",
|
|
505
|
+
text: JSON.stringify({
|
|
506
|
+
query: currentSession.query,
|
|
507
|
+
resultCount: currentSession.results.length,
|
|
508
|
+
lastUpdated: currentSession.lastUpdated,
|
|
509
|
+
results: currentSession.results.map(r => ({
|
|
510
|
+
title: r.title,
|
|
511
|
+
url: r.url,
|
|
512
|
+
timestamp: r.timestamp,
|
|
513
|
+
screenshotPath: r.screenshotPath
|
|
514
|
+
}))
|
|
515
|
+
}, null, 2)
|
|
516
|
+
}]
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
// Handle screenshot requests
|
|
520
|
+
if (uri.startsWith("research://screenshots/")) {
|
|
521
|
+
const index = parseInt(uri.split("/").pop() || "", 10);
|
|
522
|
+
// Verify session exists
|
|
523
|
+
if (!currentSession) {
|
|
524
|
+
throw new McpError(ErrorCode.InvalidRequest, "No active research session");
|
|
525
|
+
}
|
|
526
|
+
// Verify index is within bounds
|
|
527
|
+
if (isNaN(index) || index < 0 || index >= currentSession.results.length) {
|
|
528
|
+
throw new McpError(ErrorCode.InvalidRequest, `Screenshot index out of bounds: ${index}`);
|
|
529
|
+
}
|
|
530
|
+
// Get result containing screenshot
|
|
531
|
+
const result = currentSession.results[index];
|
|
532
|
+
if (!result?.screenshotPath) {
|
|
533
|
+
throw new McpError(ErrorCode.InvalidRequest, `No screenshot available at index: ${index}`);
|
|
534
|
+
}
|
|
535
|
+
try {
|
|
536
|
+
// Read the binary data and convert to base64
|
|
537
|
+
const screenshotData = await fs.promises.readFile(result.screenshotPath);
|
|
538
|
+
// Convert Buffer to base64 string before returning
|
|
539
|
+
const base64Data = screenshotData.toString('base64');
|
|
540
|
+
// Return compiled list of resources
|
|
541
|
+
return {
|
|
542
|
+
contents: [{
|
|
543
|
+
uri,
|
|
544
|
+
mimeType: "image/png",
|
|
545
|
+
blob: base64Data
|
|
546
|
+
}]
|
|
547
|
+
};
|
|
548
|
+
}
|
|
549
|
+
catch (error) {
|
|
550
|
+
// Handle error if screenshot cannot be read
|
|
551
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
|
|
552
|
+
throw new McpError(ErrorCode.InternalError, `Failed to read screenshot: ${errorMessage}`);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
// Handle unknown resource types
|
|
556
|
+
throw new McpError(ErrorCode.InvalidRequest, `Unknown resource: ${uri}`);
|
|
557
|
+
});
|
|
558
|
+
// Initialize MCP server connection using stdio transport
|
|
559
|
+
const transport = new StdioServerTransport();
|
|
560
|
+
server.connect(transport).catch((error) => {
|
|
561
|
+
console.error("Failed to start server:", error);
|
|
562
|
+
process.exit(1);
|
|
563
|
+
});
|
|
564
|
+
// Convert HTML content to clean, readable markdown format
|
|
565
|
+
async function extractContentAsMarkdown(page, // Puppeteer page to extract from
|
|
566
|
+
selector // Optional CSS selector to target specific content
|
|
567
|
+
) {
|
|
568
|
+
// Step 1: Execute content extraction in browser context
|
|
569
|
+
const html = await page.evaluate((sel) => {
|
|
570
|
+
// Handle case where specific selector is provided
|
|
571
|
+
if (sel) {
|
|
572
|
+
const element = document.querySelector(sel);
|
|
573
|
+
// Return element content or empty string if not found
|
|
574
|
+
return element ? element.outerHTML : '';
|
|
575
|
+
}
|
|
576
|
+
// Step 2: Try standard content containers first
|
|
577
|
+
const contentSelectors = [
|
|
578
|
+
'main', // HTML5 semantic main content
|
|
579
|
+
'article', // HTML5 semantic article content
|
|
580
|
+
'[role="main"]', // ARIA main content role
|
|
581
|
+
'#content', // Common content ID
|
|
582
|
+
'.content', // Common content class
|
|
583
|
+
'.main', // Alternative main class
|
|
584
|
+
'.post', // Blog post content
|
|
585
|
+
'.article', // Article content container
|
|
586
|
+
];
|
|
587
|
+
// Try each selector in priority order
|
|
588
|
+
for (const contentSelector of contentSelectors) {
|
|
589
|
+
const element = document.querySelector(contentSelector);
|
|
590
|
+
if (element) {
|
|
591
|
+
return element.outerHTML; // Return first matching content
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
// Step 3: Fallback to cleaning full body content
|
|
595
|
+
const body = document.body;
|
|
596
|
+
// Define elements to remove for cleaner content
|
|
597
|
+
const elementsToRemove = [
|
|
598
|
+
// Navigation elements
|
|
599
|
+
'header', // Page header
|
|
600
|
+
'footer', // Page footer
|
|
601
|
+
'nav', // Navigation sections
|
|
602
|
+
'[role="navigation"]', // ARIA navigation elements
|
|
603
|
+
// Sidebars and complementary content
|
|
604
|
+
'aside', // Sidebar content
|
|
605
|
+
'.sidebar', // Sidebar by class
|
|
606
|
+
'[role="complementary"]', // ARIA complementary content
|
|
607
|
+
// Navigation-related elements
|
|
608
|
+
'.nav', // Navigation classes
|
|
609
|
+
'.menu', // Menu elements
|
|
610
|
+
// Page structure elements
|
|
611
|
+
'.header', // Header classes
|
|
612
|
+
'.footer', // Footer classes
|
|
613
|
+
// Advertising and notices
|
|
614
|
+
'.advertisement', // Advertisement containers
|
|
615
|
+
'.ads', // Ad containers
|
|
616
|
+
'.cookie-notice', // Cookie consent notices
|
|
617
|
+
];
|
|
618
|
+
// Remove each unwanted element from content
|
|
619
|
+
elementsToRemove.forEach(sel => {
|
|
620
|
+
body.querySelectorAll(sel).forEach(el => el.remove());
|
|
621
|
+
});
|
|
622
|
+
// Return cleaned body content
|
|
623
|
+
return body.outerHTML;
|
|
624
|
+
}, selector);
|
|
625
|
+
// Step 4: Handle empty content case
|
|
626
|
+
if (!html) {
|
|
627
|
+
return '';
|
|
628
|
+
}
|
|
629
|
+
try {
|
|
630
|
+
// Step 5: Convert HTML to Markdown
|
|
631
|
+
const markdown = turndownService.turndown(html);
|
|
632
|
+
// Step 6: Clean up and format markdown
|
|
633
|
+
return markdown
|
|
634
|
+
.replace(/\n{3,}/g, '\n\n') // Replace excessive newlines with double
|
|
635
|
+
.replace(/^- $/gm, '') // Remove empty list items
|
|
636
|
+
.replace(/^\s+$/gm, '') // Remove whitespace-only lines
|
|
637
|
+
.trim(); // Remove leading/trailing whitespace
|
|
638
|
+
}
|
|
639
|
+
catch (error) {
|
|
640
|
+
// Log conversion errors and return original HTML as fallback
|
|
641
|
+
console.error('Error converting HTML to Markdown:', error);
|
|
642
|
+
return html;
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
// Validate URL format and ensure security constraints
|
|
646
|
+
function isValidUrl(urlString) {
|
|
647
|
+
try {
|
|
648
|
+
// Attempt to parse URL string
|
|
649
|
+
const url = new URL(urlString);
|
|
650
|
+
// Only allow HTTP and HTTPS protocols for security
|
|
651
|
+
return url.protocol === 'http:' || url.protocol === 'https:';
|
|
652
|
+
}
|
|
653
|
+
catch {
|
|
654
|
+
// Return false for any invalid URL format
|
|
655
|
+
return false;
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
// Tool request handler for executing research operations
|
|
659
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
660
|
+
// Initialize browser for tool operations
|
|
661
|
+
const page = await ensureBrowser();
|
|
662
|
+
switch (request.params.name) {
|
|
663
|
+
// Handle Google search operations
|
|
664
|
+
case "search_google": {
|
|
665
|
+
// Extract search query from request parameters
|
|
666
|
+
const { query } = request.params.arguments;
|
|
667
|
+
try {
|
|
668
|
+
// Execute search with retry mechanism
|
|
669
|
+
const results = await withRetry(async () => {
|
|
670
|
+
// Step 1: Navigate to Google search page
|
|
671
|
+
await safePageNavigation(page, 'https://www.google.com');
|
|
672
|
+
await dismissGoogleConsent(page);
|
|
673
|
+
// Step 2: Find and interact with search input
|
|
674
|
+
await withRetry(async () => {
|
|
675
|
+
// Wait for any search input element to appear
|
|
676
|
+
await Promise.race([
|
|
677
|
+
// Try multiple possible selectors for search input
|
|
678
|
+
page.waitForSelector('input[name="q"]', { timeout: 5000 }),
|
|
679
|
+
page.waitForSelector('textarea[name="q"]', { timeout: 5000 }),
|
|
680
|
+
page.waitForSelector('input[type="text"]', { timeout: 5000 })
|
|
681
|
+
]).catch(() => {
|
|
682
|
+
throw new Error('Search input not found - no matching selectors');
|
|
683
|
+
});
|
|
684
|
+
// Find the actual search input element
|
|
685
|
+
const searchInput = await page.$('input[name="q"]') ||
|
|
686
|
+
await page.$('textarea[name="q"]') ||
|
|
687
|
+
await page.$('input[type="text"]');
|
|
688
|
+
// Verify search input was found
|
|
689
|
+
if (!searchInput) {
|
|
690
|
+
throw new Error('Search input element not found after waiting');
|
|
691
|
+
}
|
|
692
|
+
// Step 3: Enter search query
|
|
693
|
+
await searchInput.click({ clickCount: 3 }); // Select all existing text
|
|
694
|
+
await searchInput.press('Backspace'); // Clear selected text
|
|
695
|
+
await searchInput.type(query); // Type new query
|
|
696
|
+
}, 3, 2000); // Allow 3 retries with 2s delay
|
|
697
|
+
// Step 4: Submit search and wait for results
|
|
698
|
+
await withRetry(async () => {
|
|
699
|
+
await Promise.all([
|
|
700
|
+
page.keyboard.press('Enter'),
|
|
701
|
+
page.waitForLoadState('networkidle', { timeout: 15000 }),
|
|
702
|
+
]);
|
|
703
|
+
});
|
|
704
|
+
// Step 5: Extract search results
|
|
705
|
+
const searchResults = await withRetry(async () => {
|
|
706
|
+
const results = await page.evaluate(() => {
|
|
707
|
+
// Find all search result containers
|
|
708
|
+
const elements = document.querySelectorAll('div.g');
|
|
709
|
+
if (!elements || elements.length === 0) {
|
|
710
|
+
throw new Error('No search results found');
|
|
711
|
+
}
|
|
712
|
+
// Extract data from each result
|
|
713
|
+
return Array.from(elements).map((el) => {
|
|
714
|
+
// Find required elements within result container
|
|
715
|
+
const titleEl = el.querySelector('h3'); // Title element
|
|
716
|
+
const linkEl = el.querySelector('a'); // Link element
|
|
717
|
+
const snippetEl = el.querySelector('div.VwiC3b'); // Snippet element
|
|
718
|
+
// Skip results missing required elements
|
|
719
|
+
if (!titleEl || !linkEl || !snippetEl) {
|
|
720
|
+
return null;
|
|
721
|
+
}
|
|
722
|
+
// Return structured result data
|
|
723
|
+
return {
|
|
724
|
+
title: titleEl.textContent || '', // Result title
|
|
725
|
+
url: linkEl.getAttribute('href') || '', // Result URL
|
|
726
|
+
snippet: snippetEl.textContent || '', // Result description
|
|
727
|
+
};
|
|
728
|
+
}).filter(result => result !== null); // Remove invalid results
|
|
729
|
+
});
|
|
730
|
+
// Verify we found valid results
|
|
731
|
+
if (!results || results.length === 0) {
|
|
732
|
+
throw new Error('No valid search results found');
|
|
733
|
+
}
|
|
734
|
+
// Return compiled list of results
|
|
735
|
+
return results;
|
|
736
|
+
});
|
|
737
|
+
// Step 6: Store results in session
|
|
738
|
+
searchResults.forEach((result) => {
|
|
739
|
+
addResult({
|
|
740
|
+
url: result.url,
|
|
741
|
+
title: result.title,
|
|
742
|
+
content: result.snippet,
|
|
743
|
+
timestamp: new Date().toISOString(),
|
|
744
|
+
});
|
|
745
|
+
});
|
|
746
|
+
// Return compiled list of results
|
|
747
|
+
return searchResults;
|
|
748
|
+
});
|
|
749
|
+
// Step 7: Return formatted results
|
|
750
|
+
return {
|
|
751
|
+
content: [{
|
|
752
|
+
type: "text",
|
|
753
|
+
text: JSON.stringify(results, null, 2) // Pretty-print JSON results
|
|
754
|
+
}]
|
|
755
|
+
};
|
|
756
|
+
}
|
|
757
|
+
catch (error) {
|
|
758
|
+
// Handle and format search errors
|
|
759
|
+
return {
|
|
760
|
+
content: [{
|
|
761
|
+
type: "text",
|
|
762
|
+
text: `Failed to perform search: ${error.message}`
|
|
763
|
+
}],
|
|
764
|
+
isError: true
|
|
765
|
+
};
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
// Handle webpage visit and content extraction
|
|
769
|
+
case "visit_page": {
|
|
770
|
+
// Extract URL and screenshot flag from request
|
|
771
|
+
const { url, takeScreenshot } = request.params.arguments;
|
|
772
|
+
// Step 1: Validate URL format and security
|
|
773
|
+
if (!isValidUrl(url)) {
|
|
774
|
+
return {
|
|
775
|
+
content: [{
|
|
776
|
+
type: "text",
|
|
777
|
+
text: `Invalid URL: ${url}. Only http and https protocols are supported.`
|
|
778
|
+
}],
|
|
779
|
+
isError: true
|
|
780
|
+
};
|
|
781
|
+
}
|
|
782
|
+
try {
|
|
783
|
+
// Step 2: Visit page and extract content with retry mechanism
|
|
784
|
+
const result = await withRetry(async () => {
|
|
785
|
+
// Navigate to target URL safely
|
|
786
|
+
await safePageNavigation(page, url);
|
|
787
|
+
const title = await page.title();
|
|
788
|
+
// Step 3: Extract and process page content
|
|
789
|
+
const content = await withRetry(async () => {
|
|
790
|
+
// Convert page content to markdown
|
|
791
|
+
const extractedContent = await extractContentAsMarkdown(page);
|
|
792
|
+
// If no content is extracted, throw an error
|
|
793
|
+
if (!extractedContent) {
|
|
794
|
+
throw new Error('Failed to extract content');
|
|
795
|
+
}
|
|
796
|
+
// Return the extracted content
|
|
797
|
+
return extractedContent;
|
|
798
|
+
});
|
|
799
|
+
// Step 4: Create result object with page data
|
|
800
|
+
const pageResult = {
|
|
801
|
+
url, // Original URL
|
|
802
|
+
title, // Page title
|
|
803
|
+
content, // Markdown content
|
|
804
|
+
timestamp: new Date().toISOString(), // Capture time
|
|
805
|
+
};
|
|
806
|
+
// Step 5: Take screenshot if requested
|
|
807
|
+
let screenshotUri;
|
|
808
|
+
if (takeScreenshot) {
|
|
809
|
+
// Capture and process screenshot
|
|
810
|
+
const screenshot = await takeScreenshotWithSizeLimit(page);
|
|
811
|
+
pageResult.screenshotPath = await saveScreenshot(screenshot, title);
|
|
812
|
+
// Get the index for the resource URI
|
|
813
|
+
const resultIndex = currentSession ? currentSession.results.length : 0;
|
|
814
|
+
screenshotUri = `research://screenshots/${resultIndex}`;
|
|
815
|
+
// Notify clients about new screenshot resource
|
|
816
|
+
server.notification({
|
|
817
|
+
method: "notifications/resources/list_changed"
|
|
818
|
+
});
|
|
819
|
+
}
|
|
820
|
+
// Step 6: Store result in session
|
|
821
|
+
addResult(pageResult);
|
|
822
|
+
return { pageResult, screenshotUri };
|
|
823
|
+
});
|
|
824
|
+
// Step 7: Return formatted result with screenshot URI if taken
|
|
825
|
+
const response = {
|
|
826
|
+
content: [{
|
|
827
|
+
type: "text",
|
|
828
|
+
text: JSON.stringify({
|
|
829
|
+
url: result.pageResult.url,
|
|
830
|
+
title: result.pageResult.title,
|
|
831
|
+
content: result.pageResult.content,
|
|
832
|
+
timestamp: result.pageResult.timestamp,
|
|
833
|
+
screenshot: result.screenshotUri ? `View screenshot via *MCP Resources* (Paperclip icon) @ URI: ${result.screenshotUri}` : undefined
|
|
834
|
+
}, null, 2)
|
|
835
|
+
}]
|
|
836
|
+
};
|
|
837
|
+
return response;
|
|
838
|
+
}
|
|
839
|
+
catch (error) {
|
|
840
|
+
// Handle and format page visit errors
|
|
841
|
+
return {
|
|
842
|
+
content: [{
|
|
843
|
+
type: "text",
|
|
844
|
+
text: `Failed to visit page: ${error.message}`
|
|
845
|
+
}],
|
|
846
|
+
isError: true
|
|
847
|
+
};
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
// Handle standalone screenshot requests
|
|
851
|
+
case "take_screenshot": {
|
|
852
|
+
try {
|
|
853
|
+
// Step 1: Capture screenshot with retry mechanism
|
|
854
|
+
const screenshot = await withRetry(async () => {
|
|
855
|
+
// Take and optimize screenshot with default size limits
|
|
856
|
+
return await takeScreenshotWithSizeLimit(page);
|
|
857
|
+
});
|
|
858
|
+
// Step 2: Initialize session if needed
|
|
859
|
+
if (!currentSession) {
|
|
860
|
+
currentSession = {
|
|
861
|
+
query: "Screenshot Session", // Session identifier
|
|
862
|
+
results: [], // Empty results array
|
|
863
|
+
lastUpdated: new Date().toISOString(), // Current timestamp
|
|
864
|
+
};
|
|
865
|
+
}
|
|
866
|
+
// Step 3: Get current page information
|
|
867
|
+
const pageUrl = await page.url(); // Current page URL
|
|
868
|
+
const pageTitle = await page.title(); // Current page title
|
|
869
|
+
// Step 4: Save screenshot to disk
|
|
870
|
+
const screenshotPath = await saveScreenshot(screenshot, pageTitle || 'untitled');
|
|
871
|
+
// Step 5: Create and store screenshot result
|
|
872
|
+
const resultIndex = currentSession ? currentSession.results.length : 0;
|
|
873
|
+
addResult({
|
|
874
|
+
url: pageUrl,
|
|
875
|
+
title: pageTitle || "Untitled Page", // Fallback title if none available
|
|
876
|
+
content: "Screenshot taken", // Simple content description
|
|
877
|
+
timestamp: new Date().toISOString(), // Capture time
|
|
878
|
+
screenshotPath // Path to screenshot file
|
|
879
|
+
});
|
|
880
|
+
// Step 6: Notify clients about new screenshot resource
|
|
881
|
+
server.notification({
|
|
882
|
+
method: "notifications/resources/list_changed"
|
|
883
|
+
});
|
|
884
|
+
// Step 7: Return success message with resource URI
|
|
885
|
+
const resourceUri = `research://screenshots/${resultIndex}`;
|
|
886
|
+
return {
|
|
887
|
+
content: [{
|
|
888
|
+
type: "text",
|
|
889
|
+
text: `Screenshot taken successfully. You can view it via *MCP Resources* (Paperclip icon) @ URI: ${resourceUri}`
|
|
890
|
+
}]
|
|
891
|
+
};
|
|
892
|
+
}
|
|
893
|
+
catch (error) {
|
|
894
|
+
// Handle and format screenshot errors
|
|
895
|
+
return {
|
|
896
|
+
content: [{
|
|
897
|
+
type: "text",
|
|
898
|
+
text: `Failed to take screenshot: ${error.message}`
|
|
899
|
+
}],
|
|
900
|
+
isError: true
|
|
901
|
+
};
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
// Handle unknown tool requests
|
|
905
|
+
default:
|
|
906
|
+
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${request.params.name}`);
|
|
907
|
+
}
|
|
908
|
+
});
|
|
909
|
+
// Register handler for prompt listing requests
|
|
910
|
+
server.setRequestHandler(ListPromptsRequestSchema, async () => {
|
|
911
|
+
// Return all available prompts
|
|
912
|
+
return { prompts: Object.values(PROMPTS) };
|
|
913
|
+
});
|
|
914
|
+
// Register handler for prompt retrieval and execution
|
|
915
|
+
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
916
|
+
// Extract and validate prompt name
|
|
917
|
+
const promptName = request.params.name;
|
|
918
|
+
const prompt = PROMPTS[promptName];
|
|
919
|
+
// Handle unknown prompt requests
|
|
920
|
+
if (!prompt) {
|
|
921
|
+
throw new McpError(ErrorCode.InvalidRequest, `Prompt not found: ${promptName}`);
|
|
922
|
+
}
|
|
923
|
+
// Handle agentic research prompt
|
|
924
|
+
if (promptName === "agentic-research") {
|
|
925
|
+
// Extract research topic from request arguments
|
|
926
|
+
const args = request.params.arguments;
|
|
927
|
+
const topic = args?.topic || ""; // Use empty string if no topic provided
|
|
928
|
+
// Return research assistant prompt with instructions
|
|
929
|
+
return {
|
|
930
|
+
messages: [
|
|
931
|
+
// Initial assistant message establishing role
|
|
932
|
+
{
|
|
933
|
+
role: "assistant",
|
|
934
|
+
content: {
|
|
935
|
+
type: "text",
|
|
936
|
+
text: "I am ready to help you with your research. I will conduct thorough web research, explore topics deeply, and maintain a dialogue with you throughout the process."
|
|
937
|
+
}
|
|
938
|
+
},
|
|
939
|
+
// Detailed research instructions for the user
|
|
940
|
+
{
|
|
941
|
+
role: "user",
|
|
942
|
+
content: {
|
|
943
|
+
type: "text",
|
|
944
|
+
text: `I'd like to research this topic: <topic>${topic}</topic>
|
|
945
|
+
|
|
946
|
+
Please help me explore it deeply, like you're a thoughtful, highly-trained research assistant.
|
|
947
|
+
|
|
948
|
+
General instructions:
|
|
949
|
+
1. Start by proposing your research approach -- namely, formulate what initial query you will use to search the web. Propose a relatively broad search to understand the topic landscape. At the same time, make your queries optimized for returning high-quality results based on what you know about constructing Google search queries.
|
|
950
|
+
2. Next, get my input on whether you should proceed with that query or if you should refine it.
|
|
951
|
+
3. Once you have an approved query, perform the search.
|
|
952
|
+
4. Prioritize high quality, authoritative sources when they are available and relevant to the topic. Avoid low quality or spammy sources.
|
|
953
|
+
5. Retrieve information that is relevant to the topic at hand.
|
|
954
|
+
6. Iteratively refine your research direction based on what you find.
|
|
955
|
+
7. Keep me informed of what you find and let *me* guide the direction of the research interactively.
|
|
956
|
+
8. If you run into a dead end while researching, do a Google search for the topic and attempt to find a URL for a relevant page. Then, explore that page in depth.
|
|
957
|
+
9. Only conclude when my research goals are met.
|
|
958
|
+
10. **Always cite your sources**, providing URLs to the sources you used in a citation block at the end of your response.
|
|
959
|
+
|
|
960
|
+
You can use these tools:
|
|
961
|
+
- search_google: Search for information
|
|
962
|
+
- visit_page: Visit and extract content from web pages
|
|
963
|
+
|
|
964
|
+
Do *NOT* use the following tools:
|
|
965
|
+
- Anything related to knowledge graphs or memory, unless explicitly instructed to do so by the user.`
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
]
|
|
969
|
+
};
|
|
970
|
+
}
|
|
971
|
+
// Handle unsupported prompt types
|
|
972
|
+
throw new McpError(ErrorCode.InvalidRequest, "Prompt implementation not found");
|
|
973
|
+
});
|
|
974
|
+
// Ensures browser is running, and creates a new page if needed
|
|
975
|
+
async function ensureBrowser() {
|
|
976
|
+
// Launch browser if not already running
|
|
977
|
+
if (!browser) {
|
|
978
|
+
browser = await chromium.launch({
|
|
979
|
+
headless: true, // Run in headless mode for automation
|
|
980
|
+
});
|
|
981
|
+
// Create initial context and page
|
|
982
|
+
const context = await browser.newContext();
|
|
983
|
+
page = await context.newPage();
|
|
984
|
+
}
|
|
985
|
+
// Create new page if current one is closed/invalid
|
|
986
|
+
if (!page) {
|
|
987
|
+
const context = await browser.newContext();
|
|
988
|
+
page = await context.newPage();
|
|
989
|
+
}
|
|
990
|
+
// Return the current page
|
|
991
|
+
return page;
|
|
992
|
+
}
|
|
993
|
+
// Cleanup function
|
|
994
|
+
async function cleanup() {
|
|
995
|
+
try {
|
|
996
|
+
// Clean up screenshots first
|
|
997
|
+
await cleanupScreenshots();
|
|
998
|
+
// Then close the browser
|
|
999
|
+
if (browser) {
|
|
1000
|
+
await browser.close();
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
catch (error) {
|
|
1004
|
+
console.error('Error during cleanup:', error);
|
|
1005
|
+
}
|
|
1006
|
+
finally {
|
|
1007
|
+
browser = undefined;
|
|
1008
|
+
page = undefined;
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
// Register cleanup handlers
|
|
1012
|
+
process.on('exit', cleanup);
|
|
1013
|
+
process.on('SIGTERM', cleanup);
|
|
1014
|
+
process.on('SIGINT', cleanup);
|
|
1015
|
+
process.on('SIGHUP', cleanup);
|
|
1016
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@iflow-mcp/mcp-webresearch",
|
|
3
|
+
"version": "0.1.7",
|
|
4
|
+
"description": "MCP server for web research",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "mzxrai",
|
|
7
|
+
"homepage": "https://github.com/mzxrai/mcp-webresearch",
|
|
8
|
+
"bugs": "https://github.com/mzxrai/mcp-webresearch/issues",
|
|
9
|
+
"type": "module",
|
|
10
|
+
"bin": {
|
|
11
|
+
"mcp-server-webresearch": "dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsc && shx chmod +x dist/*.js",
|
|
18
|
+
"prepare": "pnpm run build",
|
|
19
|
+
"postinstall": "playwright install chromium",
|
|
20
|
+
"watch": "tsc --watch",
|
|
21
|
+
"dev": "tsx watch index.ts"
|
|
22
|
+
},
|
|
23
|
+
"publishConfig": {
|
|
24
|
+
"access": "public"
|
|
25
|
+
},
|
|
26
|
+
"keywords": [
|
|
27
|
+
"mcp",
|
|
28
|
+
"model-context-protocol",
|
|
29
|
+
"web-research",
|
|
30
|
+
"ai",
|
|
31
|
+
"web-scraping"
|
|
32
|
+
],
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"@modelcontextprotocol/sdk": "1.0.1",
|
|
35
|
+
"playwright": "^1.49.0",
|
|
36
|
+
"turndown": "^7.1.2"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@types/node": "^24.9.1",
|
|
40
|
+
"@types/turndown": "^5.0.4",
|
|
41
|
+
"shx": "^0.3.4",
|
|
42
|
+
"tsx": "^4.19.2",
|
|
43
|
+
"typescript": "^5.6.2"
|
|
44
|
+
}
|
|
45
|
+
}
|