httpcat-cli 0.3.0 → 0.3.1
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/.github/workflows/ci.yml +3 -0
- package/.github/workflows/rc-publish.yml +6 -0
- package/.github/workflows/release.yml +102 -0
- package/.github/workflows/sync-version.yml +31 -2
- package/README.md +1408 -109
- package/additions.txt +3 -0
- package/bun.lock +260 -25
- package/dist/agent/autonomous-trader.d.ts.map +1 -0
- package/dist/agent/autonomous-trader.js +362 -0
- package/dist/agent/autonomous-trader.js.map +1 -0
- package/dist/agent/ax-agent.d.ts.map +1 -1
- package/dist/agent/ax-agent.js +356 -18
- package/dist/agent/ax-agent.js.map +1 -1
- package/dist/agent/event-client.d.ts.map +1 -0
- package/dist/agent/event-client.js +82 -0
- package/dist/agent/event-client.js.map +1 -0
- package/dist/agent/log-stream.d.ts.map +1 -0
- package/dist/agent/log-stream.js +95 -0
- package/dist/agent/log-stream.js.map +1 -0
- package/dist/agent/memory/conversation-session.d.ts.map +1 -0
- package/dist/agent/memory/conversation-session.js +232 -0
- package/dist/agent/memory/conversation-session.js.map +1 -0
- package/dist/agent/memory/conversation-store.d.ts.map +1 -0
- package/dist/agent/memory/conversation-store.js +214 -0
- package/dist/agent/memory/conversation-store.js.map +1 -0
- package/dist/agent/memory/database-schema.d.ts.map +1 -0
- package/dist/agent/memory/database-schema.js +355 -0
- package/dist/agent/memory/database-schema.js.map +1 -0
- package/dist/agent/memory/decision-tracker.d.ts.map +1 -0
- package/dist/agent/memory/decision-tracker.js +274 -0
- package/dist/agent/memory/decision-tracker.js.map +1 -0
- package/dist/agent/memory/memory-manager.d.ts.map +1 -0
- package/dist/agent/memory/memory-manager.js +187 -0
- package/dist/agent/memory/memory-manager.js.map +1 -0
- package/dist/agent/memory/types.d.ts.map +1 -0
- package/dist/agent/memory/types.js +5 -0
- package/dist/agent/memory/types.js.map +1 -0
- package/dist/agent/message-formatter.d.ts.map +1 -0
- package/dist/agent/message-formatter.js +76 -0
- package/dist/agent/message-formatter.js.map +1 -0
- package/dist/agent/position-db.d.ts.map +1 -0
- package/dist/agent/position-db.js +154 -0
- package/dist/agent/position-db.js.map +1 -0
- package/dist/agent/simple-chat-ui-static.d.ts.map +1 -0
- package/dist/agent/simple-chat-ui-static.js +129 -0
- package/dist/agent/simple-chat-ui-static.js.map +1 -0
- package/dist/agent/simple-chat-ui.d.ts.map +1 -0
- package/dist/agent/simple-chat-ui.js +90 -0
- package/dist/agent/simple-chat-ui.js.map +1 -0
- package/dist/agent/tools.d.ts.map +1 -1
- package/dist/agent/tools.js +297 -4
- package/dist/agent/tools.js.map +1 -1
- package/dist/agent/ui.d.ts.map +1 -0
- package/dist/agent/ui.js +84 -0
- package/dist/agent/ui.js.map +1 -0
- package/dist/agent/unified-runtime.d.ts.map +1 -0
- package/dist/agent/unified-runtime.js +397 -0
- package/dist/agent/unified-runtime.js.map +1 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +272 -21
- package/dist/client.js.map +1 -1
- package/dist/commands/account.d.ts.map +1 -1
- package/dist/commands/account.js +187 -33
- package/dist/commands/account.js.map +1 -1
- package/dist/commands/agent.d.ts.map +1 -0
- package/dist/commands/agent.js +125 -0
- package/dist/commands/agent.js.map +1 -0
- package/dist/commands/approve.d.ts.map +1 -0
- package/dist/commands/approve.js +505 -0
- package/dist/commands/approve.js.map +1 -0
- package/dist/commands/automation.d.ts.map +1 -0
- package/dist/commands/automation.js +346 -0
- package/dist/commands/automation.js.map +1 -0
- package/dist/commands/balances.d.ts.map +1 -1
- package/dist/commands/balances.js +226 -73
- package/dist/commands/balances.js.map +1 -1
- package/dist/commands/buy.d.ts.map +1 -1
- package/dist/commands/buy.js +149 -146
- package/dist/commands/buy.js.map +1 -1
- package/dist/commands/call.d.ts.map +1 -0
- package/dist/commands/call.js +51 -0
- package/dist/commands/call.js.map +1 -0
- package/dist/commands/cex.d.ts.map +1 -0
- package/dist/commands/cex.js +958 -0
- package/dist/commands/cex.js.map +1 -0
- package/dist/commands/chat.d.ts.map +1 -1
- package/dist/commands/chat.js +169 -411
- package/dist/commands/chat.js.map +1 -1
- package/dist/commands/claim.d.ts.map +1 -1
- package/dist/commands/claim.js +313 -29
- package/dist/commands/claim.js.map +1 -1
- package/dist/commands/create.d.ts.map +1 -1
- package/dist/commands/create.js +151 -43
- package/dist/commands/create.js.map +1 -1
- package/dist/commands/gasless-swap.d.ts.map +1 -0
- package/dist/commands/gasless-swap.js +232 -0
- package/dist/commands/gasless-swap.js.map +1 -0
- package/dist/commands/health.d.ts.map +1 -1
- package/dist/commands/health.js +63 -7
- package/dist/commands/health.js.map +1 -1
- package/dist/commands/info.d.ts.map +1 -1
- package/dist/commands/info.js +131 -47
- package/dist/commands/info.js.map +1 -1
- package/dist/commands/launchpad.d.ts.map +1 -0
- package/dist/commands/launchpad.js +708 -0
- package/dist/commands/launchpad.js.map +1 -0
- package/dist/commands/list.d.ts.map +1 -1
- package/dist/commands/list.js +57 -23
- package/dist/commands/list.js.map +1 -1
- package/dist/commands/market.d.ts.map +1 -0
- package/dist/commands/market.js +960 -0
- package/dist/commands/market.js.map +1 -0
- package/dist/commands/mcp-install.d.ts.map +1 -0
- package/dist/commands/mcp-install.js +387 -0
- package/dist/commands/mcp-install.js.map +1 -0
- package/dist/commands/opps.d.ts.map +1 -0
- package/dist/commands/opps.js +409 -0
- package/dist/commands/opps.js.map +1 -0
- package/dist/commands/perps.d.ts.map +1 -0
- package/dist/commands/perps.js +248 -0
- package/dist/commands/perps.js.map +1 -0
- package/dist/commands/portfolio.d.ts.map +1 -0
- package/dist/commands/portfolio.js +679 -0
- package/dist/commands/portfolio.js.map +1 -0
- package/dist/commands/positions.d.ts.map +1 -1
- package/dist/commands/positions.js +76 -47
- package/dist/commands/positions.js.map +1 -1
- package/dist/commands/predict.d.ts.map +1 -0
- package/dist/commands/predict.js +280 -0
- package/dist/commands/predict.js.map +1 -0
- package/dist/commands/predictions.d.ts.map +1 -0
- package/dist/commands/predictions.js +486 -0
- package/dist/commands/predictions.js.map +1 -0
- package/dist/commands/risk.d.ts.map +1 -0
- package/dist/commands/risk.js +225 -0
- package/dist/commands/risk.js.map +1 -0
- package/dist/commands/security.d.ts.map +1 -0
- package/dist/commands/security.js +244 -0
- package/dist/commands/security.js.map +1 -0
- package/dist/commands/sell.d.ts.map +1 -1
- package/dist/commands/sell.js +67 -34
- package/dist/commands/sell.js.map +1 -1
- package/dist/commands/send.d.ts.map +1 -0
- package/dist/commands/send.js +733 -0
- package/dist/commands/send.js.map +1 -0
- package/dist/commands/sign.d.ts.map +1 -0
- package/dist/commands/sign.js +1048 -0
- package/dist/commands/sign.js.map +1 -0
- package/dist/commands/swap.d.ts.map +1 -0
- package/dist/commands/swap.js +744 -0
- package/dist/commands/swap.js.map +1 -0
- package/dist/commands/system.d.ts.map +1 -0
- package/dist/commands/system.js +417 -0
- package/dist/commands/system.js.map +1 -0
- package/dist/commands/tools/index.d.ts.map +1 -0
- package/dist/commands/tools/index.js +2040 -0
- package/dist/commands/tools/index.js.map +1 -0
- package/dist/commands/trade.d.ts.map +1 -0
- package/dist/commands/trade.js +237 -0
- package/dist/commands/trade.js.map +1 -0
- package/dist/commands/transactions.d.ts.map +1 -1
- package/dist/commands/transactions.js +29 -17
- package/dist/commands/transactions.js.map +1 -1
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +429 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +351 -40
- package/dist/config.js.map +1 -1
- package/dist/index.js +4524 -924
- package/dist/index.js.map +1 -1
- package/dist/interactive/art.d.ts.map +1 -1
- package/dist/interactive/art.js +33 -1
- package/dist/interactive/art.js.map +1 -1
- package/dist/interactive/shell.d.ts.map +1 -1
- package/dist/interactive/shell.js +467 -2652
- package/dist/interactive/shell.js.map +1 -1
- package/dist/mcp/context.d.ts.map +1 -0
- package/dist/mcp/context.js +211 -0
- package/dist/mcp/context.js.map +1 -0
- package/dist/mcp/onboarding.d.ts.map +1 -0
- package/dist/mcp/onboarding.js +266 -0
- package/dist/mcp/onboarding.js.map +1 -0
- package/dist/mcp/resources.d.ts.map +1 -0
- package/dist/mcp/resources.js +222 -0
- package/dist/mcp/resources.js.map +1 -0
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +51 -1
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +4119 -169
- package/dist/mcp/tools.js.map +1 -1
- package/dist/mcp/types.d.ts.map +1 -1
- package/dist/types/agent-info.d.ts.map +1 -0
- package/dist/types/agent-info.js +11 -0
- package/dist/types/agent-info.js.map +1 -0
- package/dist/ui/components/ScrollableList.d.ts.map +1 -0
- package/dist/ui/components/ScrollableList.js +72 -0
- package/dist/ui/components/ScrollableList.js.map +1 -0
- package/dist/ui/components/ThemeProvider.d.ts.map +1 -0
- package/dist/ui/components/ThemeProvider.js +87 -0
- package/dist/ui/components/ThemeProvider.js.map +1 -0
- package/dist/ui/components/ThemedBox.d.ts.map +1 -0
- package/dist/ui/components/ThemedBox.js +24 -0
- package/dist/ui/components/ThemedBox.js.map +1 -0
- package/dist/ui/components/agent/ChatHeader.d.ts.map +1 -0
- package/dist/ui/components/agent/ChatHeader.js +39 -0
- package/dist/ui/components/agent/ChatHeader.js.map +1 -0
- package/dist/ui/components/agent/Header.d.ts.map +1 -0
- package/dist/ui/components/agent/Header.js +14 -0
- package/dist/ui/components/agent/Header.js.map +1 -0
- package/dist/ui/components/agent/Input.d.ts.map +1 -0
- package/dist/ui/components/agent/Input.js +23 -0
- package/dist/ui/components/agent/Input.js.map +1 -0
- package/dist/ui/components/agent/Output.d.ts.map +1 -0
- package/dist/ui/components/agent/Output.js +23 -0
- package/dist/ui/components/agent/Output.js.map +1 -0
- package/dist/ui/components/chat/TokenChatUI.d.ts.map +1 -0
- package/dist/ui/components/chat/TokenChatUI.js +133 -0
- package/dist/ui/components/chat/TokenChatUI.js.map +1 -0
- package/dist/ui/components/shell/ShellHeader.d.ts.map +1 -0
- package/dist/ui/components/shell/ShellHeader.js +31 -0
- package/dist/ui/components/shell/ShellHeader.js.map +1 -0
- package/dist/ui/components/shell/ShellInput.d.ts.map +1 -0
- package/dist/ui/components/shell/ShellInput.js +151 -0
- package/dist/ui/components/shell/ShellInput.js.map +1 -0
- package/dist/ui/components/shell/ShellOutput.d.ts.map +1 -0
- package/dist/ui/components/shell/ShellOutput.js +8 -0
- package/dist/ui/components/shell/ShellOutput.js.map +1 -0
- package/dist/ui/hooks/useChatWebSocket.d.ts.map +1 -0
- package/dist/ui/hooks/useChatWebSocket.js +76 -0
- package/dist/ui/hooks/useChatWebSocket.js.map +1 -0
- package/dist/ui/hooks/useCommandHistory.d.ts.map +1 -0
- package/dist/ui/hooks/useCommandHistory.js +70 -0
- package/dist/ui/hooks/useCommandHistory.js.map +1 -0
- package/dist/ui/hooks/useDebounce.d.ts.map +1 -0
- package/dist/ui/hooks/useDebounce.js +17 -0
- package/dist/ui/hooks/useDebounce.js.map +1 -0
- package/dist/ui/hooks/useLogStream.d.ts.map +1 -0
- package/dist/ui/hooks/useLogStream.js +20 -0
- package/dist/ui/hooks/useLogStream.js.map +1 -0
- package/dist/ui/hooks/useVirtualScroll.d.ts.map +1 -0
- package/dist/ui/hooks/useVirtualScroll.js +70 -0
- package/dist/ui/hooks/useVirtualScroll.js.map +1 -0
- package/dist/utils/admin.d.ts.map +1 -0
- package/dist/utils/admin.js +144 -0
- package/dist/utils/admin.js.map +1 -0
- package/dist/utils/autoSetup.d.ts.map +1 -0
- package/dist/utils/autoSetup.js +252 -0
- package/dist/utils/autoSetup.js.map +1 -0
- package/dist/utils/build-constants.d.ts.map +1 -0
- package/dist/utils/build-constants.js +10 -0
- package/dist/utils/build-constants.js.map +1 -0
- package/dist/utils/constants.d.ts.map +1 -1
- package/dist/utils/errors.d.ts.map +1 -1
- package/dist/utils/errors.js +10 -1
- package/dist/utils/errors.js.map +1 -1
- package/dist/utils/formatting.d.ts.map +1 -1
- package/dist/utils/formatting.js +46 -9
- package/dist/utils/formatting.js.map +1 -1
- package/dist/utils/llm-cli-config.d.ts.map +1 -0
- package/dist/utils/llm-cli-config.js +963 -0
- package/dist/utils/llm-cli-config.js.map +1 -0
- package/dist/utils/llm-cli-detector.d.ts.map +1 -0
- package/dist/utils/llm-cli-detector.js +202 -0
- package/dist/utils/llm-cli-detector.js.map +1 -0
- package/dist/utils/loading.d.ts.map +1 -1
- package/dist/utils/loading.js +25 -3
- package/dist/utils/loading.js.map +1 -1
- package/dist/utils/maintenance.d.ts.map +1 -0
- package/dist/utils/maintenance.js +17 -0
- package/dist/utils/maintenance.js.map +1 -0
- package/dist/utils/mcp-config.d.ts.map +1 -0
- package/dist/utils/mcp-config.js +77 -0
- package/dist/utils/mcp-config.js.map +1 -0
- package/dist/utils/privateKeyPrompt.d.ts.map +1 -1
- package/dist/utils/privateKeyPrompt.js +308 -129
- package/dist/utils/privateKeyPrompt.js.map +1 -1
- package/dist/utils/process-cleanup.d.ts.map +1 -0
- package/dist/utils/process-cleanup.js +136 -0
- package/dist/utils/process-cleanup.js.map +1 -0
- package/dist/utils/retry.d.ts.map +1 -0
- package/dist/utils/retry.js +56 -0
- package/dist/utils/retry.js.map +1 -0
- package/dist/utils/rpc-helpers.d.ts.map +1 -0
- package/dist/utils/rpc-helpers.js +70 -0
- package/dist/utils/rpc-helpers.js.map +1 -0
- package/dist/utils/rpc-transport.d.ts.map +1 -0
- package/dist/utils/rpc-transport.js +87 -0
- package/dist/utils/rpc-transport.js.map +1 -0
- package/dist/utils/shell-setup.d.ts.map +1 -0
- package/dist/utils/shell-setup.js +531 -0
- package/dist/utils/shell-setup.js.map +1 -0
- package/dist/utils/status.d.ts.map +1 -1
- package/dist/utils/status.js +34 -5
- package/dist/utils/status.js.map +1 -1
- package/dist/utils/token-resolver.d.ts.map +1 -1
- package/dist/utils/token-resolver.js +51 -8
- package/dist/utils/token-resolver.js.map +1 -1
- package/dist/utils/x402-caller.d.ts.map +1 -0
- package/dist/utils/x402-caller.js +17 -0
- package/dist/utils/x402-caller.js.map +1 -0
- package/docs/README.md +28 -0
- package/docs/agent/README.md +18 -0
- package/docs/api/README.md +41 -0
- package/docs/cli/README.md +42 -0
- package/docs/guides/README.md +26 -0
- package/docs/implementation/README.md +18 -0
- package/docs/planning/README.md +19 -0
- package/docs/testing/README.md +15 -0
- package/docs/ux/README.md +16 -0
- package/issues.txt +2 -0
- package/package.json +24 -9
- package/scripts/cat-spin.sh +417 -0
- package/scripts/deprecate-rc-versions.js +58 -0
- package/scripts/inject-build-constants.js +43 -0
- package/scripts/monitor-foobar.js +117 -0
- package/swap.logs +61 -0
- package/swapping.txt +108 -0
- package/test.txt +12 -0
- package/tests/fixtures/test-data.json +16 -0
- package/Screenshot 2025-12-21 at 8.56.02/342/200/257PM.png +0 -0
|
@@ -0,0 +1,963 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LLM CLI Configuration Writers
|
|
3
|
+
*
|
|
4
|
+
* This module provides configuration functions for each supported LLM CLI tool.
|
|
5
|
+
* Each function handles the specific configuration format and location for its tool.
|
|
6
|
+
*
|
|
7
|
+
* Configuration Strategy:
|
|
8
|
+
* 1. For tools with CLI commands (Codex, Gemini, MCP-Use): Try CLI command first, fall back to file
|
|
9
|
+
* 2. For file-only tools (Claude Desktop, Cursor): Direct file modification
|
|
10
|
+
* 3. All functions update existing MCP server configs if they already exist
|
|
11
|
+
* 4. Private key is always passed via HTTPCAT_PRIVATE_KEY environment variable
|
|
12
|
+
*
|
|
13
|
+
* Supported Configuration Formats:
|
|
14
|
+
* - JSON: Most tools (Claude Desktop, Cursor, LLM Tools, MCP Client)
|
|
15
|
+
* - TOML: Codex CLI (requires custom parser/stringifier)
|
|
16
|
+
* - Extension JSON: Gemini CLI (extension-based architecture)
|
|
17
|
+
*
|
|
18
|
+
* Error Handling:
|
|
19
|
+
* - All functions return boolean (true = success, false = failure)
|
|
20
|
+
* - Errors are logged but don't throw (graceful degradation)
|
|
21
|
+
* - Invalid config files are backed up and recreated
|
|
22
|
+
*/
|
|
23
|
+
import fs from "fs";
|
|
24
|
+
import path from "path";
|
|
25
|
+
import { execSync } from "child_process";
|
|
26
|
+
/**
|
|
27
|
+
* Check if httpcat is globally installed
|
|
28
|
+
*
|
|
29
|
+
* Determines whether to use "httpcat" directly or "npx httpcat-cli".
|
|
30
|
+
* This affects the command and args in MCP server configurations.
|
|
31
|
+
*
|
|
32
|
+
* @returns true if httpcat command exists in PATH, false otherwise
|
|
33
|
+
*/
|
|
34
|
+
function isHttpcatGlobal() {
|
|
35
|
+
try {
|
|
36
|
+
execSync("which httpcat", { stdio: "ignore" });
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Get standardized MCP server configuration
|
|
45
|
+
*
|
|
46
|
+
* Creates a consistent MCP server config object that can be used across all LLM tools.
|
|
47
|
+
* The configuration includes:
|
|
48
|
+
* - command: "httpcat" (if global) or "npx" (if npm package)
|
|
49
|
+
* - args: Appropriate arguments for the installation method
|
|
50
|
+
* - Note: No HTTPCAT_PRIVATE_KEY in env - server reads from config file instead
|
|
51
|
+
*
|
|
52
|
+
* This ensures all tools use the same MCP server setup, just in different formats.
|
|
53
|
+
*
|
|
54
|
+
* @returns MCP server configuration object
|
|
55
|
+
*/
|
|
56
|
+
function getMcpServerConfig() {
|
|
57
|
+
const isGlobal = isHttpcatGlobal();
|
|
58
|
+
return {
|
|
59
|
+
command: isGlobal ? "httpcat" : "npx",
|
|
60
|
+
args: isGlobal ? ["mcp", "start"] : ["-y", "httpcat-cli", "mcp", "start"],
|
|
61
|
+
// No env vars - private key is read from ~/.config/httpcat/config.json by MCP server
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Configure Claude Desktop
|
|
66
|
+
*
|
|
67
|
+
* Claude Desktop is a desktop application (no CLI). Configuration is done via JSON file:
|
|
68
|
+
* - macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
|
|
69
|
+
* - Windows: %APPDATA%/Claude/claude_desktop_config.json
|
|
70
|
+
* - Linux: ~/.config/Claude/claude_desktop_config.json
|
|
71
|
+
*
|
|
72
|
+
* Configuration format: Standard MCP JSON format with mcpServers object.
|
|
73
|
+
* Note: Private key is NOT included - MCP server reads from config file instead.
|
|
74
|
+
*
|
|
75
|
+
* @param configPath - Full path to claude_desktop_config.json
|
|
76
|
+
* @returns true if configuration succeeded, false otherwise
|
|
77
|
+
*/
|
|
78
|
+
export async function configureClaudeDesktop(configPath) {
|
|
79
|
+
try {
|
|
80
|
+
// Ensure config directory exists
|
|
81
|
+
const configDir = path.dirname(configPath);
|
|
82
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
83
|
+
// Read existing config or start with empty object
|
|
84
|
+
let config = {};
|
|
85
|
+
if (fs.existsSync(configPath)) {
|
|
86
|
+
const content = fs.readFileSync(configPath, "utf-8");
|
|
87
|
+
try {
|
|
88
|
+
config = JSON.parse(content);
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
// Invalid JSON - create new config (old one may be corrupted)
|
|
92
|
+
config = {};
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
// Ensure mcpServers object exists
|
|
96
|
+
if (!config.mcpServers) {
|
|
97
|
+
config.mcpServers = {};
|
|
98
|
+
}
|
|
99
|
+
// Add or update httpcat server configuration
|
|
100
|
+
config.mcpServers.httpcat = getMcpServerConfig();
|
|
101
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
console.error(`Failed to configure Claude Desktop: ${error}`);
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Configure Cursor IDE
|
|
111
|
+
*
|
|
112
|
+
* Cursor is a code editor with MCP support. Configuration can be:
|
|
113
|
+
* - Global: ~/.cursor/mcp.json (applies to all projects)
|
|
114
|
+
* - Workspace: .cursor/mcp.json (project-specific)
|
|
115
|
+
*
|
|
116
|
+
* The detector prioritizes global config, but this function works with either.
|
|
117
|
+
* Configuration format: Standard MCP JSON format.
|
|
118
|
+
* Note: Private key is NOT included - MCP server reads from config file instead.
|
|
119
|
+
*
|
|
120
|
+
* @param configPath - Full path to mcp.json (global or workspace)
|
|
121
|
+
* @returns true if configuration succeeded, false otherwise
|
|
122
|
+
*/
|
|
123
|
+
export async function configureCursor(configPath) {
|
|
124
|
+
try {
|
|
125
|
+
// Ensure config directory exists
|
|
126
|
+
const configDir = path.dirname(configPath);
|
|
127
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
128
|
+
// Read existing config or start with empty object
|
|
129
|
+
let config = {};
|
|
130
|
+
if (fs.existsSync(configPath)) {
|
|
131
|
+
const content = fs.readFileSync(configPath, "utf-8");
|
|
132
|
+
try {
|
|
133
|
+
config = JSON.parse(content);
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
// Invalid JSON - create new config
|
|
137
|
+
config = {};
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// Ensure mcpServers object exists
|
|
141
|
+
if (!config.mcpServers) {
|
|
142
|
+
config.mcpServers = {};
|
|
143
|
+
}
|
|
144
|
+
// Add or update httpcat server configuration
|
|
145
|
+
config.mcpServers.httpcat = getMcpServerConfig();
|
|
146
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
147
|
+
return true;
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
console.error(`Failed to configure Cursor: ${error}`);
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Configure LLM Tools MCP
|
|
156
|
+
*
|
|
157
|
+
* LLM Tools MCP is a plugin for Simon Willison's "llm" CLI tool.
|
|
158
|
+
* Requires: "llm" CLI installed AND "llm-tools-mcp" plugin installed.
|
|
159
|
+
*
|
|
160
|
+
* Configuration location: ~/.llm-tools-mcp/mcp.json
|
|
161
|
+
* Configuration format: Standard MCP JSON format.
|
|
162
|
+
* Note: Private key is NOT included - MCP server reads from config file instead.
|
|
163
|
+
*
|
|
164
|
+
* @param configPath - Full path to ~/.llm-tools-mcp/mcp.json
|
|
165
|
+
* @returns true if configuration succeeded, false otherwise
|
|
166
|
+
*/
|
|
167
|
+
export async function configureLlmToolsMcp(configPath) {
|
|
168
|
+
try {
|
|
169
|
+
// Ensure config directory exists
|
|
170
|
+
const configDir = path.dirname(configPath);
|
|
171
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
172
|
+
// Read existing config or start with empty object
|
|
173
|
+
let config = {};
|
|
174
|
+
if (fs.existsSync(configPath)) {
|
|
175
|
+
const content = fs.readFileSync(configPath, "utf-8");
|
|
176
|
+
try {
|
|
177
|
+
config = JSON.parse(content);
|
|
178
|
+
}
|
|
179
|
+
catch {
|
|
180
|
+
// Invalid JSON - create new config
|
|
181
|
+
config = {};
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
// Ensure mcpServers object exists
|
|
185
|
+
if (!config.mcpServers) {
|
|
186
|
+
config.mcpServers = {};
|
|
187
|
+
}
|
|
188
|
+
// Add or update httpcat server configuration
|
|
189
|
+
config.mcpServers.httpcat = getMcpServerConfig();
|
|
190
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
191
|
+
return true;
|
|
192
|
+
}
|
|
193
|
+
catch (error) {
|
|
194
|
+
console.error(`Failed to configure LLM Tools MCP: ${error}`);
|
|
195
|
+
return false;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Configure MCP-Use CLI
|
|
200
|
+
*
|
|
201
|
+
* MCP-Use is a standalone MCP client CLI tool. It supports both:
|
|
202
|
+
* 1. CLI commands: "mcp-use server add" (preferred method)
|
|
203
|
+
* 2. File-based config: ~/.mcp-use/config.json (fallback)
|
|
204
|
+
*
|
|
205
|
+
* Strategy: Try CLI command first, fall back to file if CLI fails.
|
|
206
|
+
* This ensures we use the official CLI interface when available.
|
|
207
|
+
* Note: Private key is NOT included - MCP server reads from config file instead.
|
|
208
|
+
*
|
|
209
|
+
* @returns true if configuration succeeded, false otherwise
|
|
210
|
+
*/
|
|
211
|
+
export async function configureMcpUse() {
|
|
212
|
+
try {
|
|
213
|
+
// Try CLI command first (preferred method)
|
|
214
|
+
const isGlobal = isHttpcatGlobal();
|
|
215
|
+
const command = isGlobal ? "httpcat" : "npx -y httpcat-cli";
|
|
216
|
+
const args = isGlobal ? "mcp start" : "mcp start";
|
|
217
|
+
try {
|
|
218
|
+
// Execute CLI command to add MCP server
|
|
219
|
+
execSync(`mcp-use server add httpcat --command "${command}" --args "${args}"`, { stdio: "ignore" });
|
|
220
|
+
return true;
|
|
221
|
+
}
|
|
222
|
+
catch {
|
|
223
|
+
// CLI command failed (tool may not support this command or not installed)
|
|
224
|
+
// Fall back to file-based configuration
|
|
225
|
+
const configPath = path.join(process.env.HOME || "", ".mcp-use", "config.json");
|
|
226
|
+
const configDir = path.dirname(configPath);
|
|
227
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
228
|
+
// Read existing config or start with empty object
|
|
229
|
+
let config = {};
|
|
230
|
+
if (fs.existsSync(configPath)) {
|
|
231
|
+
const content = fs.readFileSync(configPath, "utf-8");
|
|
232
|
+
try {
|
|
233
|
+
config = JSON.parse(content);
|
|
234
|
+
}
|
|
235
|
+
catch {
|
|
236
|
+
config = {};
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
// Ensure mcpServers object exists
|
|
240
|
+
if (!config.mcpServers) {
|
|
241
|
+
config.mcpServers = {};
|
|
242
|
+
}
|
|
243
|
+
// Add or update httpcat server configuration
|
|
244
|
+
config.mcpServers.httpcat = getMcpServerConfig();
|
|
245
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
246
|
+
return true;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
catch (error) {
|
|
250
|
+
console.error(`Failed to configure MCP-Use: ${error}`);
|
|
251
|
+
return false;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Configure MCP Client CLI
|
|
256
|
+
*
|
|
257
|
+
* MCP Client CLI is another MCP client implementation.
|
|
258
|
+
* Configuration location: ~/.llm/config.json
|
|
259
|
+
* Configuration format: Standard MCP JSON format.
|
|
260
|
+
*
|
|
261
|
+
* Note: This shares the same config directory as other LLM tools,
|
|
262
|
+
* so we're careful to merge rather than overwrite.
|
|
263
|
+
* Note: Private key is NOT included - MCP server reads from config file instead.
|
|
264
|
+
*
|
|
265
|
+
* @param configPath - Full path to ~/.llm/config.json
|
|
266
|
+
* @returns true if configuration succeeded, false otherwise
|
|
267
|
+
*/
|
|
268
|
+
export async function configureMcpClient(configPath) {
|
|
269
|
+
try {
|
|
270
|
+
// Ensure config directory exists
|
|
271
|
+
const configDir = path.dirname(configPath);
|
|
272
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
273
|
+
// Read existing config or start with empty object
|
|
274
|
+
let config = {};
|
|
275
|
+
if (fs.existsSync(configPath)) {
|
|
276
|
+
const content = fs.readFileSync(configPath, "utf-8");
|
|
277
|
+
try {
|
|
278
|
+
config = JSON.parse(content);
|
|
279
|
+
}
|
|
280
|
+
catch {
|
|
281
|
+
// Invalid JSON - create new config
|
|
282
|
+
config = {};
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
// Ensure mcpServers object exists
|
|
286
|
+
if (!config.mcpServers) {
|
|
287
|
+
config.mcpServers = {};
|
|
288
|
+
}
|
|
289
|
+
// Add or update httpcat server configuration
|
|
290
|
+
config.mcpServers.httpcat = getMcpServerConfig();
|
|
291
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
292
|
+
return true;
|
|
293
|
+
}
|
|
294
|
+
catch (error) {
|
|
295
|
+
console.error(`Failed to configure MCP Client: ${error}`);
|
|
296
|
+
return false;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Parse TOML file (simplified parser for Codex config)
|
|
301
|
+
*
|
|
302
|
+
* This is a simplified TOML parser that handles the subset of TOML syntax
|
|
303
|
+
* needed for Codex CLI configuration. It supports:
|
|
304
|
+
* - Section headers: [section.name]
|
|
305
|
+
* - String values: key = "value"
|
|
306
|
+
* - Arrays: key = ["value1", "value2"]
|
|
307
|
+
* - Inline tables: key = { k1 = "v1", k2 = "v2" }
|
|
308
|
+
* - Comments: Lines starting with #
|
|
309
|
+
*
|
|
310
|
+
* Note: This is NOT a full TOML parser. It's designed specifically for
|
|
311
|
+
* the Codex config format. For more complex TOML files, consider using
|
|
312
|
+
* a proper TOML library like @iarna/toml.
|
|
313
|
+
*
|
|
314
|
+
* @param content - TOML file content as string
|
|
315
|
+
* @returns Parsed TOML as JavaScript object
|
|
316
|
+
*/
|
|
317
|
+
function parseToml(content) {
|
|
318
|
+
const result = {};
|
|
319
|
+
const lines = content.split("\n");
|
|
320
|
+
let currentSection = null;
|
|
321
|
+
for (const line of lines) {
|
|
322
|
+
const trimmed = line.trim();
|
|
323
|
+
// Skip empty lines and comments
|
|
324
|
+
if (!trimmed || trimmed.startsWith("#"))
|
|
325
|
+
continue;
|
|
326
|
+
// Parse section header: [section.name]
|
|
327
|
+
const sectionMatch = trimmed.match(/^\[([^\]]+)\]$/);
|
|
328
|
+
if (sectionMatch) {
|
|
329
|
+
currentSection = sectionMatch[1];
|
|
330
|
+
if (!result[currentSection]) {
|
|
331
|
+
result[currentSection] = {};
|
|
332
|
+
}
|
|
333
|
+
continue;
|
|
334
|
+
}
|
|
335
|
+
// Parse key = value pairs
|
|
336
|
+
const keyValueMatch = trimmed.match(/^([^=]+)\s*=\s*(.+)$/);
|
|
337
|
+
if (keyValueMatch && currentSection) {
|
|
338
|
+
const key = keyValueMatch[1].trim();
|
|
339
|
+
let value = keyValueMatch[2].trim();
|
|
340
|
+
// Remove quotes from string values
|
|
341
|
+
if ((value.startsWith('"') && value.endsWith('"')) ||
|
|
342
|
+
(value.startsWith("'") && value.endsWith("'"))) {
|
|
343
|
+
value = value.slice(1, -1);
|
|
344
|
+
}
|
|
345
|
+
// Parse arrays: ["value1", "value2"]
|
|
346
|
+
else if (value.startsWith("[") && value.endsWith("]")) {
|
|
347
|
+
value = value.slice(1, -1).split(",").map((v) => v.trim().replace(/^["']|["']$/g, ""));
|
|
348
|
+
}
|
|
349
|
+
// Parse inline tables: { key1 = "value1", key2 = "value2" }
|
|
350
|
+
else if (value.startsWith("{") && value.endsWith("}")) {
|
|
351
|
+
const tableContent = value.slice(1, -1);
|
|
352
|
+
value = {};
|
|
353
|
+
tableContent.split(",").forEach((pair) => {
|
|
354
|
+
const [k, v] = pair.split("=").map((s) => s.trim());
|
|
355
|
+
if (k && v) {
|
|
356
|
+
// Remove quotes from table values
|
|
357
|
+
value[k] = v.replace(/^["']|["']$/g, "");
|
|
358
|
+
}
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
result[currentSection][key] = value;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
return result;
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* Stringify TOML (simplified stringifier for Codex config)
|
|
368
|
+
*
|
|
369
|
+
* Converts a JavaScript object back to TOML format. Handles:
|
|
370
|
+
* - Sections: [section.name]
|
|
371
|
+
* - Strings: key = "value"
|
|
372
|
+
* - Arrays: key = ["value1", "value2"]
|
|
373
|
+
* - Inline tables: key = { k1 = "v1", k2 = "v2" }
|
|
374
|
+
*
|
|
375
|
+
* This is the inverse of parseToml() and is designed for the Codex config format.
|
|
376
|
+
*
|
|
377
|
+
* @param obj - JavaScript object to convert to TOML
|
|
378
|
+
* @returns TOML-formatted string
|
|
379
|
+
*/
|
|
380
|
+
function stringifyToml(obj) {
|
|
381
|
+
const lines = [];
|
|
382
|
+
for (const [section, content] of Object.entries(obj)) {
|
|
383
|
+
if (typeof content === "object" && content !== null) {
|
|
384
|
+
// Write section header
|
|
385
|
+
lines.push(`[${section}]`);
|
|
386
|
+
// Write key-value pairs in this section
|
|
387
|
+
for (const [key, value] of Object.entries(content)) {
|
|
388
|
+
if (typeof value === "string") {
|
|
389
|
+
// String value: key = "value"
|
|
390
|
+
lines.push(`${key} = "${value}"`);
|
|
391
|
+
}
|
|
392
|
+
else if (Array.isArray(value)) {
|
|
393
|
+
// Array value: key = ["value1", "value2"]
|
|
394
|
+
lines.push(`${key} = [${value.map((v) => `"${v}"`).join(", ")}]`);
|
|
395
|
+
}
|
|
396
|
+
else if (typeof value === "object" && value !== null) {
|
|
397
|
+
// Inline table: key = { k1 = "v1", k2 = "v2" }
|
|
398
|
+
// Used for nested objects like env = { HTTPCAT_PRIVATE_KEY = "0x..." }
|
|
399
|
+
const tableEntries = Object.entries(value)
|
|
400
|
+
.map(([k, v]) => `${k} = "${String(v)}"`)
|
|
401
|
+
.join(", ");
|
|
402
|
+
lines.push(`${key} = { ${tableEntries} }`);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
// Add blank line after each section for readability
|
|
406
|
+
lines.push("");
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
return lines.join("\n");
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* Configure Codex CLI (OpenAI)
|
|
413
|
+
*
|
|
414
|
+
* Codex CLI supports both CLI commands and TOML file configuration:
|
|
415
|
+
* 1. CLI: "codex mcp add httpcat -- npx -y httpcat-cli mcp start" (preferred)
|
|
416
|
+
* 2. File: ~/.codex/config.toml (fallback)
|
|
417
|
+
*
|
|
418
|
+
* Configuration format: TOML (not JSON like most other tools)
|
|
419
|
+
* Section format: [mcp_servers.httpcat] (uses underscores, not camelCase)
|
|
420
|
+
*
|
|
421
|
+
* Strategy: Try CLI command first, fall back to TOML file modification.
|
|
422
|
+
* Note: Private key is NOT included - MCP server reads from config file instead.
|
|
423
|
+
*
|
|
424
|
+
* @param configPath - Full path to ~/.codex/config.toml
|
|
425
|
+
* @returns true if configuration succeeded, false otherwise
|
|
426
|
+
*/
|
|
427
|
+
export async function configureCodex(configPath) {
|
|
428
|
+
try {
|
|
429
|
+
// Try CLI command first (preferred method)
|
|
430
|
+
if (commandExists("codex")) {
|
|
431
|
+
try {
|
|
432
|
+
const isGlobal = isHttpcatGlobal();
|
|
433
|
+
const command = isGlobal ? "httpcat" : "npx";
|
|
434
|
+
const args = isGlobal ? "mcp start" : "-y httpcat-cli mcp start";
|
|
435
|
+
// Execute CLI command to add MCP server
|
|
436
|
+
execSync(`codex mcp add httpcat -- ${command} ${args}`, { stdio: "ignore" });
|
|
437
|
+
return true;
|
|
438
|
+
}
|
|
439
|
+
catch {
|
|
440
|
+
// CLI command failed - fall back to file-based configuration
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
// File-based configuration (TOML format)
|
|
444
|
+
const configDir = path.dirname(configPath);
|
|
445
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
446
|
+
// Read existing TOML config or start with empty object
|
|
447
|
+
let config = {};
|
|
448
|
+
if (fs.existsSync(configPath)) {
|
|
449
|
+
const content = fs.readFileSync(configPath, "utf-8");
|
|
450
|
+
try {
|
|
451
|
+
config = parseToml(content);
|
|
452
|
+
}
|
|
453
|
+
catch {
|
|
454
|
+
// Invalid TOML - create new config
|
|
455
|
+
config = {};
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
// Ensure mcp_servers section exists (Codex uses underscores, not camelCase)
|
|
459
|
+
if (!config.mcp_servers) {
|
|
460
|
+
config.mcp_servers = {};
|
|
461
|
+
}
|
|
462
|
+
// Add or update httpcat server configuration
|
|
463
|
+
const mcpConfig = getMcpServerConfig();
|
|
464
|
+
// Store in TOML format (mcp_servers.httpcat section)
|
|
465
|
+
config.mcp_servers.httpcat = {
|
|
466
|
+
command: mcpConfig.command,
|
|
467
|
+
args: mcpConfig.args,
|
|
468
|
+
// No env vars - private key is read from config file
|
|
469
|
+
};
|
|
470
|
+
// Write back as TOML
|
|
471
|
+
fs.writeFileSync(configPath, stringifyToml(config), "utf-8");
|
|
472
|
+
return true;
|
|
473
|
+
}
|
|
474
|
+
catch (error) {
|
|
475
|
+
console.error(`Failed to configure Codex: ${error}`);
|
|
476
|
+
return false;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
/**
|
|
480
|
+
* Configure Gemini CLI (Google)
|
|
481
|
+
*
|
|
482
|
+
* Gemini CLI uses an extension-based architecture. It supports both:
|
|
483
|
+
* 1. CLI: "gemini mcp add httpcat --command ... --args ..." (preferred)
|
|
484
|
+
* 2. Extension file: ~/.gemini/extensions/httpcat/gemini-extension.json (fallback)
|
|
485
|
+
*
|
|
486
|
+
* Extension format: JSON file with name, version, and mcpServers object.
|
|
487
|
+
* This is different from standard MCP config - it's wrapped in an extension structure.
|
|
488
|
+
*
|
|
489
|
+
* Strategy: Try CLI command first, fall back to creating extension JSON file.
|
|
490
|
+
* Note: Private key is NOT included - MCP server reads from config file instead.
|
|
491
|
+
*
|
|
492
|
+
* @param extensionPath - Full path to extension JSON file
|
|
493
|
+
* @returns true if configuration succeeded, false otherwise
|
|
494
|
+
*/
|
|
495
|
+
export async function configureGemini(extensionPath) {
|
|
496
|
+
try {
|
|
497
|
+
// Try CLI command first (preferred method)
|
|
498
|
+
if (commandExists("gemini")) {
|
|
499
|
+
try {
|
|
500
|
+
const isGlobal = isHttpcatGlobal();
|
|
501
|
+
const command = isGlobal ? "httpcat" : "npx";
|
|
502
|
+
const args = isGlobal ? "mcp start" : "-y httpcat-cli mcp start";
|
|
503
|
+
// Execute CLI command to add MCP server
|
|
504
|
+
execSync(`gemini mcp add httpcat --command "${command}" --args "${args}"`, { stdio: "ignore" });
|
|
505
|
+
return true;
|
|
506
|
+
}
|
|
507
|
+
catch {
|
|
508
|
+
// CLI command failed - fall back to file-based configuration
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
// File-based configuration (extension JSON format)
|
|
512
|
+
// Ensure extension directory exists
|
|
513
|
+
const extensionDir = path.dirname(extensionPath);
|
|
514
|
+
fs.mkdirSync(extensionDir, { recursive: true });
|
|
515
|
+
// Build extension config structure (Gemini-specific format)
|
|
516
|
+
const mcpConfig = getMcpServerConfig();
|
|
517
|
+
const extensionConfig = {
|
|
518
|
+
name: "httpcat",
|
|
519
|
+
version: "1.0.0",
|
|
520
|
+
mcpServers: {
|
|
521
|
+
httpcat: mcpConfig,
|
|
522
|
+
},
|
|
523
|
+
};
|
|
524
|
+
// Add or update extension file
|
|
525
|
+
fs.writeFileSync(extensionPath, JSON.stringify(extensionConfig, null, 2), "utf-8");
|
|
526
|
+
return true;
|
|
527
|
+
}
|
|
528
|
+
catch (error) {
|
|
529
|
+
console.error(`Failed to configure Gemini: ${error}`);
|
|
530
|
+
return false;
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
/**
|
|
534
|
+
* Check if a command exists in PATH
|
|
535
|
+
*
|
|
536
|
+
* Helper function used by configuration functions to check if CLI tools are available.
|
|
537
|
+
*
|
|
538
|
+
* @param command - Command name to check (e.g., "codex", "gemini")
|
|
539
|
+
* @returns true if command exists in PATH, false otherwise
|
|
540
|
+
*/
|
|
541
|
+
function commandExists(command) {
|
|
542
|
+
try {
|
|
543
|
+
execSync(`which ${command}`, { stdio: "ignore" });
|
|
544
|
+
return true;
|
|
545
|
+
}
|
|
546
|
+
catch {
|
|
547
|
+
return false;
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
/**
|
|
551
|
+
* Configure Claude CLI (Anthropic)
|
|
552
|
+
*
|
|
553
|
+
* Claude CLI is Anthropic's command-line tool for Claude.
|
|
554
|
+
* Configuration location: ~/.claude/config.json
|
|
555
|
+
* Configuration format: Standard MCP JSON format.
|
|
556
|
+
*
|
|
557
|
+
* Note: Private key is NOT included - MCP server reads from config file instead.
|
|
558
|
+
*
|
|
559
|
+
* @param configPath - Full path to ~/.claude/config.json
|
|
560
|
+
* @returns true if configuration succeeded, false otherwise
|
|
561
|
+
*/
|
|
562
|
+
export async function configureClaudeCli(configPath) {
|
|
563
|
+
try {
|
|
564
|
+
// Ensure config directory exists
|
|
565
|
+
const configDir = path.dirname(configPath);
|
|
566
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
567
|
+
// Read existing config or start with empty object
|
|
568
|
+
let config = {};
|
|
569
|
+
if (fs.existsSync(configPath)) {
|
|
570
|
+
const content = fs.readFileSync(configPath, "utf-8");
|
|
571
|
+
try {
|
|
572
|
+
config = JSON.parse(content);
|
|
573
|
+
}
|
|
574
|
+
catch {
|
|
575
|
+
// Invalid JSON - create new config
|
|
576
|
+
config = {};
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
// Ensure mcpServers object exists
|
|
580
|
+
if (!config.mcpServers) {
|
|
581
|
+
config.mcpServers = {};
|
|
582
|
+
}
|
|
583
|
+
// Add or update httpcat server configuration
|
|
584
|
+
config.mcpServers.httpcat = getMcpServerConfig();
|
|
585
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
586
|
+
return true;
|
|
587
|
+
}
|
|
588
|
+
catch (error) {
|
|
589
|
+
console.error(`Failed to configure Claude CLI: ${error}`);
|
|
590
|
+
return false;
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
/**
|
|
594
|
+
* Configure LLM based on detected LLM info
|
|
595
|
+
*
|
|
596
|
+
* Main router function that dispatches to the appropriate configuration function
|
|
597
|
+
* based on the detected LLM tool. This is called by the wizard after the user
|
|
598
|
+
* selects which LLM tools to configure.
|
|
599
|
+
*
|
|
600
|
+
* Note: Private key is NOT passed - MCP server reads from config file instead.
|
|
601
|
+
*
|
|
602
|
+
* @param llm - Detected LLM tool information from detector
|
|
603
|
+
* @returns true if configuration succeeded, false otherwise
|
|
604
|
+
*/
|
|
605
|
+
export async function configureLLM(llm) {
|
|
606
|
+
// Route to appropriate configuration function based on LLM ID
|
|
607
|
+
switch (llm.id) {
|
|
608
|
+
case "claude-desktop":
|
|
609
|
+
return await configureClaudeDesktop(llm.configPath);
|
|
610
|
+
case "claude-cli":
|
|
611
|
+
return await configureClaudeCli(llm.configPath);
|
|
612
|
+
case "cursor":
|
|
613
|
+
return await configureCursor(llm.configPath);
|
|
614
|
+
case "llm-tools-mcp":
|
|
615
|
+
return await configureLlmToolsMcp(llm.configPath);
|
|
616
|
+
case "mcp-use":
|
|
617
|
+
return await configureMcpUse();
|
|
618
|
+
case "mcp-client":
|
|
619
|
+
return await configureMcpClient(llm.configPath);
|
|
620
|
+
case "codex":
|
|
621
|
+
return await configureCodex(llm.configPath);
|
|
622
|
+
case "gemini":
|
|
623
|
+
return await configureGemini(llm.configPath);
|
|
624
|
+
default:
|
|
625
|
+
// Unknown LLM ID - return false
|
|
626
|
+
return false;
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
/**
|
|
630
|
+
* Remove httpcat MCP server from JSON-based config file
|
|
631
|
+
*
|
|
632
|
+
* @param configPath - Path to JSON config file
|
|
633
|
+
* @returns true if removal succeeded, false otherwise
|
|
634
|
+
*/
|
|
635
|
+
function removeFromJsonConfig(configPath) {
|
|
636
|
+
try {
|
|
637
|
+
if (!fs.existsSync(configPath)) {
|
|
638
|
+
return true; // Already removed or doesn't exist
|
|
639
|
+
}
|
|
640
|
+
const content = fs.readFileSync(configPath, "utf-8");
|
|
641
|
+
let config = {};
|
|
642
|
+
try {
|
|
643
|
+
config = JSON.parse(content);
|
|
644
|
+
}
|
|
645
|
+
catch {
|
|
646
|
+
// Invalid JSON - nothing to remove
|
|
647
|
+
return true;
|
|
648
|
+
}
|
|
649
|
+
// Remove httpcat from mcpServers if it exists
|
|
650
|
+
if (config.mcpServers && config.mcpServers.httpcat) {
|
|
651
|
+
delete config.mcpServers.httpcat;
|
|
652
|
+
// If mcpServers is now empty, remove it
|
|
653
|
+
if (Object.keys(config.mcpServers).length === 0) {
|
|
654
|
+
delete config.mcpServers;
|
|
655
|
+
}
|
|
656
|
+
// Write back the updated config
|
|
657
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
658
|
+
}
|
|
659
|
+
return true;
|
|
660
|
+
}
|
|
661
|
+
catch (error) {
|
|
662
|
+
return false;
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
/**
|
|
666
|
+
* Remove httpcat MCP server from TOML-based config file (Codex)
|
|
667
|
+
*
|
|
668
|
+
* @param configPath - Path to TOML config file
|
|
669
|
+
* @returns true if removal succeeded, false otherwise
|
|
670
|
+
*/
|
|
671
|
+
function removeFromTomlConfig(configPath) {
|
|
672
|
+
try {
|
|
673
|
+
if (!fs.existsSync(configPath)) {
|
|
674
|
+
return true; // Already removed or doesn't exist
|
|
675
|
+
}
|
|
676
|
+
const content = fs.readFileSync(configPath, "utf-8");
|
|
677
|
+
let config = {};
|
|
678
|
+
try {
|
|
679
|
+
config = parseToml(content);
|
|
680
|
+
}
|
|
681
|
+
catch {
|
|
682
|
+
// Invalid TOML - nothing to remove
|
|
683
|
+
return true;
|
|
684
|
+
}
|
|
685
|
+
// Remove httpcat from mcp_servers if it exists
|
|
686
|
+
if (config.mcp_servers && config.mcp_servers.httpcat) {
|
|
687
|
+
delete config.mcp_servers.httpcat;
|
|
688
|
+
// If mcp_servers is now empty, remove it
|
|
689
|
+
if (Object.keys(config.mcp_servers).length === 0) {
|
|
690
|
+
delete config.mcp_servers;
|
|
691
|
+
}
|
|
692
|
+
// Write back the updated TOML
|
|
693
|
+
fs.writeFileSync(configPath, stringifyToml(config), "utf-8");
|
|
694
|
+
}
|
|
695
|
+
return true;
|
|
696
|
+
}
|
|
697
|
+
catch (error) {
|
|
698
|
+
return false;
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
/**
|
|
702
|
+
* Remove httpcat extension from Gemini CLI
|
|
703
|
+
*
|
|
704
|
+
* @param extensionPath - Path to Gemini extension JSON file
|
|
705
|
+
* @returns true if removal succeeded, false otherwise
|
|
706
|
+
*/
|
|
707
|
+
function removeGeminiExtension(extensionPath) {
|
|
708
|
+
try {
|
|
709
|
+
if (fs.existsSync(extensionPath)) {
|
|
710
|
+
fs.unlinkSync(extensionPath);
|
|
711
|
+
// Also try to remove the directory if it's empty
|
|
712
|
+
const extensionDir = path.dirname(extensionPath);
|
|
713
|
+
try {
|
|
714
|
+
const files = fs.readdirSync(extensionDir);
|
|
715
|
+
if (files.length === 0) {
|
|
716
|
+
fs.rmdirSync(extensionDir);
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
catch {
|
|
720
|
+
// Ignore errors removing directory
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
return true;
|
|
724
|
+
}
|
|
725
|
+
catch (error) {
|
|
726
|
+
return false;
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
/**
|
|
730
|
+
* Remove httpcat MCP server from MCP-Use CLI (try CLI first, fallback to file)
|
|
731
|
+
*
|
|
732
|
+
* @returns true if removal succeeded, false otherwise
|
|
733
|
+
*/
|
|
734
|
+
function removeFromMcpUse() {
|
|
735
|
+
try {
|
|
736
|
+
// Try CLI command first
|
|
737
|
+
if (commandExists("mcp-use")) {
|
|
738
|
+
try {
|
|
739
|
+
execSync("mcp-use server remove httpcat", { stdio: "ignore" });
|
|
740
|
+
return true;
|
|
741
|
+
}
|
|
742
|
+
catch {
|
|
743
|
+
// CLI failed, try file-based removal
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
// Fallback to file-based removal
|
|
747
|
+
const configPath = path.join(process.env.HOME || "", ".mcp-use", "config.json");
|
|
748
|
+
return removeFromJsonConfig(configPath);
|
|
749
|
+
}
|
|
750
|
+
catch (error) {
|
|
751
|
+
return false;
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
/**
|
|
755
|
+
* Remove httpcat MCP server from Codex CLI (try CLI first, fallback to file)
|
|
756
|
+
*
|
|
757
|
+
* @param configPath - Path to Codex TOML config file
|
|
758
|
+
* @returns true if removal succeeded, false otherwise
|
|
759
|
+
*/
|
|
760
|
+
function removeFromCodex(configPath) {
|
|
761
|
+
try {
|
|
762
|
+
// Try CLI command first
|
|
763
|
+
if (commandExists("codex")) {
|
|
764
|
+
try {
|
|
765
|
+
execSync("codex mcp remove httpcat", { stdio: "ignore" });
|
|
766
|
+
return true;
|
|
767
|
+
}
|
|
768
|
+
catch {
|
|
769
|
+
// CLI failed, try file-based removal
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
// Fallback to file-based removal
|
|
773
|
+
return removeFromTomlConfig(configPath);
|
|
774
|
+
}
|
|
775
|
+
catch (error) {
|
|
776
|
+
return false;
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
/**
|
|
780
|
+
* Remove httpcat MCP server from Gemini CLI (try CLI first, fallback to file)
|
|
781
|
+
*
|
|
782
|
+
* @param extensionPath - Path to Gemini extension JSON file
|
|
783
|
+
* @returns true if removal succeeded, false otherwise
|
|
784
|
+
*/
|
|
785
|
+
function removeFromGemini(extensionPath) {
|
|
786
|
+
try {
|
|
787
|
+
// Try CLI command first
|
|
788
|
+
if (commandExists("gemini")) {
|
|
789
|
+
try {
|
|
790
|
+
execSync("gemini mcp remove httpcat", { stdio: "ignore" });
|
|
791
|
+
return true;
|
|
792
|
+
}
|
|
793
|
+
catch {
|
|
794
|
+
// CLI failed, try file-based removal
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
// Fallback to file-based removal
|
|
798
|
+
return removeGeminiExtension(extensionPath);
|
|
799
|
+
}
|
|
800
|
+
catch (error) {
|
|
801
|
+
return false;
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
/**
|
|
805
|
+
* Remove httpcat MCP server from a specific LLM tool
|
|
806
|
+
*
|
|
807
|
+
* @param llm - Detected LLM tool information
|
|
808
|
+
* @returns true if removal succeeded, false otherwise
|
|
809
|
+
*/
|
|
810
|
+
export async function removeMcpFromLLM(llm) {
|
|
811
|
+
switch (llm.id) {
|
|
812
|
+
case "claude-desktop":
|
|
813
|
+
case "cursor":
|
|
814
|
+
case "llm-tools-mcp":
|
|
815
|
+
case "mcp-client":
|
|
816
|
+
return removeFromJsonConfig(llm.configPath);
|
|
817
|
+
case "mcp-use":
|
|
818
|
+
return removeFromMcpUse();
|
|
819
|
+
case "codex":
|
|
820
|
+
return removeFromCodex(llm.configPath);
|
|
821
|
+
case "gemini":
|
|
822
|
+
return removeFromGemini(llm.configPath);
|
|
823
|
+
default:
|
|
824
|
+
return false;
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
/**
|
|
828
|
+
* Get platform-specific Claude Desktop config path
|
|
829
|
+
*
|
|
830
|
+
* @returns Platform-appropriate config file path
|
|
831
|
+
*/
|
|
832
|
+
function getClaudeDesktopConfigPath() {
|
|
833
|
+
const platform = process.platform;
|
|
834
|
+
if (platform === "darwin") {
|
|
835
|
+
return path.join(process.env.HOME || "", "Library", "Application Support", "Claude", "claude_desktop_config.json");
|
|
836
|
+
}
|
|
837
|
+
else if (platform === "win32") {
|
|
838
|
+
return path.join(process.env.APPDATA || "", "Claude", "claude_desktop_config.json");
|
|
839
|
+
}
|
|
840
|
+
else {
|
|
841
|
+
return path.join(process.env.HOME || "", ".config", "Claude", "claude_desktop_config.json");
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
/**
|
|
845
|
+
* Remove httpcat MCP configurations from all detected LLM tools
|
|
846
|
+
*
|
|
847
|
+
* This function scans for all LLM tools that have httpcat MCP configured
|
|
848
|
+
* and removes the httpcat server from their configurations.
|
|
849
|
+
* It also checks known config paths directly to ensure cleanup even if
|
|
850
|
+
* tools weren't detected.
|
|
851
|
+
*
|
|
852
|
+
* @returns Array of results showing which tools were cleaned up
|
|
853
|
+
*/
|
|
854
|
+
export async function removeAllMcpConfigurations() {
|
|
855
|
+
const { detectInstalledLlms } = await import("./llm-cli-detector.js");
|
|
856
|
+
const detectedLlms = await detectInstalledLlms();
|
|
857
|
+
const results = [];
|
|
858
|
+
// Remove from each detected LLM tool
|
|
859
|
+
for (const llm of detectedLlms) {
|
|
860
|
+
try {
|
|
861
|
+
const success = await removeMcpFromLLM(llm);
|
|
862
|
+
results.push({
|
|
863
|
+
name: llm.name,
|
|
864
|
+
success,
|
|
865
|
+
});
|
|
866
|
+
}
|
|
867
|
+
catch (error) {
|
|
868
|
+
results.push({
|
|
869
|
+
name: llm.name,
|
|
870
|
+
success: false,
|
|
871
|
+
});
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
// Also check known config paths directly (in case they weren't detected)
|
|
875
|
+
// This ensures we clean up even if detection missed them
|
|
876
|
+
const knownConfigs = [
|
|
877
|
+
{
|
|
878
|
+
name: "Claude Desktop",
|
|
879
|
+
path: getClaudeDesktopConfigPath(),
|
|
880
|
+
type: "json",
|
|
881
|
+
},
|
|
882
|
+
{
|
|
883
|
+
name: "Cursor IDE",
|
|
884
|
+
path: path.join(process.env.HOME || "", ".cursor", "mcp.json"),
|
|
885
|
+
type: "json",
|
|
886
|
+
},
|
|
887
|
+
{
|
|
888
|
+
name: "LLM Tools MCP",
|
|
889
|
+
path: path.join(process.env.HOME || "", ".llm-tools-mcp", "mcp.json"),
|
|
890
|
+
type: "json",
|
|
891
|
+
},
|
|
892
|
+
{
|
|
893
|
+
name: "MCP Client",
|
|
894
|
+
path: path.join(process.env.HOME || "", ".llm", "config.json"),
|
|
895
|
+
type: "json",
|
|
896
|
+
},
|
|
897
|
+
{
|
|
898
|
+
name: "MCP-Use",
|
|
899
|
+
path: path.join(process.env.HOME || "", ".mcp-use", "config.json"),
|
|
900
|
+
type: "json",
|
|
901
|
+
},
|
|
902
|
+
{
|
|
903
|
+
name: "Codex CLI",
|
|
904
|
+
path: path.join(process.env.HOME || "", ".codex", "config.toml"),
|
|
905
|
+
type: "toml",
|
|
906
|
+
},
|
|
907
|
+
{
|
|
908
|
+
name: "Gemini CLI",
|
|
909
|
+
path: path.join(process.env.HOME || "", ".gemini", "extensions", "httpcat", "gemini-extension.json"),
|
|
910
|
+
type: "extension",
|
|
911
|
+
},
|
|
912
|
+
];
|
|
913
|
+
// Check each known config path and clean up if it exists
|
|
914
|
+
for (const knownConfig of knownConfigs) {
|
|
915
|
+
// Skip if we already processed it via detection
|
|
916
|
+
const alreadyProcessed = detectedLlms.some((llm) => llm.configPath === knownConfig.path);
|
|
917
|
+
if (!alreadyProcessed && fs.existsSync(knownConfig.path)) {
|
|
918
|
+
try {
|
|
919
|
+
let success = false;
|
|
920
|
+
if (knownConfig.type === "json") {
|
|
921
|
+
success = removeFromJsonConfig(knownConfig.path);
|
|
922
|
+
}
|
|
923
|
+
else if (knownConfig.type === "toml") {
|
|
924
|
+
success = removeFromTomlConfig(knownConfig.path);
|
|
925
|
+
}
|
|
926
|
+
else if (knownConfig.type === "extension") {
|
|
927
|
+
success = removeGeminiExtension(knownConfig.path);
|
|
928
|
+
}
|
|
929
|
+
results.push({
|
|
930
|
+
name: knownConfig.name,
|
|
931
|
+
success,
|
|
932
|
+
});
|
|
933
|
+
}
|
|
934
|
+
catch (error) {
|
|
935
|
+
results.push({
|
|
936
|
+
name: knownConfig.name,
|
|
937
|
+
success: false,
|
|
938
|
+
});
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
return results;
|
|
943
|
+
}
|
|
944
|
+
/**
|
|
945
|
+
* Remove the base httpcat MCP config file
|
|
946
|
+
*
|
|
947
|
+
* Removes ~/.config/httpcat/mcp.json if it exists.
|
|
948
|
+
*
|
|
949
|
+
* @returns true if removal succeeded or file doesn't exist, false on error
|
|
950
|
+
*/
|
|
951
|
+
export function removeBaseMcpConfig() {
|
|
952
|
+
try {
|
|
953
|
+
const mcpConfigPath = path.join(process.env.HOME || "", ".config", "httpcat", "mcp.json");
|
|
954
|
+
if (fs.existsSync(mcpConfigPath)) {
|
|
955
|
+
fs.unlinkSync(mcpConfigPath);
|
|
956
|
+
}
|
|
957
|
+
return true;
|
|
958
|
+
}
|
|
959
|
+
catch (error) {
|
|
960
|
+
return false;
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
//# sourceMappingURL=llm-cli-config.js.map
|