feat: Codex CLI support
docs: Update instructions to discover uvx automatically, may not be installed system wide
This commit is contained in:
68
README.md
68
README.md
@@ -3,12 +3,13 @@
|
||||
[zen_web.webm](https://github.com/user-attachments/assets/851e3911-7f06-47c0-a4ab-a2601236697c)
|
||||
|
||||
<div align="center">
|
||||
<b>🤖 <a href="https://www.anthropic.com/claude-code">Claude Code</a> OR <a href="https://github.com/google-gemini/gemini-cli">Gemini CLI</a> + [Gemini / OpenAI / Grok / OpenRouter / DIAL / Ollama / Anthropic / Any Model] = Your Ultimate AI Development Team</b>
|
||||
<b>🤖 <a href="https://www.anthropic.com/claude-code">Claude Code</a> OR <a href="https://github.com/google-gemini/gemini-cli">Gemini CLI</a> OR <a href="https://github.com/openai/codex">Codex CLI</a> + [Gemini / OpenAI / Grok / OpenRouter / DIAL / Ollama / Anthropic / Any Model] = Your Ultimate AI Development Team</b>
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
|
||||
**AI orchestration for Claude Code** - A Model Context Protocol server that gives your CLI of choice (e.g. [Claude Code](https://www.anthropic.com/claude-code)) access to multiple AI models for enhanced code analysis, problem-solving, and collaborative development.
|
||||
**AI orchestration for Claude Code** - A Model Context Protocol server that gives your CLI of choice (e.g. [Claude Code](https://www.anthropic.com/claude-code)) access to multiple AI models for enhanced code analysis, problem-solving, and collaborative development. Zen
|
||||
works with Claude Code, Gemini CLI, Codex CLI as well as others.
|
||||
|
||||
**True AI collaboration with conversation continuity** - Claude stays in control but gets perspectives from the best AI for each subtask. Context carries forward seamlessly across tools and models, enabling complex workflows like: code reviews with multiple models → automated planning → implementation → pre-commit validation.
|
||||
|
||||
@@ -90,28 +91,35 @@ For best results, use Claude Code with:
|
||||
|
||||
**2. Install** (choose one):
|
||||
|
||||
**Option A: Instant Setup with uvx** (recommended)
|
||||
```json
|
||||
// Add to ~/.claude/settings.json or .mcp.json
|
||||
{
|
||||
"mcpServers": {
|
||||
"zen": {
|
||||
"command": "uvx",
|
||||
"args": ["--from", "git+https://github.com/BeehiveInnovations/zen-mcp-server.git", "zen-mcp-server"],
|
||||
"env": {
|
||||
"PATH": "/usr/local/bin:/usr/bin:/bin:/opt/homebrew/bin:~/.local/bin",
|
||||
"GEMINI_API_KEY": "your-key-here"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Option B: Clone and Setup**
|
||||
**Option A: Clone and Automatic Setup** (recommended)
|
||||
```bash
|
||||
git clone https://github.com/BeehiveInnovations/zen-mcp-server.git
|
||||
cd zen-mcp-server
|
||||
./run-server.sh # Handles everything: setup, config, API keys
|
||||
|
||||
# Handles everything: setup, config, API keys from system environment.
|
||||
# Auto-configures Claude Desktop, Claude Code, Gemini CLI, Codex CLI
|
||||
# Enable / disable additional settings in .env
|
||||
./run-server.sh
|
||||
```
|
||||
|
||||
**Option B: Instant Setup with [uvx](https://docs.astral.sh/uv/getting-started/installation/)**
|
||||
```json
|
||||
// Add to ~/.claude/settings.json or .mcp.json
|
||||
// Don't forget to add your API keys under env
|
||||
{
|
||||
"mcpServers": {
|
||||
"zen": {
|
||||
"command": "bash",
|
||||
"args": ["-c", "for p in $(which uvx 2>/dev/null) $HOME/.local/bin/uvx /opt/homebrew/bin/uvx /usr/local/bin/uvx uvx; do [ -x \"$p\" ] && exec \"$p\" --from git+https://github.com/BeehiveInnovations/zen-mcp-server.git zen-mcp-server; done; echo 'uvx not found' >&2; exit 1"],
|
||||
"env": {
|
||||
"PATH": "/usr/local/bin:/usr/bin:/bin:/opt/homebrew/bin:~/.local/bin",
|
||||
"GEMINI_API_KEY": "your-key-here",
|
||||
"DISABLED_TOOLS": "analyze,refactor,testgen,secaudit,docgen,tracer",
|
||||
"DEFAULT_MODEL": "auto"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**3. Start Using!**
|
||||
@@ -121,7 +129,7 @@ cd zen-mcp-server
|
||||
"Plan the migration strategy with zen, get consensus from multiple models"
|
||||
```
|
||||
|
||||
👉 **[Complete Setup Guide](docs/getting-started.md)** with detailed installation, configuration, and troubleshooting
|
||||
👉 **[Complete Setup Guide](docs/getting-started.md)** with detailed installation, configuration for Gemini / Codex, and troubleshooting
|
||||
|
||||
## Core Tools
|
||||
|
||||
@@ -188,8 +196,20 @@ DISABLED_TOOLS=
|
||||
"mcpServers": {
|
||||
"zen": {
|
||||
"env": {
|
||||
// Enable analyze by removing it from disabled list
|
||||
"DISABLED_TOOLS": "refactor,testgen,secaudit,docgen,tracer"
|
||||
// Tool configuration
|
||||
"DISABLED_TOOLS": "refactor,testgen,secaudit,docgen,tracer",
|
||||
"DEFAULT_MODEL": "pro",
|
||||
"DEFAULT_THINKING_MODE_THINKDEEP": "high",
|
||||
|
||||
// API configuration
|
||||
"GEMINI_API_KEY": "your-gemini-key",
|
||||
"OPENAI_API_KEY": "your-openai-key",
|
||||
"OPENROUTER_API_KEY": "your-openrouter-key",
|
||||
|
||||
// Logging and performance
|
||||
"LOG_LEVEL": "INFO",
|
||||
"CONVERSATION_TIMEOUT_HOURS": "6",
|
||||
"MAX_CONVERSATION_TURNS": "50"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,6 +68,8 @@ Choose your preferred installation method:
|
||||
|
||||
**Prerequisites**: [Install uv first](https://docs.astral.sh/uv/getting-started/installation/)
|
||||
|
||||
Choose your AI coding assistant and add the corresponding configuration:
|
||||
|
||||
**For Claude Desktop:**
|
||||
1. Open Claude Desktop → Settings → Developer → Edit Config
|
||||
2. Add this configuration:
|
||||
@@ -79,7 +81,7 @@ Choose your preferred installation method:
|
||||
"command": "sh",
|
||||
"args": [
|
||||
"-c",
|
||||
"exec $(which uvx || echo uvx) --from git+https://github.com/BeehiveInnovations/zen-mcp-server.git zen-mcp-server"
|
||||
"for p in $(which uvx 2>/dev/null) $HOME/.local/bin/uvx /opt/homebrew/bin/uvx /usr/local/bin/uvx uvx; do [ -x \"$p\" ] && exec \"$p\" --from git+https://github.com/BeehiveInnovations/zen-mcp-server.git zen-mcp-server; done; echo 'uvx not found' >&2; exit 1"
|
||||
],
|
||||
"env": {
|
||||
"PATH": "/usr/local/bin:/usr/bin:/bin:/opt/homebrew/bin:~/.local/bin",
|
||||
@@ -100,7 +102,7 @@ Create `.mcp.json` in your project root:
|
||||
"command": "sh",
|
||||
"args": [
|
||||
"-c",
|
||||
"exec $(which uvx || echo uvx) --from git+https://github.com/BeehiveInnovations/zen-mcp-server.git zen-mcp-server"
|
||||
"for p in $(which uvx 2>/dev/null) $HOME/.local/bin/uvx /opt/homebrew/bin/uvx /usr/local/bin/uvx uvx; do [ -x \"$p\" ] && exec \"$p\" --from git+https://github.com/BeehiveInnovations/zen-mcp-server.git zen-mcp-server; done; echo 'uvx not found' >&2; exit 1"
|
||||
],
|
||||
"env": {
|
||||
"PATH": "/usr/local/bin:/usr/bin:/bin:/opt/homebrew/bin:~/.local/bin",
|
||||
@@ -121,7 +123,7 @@ Edit `~/.gemini/settings.json`:
|
||||
"command": "sh",
|
||||
"args": [
|
||||
"-c",
|
||||
"exec $(which uvx || echo uvx) --from git+https://github.com/BeehiveInnovations/zen-mcp-server.git zen-mcp-server"
|
||||
"for p in $(which uvx 2>/dev/null) $HOME/.local/bin/uvx /opt/homebrew/bin/uvx /usr/local/bin/uvx uvx; do [ -x \"$p\" ] && exec \"$p\" --from git+https://github.com/BeehiveInnovations/zen-mcp-server.git zen-mcp-server; done; echo 'uvx not found' >&2; exit 1"
|
||||
],
|
||||
"env": {
|
||||
"PATH": "/usr/local/bin:/usr/bin:/bin:/opt/homebrew/bin:~/.local/bin",
|
||||
@@ -132,6 +134,19 @@ Edit `~/.gemini/settings.json`:
|
||||
}
|
||||
```
|
||||
|
||||
**For Codex CLI:**
|
||||
Edit `~/.codex/config.toml`:
|
||||
|
||||
```toml
|
||||
[mcp_servers.zen]
|
||||
command = "bash"
|
||||
args = ["-c", "for p in $(which uvx 2>/dev/null) $HOME/.local/bin/uvx /opt/homebrew/bin/uvx /usr/local/bin/uvx uvx; do [ -x \\\"$p\\\" ] && exec \\\"$p\\\" --from git+https://github.com/BeehiveInnovations/zen-mcp-server.git zen-mcp-server; done; echo 'uvx not found' >&2; exit 1"]
|
||||
|
||||
[mcp_servers.zen.env]
|
||||
PATH = "/usr/local/bin:/usr/bin:/bin:/opt/homebrew/bin:$HOME/.local/bin:$HOME/.cargo/bin:$HOME/bin"
|
||||
GEMINI_API_KEY = "your_api_key_here"
|
||||
```
|
||||
|
||||
**Benefits of uvx method:**
|
||||
- ✅ Zero manual setup required
|
||||
- ✅ Always pulls latest version
|
||||
@@ -221,6 +236,11 @@ CUSTOM_MODEL_NAME=llama3.2 # Default model name
|
||||
### For Gemini CLI:
|
||||
**Note**: While Zen MCP connects to Gemini CLI, tool invocation isn't working correctly yet. See [Gemini CLI Setup](gemini-setup.md) for updates.
|
||||
|
||||
### For Codex CLI:
|
||||
1. Restart Codex CLI if running
|
||||
2. Open a new conversation
|
||||
3. Try: `"Use zen to list available models"`
|
||||
|
||||
### Test Commands:
|
||||
```
|
||||
"Use zen to list available models"
|
||||
@@ -229,6 +249,8 @@ CUSTOM_MODEL_NAME=llama3.2 # Default model name
|
||||
"Debug this error with o3: [paste error]"
|
||||
```
|
||||
|
||||
**Note**: Codex CLI provides excellent MCP integration with automatic environment variable configuration when using the setup script.
|
||||
|
||||
## Step 5: Start Using Zen
|
||||
|
||||
### Basic Usage Patterns:
|
||||
|
||||
410
run-server.sh
410
run-server.sh
@@ -1163,6 +1163,72 @@ check_api_keys() {
|
||||
}
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Environment Variable Parsing Function
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# Parse .env file and extract all valid environment variables
|
||||
parse_env_variables() {
|
||||
local env_vars=""
|
||||
|
||||
if [[ -f .env ]]; then
|
||||
# Read .env file and extract non-empty, non-comment variables
|
||||
while IFS= read -r line; do
|
||||
# Skip comments, empty lines, and lines starting with #
|
||||
if [[ -n "$line" && ! "$line" =~ ^[[:space:]]*# && "$line" =~ ^[[:space:]]*([^=]+)=(.*)$ ]]; then
|
||||
local key="${BASH_REMATCH[1]}"
|
||||
local value="${BASH_REMATCH[2]}"
|
||||
|
||||
# Clean up key (remove leading/trailing whitespace)
|
||||
key=$(echo "$key" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
|
||||
|
||||
# Skip if value is empty or just whitespace
|
||||
if [[ -n "$value" && ! "$value" =~ ^[[:space:]]*$ ]]; then
|
||||
# Clean up value (remove leading/trailing whitespace and quotes)
|
||||
value=$(echo "$value" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | sed 's/^"//;s/"$//')
|
||||
|
||||
# Remove inline comments (everything after # that's not in quotes)
|
||||
value=$(echo "$value" | sed 's/[[:space:]]*#.*$//')
|
||||
|
||||
# Skip if value is a placeholder or empty after comment removal
|
||||
if [[ ! "$value" =~ ^your_.*_here$ && "$value" != "your_" && -n "$value" && ! "$value" =~ ^[[:space:]]*$ ]]; then
|
||||
env_vars+="$key=$value"$'\n'
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done < .env
|
||||
fi
|
||||
|
||||
# If no .env file or no valid vars, fall back to environment variables
|
||||
if [[ -z "$env_vars" ]]; then
|
||||
local api_keys=(
|
||||
"GEMINI_API_KEY"
|
||||
"OPENAI_API_KEY"
|
||||
"XAI_API_KEY"
|
||||
"DIAL_API_KEY"
|
||||
"OPENROUTER_API_KEY"
|
||||
"CUSTOM_API_URL"
|
||||
"CUSTOM_API_KEY"
|
||||
"CUSTOM_MODEL_NAME"
|
||||
"DISABLED_TOOLS"
|
||||
"DEFAULT_MODEL"
|
||||
"LOG_LEVEL"
|
||||
"DEFAULT_THINKING_MODE_THINKDEEP"
|
||||
"CONVERSATION_TIMEOUT_HOURS"
|
||||
"MAX_CONVERSATION_TURNS"
|
||||
)
|
||||
|
||||
for key_name in "${api_keys[@]}"; do
|
||||
local key_value="${!key_name:-}"
|
||||
if [[ -n "$key_value" && ! "$key_value" =~ ^your_.*_here$ ]]; then
|
||||
env_vars+="$key_name=$key_value"$'\n'
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
echo "$env_vars"
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Claude Integration Functions
|
||||
# ----------------------------------------------------------------------------
|
||||
@@ -1199,15 +1265,28 @@ check_claude_cli_integration() {
|
||||
print_warning "Found old Docker-based Zen registration, updating..."
|
||||
claude mcp remove zen -s user 2>/dev/null || true
|
||||
|
||||
# Re-add with correct Python command
|
||||
if claude mcp add zen -s user -- "$python_cmd" "$server_path" 2>/dev/null; then
|
||||
print_success "Updated Zen to become a standalone script"
|
||||
# Re-add with correct Python command and environment variables
|
||||
local env_vars=$(parse_env_variables)
|
||||
local env_args=""
|
||||
|
||||
# Convert environment variables to -e arguments
|
||||
if [[ -n "$env_vars" ]]; then
|
||||
while IFS= read -r line; do
|
||||
if [[ -n "$line" && "$line" =~ ^([^=]+)=(.*)$ ]]; then
|
||||
env_args+=" -e ${BASH_REMATCH[1]}=\"${BASH_REMATCH[2]}\""
|
||||
fi
|
||||
done <<< "$env_vars"
|
||||
fi
|
||||
|
||||
local claude_cmd="claude mcp add zen -s user$env_args -- \"$python_cmd\" \"$server_path\""
|
||||
if eval "$claude_cmd" 2>/dev/null; then
|
||||
print_success "Updated Zen to become a standalone script with environment variables"
|
||||
return 0
|
||||
else
|
||||
echo ""
|
||||
echo "Failed to update MCP registration. Please run manually:"
|
||||
echo " claude mcp remove zen -s user"
|
||||
echo " claude mcp add zen -s user -- $python_cmd $server_path"
|
||||
echo " $claude_cmd"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
@@ -1219,14 +1298,28 @@ check_claude_cli_integration() {
|
||||
print_warning "Zen registered with different path, updating..."
|
||||
claude mcp remove zen -s user 2>/dev/null || true
|
||||
|
||||
if claude mcp add zen -s user -- "$python_cmd" "$server_path" 2>/dev/null; then
|
||||
print_success "Updated Zen with current path"
|
||||
# Re-add with current path and environment variables
|
||||
local env_vars=$(parse_env_variables)
|
||||
local env_args=""
|
||||
|
||||
# Convert environment variables to -e arguments
|
||||
if [[ -n "$env_vars" ]]; then
|
||||
while IFS= read -r line; do
|
||||
if [[ -n "$line" && "$line" =~ ^([^=]+)=(.*)$ ]]; then
|
||||
env_args+=" -e ${BASH_REMATCH[1]}=\"${BASH_REMATCH[2]}\""
|
||||
fi
|
||||
done <<< "$env_vars"
|
||||
fi
|
||||
|
||||
local claude_cmd="claude mcp add zen -s user$env_args -- \"$python_cmd\" \"$server_path\""
|
||||
if eval "$claude_cmd" 2>/dev/null; then
|
||||
print_success "Updated Zen with current path and environment variables"
|
||||
return 0
|
||||
else
|
||||
echo ""
|
||||
echo "Failed to update MCP registration. Please run manually:"
|
||||
echo " claude mcp remove zen -s user"
|
||||
echo " claude mcp add zen -s user -- $python_cmd $server_path"
|
||||
echo " $claude_cmd"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
@@ -1237,19 +1330,46 @@ check_claude_cli_integration() {
|
||||
read -p "Add Zen to Claude Code? (Y/n): " -n 1 -r
|
||||
echo ""
|
||||
if [[ $REPLY =~ ^[Nn]$ ]]; then
|
||||
local env_vars=$(parse_env_variables)
|
||||
local env_args=""
|
||||
|
||||
# Convert environment variables to -e arguments for manual command
|
||||
if [[ -n "$env_vars" ]]; then
|
||||
while IFS= read -r line; do
|
||||
if [[ -n "$line" && "$line" =~ ^([^=]+)=(.*)$ ]]; then
|
||||
env_args+=" -e ${BASH_REMATCH[1]}=\"${BASH_REMATCH[2]}\""
|
||||
fi
|
||||
done <<< "$env_vars"
|
||||
fi
|
||||
|
||||
print_info "To add manually later, run:"
|
||||
echo " claude mcp add zen -s user -- $python_cmd $server_path"
|
||||
echo " claude mcp add zen -s user$env_args -- $python_cmd $server_path"
|
||||
return 0
|
||||
fi
|
||||
|
||||
print_info "Registering Zen with Claude Code..."
|
||||
if claude mcp add zen -s user -- "$python_cmd" "$server_path" 2>/dev/null; then
|
||||
print_success "Successfully added Zen to Claude Code"
|
||||
|
||||
# Add with environment variables
|
||||
local env_vars=$(parse_env_variables)
|
||||
local env_args=""
|
||||
|
||||
# Convert environment variables to -e arguments
|
||||
if [[ -n "$env_vars" ]]; then
|
||||
while IFS= read -r line; do
|
||||
if [[ -n "$line" && "$line" =~ ^([^=]+)=(.*)$ ]]; then
|
||||
env_args+=" -e ${BASH_REMATCH[1]}=\"${BASH_REMATCH[2]}\""
|
||||
fi
|
||||
done <<< "$env_vars"
|
||||
fi
|
||||
|
||||
local claude_cmd="claude mcp add zen -s user$env_args -- \"$python_cmd\" \"$server_path\""
|
||||
if eval "$claude_cmd" 2>/dev/null; then
|
||||
print_success "Successfully added Zen to Claude Code with environment variables"
|
||||
return 0
|
||||
else
|
||||
echo ""
|
||||
echo "Failed to add automatically. To add manually, run:"
|
||||
echo " claude mcp add zen -s user -- $python_cmd $server_path"
|
||||
echo " $claude_cmd"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
@@ -1318,8 +1438,16 @@ except Exception as e:
|
||||
" && mv "$temp_file" "$config_path"
|
||||
fi
|
||||
|
||||
# Add new config
|
||||
# Add new config with environment variables
|
||||
local env_vars=$(parse_env_variables)
|
||||
local temp_file=$(mktemp)
|
||||
local env_file=$(mktemp)
|
||||
|
||||
# Write environment variables to a temporary file for Python to read
|
||||
if [[ -n "$env_vars" ]]; then
|
||||
echo "$env_vars" > "$env_file"
|
||||
fi
|
||||
|
||||
python3 -c "
|
||||
import json
|
||||
import sys
|
||||
@@ -1335,27 +1463,83 @@ if 'mcpServers' not in config:
|
||||
config['mcpServers'] = {}
|
||||
|
||||
# Add zen server
|
||||
config['mcpServers']['zen'] = {
|
||||
zen_config = {
|
||||
'command': '$python_cmd',
|
||||
'args': ['$server_path']
|
||||
}
|
||||
|
||||
# Add environment variables if they exist
|
||||
env_dict = {}
|
||||
try:
|
||||
with open('$env_file', 'r') as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if '=' in line and line:
|
||||
key, value = line.split('=', 1)
|
||||
env_dict[key] = value
|
||||
except:
|
||||
pass
|
||||
|
||||
if env_dict:
|
||||
zen_config['env'] = env_dict
|
||||
|
||||
config['mcpServers']['zen'] = zen_config
|
||||
|
||||
with open('$temp_file', 'w') as f:
|
||||
json.dump(config, f, indent=2)
|
||||
" && mv "$temp_file" "$config_path"
|
||||
|
||||
# Clean up temporary env file
|
||||
rm -f "$env_file" 2>/dev/null || true
|
||||
|
||||
else
|
||||
print_info "Creating new Claude Desktop config..."
|
||||
cat > "$config_path" << EOF
|
||||
{
|
||||
"mcpServers": {
|
||||
"zen": {
|
||||
"command": "$python_cmd",
|
||||
"args": ["$server_path"]
|
||||
|
||||
# Create new config with environment variables
|
||||
local env_vars=$(parse_env_variables)
|
||||
local temp_file=$(mktemp)
|
||||
local env_file=$(mktemp)
|
||||
|
||||
# Write environment variables to a temporary file for Python to read
|
||||
if [[ -n "$env_vars" ]]; then
|
||||
echo "$env_vars" > "$env_file"
|
||||
fi
|
||||
|
||||
python3 -c "
|
||||
import json
|
||||
import sys
|
||||
|
||||
config = {'mcpServers': {}}
|
||||
|
||||
# Add zen server
|
||||
zen_config = {
|
||||
'command': '$python_cmd',
|
||||
'args': ['$server_path']
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
# Add environment variables if they exist
|
||||
env_dict = {}
|
||||
try:
|
||||
with open('$env_file', 'r') as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if '=' in line and line:
|
||||
key, value = line.split('=', 1)
|
||||
env_dict[key] = value
|
||||
except:
|
||||
pass
|
||||
|
||||
if env_dict:
|
||||
zen_config['env'] = env_dict
|
||||
|
||||
config['mcpServers']['zen'] = zen_config
|
||||
|
||||
with open('$temp_file', 'w') as f:
|
||||
json.dump(config, f, indent=2)
|
||||
" && mv "$temp_file" "$config_path"
|
||||
|
||||
# Clean up temporary env file
|
||||
rm -f "$env_file" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
if [[ $? -eq 0 ]]; then
|
||||
@@ -1367,12 +1551,36 @@ EOF
|
||||
print_error "Failed to update Claude Desktop config"
|
||||
echo "Manual config location: $config_path"
|
||||
echo "Add this configuration:"
|
||||
|
||||
# Generate example with actual environment variables for error case
|
||||
example_env=""
|
||||
env_vars=$(parse_env_variables)
|
||||
if [[ -n "$env_vars" ]]; then
|
||||
local first_entry=true
|
||||
while IFS= read -r line; do
|
||||
if [[ -n "$line" && "$line" =~ ^([^=]+)=(.*)$ ]]; then
|
||||
local key="${BASH_REMATCH[1]}"
|
||||
local value="your_$(echo "${key}" | tr '[:upper:]' '[:lower:]')"
|
||||
|
||||
if [[ "$first_entry" == true ]]; then
|
||||
first_entry=false
|
||||
example_env=" \"$key\": \"$value\""
|
||||
else
|
||||
example_env+=",\n \"$key\": \"$value\""
|
||||
fi
|
||||
fi
|
||||
done <<< "$env_vars"
|
||||
fi
|
||||
|
||||
cat << EOF
|
||||
{
|
||||
"mcpServers": {
|
||||
"zen": {
|
||||
"command": "$python_cmd",
|
||||
"args": ["$server_path"]
|
||||
"args": ["$server_path"]$(if [[ -n "$example_env" ]]; then echo ","; fi)$(if [[ -n "$example_env" ]]; then echo "
|
||||
\"env\": {
|
||||
$(echo -e "$example_env")
|
||||
}"; fi)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1474,6 +1682,103 @@ EOF
|
||||
fi
|
||||
}
|
||||
|
||||
# Check and update Codex CLI configuration
|
||||
check_codex_cli_integration() {
|
||||
# Check if Codex is installed
|
||||
if ! command -v codex &> /dev/null; then
|
||||
# Codex CLI not installed
|
||||
return 0
|
||||
fi
|
||||
|
||||
local codex_config="$HOME/.codex/config.toml"
|
||||
|
||||
# Check if zen is already configured
|
||||
if [[ -f "$codex_config" ]] && grep -q '\[mcp_servers\.zen\]' "$codex_config" 2>/dev/null; then
|
||||
# Already configured
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Ask user if they want to add Zen to Codex CLI
|
||||
echo ""
|
||||
read -p "Configure Zen for Codex CLI? (Y/n): " -n 1 -r
|
||||
echo ""
|
||||
if [[ $REPLY =~ ^[Nn]$ ]]; then
|
||||
print_info "Skipping Codex CLI integration"
|
||||
return 0
|
||||
fi
|
||||
|
||||
print_info "Updating Codex CLI configuration..."
|
||||
|
||||
# Create config directory if it doesn't exist
|
||||
mkdir -p "$(dirname "$codex_config")" 2>/dev/null || true
|
||||
|
||||
# Create backup if config exists
|
||||
if [[ -f "$codex_config" ]]; then
|
||||
cp "$codex_config" "${codex_config}.backup_$(date +%Y%m%d_%H%M%S)"
|
||||
fi
|
||||
|
||||
# Get environment variables using shared function
|
||||
local env_vars=$(parse_env_variables)
|
||||
|
||||
# Write zen configuration to config.toml
|
||||
{
|
||||
echo ""
|
||||
echo "[mcp_servers.zen]"
|
||||
echo "command = \"bash\""
|
||||
echo "args = [\"-c\", \"for p in \$(which uvx 2>/dev/null) \$HOME/.local/bin/uvx /opt/homebrew/bin/uvx /usr/local/bin/uvx uvx; do [ -x \\\"\$p\\\" ] && exec \\\"\$p\\\" --from git+https://github.com/BeehiveInnovations/zen-mcp-server.git zen-mcp-server; done; echo 'uvx not found' >&2; exit 1\"]"
|
||||
echo ""
|
||||
echo "[mcp_servers.zen.env]"
|
||||
echo "PATH = \"/usr/local/bin:/usr/bin:/bin:/opt/homebrew/bin:\$HOME/.local/bin:\$HOME/.cargo/bin:\$HOME/bin\""
|
||||
if [[ -n "$env_vars" ]]; then
|
||||
# Convert KEY=VALUE format to TOML KEY = "VALUE" format
|
||||
while IFS= read -r line; do
|
||||
if [[ -n "$line" && "$line" =~ ^([^=]+)=(.*)$ ]]; then
|
||||
local key="${BASH_REMATCH[1]}"
|
||||
local value="${BASH_REMATCH[2]}"
|
||||
# Escape backslashes first, then double quotes for TOML compatibility
|
||||
local escaped_value
|
||||
escaped_value=$(echo "$value" | sed -e 's/\\/\\\\/g' -e 's/"/\\"/g')
|
||||
echo "$key = \"$escaped_value\""
|
||||
fi
|
||||
done <<< "$env_vars"
|
||||
fi
|
||||
} >> "$codex_config"
|
||||
|
||||
if [[ $? -eq 0 ]]; then
|
||||
print_success "Successfully configured Codex CLI"
|
||||
echo " Config: $codex_config"
|
||||
echo " Restart Codex CLI to use Zen MCP Server"
|
||||
else
|
||||
print_error "Failed to update Codex CLI config"
|
||||
echo "Manual config location: $codex_config"
|
||||
echo "Add this configuration:"
|
||||
|
||||
# Generate example with actual environment variables for error case
|
||||
env_vars=$(parse_env_variables)
|
||||
cat << EOF
|
||||
[mcp_servers.zen]
|
||||
command = "sh"
|
||||
args = ["-c", "exec \$(which uvx 2>/dev/null || echo uvx) --from git+https://github.com/BeehiveInnovations/zen-mcp-server.git zen-mcp-server"]
|
||||
|
||||
[mcp_servers.zen.env]
|
||||
PATH = "/usr/local/bin:/usr/bin:/bin:/opt/homebrew/bin:\$HOME/.local/bin:\$HOME/.cargo/bin:\$HOME/bin"
|
||||
EOF
|
||||
|
||||
# Add environment variable examples only if they exist
|
||||
if [[ -n "$env_vars" ]]; then
|
||||
while IFS= read -r line; do
|
||||
if [[ -n "$line" && "$line" =~ ^([^=]+)=(.*)$ ]]; then
|
||||
local key="${BASH_REMATCH[1]}"
|
||||
echo "${key} = \"your_$(echo "${key}" | tr '[:upper:]' '[:lower:]')\""
|
||||
fi
|
||||
done <<< "$env_vars"
|
||||
else
|
||||
# Show GEMINI_API_KEY example if no environment variables exist
|
||||
echo "GEMINI_API_KEY = \"your_gemini_api_key_here\""
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Display configuration instructions
|
||||
display_config_instructions() {
|
||||
local python_cmd="$1"
|
||||
@@ -1491,18 +1796,52 @@ display_config_instructions() {
|
||||
echo ""
|
||||
|
||||
print_info "1. For Claude Code (CLI):"
|
||||
echo -e " ${GREEN}claude mcp add zen -s user -- $python_cmd $server_path${NC}"
|
||||
# Show command with environment variables
|
||||
local env_vars=$(parse_env_variables)
|
||||
local env_args=""
|
||||
if [[ -n "$env_vars" ]]; then
|
||||
while IFS= read -r line; do
|
||||
if [[ -n "$line" && "$line" =~ ^([^=]+)=(.*)$ ]]; then
|
||||
env_args+=" -e ${BASH_REMATCH[1]}=\"${BASH_REMATCH[2]}\""
|
||||
fi
|
||||
done <<< "$env_vars"
|
||||
fi
|
||||
echo -e " ${GREEN}claude mcp add zen -s user$env_args -- $python_cmd $server_path${NC}"
|
||||
echo ""
|
||||
|
||||
print_info "2. For Claude Desktop:"
|
||||
echo " Add this configuration to your Claude Desktop config file:"
|
||||
echo ""
|
||||
|
||||
# Generate example with actual environment variables that exist
|
||||
example_env=""
|
||||
env_vars=$(parse_env_variables)
|
||||
if [[ -n "$env_vars" ]]; then
|
||||
local first_entry=true
|
||||
while IFS= read -r line; do
|
||||
if [[ -n "$line" && "$line" =~ ^([^=]+)=(.*)$ ]]; then
|
||||
local key="${BASH_REMATCH[1]}"
|
||||
local value="your_$(echo "${key}" | tr '[:upper:]' '[:lower:]')"
|
||||
|
||||
if [[ "$first_entry" == true ]]; then
|
||||
first_entry=false
|
||||
example_env=" \"$key\": \"$value\""
|
||||
else
|
||||
example_env+=",\n \"$key\": \"$value\""
|
||||
fi
|
||||
fi
|
||||
done <<< "$env_vars"
|
||||
fi
|
||||
|
||||
cat << EOF
|
||||
{
|
||||
"mcpServers": {
|
||||
"zen": {
|
||||
"command": "$python_cmd",
|
||||
"args": ["$server_path"]
|
||||
"args": ["$server_path"]$(if [[ -n "$example_env" ]]; then echo ","; fi)$(if [[ -n "$example_env" ]]; then echo "
|
||||
\"env\": {
|
||||
$(echo -e "$example_env")
|
||||
}"; fi)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1531,6 +1870,20 @@ EOF
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
echo ""
|
||||
|
||||
print_info "For Codex CLI:"
|
||||
echo " Add this configuration to ~/.codex/config.toml:"
|
||||
echo ""
|
||||
cat << EOF
|
||||
[mcp_servers.zen]
|
||||
command = "bash"
|
||||
args = ["-c", "for p in \$(which uvx 2>/dev/null) \$HOME/.local/bin/uvx /opt/homebrew/bin/uvx /usr/local/bin/uvx uvx; do [ -x \\\"\$p\\\" ] && exec \\\"\$p\\\" --from git+https://github.com/BeehiveInnovations/zen-mcp-server.git zen-mcp-server; done; echo 'uvx not found' >&2; exit 1"]
|
||||
|
||||
[mcp_servers.zen.env]
|
||||
PATH = "/usr/local/bin:/usr/bin:/bin:/opt/homebrew/bin:\$HOME/.local/bin:\$HOME/.cargo/bin:\$HOME/bin"
|
||||
GEMINI_API_KEY = "your_gemini_api_key_here"
|
||||
EOF
|
||||
echo ""
|
||||
}
|
||||
@@ -1775,12 +2128,15 @@ main() {
|
||||
# Step 10: Check Gemini CLI integration
|
||||
check_gemini_cli_integration "$script_dir"
|
||||
|
||||
# Step 11: Display log information
|
||||
# Step 11: Check Codex CLI integration
|
||||
check_codex_cli_integration
|
||||
|
||||
# Step 12: Display log information
|
||||
echo ""
|
||||
echo "Logs will be written to: $script_dir/$LOG_DIR/$LOG_FILE"
|
||||
echo ""
|
||||
|
||||
# Step 12: Handle command line arguments
|
||||
# Step 13: Handle command line arguments
|
||||
if [[ "$arg" == "-f" ]] || [[ "$arg" == "--follow" ]]; then
|
||||
follow_logs
|
||||
else
|
||||
|
||||
Reference in New Issue
Block a user