crawlforge-mcp-server 3.0.9 → 3.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -32,11 +32,12 @@ npx crawlforge-setup
32
32
  This will:
33
33
  - Guide you through getting your free API key
34
34
  - Configure your credentials securely
35
+ - **Auto-configure Claude Code and Cursor** (if installed)
35
36
  - Verify your setup is working
36
37
 
37
38
  **Don't have an API key?** Get one free at [https://www.crawlforge.dev/signup](https://www.crawlforge.dev/signup)
38
39
 
39
- ### 3. Configure Your IDE
40
+ ### 3. Configure Your IDE (if not auto-configured)
40
41
 
41
42
  <details>
42
43
  <summary>🤖 For Claude Desktop</summary>
@@ -62,17 +63,39 @@ Restart Claude Desktop to activate.
62
63
  </details>
63
64
 
64
65
  <details>
65
- <summary>đŸ’ģ For Cursor IDE</summary>
66
+ <summary>đŸ–Ĩī¸ For Claude Code CLI (Auto-configured)</summary>
66
67
 
67
- Add to `.cursorrules` in your project:
68
- ```bash
69
- mcp_servers:
70
- crawlforge:
71
- command: npx
72
- args: ["crawlforge-mcp-server"]
68
+ The setup wizard automatically configures Claude Code by adding to `~/.claude.json`:
69
+ ```json
70
+ {
71
+ "mcpServers": {
72
+ "crawlforge": {
73
+ "type": "stdio",
74
+ "command": "crawlforge"
75
+ }
76
+ }
77
+ }
78
+ ```
79
+
80
+ After setup, restart Claude Code to activate.
81
+ </details>
82
+
83
+ <details>
84
+ <summary>đŸ’ģ For Cursor IDE (Auto-configured)</summary>
85
+
86
+ The setup wizard automatically configures Cursor by adding to `~/.cursor/mcp.json`:
87
+ ```json
88
+ {
89
+ "mcpServers": {
90
+ "crawlforge": {
91
+ "type": "stdio",
92
+ "command": "crawlforge"
93
+ }
94
+ }
95
+ }
73
96
  ```
74
97
 
75
- Or use the MCP plugin in Cursor settings.
98
+ Restart Cursor to activate.
76
99
  </details>
77
100
 
78
101
  ## 📊 Available Tools
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "crawlforge-mcp-server",
3
- "version": "3.0.9",
3
+ "version": "3.0.11",
4
4
  "description": "CrawlForge MCP Server - Professional Model Context Protocol server with 19 comprehensive web scraping, crawling, and content processing tools.",
5
5
  "main": "server.js",
6
6
  "bin": {
package/server.js CHANGED
@@ -97,7 +97,7 @@ if (configErrors.length > 0 && config.server.nodeEnv === 'production') {
97
97
  }
98
98
 
99
99
  // Create the server
100
- const server = new McpServer({ name: "crawlforge", version: "3.0.4" });
100
+ const server = new McpServer({ name: "crawlforge", version: "3.0.10" });
101
101
 
102
102
  // Helper function to wrap tool handlers with authentication and credit tracking
103
103
  function withAuth(toolName, handler) {
package/setup.js CHANGED
@@ -6,16 +6,143 @@
6
6
  */
7
7
 
8
8
  import readline from 'readline';
9
+ import fs from 'fs';
10
+ import path from 'path';
11
+ import os from 'os';
9
12
  import AuthManager from './src/core/AuthManager.js';
10
13
 
11
- const rl = readline.createInterface({
12
- input: process.stdin,
13
- output: process.stdout
14
- });
14
+ /**
15
+ * Add CrawlForge to an MCP client configuration file
16
+ * @param {string} configPath - Path to the config file
17
+ * @param {string} clientName - Name of the client (for messages)
18
+ * @param {string} apiKey - The CrawlForge API key to include in env
19
+ * @returns {object} Result with success status and message
20
+ */
21
+ function addToMcpConfig(configPath, clientName, apiKey) {
22
+ // Check if config exists
23
+ if (!fs.existsSync(configPath)) {
24
+ return {
25
+ success: false,
26
+ message: `${clientName} config not found (${configPath}). You may need to configure manually.`,
27
+ notInstalled: true
28
+ };
29
+ }
30
+
31
+ try {
32
+ // Read existing config
33
+ const configContent = fs.readFileSync(configPath, 'utf8');
34
+ const config = JSON.parse(configContent);
35
+
36
+ // Ensure mcpServers object exists
37
+ if (!config.mcpServers) {
38
+ config.mcpServers = {};
39
+ }
40
+
41
+ // Check if crawlforge is already configured with the correct API key
42
+ const existingConfig = config.mcpServers.crawlforge;
43
+ if (existingConfig && existingConfig.env?.CRAWLFORGE_API_KEY === apiKey) {
44
+ return {
45
+ success: true,
46
+ message: `CrawlForge already configured in ${clientName}`,
47
+ alreadyConfigured: true
48
+ };
49
+ }
50
+
51
+ // Add or update crawlforge MCP server configuration with API key
52
+ config.mcpServers.crawlforge = {
53
+ type: "stdio",
54
+ command: "crawlforge",
55
+ args: [],
56
+ env: {
57
+ CRAWLFORGE_API_KEY: apiKey
58
+ }
59
+ };
60
+
61
+ // Write updated config
62
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
63
+
64
+ return {
65
+ success: true,
66
+ message: existingConfig
67
+ ? `CrawlForge API key updated in ${clientName} MCP config`
68
+ : `CrawlForge added to ${clientName} MCP config`
69
+ };
70
+ } catch (error) {
71
+ return {
72
+ success: false,
73
+ message: `Failed to update ${clientName} config: ${error.message}`
74
+ };
75
+ }
76
+ }
77
+
78
+ /**
79
+ * Configure all detected MCP clients
80
+ * @param {string} apiKey - The CrawlForge API key to include in env
81
+ * @returns {object} Results for each client
82
+ */
83
+ function configureMcpClients(apiKey) {
84
+ const results = {
85
+ claudeCode: null,
86
+ cursor: null
87
+ };
88
+
89
+ // Claude Code config path
90
+ const claudeConfigPath = path.join(os.homedir(), '.claude.json');
91
+ results.claudeCode = addToMcpConfig(claudeConfigPath, 'Claude Code', apiKey);
92
+
93
+ // Cursor config path (macOS)
94
+ const cursorConfigPath = path.join(os.homedir(), '.cursor', 'mcp.json');
95
+ if (fs.existsSync(path.join(os.homedir(), '.cursor'))) {
96
+ // Cursor directory exists, try to configure
97
+ if (!fs.existsSync(cursorConfigPath)) {
98
+ // Create mcp.json if it doesn't exist
99
+ try {
100
+ fs.writeFileSync(cursorConfigPath, JSON.stringify({ mcpServers: {} }, null, 2));
101
+ } catch (e) {
102
+ // Ignore creation errors
103
+ }
104
+ }
105
+ results.cursor = addToMcpConfig(cursorConfigPath, 'Cursor', apiKey);
106
+ }
107
+
108
+ return results;
109
+ }
110
+
111
+ let rl = null;
112
+
113
+ function getReadline() {
114
+ if (!rl) {
115
+ rl = readline.createInterface({
116
+ input: process.stdin,
117
+ output: process.stdout
118
+ });
119
+ }
120
+ return rl;
121
+ }
15
122
 
16
- const question = (query) => new Promise((resolve) => rl.question(query, resolve));
123
+ const question = (query) => new Promise((resolve) => getReadline().question(query, resolve));
124
+
125
+ function closeReadline() {
126
+ if (rl) {
127
+ rl.close();
128
+ rl = null;
129
+ }
130
+ }
17
131
 
18
132
  async function main() {
133
+ // Check if running interactively
134
+ const isInteractive = process.stdin.isTTY;
135
+
136
+ if (!isInteractive) {
137
+ console.log('');
138
+ console.log('❌ Setup requires an interactive terminal.');
139
+ console.log('');
140
+ console.log('Please run this command directly in your terminal:');
141
+ console.log(' npx crawlforge-setup');
142
+ console.log('');
143
+ process.exit(1);
144
+ }
145
+
19
146
  console.log('');
20
147
  console.log('╔═══════════════════════════════════════════════════════╗');
21
148
  console.log('║ CrawlForge MCP Server Setup Wizard ║');
@@ -45,7 +172,7 @@ async function main() {
45
172
 
46
173
  if (overwrite.toLowerCase() !== 'y') {
47
174
  console.log('Setup cancelled.');
48
- rl.close();
175
+ closeReadline();
49
176
  process.exit(0);
50
177
  }
51
178
  console.log('');
@@ -58,7 +185,7 @@ async function main() {
58
185
  console.log('');
59
186
  console.log('❌ API key is required');
60
187
  console.log('Get your free API key at: https://www.crawlforge.dev/signup');
61
- rl.close();
188
+ closeReadline();
62
189
  process.exit(1);
63
190
  }
64
191
 
@@ -74,8 +201,72 @@ async function main() {
74
201
  console.log('');
75
202
  console.log('🎉 Setup complete! You can now use CrawlForge MCP Server.');
76
203
  console.log('');
204
+
205
+ // Auto-configure MCP clients (Claude Code, Cursor) with API key
206
+ console.log('🔧 Configuring MCP client integrations...');
207
+ const clientResults = configureMcpClients(apiKey.trim());
208
+ let anyConfigured = false;
209
+ let needsRestart = false;
210
+
211
+ // Report Claude Code status
212
+ if (clientResults.claudeCode) {
213
+ if (clientResults.claudeCode.success) {
214
+ anyConfigured = true;
215
+ if (clientResults.claudeCode.alreadyConfigured) {
216
+ console.log('✅ Claude Code: Already configured');
217
+ } else {
218
+ console.log('✅ Claude Code: Added to MCP config (~/.claude.json)');
219
+ needsRestart = true;
220
+ }
221
+ } else if (!clientResults.claudeCode.notInstalled) {
222
+ console.log(`âš ī¸ Claude Code: ${clientResults.claudeCode.message}`);
223
+ }
224
+ }
225
+
226
+ // Report Cursor status
227
+ if (clientResults.cursor) {
228
+ if (clientResults.cursor.success) {
229
+ anyConfigured = true;
230
+ if (clientResults.cursor.alreadyConfigured) {
231
+ console.log('✅ Cursor: Already configured');
232
+ } else {
233
+ console.log('✅ Cursor: Added to MCP config (~/.cursor/mcp.json)');
234
+ needsRestart = true;
235
+ }
236
+ } else if (!clientResults.cursor.notInstalled) {
237
+ console.log(`âš ī¸ Cursor: ${clientResults.cursor.message}`);
238
+ }
239
+ }
240
+
241
+ // Show restart warning if any client was configured
242
+ if (needsRestart) {
243
+ console.log('');
244
+ console.log('âš ī¸ IMPORTANT: Restart your IDE to load the new MCP server');
245
+ }
246
+
247
+ // Show manual config instructions if no clients detected
248
+ if (!anyConfigured && clientResults.claudeCode?.notInstalled && !clientResults.cursor) {
249
+ console.log('â„šī¸ No MCP clients detected. Manual configuration needed:');
250
+ console.log('');
251
+ console.log(' Add this to your MCP client config:');
252
+ console.log(' {');
253
+ console.log(' "mcpServers": {');
254
+ console.log(' "crawlforge": {');
255
+ console.log(' "type": "stdio",');
256
+ console.log(' "command": "crawlforge",');
257
+ console.log(' "env": {');
258
+ console.log(` "CRAWLFORGE_API_KEY": "${apiKey.trim()}"`);
259
+ console.log(' }');
260
+ console.log(' }');
261
+ console.log(' }');
262
+ console.log(' }');
263
+ }
264
+
265
+ console.log('');
266
+ console.log('────────────────────────────────────────────────────────');
267
+ console.log('');
77
268
  console.log('Quick start:');
78
- console.log(' npm start # Start the MCP server');
269
+ console.log(' crawlforge # Start the MCP server');
79
270
  console.log(' npm run test # Test your setup');
80
271
  console.log('');
81
272
  console.log('Need help? Visit: https://www.crawlforge.dev/docs');
@@ -88,11 +279,11 @@ async function main() {
88
279
  console.log(' â€ĸ Documentation: https://www.crawlforge.dev/docs');
89
280
  console.log(' â€ĸ Support: support@crawlforge.dev');
90
281
  console.log('');
91
- rl.close();
282
+ closeReadline();
92
283
  process.exit(1);
93
284
  }
94
285
 
95
- rl.close();
286
+ closeReadline();
96
287
  }
97
288
 
98
289
  // Handle errors
@@ -100,13 +291,13 @@ process.on('unhandledRejection', (error) => {
100
291
  console.error('');
101
292
  console.error('❌ Setup error:', error.message);
102
293
  console.error('');
103
- rl.close();
294
+ closeReadline();
104
295
  process.exit(1);
105
296
  });
106
297
 
107
298
  // Run setup
108
299
  main().catch((error) => {
109
300
  console.error('❌ Fatal error:', error);
110
- rl.close();
301
+ closeReadline();
111
302
  process.exit(1);
112
303
  });
@@ -11,7 +11,7 @@ export const config = {
11
11
  // CrawlForge API Configuration
12
12
  crawlforge: {
13
13
  apiKey: process.env.CRAWLFORGE_API_KEY || '',
14
- apiBaseUrl: process.env.CRAWLFORGE_API_URL || 'https://api.crawlforge.dev'
14
+ apiBaseUrl: process.env.CRAWLFORGE_API_URL || 'https://www.crawlforge.dev'
15
15
  },
16
16
 
17
17
  // Performance
@@ -9,7 +9,7 @@ import path from 'path';
9
9
 
10
10
  class AuthManager {
11
11
  constructor() {
12
- this.apiEndpoint = process.env.CRAWLFORGE_API_URL || 'https://api.crawlforge.dev';
12
+ this.apiEndpoint = process.env.CRAWLFORGE_API_URL || 'https://www.crawlforge.dev';
13
13
  this.configPath = path.join(process.env.HOME || process.env.USERPROFILE, '.crawlforge', 'config.json');
14
14
  this.config = null;
15
15
  this.creditCache = new Map();
@@ -8,7 +8,7 @@
8
8
  */
9
9
 
10
10
  export class CrawlForgeSearchAdapter {
11
- constructor(apiKey, apiBaseUrl = 'https://api.crawlforge.dev') {
11
+ constructor(apiKey, apiBaseUrl = 'https://www.crawlforge.dev') {
12
12
  if (!apiKey) {
13
13
  throw new Error('CrawlForge API key is required for search functionality');
14
14
  }