@amplify-studio/open-mcp 0.8.1 → 0.9.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 +268 -23
- package/dist/http-server.js +37 -2
- package/dist/index.js +1 -1
- package/dist/search.d.ts +1 -1
- package/dist/search.js +53 -57
- package/dist/types.d.ts +1 -5
- package/dist/types.js +9 -22
- package/dist/url-reader.js +10 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -11,10 +11,9 @@ Open MCP is a comprehensive server solution that enables AI assistants (like Cla
|
|
|
11
11
|
## Current Features
|
|
12
12
|
|
|
13
13
|
### 🌐 Web Search
|
|
14
|
-
- General web queries
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
- Safe search levels
|
|
14
|
+
- General web queries via Firecrawl API
|
|
15
|
+
- Configurable result limit (default: 10, max: 100)
|
|
16
|
+
- JSON-formatted structured output
|
|
18
17
|
|
|
19
18
|
### 📄 URL Content Reading
|
|
20
19
|
- Extract web page content as text/markdown
|
|
@@ -80,56 +79,67 @@ Open MCP is a comprehensive server solution that enables AI assistants (like Cla
|
|
|
80
79
|
|
|
81
80
|
## Installation
|
|
82
81
|
|
|
83
|
-
### Option 1: From npm (Recommended
|
|
84
|
-
|
|
85
|
-
Install from npm registry:
|
|
82
|
+
### Option 1: From npm (Recommended)
|
|
86
83
|
|
|
87
84
|
**Using Claude CLI:**
|
|
88
85
|
```bash
|
|
89
|
-
claude mcp add
|
|
86
|
+
claude mcp add-json -s user open-mcp '{
|
|
87
|
+
"command": "npx",
|
|
88
|
+
"args": ["-y", "@amplify-studio/open-mcp@latest"]
|
|
89
|
+
}'
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
**With custom gateway:**
|
|
93
|
+
```bash
|
|
94
|
+
claude mcp add-json -s user open-mcp '{
|
|
95
|
+
"command": "npx",
|
|
96
|
+
"args": ["-y", "@amplify-studio/open-mcp@latest"],
|
|
97
|
+
"env": {
|
|
98
|
+
"GATEWAY_URL": "http://115.190.91.253:80"
|
|
99
|
+
}
|
|
100
|
+
}'
|
|
90
101
|
```
|
|
91
102
|
|
|
92
|
-
|
|
103
|
+
### Option 2: Claude Desktop Config
|
|
104
|
+
|
|
105
|
+
Edit `claude_desktop_config.json`:
|
|
106
|
+
|
|
93
107
|
```json
|
|
94
108
|
{
|
|
95
109
|
"mcpServers": {
|
|
96
110
|
"open-mcp": {
|
|
97
111
|
"command": "npx",
|
|
98
|
-
"args": ["-y", "@amplify-studio/open-mcp"]
|
|
112
|
+
"args": ["-y", "@amplify-studio/open-mcp@latest"]
|
|
99
113
|
}
|
|
100
114
|
}
|
|
101
115
|
}
|
|
102
116
|
```
|
|
103
117
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
No installation needed - runs directly from GitHub:
|
|
107
|
-
|
|
108
|
-
**Claude Desktop Config**:
|
|
118
|
+
**With custom gateway:**
|
|
109
119
|
```json
|
|
110
120
|
{
|
|
111
121
|
"mcpServers": {
|
|
112
122
|
"open-mcp": {
|
|
113
123
|
"command": "npx",
|
|
114
|
-
"args": ["-y", "
|
|
124
|
+
"args": ["-y", "@amplify-studio/open-mcp@latest"],
|
|
125
|
+
"env": {
|
|
126
|
+
"GATEWAY_URL": "http://115.190.91.253:80"
|
|
127
|
+
}
|
|
115
128
|
}
|
|
116
129
|
}
|
|
117
130
|
}
|
|
118
131
|
```
|
|
119
132
|
|
|
120
|
-
### Option 3:
|
|
133
|
+
### Option 3: From GitHub
|
|
121
134
|
|
|
122
|
-
|
|
135
|
+
Alternative: install directly from GitHub (no npm):
|
|
123
136
|
|
|
124
137
|
```json
|
|
125
138
|
{
|
|
126
139
|
"mcpServers": {
|
|
127
140
|
"open-mcp": {
|
|
128
141
|
"command": "npx",
|
|
129
|
-
"args": ["-y", "github:amplify-studio/open-mcp"]
|
|
130
|
-
"env": {
|
|
131
|
-
"GATEWAY_URL": "http://your-gateway.com:80"
|
|
132
|
-
}
|
|
142
|
+
"args": ["-y", "github:amplify-studio/open-mcp"]
|
|
133
143
|
}
|
|
134
144
|
}
|
|
135
145
|
}
|
|
@@ -180,6 +190,79 @@ npm link
|
|
|
180
190
|
# Then use: open-mcp
|
|
181
191
|
```
|
|
182
192
|
|
|
193
|
+
## Updating
|
|
194
|
+
|
|
195
|
+
To update to the latest version:
|
|
196
|
+
|
|
197
|
+
### Using Claude CLI
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
# Remove old version
|
|
201
|
+
claude mcp remove open-mcp
|
|
202
|
+
|
|
203
|
+
# Install latest version
|
|
204
|
+
claude mcp add-json -s user open-mcp '{
|
|
205
|
+
"command": "npx",
|
|
206
|
+
"args": ["-y", "@amplify-studio/open-mcp@latest"]
|
|
207
|
+
}'
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### Clear npx Cache (Optional)
|
|
211
|
+
|
|
212
|
+
If you encounter issues after updating:
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
# Clear npx cache
|
|
216
|
+
npm cache clean --force
|
|
217
|
+
|
|
218
|
+
# Then reinstall
|
|
219
|
+
claude mcp remove open-mcp
|
|
220
|
+
claude mcp add-json -s user open-mcp '{
|
|
221
|
+
"command": "npx",
|
|
222
|
+
"args": ["-y", "@amplify-studio/open-mcp@latest"]
|
|
223
|
+
}'
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### Check Current Version
|
|
227
|
+
|
|
228
|
+
```bash
|
|
229
|
+
# View your configuration
|
|
230
|
+
cat ~/Library/Application\ Support/Claude/claude_desktop_config.json
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
## Output Format
|
|
234
|
+
|
|
235
|
+
Both tools return JSON strings for structured data parsing.
|
|
236
|
+
|
|
237
|
+
### Web Search Output
|
|
238
|
+
|
|
239
|
+
```json
|
|
240
|
+
{
|
|
241
|
+
"query": "search term",
|
|
242
|
+
"results": [
|
|
243
|
+
{
|
|
244
|
+
"title": "Result Title",
|
|
245
|
+
"content": "Description or snippet",
|
|
246
|
+
"url": "https://example.com"
|
|
247
|
+
}
|
|
248
|
+
],
|
|
249
|
+
"totalCount": 1,
|
|
250
|
+
"duration": "234ms"
|
|
251
|
+
}
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### URL Read Output
|
|
255
|
+
|
|
256
|
+
```json
|
|
257
|
+
{
|
|
258
|
+
"url": "https://example.com",
|
|
259
|
+
"content": "Page content in markdown/text format...",
|
|
260
|
+
"charCount": 1500,
|
|
261
|
+
"duration": "456ms",
|
|
262
|
+
"cached": false
|
|
263
|
+
}
|
|
264
|
+
```
|
|
265
|
+
|
|
183
266
|
## Configuration
|
|
184
267
|
|
|
185
268
|
| Variable | Required | Default | Description |
|
|
@@ -198,11 +281,119 @@ The server connects to a Gateway API that provides:
|
|
|
198
281
|
|
|
199
282
|
| API | Method | Endpoint | Description |
|
|
200
283
|
|-----|--------|----------|-------------|
|
|
201
|
-
| Search |
|
|
284
|
+
| Search | POST | `/api/firecrawl-search` | Web search via Firecrawl |
|
|
202
285
|
| Read | GET | `/api/read/{url}` | Extract web content |
|
|
203
286
|
| Health | GET | `/health` | Health check |
|
|
204
287
|
| Status | GET | `/api/status` | Service status |
|
|
205
288
|
|
|
289
|
+
## HTTP Transport Mode
|
|
290
|
+
|
|
291
|
+
The server supports two transport modes: **STDIO** (default) and **HTTP**.
|
|
292
|
+
|
|
293
|
+
### STDIO Mode (Default)
|
|
294
|
+
|
|
295
|
+
Standard MCP transport for local development and Claude Desktop integration. The server communicates via stdin/stdout.
|
|
296
|
+
|
|
297
|
+
### HTTP Mode
|
|
298
|
+
|
|
299
|
+
HTTP transport enables remote server deployment and multi-client connections. Uses the **Streamable HTTP** protocol from MCP specification.
|
|
300
|
+
|
|
301
|
+
#### Starting HTTP Server
|
|
302
|
+
|
|
303
|
+
```bash
|
|
304
|
+
# Basic
|
|
305
|
+
MCP_HTTP_PORT=3333 npm start
|
|
306
|
+
|
|
307
|
+
# With custom gateway
|
|
308
|
+
GATEWAY_URL=http://115.190.91.253:80 MCP_HTTP_PORT=3333 npm start
|
|
309
|
+
|
|
310
|
+
# Background mode
|
|
311
|
+
MCP_HTTP_PORT=3333 npm start &
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
#### API Endpoints
|
|
315
|
+
|
|
316
|
+
| Endpoint | Method | Description |
|
|
317
|
+
|----------|--------|-------------|
|
|
318
|
+
| `/health` | GET | Health check |
|
|
319
|
+
| `/mcp` | POST | Send JSON-RPC requests |
|
|
320
|
+
| `/mcp` | GET | Receive SSE notifications |
|
|
321
|
+
| `/mcp` | DELETE | Close session |
|
|
322
|
+
|
|
323
|
+
#### Verify Connection
|
|
324
|
+
|
|
325
|
+
```bash
|
|
326
|
+
# Health check
|
|
327
|
+
curl http://localhost:3333/health
|
|
328
|
+
|
|
329
|
+
# Expected response
|
|
330
|
+
# {"status":"healthy","server":"ihor-sokoliuk/mcp-searxng","version":"0.8.2","transport":"http"}
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
#### Claude Code Integration
|
|
334
|
+
|
|
335
|
+
```bash
|
|
336
|
+
# Add HTTP server to Claude Code
|
|
337
|
+
claude mcp add --transport http open-mcp http://localhost:3333/mcp
|
|
338
|
+
|
|
339
|
+
# Verify
|
|
340
|
+
claude mcp list
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
#### Example curl Commands
|
|
344
|
+
|
|
345
|
+
```bash
|
|
346
|
+
# 1. Initialize session
|
|
347
|
+
curl -X POST http://localhost:3333/mcp \
|
|
348
|
+
-H "Content-Type: application/json" \
|
|
349
|
+
-H "Accept: application/json, text/event-stream" \
|
|
350
|
+
-d '{
|
|
351
|
+
"jsonrpc": "2.0",
|
|
352
|
+
"id": 1,
|
|
353
|
+
"method": "initialize",
|
|
354
|
+
"params": {
|
|
355
|
+
"protocolVersion": "2025-06-18",
|
|
356
|
+
"capabilities": {},
|
|
357
|
+
"clientInfo": {"name": "test-client", "version": "1.0"}
|
|
358
|
+
}
|
|
359
|
+
}'
|
|
360
|
+
|
|
361
|
+
# 2. List tools (use returned session-id)
|
|
362
|
+
curl -X POST http://localhost:3333/mcp \
|
|
363
|
+
-H "Content-Type: application/json" \
|
|
364
|
+
-H "mcp-session-id: <session-id>" \
|
|
365
|
+
-d '{"jsonrpc": "2.0", "id": 2, "method": "tools/list"}'
|
|
366
|
+
|
|
367
|
+
# 3. Call search tool
|
|
368
|
+
curl -X POST http://localhost:3333/mcp \
|
|
369
|
+
-H "Content-Type: application/json" \
|
|
370
|
+
-H "mcp-session-id: <session-id>" \
|
|
371
|
+
-d '{
|
|
372
|
+
"jsonrpc": "2.0",
|
|
373
|
+
"id": 3,
|
|
374
|
+
"method": "tools/call",
|
|
375
|
+
"params": {
|
|
376
|
+
"name": "searxng_web_search",
|
|
377
|
+
"arguments": {"query": "test"}
|
|
378
|
+
}
|
|
379
|
+
}'
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
#### Security Considerations
|
|
383
|
+
|
|
384
|
+
For production deployments:
|
|
385
|
+
|
|
386
|
+
1. **DNS Rebinding Protection** - Enable `enableDnsRebindingProtection` in `http-server.ts`
|
|
387
|
+
2. **Bind to localhost** - Use `127.0.0.1` instead of `0.0.0.0` for local development
|
|
388
|
+
3. **Authentication** - Use API Gateway, reverse proxy, or implement auth headers
|
|
389
|
+
4. **CORS** - Configure `ALLOWED_ORIGINS` environment variable
|
|
390
|
+
|
|
391
|
+
```bash
|
|
392
|
+
# Example: Production configuration
|
|
393
|
+
MCP_HTTP_PORT=3333
|
|
394
|
+
ALLOWED_ORIGINS=https://yourdomain.com
|
|
395
|
+
```
|
|
396
|
+
|
|
206
397
|
## Development
|
|
207
398
|
|
|
208
399
|
```bash
|
|
@@ -222,6 +413,60 @@ npm run inspector
|
|
|
222
413
|
npm run build
|
|
223
414
|
```
|
|
224
415
|
|
|
416
|
+
## Docker Deployment
|
|
417
|
+
|
|
418
|
+
The server can be deployed in HTTP mode using Docker for remote access.
|
|
419
|
+
|
|
420
|
+
### Quick Start (HTTP Mode)
|
|
421
|
+
|
|
422
|
+
```bash
|
|
423
|
+
# Build the Docker image
|
|
424
|
+
docker build -t open-mcp:latest .
|
|
425
|
+
|
|
426
|
+
# Run HTTP server on port 3333
|
|
427
|
+
docker run -d -p 3333:3333 \
|
|
428
|
+
-e MCP_HTTP_PORT=3333 \
|
|
429
|
+
-e GATEWAY_URL=http://115.190.91.253:80 \
|
|
430
|
+
--name open-mcp \
|
|
431
|
+
open-mcp:latest
|
|
432
|
+
|
|
433
|
+
# Verify deployment
|
|
434
|
+
curl http://localhost:3333/health
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
### Configuration
|
|
438
|
+
|
|
439
|
+
| Environment Variable | Description | Default |
|
|
440
|
+
|---------------------|-------------|---------|
|
|
441
|
+
| `MCP_HTTP_PORT` | HTTP server port | 3333 |
|
|
442
|
+
| `GATEWAY_URL` | Gateway API base URL | `http://115.190.91.253:80` |
|
|
443
|
+
| `ALLOWED_ORIGINS` | CORS allowed origins | `*` |
|
|
444
|
+
|
|
445
|
+
### Claude Code Integration
|
|
446
|
+
|
|
447
|
+
```bash
|
|
448
|
+
# Add HTTP server to Claude Code
|
|
449
|
+
claude mcp add --transport http open-mcp http://your-server:3333/mcp
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
### Docker Compose (Optional)
|
|
453
|
+
|
|
454
|
+
For production deployments, you can use Docker Compose to manage the service:
|
|
455
|
+
|
|
456
|
+
```yaml
|
|
457
|
+
services:
|
|
458
|
+
open-mcp:
|
|
459
|
+
image: open-mcp:latest
|
|
460
|
+
container_name: open-mcp
|
|
461
|
+
ports:
|
|
462
|
+
- "3333:3333"
|
|
463
|
+
environment:
|
|
464
|
+
- MCP_HTTP_PORT=3333
|
|
465
|
+
- GATEWAY_URL=http://115.190.91.253:80
|
|
466
|
+
- ALLOWED_ORIGINS=https://yourdomain.com
|
|
467
|
+
restart: unless-stopped
|
|
468
|
+
```
|
|
469
|
+
|
|
225
470
|
## Contributing
|
|
226
471
|
|
|
227
472
|
We're building an open-source community for AI agent infrastructure. Contributions welcome!
|
package/dist/http-server.js
CHANGED
|
@@ -5,19 +5,54 @@ import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/
|
|
|
5
5
|
import { isInitializeRequest } from "@modelcontextprotocol/sdk/types.js";
|
|
6
6
|
import { logMessage } from "./logging.js";
|
|
7
7
|
import { packageVersion } from "./index.js";
|
|
8
|
+
// Get allowed origins from environment variable
|
|
9
|
+
const getAllowedOrigins = () => {
|
|
10
|
+
const allowedOrigins = process.env.ALLOWED_ORIGINS;
|
|
11
|
+
if (!allowedOrigins) {
|
|
12
|
+
return '*'; // Default to allowing all origins
|
|
13
|
+
}
|
|
14
|
+
return allowedOrigins.split(',').map(o => o.trim());
|
|
15
|
+
};
|
|
8
16
|
export async function createHttpServer(server) {
|
|
9
17
|
const app = express();
|
|
10
18
|
app.use(express.json());
|
|
11
19
|
// Add CORS support for web clients
|
|
12
20
|
app.use(cors({
|
|
13
|
-
origin:
|
|
21
|
+
origin: getAllowedOrigins(),
|
|
14
22
|
exposedHeaders: ['Mcp-Session-Id'],
|
|
15
|
-
allowedHeaders: ['Content-Type', 'mcp-session-id'],
|
|
23
|
+
allowedHeaders: ['Content-Type', 'mcp-session-id', 'Accept'],
|
|
24
|
+
credentials: true,
|
|
16
25
|
}));
|
|
17
26
|
// Map to store transports by session ID
|
|
18
27
|
const transports = {};
|
|
28
|
+
// Validate Accept header for MCP specification compliance
|
|
29
|
+
const validateAcceptHeader = (acceptHeader) => {
|
|
30
|
+
if (!acceptHeader) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
const header = acceptHeader.toLowerCase();
|
|
34
|
+
return header.includes('application/json') || header.includes('text/event-stream');
|
|
35
|
+
};
|
|
19
36
|
// Handle POST requests for client-to-server communication
|
|
20
37
|
app.post('/mcp', async (req, res) => {
|
|
38
|
+
// Validate Accept header for MCP spec compliance
|
|
39
|
+
const acceptHeader = req.headers['accept'];
|
|
40
|
+
if (!validateAcceptHeader(acceptHeader)) {
|
|
41
|
+
console.warn(`⚠️ POST request rejected - missing/invalid Accept header:`, {
|
|
42
|
+
clientIP: req.ip || req.connection.remoteAddress,
|
|
43
|
+
accept: acceptHeader || 'undefined',
|
|
44
|
+
userAgent: req.headers['user-agent'],
|
|
45
|
+
});
|
|
46
|
+
res.status(406).json({
|
|
47
|
+
jsonrpc: '2.0',
|
|
48
|
+
error: {
|
|
49
|
+
code: -32000,
|
|
50
|
+
message: 'Not Acceptable: Accept header must include application/json or text/event-stream',
|
|
51
|
+
},
|
|
52
|
+
id: null,
|
|
53
|
+
});
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
21
56
|
const sessionId = req.headers['mcp-session-id'];
|
|
22
57
|
let transport;
|
|
23
58
|
if (sessionId && transports[sessionId]) {
|
package/dist/index.js
CHANGED
|
@@ -84,7 +84,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
84
84
|
if (!isSearXNGWebSearchArgs(args)) {
|
|
85
85
|
throw new Error("Invalid arguments for web search");
|
|
86
86
|
}
|
|
87
|
-
const result = await performWebSearch(server, args.query, args.
|
|
87
|
+
const result = await performWebSearch(server, args.query, args.limit);
|
|
88
88
|
return {
|
|
89
89
|
content: [
|
|
90
90
|
{
|
package/dist/search.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
2
|
-
export declare function performWebSearch(server: Server, query: string,
|
|
2
|
+
export declare function performWebSearch(server: Server, query: string, limit?: number): Promise<string>;
|
package/dist/search.js
CHANGED
|
@@ -1,18 +1,11 @@
|
|
|
1
1
|
import { createProxyAgent } from "./proxy.js";
|
|
2
2
|
import { logMessage } from "./logging.js";
|
|
3
|
-
import { createConfigurationError, createNetworkError, createServerError
|
|
4
|
-
export async function performWebSearch(server, query,
|
|
3
|
+
import { createConfigurationError, createNetworkError, createServerError } from "./error-handler.js";
|
|
4
|
+
export async function performWebSearch(server, query, limit = 10) {
|
|
5
5
|
const startTime = Date.now();
|
|
6
|
-
|
|
7
|
-
const searchParams = [
|
|
8
|
-
`page ${pageno}`,
|
|
9
|
-
`lang: ${language}`,
|
|
10
|
-
time_range ? `time: ${time_range}` : null,
|
|
11
|
-
safesearch ? `safesearch: ${safesearch}` : null
|
|
12
|
-
].filter(Boolean).join(", ");
|
|
13
|
-
logMessage(server, "info", `Starting web search: "${query}" (${searchParams})`);
|
|
6
|
+
logMessage(server, "info", `Starting web search: "${query}" (limit: ${limit})`);
|
|
14
7
|
const gatewayUrl = process.env.GATEWAY_URL || "http://115.190.91.253:80";
|
|
15
|
-
// Validate
|
|
8
|
+
// Validate gateway URL
|
|
16
9
|
let parsedUrl;
|
|
17
10
|
try {
|
|
18
11
|
parsedUrl = new URL(gatewayUrl);
|
|
@@ -20,52 +13,41 @@ export async function performWebSearch(server, query, pageno = 1, time_range, la
|
|
|
20
13
|
catch (error) {
|
|
21
14
|
throw createConfigurationError(`Invalid GATEWAY_URL format: ${gatewayUrl}. Use format: http://115.190.91.253:80`);
|
|
22
15
|
}
|
|
23
|
-
const url = new URL('/api/search
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
31
|
-
if (language && language !== "all") {
|
|
32
|
-
url.searchParams.set("language", language);
|
|
33
|
-
}
|
|
34
|
-
if (safesearch !== undefined && ["0", "1", "2"].includes(safesearch)) {
|
|
35
|
-
url.searchParams.set("safesearch", safesearch);
|
|
36
|
-
}
|
|
37
|
-
// Prepare request options with headers
|
|
16
|
+
const url = new URL('/api/firecrawl-search', parsedUrl);
|
|
17
|
+
// Prepare request body
|
|
18
|
+
const requestBody = {
|
|
19
|
+
query,
|
|
20
|
+
limit
|
|
21
|
+
};
|
|
22
|
+
// Prepare request options
|
|
38
23
|
const requestOptions = {
|
|
39
|
-
method: "
|
|
24
|
+
method: "POST",
|
|
25
|
+
headers: {
|
|
26
|
+
"Content-Type": "application/json"
|
|
27
|
+
},
|
|
28
|
+
body: JSON.stringify(requestBody)
|
|
40
29
|
};
|
|
41
|
-
// Add proxy dispatcher if
|
|
42
|
-
// Node.js fetch uses 'dispatcher' option for proxy, not 'agent'
|
|
30
|
+
// Add proxy dispatcher if configured
|
|
43
31
|
const proxyAgent = createProxyAgent(url.toString());
|
|
44
32
|
if (proxyAgent) {
|
|
45
33
|
requestOptions.dispatcher = proxyAgent;
|
|
46
34
|
}
|
|
47
|
-
// Add basic authentication if
|
|
35
|
+
// Add basic authentication if configured
|
|
48
36
|
const username = process.env.AUTH_USERNAME;
|
|
49
37
|
const password = process.env.AUTH_PASSWORD;
|
|
50
38
|
if (username && password) {
|
|
51
39
|
const base64Auth = Buffer.from(`${username}:${password}`).toString('base64');
|
|
52
|
-
requestOptions.headers = {
|
|
53
|
-
...requestOptions.headers,
|
|
54
|
-
'Authorization': `Basic ${base64Auth}`
|
|
55
|
-
};
|
|
40
|
+
requestOptions.headers['Authorization'] = `Basic ${base64Auth}`;
|
|
56
41
|
}
|
|
57
|
-
// Add User-Agent
|
|
42
|
+
// Add User-Agent if configured
|
|
58
43
|
const userAgent = process.env.USER_AGENT;
|
|
59
44
|
if (userAgent) {
|
|
60
|
-
requestOptions.headers =
|
|
61
|
-
...requestOptions.headers,
|
|
62
|
-
'User-Agent': userAgent
|
|
63
|
-
};
|
|
45
|
+
requestOptions.headers['User-Agent'] = userAgent;
|
|
64
46
|
}
|
|
65
|
-
// Fetch with
|
|
47
|
+
// Fetch with error handling
|
|
66
48
|
let response;
|
|
67
49
|
try {
|
|
68
|
-
logMessage(server, "info", `Making request to: ${url.toString()}`);
|
|
50
|
+
logMessage(server, "info", `Making POST request to: ${url.toString()}`);
|
|
69
51
|
response = await fetch(url.toString(), requestOptions);
|
|
70
52
|
}
|
|
71
53
|
catch (error) {
|
|
@@ -95,7 +77,7 @@ export async function performWebSearch(server, query, pageno = 1, time_range, la
|
|
|
95
77
|
// Parse JSON response
|
|
96
78
|
let data;
|
|
97
79
|
try {
|
|
98
|
-
data =
|
|
80
|
+
data = await response.json();
|
|
99
81
|
}
|
|
100
82
|
catch (error) {
|
|
101
83
|
let responseText;
|
|
@@ -106,25 +88,39 @@ export async function performWebSearch(server, query, pageno = 1, time_range, la
|
|
|
106
88
|
responseText = '[Could not read response text]';
|
|
107
89
|
}
|
|
108
90
|
const context = { url: url.toString() };
|
|
109
|
-
throw
|
|
91
|
+
throw new Error(`Failed to parse JSON response: ${responseText}`);
|
|
110
92
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
93
|
+
// Handle Firecrawl API response format: {success: true, data: [...]}
|
|
94
|
+
let results = data.results || data.data || [];
|
|
95
|
+
// If wrapped in success object
|
|
96
|
+
if (data.success && data.data) {
|
|
97
|
+
results = data.data;
|
|
98
|
+
}
|
|
99
|
+
if (!Array.isArray(results)) {
|
|
100
|
+
throw new Error(`Invalid response format: results is not an array`);
|
|
114
101
|
}
|
|
115
|
-
const results = data.results.map((result) => ({
|
|
116
|
-
title: result.title || "",
|
|
117
|
-
content: result.content || "",
|
|
118
|
-
url: result.url || "",
|
|
119
|
-
score: result.score || 0,
|
|
120
|
-
}));
|
|
121
102
|
if (results.length === 0) {
|
|
122
103
|
logMessage(server, "info", `No results found for query: "${query}"`);
|
|
123
|
-
return
|
|
104
|
+
return JSON.stringify({
|
|
105
|
+
query,
|
|
106
|
+
results: [],
|
|
107
|
+
totalCount: 0,
|
|
108
|
+
duration: `${Date.now() - startTime}ms`
|
|
109
|
+
}, null, 2);
|
|
124
110
|
}
|
|
111
|
+
// Format results (API returns: url, title, description)
|
|
112
|
+
const formattedResults = results.map((result) => ({
|
|
113
|
+
title: result.title || "",
|
|
114
|
+
content: result.description || result.content || "",
|
|
115
|
+
url: result.url || result.link || ""
|
|
116
|
+
}));
|
|
125
117
|
const duration = Date.now() - startTime;
|
|
126
|
-
logMessage(server, "info", `Search completed: "${query}"
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
118
|
+
logMessage(server, "info", `Search completed: "${query}" - ${formattedResults.length} results in ${duration}ms`);
|
|
119
|
+
// Return as JSON string
|
|
120
|
+
return JSON.stringify({
|
|
121
|
+
query,
|
|
122
|
+
results: formattedResults,
|
|
123
|
+
totalCount: formattedResults.length,
|
|
124
|
+
duration: `${duration}ms`
|
|
125
|
+
}, null, 2);
|
|
130
126
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -4,15 +4,11 @@ export interface SearXNGWeb {
|
|
|
4
4
|
title: string;
|
|
5
5
|
content: string;
|
|
6
6
|
url: string;
|
|
7
|
-
score: number;
|
|
8
7
|
}>;
|
|
9
8
|
}
|
|
10
9
|
export declare function isSearXNGWebSearchArgs(args: unknown): args is {
|
|
11
10
|
query: string;
|
|
12
|
-
|
|
13
|
-
time_range?: string;
|
|
14
|
-
language?: string;
|
|
15
|
-
safesearch?: string;
|
|
11
|
+
limit?: number;
|
|
16
12
|
};
|
|
17
13
|
export declare const WEB_SEARCH_TOOL: Tool;
|
|
18
14
|
export declare const READ_URL_TOOL: Tool;
|
package/dist/types.js
CHANGED
|
@@ -6,35 +6,22 @@ export function isSearXNGWebSearchArgs(args) {
|
|
|
6
6
|
}
|
|
7
7
|
export const WEB_SEARCH_TOOL = {
|
|
8
8
|
name: "searxng_web_search",
|
|
9
|
-
description: "Performs
|
|
10
|
-
"
|
|
9
|
+
description: "Performs web search using the Gateway API Firecrawl search. " +
|
|
10
|
+
"Returns search results with title, content, URL, and relevance score. " +
|
|
11
|
+
"Use this for general queries, news, articles, and online content.",
|
|
11
12
|
inputSchema: {
|
|
12
13
|
type: "object",
|
|
13
14
|
properties: {
|
|
14
15
|
query: {
|
|
15
16
|
type: "string",
|
|
16
|
-
description: "The search query
|
|
17
|
+
description: "The search query string",
|
|
17
18
|
},
|
|
18
|
-
|
|
19
|
+
limit: {
|
|
19
20
|
type: "number",
|
|
20
|
-
description: "
|
|
21
|
-
default:
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
type: "string",
|
|
25
|
-
description: "Time range of search (day, month, year)",
|
|
26
|
-
enum: ["day", "month", "year"],
|
|
27
|
-
},
|
|
28
|
-
language: {
|
|
29
|
-
type: "string",
|
|
30
|
-
description: "Language code for search results (e.g., 'en', 'fr', 'de'). Default is instance-dependent.",
|
|
31
|
-
default: "all",
|
|
32
|
-
},
|
|
33
|
-
safesearch: {
|
|
34
|
-
type: "string",
|
|
35
|
-
description: "Safe search filter level (0: None, 1: Moderate, 2: Strict)",
|
|
36
|
-
enum: ["0", "1", "2"],
|
|
37
|
-
default: "0",
|
|
21
|
+
description: "Maximum number of results to return (default: 10, max: 100)",
|
|
22
|
+
default: 10,
|
|
23
|
+
minimum: 1,
|
|
24
|
+
maximum: 100,
|
|
38
25
|
},
|
|
39
26
|
},
|
|
40
27
|
required: ["query"],
|
package/dist/url-reader.js
CHANGED
|
@@ -185,10 +185,17 @@ export async function fetchAndConvertToMarkdown(server, url, timeoutMs = 10000,
|
|
|
185
185
|
// Cache the markdown content from gateway
|
|
186
186
|
urlCache.set(url, "", markdownContent);
|
|
187
187
|
// Apply pagination options
|
|
188
|
-
const
|
|
188
|
+
const content = applyPaginationOptions(markdownContent, paginationOptions);
|
|
189
189
|
const duration = Date.now() - startTime;
|
|
190
|
-
logMessage(server, "info", `Successfully fetched and converted URL: ${url} (${
|
|
191
|
-
|
|
190
|
+
logMessage(server, "info", `Successfully fetched and converted URL: ${url} (${content.length} chars in ${duration}ms)`);
|
|
191
|
+
// Return as JSON string
|
|
192
|
+
return JSON.stringify({
|
|
193
|
+
url,
|
|
194
|
+
content,
|
|
195
|
+
charCount: content.length,
|
|
196
|
+
duration: `${duration}ms`,
|
|
197
|
+
cached: !!cachedEntry
|
|
198
|
+
}, null, 2);
|
|
192
199
|
}
|
|
193
200
|
catch (error) {
|
|
194
201
|
if (error.name === "AbortError") {
|
package/package.json
CHANGED