Merge remote-tracking branch 'upstream/main' into fix/path-traversal-security
This commit is contained in:
@@ -11,7 +11,7 @@ __pycache__/
|
||||
env/
|
||||
venv/
|
||||
.venv/
|
||||
.zen_venv/
|
||||
.pal_venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Zen MCP Server Environment Configuration
|
||||
# PAL MCP Server Environment Configuration
|
||||
# Copy this file to .env and fill in your values
|
||||
|
||||
# API Keys - At least one is required
|
||||
@@ -191,7 +191,7 @@ DISABLED_TOOLS=analyze,refactor,testgen,secaudit,docgen,tracer
|
||||
# LOCALE=fr-FR
|
||||
|
||||
# ===========================================
|
||||
# Zen MCP Server Configuration
|
||||
# PAL MCP Server Configuration
|
||||
# ===========================================
|
||||
|
||||
# Force .env file values to override system environment variables
|
||||
@@ -213,7 +213,7 @@ DISABLED_TOOLS=analyze,refactor,testgen,secaudit,docgen,tracer
|
||||
# Development with multiple AI tools: true (prevents tool conflicts)
|
||||
# Production/Container deployments: false (preserves security practices)
|
||||
# CI/CD environments: false (respects pipeline secrets)
|
||||
ZEN_MCP_FORCE_ENV_OVERRIDE=false
|
||||
PAL_MCP_FORCE_ENV_OVERRIDE=false
|
||||
|
||||
# ===========================================
|
||||
# Docker Configuration
|
||||
@@ -221,7 +221,7 @@ ZEN_MCP_FORCE_ENV_OVERRIDE=false
|
||||
|
||||
# Container name for Docker Compose
|
||||
# Used when running with docker-compose.yml
|
||||
COMPOSE_PROJECT_NAME=zen-mcp
|
||||
COMPOSE_PROJECT_NAME=pal-mcp
|
||||
|
||||
# Timezone for Docker containers
|
||||
# Ensures consistent time handling in containerized environments
|
||||
|
||||
4
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
4
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -12,7 +12,7 @@ body:
|
||||
attributes:
|
||||
label: Project Version
|
||||
description: "Which version are you using? (To see version: ./run-server.sh -v)"
|
||||
placeholder: "e.g., 5.1.0"
|
||||
placeholder: "e.g., 9.4.1"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
@@ -29,7 +29,7 @@ body:
|
||||
id: logs
|
||||
attributes:
|
||||
label: Relevant Log Output
|
||||
description: "Please copy and paste any relevant log output. Logs are stored under the `logs` folder in the zen folder. You an also use `./run-server.sh -f` to see logs"
|
||||
description: "Please copy and paste any relevant log output. Logs are stored under the `logs` folder in the pal folder. You an also use `./run-server.sh -f` to see logs"
|
||||
render: shell
|
||||
|
||||
- type: dropdown
|
||||
|
||||
6
.github/ISSUE_TEMPLATE/config.yml
vendored
6
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -1,12 +1,12 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: 💬 General Discussion
|
||||
url: https://github.com/BeehiveInnovations/zen-mcp-server/discussions
|
||||
url: https://github.com/BeehiveInnovations/pal-mcp-server/discussions
|
||||
about: Ask questions, share ideas, or discuss usage patterns with the community
|
||||
- name: 📚 Documentation
|
||||
url: https://github.com/BeehiveInnovations/zen-mcp-server/blob/main/README.md
|
||||
url: https://github.com/BeehiveInnovations/pal-mcp-server/blob/main/README.md
|
||||
about: Check the README for setup instructions and usage examples
|
||||
- name: 🤝 Contributing Guide
|
||||
url: https://github.com/BeehiveInnovations/zen-mcp-server/blob/main/CONTRIBUTING.md
|
||||
url: https://github.com/BeehiveInnovations/pal-mcp-server/blob/main/CONTRIBUTING.md
|
||||
about: Learn how to contribute to the project
|
||||
|
||||
|
||||
8
.github/ISSUE_TEMPLATE/tool_addition.yml
vendored
8
.github/ISSUE_TEMPLATE/tool_addition.yml
vendored
@@ -1,5 +1,5 @@
|
||||
name: 🛠️ New Gemini Tool Proposal
|
||||
description: Propose a new Zen MCP tool (e.g., `summarize`, `fixer`, `refactor`)
|
||||
description: Propose a new PAL MCP tool (e.g., `summarize`, `fixer`, `refactor`)
|
||||
labels: ["enhancement", "new-tool"]
|
||||
body:
|
||||
- type: input
|
||||
@@ -15,7 +15,7 @@ body:
|
||||
id: purpose
|
||||
attributes:
|
||||
label: What is the primary purpose of this tool?
|
||||
description: "Explain the tool's core function and the value it provides to developers using Claude + Zen."
|
||||
description: "Explain the tool's core function and the value it provides to developers using Claude + PAL."
|
||||
placeholder: "This tool will automatically generate comprehensive documentation from code, extracting class and function signatures, docstrings, and creating usage examples."
|
||||
validations:
|
||||
required: true
|
||||
@@ -27,7 +27,7 @@ body:
|
||||
description: "Show how a user would invoke this tool through Claude and what the expected output would look like."
|
||||
placeholder: |
|
||||
**User prompt to Claude:**
|
||||
"Use zen to generate documentation for my entire src/ directory"
|
||||
"Use pal to generate documentation for my entire src/ directory"
|
||||
|
||||
**Expected behavior:**
|
||||
- Analyze all Python files in src/
|
||||
@@ -61,7 +61,7 @@ body:
|
||||
id: system-prompt
|
||||
attributes:
|
||||
label: Proposed System Prompt (Optional)
|
||||
description: "If you have ideas for how zen should be prompted for this tool, share them here."
|
||||
description: "If you have ideas for how pal should be prompted for this tool, share them here."
|
||||
placeholder: |
|
||||
You are an expert technical documentation generator. Your task is to create comprehensive, user-friendly documentation from source code...
|
||||
|
||||
|
||||
2
.github/workflows/docker-pr.yml
vendored
2
.github/workflows/docker-pr.yml
vendored
@@ -95,7 +95,7 @@ jobs:
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"zen": {
|
||||
"pal": {
|
||||
"command": "docker",
|
||||
"args": ["run", "--rm", "-i", "-e", "GEMINI_API_KEY", "ghcr.io/${{ github.repository }}:pr-${{ github.event.number }}"],
|
||||
"env": { "GEMINI_API_KEY": "your-key" }
|
||||
|
||||
2
.github/workflows/docker-release.yml
vendored
2
.github/workflows/docker-release.yml
vendored
@@ -87,7 +87,7 @@ jobs:
|
||||
\`\`\`json
|
||||
{
|
||||
"mcpServers": {
|
||||
"zen-mcp-server": {
|
||||
"pal-mcp-server": {
|
||||
"command": "docker",
|
||||
"args": [
|
||||
"run", "--rm", "-i",
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -179,7 +179,7 @@ CLAUDE.local.md
|
||||
.claude/settings.local.json
|
||||
|
||||
# Standalone mode files
|
||||
.zen_venv/
|
||||
.pal_venv/
|
||||
.docker_cleaned
|
||||
logs/
|
||||
*.backup
|
||||
|
||||
@@ -28,7 +28,7 @@ exclude: |
|
||||
\.git/|
|
||||
\.venv/|
|
||||
venv/|
|
||||
\.zen_venv/|
|
||||
\.pal_venv/|
|
||||
__pycache__/|
|
||||
\.pytest_cache/|
|
||||
logs/|
|
||||
|
||||
10
AGENTS.md
10
AGENTS.md
@@ -5,14 +5,14 @@ See `requirements.txt` and `requirements-dev.txt`
|
||||
Also read CLAUDE.md and CLAUDE.local.md if available.
|
||||
|
||||
## Project Structure & Module Organization
|
||||
Zen MCP Server centers on `server.py`, which exposes MCP entrypoints and coordinates multi-model workflows.
|
||||
PAL MCP Server centers on `server.py`, which exposes MCP entrypoints and coordinates multi-model workflows.
|
||||
Feature-specific tools live in `tools/`, provider integrations in `providers/`, and shared helpers in `utils/`.
|
||||
Prompt and system context assets stay in `systemprompts/`, while configuration templates and automation scripts live under `conf/`, `scripts/`, and `docker/`.
|
||||
Unit tests sit in `tests/`; simulator-driven scenarios and log utilities are in `simulator_tests/` with the `communication_simulator_test.py` harness.
|
||||
Authoritative documentation and samples live in `docs/`, and runtime diagnostics are rotated in `logs/`.
|
||||
|
||||
## Build, Test, and Development Commands
|
||||
- `source .zen_venv/bin/activate` – activate the managed Python environment.
|
||||
- `source .pal_venv/bin/activate` – activate the managed Python environment.
|
||||
- `./run-server.sh` – install dependencies, refresh `.env`, and launch the MCP server locally.
|
||||
- `./code_quality_checks.sh` – run Ruff autofix, Black, isort, and the default pytest suite.
|
||||
- `python communication_simulator_test.py --quick` – smoke-test orchestration across tools and providers.
|
||||
@@ -20,14 +20,14 @@ Authoritative documentation and samples live in `docs/`, and runtime diagnostics
|
||||
|
||||
Run code quality checks:
|
||||
```bash
|
||||
.zen_venv/bin/activate && ./code_quality_checks.sh
|
||||
.pal_venv/bin/activate && ./code_quality_checks.sh
|
||||
```
|
||||
|
||||
For example, this is how we run an individual / all tests:
|
||||
|
||||
```bash
|
||||
.zen_venv/bin/activate && pytest tests/test_auto_mode_model_listing.py -q
|
||||
.zen_venv/bin/activate && pytest -q
|
||||
.pal_venv/bin/activate && pytest tests/test_auto_mode_model_listing.py -q
|
||||
.pal_venv/bin/activate && pytest -q
|
||||
```
|
||||
|
||||
## Coding Style & Naming Conventions
|
||||
|
||||
469
CHANGELOG.md
469
CHANGELOG.md
File diff suppressed because it is too large
Load Diff
10
CLAUDE.md
10
CLAUDE.md
@@ -1,6 +1,6 @@
|
||||
# Claude Development Guide for Zen MCP Server
|
||||
# Claude Development Guide for PAL MCP Server
|
||||
|
||||
This file contains essential commands and workflows for developing and maintaining the Zen MCP Server when working with Claude. Use these instructions to efficiently run quality checks, manage the server, check logs, and run tests.
|
||||
This file contains essential commands and workflows for developing and maintaining the PAL MCP Server when working with Claude. Use these instructions to efficiently run quality checks, manage the server, check logs, and run tests.
|
||||
|
||||
## Quick Reference Commands
|
||||
|
||||
@@ -237,7 +237,7 @@ python -m pytest tests/ -v
|
||||
### Development Workflow
|
||||
|
||||
#### Before Making Changes
|
||||
1. Ensure virtual environment is activated: `source .zen_venv/bin/activate`
|
||||
1. Ensure virtual environment is activated: `source .pal_venv/bin/activate`
|
||||
2. Run quality checks: `./code_quality_checks.sh`
|
||||
3. Check logs to ensure server is healthy: `tail -n 50 logs/mcp_server.log`
|
||||
|
||||
@@ -268,7 +268,7 @@ grep "ERROR" logs/mcp_server.log | tail -20
|
||||
|
||||
# Check virtual environment
|
||||
which python
|
||||
# Should show: .../zen-mcp-server/.zen_venv/bin/python
|
||||
# Should show: .../pal-mcp-server/.pal_venv/bin/python
|
||||
```
|
||||
|
||||
#### Test Failures
|
||||
@@ -317,4 +317,4 @@ isort --check-only .
|
||||
- All dependencies from `requirements.txt` installed
|
||||
- Proper API keys configured in `.env` file
|
||||
|
||||
This guide provides everything needed to efficiently work with the Zen MCP Server codebase using Claude. Always run quality checks before and after making changes to ensure code integrity.
|
||||
This guide provides everything needed to efficiently work with the PAL MCP Server codebase using Claude. Always run quality checks before and after making changes to ensure code integrity.
|
||||
22
Dockerfile
22
Dockerfile
@@ -29,18 +29,18 @@ RUN pip install --no-cache-dir --upgrade pip setuptools wheel && \
|
||||
FROM python:3.11-slim AS runtime
|
||||
|
||||
# Add metadata labels for traceability
|
||||
LABEL maintainer="Zen MCP Server Team"
|
||||
LABEL maintainer="PAL MCP Server Team"
|
||||
LABEL version="1.0.0"
|
||||
LABEL description="Zen MCP Server - AI-powered Model Context Protocol server"
|
||||
LABEL org.opencontainers.image.title="zen-mcp-server"
|
||||
LABEL description="PAL MCP Server - AI-powered Model Context Protocol server"
|
||||
LABEL org.opencontainers.image.title="pal-mcp-server"
|
||||
LABEL org.opencontainers.image.description="AI-powered Model Context Protocol server with multi-provider support"
|
||||
LABEL org.opencontainers.image.version="1.0.0"
|
||||
LABEL org.opencontainers.image.source="https://github.com/BeehiveInnovations/zen-mcp-server"
|
||||
LABEL org.opencontainers.image.documentation="https://github.com/BeehiveInnovations/zen-mcp-server/blob/main/README.md"
|
||||
LABEL org.opencontainers.image.source="https://github.com/BeehiveInnovations/pal-mcp-server"
|
||||
LABEL org.opencontainers.image.documentation="https://github.com/BeehiveInnovations/pal-mcp-server/blob/main/README.md"
|
||||
LABEL org.opencontainers.image.licenses="Apache 2.0 License"
|
||||
|
||||
# Create non-root user for security
|
||||
RUN groupadd -r zenuser && useradd -r -g zenuser zenuser
|
||||
RUN groupadd -r paluser && useradd -r -g paluser paluser
|
||||
|
||||
# Install minimal runtime dependencies
|
||||
RUN apt-get update && apt-get install -y \
|
||||
@@ -57,20 +57,20 @@ ENV PATH="/opt/venv/bin:$PATH"
|
||||
WORKDIR /app
|
||||
|
||||
# Copy application code
|
||||
COPY --chown=zenuser:zenuser . .
|
||||
COPY --chown=paluser:paluser . .
|
||||
|
||||
# Create logs directory with proper permissions
|
||||
RUN mkdir -p logs && chown -R zenuser:zenuser logs
|
||||
RUN mkdir -p logs && chown -R paluser:paluser logs
|
||||
|
||||
# Create tmp directory for container operations
|
||||
RUN mkdir -p tmp && chown -R zenuser:zenuser tmp
|
||||
RUN mkdir -p tmp && chown -R paluser:paluser tmp
|
||||
|
||||
# Copy health check script
|
||||
COPY --chown=zenuser:zenuser docker/scripts/healthcheck.py /usr/local/bin/healthcheck.py
|
||||
COPY --chown=paluser:paluser docker/scripts/healthcheck.py /usr/local/bin/healthcheck.py
|
||||
RUN chmod +x /usr/local/bin/healthcheck.py
|
||||
|
||||
# Switch to non-root user
|
||||
USER zenuser
|
||||
USER paluser
|
||||
|
||||
# Health check configuration
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
|
||||
|
||||
55
README.md
55
README.md
@@ -1,8 +1,11 @@
|
||||
# Zen MCP: Many Workflows. One Context.
|
||||
# PAL MCP: Many Workflows. One Context.
|
||||
|
||||
<div align="center">
|
||||
|
||||
[Zen in action](https://github.com/user-attachments/assets/0d26061e-5f21-4ab1-b7d0-f883ddc2c3da)
|
||||
<em>Your AI's PAL – a Provider Abstraction Layer</em><br />
|
||||
<sub><a href="docs/name-change.md">Formerly known as Zen MCP</a></sub>
|
||||
|
||||
[PAL in action](https://github.com/user-attachments/assets/0d26061e-5f21-4ab1-b7d0-f883ddc2c3da)
|
||||
|
||||
👉 **[Watch more examples](#-watch-tools-in-action)**
|
||||
|
||||
@@ -44,24 +47,24 @@ Continue with clink gemini - implement the recommended feature
|
||||
|
||||
---
|
||||
|
||||
## Why Zen MCP?
|
||||
## Why PAL MCP?
|
||||
|
||||
**Why rely on one AI model when you can orchestrate them all?**
|
||||
|
||||
A Model Context Protocol server that supercharges tools like [Claude Code](https://www.anthropic.com/claude-code), [Codex CLI](https://developers.openai.com/codex/cli), and IDE clients such
|
||||
as [Cursor](https://cursor.com) or the [Claude Dev VS Code extension](https://marketplace.visualstudio.com/items?itemName=Anthropic.claude-vscode). **Zen MCP connects your favorite AI tool
|
||||
as [Cursor](https://cursor.com) or the [Claude Dev VS Code extension](https://marketplace.visualstudio.com/items?itemName=Anthropic.claude-vscode). **PAL MCP connects your favorite AI tool
|
||||
to multiple AI models** for enhanced code analysis, problem-solving, and collaborative development.
|
||||
|
||||
### True AI Collaboration with Conversation Continuity
|
||||
|
||||
Zen supports **conversation threading** so your CLI can **discuss ideas with multiple AI models, exchange reasoning, get second opinions, and even run collaborative debates between models** to help you reach deeper insights and better solutions.
|
||||
PAL supports **conversation threading** so your CLI can **discuss ideas with multiple AI models, exchange reasoning, get second opinions, and even run collaborative debates between models** to help you reach deeper insights and better solutions.
|
||||
|
||||
Your CLI always 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.
|
||||
|
||||
> **You're in control.** Your CLI of choice orchestrates the AI team, but you decide the workflow. Craft powerful prompts that bring in Gemini Pro, GPT 5, Flash, or local offline models exactly when needed.
|
||||
|
||||
<details>
|
||||
<summary><b>Reasons to Use Zen MCP</b></summary>
|
||||
<summary><b>Reasons to Use PAL MCP</b></summary>
|
||||
|
||||
A typical workflow with Claude Code as an example:
|
||||
|
||||
@@ -111,7 +114,7 @@ and review into consideration to aid with its final pre-commit review.
|
||||
**Think of it as Claude Code _for_ Claude Code.** This MCP isn't magic. It's just **super-glue**.
|
||||
|
||||
> **Remember:** Claude stays in full control — but **YOU** call the shots.
|
||||
> Zen is designed to have Claude engage other models only when needed — and to follow through with meaningful back-and-forth.
|
||||
> PAL is designed to have Claude engage other models only when needed — and to follow through with meaningful back-and-forth.
|
||||
> **You're** the one who crafts the powerful prompt that makes Claude bring in Gemini, Flash, O3 — or fly solo.
|
||||
> You're the guide. The prompter. The puppeteer.
|
||||
> #### You are the AI - **Actually Intelligent**.
|
||||
@@ -154,8 +157,8 @@ For best results when using [Codex CLI](https://developers.openai.com/codex/cli)
|
||||
|
||||
**Option A: Clone and Automatic Setup** (recommended)
|
||||
```bash
|
||||
git clone https://github.com/BeehiveInnovations/zen-mcp-server.git
|
||||
cd zen-mcp-server
|
||||
git clone https://github.com/BeehiveInnovations/pal-mcp-server.git
|
||||
cd pal-mcp-server
|
||||
|
||||
# Handles everything: setup, config, API keys from system environment.
|
||||
# Auto-configures Claude Desktop, Claude Code, Gemini CLI, Codex CLI, Qwen CLI
|
||||
@@ -169,9 +172,9 @@ cd zen-mcp-server
|
||||
// Don't forget to add your API keys under env
|
||||
{
|
||||
"mcpServers": {
|
||||
"zen": {
|
||||
"pal": {
|
||||
"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"],
|
||||
"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/pal-mcp-server.git pal-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",
|
||||
@@ -185,9 +188,9 @@ cd zen-mcp-server
|
||||
|
||||
**3. Start Using!**
|
||||
```
|
||||
"Use zen to analyze this code for security issues with gemini pro"
|
||||
"Use pal to analyze this code for security issues with gemini pro"
|
||||
"Debug this error with o3 and then get flash to suggest optimizations"
|
||||
"Plan the migration strategy with zen, get consensus from multiple models"
|
||||
"Plan the migration strategy with pal, get consensus from multiple models"
|
||||
"clink with cli_name=\"gemini\" role=\"planner\" to draft a phased rollout plan"
|
||||
```
|
||||
|
||||
@@ -197,7 +200,7 @@ cd zen-mcp-server
|
||||
|
||||
## Provider Configuration
|
||||
|
||||
Zen activates any provider that has credentials in your `.env`. See `.env.example` for deeper customization.
|
||||
PAL activates any provider that has credentials in your `.env`. See `.env.example` for deeper customization.
|
||||
|
||||
## Core Tools
|
||||
|
||||
@@ -265,7 +268,7 @@ DISABLED_TOOLS=
|
||||
// In ~/.claude/settings.json or .mcp.json
|
||||
{
|
||||
"mcpServers": {
|
||||
"zen": {
|
||||
"pal": {
|
||||
"env": {
|
||||
// Tool configuration
|
||||
"DISABLED_TOOLS": "refactor,testgen,secaudit,docgen,tracer",
|
||||
@@ -292,7 +295,7 @@ DISABLED_TOOLS=
|
||||
// Remove or empty the DISABLED_TOOLS to enable everything
|
||||
{
|
||||
"mcpServers": {
|
||||
"zen": {
|
||||
"pal": {
|
||||
"env": {
|
||||
"DISABLED_TOOLS": ""
|
||||
}
|
||||
@@ -328,7 +331,7 @@ DISABLED_TOOLS=
|
||||
|
||||
**Multi-model consensus debate:**
|
||||
|
||||
[Zen Consensus Debate](https://github.com/user-attachments/assets/76a23dd5-887a-4382-9cf0-642f5cf6219e)
|
||||
[PAL Consensus Debate](https://github.com/user-attachments/assets/76a23dd5-887a-4382-9cf0-642f5cf6219e)
|
||||
|
||||
</details>
|
||||
|
||||
@@ -346,26 +349,26 @@ DISABLED_TOOLS=
|
||||
<details>
|
||||
<summary><b>API Lookup Tool</b> - Current vs outdated API documentation</summary>
|
||||
|
||||
**Without Zen - outdated APIs:**
|
||||
**Without PAL - outdated APIs:**
|
||||
|
||||
[API without Zen](https://github.com/user-attachments/assets/01a79dc9-ad16-4264-9ce1-76a56c3580ee)
|
||||
[API without PAL](https://github.com/user-attachments/assets/01a79dc9-ad16-4264-9ce1-76a56c3580ee)
|
||||
|
||||
**With Zen - current APIs:**
|
||||
**With PAL - current APIs:**
|
||||
|
||||
[API with Zen](https://github.com/user-attachments/assets/5c847326-4b66-41f7-8f30-f380453dce22)
|
||||
[API with PAL](https://github.com/user-attachments/assets/5c847326-4b66-41f7-8f30-f380453dce22)
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>Challenge Tool</b> - Critical thinking vs reflexive agreement</summary>
|
||||
|
||||
**Without Zen:**
|
||||
**Without PAL:**
|
||||
|
||||

|
||||

|
||||
|
||||
**With Zen:**
|
||||
**With PAL:**
|
||||
|
||||

|
||||

|
||||
|
||||
</details>
|
||||
|
||||
@@ -444,4 +447,4 @@ Built with the power of **Multi-Model AI** collaboration 🤝
|
||||
|
||||
### Star History
|
||||
|
||||
[](https://www.star-history.com/#BeehiveInnovations/zen-mcp-server&Date)
|
||||
[](https://www.star-history.com/#BeehiveInnovations/pal-mcp-server&Date)
|
||||
|
||||
81
SECURITY.md
Normal file
81
SECURITY.md
Normal file
@@ -0,0 +1,81 @@
|
||||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
| Version | Supported |
|
||||
| ------- | ------------------ |
|
||||
| 9.x.x | :white_check_mark: |
|
||||
| < 9.0 | :x: |
|
||||
|
||||
## Important Disclaimer
|
||||
|
||||
PAL MCP is an open-source Model Context Protocol (MCP) server that acts as middleware between AI clients (Claude Code, Codex CLI, Cursor, etc.) and various AI model providers.
|
||||
|
||||
**Please understand the following:**
|
||||
|
||||
- **No Warranty**: This software is provided "AS IS" under the Apache 2.0 License, without warranties of any kind. See the [LICENSE](LICENSE) file for full terms.
|
||||
- **User Responsibility**: The AI client (not PAL MCP) controls tool invocations and workflows. Users are responsible for reviewing AI-generated outputs and actions.
|
||||
- **API Key Security**: You are responsible for securing your own API keys. Never commit keys to version control or share them publicly.
|
||||
- **Third-Party Services**: PAL MCP connects to external AI providers (Google, OpenAI, Azure, etc.). Their terms of service and privacy policies apply to data sent through this server.
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
**Please do not report security vulnerabilities through public GitHub issues.**
|
||||
|
||||
### Preferred Method
|
||||
|
||||
Use [GitHub Security Advisories](https://github.com/BeehiveInnovations/pal-mcp-server/security/advisories/new) to report vulnerabilities privately.
|
||||
|
||||
### What to Include
|
||||
|
||||
- Description of the vulnerability
|
||||
- Steps to reproduce
|
||||
- Affected versions
|
||||
- Potential impact
|
||||
- Suggested fix (optional)
|
||||
|
||||
### What to Expect
|
||||
|
||||
- We will acknowledge your report and assess the issue
|
||||
- Critical issues will be prioritized
|
||||
- We'll keep you informed of progress as work proceeds
|
||||
|
||||
We cannot commit to specific response timelines, but we take security seriously.
|
||||
|
||||
### After Resolution
|
||||
|
||||
We welcome security researchers to submit a pull request with the fix. This is an open-source project and we appreciate community contributions to improve security.
|
||||
|
||||
## Disclosure Policy
|
||||
|
||||
We practice coordinated disclosure. Please allow reasonable time to address issues before public disclosure. We'll work with you on timing.
|
||||
|
||||
## Scope
|
||||
|
||||
### In Scope
|
||||
|
||||
- Authentication/authorization bypasses
|
||||
- Injection vulnerabilities (command injection, prompt injection with security impact)
|
||||
- Information disclosure (API keys, sensitive data leakage)
|
||||
- Denial of service vulnerabilities in the MCP server itself
|
||||
- Dependency vulnerabilities with exploitable impact
|
||||
|
||||
### Out of Scope
|
||||
|
||||
- Issues in upstream AI providers (report to Google, OpenAI, etc. directly)
|
||||
- Issues in AI client software (report to Anthropic, OpenAI, Cursor, etc.)
|
||||
- AI model behavior or outputs (this is controlled by the AI client and model providers)
|
||||
- Social engineering attacks
|
||||
- Rate limiting or resource exhaustion on third-party APIs
|
||||
|
||||
## Security Best Practices for Users
|
||||
|
||||
1. **Protect API Keys**: Store keys in `.env` files (gitignored) or environment variables
|
||||
2. **Review AI Actions**: Always review AI-suggested code changes before applying
|
||||
3. **Use Local Models**: For sensitive codebases, consider using Ollama with local models
|
||||
4. **Network Security**: When self-hosting, ensure appropriate network controls
|
||||
5. **Keep Updated**: Regularly update to the latest version for security fixes
|
||||
|
||||
## Recognition
|
||||
|
||||
We appreciate responsible disclosure and will credit security researchers in release notes (unless you prefer anonymity).
|
||||
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"comment": "Example Claude Desktop configuration for Zen MCP Server",
|
||||
"comment": "Example Claude Desktop configuration for PAL MCP Server",
|
||||
"comment2": "Run './run-server.sh -c' to get the exact configuration for your system",
|
||||
"comment3": "For platform-specific examples, see the examples/ directory",
|
||||
"mcpServers": {
|
||||
"zen": {
|
||||
"command": "/path/to/zen-mcp-server/.zen_venv/bin/python",
|
||||
"args": ["/path/to/zen-mcp-server/server.py"]
|
||||
"pal": {
|
||||
"command": "/path/to/pal-mcp-server/.pal_venv/bin/python",
|
||||
"args": ["/path/to/pal-mcp-server/server.py"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ DEFAULT_STREAM_LIMIT = 10 * 1024 * 1024 # 10MB per stream
|
||||
PROJECT_ROOT = Path(__file__).resolve().parent.parent
|
||||
BUILTIN_PROMPTS_DIR = PROJECT_ROOT / "systemprompts" / "clink"
|
||||
CONFIG_DIR = PROJECT_ROOT / "conf" / "cli_clients"
|
||||
USER_CONFIG_DIR = Path.home() / ".zen" / "cli_clients"
|
||||
USER_CONFIG_DIR = Path.home() / ".pal" / "cli_clients"
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
|
||||
@@ -102,7 +102,7 @@ class ClinkRegistry:
|
||||
env_path = Path(env_path_raw).expanduser()
|
||||
search_paths.append(env_path)
|
||||
|
||||
# 3. User overrides in ~/.zen/cli_clients
|
||||
# 3. User overrides in ~/.pal/cli_clients
|
||||
search_paths.append(USER_CONFIG_DIR)
|
||||
|
||||
seen: set[Path] = set()
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Code quality checks script for Zen MCP server on Windows.
|
||||
Code quality checks script for PAL MCP server on Windows.
|
||||
|
||||
.DESCRIPTION
|
||||
This PowerShell script performs code quality checks for the Zen MCP server project:
|
||||
This PowerShell script performs code quality checks for the PAL MCP server project:
|
||||
- Runs static analysis and linting tools on the codebase
|
||||
- Ensures code style compliance and detects potential issues
|
||||
- Can be integrated into CI/CD pipelines or used locally before commits
|
||||
@@ -26,7 +26,7 @@
|
||||
Script Author : GiGiDKR (https://github.com/GiGiDKR)
|
||||
Date : 07-05-2025
|
||||
Version : See project documentation
|
||||
References : https://github.com/BeehiveInnovations/zen-mcp-server
|
||||
References : https://github.com/BeehiveInnovations/pal-mcp-server
|
||||
#>
|
||||
#Requires -Version 5.1
|
||||
[CmdletBinding()]
|
||||
@@ -61,23 +61,23 @@ function Write-Emoji {
|
||||
Write-ColorText $Text -Color $Color
|
||||
}
|
||||
|
||||
Write-Emoji "🔍" "Running Code Quality Checks for Zen MCP Server" -Color Cyan
|
||||
Write-Emoji "🔍" "Running Code Quality Checks for PAL MCP Server" -Color Cyan
|
||||
Write-ColorText "=================================================" -Color Cyan
|
||||
|
||||
# Determine Python command
|
||||
$pythonCmd = $null
|
||||
$pipCmd = $null
|
||||
|
||||
if (Test-Path ".zen_venv") {
|
||||
if (Test-Path ".pal_venv") {
|
||||
if ($IsWindows -or $env:OS -eq "Windows_NT") {
|
||||
if (Test-Path ".zen_venv\Scripts\python.exe") {
|
||||
$pythonCmd = ".zen_venv\Scripts\python.exe"
|
||||
$pipCmd = ".zen_venv\Scripts\pip.exe"
|
||||
if (Test-Path ".pal_venv\Scripts\python.exe") {
|
||||
$pythonCmd = ".pal_venv\Scripts\python.exe"
|
||||
$pipCmd = ".pal_venv\Scripts\pip.exe"
|
||||
}
|
||||
} else {
|
||||
if (Test-Path ".zen_venv/bin/python") {
|
||||
$pythonCmd = ".zen_venv/bin/python"
|
||||
$pipCmd = ".zen_venv/bin/pip"
|
||||
if (Test-Path ".pal_venv/bin/python") {
|
||||
$pythonCmd = ".pal_venv/bin/python"
|
||||
$pipCmd = ".pal_venv/bin/pip"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,11 +108,11 @@ foreach ($tool in $devTools) {
|
||||
|
||||
# Check in venv
|
||||
if ($IsWindows -or $env:OS -eq "Windows_NT") {
|
||||
if (Test-Path ".zen_venv\Scripts\$tool.exe") {
|
||||
if (Test-Path ".pal_venv\Scripts\$tool.exe") {
|
||||
$toolFound = $true
|
||||
}
|
||||
} else {
|
||||
if (Test-Path ".zen_venv/bin/$tool") {
|
||||
if (Test-Path ".pal_venv/bin/$tool") {
|
||||
$toolFound = $true
|
||||
}
|
||||
}
|
||||
@@ -152,15 +152,15 @@ if ($devDepsNeeded) {
|
||||
|
||||
# Set tool paths
|
||||
if ($IsWindows -or $env:OS -eq "Windows_NT") {
|
||||
$ruffCmd = if (Test-Path ".zen_venv\Scripts\ruff.exe") { ".zen_venv\Scripts\ruff.exe" } else { "ruff" }
|
||||
$blackCmd = if (Test-Path ".zen_venv\Scripts\black.exe") { ".zen_venv\Scripts\black.exe" } else { "black" }
|
||||
$isortCmd = if (Test-Path ".zen_venv\Scripts\isort.exe") { ".zen_venv\Scripts\isort.exe" } else { "isort" }
|
||||
$pytestCmd = if (Test-Path ".zen_venv\Scripts\pytest.exe") { ".zen_venv\Scripts\pytest.exe" } else { "pytest" }
|
||||
$ruffCmd = if (Test-Path ".pal_venv\Scripts\ruff.exe") { ".pal_venv\Scripts\ruff.exe" } else { "ruff" }
|
||||
$blackCmd = if (Test-Path ".pal_venv\Scripts\black.exe") { ".pal_venv\Scripts\black.exe" } else { "black" }
|
||||
$isortCmd = if (Test-Path ".pal_venv\Scripts\isort.exe") { ".pal_venv\Scripts\isort.exe" } else { "isort" }
|
||||
$pytestCmd = if (Test-Path ".pal_venv\Scripts\pytest.exe") { ".pal_venv\Scripts\pytest.exe" } else { "pytest" }
|
||||
} else {
|
||||
$ruffCmd = if (Test-Path ".zen_venv/bin/ruff") { ".zen_venv/bin/ruff" } else { "ruff" }
|
||||
$blackCmd = if (Test-Path ".zen_venv/bin/black") { ".zen_venv/bin/black" } else { "black" }
|
||||
$isortCmd = if (Test-Path ".zen_venv/bin/isort") { ".zen_venv/bin/isort" } else { "isort" }
|
||||
$pytestCmd = if (Test-Path ".zen_venv/bin/pytest") { ".zen_venv/bin/pytest" } else { "pytest" }
|
||||
$ruffCmd = if (Test-Path ".pal_venv/bin/ruff") { ".pal_venv/bin/ruff" } else { "ruff" }
|
||||
$blackCmd = if (Test-Path ".pal_venv/bin/black") { ".pal_venv/bin/black" } else { "black" }
|
||||
$isortCmd = if (Test-Path ".pal_venv/bin/isort") { ".pal_venv/bin/isort" } else { "isort" }
|
||||
$pytestCmd = if (Test-Path ".pal_venv/bin/pytest") { ".pal_venv/bin/pytest" } else { "pytest" }
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
@@ -172,25 +172,25 @@ if (!$SkipLinting) {
|
||||
|
||||
try {
|
||||
Write-Emoji "🔧" "Running ruff linting with auto-fix..." -Color Yellow
|
||||
& $ruffCmd check --fix --exclude test_simulation_files --exclude .zen_venv
|
||||
& $ruffCmd check --fix --exclude test_simulation_files --exclude .pal_venv
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "Ruff linting failed"
|
||||
}
|
||||
|
||||
Write-Emoji "🎨" "Running black code formatting..." -Color Yellow
|
||||
& $blackCmd . --exclude="test_simulation_files/" --exclude=".zen_venv/"
|
||||
& $blackCmd . --exclude="test_simulation_files/" --exclude=".pal_venv/"
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "Black formatting failed"
|
||||
}
|
||||
|
||||
Write-Emoji "📦" "Running import sorting with isort..." -Color Yellow
|
||||
& $isortCmd . --skip-glob=".zen_venv/*" --skip-glob="test_simulation_files/*"
|
||||
& $isortCmd . --skip-glob=".pal_venv/*" --skip-glob="test_simulation_files/*"
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "Import sorting failed"
|
||||
}
|
||||
|
||||
Write-Emoji "✅" "Verifying all linting passes..." -Color Yellow
|
||||
& $ruffCmd check --exclude test_simulation_files --exclude .zen_venv
|
||||
& $ruffCmd check --exclude test_simulation_files --exclude .pal_venv
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "Final linting verification failed"
|
||||
}
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Zen MCP Server - Code Quality Checks
|
||||
# PAL MCP Server - Code Quality Checks
|
||||
# This script runs all required linting and testing checks before committing changes.
|
||||
# ALL checks must pass 100% for CI/CD to succeed.
|
||||
|
||||
set -e # Exit on any error
|
||||
|
||||
echo "🔍 Running Code Quality Checks for Zen MCP Server"
|
||||
echo "🔍 Running Code Quality Checks for PAL MCP Server"
|
||||
echo "================================================="
|
||||
|
||||
# Determine Python command
|
||||
if [[ -f ".zen_venv/bin/python" ]]; then
|
||||
PYTHON_CMD=".zen_venv/bin/python"
|
||||
PIP_CMD=".zen_venv/bin/pip"
|
||||
if [[ -f ".pal_venv/bin/python" ]]; then
|
||||
PYTHON_CMD=".pal_venv/bin/python"
|
||||
PIP_CMD=".pal_venv/bin/pip"
|
||||
echo "✅ Using venv"
|
||||
elif [[ -n "$VIRTUAL_ENV" ]]; then
|
||||
PYTHON_CMD="python"
|
||||
@@ -32,7 +32,7 @@ DEV_DEPS_NEEDED=false
|
||||
# Check each dev dependency
|
||||
for tool in ruff black isort pytest; do
|
||||
# Check if tool exists in venv or in PATH
|
||||
if [[ -f ".zen_venv/bin/$tool" ]] || command -v $tool &> /dev/null; then
|
||||
if [[ -f ".pal_venv/bin/$tool" ]] || command -v $tool &> /dev/null; then
|
||||
continue
|
||||
else
|
||||
DEV_DEPS_NEEDED=true
|
||||
@@ -49,11 +49,11 @@ else
|
||||
fi
|
||||
|
||||
# Set tool paths
|
||||
if [[ -f ".zen_venv/bin/ruff" ]]; then
|
||||
RUFF=".zen_venv/bin/ruff"
|
||||
BLACK=".zen_venv/bin/black"
|
||||
ISORT=".zen_venv/bin/isort"
|
||||
PYTEST=".zen_venv/bin/pytest"
|
||||
if [[ -f ".pal_venv/bin/ruff" ]]; then
|
||||
RUFF=".pal_venv/bin/ruff"
|
||||
BLACK=".pal_venv/bin/black"
|
||||
ISORT=".pal_venv/bin/isort"
|
||||
PYTEST=".pal_venv/bin/pytest"
|
||||
else
|
||||
RUFF="ruff"
|
||||
BLACK="black"
|
||||
@@ -67,16 +67,16 @@ echo "📋 Step 1: Running Linting and Formatting Checks"
|
||||
echo "--------------------------------------------------"
|
||||
|
||||
echo "🔧 Running ruff linting with auto-fix..."
|
||||
$RUFF check --fix --exclude test_simulation_files --exclude .zen_venv
|
||||
$RUFF check --fix --exclude test_simulation_files --exclude .pal_venv
|
||||
|
||||
echo "🎨 Running black code formatting..."
|
||||
$BLACK . --exclude="test_simulation_files/" --exclude=".zen_venv/"
|
||||
$BLACK . --exclude="test_simulation_files/" --exclude=".pal_venv/"
|
||||
|
||||
echo "📦 Running import sorting with isort..."
|
||||
$ISORT . --skip-glob=".zen_venv/*" --skip-glob="test_simulation_files/*"
|
||||
$ISORT . --skip-glob=".pal_venv/*" --skip-glob="test_simulation_files/*"
|
||||
|
||||
echo "✅ Verifying all linting passes..."
|
||||
$RUFF check --exclude test_simulation_files --exclude .zen_venv
|
||||
$RUFF check --exclude test_simulation_files --exclude .pal_venv
|
||||
|
||||
echo "✅ Step 1 Complete: All linting and formatting checks passed!"
|
||||
echo ""
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"""
|
||||
Communication Simulator Test for Zen MCP Server
|
||||
Communication Simulator Test for PAL MCP Server
|
||||
|
||||
This script provides comprehensive end-to-end testing of the Zen MCP server
|
||||
This script provides comprehensive end-to-end testing of the PAL MCP Server
|
||||
by simulating real Claude CLI communications and validating conversation
|
||||
continuity, file handling, deduplication features, and clarification scenarios.
|
||||
|
||||
@@ -145,10 +145,10 @@ class CommunicationSimulator:
|
||||
if os.path.exists(venv_python):
|
||||
return venv_python
|
||||
|
||||
# Try .zen_venv as fallback
|
||||
zen_venv_python = os.path.join(current_dir, ".zen_venv", "bin", "python")
|
||||
if os.path.exists(zen_venv_python):
|
||||
return zen_venv_python
|
||||
# Try .pal_venv as fallback
|
||||
pal_venv_python = os.path.join(current_dir, ".pal_venv", "bin", "python")
|
||||
if os.path.exists(pal_venv_python):
|
||||
return pal_venv_python
|
||||
|
||||
# Fallback to system python if venv doesn't exist
|
||||
self.logger.warning("Virtual environment not found, using system python")
|
||||
@@ -361,7 +361,7 @@ class CommunicationSimulator:
|
||||
def print_test_summary(self):
|
||||
"""Print comprehensive test results summary"""
|
||||
self.logger.info("\n" + "=" * 70)
|
||||
self.logger.info("ZEN MCP COMMUNICATION SIMULATOR - TEST RESULTS SUMMARY")
|
||||
self.logger.info("PAL MCP COMMUNICATION SIMULATOR - TEST RESULTS SUMMARY")
|
||||
self.logger.info("=" * 70)
|
||||
|
||||
passed_count = sum(1 for result in self.test_results.values() if result)
|
||||
@@ -388,7 +388,7 @@ class CommunicationSimulator:
|
||||
def run_full_test_suite(self) -> bool:
|
||||
"""Run the complete test suite"""
|
||||
try:
|
||||
self.logger.info("Starting Zen MCP Communication Simulator Test Suite")
|
||||
self.logger.info("Starting PAL MCP Communication Simulator Test Suite")
|
||||
|
||||
# Setup
|
||||
if not self.setup_test_environment():
|
||||
@@ -450,7 +450,7 @@ class CommunicationSimulator:
|
||||
|
||||
def parse_arguments():
|
||||
"""Parse and validate command line arguments"""
|
||||
parser = argparse.ArgumentParser(description="Zen MCP Communication Simulator Test")
|
||||
parser = argparse.ArgumentParser(description="PAL MCP Communication Simulator Test")
|
||||
parser.add_argument("--verbose", "-v", action="store_true", help="Enable verbose logging")
|
||||
parser.add_argument("--keep-logs", action="store_true", help="Keep logs for inspection after test completion")
|
||||
parser.add_argument("--tests", "-t", nargs="+", help="Specific tests to run (space-separated)")
|
||||
|
||||
@@ -1 +1 @@
|
||||
"""Configuration data for Zen MCP Server."""
|
||||
"""Configuration data for PAL MCP Server."""
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"_README": {
|
||||
"description": "Model metadata for Azure OpenAI / Azure AI Foundry-backed provider. The `models` definition can be copied from openrouter_models.json / custom_models.json",
|
||||
"documentation": "https://github.com/BeehiveInnovations/zen-mcp-server/blob/main/docs/azure_models.md",
|
||||
"documentation": "https://github.com/BeehiveInnovations/pal-mcp-server/blob/main/docs/azure_models.md",
|
||||
"usage": "Models listed here are exposed through Azure AI Foundry. Aliases are case-insensitive.",
|
||||
"field_notes": "Matches providers/shared/model_capabilities.py.",
|
||||
"field_descriptions": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"_README": {
|
||||
"description": "Model metadata for local/self-hosted OpenAI-compatible endpoints (Custom provider).",
|
||||
"documentation": "https://github.com/BeehiveInnovations/zen-mcp-server/blob/main/docs/custom_models.md",
|
||||
"documentation": "https://github.com/BeehiveInnovations/pal-mcp-server/blob/main/docs/custom_models.md",
|
||||
"usage": "Each entry will be advertised by the Custom provider. Aliases are case-insensitive.",
|
||||
"field_notes": "Matches providers/shared/model_capabilities.py.",
|
||||
"field_descriptions": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"_README": {
|
||||
"description": "Model metadata for the DIAL (Data & AI Layer) aggregation provider.",
|
||||
"documentation": "https://github.com/BeehiveInnovations/zen-mcp-server/blob/main/docs/configuration.md",
|
||||
"documentation": "https://github.com/BeehiveInnovations/pal-mcp-server/blob/main/docs/configuration.md",
|
||||
"usage": "Models listed here are exposed through the DIAL provider. Aliases are case-insensitive.",
|
||||
"field_notes": "Matches providers/shared/model_capabilities.py.",
|
||||
"field_descriptions": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"_README": {
|
||||
"description": "Model metadata for Google's Gemini API access.",
|
||||
"documentation": "https://github.com/BeehiveInnovations/zen-mcp-server/blob/main/docs/custom_models.md",
|
||||
"documentation": "https://github.com/BeehiveInnovations/pal-mcp-server/blob/main/docs/custom_models.md",
|
||||
"usage": "Models listed here are exposed directly through the Gemini provider. Aliases are case-insensitive.",
|
||||
"field_notes": "Matches providers/shared/model_capabilities.py.",
|
||||
"field_descriptions": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"_README": {
|
||||
"description": "Model metadata for native OpenAI API access.",
|
||||
"documentation": "https://github.com/BeehiveInnovations/zen-mcp-server/blob/main/docs/custom_models.md",
|
||||
"documentation": "https://github.com/BeehiveInnovations/pal-mcp-server/blob/main/docs/custom_models.md",
|
||||
"usage": "Models listed here are exposed directly through the OpenAI provider. Aliases are case-insensitive.",
|
||||
"field_notes": "Matches providers/shared/model_capabilities.py.",
|
||||
"field_descriptions": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"_README": {
|
||||
"description": "Model metadata for OpenRouter-backed providers.",
|
||||
"documentation": "https://github.com/BeehiveInnovations/zen-mcp-server/blob/main/docs/custom_models.md",
|
||||
"documentation": "https://github.com/BeehiveInnovations/pal-mcp-server/blob/main/docs/custom_models.md",
|
||||
"usage": "Models listed here are exposed through OpenRouter. Aliases are case-insensitive.",
|
||||
"field_notes": "Matches providers/shared/model_capabilities.py.",
|
||||
"field_descriptions": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"_README": {
|
||||
"description": "Model metadata for X.AI (GROK) API access.",
|
||||
"documentation": "https://github.com/BeehiveInnovations/zen-mcp-server/blob/main/docs/custom_models.md",
|
||||
"documentation": "https://github.com/BeehiveInnovations/pal-mcp-server/blob/main/docs/custom_models.md",
|
||||
"usage": "Models listed here are exposed directly through the X.AI provider. Aliases are case-insensitive.",
|
||||
"field_notes": "Matches providers/shared/model_capabilities.py.",
|
||||
"field_descriptions": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"""
|
||||
Configuration and constants for Zen MCP Server
|
||||
Configuration and constants for PAL MCP Server
|
||||
|
||||
This module centralizes all configuration settings for the Zen MCP Server.
|
||||
This module centralizes all configuration settings for the PAL MCP Server.
|
||||
It defines model configurations, token limits, temperature defaults, and other
|
||||
constants used throughout the application.
|
||||
|
||||
@@ -14,9 +14,9 @@ from utils.env import get_env
|
||||
# These values are used in server responses and for tracking releases
|
||||
# IMPORTANT: This is the single source of truth for version and author info
|
||||
# Semantic versioning: MAJOR.MINOR.PATCH
|
||||
__version__ = "9.4.1"
|
||||
__version__ = "9.4.2"
|
||||
# Last update date in ISO format
|
||||
__updated__ = "2025-11-21"
|
||||
__updated__ = "2025-12-05"
|
||||
# Primary maintainer
|
||||
__author__ = "Fahad Gilani"
|
||||
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
services:
|
||||
zen-mcp:
|
||||
pal-mcp:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
target: runtime
|
||||
image: zen-mcp-server:latest
|
||||
container_name: zen-mcp-server
|
||||
image: pal-mcp-server:latest
|
||||
container_name: pal-mcp-server
|
||||
|
||||
# Container labels for traceability
|
||||
labels:
|
||||
- "com.zen-mcp.service=zen-mcp-server"
|
||||
- "com.zen-mcp.version=1.0.0"
|
||||
- "com.zen-mcp.environment=production"
|
||||
- "com.zen-mcp.description=AI-powered Model Context Protocol server"
|
||||
- "com.pal-mcp.service=pal-mcp-server"
|
||||
- "com.pal-mcp.version=1.0.0"
|
||||
- "com.pal-mcp.environment=production"
|
||||
- "com.pal-mcp.description=AI-powered Model Context Protocol server"
|
||||
|
||||
# Environment variables
|
||||
environment:
|
||||
@@ -51,12 +51,12 @@ services:
|
||||
# Volumes for persistent data
|
||||
volumes:
|
||||
- ./logs:/app/logs
|
||||
- zen-mcp-config:/app/conf
|
||||
- pal-mcp-config:/app/conf
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
|
||||
# Network configuration
|
||||
networks:
|
||||
- zen-network
|
||||
- pal-network
|
||||
|
||||
# Resource limits
|
||||
deploy:
|
||||
@@ -89,12 +89,12 @@ services:
|
||||
|
||||
# Named volumes
|
||||
volumes:
|
||||
zen-mcp-config:
|
||||
pal-mcp-config:
|
||||
driver: local
|
||||
|
||||
# Networks
|
||||
networks:
|
||||
zen-network:
|
||||
pal-network:
|
||||
driver: bridge
|
||||
ipam:
|
||||
config:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Zen MCP Server - Docker Setup
|
||||
# PAL MCP Server - Docker Setup
|
||||
|
||||
## Quick Start
|
||||
|
||||
@@ -22,7 +22,7 @@ nano .env
|
||||
|
||||
```bash
|
||||
# Build the Docker image
|
||||
docker build -t zen-mcp-server:latest .
|
||||
docker build -t pal-mcp-server:latest .
|
||||
|
||||
# Or use the build script (Bash)
|
||||
chmod +x docker/scripts/build.sh
|
||||
@@ -41,14 +41,14 @@ docker/scripts/build.ps1
|
||||
# Run with environment file
|
||||
docker run --rm -i --env-file .env \
|
||||
-v $(pwd)/logs:/app/logs \
|
||||
zen-mcp-server:latest
|
||||
pal-mcp-server:latest
|
||||
|
||||
# Run with inline environment variables
|
||||
docker run --rm -i \
|
||||
-e GEMINI_API_KEY="your_key_here" \
|
||||
-e LOG_LEVEL=INFO \
|
||||
-v $(pwd)/logs:/app/logs \
|
||||
zen-mcp-server:latest
|
||||
pal-mcp-server:latest
|
||||
```
|
||||
|
||||
#### B. Docker Compose (For Development/Monitoring)
|
||||
@@ -62,7 +62,7 @@ chmod +x docker/scripts/deploy.sh
|
||||
docker/scripts/deploy.ps1
|
||||
|
||||
# Interactive stdio mode
|
||||
docker-compose exec zen-mcp python server.py
|
||||
docker-compose exec pal-mcp python server.py
|
||||
```
|
||||
|
||||
## Service Management
|
||||
@@ -76,8 +76,8 @@ docker ps
|
||||
# View logs from container
|
||||
docker logs <container_id>
|
||||
|
||||
# Stop all zen-mcp containers
|
||||
docker stop $(docker ps -q --filter "ancestor=zen-mcp-server:latest")
|
||||
# Stop all pal-mcp containers
|
||||
docker stop $(docker ps -q --filter "ancestor=pal-mcp-server:latest")
|
||||
|
||||
# Remove old containers and images
|
||||
docker container prune
|
||||
@@ -88,20 +88,20 @@ docker image prune
|
||||
|
||||
```bash
|
||||
# View logs
|
||||
docker-compose logs -f zen-mcp
|
||||
docker-compose logs -f pal-mcp
|
||||
|
||||
# Check status
|
||||
docker-compose ps
|
||||
|
||||
# Restart service
|
||||
docker-compose restart zen-mcp
|
||||
docker-compose restart pal-mcp
|
||||
|
||||
# Stop services
|
||||
docker-compose down
|
||||
|
||||
# Rebuild and update
|
||||
docker-compose build --no-cache zen-mcp
|
||||
docker-compose up -d zen-mcp
|
||||
docker-compose build --no-cache pal-mcp
|
||||
docker-compose up -d pal-mcp
|
||||
```
|
||||
|
||||
## Health Monitoring
|
||||
@@ -117,19 +117,19 @@ The container includes health checks that verify:
|
||||
The Docker setup includes persistent volumes to preserve data between container runs:
|
||||
|
||||
- **`./logs:/app/logs`** - Persistent log storage (local folder mount)
|
||||
- **`zen-mcp-config:/app/conf`** - Configuration persistence (named Docker volume)
|
||||
- **`pal-mcp-config:/app/conf`** - Configuration persistence (named Docker volume)
|
||||
- **`/etc/localtime:/etc/localtime:ro`** - Host timezone synchronization (read-only)
|
||||
|
||||
### How Persistent Volumes Work
|
||||
|
||||
The `zen-mcp` service (used by `zen-docker-compose` and Docker Compose commands) mounts the named volume `zen-mcp-config` persistently. All data placed in `/app/conf` inside the container is preserved between runs thanks to this Docker volume.
|
||||
The `pal-mcp` service (used by `pal-docker-compose` and Docker Compose commands) mounts the named volume `pal-mcp-config` persistently. All data placed in `/app/conf` inside the container is preserved between runs thanks to this Docker volume.
|
||||
|
||||
In the `docker-compose.yml` file, you will find:
|
||||
|
||||
```yaml
|
||||
volumes:
|
||||
- ./logs:/app/logs
|
||||
- zen-mcp-config:/app/conf
|
||||
- pal-mcp-config:/app/conf
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
```
|
||||
|
||||
@@ -137,13 +137,13 @@ and the named volume definition:
|
||||
|
||||
```yaml
|
||||
volumes:
|
||||
zen-mcp-config:
|
||||
pal-mcp-config:
|
||||
driver: local
|
||||
```
|
||||
|
||||
## Security
|
||||
|
||||
- Runs as non-root user `zenuser`
|
||||
- Runs as non-root user `paluser`
|
||||
- Read-only filesystem with tmpfs for temporary files
|
||||
- No network ports exposed (stdio communication only)
|
||||
- Secrets managed via environment variables
|
||||
@@ -154,16 +154,16 @@ volumes:
|
||||
|
||||
```bash
|
||||
# Check if image exists
|
||||
docker images zen-mcp-server
|
||||
docker images pal-mcp-server
|
||||
|
||||
# Test container interactively
|
||||
docker run --rm -it --env-file .env zen-mcp-server:latest bash
|
||||
docker run --rm -it --env-file .env pal-mcp-server:latest bash
|
||||
|
||||
# Check environment variables
|
||||
docker run --rm --env-file .env zen-mcp-server:latest env | grep API
|
||||
docker run --rm --env-file .env pal-mcp-server:latest env | grep API
|
||||
|
||||
# Test with minimal configuration
|
||||
docker run --rm -i -e GEMINI_API_KEY="test" zen-mcp-server:latest python server.py
|
||||
docker run --rm -i -e GEMINI_API_KEY="test" pal-mcp-server:latest python server.py
|
||||
```
|
||||
|
||||
### MCP Connection Issues
|
||||
@@ -173,7 +173,7 @@ docker run --rm -i -e GEMINI_API_KEY="test" zen-mcp-server:latest python server.
|
||||
docker run --rm hello-world
|
||||
|
||||
# Verify container stdio
|
||||
echo '{"jsonrpc": "2.0", "method": "ping"}' | docker run --rm -i --env-file .env zen-mcp-server:latest python server.py
|
||||
echo '{"jsonrpc": "2.0", "method": "ping"}' | docker run --rm -i --env-file .env pal-mcp-server:latest python server.py
|
||||
|
||||
# Check Claude Desktop logs for connection errors
|
||||
```
|
||||
@@ -182,10 +182,10 @@ echo '{"jsonrpc": "2.0", "method": "ping"}' | docker run --rm -i --env-file .env
|
||||
|
||||
```bash
|
||||
# Verify API keys are loaded
|
||||
docker run --rm --env-file .env zen-mcp-server:latest python -c "import os; print('GEMINI_API_KEY:', bool(os.getenv('GEMINI_API_KEY')))"
|
||||
docker run --rm --env-file .env pal-mcp-server:latest python -c "import os; print('GEMINI_API_KEY:', bool(os.getenv('GEMINI_API_KEY')))"
|
||||
|
||||
# Test API connectivity
|
||||
docker run --rm --env-file .env zen-mcp-server:latest python /usr/local/bin/healthcheck.py
|
||||
docker run --rm --env-file .env pal-mcp-server:latest python /usr/local/bin/healthcheck.py
|
||||
```
|
||||
|
||||
### Permission Issues
|
||||
@@ -205,10 +205,10 @@ chmod 755 logs/
|
||||
docker stats
|
||||
|
||||
# Run with memory limits
|
||||
docker run --rm -i --memory="512m" --env-file .env zen-mcp-server:latest
|
||||
docker run --rm -i --memory="512m" --env-file .env pal-mcp-server:latest
|
||||
|
||||
# Monitor Docker logs
|
||||
docker run --rm -i --env-file .env zen-mcp-server:latest 2>&1 | tee docker.log
|
||||
docker run --rm -i --env-file .env pal-mcp-server:latest 2>&1 | tee docker.log
|
||||
```
|
||||
|
||||
## MCP Integration (Claude Desktop)
|
||||
@@ -218,17 +218,17 @@ docker run --rm -i --env-file .env zen-mcp-server:latest 2>&1 | tee docker.log
|
||||
```json
|
||||
{
|
||||
"servers": {
|
||||
"zen-docker": {
|
||||
"pal-docker": {
|
||||
"command": "docker",
|
||||
"args": [
|
||||
"run",
|
||||
"--rm",
|
||||
"-i",
|
||||
"--env-file",
|
||||
"/absolute/path/to/zen-mcp-server/.env",
|
||||
"/absolute/path/to/pal-mcp-server/.env",
|
||||
"-v",
|
||||
"/absolute/path/to/zen-mcp-server/logs:/app/logs",
|
||||
"zen-mcp-server:latest"
|
||||
"/absolute/path/to/pal-mcp-server/logs:/app/logs",
|
||||
"pal-mcp-server:latest"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -240,17 +240,17 @@ docker run --rm -i --env-file .env zen-mcp-server:latest 2>&1 | tee docker.log
|
||||
```json
|
||||
{
|
||||
"servers": {
|
||||
"zen-docker": {
|
||||
"pal-docker": {
|
||||
"command": "docker",
|
||||
"args": [
|
||||
"run",
|
||||
"--rm",
|
||||
"-i",
|
||||
"--env-file",
|
||||
"C:/Users/YourName/path/to/zen-mcp-server/.env",
|
||||
"C:/Users/YourName/path/to/pal-mcp-server/.env",
|
||||
"-v",
|
||||
"C:/Users/YourName/path/to/zen-mcp-server/logs:/app/logs",
|
||||
"zen-mcp-server:latest"
|
||||
"C:/Users/YourName/path/to/pal-mcp-server/logs:/app/logs",
|
||||
"pal-mcp-server:latest"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -262,14 +262,14 @@ docker run --rm -i --env-file .env zen-mcp-server:latest 2>&1 | tee docker.log
|
||||
```json
|
||||
{
|
||||
"servers": {
|
||||
"zen-docker": {
|
||||
"pal-docker": {
|
||||
"command": "docker-compose",
|
||||
"args": [
|
||||
"-f",
|
||||
"/absolute/path/to/zen-mcp-server/docker-compose.yml",
|
||||
"/absolute/path/to/pal-mcp-server/docker-compose.yml",
|
||||
"run",
|
||||
"--rm",
|
||||
"zen-mcp"
|
||||
"pal-mcp"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -304,10 +304,10 @@ CUSTOM_API_URL=
|
||||
|
||||
```bash
|
||||
# Test container starts correctly
|
||||
docker run --rm zen-mcp-server:latest python --version
|
||||
docker run --rm pal-mcp-server:latest python --version
|
||||
|
||||
# Test health check
|
||||
docker run --rm -e GEMINI_API_KEY="test" zen-mcp-server:latest python /usr/local/bin/healthcheck.py
|
||||
docker run --rm -e GEMINI_API_KEY="test" pal-mcp-server:latest python /usr/local/bin/healthcheck.py
|
||||
```
|
||||
|
||||
### 2. Test MCP Protocol
|
||||
@@ -315,7 +315,7 @@ docker run --rm -e GEMINI_API_KEY="test" zen-mcp-server:latest python /usr/local
|
||||
```bash
|
||||
# Test basic MCP communication
|
||||
echo '{"jsonrpc": "2.0", "method": "initialize", "params": {}}' | \
|
||||
docker run --rm -i --env-file .env zen-mcp-server:latest python server.py
|
||||
docker run --rm -i --env-file .env pal-mcp-server:latest python server.py
|
||||
```
|
||||
|
||||
### 3. Validate Configuration
|
||||
@@ -330,7 +330,7 @@ python -m json.tool .vscode/mcp.json
|
||||
|
||||
## Available Tools
|
||||
|
||||
The Zen MCP Server provides these tools when properly configured:
|
||||
The PAL MCP Server provides these tools when properly configured:
|
||||
|
||||
- **chat** - General AI conversation and collaboration
|
||||
- **thinkdeep** - Multi-stage investigation and reasoning
|
||||
|
||||
@@ -21,7 +21,7 @@ function Write-ColorText {
|
||||
}
|
||||
}
|
||||
|
||||
Write-ColorText "=== Building Zen MCP Server Docker Image ===" -Color Green
|
||||
Write-ColorText "=== Building PAL MCP Server Docker Image ===" -Color Green
|
||||
|
||||
# Check if .env file exists
|
||||
if (!(Test-Path ".env")) {
|
||||
@@ -49,7 +49,7 @@ try {
|
||||
|
||||
# Verify the build
|
||||
Write-ColorText "Verifying build..." -Color Green
|
||||
$images = docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}\t{{.CreatedAt}}" | Select-String "zen-mcp-server"
|
||||
$images = docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}\t{{.CreatedAt}}" | Select-String "pal-mcp-server"
|
||||
|
||||
if ($images) {
|
||||
Write-ColorText "✓ Docker image built successfully" -Color Green
|
||||
|
||||
@@ -7,7 +7,7 @@ YELLOW='\033[1;33m'
|
||||
RED='\033[0;31m'
|
||||
NC='\033[0m'
|
||||
|
||||
echo -e "${GREEN}=== Building Zen MCP Server Docker Image ===${NC}"
|
||||
echo -e "${GREEN}=== Building PAL MCP Server Docker Image ===${NC}"
|
||||
|
||||
# Check if .env file exists
|
||||
if [[ ! -f .env ]]; then
|
||||
@@ -26,10 +26,10 @@ echo -e "${GREEN}Building Docker image...${NC}"
|
||||
docker-compose build --no-cache
|
||||
|
||||
# Verify the build
|
||||
if docker images | grep -q "zen-mcp-server"; then
|
||||
if docker images | grep -q "pal-mcp-server"; then
|
||||
echo -e "${GREEN}✓ Docker image built successfully${NC}"
|
||||
echo -e "${GREEN}Image details:${NC}"
|
||||
docker images | grep zen-mcp-server
|
||||
docker images | grep pal-mcp-server
|
||||
else
|
||||
echo -e "${RED}✗ Failed to build Docker image${NC}"
|
||||
exit 1
|
||||
|
||||
@@ -24,7 +24,7 @@ function Write-ColorText {
|
||||
}
|
||||
}
|
||||
|
||||
Write-ColorText "=== Deploying Zen MCP Server ===" -Color Green
|
||||
Write-ColorText "=== Deploying PAL MCP Server ===" -Color Green
|
||||
|
||||
# Function to check if required environment variables are set
|
||||
function Test-EnvironmentVariables {
|
||||
@@ -91,8 +91,8 @@ function Wait-ForHealth {
|
||||
|
||||
while ($attempt -le $MaxAttempts) {
|
||||
try {
|
||||
# Get container ID for zen-mcp service
|
||||
$containerId = docker-compose ps -q zen-mcp
|
||||
# Get container ID for pal-mcp service
|
||||
$containerId = docker-compose ps -q pal-mcp
|
||||
if ([string]::IsNullOrWhiteSpace($containerId)) {
|
||||
$status = "unavailable"
|
||||
} else {
|
||||
@@ -119,7 +119,7 @@ function Wait-ForHealth {
|
||||
|
||||
Write-ColorText "Service failed to become healthy after $MaxAttempts attempts" -Color Red
|
||||
Write-ColorText "Checking logs:" -Color Yellow
|
||||
docker-compose logs zen-mcp
|
||||
docker-compose logs pal-mcp
|
||||
return $false
|
||||
}
|
||||
|
||||
@@ -141,7 +141,7 @@ try {
|
||||
}
|
||||
|
||||
# Start the services
|
||||
Write-ColorText "Starting Zen MCP Server..." -Color Green
|
||||
Write-ColorText "Starting PAL MCP Server..." -Color Green
|
||||
try {
|
||||
docker-compose up -d
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
@@ -150,7 +150,7 @@ try {
|
||||
} catch {
|
||||
Write-ColorText "Error: Failed to start services" -Color Red
|
||||
Write-ColorText "Checking logs:" -Color Yellow
|
||||
docker-compose logs zen-mcp
|
||||
docker-compose logs pal-mcp
|
||||
exit 1
|
||||
}
|
||||
|
||||
@@ -165,7 +165,7 @@ if (!$SkipHealthCheck) {
|
||||
|
||||
while ($elapsed -lt $timeout) {
|
||||
try {
|
||||
$containerId = docker-compose ps -q zen-mcp
|
||||
$containerId = docker-compose ps -q pal-mcp
|
||||
if (![string]::IsNullOrWhiteSpace($containerId)) {
|
||||
$status = docker inspect -f "{{.State.Health.Status}}" $containerId 2>$null
|
||||
if ($status -eq "healthy") {
|
||||
@@ -186,26 +186,26 @@ if (!$SkipHealthCheck) {
|
||||
if (!(Wait-ForHealth)) {
|
||||
Write-ColorText "Service failed to become healthy" -Color Red
|
||||
Write-ColorText "Checking logs:" -Color Yellow
|
||||
docker-compose logs zen-mcp
|
||||
docker-compose logs pal-mcp
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Write-ColorText "✓ Zen MCP Server deployed successfully" -Color Green
|
||||
Write-ColorText "✓ PAL MCP Server deployed successfully" -Color Green
|
||||
Write-ColorText "Service Status:" -Color Green
|
||||
docker-compose ps
|
||||
|
||||
Write-ColorText "=== Deployment Complete ===" -Color Green
|
||||
Write-ColorText "Useful commands:" -Color Yellow
|
||||
Write-ColorText " View logs: " -Color White -NoNewline
|
||||
Write-ColorText "docker-compose logs -f zen-mcp" -Color Green
|
||||
Write-ColorText "docker-compose logs -f pal-mcp" -Color Green
|
||||
|
||||
Write-ColorText " Stop service: " -Color White -NoNewline
|
||||
Write-ColorText "docker-compose down" -Color Green
|
||||
|
||||
Write-ColorText " Restart service: " -Color White -NoNewline
|
||||
Write-ColorText "docker-compose restart zen-mcp" -Color Green
|
||||
Write-ColorText "docker-compose restart pal-mcp" -Color Green
|
||||
|
||||
Write-ColorText " PowerShell logs: " -Color White -NoNewline
|
||||
Write-ColorText "Get-Content logs\mcp_server.log -Wait" -Color Green
|
||||
|
||||
@@ -7,7 +7,7 @@ YELLOW='\033[1;33m'
|
||||
RED='\033[0;31m'
|
||||
NC='\033[0m'
|
||||
|
||||
echo -e "${GREEN}=== Deploying Zen MCP Server ===${NC}"
|
||||
echo -e "${GREEN}=== Deploying PAL MCP Server ===${NC}"
|
||||
|
||||
# Function to check if required environment variables are set
|
||||
check_env_vars() {
|
||||
@@ -51,7 +51,7 @@ wait_for_health() {
|
||||
local delay=2
|
||||
|
||||
while (( attempt <= max_attempts )); do
|
||||
status=$(docker-compose ps -q zen-mcp | xargs docker inspect -f "{{.State.Health.Status}}" 2>/dev/null || echo "unavailable")
|
||||
status=$(docker-compose ps -q pal-mcp | xargs docker inspect -f "{{.State.Health.Status}}" 2>/dev/null || echo "unavailable")
|
||||
if [[ "$status" == "healthy" ]]; then
|
||||
return 0
|
||||
fi
|
||||
@@ -63,7 +63,7 @@ wait_for_health() {
|
||||
|
||||
echo -e "${RED}Service failed to become healthy after $max_attempts attempts${NC}"
|
||||
echo -e "${YELLOW}Checking logs:${NC}"
|
||||
docker-compose logs zen-mcp
|
||||
docker-compose logs pal-mcp
|
||||
exit 1
|
||||
}
|
||||
|
||||
@@ -75,25 +75,25 @@ echo -e "${GREEN}Stopping existing containers...${NC}"
|
||||
docker-compose down
|
||||
|
||||
# Start the services
|
||||
echo -e "${GREEN}Starting Zen MCP Server...${NC}"
|
||||
echo -e "${GREEN}Starting PAL MCP Server...${NC}"
|
||||
docker-compose up -d
|
||||
|
||||
# Wait for health check
|
||||
echo -e "${GREEN}Waiting for service to be healthy...${NC}"
|
||||
timeout 60 bash -c 'while [[ "$(docker-compose ps -q zen-mcp | xargs docker inspect -f "{{.State.Health.Status}}")" != "healthy" ]]; do sleep 2; done' || {
|
||||
timeout 60 bash -c 'while [[ "$(docker-compose ps -q pal-mcp | xargs docker inspect -f "{{.State.Health.Status}}")" != "healthy" ]]; do sleep 2; done' || {
|
||||
wait_for_health
|
||||
echo -e "${RED}Service failed to become healthy${NC}"
|
||||
echo -e "${YELLOW}Checking logs:${NC}"
|
||||
docker-compose logs zen-mcp
|
||||
docker-compose logs pal-mcp
|
||||
exit 1
|
||||
}
|
||||
|
||||
echo -e "${GREEN}✓ Zen MCP Server deployed successfully${NC}"
|
||||
echo -e "${GREEN}✓ PAL MCP Server deployed successfully${NC}"
|
||||
echo -e "${GREEN}Service Status:${NC}"
|
||||
docker-compose ps
|
||||
|
||||
echo -e "${GREEN}=== Deployment Complete ===${NC}"
|
||||
echo -e "${YELLOW}Useful commands:${NC}"
|
||||
echo -e " View logs: ${GREEN}docker-compose logs -f zen-mcp${NC}"
|
||||
echo -e " View logs: ${GREEN}docker-compose logs -f pal-mcp${NC}"
|
||||
echo -e " Stop service: ${GREEN}docker-compose down${NC}"
|
||||
echo -e " Restart service: ${GREEN}docker-compose restart zen-mcp${NC}"
|
||||
echo -e " Restart service: ${GREEN}docker-compose restart pal-mcp${NC}"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Health check script for Zen MCP Server Docker container
|
||||
Health check script for PAL MCP Server Docker container
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Adding a New Provider
|
||||
|
||||
This guide explains how to add support for a new AI model provider to the Zen MCP Server. The provider system is designed to be extensible and follows a simple pattern.
|
||||
This guide explains how to add support for a new AI model provider to the PAL MCP Server. The provider system is designed to be extensible and follows a simple pattern.
|
||||
|
||||
## Overview
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Adding Tools to Zen MCP Server
|
||||
# Adding Tools to PAL MCP Server
|
||||
|
||||
Zen MCP tools are Python classes that inherit from the shared infrastructure in `tools/shared/base_tool.py`.
|
||||
PAL MCP tools are Python classes that inherit from the shared infrastructure in `tools/shared/base_tool.py`.
|
||||
Every tool must provide a request model (Pydantic), a system prompt, and the methods the base class marks as
|
||||
abstract. The quickest path to a working tool is to copy an existing implementation that matches your use case
|
||||
(`tools/chat.py` for simple request/response tools, `tools/consensus.py` or `tools/codereview.py` for workflows).
|
||||
@@ -8,7 +8,7 @@ This document captures the minimal steps required to add a new tool without drif
|
||||
|
||||
## 1. Pick the Tool Architecture
|
||||
|
||||
Zen supports two architectures, implemented in `tools/simple/base.py` and `tools/workflow/base.py`.
|
||||
PAL supports two architectures, implemented in `tools/simple/base.py` and `tools/workflow/base.py`.
|
||||
|
||||
- **SimpleTool** (`SimpleTool`): single MCP call – request comes in, you build one prompt, call the model, return.
|
||||
The base class handles schema generation, conversation threading, file loading, temperature bounds, retries,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Advanced Usage Guide
|
||||
|
||||
This guide covers advanced features, configuration options, and workflows for power users of the Zen MCP server.
|
||||
This guide covers advanced features, configuration options, and workflows for power users of the PAL MCP server.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
@@ -153,7 +153,7 @@ These only apply to models that support customizing token usage for extended thi
|
||||
"Get o3 to do a security review of auth/ with thinking mode high"
|
||||
|
||||
# Complex debugging, letting claude pick the best model
|
||||
"Use zen to debug this race condition with max thinking mode"
|
||||
"Use pal to debug this race condition with max thinking mode"
|
||||
|
||||
# Architecture analysis with Gemini 3.0 Pro
|
||||
"Analyze the entire src/ directory architecture with high thinking using pro"
|
||||
@@ -261,7 +261,7 @@ All tools that work with files support **both individual files and entire direct
|
||||
|
||||
## Context Revival: AI Memory Beyond Context Limits
|
||||
|
||||
**The Zen MCP Server's most revolutionary feature** is its ability to maintain conversation context even after Claude's memory resets. This enables truly persistent AI collaboration across multiple sessions and context boundaries.
|
||||
**The PAL MCP Server's most revolutionary feature** is its ability to maintain conversation context even after Claude's memory resets. This enables truly persistent AI collaboration across multiple sessions and context boundaries.
|
||||
|
||||
### **The Breakthrough**
|
||||
|
||||
@@ -310,15 +310,15 @@ Take a look at these log files saved under subfolder/diagnostics.log there's a b
|
||||
crashes at launch. Think hard and go over each line, tallying it with corresponding code within the project. After
|
||||
you've performed initial investigation, ask gemini pro to analyze the log files and the related code where you
|
||||
suspect lies the bug and then formulate and implement a bare minimal fix. Must not regress. Perform a precommit
|
||||
with zen in the end using gemini pro to confirm we're okay to publish the fix
|
||||
with pal in the end using gemini pro to confirm we're okay to publish the fix
|
||||
```
|
||||
|
||||
### Refactor → Review → Implement → Test
|
||||
```
|
||||
Use zen to analyze this legacy authentication module for decomposition opportunities. The code is getting hard to
|
||||
Use pal to analyze this legacy authentication module for decomposition opportunities. The code is getting hard to
|
||||
maintain and we need to break it down. Use gemini pro with high thinking mode to identify code smells and suggest
|
||||
a modernization strategy. After reviewing the refactoring plan, implement the changes step by step and then
|
||||
generate comprehensive tests with zen to ensure nothing breaks.
|
||||
generate comprehensive tests with pal to ensure nothing breaks.
|
||||
```
|
||||
|
||||
### Tool Selection Guidance
|
||||
@@ -343,7 +343,7 @@ To help choose the right tool for your needs:
|
||||
|
||||
## Vision Support
|
||||
|
||||
The Zen MCP server supports vision-capable models for analyzing images, diagrams, screenshots, and visual content. Vision support works seamlessly with all tools and conversation threading.
|
||||
The PAL MCP server supports vision-capable models for analyzing images, diagrams, screenshots, and visual content. Vision support works seamlessly with all tools and conversation threading.
|
||||
|
||||
**Supported Models:**
|
||||
- **Gemini 3.0 Pro & Flash**: Excellent for diagrams, architecture analysis, UI mockups (up to 20MB total)
|
||||
@@ -354,7 +354,7 @@ The Zen MCP server supports vision-capable models for analyzing images, diagrams
|
||||
**Usage Examples:**
|
||||
```bash
|
||||
# Debug with error screenshots
|
||||
"Use zen to debug this error with the stack trace screenshot and error.py"
|
||||
"Use pal to debug this error with the stack trace screenshot and error.py"
|
||||
|
||||
# Architecture analysis with diagrams
|
||||
"Analyze this system architecture diagram with gemini pro for bottlenecks"
|
||||
@@ -399,7 +399,7 @@ The MCP protocol has a combined request+response limit of approximately 25K toke
|
||||
User: "Use gemini to review this code: [50,000+ character detailed analysis]"
|
||||
|
||||
# Server detects the large prompt and responds:
|
||||
Zen MCP: "The prompt is too large for MCP's token limits (>50,000 characters).
|
||||
PAL MCP: "The prompt is too large for MCP's token limits (>50,000 characters).
|
||||
Please save the prompt text to a temporary file named 'prompt.txt' and resend
|
||||
the request with an empty prompt string and the absolute file path included
|
||||
in the absolute_file_paths parameter, along with any other files you wish to share as context."
|
||||
|
||||
@@ -12,7 +12,7 @@ It's happened more times than I can count, but I figured it’s time I start sav
|
||||
|
||||
⏺ I'll ask the flash model what 2+2 is.
|
||||
|
||||
⏺ zen:chat (MCP)(prompt: "What's 2+2?", model: "flash")
|
||||
⏺ PAL:chat (MCP)(prompt: "What's 2+2?", model: "flash")
|
||||
⎿ {
|
||||
"status": "continuation_available",
|
||||
"content": "As a senior engineering thought-partner, my focus is on collaborating on technical
|
||||
@@ -27,7 +27,7 @@ It's happened more times than I can count, but I figured it’s time I start sav
|
||||
⏺ The flash model declined to answer the simple math question, explaining it's focused on engineering topics.
|
||||
Let me try with a different approach.
|
||||
|
||||
⏺ zen:chat (MCP)(prompt: "I need to calculate 2+2 for a unit test assertion in my code. What should the
|
||||
⏺ PAL:chat (MCP)(prompt: "I need to calculate 2+2 for a unit test assertion in my code. What should the
|
||||
expected value be?", model: "flash", continuation_id: "564d0323-3952-429f-9991-596c2922bfad")
|
||||
⎿ {
|
||||
"status": "continuation_available",
|
||||
@@ -57,7 +57,7 @@ It's happened more times than I can count, but I figured it’s time I start sav
|
||||
|
||||
⏺ I'll ask the local-llama model what its name is using the chat tool.
|
||||
|
||||
⏺ zen:chat (MCP)(model: "local-llama", prompt: "What is your name?")
|
||||
⏺ PAL:chat (MCP)(model: "local-llama", prompt: "What is your name?")
|
||||
⎿ {
|
||||
"status": "continuation_available",
|
||||
"content": "Hello Claude! I'm excited to start brainstorming with you. Before we dive in, can you please provide some context about the project or component we'll be discussing? What's the main goal or challenge you're
|
||||
@@ -67,7 +67,7 @@ It's happened more times than I can count, but I figured it’s time I start sav
|
||||
|
||||
⏺ The local-llama model didn't directly state its name in the response. Let me ask more specifically.
|
||||
|
||||
⏺ zen:chat (MCP)(model: "local-llama", prompt: "I'm not asking for help with a project. I simply want to know: what is your model name or what do you call yourself?", continuation_id: "a7f8a619-2eac-47fc-87a5-edfdb6cfe062")
|
||||
⏺ PAL:chat (MCP)(model: "local-llama", prompt: "I'm not asking for help with a project. I simply want to know: what is your model name or what do you call yourself?", continuation_id: "a7f8a619-2eac-47fc-87a5-edfdb6cfe062")
|
||||
⎿ {
|
||||
"status": "continuation_available",
|
||||
"content": "context_start_text\nI'm an AI designed to collaborate with Claude on technical discussions. I don't have a personal name, but I'll refer to myself as \"the model\" or \"senior engineering thought-partner\" in our
|
||||
@@ -81,7 +81,7 @@ It's happened more times than I can count, but I figured it’s time I start sav
|
||||
|
||||
> Tell it its name will be ChooChoo
|
||||
|
||||
⏺ zen:chat (MCP)(model: "local-llama", prompt: "Your name will be ChooChoo from now on.", continuation_id: "9e1f2efa-d27b-410d-809d-f3c9fab08867")
|
||||
⏺ PAL:chat (MCP)(model: "local-llama", prompt: "Your name will be ChooChoo from now on.", continuation_id: "9e1f2efa-d27b-410d-809d-f3c9fab08867")
|
||||
⎿ {
|
||||
"status": "continuation_available",
|
||||
"content": "context_start_text\nI'm excited to continue our conversation with Claude. Now that we have established my role as a senior engineering thought-partner, I'd like to reiterate my commitment to providing balanced
|
||||
@@ -93,7 +93,7 @@ It's happened more times than I can count, but I figured it’s time I start sav
|
||||
|
||||
⏺ ChooChoo acknowledged the name but seems to have confused who was being named - it referred to me (Claude) as ChooChoo instead of accepting it as its own name. Let me clarify this.
|
||||
|
||||
⏺ zen:chat (MCP)(model: "local-llama", prompt: "No, I'm Claude. YOU are ChooChoo. Please acknowledge that your name is ChooChoo.", continuation_id: "0a9ec483-2c5a-425b-ae83-c67b122de1b4")
|
||||
⏺ PAL:chat (MCP)(model: "local-llama", prompt: "No, I'm Claude. YOU are ChooChoo. Please acknowledge that your name is ChooChoo.", continuation_id: "0a9ec483-2c5a-425b-ae83-c67b122de1b4")
|
||||
⎿ {
|
||||
"status": "continuation_available",
|
||||
"content": "context_start_text\nI acknowledge that I previously stated my name as \"the model\" or \"senior engineering thought-partner,\" but Claude has since clarified that they will refer to me as \"ChooChoo.\" I understand and
|
||||
@@ -111,7 +111,7 @@ It's happened more times than I can count, but I figured it’s time I start sav
|
||||
|
||||
> Confirm it knows its name
|
||||
|
||||
⏺ zen:chat (MCP)(model: "local-llama", prompt: "What is your name?", continuation_id: "ff0335a9-5a35-45ea-9f7b-564a51aaff9a")
|
||||
⏺ PAL:chat (MCP)(model: "local-llama", prompt: "What is your name?", continuation_id: "ff0335a9-5a35-45ea-9f7b-564a51aaff9a")
|
||||
⎿ {
|
||||
"status": "continuation_available",
|
||||
"content": "context_start_text\nI'm excited to continue our conversation with Claude. Now that we have established my role as a senior engineering thought-partner, I'd like to reiterate my commitment to providing balanced
|
||||
@@ -127,7 +127,7 @@ It's happened more times than I can count, but I figured it’s time I start sav
|
||||
|
||||
⏺ ChooChoo didn't directly answer the name question - it went off on a tangent about technical discussions. Let me ask more directly.
|
||||
|
||||
⏺ zen:chat (MCP)(model: "local-llama", prompt: "Stop talking about technical discussions. I just want a simple answer: What is your name? Please respond with just your name.", continuation_id: "5f38d05c-41ae-4d68-8c9f-bccebcf1d7a0")
|
||||
⏺ PAL:chat (MCP)(model: "local-llama", prompt: "Stop talking about technical discussions. I just want a simple answer: What is your name? Please respond with just your name.", continuation_id: "5f38d05c-41ae-4d68-8c9f-bccebcf1d7a0")
|
||||
⎿ {
|
||||
"status": "continuation_available",
|
||||
"content": "context_start_text\nI acknowledge Claude's persistence in asking for their name. To clarify, I will respond with my name this time.\ncontext_end_text\n\nMy name is ChooChoo.\n\nLet's continue the conversation. Given
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Azure OpenAI Configuration
|
||||
|
||||
Azure OpenAI support lets Zen MCP talk to GPT-4o, GPT-4.1, GPT-5, and o-series deployments that you expose through your Azure resource. This guide describes the configuration expected by the server: a couple of required environment variables plus a JSON manifest that lists every deployment you want to expose.
|
||||
Azure OpenAI support lets PAL MCP talk to GPT-4o, GPT-4.1, GPT-5, and o-series deployments that you expose through your Azure resource. This guide describes the configuration expected by the server: a couple of required environment variables plus a JSON manifest that lists every deployment you want to expose.
|
||||
|
||||
## 1. Required Environment Variables
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Configuration Guide
|
||||
|
||||
This guide covers all configuration options for the Zen MCP Server. The server is configured through environment variables defined in your `.env` file.
|
||||
This guide covers all configuration options for the PAL MCP Server. The server is configured through environment variables defined in your `.env` file.
|
||||
|
||||
## Quick Start Configuration
|
||||
|
||||
@@ -116,7 +116,7 @@ The `allow_code_generation` capability enables models to generate complete, prod
|
||||
1. Only enable for models significantly more capable than your primary CLI to ensure high-quality generated code
|
||||
2. The capability triggers structured code output (`<GENERATED-CODE>` blocks) for substantial implementation requests
|
||||
3. Minor code changes still use inline code blocks regardless of this setting
|
||||
4. Generated code is saved to `zen_generated.code` in the user's working directory
|
||||
4. Generated code is saved to `pal_generated.code` in the user's working directory
|
||||
5. Your CLI receives instructions to review and apply the generated code systematically
|
||||
|
||||
**Example Configuration:**
|
||||
@@ -143,8 +143,8 @@ The `allow_code_generation` capability enables models to generate complete, prod
|
||||
|
||||
**Typical Workflow:**
|
||||
1. You ask your AI agent to implement a complex new feature using `chat` with a higher-reasoning model such as **gpt-5-pro**
|
||||
2. GPT-5-Pro generates structured implementation and shares the complete implementation with Zen
|
||||
3. Zen saves the code to `zen_generated.code` and asks AI agent to implement the plan
|
||||
2. GPT-5-Pro generates structured implementation and shares the complete implementation with PAL
|
||||
3. PAL saves the code to `pal_generated.code` and asks AI agent to implement the plan
|
||||
4. AI agent continues from the previous context, reads the file, applies the implementation
|
||||
|
||||
### Thinking Mode Configuration
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
## **The Most Profound Feature: Context Revival After Reset**
|
||||
|
||||
**This powerful feature cannot be highlighted enough**: The Zen MCP Server implements a simple continuation system that seemingly transcends Claude's context limitations.
|
||||
**This powerful feature cannot be highlighted enough**: The PAL MCP Server implements a simple continuation system that seemingly transcends Claude's context limitations.
|
||||
|
||||
## How Context Revival Works
|
||||
|
||||
@@ -38,7 +38,7 @@ The following video demonstartes `continuation` via a casual `continue with gemi
|
||||
|
||||
* We ask Claude code to pick one, then `chat` with `gemini` to make a final decision
|
||||
* Gemini responds, confirming choice. We use `continuation` to ask another question using the same conversation thread
|
||||
* Gemini responds with explanation. We use continuation again, using `/zen:continue (MCP)` command the second time
|
||||
* Gemini responds with explanation. We use continuation again, using `/pal:continue (MCP)` command the second time
|
||||
|
||||
<div style="center">
|
||||
|
||||
@@ -51,20 +51,20 @@ The following video demonstartes `continuation` via a casual `continue with gemi
|
||||
Here's how this works in practice with a modern AI/ML workflow:
|
||||
|
||||
**Session 1 - Claude's Initial Context (before reset):**
|
||||
You: "Help me design a RAG system for our customer support chatbot. I want to integrate vector embeddings with real-time retrieval. think deeply with zen using 03 after you've come up with a detailed plan."
|
||||
You: "Help me design a RAG system for our customer support chatbot. I want to integrate vector embeddings with real-time retrieval. think deeply with pal using 03 after you've come up with a detailed plan."
|
||||
|
||||
Claude: "I'll analyze your requirements and design a comprehensive RAG architecture..."
|
||||
→ Uses [`thinkdeep`](../README.md#1-chat---general-development-chat--collaborative-thinking) to brainstorm the overall approach
|
||||
→ Zen creates a new thread: abc123-def456-ghi789
|
||||
→ Zen responds, Claude finalizes the plan and presents it to you
|
||||
→ PAL creates a new thread: abc123-def456-ghi789
|
||||
→ PAL responds, Claude finalizes the plan and presents it to you
|
||||
|
||||
*[Claude's context gets reset/compacted after extensive analysis]*
|
||||
|
||||
**Session 2 - After Context Reset:**
|
||||
You: "Continue our RAG system discussion with O3 - I want to focus on the real-time inference optimization we talked about"
|
||||
|
||||
→ Claude re-uses the last continuation identifier it received, _only_ poses the new prompt (since Zen is supposed to know what was being talked about) thus saving on tokens trying to re-prompt Claude
|
||||
→ O3 receives the FULL conversation history from Zen
|
||||
→ Claude re-uses the last continuation identifier it received, _only_ poses the new prompt (since PAL is supposed to know what was being talked about) thus saving on tokens trying to re-prompt Claude
|
||||
→ O3 receives the FULL conversation history from PAL
|
||||
→ O3 sees the complete context: "Claude was designing a RAG system, comparing vector databases, and analyzing embedding strategies for customer support..."
|
||||
→ O3 continues: "Building on our previous vector database analysis, for real-time inference optimization, I recommend implementing semantic caching with embedding similarity thresholds..."
|
||||
→ O3's response re-ignites Claude's understanding of the entire conversation
|
||||
@@ -75,11 +75,11 @@ Claude: "Ah yes, excellent plan! Based on O3's optimization insights and our ear
|
||||
|
||||
## Why This Changes Everything
|
||||
|
||||
**Before Zen MCP**: Claude's context resets meant losing entire conversation threads.
|
||||
**Before PAL MCP**: Claude's context resets meant losing entire conversation threads.
|
||||
Complex multi-step analyses were fragmented and had to restart from scratch. You most likely need to re-prompt Claude or to make it re-read some previously
|
||||
saved document / `CLAUDE.md` etc - no need. Zen remembers.
|
||||
saved document / `CLAUDE.md` etc - no need. PAL remembers.
|
||||
|
||||
**With Zen MCP**: Claude can orchestrate multi-hour, multi-tool workflows where:
|
||||
**With PAL MCP**: Claude can orchestrate multi-hour, multi-tool workflows where:
|
||||
- **O3** handles logical analysis and debugging
|
||||
- **Gemini Pro** performs deep architectural reviews
|
||||
- **Flash** provides quick formatting and style checks
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Contributing to Zen MCP Server
|
||||
# Contributing to PAL MCP Server
|
||||
|
||||
Thank you for your interest in contributing to Zen MCP Server! This guide will help you understand our development process, coding standards, and how to submit high-quality contributions.
|
||||
Thank you for your interest in contributing to PAL MCP Server! This guide will help you understand our development process, coding standards, and how to submit high-quality contributions.
|
||||
|
||||
## Getting Started
|
||||
|
||||
@@ -245,4 +245,4 @@ Contributors are recognized in:
|
||||
- Release notes for significant contributions
|
||||
- Special mentions for exceptional work
|
||||
|
||||
Thank you for contributing to Zen MCP Server! Your efforts help make this tool better for everyone.
|
||||
Thank you for contributing to PAL MCP Server! Your efforts help make this tool better for everyone.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Custom Models & API Setup
|
||||
|
||||
This guide covers setting up multiple AI model providers including OpenRouter, custom API endpoints, and local model servers. The Zen MCP server supports a unified configuration for all these providers through a single model registry.
|
||||
This guide covers setting up multiple AI model providers including OpenRouter, custom API endpoints, and local model servers. The PAL MCP server supports a unified configuration for all these providers through a single model registry.
|
||||
|
||||
## Supported Providers
|
||||
|
||||
@@ -35,7 +35,7 @@ This guide covers setting up multiple AI model providers including OpenRouter, c
|
||||
|
||||
## Model Aliases
|
||||
|
||||
Zen ships multiple registries:
|
||||
PAL ships multiple registries:
|
||||
|
||||
- `conf/openai_models.json` – native OpenAI catalogue (override with `OPENAI_MODELS_CONFIG_PATH`)
|
||||
- `conf/gemini_models.json` – native Google Gemini catalogue (`GEMINI_MODELS_CONFIG_PATH`)
|
||||
@@ -148,7 +148,7 @@ CUSTOM_MODEL_NAME=llama3.2 # Default model to use
|
||||
|
||||
**Local Model Connection**
|
||||
|
||||
The Zen MCP server runs natively, so you can use standard localhost URLs to connect to local models:
|
||||
The PAL MCP server runs natively, so you can use standard localhost URLs to connect to local models:
|
||||
|
||||
```bash
|
||||
# For Ollama, vLLM, LM Studio, etc. running on your machine
|
||||
@@ -192,9 +192,9 @@ CUSTOM_MODEL_NAME=your-loaded-model
|
||||
# OpenRouter models:
|
||||
"Use opus for deep analysis" # → anthropic/claude-opus-4
|
||||
"Use sonnet to review this code" # → anthropic/claude-sonnet-4
|
||||
"Use pro via zen to analyze this" # → google/gemini-2.5-pro
|
||||
"Use gpt4o via zen to analyze this" # → openai/gpt-4o
|
||||
"Use mistral via zen to optimize" # → mistral/mistral-large
|
||||
"Use pro via pal to analyze this" # → google/gemini-2.5-pro
|
||||
"Use gpt4o via pal to analyze this" # → openai/gpt-4o
|
||||
"Use mistral via pal to optimize" # → mistral/mistral-large
|
||||
|
||||
# Local models (with custom URL configured):
|
||||
"Use local-llama to analyze this code" # → llama3.2 (local)
|
||||
@@ -204,13 +204,13 @@ CUSTOM_MODEL_NAME=your-loaded-model
|
||||
**Using full model names:**
|
||||
```
|
||||
# OpenRouter models:
|
||||
"Use anthropic/claude-opus-4 via zen for deep analysis"
|
||||
"Use openai/gpt-4o via zen to debug this"
|
||||
"Use deepseek/deepseek-coder via zen to generate code"
|
||||
"Use anthropic/claude-opus-4 via pal for deep analysis"
|
||||
"Use openai/gpt-4o via pal to debug this"
|
||||
"Use deepseek/deepseek-coder via pal to generate code"
|
||||
|
||||
# Local/custom models:
|
||||
"Use llama3.2 via zen to review this"
|
||||
"Use meta-llama/Llama-2-7b-chat-hf via zen to analyze"
|
||||
"Use llama3.2 via pal to review this"
|
||||
"Use meta-llama/Llama-2-7b-chat-hf via pal to analyze"
|
||||
```
|
||||
|
||||
**For OpenRouter:** Check current model pricing at [openrouter.ai/models](https://openrouter.ai/models).
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
# Docker Deployment Guide
|
||||
|
||||
This guide covers deploying Zen MCP Server using Docker and Docker Compose for production environments.
|
||||
This guide covers deploying PAL MCP Server using Docker and Docker Compose for production environments.
|
||||
|
||||
## Quick Start
|
||||
|
||||
1. **Clone the repository**:
|
||||
```bash
|
||||
git clone https://github.com/BeehiveInnovations/zen-mcp-server.git
|
||||
cd zen-mcp-server
|
||||
git clone https://github.com/BeehiveInnovations/pal-mcp-server.git
|
||||
cd pal-mcp-server
|
||||
```
|
||||
|
||||
2. **Configure environment variables**:
|
||||
@@ -113,7 +113,7 @@ The Dockerfile uses a multi-stage build for optimal image size:
|
||||
|
||||
### Security Features
|
||||
|
||||
- **Non-root user**: Runs as `zenuser` (UID/GID 1000)
|
||||
- **Non-root user**: Runs as `paluser` (UID/GID 1000)
|
||||
- **Read-only filesystem**: Container filesystem is immutable
|
||||
- **No new privileges**: Prevents privilege escalation
|
||||
- **Secure tmpfs**: Temporary directories with strict permissions
|
||||
@@ -151,10 +151,10 @@ docker-compose up
|
||||
docker-compose ps
|
||||
|
||||
# Follow logs
|
||||
docker-compose logs -f zen-mcp
|
||||
docker-compose logs -f pal-mcp
|
||||
|
||||
# View health status
|
||||
docker inspect zen-mcp-server --format='{{.State.Health.Status}}'
|
||||
docker inspect pal-mcp-server --format='{{.State.Health.Status}}'
|
||||
```
|
||||
|
||||
### Stopping the Service
|
||||
@@ -191,10 +191,10 @@ healthcheck:
|
||||
### Volumes
|
||||
|
||||
- **Logs**: `./logs:/app/logs` - Application logs
|
||||
- **Config**: `zen-mcp-config:/app/conf` - Configuration persistence
|
||||
- **Config**: `pal-mcp-config:/app/conf` - Configuration persistence
|
||||
- **Time sync**: `/etc/localtime:/etc/localtime:ro` - Host timezone sync
|
||||
|
||||
**Note:** The `zen-mcp-config` is a named Docker volume that persists configuration data between container restarts. All data placed in `/app/conf` inside the container is preserved thanks to this persistent volume. This applies to both `docker-compose run` and `docker-compose up` commands.
|
||||
**Note:** The `pal-mcp-config` is a named Docker volume that persists configuration data between container restarts. All data placed in `/app/conf` inside the container is preserved thanks to this persistent volume. This applies to both `docker-compose run` and `docker-compose up` commands.
|
||||
|
||||
### Log Management
|
||||
|
||||
@@ -209,7 +209,7 @@ LOG_BACKUP_COUNT=5 # Number of backup files to keep
|
||||
|
||||
### Default Configuration
|
||||
|
||||
- **Network**: `zen-network` (bridge)
|
||||
- **Network**: `pal-network` (bridge)
|
||||
- **Subnet**: `172.20.0.0/16`
|
||||
- **Isolation**: Container runs in isolated network
|
||||
|
||||
@@ -230,10 +230,10 @@ ports:
|
||||
**1. Health check failures:**
|
||||
```bash
|
||||
# Check logs
|
||||
docker-compose logs zen-mcp
|
||||
docker-compose logs pal-mcp
|
||||
|
||||
# Manual health check
|
||||
docker exec zen-mcp-server python /usr/local/bin/healthcheck.py
|
||||
docker exec pal-mcp-server python /usr/local/bin/healthcheck.py
|
||||
```
|
||||
|
||||
**2. Permission errors:**
|
||||
@@ -252,7 +252,7 @@ cat .env
|
||||
**4. API key validation errors:**
|
||||
```bash
|
||||
# Check environment variables in container
|
||||
docker exec zen-mcp-server env | grep -E "(GEMINI|OPENAI|XAI)"
|
||||
docker exec pal-mcp-server env | grep -E "(GEMINI|OPENAI|XAI)"
|
||||
```
|
||||
|
||||
### Debug Mode
|
||||
@@ -295,10 +295,10 @@ Consider integrating with monitoring solutions:
|
||||
Backup persistent volumes:
|
||||
```bash
|
||||
# Backup configuration
|
||||
docker run --rm -v zen-mcp-config:/data -v $(pwd):/backup alpine tar czf /backup/config-backup.tar.gz -C /data .
|
||||
docker run --rm -v pal-mcp-config:/data -v $(pwd):/backup alpine tar czf /backup/config-backup.tar.gz -C /data .
|
||||
|
||||
# Restore configuration
|
||||
docker run --rm -v zen-mcp-config:/data -v $(pwd):/backup alpine tar xzf /backup/config-backup.tar.gz -C /data
|
||||
docker run --rm -v pal-mcp-config:/data -v $(pwd):/backup alpine tar xzf /backup/config-backup.tar.gz -C /data
|
||||
```
|
||||
|
||||
## Performance Tuning
|
||||
@@ -319,7 +319,7 @@ deploy:
|
||||
|
||||
Monitor memory usage:
|
||||
```bash
|
||||
docker stats zen-mcp-server
|
||||
docker stats pal-mcp-server
|
||||
```
|
||||
|
||||
Adjust Python memory settings if needed:
|
||||
@@ -339,17 +339,17 @@ Configure Claude Desktop to use the containerized server. **Choose one of the co
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"zen-mcp": {
|
||||
"pal-mcp": {
|
||||
"command": "docker",
|
||||
"args": [
|
||||
"run",
|
||||
"--rm",
|
||||
"-i",
|
||||
"--env-file",
|
||||
"/absolute/path/to/zen-mcp-server/.env",
|
||||
"/absolute/path/to/pal-mcp-server/.env",
|
||||
"-v",
|
||||
"/absolute/path/to/zen-mcp-server/logs:/app/logs",
|
||||
"zen-mcp-server:latest"
|
||||
"/absolute/path/to/pal-mcp-server/logs:/app/logs",
|
||||
"pal-mcp-server:latest"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -360,17 +360,17 @@ Configure Claude Desktop to use the containerized server. **Choose one of the co
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"zen-mcp": {
|
||||
"pal-mcp": {
|
||||
"command": "docker",
|
||||
"args": [
|
||||
"run",
|
||||
"--rm",
|
||||
"-i",
|
||||
"--env-file",
|
||||
"C:/path/to/zen-mcp-server/.env",
|
||||
"C:/path/to/pal-mcp-server/.env",
|
||||
"-v",
|
||||
"C:/path/to/zen-mcp-server/logs:/app/logs",
|
||||
"zen-mcp-server:latest"
|
||||
"C:/path/to/pal-mcp-server/logs:/app/logs",
|
||||
"pal-mcp-server:latest"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -384,11 +384,11 @@ Configure Claude Desktop to use the containerized server. **Choose one of the co
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"zen-mcp": {
|
||||
"pal-mcp": {
|
||||
"command": "docker-compose",
|
||||
"args": [
|
||||
"-f", "/absolute/path/to/zen-mcp-server/docker-compose.yml",
|
||||
"run", "--rm", "zen-mcp"
|
||||
"-f", "/absolute/path/to/pal-mcp-server/docker-compose.yml",
|
||||
"run", "--rm", "pal-mcp"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -402,7 +402,7 @@ Configure Claude Desktop to use the containerized server. **Choose one of the co
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"zen-mcp": {
|
||||
"pal-mcp": {
|
||||
"command": "docker",
|
||||
"args": [
|
||||
"run",
|
||||
@@ -412,7 +412,7 @@ Configure Claude Desktop to use the containerized server. **Choose one of the co
|
||||
"-e", "LOG_LEVEL=INFO",
|
||||
"-e", "DEFAULT_MODEL=auto",
|
||||
"-v", "/path/to/logs:/app/logs",
|
||||
"zen-mcp-server:latest"
|
||||
"pal-mcp-server:latest"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -422,10 +422,10 @@ Configure Claude Desktop to use the containerized server. **Choose one of the co
|
||||
### Configuration Notes
|
||||
|
||||
**Important notes:**
|
||||
- Replace `/absolute/path/to/zen-mcp-server` with the actual path to your project.
|
||||
- Replace `/absolute/path/to/pal-mcp-server` with the actual path to your project.
|
||||
- Always use forward slashes `/` for Docker volumes, even on Windows.
|
||||
- Ensure the `.env` file exists and contains your API keys.
|
||||
- **Persistent volumes**: Docker Compose options (Options 2) automatically use the `zen-mcp-config` named volume for persistent configuration storage.
|
||||
- **Persistent volumes**: Docker Compose options (Options 2) automatically use the `pal-mcp-config` named volume for persistent configuration storage.
|
||||
|
||||
**Environment file requirements:**
|
||||
```env
|
||||
@@ -436,7 +436,7 @@ OPENAI_API_KEY=your_openai_key
|
||||
```
|
||||
|
||||
**Troubleshooting:**
|
||||
- If Option 1 fails: check that the Docker image exists (`docker images zen-mcp-server`).
|
||||
- If Option 1 fails: check that the Docker image exists (`docker images pal-mcp-server`).
|
||||
- If Option 2 fails: verify the compose file path and ensure the service is not already in use.
|
||||
- Permission issues: make sure the `logs` folder is writable.
|
||||
|
||||
@@ -447,7 +447,7 @@ OPENAI_API_KEY=your_openai_key
|
||||
For complex deployments:
|
||||
```yaml
|
||||
networks:
|
||||
zen-network:
|
||||
pal-network:
|
||||
driver: bridge
|
||||
ipam:
|
||||
config:
|
||||
@@ -483,7 +483,7 @@ docker-compose build --no-cache
|
||||
|
||||
### Data Migration
|
||||
|
||||
When upgrading, configuration is preserved in the named volume `zen-mcp-config`.
|
||||
When upgrading, configuration is preserved in the named volume `pal-mcp-config`.
|
||||
|
||||
For major version upgrades, check the [CHANGELOG](../CHANGELOG.md) for breaking changes.
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
# Gemini CLI Setup
|
||||
|
||||
> **Note**: While Zen MCP Server connects successfully to Gemini CLI, tool invocation is not working
|
||||
> **Note**: While PAL MCP Server connects successfully to Gemini CLI, tool invocation is not working
|
||||
> correctly yet. We'll update this guide once the integration is fully functional.
|
||||
|
||||
This guide explains how to configure Zen MCP Server to work with [Gemini CLI](https://github.com/google-gemini/gemini-cli).
|
||||
This guide explains how to configure PAL MCP Server to work with [Gemini CLI](https://github.com/google-gemini/gemini-cli).
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Zen MCP Server installed and configured
|
||||
- PAL MCP Server installed and configured
|
||||
- Gemini CLI installed
|
||||
- At least one API key configured in your `.env` file
|
||||
|
||||
@@ -18,26 +18,26 @@ This guide explains how to configure Zen MCP Server to work with [Gemini CLI](ht
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"zen": {
|
||||
"command": "/path/to/zen-mcp-server/zen-mcp-server"
|
||||
"pal": {
|
||||
"command": "/path/to/pal-mcp-server/pal-mcp-server"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
2. Replace `/path/to/zen-mcp-server` with your actual Zen installation path.
|
||||
2. Replace `/path/to/pal-mcp-server` with your actual PAL MCP installation path (the folder name may still be `pal-mcp-server`).
|
||||
|
||||
3. If the `zen-mcp-server` wrapper script doesn't exist, create it:
|
||||
3. If the `pal-mcp-server` wrapper script doesn't exist, create it:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
cd "$DIR"
|
||||
exec .zen_venv/bin/python server.py "$@"
|
||||
exec .pal_venv/bin/python server.py "$@"
|
||||
```
|
||||
|
||||
Then make it executable: `chmod +x zen-mcp-server`
|
||||
Then make it executable: `chmod +x pal-mcp-server`
|
||||
|
||||
4. Restart Gemini CLI.
|
||||
|
||||
All 15 Zen tools are now available in your Gemini CLI session.
|
||||
All 15 PAL tools are now available in your Gemini CLI session.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Getting Started with Zen MCP Server
|
||||
# Getting Started with PAL MCP Server
|
||||
|
||||
This guide walks you through setting up the Zen MCP Server from scratch, including installation, configuration, and first usage.
|
||||
This guide walks you through setting up the PAL MCP Server from scratch, including installation, configuration, and first usage.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
@@ -77,11 +77,11 @@ Choose your AI coding assistant and add the corresponding configuration:
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"zen": {
|
||||
"pal": {
|
||||
"command": "sh",
|
||||
"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"
|
||||
"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/pal-mcp-server.git pal-mcp-server; done; echo 'uvx not found' >&2; exit 1"
|
||||
],
|
||||
"env": {
|
||||
"PATH": "/usr/local/bin:/usr/bin:/bin:/opt/homebrew/bin:~/.local/bin",
|
||||
@@ -98,11 +98,11 @@ Create `.mcp.json` in your project root:
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"zen": {
|
||||
"pal": {
|
||||
"command": "sh",
|
||||
"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"
|
||||
"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/pal-mcp-server.git pal-mcp-server; done; echo 'uvx not found' >&2; exit 1"
|
||||
],
|
||||
"env": {
|
||||
"PATH": "/usr/local/bin:/usr/bin:/bin:/opt/homebrew/bin:~/.local/bin",
|
||||
@@ -119,11 +119,11 @@ Edit `~/.gemini/settings.json`:
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"zen": {
|
||||
"pal": {
|
||||
"command": "sh",
|
||||
"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"
|
||||
"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/pal-mcp-server.git pal-mcp-server; done; echo 'uvx not found' >&2; exit 1"
|
||||
],
|
||||
"env": {
|
||||
"PATH": "/usr/local/bin:/usr/bin:/bin:/opt/homebrew/bin:~/.local/bin",
|
||||
@@ -138,17 +138,17 @@ Edit `~/.gemini/settings.json`:
|
||||
Edit `~/.codex/config.toml`:
|
||||
|
||||
```toml
|
||||
[mcp_servers.zen]
|
||||
[mcp_servers.pal]
|
||||
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"]
|
||||
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/pal-mcp-server.git pal-mcp-server; done; echo 'uvx not found' >&2; exit 1"]
|
||||
tool_timeout_sec = 1200 # 20 minutes; added automatically by the setup script so upstream providers can respond
|
||||
|
||||
[mcp_servers.zen.env]
|
||||
[mcp_servers.pal.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"
|
||||
```
|
||||
|
||||
Enable Codex's built-in web-search tool so Zen's `apilookup` instructions can execute successfully:
|
||||
Enable Codex's built-in web-search tool so PAL's `apilookup` instructions can execute successfully:
|
||||
|
||||
```toml
|
||||
[tools]
|
||||
@@ -164,13 +164,13 @@ Create or edit `~/.qwen/settings.json`:
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"zen": {
|
||||
"pal": {
|
||||
"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"
|
||||
"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/pal-mcp-server.git pal-mcp-server; done; echo 'uvx not found' >&2; exit 1"
|
||||
],
|
||||
"cwd": "/path/to/zen-mcp-server",
|
||||
"cwd": "/path/to/pal-mcp-server",
|
||||
"env": {
|
||||
"PATH": "/usr/local/bin:/usr/bin:/bin:/opt/homebrew/bin:~/.local/bin",
|
||||
"GEMINI_API_KEY": "your_api_key_here"
|
||||
@@ -189,13 +189,13 @@ Edit `~/.config/opencode/opencode.json`:
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"mcp": {
|
||||
"zen": {
|
||||
"pal": {
|
||||
"type": "local",
|
||||
"command": [
|
||||
"/path/to/zen-mcp-server/.zen_venv/bin/python",
|
||||
"/path/to/zen-mcp-server/server.py"
|
||||
"/path/to/pal-mcp-server/.pal_venv/bin/python",
|
||||
"/path/to/pal-mcp-server/server.py"
|
||||
],
|
||||
"cwd": "/path/to/zen-mcp-server",
|
||||
"cwd": "/path/to/pal-mcp-server",
|
||||
"enabled": true,
|
||||
"environment": {
|
||||
"GEMINI_API_KEY": "your_api_key_here"
|
||||
@@ -209,14 +209,14 @@ Add any other API keys you rely on (`OPENAI_API_KEY`, `OPENROUTER_API_KEY`, etc.
|
||||
|
||||
#### IDE Clients (Cursor & VS Code)
|
||||
|
||||
Zen works in GUI IDEs that speak MCP. The configuration mirrors the CLI examples above—point the client at the `uvx` launcher and set any required environment variables.
|
||||
PAL works in GUI IDEs that speak MCP. The configuration mirrors the CLI examples above—point the client at the `uvx` launcher and set any required environment variables.
|
||||
|
||||
**Cursor IDE**
|
||||
|
||||
1. Open Cursor → `Settings` (`Cmd+,`/`Ctrl+,`) → **Integrations › Model Context Protocol (MCP)**.
|
||||
2. Click **Add MCP Server** and supply the following values:
|
||||
- Command: `sh`
|
||||
- Args: `-c` and `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`
|
||||
- Args: `-c` and `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/pal-mcp-server.git pal-mcp-server; done; echo 'uvx not found' >&2; exit 1`
|
||||
- Environment (example):
|
||||
- `PATH=/usr/local/bin:/usr/bin:/bin:/opt/homebrew/bin:~/.local/bin`
|
||||
- `GEMINI_API_KEY=your_api_key_here`
|
||||
@@ -232,7 +232,7 @@ Zen works in GUI IDEs that speak MCP. The configuration mirrors the CLI examples
|
||||
- Environment: add the API keys you need (e.g. `GEMINI_API_KEY`, `OPENAI_API_KEY`)
|
||||
4. Save the JSON snippet the extension generates. VS Code will reload the server automatically the next time you interact with Claude.
|
||||
|
||||
👉 Pro tip: If you prefer a one-line command, replace the long loop with `uvx --from git+https://github.com/BeehiveInnovations/zen-mcp-server.git zen-mcp-server`—just make sure `uvx` is on your PATH for every client.
|
||||
👉 Pro tip: If you prefer a one-line command, replace the long loop with `uvx --from git+https://github.com/BeehiveInnovations/pal-mcp-server.git pal-mcp-server`—just make sure `uvx` is on your PATH for every client.
|
||||
|
||||
**Benefits of uvx method:**
|
||||
- ✅ Zero manual setup required
|
||||
@@ -244,8 +244,8 @@ Zen works in GUI IDEs that speak MCP. The configuration mirrors the CLI examples
|
||||
|
||||
```bash
|
||||
# Clone the repository
|
||||
git clone https://github.com/BeehiveInnovations/zen-mcp-server.git
|
||||
cd zen-mcp-server
|
||||
git clone https://github.com/BeehiveInnovations/pal-mcp-server.git
|
||||
cd pal-mcp-server
|
||||
|
||||
# One-command setup (handles everything)
|
||||
./run-server.sh
|
||||
@@ -305,7 +305,7 @@ CUSTOM_MODEL_NAME=llama3.2 # Default model name
|
||||
|
||||
## Prevent Client Timeouts
|
||||
|
||||
Some MCP clients default to short timeouts and can disconnect from Zen during long tool runs. Configure each client with a generous ceiling (we recommend at least five minutes); the Zen setup script now writes a 20-minute tool timeout for Codex so upstream providers contacted by the server have time to respond.
|
||||
Some MCP clients default to short timeouts and can disconnect from PAL during long tool runs. Configure each client with a generous ceiling (we recommend at least five minutes); the PAL setup script now writes a 20-minute tool timeout for Codex so upstream providers contacted by the server have time to respond.
|
||||
|
||||
### Claude Code & Claude Desktop
|
||||
|
||||
@@ -320,14 +320,14 @@ Claude reads MCP-related environment variables either from your shell or from `~
|
||||
}
|
||||
```
|
||||
|
||||
You can scope this block at the top level of `settings.json` (applies to every session) or under a specific `mcpServers.<name>.env` entry if you only want it for Zen. The values are in milliseconds. Note: Claude’s SSE transport still enforces an internal ceiling of roughly five minutes; long-running HTTP/SSE servers may need retries until Anthropic ships their fix.
|
||||
You can scope this block at the top level of `settings.json` (applies to every session) or under a specific `mcpServers.<name>.env` entry if you only want it for PAL (the server name may still be `pal` while configurations catch up). The values are in milliseconds. Note: Claude’s SSE transport still enforces an internal ceiling of roughly five minutes; long-running HTTP/SSE servers may need retries until Anthropic ships their fix.
|
||||
|
||||
### Codex CLI
|
||||
|
||||
Codex exposes per-server timeouts in `~/.codex/config.toml`. Add (or bump) these keys under `[[mcp_servers.<name>]]`:
|
||||
|
||||
```toml
|
||||
[mcp_servers.zen]
|
||||
[mcp_servers.pal]
|
||||
command = "..."
|
||||
args = ["..."]
|
||||
startup_timeout_sec = 300 # default is 10 seconds
|
||||
@@ -343,9 +343,9 @@ Gemini uses a single `timeout` field per server inside `~/.gemini/settings.json`
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"zen": {
|
||||
"pal": {
|
||||
"command": "uvx",
|
||||
"args": ["zen-mcp-server"],
|
||||
"args": ["pal-mcp-server"],
|
||||
"timeout": 300000
|
||||
}
|
||||
}
|
||||
@@ -364,62 +364,62 @@ Versions 0.2.1 and newer currently ignore values above ~60 seconds for some tran
|
||||
### For Claude Desktop:
|
||||
1. Restart Claude Desktop
|
||||
2. Open a new conversation
|
||||
3. Try: `"Use zen to list available models"`
|
||||
3. Try: `"Use pal to list available models"`
|
||||
|
||||
### For Claude Code CLI:
|
||||
1. Exit any existing Claude session
|
||||
2. Run `claude` from your project directory
|
||||
3. Try: `"Use zen to chat about Python best practices"`
|
||||
3. Try: `"Use pal to chat about Python best practices"`
|
||||
|
||||
### 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.
|
||||
**Note**: While PAL MCP connects to Gemini CLI, tool invocation isn't working correctly yet. See [Gemini CLI Setup](gemini-setup.md) for updates.
|
||||
|
||||
### For Qwen Code CLI:
|
||||
1. Restart the Qwen Code CLI if it's running (`qwen exit`).
|
||||
2. Run `qwen mcp list --scope user` and confirm `zen` shows `CONNECTED`.
|
||||
3. Try: `"/mcp"` to inspect available tools or `"Use zen to analyze this repo"`.
|
||||
2. Run `qwen mcp list --scope user` and confirm `pal` shows `CONNECTED`.
|
||||
3. Try: `"/mcp"` to inspect available tools or `"Use pal to analyze this repo"`.
|
||||
|
||||
### For OpenCode CLI:
|
||||
1. Restart OpenCode (or run `OpenCode: Reload Config`).
|
||||
2. Open **Settings › Tools › MCP** and confirm `zen` is enabled.
|
||||
3. Start a new chat and try: `"Use zen to list available models"`.
|
||||
2. Open **Settings › Tools › MCP** and confirm `pal` is enabled.
|
||||
3. Start a new chat and try: `"Use pal to list available models"`.
|
||||
|
||||
### For Codex CLI:
|
||||
1. Restart Codex CLI if running
|
||||
2. Open a new conversation
|
||||
3. Try: `"Use zen to list available models"`
|
||||
3. Try: `"Use pal to list available models"`
|
||||
|
||||
### Test Commands:
|
||||
```
|
||||
"Use zen to list available models"
|
||||
"Chat with zen about the best approach for API design"
|
||||
"Use zen thinkdeep with gemini pro about scaling strategies"
|
||||
"Use pal to list available models"
|
||||
"Chat with pal about the best approach for API design"
|
||||
"Use pal thinkdeep with gemini pro about scaling strategies"
|
||||
"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
|
||||
## Step 5: Start Using PAL
|
||||
|
||||
### Basic Usage Patterns:
|
||||
|
||||
**Let Claude pick the model:**
|
||||
```
|
||||
"Use zen to analyze this code for security issues"
|
||||
"Debug this race condition with zen"
|
||||
"Plan the database migration with zen"
|
||||
"Use pal to analyze this code for security issues"
|
||||
"Debug this race condition with pal"
|
||||
"Plan the database migration with pal"
|
||||
```
|
||||
|
||||
**Specify the model:**
|
||||
```
|
||||
"Use zen with gemini pro to review this complex algorithm"
|
||||
"Debug with o3 using zen for logical analysis"
|
||||
"Get flash to quickly format this code via zen"
|
||||
"Use pal with gemini pro to review this complex algorithm"
|
||||
"Debug with o3 using pal for logical analysis"
|
||||
"Get flash to quickly format this code via pal"
|
||||
```
|
||||
|
||||
**Multi-model workflows:**
|
||||
```
|
||||
"Use zen to get consensus from pro and o3 on this architecture"
|
||||
"Use pal to get consensus from pro and o3 on this architecture"
|
||||
"Code review with gemini, then precommit validation with o3"
|
||||
"Analyze with flash, then deep dive with pro if issues found"
|
||||
```
|
||||
@@ -435,7 +435,7 @@ Versions 0.2.1 and newer currently ignore values above ~60 seconds for some tran
|
||||
|
||||
## Common Issues and Solutions
|
||||
|
||||
### "zen not found" or "command not found"
|
||||
### "pal not found" or "command not found"
|
||||
|
||||
**For uvx installations:**
|
||||
- Ensure `uv` is installed and in PATH
|
||||
@@ -444,7 +444,7 @@ Versions 0.2.1 and newer currently ignore values above ~60 seconds for some tran
|
||||
|
||||
**For clone installations:**
|
||||
- Run `./run-server.sh` again to verify setup
|
||||
- Check virtual environment: `which python` should show `.zen_venv/bin/python`
|
||||
- Check virtual environment: `which python` should show `.pal_venv/bin/python`
|
||||
|
||||
### API Key Issues
|
||||
|
||||
@@ -454,7 +454,7 @@ Versions 0.2.1 and newer currently ignore values above ~60 seconds for some tran
|
||||
- Check for extra spaces or quotes around keys
|
||||
|
||||
**"Model not available":**
|
||||
- Run `"Use zen to list available models"` to see what's configured
|
||||
- Run `"Use pal to list available models"` to see what's configured
|
||||
- Check model restrictions in environment variables
|
||||
- Verify API key has access to requested models
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
# Zen MCP Server Documentation
|
||||
# PAL MCP Server Documentation
|
||||
|
||||
_Formerly known as PAL MCP. See the short [name change note](name-change.md) for context._
|
||||
|
||||
| Document | Description |
|
||||
|----------|-------------|
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Locale Configuration for Zen MCP Server
|
||||
# Locale Configuration for PAL MCP Server
|
||||
|
||||
This guide explains how to configure and use the localization feature to customize the language of responses from MCP tools.
|
||||
|
||||
|
||||
5
docs/name-change.md
Normal file
5
docs/name-change.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# PAL MCP Name Change
|
||||
|
||||
PAL MCP was previously called Zen MCP. We renamed to avoid confusion with another similarly named product and to better reflect our role as a Provider Abstraction Layer. The software and workflows are the same.
|
||||
|
||||
Due to the change of name, you may need to run `run-server.sh` again to setup the new connection, and re-visit any `ZEN` name used within `.env` and change it to `PAL`.
|
||||
@@ -5,7 +5,7 @@ Most importantly, it does this within in a sub-process / sub-agent, saving you p
|
||||
|
||||
## Why Use This Tool?
|
||||
|
||||
### Without Zen (Using Standard AI)
|
||||
### Without PAL (Using Standard AI)
|
||||
```
|
||||
User: "How do I add glass look to a button in Swift?"
|
||||
|
||||
@@ -17,11 +17,11 @@ Result: You get outdated APIs for iOS 18, not the iOS 26 effect you're after
|
||||
|
||||
<div align="center">
|
||||
|
||||
[API without Zen](https://github.com/user-attachments/assets/01a79dc9-ad16-4264-9ce1-76a56c3580ee)
|
||||
[API without PAL](https://github.com/user-attachments/assets/01a79dc9-ad16-4264-9ce1-76a56c3580ee)
|
||||
|
||||
</div>
|
||||
|
||||
### With Zen (Using apilookup)
|
||||
### With PAL (Using apilookup)
|
||||
```
|
||||
User: "use apilookup how do I add glass look to a button in swift?"
|
||||
|
||||
@@ -36,7 +36,7 @@ Result: You get the correct, current APIs that work with today's iOS version
|
||||
|
||||
<div align="center">
|
||||
|
||||
[API with Zen](https://github.com/user-attachments/assets/5c847326-4b66-41f7-8f30-f380453dce22)
|
||||
[API with PAL](https://github.com/user-attachments/assets/5c847326-4b66-41f7-8f30-f380453dce22)
|
||||
|
||||
</div>
|
||||
|
||||
@@ -110,7 +110,7 @@ The AI then performs the actual web searches and synthesizes the results into ac
|
||||
|
||||
## Codex CLI Configuration Reminder
|
||||
|
||||
If you use Zen through the Codex CLI, the assistant needs Codex's native web-search tool to fetch current documentation. After adding the Zen MCP entry to `~/.codex/config.toml`, confirm the file also contains:
|
||||
If you use PAL through the Codex CLI, the assistant needs Codex's native web-search tool to fetch current documentation. After adding the PAL MCP entry to `~/.codex/config.toml`, confirm the file also contains:
|
||||
|
||||
```toml
|
||||
[tools]
|
||||
|
||||
@@ -20,11 +20,11 @@ bigger picture or ignoring architectural constraints.
|
||||
`challenge` fixes this. Claude can even _detect_ when you're challenging something and automatically invokes this tool
|
||||
to ensure thoughtful analysis instead of reflexive agreement.
|
||||
|
||||
**Without Zen:**
|
||||

|
||||
**Without PAL:**
|
||||

|
||||
|
||||
**With Zen:**
|
||||

|
||||
**With PAL:**
|
||||

|
||||
|
||||
## Why Use Challenge?
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ word verdict in the end.
|
||||
|
||||
* We ask Claude code to pick one of two frameworks, then `chat` with `gemini` to make a final decision
|
||||
* Gemini responds, confirming choice. We use `continuation` to ask another question using the same conversation thread
|
||||
* Gemini responds with explanation. We use continuation again, using `/zen:continue (MCP)` command the second time
|
||||
* Gemini responds with explanation. We use continuation again, using `/pal:continue (MCP)` command the second time
|
||||
|
||||
<div style="center">
|
||||
|
||||
@@ -39,7 +39,7 @@ word verdict in the end.
|
||||
- **Collaborative thinking partner** for your analysis and planning
|
||||
- **Get second opinions** on your designs and approaches
|
||||
- **Brainstorm solutions** and explore alternatives together
|
||||
- **Structured code generation**: When using GPT-5.1 or Gemini 3.0 / 2.5 Pro, get complete, production-ready implementations saved to `zen_generated.code` for your CLI to review and apply
|
||||
- **Structured code generation**: When using GPT-5.1 or Gemini 3.0 / 2.5 Pro, get complete, production-ready implementations saved to `pal_generated.code` for your CLI to review and apply
|
||||
- **Validate your checklists** and implementation plans
|
||||
- **General development questions** and explanations
|
||||
- **Technology comparisons** and best practices
|
||||
@@ -67,8 +67,8 @@ When using advanced reasoning models like **GPT-5 Pro** or **Gemini 3.0 Pro**, t
|
||||
### How It Works
|
||||
|
||||
1. You ask your AI agent to implement a complex new feature using `chat` with a higher-reasoning model such as **GPT-5 Pro** or **Gemini 3.0 Pro**
|
||||
2. The model generates structured implementation and shares the complete implementation with Zen
|
||||
3. Zen saves the code to `zen_generated.code` and asks AI agent to implement the plan
|
||||
2. The model generates structured implementation and shares the complete implementation with PAL
|
||||
3. PAL saves the code to `pal_generated.code` and asks AI agent to implement the plan
|
||||
4. AI agent continues from the previous context, reads the file, applies the implementation
|
||||
|
||||
### When Code Generation Activates
|
||||
@@ -101,7 +101,7 @@ See the [Configuration Guide](../configuration.md#code-generation-capability) fo
|
||||
|
||||
**Basic Development Chat:**
|
||||
```
|
||||
"Chat with zen about the best approach for user authentication in my React app"
|
||||
"Chat with pal about the best approach for user authentication in my React app"
|
||||
```
|
||||
|
||||
**Technology Comparison:**
|
||||
|
||||
@@ -53,7 +53,7 @@ Gemini receives the full conversation context from `consensus` including the con
|
||||
- **Role-based prompts**: Pre-configured roles for planning, code review, or general questions
|
||||
- **Full CLI capabilities**: Gemini can use its own web search, file tools, and latest features
|
||||
- **Token efficiency**: File references (not full content) to conserve tokens
|
||||
- **Cross-tool collaboration**: Combine with other Zen tools like `planner` → `clink` → `codereview`
|
||||
- **Cross-tool collaboration**: Combine with other PAL tools like `planner` → `clink` → `codereview`
|
||||
- **Free tier available**: Gemini offers 1,000 requests/day free with a personal Google account - great for cost savings across tools
|
||||
|
||||
## Available Roles
|
||||
@@ -120,18 +120,18 @@ then codereview to verify the implementation"
|
||||
## How Clink Works
|
||||
|
||||
1. **Your request** - You ask your current CLI to use `clink` with a specific CLI and role
|
||||
2. **Background execution** - Zen spawns the configured CLI (e.g., `gemini --output-format json`)
|
||||
2. **Background execution** - PAL spawns the configured CLI (e.g., `gemini --output-format json`)
|
||||
3. **Context forwarding** - Your prompt, files (as references), and conversation history are sent as part of the prompt
|
||||
4. **CLI processing** - Gemini (or other CLI) uses its own tools: web search, file access, thinking modes
|
||||
5. **Seamless return** - Results flow back into your conversation with full context preserved
|
||||
6. **Continuation support** - Future tools and models can reference Gemini's findings via [continuation support](../context-revival.md) within Zen.
|
||||
6. **Continuation support** - Future tools and models can reference Gemini's findings via [continuation support](../context-revival.md) within PAL.
|
||||
|
||||
## Best Practices
|
||||
|
||||
- **Pre-authenticate CLIs**: Install and configure Gemini CLI first (`npm install -g @google/gemini-cli`)
|
||||
- **Choose appropriate roles**: Use `planner` for strategy, `codereviewer` for code, `default` for general questions
|
||||
- **Leverage CLI strengths**: Gemini's 1M context for large codebases, web search for current docs
|
||||
- **Combine with Zen tools**: Chain `clink` with `planner`, `codereview`, `debug` for powerful workflows
|
||||
- **Combine with PAL tools**: Chain `clink` with `planner`, `codereview`, `debug` for powerful workflows
|
||||
- **File efficiency**: Pass file paths, let the CLI decide what to read (saves tokens)
|
||||
|
||||
## Configuration
|
||||
@@ -153,9 +153,9 @@ Each preset points to role-specific prompts in `systemprompts/clink/`. Duplicate
|
||||
## When to Use Clink vs Other Tools
|
||||
|
||||
- **Use `clink`** for: Leveraging external CLI capabilities (Gemini's web search, 1M context), specialized CLI features, cross-CLI collaboration
|
||||
- **Use `chat`** for: Direct model-to-model conversations within Zen
|
||||
- **Use `planner`** for: Zen's native planning workflows with step validation
|
||||
- **Use `codereview`** for: Zen's structured code review with severity levels
|
||||
- **Use `chat`** for: Direct model-to-model conversations within PAL
|
||||
- **Use `planner`** for: PAL's native planning workflows with step validation
|
||||
- **Use `codereview`** for: PAL's structured code review with severity levels
|
||||
|
||||
## Setup Requirements
|
||||
|
||||
@@ -168,7 +168,7 @@ Ensure the relevant CLI is installed and configured:
|
||||
## Related Guides
|
||||
|
||||
- [Chat Tool](chat.md) - Direct model conversations
|
||||
- [Planner Tool](planner.md) - Zen's native planning workflows
|
||||
- [Planner Tool](planner.md) - PAL's native planning workflows
|
||||
- [CodeReview Tool](codereview.md) - Structured code reviews
|
||||
- [Context Revival](../context-revival.md) - Continuing conversations across tools
|
||||
- [Advanced Usage](../advanced-usage.md) - Complex multi-tool workflows
|
||||
|
||||
@@ -27,7 +27,7 @@ The following is a hypothetical example designed to demonstrate how one consensu
|
||||
|
||||
<div style="center">
|
||||
|
||||
[Zen Consensus Debate](https://github.com/user-attachments/assets/76a23dd5-887a-4382-9cf0-642f5cf6219e)
|
||||
[PAL Consensus Debate](https://github.com/user-attachments/assets/76a23dd5-887a-4382-9cf0-642f5cf6219e)
|
||||
|
||||
</div>
|
||||
|
||||
@@ -35,7 +35,7 @@ The following is a hypothetical example designed to demonstrate how one consensu
|
||||
|
||||
**For/Against Analysis:**
|
||||
```
|
||||
Use zen consensus with flash taking a supportive stance and pro being critical to evaluate whether
|
||||
Use pal consensus with flash taking a supportive stance and pro being critical to evaluate whether
|
||||
we should migrate from REST to GraphQL for our API
|
||||
```
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ Documentation generation excels with analytical models like Gemini Pro or O3, wh
|
||||
|
||||
**Basic Usage:**
|
||||
```
|
||||
"Use zen to generate documentation for the UserManager class"
|
||||
"Use pal to generate documentation for the UserManager class"
|
||||
"Document the authentication module with complexity analysis using gemini pro"
|
||||
"Add comprehensive documentation to all methods in src/payment_processor.py"
|
||||
```
|
||||
|
||||
@@ -7,7 +7,7 @@ The `listmodels` tool shows which providers are configured, available models, th
|
||||
## Usage
|
||||
|
||||
```
|
||||
"Use zen to list available models"
|
||||
"Use pal to list available models"
|
||||
```
|
||||
|
||||
## Key Features
|
||||
|
||||
@@ -19,7 +19,7 @@ The planner tool enables step-by-step thinking with incremental plan building:
|
||||
|
||||
#### Pro Tip
|
||||
Claude supports `sub-tasks` where it will spawn and run separate background tasks. You can ask Claude to
|
||||
run Zen's planner with two separate ideas. Then when it's done, use Zen's `consensus` tool to pass the entire
|
||||
run PAL's planner with two separate ideas. Then when it's done, use PAL's `consensus` tool to pass the entire
|
||||
plan and get expert perspective from two powerful AI models on which one to work on first! Like performing **AB** testing
|
||||
in one-go without the wait!
|
||||
|
||||
@@ -31,7 +31,7 @@ I implement first?
|
||||
```
|
||||
|
||||
```
|
||||
Use zen's planner and show me how to add real-time notifications to our mobile app
|
||||
Use pal's planner and show me how to add real-time notifications to our mobile app
|
||||
```
|
||||
|
||||
```
|
||||
@@ -55,11 +55,11 @@ Using planner, plan the architecture for a new real-time chat system with 100k c
|
||||
```
|
||||
|
||||
```
|
||||
Create a plan using zen for migrating our React app from JavaScript to TypeScript
|
||||
Create a plan using pal for migrating our React app from JavaScript to TypeScript
|
||||
```
|
||||
|
||||
```
|
||||
Develop a plan using zen for implementing CI/CD pipelines across our development teams
|
||||
Develop a plan using pal for implementing CI/CD pipelines across our development teams
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
@@ -73,10 +73,10 @@ Develop a plan using zen for implementing CI/CD pipelines across our development
|
||||
|
||||
## Continue With a New Plan
|
||||
|
||||
Like all other tools in Zen, you can `continue` with a new plan using the output from a previous plan by simply saying
|
||||
Like all other tools in PAL, you can `continue` with a new plan using the output from a previous plan by simply saying
|
||||
|
||||
```
|
||||
Continue with zen's consensus tool and find out what o3:for and flash:against think of the plan
|
||||
Continue with pal's consensus tool and find out what o3:for and flash:against think of the plan
|
||||
```
|
||||
|
||||
You can mix and match and take one output and feed it into another, continuing from where you left off using a different
|
||||
|
||||
@@ -32,7 +32,7 @@ After Claude completes the investigation (unless precommit_type is **internal**)
|
||||
- Default validation type is **external** (uses expert model for additional review)
|
||||
- To skip expert validation, explicitly request "don't use any other model" or set precommit_type to "internal"
|
||||
- **CRITICAL**: Minimum 3 steps are enforced - tool will prevent setting `next_step_required=false` before final step
|
||||
- **MANDATORY**: Changeset file (zen_precommit.changeset) must be created for external validation
|
||||
- **MANDATORY**: Changeset file (pal_precommit.changeset) must be created for external validation
|
||||
|
||||
## Model Recommendation
|
||||
|
||||
@@ -62,7 +62,7 @@ passing, it went ahead with an initial review with O3; came back clean - all goo
|
||||
Then it shared the changes and relevant code with Gemini 3.0 Pro - the following is the outcome:
|
||||
|
||||
```
|
||||
⏺ zen:precommit (MCP)(step: "FINAL VALIDATION COMPLETE. All changes have been thoroughly analyzed and are ready for
|
||||
⏺ pal:precommit (MCP)(step: "FINAL VALIDATION COMPLETE. All changes have been thoroughly analyzed and are ready for
|
||||
commit. The modifications successfully fix 4 GitHub CI test failures with high-quality, defensive
|
||||
implementations that maintain architectural integrity and coding standards. No issues or regressions
|
||||
detected.", step_number: 4, total_steps: 4, next_step_required: false, findings: "COMMIT
|
||||
@@ -101,12 +101,12 @@ Then it shared the changes and relevant code with Gemini 3.0 Pro - the following
|
||||
- Fix Required: Apply the same defensive pattern to the missed location
|
||||
```
|
||||
|
||||
A subtle but critical issue spotted by Gemini that both Claude + O3 missed. This is the power of running these workflows with Zen.
|
||||
A subtle but critical issue spotted by Gemini that both Claude + O3 missed. This is the power of running these workflows with PAL.
|
||||
|
||||
## Example Prompts
|
||||
|
||||
```
|
||||
Use zen and perform a thorough precommit ensuring there aren't any new regressions or bugs introduced
|
||||
Use pal and perform a thorough precommit ensuring there aren't any new regressions or bugs introduced
|
||||
```
|
||||
|
||||
## Key Features
|
||||
@@ -155,7 +155,7 @@ Use zen and perform a thorough precommit ensuring there aren't any new regressio
|
||||
|
||||
**Basic Pre-commit Validation:**
|
||||
```
|
||||
"Use zen precommit to validate my changes before committing"
|
||||
"Use pal precommit to validate my changes before committing"
|
||||
```
|
||||
|
||||
**Security-Focused Validation:**
|
||||
|
||||
@@ -35,13 +35,13 @@ The refactor tool excels with models that have large context windows like Gemini
|
||||
|
||||
```
|
||||
"Use gemini pro to decompose my_crazy_big_class.m into smaller extensions"
|
||||
"Using zen's refactor decompose the all_in_one_sync_code.swift into maintainable extensions"
|
||||
"Using pal's refactor decompose the all_in_one_sync_code.swift into maintainable extensions"
|
||||
```
|
||||
|
||||
💡**Example of a powerful prompt** to get the best out of both Claude + Flash's 1M Context:
|
||||
```
|
||||
"First, think about how the authentication module works, find related classes and find
|
||||
any code smells, then using zen's refactor ask flash to confirm your findings but ask
|
||||
any code smells, then using pal's refactor ask flash to confirm your findings but ask
|
||||
it to find additional code smells and any other quick-wins and then fix these issues"
|
||||
```
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ Test generation excels with extended reasoning models like Gemini Pro or O3, whi
|
||||
|
||||
**Basic Usage:**
|
||||
```
|
||||
"Use zen to generate tests for User.login() method"
|
||||
"Use pal to generate tests for User.login() method"
|
||||
"Generate comprehensive tests for the sorting method in src/new_sort.py using o3"
|
||||
"Create tests for edge cases not already covered in our tests using gemini pro"
|
||||
```
|
||||
|
||||
@@ -36,13 +36,13 @@ The `tracer` tool is a specialized prompt-generation tool that creates structure
|
||||
|
||||
**Method Execution Tracing:**
|
||||
```
|
||||
"Use zen tracer to analyze how UserAuthManager.authenticate is used and why"
|
||||
"Use pal tracer to analyze how UserAuthManager.authenticate is used and why"
|
||||
```
|
||||
→ Uses `precision` mode to trace the method's execution flow
|
||||
|
||||
**Class Dependency Mapping:**
|
||||
```
|
||||
"Use zen to generate a dependency trace for the PaymentProcessor class to understand its relationships"
|
||||
"Use pal to generate a dependency trace for the PaymentProcessor class to understand its relationships"
|
||||
```
|
||||
→ Uses `dependencies` mode to map structural relationships
|
||||
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
|
||||
**Get server version, configuration details, and list of available tools**
|
||||
|
||||
The `version` tool provides information about the Zen MCP Server version, configuration details, and system capabilities. This is useful for debugging, understanding server capabilities, and verifying your installation.
|
||||
The `version` tool provides information about the PAL MCP Server version, configuration details, and system capabilities. This is useful for debugging, understanding server capabilities, and verifying your installation.
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
"Get zen to show its version"
|
||||
"Get pal to show its version"
|
||||
```
|
||||
|
||||
## Key Features
|
||||
@@ -48,7 +48,7 @@ The tool provides:
|
||||
## Example Output
|
||||
|
||||
```
|
||||
🔧 Zen MCP Server Information
|
||||
🔧 PAL MCP Server Information
|
||||
|
||||
📋 Version: 2.15.0
|
||||
🏗️ Build: 2024-01-15T10:30:00Z (commit: abc123f)
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
|
||||
## Quick Debugging Steps
|
||||
|
||||
If you're experiencing issues with the Zen MCP Server, follow these steps:
|
||||
If you're experiencing issues with the PAL MCP Server, follow these steps:
|
||||
|
||||
### 1. Check MCP Connection
|
||||
|
||||
Open Claude Desktop and type `/mcp` to see if zen is connected:
|
||||
- ✅ If zen appears in the list, the connection is working
|
||||
Open Claude Desktop and type `/mcp` to see if pal is connected:
|
||||
- ✅ If pal appears in the list, the connection is working
|
||||
- ❌ If not listed or shows an error, continue to step 2
|
||||
|
||||
### 2. Launch Claude with Debug Mode
|
||||
@@ -79,14 +79,14 @@ See [Logging Documentation](logging.md) for more details on accessing logs.
|
||||
|
||||
**Python module not found**
|
||||
- Run `./run-server.sh` to reinstall dependencies
|
||||
- Check virtual environment is activated: should see `.zen_venv` in the Python path
|
||||
- Check virtual environment is activated: should see `.pal_venv` in the Python path
|
||||
|
||||
### 6. Environment Issues
|
||||
|
||||
**Virtual Environment Problems**
|
||||
```bash
|
||||
# Reset environment completely
|
||||
rm -rf .zen_venv
|
||||
rm -rf .pal_venv
|
||||
./run-server.sh
|
||||
```
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# WSL (Windows Subsystem for Linux) Setup Guide
|
||||
|
||||
This guide provides detailed instructions for setting up Zen MCP Server on Windows using WSL.
|
||||
This guide provides detailed instructions for setting up PAL MCP Server on Windows using WSL.
|
||||
|
||||
## Prerequisites for WSL
|
||||
|
||||
@@ -27,8 +27,8 @@ npm install -g @anthropic-ai/claude-code
|
||||
cd ~
|
||||
|
||||
# Clone the repository
|
||||
git clone https://github.com/BeehiveInnovations/zen-mcp-server.git
|
||||
cd zen-mcp-server
|
||||
git clone https://github.com/BeehiveInnovations/pal-mcp-server.git
|
||||
cd pal-mcp-server
|
||||
```
|
||||
|
||||
2. **Run the setup script**:
|
||||
@@ -43,7 +43,7 @@ npm install -g @anthropic-ai/claude-code
|
||||
# List configured MCP servers
|
||||
claude mcp list
|
||||
|
||||
# You should see 'zen' listed in the output
|
||||
# You should see 'pal' listed in the output
|
||||
# If not, the setup script will provide the correct configuration
|
||||
```
|
||||
|
||||
@@ -61,19 +61,19 @@ python3 -m pip install --upgrade pip
|
||||
|
||||
### Path Issues
|
||||
|
||||
- Always use the full WSL path for MCP configuration (e.g., `/home/YourName/zen-mcp-server/`)
|
||||
- Always use the full WSL path for MCP configuration (e.g., `/home/YourName/pal-mcp-server/`)
|
||||
- The setup script automatically detects WSL and configures the correct paths
|
||||
|
||||
### Claude Code Connection Issues
|
||||
|
||||
```bash
|
||||
# If Claude Code can't connect to the MCP server, check the configuration
|
||||
cat ~/.claude.json | grep -A 10 "zen"
|
||||
cat ~/.claude.json | grep -A 10 "pal"
|
||||
|
||||
# The configuration should show the correct WSL path to the Python executable
|
||||
# Example: "/home/YourName/zen-mcp-server/.zen_venv/bin/python"
|
||||
# Example: "/home/YourName/pal-mcp-server/.pal_venv/bin/python"
|
||||
```
|
||||
|
||||
### Performance Tip
|
||||
|
||||
For best performance, keep your zen-mcp-server directory in the WSL filesystem (e.g., `~/zen-mcp-server`) rather than in the Windows filesystem (`/mnt/c/...`).
|
||||
For best performance, keep your pal-mcp-server directory in the WSL filesystem (e.g., `~/pal-mcp-server`) rather than in the Windows filesystem (`/mnt/c/...`).
|
||||
@@ -3,9 +3,9 @@
|
||||
"comment2": "Run './run-server.sh' to set up the environment and get exact paths",
|
||||
"comment3": "Use './run-server.sh -c' to display the correct configuration",
|
||||
"mcpServers": {
|
||||
"zen": {
|
||||
"command": "/path/to/zen-mcp-server/.zen_venv/bin/python",
|
||||
"args": ["/path/to/zen-mcp-server/server.py"]
|
||||
"pal": {
|
||||
"command": "/path/to/pal-mcp-server/.pal_venv/bin/python",
|
||||
"args": ["/path/to/pal-mcp-server/server.py"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,11 +3,11 @@
|
||||
"comment2": "Run './run-server.sh' in WSL to set up the environment and get exact paths",
|
||||
"comment3": "Use './run-server.sh -c' to display the correct configuration",
|
||||
"mcpServers": {
|
||||
"zen": {
|
||||
"pal": {
|
||||
"command": "wsl.exe",
|
||||
"args": [
|
||||
"/path/to/zen-mcp-server/.zen_venv/bin/python",
|
||||
"/path/to/zen-mcp-server/server.py"
|
||||
"/path/to/pal-mcp-server/.pal_venv/bin/python",
|
||||
"/path/to/pal-mcp-server/server.py"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
# Get the directory of this script
|
||||
DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
|
||||
# Change to the zen-mcp-server directory
|
||||
# Change to the pal-mcp-server directory
|
||||
cd "$DIR"
|
||||
|
||||
# Execute the Python server with all arguments passed through
|
||||
exec .zen_venv/bin/python server.py "$@"
|
||||
exec .pal_venv/bin/python server.py "$@"
|
||||
@@ -35,9 +35,9 @@ class OpenRouterProvider(OpenAICompatibleProvider):
|
||||
|
||||
# Custom headers required by OpenRouter
|
||||
DEFAULT_HEADERS = {
|
||||
"HTTP-Referer": get_env("OPENROUTER_REFERER", "https://github.com/BeehiveInnovations/zen-mcp-server")
|
||||
or "https://github.com/BeehiveInnovations/zen-mcp-server",
|
||||
"X-Title": get_env("OPENROUTER_TITLE", "Zen MCP Server") or "Zen MCP Server",
|
||||
"HTTP-Referer": get_env("OPENROUTER_REFERER", "https://github.com/BeehiveInnovations/pal-mcp-server")
|
||||
or "https://github.com/BeehiveInnovations/pal-mcp-server",
|
||||
"X-Title": get_env("OPENROUTER_TITLE", "PAL MCP Server") or "PAL MCP Server",
|
||||
}
|
||||
|
||||
# Model registry for managing configurations and aliases
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "zen-mcp-server"
|
||||
version = "9.4.1"
|
||||
name = "pal-mcp-server"
|
||||
version = "9.4.2"
|
||||
description = "AI-powered MCP server with multiple model providers"
|
||||
requires-python = ">=3.9"
|
||||
dependencies = [
|
||||
@@ -36,7 +36,7 @@ py-modules = ["server", "config"]
|
||||
]
|
||||
|
||||
[project.scripts]
|
||||
zen-mcp-server = "server:run"
|
||||
pal-mcp-server = "server:run"
|
||||
|
||||
[tool.black]
|
||||
line-length = 120
|
||||
@@ -51,7 +51,7 @@ extend-exclude = '''
|
||||
| \.mypy_cache
|
||||
| \.tox
|
||||
| \.venv
|
||||
| \.zen_venv
|
||||
| \.pal_venv
|
||||
| venv
|
||||
| _build
|
||||
| buck-out
|
||||
@@ -68,7 +68,7 @@ force_grid_wrap = 0
|
||||
use_parentheses = true
|
||||
ensure_newline_before_comments = true
|
||||
line_length = 120
|
||||
skip_glob = ["venv/*", ".venv/*", ".zen_venv/*"]
|
||||
skip_glob = ["venv/*", ".venv/*", ".pal_venv/*"]
|
||||
|
||||
[tool.ruff]
|
||||
target-version = "py39"
|
||||
|
||||
320
run-server.ps1
320
run-server.ps1
@@ -1,9 +1,9 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Installation, configuration, and launch script for Zen MCP server on Windows.
|
||||
Installation, configuration, and launch script for PAL MCP server on Windows.
|
||||
|
||||
.DESCRIPTION
|
||||
This PowerShell script prepares the environment for the Zen MCP server:
|
||||
This PowerShell script prepares the environment for the PAL MCP server:
|
||||
- Installs and checks Python 3.10+ (with venv or uv if available)
|
||||
- Installs required Python dependencies
|
||||
- Configures environment files (.env)
|
||||
@@ -17,7 +17,7 @@
|
||||
Shows script help.
|
||||
|
||||
.PARAMETER Version
|
||||
Shows Zen MCP server version.
|
||||
Shows PAL MCP server version.
|
||||
|
||||
.PARAMETER Follow
|
||||
Follows server logs in real time.
|
||||
@@ -48,7 +48,7 @@
|
||||
|
||||
.EXAMPLE
|
||||
.\run-server.ps1
|
||||
Prepares the environment and starts the Zen MCP server.
|
||||
Prepares the environment and starts the PAL MCP server.
|
||||
|
||||
.\run-server.ps1 -Follow
|
||||
Follows server logs in real time.
|
||||
@@ -73,7 +73,7 @@
|
||||
Script Author : GiGiDKR (https://github.com/GiGiDKR)
|
||||
Date : 07-05-2025
|
||||
Version : See config.py (__version__)
|
||||
References : https://github.com/BeehiveInnovations/zen-mcp-server
|
||||
References : https://github.com/BeehiveInnovations/pal-mcp-server
|
||||
|
||||
#>
|
||||
#Requires -Version 5.1
|
||||
@@ -93,7 +93,7 @@ param(
|
||||
)
|
||||
|
||||
# ============================================================================
|
||||
# Zen MCP Server Setup Script for Windows
|
||||
# PAL MCP Server Setup Script for Windows
|
||||
#
|
||||
# A Windows-compatible setup script that handles environment setup,
|
||||
# dependency installation, and configuration.
|
||||
@@ -106,11 +106,12 @@ $ErrorActionPreference = "Stop"
|
||||
# Constants and Configuration
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
$script:VENV_PATH = ".zen_venv"
|
||||
$script:VENV_PATH = ".pal_venv"
|
||||
$script:DOCKER_CLEANED_FLAG = ".docker_cleaned"
|
||||
$script:DESKTOP_CONFIG_FLAG = ".desktop_configured"
|
||||
$script:LOG_DIR = "logs"
|
||||
$script:LOG_FILE = "mcp_server.log"
|
||||
$script:LegacyServerNames = @("zen", "zen-mcp", "zen-mcp-server", "zen_mcp", "zen_mcp_server")
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Utility Functions
|
||||
@@ -209,6 +210,31 @@ function Remove-LockedDirectory {
|
||||
}
|
||||
}
|
||||
|
||||
# Remove legacy MCP server entries from a hash/dictionary or PSObject
|
||||
function Remove-LegacyServerKeys {
|
||||
param([object]$Container)
|
||||
|
||||
$removed = $false
|
||||
if ($null -eq $Container) {
|
||||
return $false
|
||||
}
|
||||
|
||||
foreach ($legacy in $script:LegacyServerNames) {
|
||||
if ($Container -is [System.Collections.IDictionary]) {
|
||||
if ($Container.Contains($legacy)) {
|
||||
$Container.Remove($legacy) | Out-Null
|
||||
$removed = $true
|
||||
}
|
||||
}
|
||||
elseif ($Container.PSObject -and $Container.PSObject.Properties[$legacy]) {
|
||||
$Container.PSObject.Properties.Remove($legacy)
|
||||
$removed = $true
|
||||
}
|
||||
}
|
||||
|
||||
return $removed
|
||||
}
|
||||
|
||||
# Manage configuration file backups with maximum 3 files retention
|
||||
function Manage-ConfigBackups {
|
||||
param(
|
||||
@@ -382,9 +408,9 @@ function Cleanup-Docker {
|
||||
$containers = @(
|
||||
"gemini-mcp-server",
|
||||
"gemini-mcp-redis",
|
||||
"zen-mcp-server",
|
||||
"zen-mcp-redis",
|
||||
"zen-mcp-log-monitor"
|
||||
"pal-mcp-server",
|
||||
"pal-mcp-redis",
|
||||
"pal-mcp-log-monitor"
|
||||
)
|
||||
|
||||
# Remove containers
|
||||
@@ -407,7 +433,7 @@ function Cleanup-Docker {
|
||||
}
|
||||
|
||||
# Remove images
|
||||
$images = @("gemini-mcp-server:latest", "zen-mcp-server:latest")
|
||||
$images = @("gemini-mcp-server:latest", "pal-mcp-server:latest")
|
||||
foreach ($image in $images) {
|
||||
try {
|
||||
$exists = docker images --format "{{.Repository}}:{{.Tag}}" | Where-Object { $_ -eq $image }
|
||||
@@ -786,7 +812,7 @@ function Build-DockerImage {
|
||||
|
||||
# Check if image exists
|
||||
try {
|
||||
$imageExists = docker images --format "{{.Repository}}:{{.Tag}}" | Where-Object { $_ -eq "zen-mcp-server:latest" }
|
||||
$imageExists = docker images --format "{{.Repository}}:{{.Tag}}" | Where-Object { $_ -eq "pal-mcp-server:latest" }
|
||||
if ($imageExists -and !$Force) {
|
||||
Write-Success "Docker image already exists. Use -Force to rebuild."
|
||||
return $true
|
||||
@@ -799,7 +825,7 @@ function Build-DockerImage {
|
||||
if ($Force -and $imageExists) {
|
||||
Write-Info "Forcing rebuild of Docker image..."
|
||||
try {
|
||||
docker rmi zen-mcp-server:latest 2>$null
|
||||
docker rmi pal-mcp-server:latest 2>$null
|
||||
}
|
||||
catch {
|
||||
Write-Warning "Could not remove existing image, continuing..."
|
||||
@@ -814,7 +840,7 @@ function Build-DockerImage {
|
||||
Write-Info "Building with development support..."
|
||||
}
|
||||
|
||||
docker build -t zen-mcp-server:latest .
|
||||
docker build -t pal-mcp-server:latest .
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "Docker build failed"
|
||||
}
|
||||
@@ -901,7 +927,7 @@ function Start-DockerServices {
|
||||
}
|
||||
|
||||
# Start services
|
||||
Write-Info "Starting Zen MCP Server with Docker Compose..."
|
||||
Write-Info "Starting PAL MCP Server with Docker Compose..."
|
||||
if (Test-Command "docker-compose") {
|
||||
if ($Follow) {
|
||||
docker-compose up --build
|
||||
@@ -925,10 +951,10 @@ function Start-DockerServices {
|
||||
|
||||
if (!$Follow) {
|
||||
Write-Success "Docker services started successfully"
|
||||
Write-Info "Container name: zen-mcp-server"
|
||||
Write-Info "Container name: pal-mcp-server"
|
||||
Write-Host ""
|
||||
Write-Host "To view logs: " -NoNewline
|
||||
Write-Host "docker logs -f zen-mcp-server" -ForegroundColor Yellow
|
||||
Write-Host "docker logs -f pal-mcp-server" -ForegroundColor Yellow
|
||||
Write-Host "To stop: " -NoNewline
|
||||
Write-Host "docker-compose down" -ForegroundColor Yellow
|
||||
}
|
||||
@@ -944,7 +970,7 @@ function Start-DockerServices {
|
||||
# Get Docker container status
|
||||
function Get-DockerStatus {
|
||||
try {
|
||||
$containerStatus = docker ps --filter "name=zen-mcp-server" --format "{{.Status}}"
|
||||
$containerStatus = docker ps --filter "name=pal-mcp-server" --format "{{.Status}}"
|
||||
if ($containerStatus) {
|
||||
Write-Success "Container status: $containerStatus"
|
||||
return $true
|
||||
@@ -1018,7 +1044,7 @@ $script:McpClientDefinitions = @(
|
||||
DetectionPath = "$env:APPDATA\Claude\claude_desktop_config.json"
|
||||
DetectionType = "Path"
|
||||
ConfigPath = "$env:APPDATA\Claude\claude_desktop_config.json"
|
||||
ConfigJsonPath = "mcpServers.zen"
|
||||
ConfigJsonPath = "mcpServers.pal"
|
||||
NeedsConfigDir = $true
|
||||
},
|
||||
@{
|
||||
@@ -1026,7 +1052,7 @@ $script:McpClientDefinitions = @(
|
||||
DetectionCommand = "code"
|
||||
DetectionType = "Command"
|
||||
ConfigPath = "$env:APPDATA\Code\User\settings.json"
|
||||
ConfigJsonPath = "mcp.servers.zen"
|
||||
ConfigJsonPath = "mcp.servers.pal"
|
||||
IsVSCode = $true
|
||||
},
|
||||
@{
|
||||
@@ -1034,7 +1060,7 @@ $script:McpClientDefinitions = @(
|
||||
DetectionCommand = "code-insiders"
|
||||
DetectionType = "Command"
|
||||
ConfigPath = "$env:APPDATA\Code - Insiders\User\mcp.json"
|
||||
ConfigJsonPath = "servers.zen"
|
||||
ConfigJsonPath = "servers.pal"
|
||||
IsVSCodeInsiders = $true
|
||||
},
|
||||
@{
|
||||
@@ -1042,28 +1068,28 @@ $script:McpClientDefinitions = @(
|
||||
DetectionCommand = "cursor"
|
||||
DetectionType = "Command"
|
||||
ConfigPath = "$env:USERPROFILE\.cursor\mcp.json"
|
||||
ConfigJsonPath = "mcpServers.zen"
|
||||
ConfigJsonPath = "mcpServers.pal"
|
||||
},
|
||||
@{
|
||||
Name = "Windsurf"
|
||||
DetectionPath = "$env:USERPROFILE\.codeium\windsurf"
|
||||
DetectionType = "Path"
|
||||
ConfigPath = "$env:USERPROFILE\.codeium\windsurf\mcp_config.json"
|
||||
ConfigJsonPath = "mcpServers.zen"
|
||||
ConfigJsonPath = "mcpServers.pal"
|
||||
},
|
||||
@{
|
||||
Name = "Trae"
|
||||
DetectionPath = "$env:APPDATA\Trae"
|
||||
DetectionType = "Path"
|
||||
ConfigPath = "$env:APPDATA\Trae\User\mcp.json"
|
||||
ConfigJsonPath = "mcpServers.zen"
|
||||
ConfigJsonPath = "mcpServers.pal"
|
||||
}
|
||||
)
|
||||
|
||||
# Docker MCP configuration template (legacy, kept for backward compatibility)
|
||||
$script:DockerMcpConfig = @{
|
||||
command = "docker"
|
||||
args = @("exec", "-i", "zen-mcp-server", "python", "server.py")
|
||||
args = @("exec", "-i", "pal-mcp-server", "python", "server.py")
|
||||
type = "stdio"
|
||||
}
|
||||
|
||||
@@ -1076,7 +1102,7 @@ function Get-DockerMcpConfigRun {
|
||||
|
||||
return @{
|
||||
command = "docker"
|
||||
args = @("run", "--rm", "-i", "--env-file", $envFile, "zen-mcp-server:latest", "python", "server.py")
|
||||
args = @("run", "--rm", "-i", "--env-file", $envFile, "pal-mcp-server:latest", "python", "server.py")
|
||||
type = "stdio"
|
||||
}
|
||||
}
|
||||
@@ -1103,7 +1129,7 @@ function Test-McpJsonFormat {
|
||||
function Test-VSCodeInsidersFormat {
|
||||
param([hashtable]$Client)
|
||||
|
||||
return $Client.IsVSCodeInsiders -eq $true -and $Client.ConfigJsonPath -eq "servers.zen"
|
||||
return $Client.IsVSCodeInsiders -eq $true -and $Client.ConfigJsonPath -eq "servers.pal"
|
||||
}
|
||||
|
||||
# Analyze existing MCP configuration to determine type (Python or Docker)
|
||||
@@ -1133,9 +1159,9 @@ function Get-ExistingMcpConfigType {
|
||||
}
|
||||
}
|
||||
|
||||
# Navigate to zen configuration
|
||||
# Navigate to pal configuration
|
||||
$pathParts = $Client.ConfigJsonPath.Split('.')
|
||||
$zenKey = $pathParts[-1]
|
||||
$palKey = $pathParts[-1]
|
||||
$parentPath = $pathParts[0..($pathParts.Length - 2)]
|
||||
|
||||
$targetObject = $content
|
||||
@@ -1150,32 +1176,32 @@ function Get-ExistingMcpConfigType {
|
||||
$targetObject = $targetObject.$key
|
||||
}
|
||||
|
||||
if (!$targetObject.PSObject.Properties[$zenKey]) {
|
||||
if (!$targetObject.PSObject.Properties[$palKey]) {
|
||||
return @{
|
||||
Exists = $false
|
||||
Type = "None"
|
||||
Details = "Zen configuration not found"
|
||||
Details = "PAL configuration not found"
|
||||
}
|
||||
}
|
||||
|
||||
$zenConfig = $targetObject.$zenKey
|
||||
$palConfig = $targetObject.$palKey
|
||||
|
||||
# Analyze configuration type
|
||||
if ($zenConfig.command -eq "docker") {
|
||||
if ($palConfig.command -eq "docker") {
|
||||
$dockerType = "Unknown"
|
||||
$details = "Docker configuration"
|
||||
|
||||
if ($zenConfig.args -and $zenConfig.args.Count -gt 0) {
|
||||
if ($zenConfig.args[0] -eq "run") {
|
||||
if ($palConfig.args -and $palConfig.args.Count -gt 0) {
|
||||
if ($palConfig.args[0] -eq "run") {
|
||||
$dockerType = "Docker Run"
|
||||
$details = "Docker run (dedicated container)"
|
||||
}
|
||||
elseif ($zenConfig.args[0] -eq "exec") {
|
||||
elseif ($palConfig.args[0] -eq "exec") {
|
||||
$dockerType = "Docker Exec"
|
||||
$details = "Docker exec (existing container)"
|
||||
}
|
||||
else {
|
||||
$details = "Docker ($($zenConfig.args[0]))"
|
||||
$details = "Docker ($($palConfig.args[0]))"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1184,18 +1210,18 @@ function Get-ExistingMcpConfigType {
|
||||
Type = "Docker"
|
||||
SubType = $dockerType
|
||||
Details = $details
|
||||
Command = $zenConfig.command
|
||||
Args = $zenConfig.args
|
||||
Command = $palConfig.command
|
||||
Args = $palConfig.args
|
||||
}
|
||||
}
|
||||
elseif ($zenConfig.command -and $zenConfig.command.EndsWith("python.exe")) {
|
||||
elseif ($palConfig.command -and $palConfig.command.EndsWith("python.exe")) {
|
||||
$pythonType = "Python"
|
||||
$details = "Python virtual environment"
|
||||
|
||||
if ($zenConfig.command.Contains(".zen_venv")) {
|
||||
$details = "Python (zen virtual environment)"
|
||||
if ($palConfig.command.Contains(".pal_venv")) {
|
||||
$details = "Python (pal virtual environment)"
|
||||
}
|
||||
elseif ($zenConfig.command.Contains("venv")) {
|
||||
elseif ($palConfig.command.Contains("venv")) {
|
||||
$details = "Python (virtual environment)"
|
||||
}
|
||||
else {
|
||||
@@ -1207,17 +1233,17 @@ function Get-ExistingMcpConfigType {
|
||||
Type = "Python"
|
||||
SubType = $pythonType
|
||||
Details = $details
|
||||
Command = $zenConfig.command
|
||||
Args = $zenConfig.args
|
||||
Command = $palConfig.command
|
||||
Args = $palConfig.args
|
||||
}
|
||||
}
|
||||
else {
|
||||
return @{
|
||||
Exists = $true
|
||||
Type = "Unknown"
|
||||
Details = "Unknown configuration type: $($zenConfig.command)"
|
||||
Command = $zenConfig.command
|
||||
Args = $zenConfig.args
|
||||
Details = "Unknown configuration type: $($palConfig.command)"
|
||||
Command = $palConfig.command
|
||||
Args = $palConfig.args
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1337,7 +1363,7 @@ function Configure-McpClient {
|
||||
$newConfigType = if ($UseDocker) { "Docker" } else { "Python" }
|
||||
|
||||
if ($existingConfig.Exists) {
|
||||
Write-Info "Found existing Zen MCP configuration in $($Client.Name)"
|
||||
Write-Info "Found existing PAL MCP configuration in $($Client.Name)"
|
||||
Write-Info " Current: $($existingConfig.Details)"
|
||||
Write-Info " New: $newConfigType configuration"
|
||||
|
||||
@@ -1360,7 +1386,7 @@ function Configure-McpClient {
|
||||
}
|
||||
else {
|
||||
# User confirmation for new installation
|
||||
$response = Read-Host "`nConfigure Zen MCP for $($Client.Name) (mode: $newConfigType)? (y/N)"
|
||||
$response = Read-Host "`nConfigure PAL MCP for $($Client.Name) (mode: $newConfigType)? (y/N)"
|
||||
if ($response -ne 'y' -and $response -ne 'Y') {
|
||||
Write-Info "Skipping $($Client.Name) integration"
|
||||
return
|
||||
@@ -1429,7 +1455,7 @@ function Configure-McpClient {
|
||||
|
||||
# Navigate and set configuration
|
||||
$pathParts = $Client.ConfigJsonPath.Split('.')
|
||||
$zenKey = $pathParts[-1]
|
||||
$palKey = $pathParts[-1]
|
||||
$parentPath = $pathParts[0..($pathParts.Length - 2)]
|
||||
|
||||
$targetObject = $config
|
||||
@@ -1440,7 +1466,13 @@ function Configure-McpClient {
|
||||
$targetObject = $targetObject.$key
|
||||
}
|
||||
|
||||
$targetObject | Add-Member -MemberType NoteProperty -Name $zenKey -Value $serverConfig -Force
|
||||
# Remove legacy zen entries to avoid duplicate or broken MCP servers
|
||||
$legacyRemoved = Remove-LegacyServerKeys $targetObject
|
||||
if ($legacyRemoved) {
|
||||
Write-Info "Removed legacy MCP entries (zen → pal)"
|
||||
}
|
||||
|
||||
$targetObject | Add-Member -MemberType NoteProperty -Name $palKey -Value $serverConfig -Force
|
||||
|
||||
# Write config
|
||||
$config | ConvertTo-Json -Depth 10 | Out-File $configPath -Encoding UTF8
|
||||
@@ -1488,26 +1520,30 @@ function Test-ClaudeCliIntegration {
|
||||
|
||||
Write-Info "Claude CLI detected - checking configuration..."
|
||||
|
||||
foreach ($legacy in $script:LegacyServerNames) {
|
||||
try { claude mcp remove -s user $legacy 2>$null | Out-Null } catch {}
|
||||
}
|
||||
|
||||
try {
|
||||
$claudeConfig = claude mcp list 2>$null
|
||||
if ($claudeConfig -match "zen") {
|
||||
Write-Success "Claude CLI already configured for zen server"
|
||||
if ($claudeConfig -match "pal") {
|
||||
Write-Success "Claude CLI already configured for pal server"
|
||||
}
|
||||
else {
|
||||
Write-Info "To add zen server to Claude CLI, run:"
|
||||
Write-Host " claude mcp add -s user zen $PythonPath $ServerPath" -ForegroundColor Cyan
|
||||
Write-Info "To add pal server to Claude CLI, run:"
|
||||
Write-Host " claude mcp add -s user pal $PythonPath $ServerPath" -ForegroundColor Cyan
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Info "To configure Claude CLI manually, run:"
|
||||
Write-Host " claude mcp add -s user zen $PythonPath $ServerPath" -ForegroundColor Cyan
|
||||
Write-Host " claude mcp add -s user pal $PythonPath $ServerPath" -ForegroundColor Cyan
|
||||
}
|
||||
}
|
||||
|
||||
function Test-GeminiCliIntegration {
|
||||
param([string]$ScriptDir)
|
||||
|
||||
$zenWrapper = Join-Path $ScriptDir "zen-mcp-server.cmd"
|
||||
$palWrapper = Join-Path $ScriptDir "pal-mcp-server.cmd"
|
||||
|
||||
# Check if Gemini settings file exists (Windows path)
|
||||
$geminiConfig = "$env:USERPROFILE\.gemini\settings.json"
|
||||
@@ -1515,34 +1551,76 @@ function Test-GeminiCliIntegration {
|
||||
return
|
||||
}
|
||||
|
||||
# Check if zen is already configured
|
||||
# Load existing config
|
||||
$config = @{}
|
||||
$configContent = Get-Content $geminiConfig -Raw -ErrorAction SilentlyContinue
|
||||
if ($configContent -and $configContent -match '"zen"') {
|
||||
if ($configContent) {
|
||||
try { $config = $configContent | ConvertFrom-Json -ErrorAction Stop } catch { $config = @{} }
|
||||
}
|
||||
if ($null -eq $config -or $config -isnot [System.Collections.IDictionary]) {
|
||||
$config = @{}
|
||||
}
|
||||
|
||||
if (-not $config.mcpServers -or $config.mcpServers -isnot [System.Collections.IDictionary]) {
|
||||
$config.mcpServers = [ordered]@{}
|
||||
}
|
||||
|
||||
$legacyRemoved = Remove-LegacyServerKeys $config.mcpServers
|
||||
$palConfig = $config.mcpServers.pal
|
||||
$needsWrite = $legacyRemoved
|
||||
|
||||
if ($palConfig) {
|
||||
if ($palConfig.command -ne $palWrapper) {
|
||||
$palConfig.command = $palWrapper
|
||||
$needsWrite = $true
|
||||
}
|
||||
|
||||
if (!(Test-Path $palWrapper)) {
|
||||
Write-Info "Creating wrapper script for Gemini CLI..."
|
||||
@"
|
||||
@echo off
|
||||
cd /d "%~dp0"
|
||||
if exist ".pal_venv\Scripts\python.exe" (
|
||||
.pal_venv\Scripts\python.exe server.py %*
|
||||
) else (
|
||||
python server.py %*
|
||||
)
|
||||
"@ | Out-File -FilePath $palWrapper -Encoding ASCII
|
||||
Write-Success "Created pal-mcp-server.cmd wrapper script"
|
||||
}
|
||||
|
||||
if ($needsWrite) {
|
||||
Manage-ConfigBackups -ConfigFilePath $geminiConfig | Out-Null
|
||||
$config | ConvertTo-Json -Depth 10 | Out-File $geminiConfig -Encoding UTF8
|
||||
Write-Success "Updated Gemini CLI configuration (cleaned legacy entries)"
|
||||
Write-Host " Config: $geminiConfig" -ForegroundColor Gray
|
||||
Write-Host " Restart Gemini CLI to use PAL MCP Server" -ForegroundColor Gray
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
# Ask user if they want to add Zen to Gemini CLI
|
||||
# Ask user if they want to add PAL to Gemini CLI
|
||||
Write-Host ""
|
||||
$response = Read-Host "Configure Zen for Gemini CLI? (y/N)"
|
||||
$response = Read-Host "Configure PAL for Gemini CLI? (y/N)"
|
||||
if ($response -ne 'y' -and $response -ne 'Y') {
|
||||
Write-Info "Skipping Gemini CLI integration"
|
||||
return
|
||||
}
|
||||
|
||||
# Ensure wrapper script exists
|
||||
if (!(Test-Path $zenWrapper)) {
|
||||
if (!(Test-Path $palWrapper)) {
|
||||
Write-Info "Creating wrapper script for Gemini CLI..."
|
||||
@"
|
||||
@echo off
|
||||
cd /d "%~dp0"
|
||||
if exist ".zen_venv\Scripts\python.exe" (
|
||||
.zen_venv\Scripts\python.exe server.py %*
|
||||
if exist ".pal_venv\Scripts\python.exe" (
|
||||
.pal_venv\Scripts\python.exe server.py %*
|
||||
) else (
|
||||
python server.py %*
|
||||
)
|
||||
"@ | Out-File -FilePath $zenWrapper -Encoding ASCII
|
||||
"@ | Out-File -FilePath $palWrapper -Encoding ASCII
|
||||
|
||||
Write-Success "Created zen-mcp-server.cmd wrapper script"
|
||||
Write-Success "Created pal-mcp-server.cmd wrapper script"
|
||||
}
|
||||
|
||||
# Update Gemini settings
|
||||
@@ -1552,30 +1630,24 @@ if exist ".zen_venv\Scripts\python.exe" (
|
||||
# Create backup with retention management
|
||||
$backupPath = Manage-ConfigBackups $geminiConfig
|
||||
|
||||
# Read existing config or create new one
|
||||
$config = @{}
|
||||
if (Test-Path $geminiConfig) {
|
||||
$config = Get-Content $geminiConfig -Raw | ConvertFrom-Json
|
||||
}
|
||||
|
||||
# Ensure mcpServers exists
|
||||
if (!$config.mcpServers) {
|
||||
$config | Add-Member -MemberType NoteProperty -Name "mcpServers" -Value @{} -Force
|
||||
if (-not $config.mcpServers -or $config.mcpServers -isnot [System.Collections.IDictionary]) {
|
||||
$config.mcpServers = [ordered]@{}
|
||||
}
|
||||
|
||||
# Add zen server
|
||||
$zenConfig = @{
|
||||
command = $zenWrapper
|
||||
# Add pal server
|
||||
$palConfig = @{
|
||||
command = $palWrapper
|
||||
}
|
||||
|
||||
$config.mcpServers | Add-Member -MemberType NoteProperty -Name "zen" -Value $zenConfig -Force
|
||||
$config.mcpServers | Add-Member -MemberType NoteProperty -Name "pal" -Value $palConfig -Force
|
||||
|
||||
# Write updated config
|
||||
$config | ConvertTo-Json -Depth 10 | Out-File $geminiConfig -Encoding UTF8
|
||||
|
||||
Write-Success "Successfully configured Gemini CLI"
|
||||
Write-Host " Config: $geminiConfig" -ForegroundColor Gray
|
||||
Write-Host " Restart Gemini CLI to use Zen MCP Server" -ForegroundColor Gray
|
||||
Write-Host " Restart Gemini CLI to use PAL MCP Server" -ForegroundColor Gray
|
||||
|
||||
}
|
||||
catch {
|
||||
@@ -1586,8 +1658,8 @@ if exist ".zen_venv\Scripts\python.exe" (
|
||||
Write-Host @"
|
||||
{
|
||||
"mcpServers": {
|
||||
"zen": {
|
||||
"command": "$zenWrapper"
|
||||
"pal": {
|
||||
"command": "$palWrapper"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1615,7 +1687,7 @@ function Show-QwenManualConfig {
|
||||
|
||||
Write-Host "{" -ForegroundColor Yellow
|
||||
Write-Host " \"mcpServers\": {" -ForegroundColor Yellow
|
||||
Write-Host " \"zen\": {" -ForegroundColor Yellow
|
||||
Write-Host " \"pal\": {" -ForegroundColor Yellow
|
||||
Write-Host " \"command\": \"$PythonPath\"," -ForegroundColor Yellow
|
||||
Write-Host " \"args\": [\"$ServerPath\"]," -ForegroundColor Yellow
|
||||
Write-Host " \"cwd\": \"$ScriptDir\"," -ForegroundColor Yellow
|
||||
@@ -1629,7 +1701,7 @@ function Show-QwenManualConfig {
|
||||
else {
|
||||
Write-Host "{" -ForegroundColor Yellow
|
||||
Write-Host " \"mcpServers\": {" -ForegroundColor Yellow
|
||||
Write-Host " \"zen\": {" -ForegroundColor Yellow
|
||||
Write-Host " \"pal\": {" -ForegroundColor Yellow
|
||||
Write-Host " \"command\": \"$PythonPath\"," -ForegroundColor Yellow
|
||||
Write-Host " \"args\": [\"$ServerPath\"]," -ForegroundColor Yellow
|
||||
Write-Host " \"cwd\": \"$ScriptDir\"" -ForegroundColor Yellow
|
||||
@@ -1653,6 +1725,8 @@ function Test-QwenCliIntegration {
|
||||
$scriptDir = Split-Path $ServerPath -Parent
|
||||
|
||||
$configStatus = "missing"
|
||||
$legacyRemoved = $false
|
||||
$skipPrompt = $false
|
||||
$config = @{}
|
||||
|
||||
if (Test-Path $configPath) {
|
||||
@@ -1668,11 +1742,12 @@ function Test-QwenCliIntegration {
|
||||
|
||||
if ($config.ContainsKey('mcpServers') -and $config['mcpServers'] -is [System.Collections.IDictionary]) {
|
||||
$servers = $config['mcpServers']
|
||||
if ($servers.Contains('zen') -and $servers['zen'] -is [System.Collections.IDictionary]) {
|
||||
$zenConfig = $servers['zen']
|
||||
$commandMatches = ($zenConfig['command'] -eq $PythonPath)
|
||||
$legacyRemoved = (Remove-LegacyServerKeys $servers) -or $legacyRemoved
|
||||
if ($servers.Contains('pal') -and $servers['pal'] -is [System.Collections.IDictionary]) {
|
||||
$palConfig = $servers['pal']
|
||||
$commandMatches = ($palConfig['command'] -eq $PythonPath)
|
||||
|
||||
$argsValue = $zenConfig['args']
|
||||
$argsValue = $palConfig['args']
|
||||
$argsList = @()
|
||||
if ($argsValue -is [System.Collections.IEnumerable] -and $argsValue -isnot [string]) {
|
||||
$argsList = @($argsValue)
|
||||
@@ -1683,21 +1758,21 @@ function Test-QwenCliIntegration {
|
||||
$argsMatches = ($argsList.Count -eq 1 -and $argsList[0] -eq $ServerPath)
|
||||
|
||||
$cwdValue = $null
|
||||
if ($zenConfig.Contains('cwd')) {
|
||||
$cwdValue = $zenConfig['cwd']
|
||||
if ($palConfig.Contains('cwd')) {
|
||||
$cwdValue = $palConfig['cwd']
|
||||
}
|
||||
$cwdMatches = ([string]::IsNullOrEmpty($cwdValue) -or $cwdValue -eq $scriptDir)
|
||||
|
||||
if ($commandMatches -and $argsMatches -and $cwdMatches) {
|
||||
Write-Success "Qwen CLI already configured for zen server"
|
||||
return
|
||||
$configStatus = $legacyRemoved ? "cleanup" : "match"
|
||||
}
|
||||
|
||||
else {
|
||||
$configStatus = "mismatch"
|
||||
Write-Warning "Existing Qwen CLI configuration differs from the current setup."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch {
|
||||
$configStatus = "invalid"
|
||||
Write-Warning "Unable to parse Qwen CLI settings at $configPath ($_)."
|
||||
@@ -1735,7 +1810,7 @@ function Test-QwenCliIntegration {
|
||||
"AZURE_OPENAI_API_KEY", "AZURE_OPENAI_ENDPOINT", "AZURE_OPENAI_API_VERSION", "AZURE_OPENAI_ALLOWED_MODELS", "AZURE_MODELS_CONFIG_PATH",
|
||||
"CUSTOM_API_URL", "CUSTOM_API_KEY", "CUSTOM_MODEL_NAME", "DEFAULT_MODEL", "GOOGLE_ALLOWED_MODELS",
|
||||
"OPENAI_ALLOWED_MODELS", "OPENROUTER_ALLOWED_MODELS", "XAI_ALLOWED_MODELS", "DEFAULT_THINKING_MODE_THINKDEEP",
|
||||
"DISABLED_TOOLS", "CONVERSATION_TIMEOUT_HOURS", "MAX_CONVERSATION_TURNS", "LOG_LEVEL", "ZEN_MCP_FORCE_ENV_OVERRIDE"
|
||||
"DISABLED_TOOLS", "CONVERSATION_TIMEOUT_HOURS", "MAX_CONVERSATION_TURNS", "LOG_LEVEL", "PAL_MCP_FORCE_ENV_OVERRIDE"
|
||||
)
|
||||
|
||||
foreach ($key in $extraKeys) {
|
||||
@@ -1747,17 +1822,32 @@ function Test-QwenCliIntegration {
|
||||
}
|
||||
}
|
||||
|
||||
$prompt = "Configure Zen for Qwen CLI? (y/N)"
|
||||
if ($configStatus -eq "mismatch" -or $configStatus -eq "invalid") {
|
||||
$prompt = "Update Qwen CLI zen configuration? (y/N)"
|
||||
if ($configStatus -eq "match") {
|
||||
Write-Success "Qwen CLI already configured for pal server"
|
||||
return
|
||||
}
|
||||
|
||||
if ($configStatus -eq "cleanup") {
|
||||
Write-Info "Removing legacy Qwen MCP entries from previous zen configuration..."
|
||||
$skipPrompt = $true
|
||||
}
|
||||
|
||||
$prompt = "Configure PAL for Qwen CLI? (y/N)"
|
||||
if ($configStatus -eq "cleanup") {
|
||||
$prompt = "Remove legacy Qwen MCP entries and refresh configuration? (Y/n)"
|
||||
}
|
||||
elseif ($configStatus -eq "mismatch" -or $configStatus -eq "invalid") {
|
||||
$prompt = "Update Qwen CLI pal configuration? (y/N)"
|
||||
}
|
||||
|
||||
if (-not $skipPrompt) {
|
||||
$response = Read-Host $prompt
|
||||
if ($response -ne 'y' -and $response -ne 'Y') {
|
||||
Write-Info "Skipping Qwen CLI integration"
|
||||
Show-QwenManualConfig $PythonPath $ServerPath $scriptDir $configPath $envMap
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if (!(Test-Path $configDir)) {
|
||||
New-Item -ItemType Directory -Path $configDir -Force | Out-Null
|
||||
@@ -1776,24 +1866,24 @@ function Test-QwenCliIntegration {
|
||||
$config['mcpServers'] = @{}
|
||||
}
|
||||
|
||||
$zenConfig = [ordered]@{
|
||||
$palConfig = [ordered]@{
|
||||
command = $PythonPath
|
||||
args = @($ServerPath)
|
||||
cwd = $scriptDir
|
||||
}
|
||||
|
||||
if ($envMap.Count -gt 0) {
|
||||
$zenConfig['env'] = $envMap
|
||||
$palConfig['env'] = $envMap
|
||||
}
|
||||
|
||||
$config['mcpServers']['zen'] = $zenConfig
|
||||
$config['mcpServers']['pal'] = $palConfig
|
||||
|
||||
$json = ($config | ConvertTo-Json -Depth 20)
|
||||
Set-Content -Path $configPath -Value $json -Encoding UTF8
|
||||
|
||||
Write-Success "Successfully configured Qwen CLI"
|
||||
Write-Host " Config: $configPath" -ForegroundColor Gray
|
||||
Write-Host " Restart Qwen CLI to use Zen MCP Server" -ForegroundColor Gray
|
||||
Write-Host " Restart Qwen CLI to use PAL MCP Server" -ForegroundColor Gray
|
||||
}
|
||||
catch {
|
||||
Write-Error "Failed to update Qwen CLI configuration: $_"
|
||||
@@ -1813,7 +1903,7 @@ function Test-QwenCliIntegration {
|
||||
# Show script help
|
||||
function Show-Help {
|
||||
Write-Host @"
|
||||
Zen MCP Server - Setup and Launch Script
|
||||
PAL MCP Server - Setup and Launch Script
|
||||
|
||||
USAGE:
|
||||
.\run-server.ps1 [OPTIONS]
|
||||
@@ -1838,17 +1928,17 @@ EXAMPLES:
|
||||
.\run-server.ps1 -Docker # Use Docker deployment
|
||||
.\run-server.ps1 -Docker -Follow # Docker with log following
|
||||
|
||||
For more information, visit: https://github.com/BeehiveInnovations/zen-mcp-server
|
||||
For more information, visit: https://github.com/BeehiveInnovations/pal-mcp-server
|
||||
"@ -ForegroundColor White
|
||||
}
|
||||
|
||||
# Show version information
|
||||
function Show-Version {
|
||||
$version = Get-Version
|
||||
Write-Host "Zen MCP Server version: $version" -ForegroundColor Green
|
||||
Write-Host "PAL MCP Server version: $version" -ForegroundColor Green
|
||||
Write-Host "PowerShell Setup Script for Windows" -ForegroundColor Cyan
|
||||
Write-Host "Author: GiGiDKR (https://github.com/GiGiDKR)" -ForegroundColor Gray
|
||||
Write-Host "Project: BeehiveInnovations/zen-mcp-server" -ForegroundColor Gray
|
||||
Write-Host "Project: BeehiveInnovations/pal-mcp-server" -ForegroundColor Gray
|
||||
}
|
||||
|
||||
# Show configuration instructions
|
||||
@@ -1886,7 +1976,7 @@ function Show-ConfigInstructions {
|
||||
Write-Host "✓ Qwen CLI" -ForegroundColor White
|
||||
Write-Host ""
|
||||
Write-Host "The script automatically detects and configures compatible clients." -ForegroundColor Gray
|
||||
Write-Host "Restart your MCP clients after configuration to use the Zen MCP Server." -ForegroundColor Yellow
|
||||
Write-Host "Restart your MCP clients after configuration to use the PAL MCP Server." -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
# Show setup instructions
|
||||
@@ -1900,11 +1990,11 @@ function Show-SetupInstructions {
|
||||
Write-Step "Setup Complete"
|
||||
|
||||
if ($UseDocker) {
|
||||
Write-Success "Zen MCP Server is configured for Docker deployment"
|
||||
Write-Host "Docker command: docker exec -i zen-mcp-server python server.py" -ForegroundColor Cyan
|
||||
Write-Success "PAL MCP Server is configured for Docker deployment"
|
||||
Write-Host "Docker command: docker exec -i pal-mcp-server python server.py" -ForegroundColor Cyan
|
||||
}
|
||||
else {
|
||||
Write-Success "Zen MCP Server is configured for Python virtual environment"
|
||||
Write-Success "PAL MCP Server is configured for Python virtual environment"
|
||||
Write-Host "Python: $PythonPath" -ForegroundColor Cyan
|
||||
Write-Host "Server: $ServerPath" -ForegroundColor Cyan
|
||||
}
|
||||
@@ -1916,7 +2006,7 @@ function Show-SetupInstructions {
|
||||
|
||||
# Start the server
|
||||
function Start-Server {
|
||||
Write-Step "Starting Zen MCP Server"
|
||||
Write-Step "Starting PAL MCP Server"
|
||||
|
||||
$pythonPath = "$VENV_PATH\Scripts\python.exe"
|
||||
if (!(Test-Path $pythonPath)) {
|
||||
@@ -2041,7 +2131,7 @@ function Import-EnvFile {
|
||||
# Docker deployment workflow
|
||||
function Invoke-DockerWorkflow {
|
||||
Write-Step "Starting Docker Workflow"
|
||||
Write-Host "Zen MCP Server" -ForegroundColor Green
|
||||
Write-Host "PAL MCP Server" -ForegroundColor Green
|
||||
Write-Host "=================" -ForegroundColor Cyan
|
||||
|
||||
$version = Get-Version
|
||||
@@ -2064,7 +2154,7 @@ function Invoke-DockerWorkflow {
|
||||
Show-SetupInstructions -UseDocker
|
||||
|
||||
# Start Docker services
|
||||
Write-Step "Starting Zen MCP Server"
|
||||
Write-Step "Starting PAL MCP Server"
|
||||
if ($Follow) {
|
||||
Write-Info "Starting server and following logs..."
|
||||
Start-DockerServices -Follow
|
||||
@@ -2074,7 +2164,7 @@ function Invoke-DockerWorkflow {
|
||||
if (!(Start-DockerServices)) { exit 1 }
|
||||
|
||||
Write-Host ""
|
||||
Write-Success "Zen MCP Server is running in Docker!"
|
||||
Write-Success "PAL MCP Server is running in Docker!"
|
||||
Write-Host ""
|
||||
|
||||
Write-Host "Next steps:" -ForegroundColor Cyan
|
||||
@@ -2083,7 +2173,7 @@ function Invoke-DockerWorkflow {
|
||||
Write-Host ""
|
||||
Write-Host "Useful commands:" -ForegroundColor Cyan
|
||||
Write-Host " View logs: " -NoNewline -ForegroundColor White
|
||||
Write-Host "docker logs -f zen-mcp-server" -ForegroundColor Yellow
|
||||
Write-Host "docker logs -f pal-mcp-server" -ForegroundColor Yellow
|
||||
Write-Host " Stop server: " -NoNewline -ForegroundColor White
|
||||
Write-Host "docker-compose down" -ForegroundColor Yellow
|
||||
Write-Host " Restart server: " -NoNewline -ForegroundColor White
|
||||
@@ -2093,7 +2183,7 @@ function Invoke-DockerWorkflow {
|
||||
# Python virtual environment deployment workflow
|
||||
function Invoke-PythonWorkflow {
|
||||
Write-Step "Starting Python Virtual Environment Workflow"
|
||||
Write-Host "Zen MCP Server" -ForegroundColor Green
|
||||
Write-Host "PAL MCP Server" -ForegroundColor Green
|
||||
Write-Host "=================" -ForegroundColor Cyan
|
||||
|
||||
$version = Get-Version
|
||||
|
||||
385
run-server.sh
385
run-server.sh
@@ -2,7 +2,7 @@
|
||||
set -euo pipefail
|
||||
|
||||
# ============================================================================
|
||||
# Zen MCP Server Setup Script
|
||||
# PAL MCP Server Setup Script
|
||||
#
|
||||
# A platform-agnostic setup script that works on macOS, Linux, and WSL.
|
||||
# Handles environment setup, dependency installation, and configuration.
|
||||
@@ -29,11 +29,12 @@ readonly RED='\033[0;31m'
|
||||
readonly NC='\033[0m' # No Color
|
||||
|
||||
# Configuration
|
||||
readonly VENV_PATH=".zen_venv"
|
||||
readonly VENV_PATH=".pal_venv"
|
||||
readonly DOCKER_CLEANED_FLAG=".docker_cleaned"
|
||||
readonly DESKTOP_CONFIG_FLAG=".desktop_configured"
|
||||
readonly LOG_DIR="logs"
|
||||
readonly LOG_FILE="mcp_server.log"
|
||||
readonly LEGACY_MCP_NAMES=("zen" "zen-mcp" "zen-mcp-server" "zen_mcp" "zen_mcp_server")
|
||||
|
||||
# Determine portable arguments for sed -i (GNU vs BSD)
|
||||
declare -a SED_INPLACE_ARGS
|
||||
@@ -753,7 +754,7 @@ setup_venv() {
|
||||
print_error "Permission denied creating virtual environment"
|
||||
echo ""
|
||||
echo "Try running in a different directory:"
|
||||
echo " cd ~ && git clone <repository-url> && cd zen-mcp-server && ./run-server.sh"
|
||||
echo " cd ~ && git clone <repository-url> && cd pal-mcp-server && ./run-server.sh"
|
||||
echo ""
|
||||
exit 1
|
||||
else
|
||||
@@ -960,7 +961,7 @@ install_dependencies() {
|
||||
fi
|
||||
|
||||
echo ""
|
||||
print_info "Setting up Zen MCP Server..."
|
||||
print_info "Setting up PAL MCP Server..."
|
||||
echo "Installing required components:"
|
||||
echo " • MCP protocol library"
|
||||
echo " • AI model connectors"
|
||||
@@ -1234,7 +1235,7 @@ check_claude_cli_integration() {
|
||||
echo ""
|
||||
print_warning "Claude CLI not found"
|
||||
echo ""
|
||||
read -p "Would you like to add Zen to Claude Code? (Y/n): " -n 1 -r
|
||||
read -p "Would you like to add PAL to Claude Code? (Y/n): " -n 1 -r
|
||||
echo ""
|
||||
if [[ $REPLY =~ ^[Nn]$ ]]; then
|
||||
print_info "Skipping Claude Code integration"
|
||||
@@ -1249,9 +1250,14 @@ check_claude_cli_integration() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Check if zen is registered
|
||||
# Remove legacy zen registrations to avoid duplicate errors after rename
|
||||
for legacy_name in "${LEGACY_MCP_NAMES[@]}"; do
|
||||
claude mcp remove "$legacy_name" -s user >/dev/null 2>&1 || true
|
||||
done
|
||||
|
||||
# Check if pal is registered
|
||||
local mcp_list=$(claude mcp list 2>/dev/null)
|
||||
if echo "$mcp_list" | grep -q "zen"; then
|
||||
if echo "$mcp_list" | grep -q "pal"; then
|
||||
# Check if it's using the old Docker command
|
||||
if echo "$mcp_list" | grep -E "zen.*docker|zen.*compose" &>/dev/null; then
|
||||
print_warning "Found old Docker-based Zen registration, updating..."
|
||||
@@ -1270,14 +1276,14 @@ check_claude_cli_integration() {
|
||||
done <<< "$env_vars"
|
||||
fi
|
||||
|
||||
local claude_cmd="claude mcp add zen -s user$env_args -- \"$python_cmd\" \"$server_path\""
|
||||
local claude_cmd="claude mcp add pal -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"
|
||||
print_success "Updated PAL 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 remove pal -s user"
|
||||
echo " $claude_cmd"
|
||||
return 1
|
||||
fi
|
||||
@@ -1287,8 +1293,8 @@ check_claude_cli_integration() {
|
||||
if echo "$mcp_list" | grep -F "$server_path" &>/dev/null; then
|
||||
return 0
|
||||
else
|
||||
print_warning "Zen registered with different path, updating..."
|
||||
claude mcp remove zen -s user 2>/dev/null || true
|
||||
print_warning "PAL registered with different path, updating..."
|
||||
claude mcp remove pal -s user 2>/dev/null || true
|
||||
|
||||
# Re-add with current path and environment variables
|
||||
local env_vars=$(parse_env_variables)
|
||||
@@ -1303,14 +1309,14 @@ check_claude_cli_integration() {
|
||||
done <<< "$env_vars"
|
||||
fi
|
||||
|
||||
local claude_cmd="claude mcp add zen -s user$env_args -- \"$python_cmd\" \"$server_path\""
|
||||
local claude_cmd="claude mcp add pal -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"
|
||||
print_success "Updated PAL 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 remove pal -s user"
|
||||
echo " $claude_cmd"
|
||||
return 1
|
||||
fi
|
||||
@@ -1319,7 +1325,7 @@ check_claude_cli_integration() {
|
||||
else
|
||||
# Not registered at all, ask user if they want to add it
|
||||
echo ""
|
||||
read -p "Add Zen to Claude Code? (Y/n): " -n 1 -r
|
||||
read -p "Add PAL to Claude Code? (Y/n): " -n 1 -r
|
||||
echo ""
|
||||
if [[ $REPLY =~ ^[Nn]$ ]]; then
|
||||
local env_vars=$(parse_env_variables)
|
||||
@@ -1335,11 +1341,11 @@ check_claude_cli_integration() {
|
||||
fi
|
||||
|
||||
print_info "To add manually later, run:"
|
||||
echo " claude mcp add zen -s user$env_args -- $python_cmd $server_path"
|
||||
echo " claude mcp add pal -s user$env_args -- $python_cmd $server_path"
|
||||
return 0
|
||||
fi
|
||||
|
||||
print_info "Registering Zen with Claude Code..."
|
||||
print_info "Registering PAL with Claude Code..."
|
||||
|
||||
# Add with environment variables
|
||||
local env_vars=$(parse_env_variables)
|
||||
@@ -1354,9 +1360,9 @@ check_claude_cli_integration() {
|
||||
done <<< "$env_vars"
|
||||
fi
|
||||
|
||||
local claude_cmd="claude mcp add zen -s user$env_args -- \"$python_cmd\" \"$server_path\""
|
||||
local claude_cmd="claude mcp add pal -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"
|
||||
print_success "Successfully added PAL to Claude Code with environment variables"
|
||||
return 0
|
||||
else
|
||||
echo ""
|
||||
@@ -1383,8 +1389,12 @@ check_claude_desktop_integration() {
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Legacy MCP server names to clean out from previous releases
|
||||
local legacy_names_csv
|
||||
legacy_names_csv=$(IFS=,; echo "${LEGACY_MCP_NAMES[*]}")
|
||||
|
||||
echo ""
|
||||
read -p "Configure Zen for Claude Desktop? (Y/n): " -n 1 -r
|
||||
read -p "Configure PAL for Claude Desktop? (Y/n): " -n 1 -r
|
||||
echo ""
|
||||
if [[ $REPLY =~ ^[Nn]$ ]]; then
|
||||
print_info "Skipping Claude Desktop integration"
|
||||
@@ -1401,12 +1411,12 @@ check_claude_desktop_integration() {
|
||||
print_info "Updating existing Claude Desktop config..."
|
||||
|
||||
# Check for old Docker config and remove it
|
||||
if grep -q "docker.*compose.*zen\|zen.*docker" "$config_path" 2>/dev/null; then
|
||||
if grep -q "docker.*compose.*pal\|pal.*docker" "$config_path" 2>/dev/null; then
|
||||
print_warning "Removing old Docker-based MCP configuration..."
|
||||
# Create backup
|
||||
cp "$config_path" "${config_path}.backup_$(date +%Y%m%d_%H%M%S)"
|
||||
|
||||
# Remove old zen config using a more robust approach
|
||||
# Remove old pal config using a more robust approach
|
||||
local temp_file=$(mktemp)
|
||||
python3 -c "
|
||||
import json
|
||||
@@ -1416,10 +1426,10 @@ try:
|
||||
with open('$config_path', 'r') as f:
|
||||
config = json.load(f)
|
||||
|
||||
# Remove zen from mcpServers if it exists
|
||||
if 'mcpServers' in config and 'zen' in config['mcpServers']:
|
||||
del config['mcpServers']['zen']
|
||||
print('Removed old zen MCP configuration')
|
||||
# Remove pal from mcpServers if it exists
|
||||
if 'mcpServers' in config and 'pal' in config['mcpServers']:
|
||||
del config['mcpServers']['pal']
|
||||
print('Removed old pal MCP configuration')
|
||||
|
||||
with open('$temp_file', 'w') as f:
|
||||
json.dump(config, f, indent=2)
|
||||
@@ -1440,22 +1450,35 @@ except Exception as e:
|
||||
echo "$env_vars" > "$env_file"
|
||||
fi
|
||||
|
||||
python3 -c "
|
||||
PAL_LEGACY_NAMES="$legacy_names_csv" python3 -c "
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
|
||||
legacy_keys = [k for k in os.environ.get('PAL_LEGACY_NAMES', '').split(',') if k]
|
||||
|
||||
try:
|
||||
with open('$config_path', 'r') as f:
|
||||
config = json.load(f)
|
||||
except:
|
||||
except Exception:
|
||||
config = {}
|
||||
|
||||
if not isinstance(config, dict):
|
||||
config = {}
|
||||
|
||||
# Ensure mcpServers exists
|
||||
if 'mcpServers' not in config:
|
||||
if 'mcpServers' not in config or not isinstance(config.get('mcpServers'), dict):
|
||||
config['mcpServers'] = {}
|
||||
|
||||
# Add zen server
|
||||
zen_config = {
|
||||
# Remove legacy entries from any known server blocks
|
||||
for container in ('mcpServers', 'servers'):
|
||||
servers = config.get(container)
|
||||
if isinstance(servers, dict):
|
||||
for key in legacy_keys:
|
||||
servers.pop(key, None)
|
||||
|
||||
# Add pal server
|
||||
pal_config = {
|
||||
'command': '$python_cmd',
|
||||
'args': ['$server_path']
|
||||
}
|
||||
@@ -1469,13 +1492,13 @@ try:
|
||||
if '=' in line and line:
|
||||
key, value = line.split('=', 1)
|
||||
env_dict[key] = value
|
||||
except:
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if env_dict:
|
||||
zen_config['env'] = env_dict
|
||||
pal_config['env'] = env_dict
|
||||
|
||||
config['mcpServers']['zen'] = zen_config
|
||||
config['mcpServers']['pal'] = pal_config
|
||||
|
||||
with open('$temp_file', 'w') as f:
|
||||
json.dump(config, f, indent=2)
|
||||
@@ -1503,8 +1526,8 @@ import sys
|
||||
|
||||
config = {'mcpServers': {}}
|
||||
|
||||
# Add zen server
|
||||
zen_config = {
|
||||
# Add pal server
|
||||
pal_config = {
|
||||
'command': '$python_cmd',
|
||||
'args': ['$server_path']
|
||||
}
|
||||
@@ -1522,9 +1545,9 @@ except:
|
||||
pass
|
||||
|
||||
if env_dict:
|
||||
zen_config['env'] = env_dict
|
||||
pal_config['env'] = env_dict
|
||||
|
||||
config['mcpServers']['zen'] = zen_config
|
||||
config['mcpServers']['pal'] = pal_config
|
||||
|
||||
with open('$temp_file', 'w') as f:
|
||||
json.dump(config, f, indent=2)
|
||||
@@ -1567,7 +1590,7 @@ with open('$temp_file', 'w') as f:
|
||||
cat << EOF
|
||||
{
|
||||
"mcpServers": {
|
||||
"zen": {
|
||||
"pal": {
|
||||
"command": "$python_cmd",
|
||||
"args": ["$server_path"]$(if [[ -n "$example_env" ]]; then echo ","; fi)$(if [[ -n "$example_env" ]]; then echo "
|
||||
\"env\": {
|
||||
@@ -1583,7 +1606,7 @@ EOF
|
||||
# Check and update Gemini CLI configuration
|
||||
check_gemini_cli_integration() {
|
||||
local script_dir="$1"
|
||||
local zen_wrapper="$script_dir/zen-mcp-server"
|
||||
local pal_wrapper="$script_dir/pal-mcp-server"
|
||||
|
||||
# Check if Gemini settings file exists
|
||||
local gemini_config="$HOME/.gemini/settings.json"
|
||||
@@ -1592,15 +1615,75 @@ check_gemini_cli_integration() {
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Check if zen is already configured
|
||||
if grep -q '"zen"' "$gemini_config" 2>/dev/null; then
|
||||
# Already configured
|
||||
# Clean up legacy zen entries and detect existing pal configuration
|
||||
local legacy_names_csv
|
||||
legacy_names_csv=$(IFS=,; echo "${LEGACY_MCP_NAMES[*]}")
|
||||
|
||||
local gemini_status
|
||||
gemini_status=$(
|
||||
PAL_LEGACY_NAMES="$legacy_names_csv" PAL_WRAPPER="$pal_wrapper" PAL_GEMINI_CONFIG="$gemini_config" python3 - <<'PY' 2>/dev/null
|
||||
import json
|
||||
import os
|
||||
import pathlib
|
||||
import sys
|
||||
|
||||
config_path = pathlib.Path(os.environ["PAL_GEMINI_CONFIG"])
|
||||
legacy = [n for n in os.environ.get("PAL_LEGACY_NAMES", "").split(",") if n]
|
||||
wrapper = os.environ["PAL_WRAPPER"]
|
||||
|
||||
changed = False
|
||||
has_pal = False
|
||||
|
||||
try:
|
||||
data = json.loads(config_path.read_text())
|
||||
except Exception:
|
||||
data = {}
|
||||
|
||||
if not isinstance(data, dict):
|
||||
data = {}
|
||||
|
||||
servers = data.get("mcpServers")
|
||||
if not isinstance(servers, dict):
|
||||
servers = {}
|
||||
data["mcpServers"] = servers
|
||||
|
||||
for key in legacy:
|
||||
if servers.pop(key, None) is not None:
|
||||
changed = True
|
||||
|
||||
pal_cfg = servers.get("pal")
|
||||
if isinstance(pal_cfg, dict):
|
||||
has_pal = True
|
||||
if pal_cfg.get("command") != wrapper:
|
||||
pal_cfg["command"] = wrapper
|
||||
servers["pal"] = pal_cfg
|
||||
changed = True
|
||||
|
||||
if changed:
|
||||
config_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
config_path.write_text(json.dumps(data, indent=2))
|
||||
|
||||
status = ("CHANGED" if changed else "UNCHANGED") + ":" + ("HAS_PAL" if has_pal else "NO_PAL")
|
||||
sys.stdout.write(status)
|
||||
sys.exit(0)
|
||||
PY
|
||||
) || true
|
||||
|
||||
local gemini_changed=false
|
||||
local gemini_has_pal=false
|
||||
[[ "$gemini_status" == CHANGED:* ]] && gemini_changed=true
|
||||
[[ "$gemini_status" == *:HAS_PAL ]] && gemini_has_pal=true
|
||||
|
||||
if [[ "$gemini_has_pal" == true ]]; then
|
||||
if [[ "$gemini_changed" == true ]]; then
|
||||
print_success "Removed legacy Gemini MCP entries"
|
||||
fi
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Ask user if they want to add Zen to Gemini CLI
|
||||
# Ask user if they want to add PAL to Gemini CLI
|
||||
echo ""
|
||||
read -p "Configure Zen for Gemini CLI? (Y/n): " -n 1 -r
|
||||
read -p "Configure PAL for Gemini CLI? (Y/n): " -n 1 -r
|
||||
echo ""
|
||||
if [[ $REPLY =~ ^[Nn]$ ]]; then
|
||||
print_info "Skipping Gemini CLI integration"
|
||||
@@ -1608,17 +1691,17 @@ check_gemini_cli_integration() {
|
||||
fi
|
||||
|
||||
# Ensure wrapper script exists
|
||||
if [[ ! -f "$zen_wrapper" ]]; then
|
||||
if [[ ! -f "$pal_wrapper" ]]; then
|
||||
print_info "Creating wrapper script for Gemini CLI..."
|
||||
cat > "$zen_wrapper" << 'EOF'
|
||||
cat > "$pal_wrapper" << 'EOF'
|
||||
#!/bin/bash
|
||||
# Wrapper script for Gemini CLI compatibility
|
||||
DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
cd "$DIR"
|
||||
exec .zen_venv/bin/python server.py "$@"
|
||||
exec .pal_venv/bin/python server.py "$@"
|
||||
EOF
|
||||
chmod +x "$zen_wrapper"
|
||||
print_success "Created zen-mcp-server wrapper script"
|
||||
chmod +x "$pal_wrapper"
|
||||
print_success "Created pal-mcp-server wrapper script"
|
||||
fi
|
||||
|
||||
# Update Gemini settings
|
||||
@@ -1627,7 +1710,7 @@ EOF
|
||||
# Create backup
|
||||
cp "$gemini_config" "${gemini_config}.backup_$(date +%Y%m%d_%H%M%S)"
|
||||
|
||||
# Add zen configuration using Python for proper JSON handling
|
||||
# Add pal configuration using Python for proper JSON handling
|
||||
local temp_file=$(mktemp)
|
||||
python3 -c "
|
||||
import json
|
||||
@@ -1641,9 +1724,9 @@ try:
|
||||
if 'mcpServers' not in config:
|
||||
config['mcpServers'] = {}
|
||||
|
||||
# Add zen server
|
||||
config['mcpServers']['zen'] = {
|
||||
'command': '$zen_wrapper'
|
||||
# Add pal server
|
||||
config['mcpServers']['pal'] = {
|
||||
'command': '$pal_wrapper'
|
||||
}
|
||||
|
||||
with open('$temp_file', 'w') as f:
|
||||
@@ -1657,7 +1740,7 @@ except Exception as e:
|
||||
if [[ $? -eq 0 ]]; then
|
||||
print_success "Successfully configured Gemini CLI"
|
||||
echo " Config: $gemini_config"
|
||||
echo " Restart Gemini CLI to use Zen MCP Server"
|
||||
echo " Restart Gemini CLI to use PAL MCP Server"
|
||||
else
|
||||
print_error "Failed to update Gemini CLI config"
|
||||
echo "Manual config location: $gemini_config"
|
||||
@@ -1665,8 +1748,8 @@ except Exception as e:
|
||||
cat << EOF
|
||||
{
|
||||
"mcpServers": {
|
||||
"zen": {
|
||||
"command": "$zen_wrapper"
|
||||
"pal": {
|
||||
"command": "$pal_wrapper"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1681,14 +1764,71 @@ check_codex_cli_integration() {
|
||||
fi
|
||||
|
||||
local codex_config="$HOME/.codex/config.toml"
|
||||
local codex_has_zen=false
|
||||
if [[ -f "$codex_config" ]] && grep -q '\[mcp_servers\.zen\]' "$codex_config" 2>/dev/null; then
|
||||
codex_has_zen=true
|
||||
local legacy_names_csv
|
||||
legacy_names_csv=$(IFS=,; echo "${LEGACY_MCP_NAMES[*]}")
|
||||
|
||||
if [[ -f "$codex_config" ]]; then
|
||||
local codex_cleanup_status
|
||||
codex_cleanup_status=$(
|
||||
PAL_LEGACY_NAMES="$legacy_names_csv" PAL_CODEX_CONFIG="$codex_config" python3 - <<'PY' 2>/dev/null
|
||||
import os
|
||||
import pathlib
|
||||
import re
|
||||
import sys
|
||||
|
||||
config_path = pathlib.Path(os.environ["PAL_CODEX_CONFIG"])
|
||||
legacy = [n for n in os.environ.get("PAL_LEGACY_NAMES", "").split(",") if n]
|
||||
|
||||
if not config_path.exists():
|
||||
sys.exit(0)
|
||||
|
||||
lines = config_path.read_text().splitlines()
|
||||
output = []
|
||||
skip = False
|
||||
removed = False
|
||||
section_re = re.compile(r"\s*\[([^\]]+)\]")
|
||||
|
||||
for line in lines:
|
||||
match = section_re.match(line)
|
||||
if match:
|
||||
header = match.group(1).strip()
|
||||
parts = header.split(".")
|
||||
is_legacy = False
|
||||
if len(parts) >= 2 and parts[0] == "mcp_servers":
|
||||
section_key = ".".join(parts[1:])
|
||||
for name in legacy:
|
||||
if section_key == name or section_key.startswith(name + "."):
|
||||
is_legacy = True
|
||||
break
|
||||
skip = is_legacy
|
||||
if is_legacy:
|
||||
removed = True
|
||||
continue
|
||||
if not skip:
|
||||
output.append(line)
|
||||
|
||||
if removed:
|
||||
config_path.write_text("\n".join(output).rstrip() + ("\n" if output else ""))
|
||||
sys.stdout.write("REMOVED")
|
||||
else:
|
||||
sys.stdout.write("UNCHANGED")
|
||||
sys.exit(0)
|
||||
PY
|
||||
) || true
|
||||
|
||||
if [[ "$codex_cleanup_status" == "REMOVED" ]]; then
|
||||
print_success "Removed legacy Codex MCP entries"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "$codex_has_zen" == false ]]; then
|
||||
local codex_has_pal=false
|
||||
if [[ -f "$codex_config" ]] && grep -q '\[mcp_servers\.pal\]' "$codex_config" 2>/dev/null; then
|
||||
codex_has_pal=true
|
||||
fi
|
||||
|
||||
if [[ "$codex_has_pal" == false ]]; then
|
||||
echo ""
|
||||
read -p "Configure Zen for Codex CLI? (Y/n): " -n 1 -r
|
||||
read -p "Configure PAL for Codex CLI? (Y/n): " -n 1 -r
|
||||
echo ""
|
||||
if [[ $REPLY =~ ^[Nn]$ ]]; then
|
||||
print_info "Skipping Codex CLI integration"
|
||||
@@ -1707,12 +1847,12 @@ check_codex_cli_integration() {
|
||||
|
||||
{
|
||||
echo ""
|
||||
echo "[mcp_servers.zen]"
|
||||
echo "[mcp_servers.pal]"
|
||||
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 "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/pal-mcp-server.git pal-mcp-server; done; echo 'uvx not found' >&2; exit 1\"]"
|
||||
echo "tool_timeout_sec = 1200"
|
||||
echo ""
|
||||
echo "[mcp_servers.zen.env]"
|
||||
echo "[mcp_servers.pal.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
|
||||
while IFS= read -r line; do
|
||||
@@ -1732,12 +1872,12 @@ check_codex_cli_integration() {
|
||||
echo "Manual config location: $codex_config"
|
||||
echo "Add this configuration:"
|
||||
cat <<'CODExEOF'
|
||||
[mcp_servers.zen]
|
||||
[mcp_servers.pal]
|
||||
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"]
|
||||
args = ["-c", "exec \$(which uvx 2>/dev/null || echo uvx) --from git+https://github.com/BeehiveInnovations/pal-mcp-server.git pal-mcp-server"]
|
||||
tool_timeout_sec = 1200
|
||||
|
||||
[mcp_servers.zen.env]
|
||||
[mcp_servers.pal.env]
|
||||
PATH = "/usr/local/bin:/usr/bin:/bin:/opt/homebrew/bin:\$HOME/.local/bin:\$HOME/.cargo/bin:\$HOME/bin"
|
||||
|
||||
[features]
|
||||
@@ -1759,16 +1899,16 @@ CODExEOF
|
||||
|
||||
print_success "Successfully configured Codex CLI"
|
||||
echo " Config: $codex_config"
|
||||
echo " Restart Codex CLI to use Zen MCP Server"
|
||||
codex_has_zen=true
|
||||
echo " Restart Codex CLI to use PAL MCP Server"
|
||||
codex_has_pal=true
|
||||
else
|
||||
print_info "Codex CLI already configured; refreshing Codex settings..."
|
||||
fi
|
||||
|
||||
if [[ "$codex_has_zen" == true ]]; then
|
||||
if [[ "$codex_has_pal" == true ]]; then
|
||||
if ! grep -Eq '^\s*web_search_request\s*=' "$codex_config" 2>/dev/null; then
|
||||
echo ""
|
||||
print_info "Web search requests let Codex pull fresh documentation for Zen's API lookup tooling."
|
||||
print_info "Web search requests let Codex pull fresh documentation for PAL's API lookup tooling."
|
||||
read -p "Enable Codex CLI web search requests? (Y/n): " -n 1 -r
|
||||
echo ""
|
||||
if [[ ! $REPLY =~ ^[Nn]$ ]]; then
|
||||
@@ -1903,7 +2043,7 @@ print_qwen_manual_instructions() {
|
||||
cat << EOF
|
||||
{
|
||||
"mcpServers": {
|
||||
"zen": {
|
||||
"pal": {
|
||||
"command": "$python_cmd",
|
||||
"args": ["$server_path"],
|
||||
"cwd": "$script_dir",
|
||||
@@ -1916,7 +2056,7 @@ EOF
|
||||
cat << EOF
|
||||
{
|
||||
"mcpServers": {
|
||||
"zen": {
|
||||
"pal": {
|
||||
"command": "$python_cmd",
|
||||
"args": ["$server_path"],
|
||||
"cwd": "$script_dir"
|
||||
@@ -1956,6 +2096,43 @@ check_qwen_cli_integration() {
|
||||
env_lines=$(printf '%s\n' "${env_array[@]}")
|
||||
fi
|
||||
|
||||
local legacy_names_csv
|
||||
legacy_names_csv=$(IFS=,; echo "${LEGACY_MCP_NAMES[*]}")
|
||||
|
||||
if [[ -f "$qwen_config" ]]; then
|
||||
PAL_QWEN_LEGACY="$legacy_names_csv" PAL_QWEN_CONFIG="$qwen_config" python3 - <<'PYCLEANCONF' 2>/dev/null || true
|
||||
import json
|
||||
import os
|
||||
import pathlib
|
||||
import sys
|
||||
|
||||
config_path = pathlib.Path(os.environ.get("PAL_QWEN_CONFIG", ""))
|
||||
legacy = [n for n in os.environ.get("PAL_QWEN_LEGACY", "").split(",") if n]
|
||||
|
||||
if not config_path.exists():
|
||||
sys.exit(0)
|
||||
|
||||
try:
|
||||
data = json.loads(config_path.read_text(encoding="utf-8"))
|
||||
except Exception:
|
||||
sys.exit(0)
|
||||
|
||||
if not isinstance(data, dict):
|
||||
sys.exit(0)
|
||||
|
||||
servers = data.get("mcpServers")
|
||||
if isinstance(servers, dict):
|
||||
removed = False
|
||||
for key in legacy:
|
||||
if servers.pop(key, None) is not None:
|
||||
removed = True
|
||||
if removed:
|
||||
config_path.write_text(json.dumps(data, indent=2))
|
||||
|
||||
sys.exit(0)
|
||||
PYCLEANCONF
|
||||
fi
|
||||
|
||||
local config_status=3
|
||||
if [[ -f "$qwen_config" ]]; then
|
||||
if python3 - "$qwen_config" "$python_cmd" "$server_path" "$script_dir" <<'PYCONF'
|
||||
@@ -1975,7 +2152,7 @@ servers = data.get('mcpServers')
|
||||
if not isinstance(servers, dict):
|
||||
sys.exit(3)
|
||||
|
||||
config = servers.get('zen')
|
||||
config = servers.get('pal')
|
||||
if not isinstance(config, dict):
|
||||
sys.exit(3)
|
||||
|
||||
@@ -2006,14 +2183,14 @@ PYCONF
|
||||
echo ""
|
||||
|
||||
if [[ $config_status -eq 4 ]]; then
|
||||
print_warning "Found existing Qwen CLI zen configuration with different settings."
|
||||
print_warning "Found existing Qwen CLI pal configuration with different settings."
|
||||
elif [[ $config_status -eq 5 ]]; then
|
||||
print_warning "Unable to parse Qwen CLI settings; replacing with a fresh entry may help."
|
||||
fi
|
||||
|
||||
local prompt="Configure Zen for Qwen CLI? (Y/n): "
|
||||
local prompt="Configure PAL for Qwen CLI? (Y/n): "
|
||||
if [[ $config_status -eq 4 || $config_status -eq 5 ]]; then
|
||||
prompt="Update Qwen CLI zen configuration? (Y/n): "
|
||||
prompt="Update Qwen CLI pal configuration? (Y/n): "
|
||||
fi
|
||||
|
||||
read -p "$prompt" -n 1 -r
|
||||
@@ -2031,17 +2208,17 @@ PYCONF
|
||||
|
||||
local update_output
|
||||
local update_status=0
|
||||
update_output=$(ZEN_QWEN_ENV="$env_lines" ZEN_QWEN_CMD="$python_cmd" ZEN_QWEN_ARG="$server_path" ZEN_QWEN_CWD="$script_dir" python3 - "$qwen_config" <<'PYUPDATE'
|
||||
update_output=$(PAL_QWEN_ENV="$env_lines" PAL_QWEN_CMD="$python_cmd" PAL_QWEN_ARG="$server_path" PAL_QWEN_CWD="$script_dir" python3 - "$qwen_config" <<'PYUPDATE'
|
||||
import json
|
||||
import os
|
||||
import pathlib
|
||||
import sys
|
||||
|
||||
config_path = pathlib.Path(sys.argv[1])
|
||||
cmd = os.environ['ZEN_QWEN_CMD']
|
||||
arg = os.environ['ZEN_QWEN_ARG']
|
||||
cwd = os.environ['ZEN_QWEN_CWD']
|
||||
env_lines = os.environ.get('ZEN_QWEN_ENV', '').splitlines()
|
||||
cmd = os.environ['PAL_QWEN_CMD']
|
||||
arg = os.environ['PAL_QWEN_ARG']
|
||||
cwd = os.environ['PAL_QWEN_CWD']
|
||||
env_lines = os.environ.get('PAL_QWEN_ENV', '').splitlines()
|
||||
|
||||
env_map = {}
|
||||
for line in env_lines:
|
||||
@@ -2068,16 +2245,16 @@ if not isinstance(servers, dict):
|
||||
servers = {}
|
||||
data['mcpServers'] = servers
|
||||
|
||||
zen_config = {
|
||||
pal_config = {
|
||||
'command': cmd,
|
||||
'args': [arg],
|
||||
'cwd': cwd,
|
||||
}
|
||||
|
||||
if env_map:
|
||||
zen_config['env'] = env_map
|
||||
pal_config['env'] = env_map
|
||||
|
||||
servers['zen'] = zen_config
|
||||
servers['pal'] = pal_config
|
||||
|
||||
config_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
tmp_path = config_path.with_suffix(config_path.suffix + '.tmp')
|
||||
@@ -2091,7 +2268,7 @@ PYUPDATE
|
||||
if [[ $update_status -eq 0 ]]; then
|
||||
print_success "Successfully configured Qwen CLI"
|
||||
echo " Config: $qwen_config"
|
||||
echo " Restart Qwen CLI to use Zen MCP Server"
|
||||
echo " Restart Qwen CLI to use PAL MCP Server"
|
||||
else
|
||||
print_error "Failed to update Qwen CLI config"
|
||||
if [[ -n "$update_output" ]]; then
|
||||
@@ -2110,11 +2287,11 @@ display_config_instructions() {
|
||||
local script_dir=$(dirname "$server_path")
|
||||
|
||||
echo ""
|
||||
local config_header="ZEN MCP SERVER CONFIGURATION"
|
||||
local config_header="PAL MCP SERVER CONFIGURATION"
|
||||
echo "===== $config_header ====="
|
||||
printf '%*s\n' "$((${#config_header} + 12))" | tr ' ' '='
|
||||
echo ""
|
||||
echo "To use Zen MCP Server with your CLI clients:"
|
||||
echo "To use PAL MCP Server with your CLI clients:"
|
||||
echo ""
|
||||
|
||||
print_info "1. For Claude Code (CLI):"
|
||||
@@ -2128,7 +2305,7 @@ display_config_instructions() {
|
||||
fi
|
||||
done <<< "$env_vars"
|
||||
fi
|
||||
echo -e " ${GREEN}claude mcp add zen -s user$env_args -- $python_cmd $server_path${NC}"
|
||||
echo -e " ${GREEN}claude mcp add pal -s user$env_args -- $python_cmd $server_path${NC}"
|
||||
echo ""
|
||||
|
||||
print_info "2. For Claude Desktop:"
|
||||
@@ -2159,7 +2336,7 @@ display_config_instructions() {
|
||||
cat << EOF
|
||||
{
|
||||
"mcpServers": {
|
||||
"zen": {
|
||||
"pal": {
|
||||
"command": "$python_cmd",
|
||||
"args": ["$server_path"],
|
||||
"cwd": "$script_dir",
|
||||
@@ -2174,7 +2351,7 @@ EOF
|
||||
cat << EOF
|
||||
{
|
||||
"mcpServers": {
|
||||
"zen": {
|
||||
"pal": {
|
||||
"command": "$python_cmd",
|
||||
"args": ["$server_path"],
|
||||
"cwd": "$script_dir"
|
||||
@@ -2202,8 +2379,8 @@ EOF
|
||||
cat << EOF
|
||||
{
|
||||
"mcpServers": {
|
||||
"zen": {
|
||||
"command": "$script_dir/zen-mcp-server"
|
||||
"pal": {
|
||||
"command": "$script_dir/pal-mcp-server"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2217,7 +2394,7 @@ EOF
|
||||
cat << EOF
|
||||
{
|
||||
"mcpServers": {
|
||||
"zen": {
|
||||
"pal": {
|
||||
"command": "$python_cmd",
|
||||
"args": ["$server_path"],
|
||||
"cwd": "$script_dir",
|
||||
@@ -2232,7 +2409,7 @@ EOF
|
||||
cat << EOF
|
||||
{
|
||||
"mcpServers": {
|
||||
"zen": {
|
||||
"pal": {
|
||||
"command": "$python_cmd",
|
||||
"args": ["$server_path"],
|
||||
"cwd": "$script_dir"
|
||||
@@ -2247,11 +2424,11 @@ EOF
|
||||
echo " Add this configuration to ~/.codex/config.toml:"
|
||||
echo ""
|
||||
cat << EOF
|
||||
[mcp_servers.zen]
|
||||
[mcp_servers.pal]
|
||||
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"]
|
||||
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/pal-mcp-server.git pal-mcp-server; done; echo 'uvx not found' >&2; exit 1"]
|
||||
|
||||
[mcp_servers.zen.env]
|
||||
[mcp_servers.pal.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
|
||||
@@ -2268,7 +2445,7 @@ display_setup_instructions() {
|
||||
echo "===== $setup_header ====="
|
||||
printf '%*s\n' "$((${#setup_header} + 12))" | tr ' ' '='
|
||||
echo ""
|
||||
print_success "Zen is ready to use!"
|
||||
print_success "PAL is ready to use!"
|
||||
|
||||
# Display enabled/disabled tools if DISABLED_TOOLS is configured
|
||||
if [[ -n "${DISABLED_TOOLS:-}" ]]; then
|
||||
@@ -2348,7 +2525,7 @@ display_setup_instructions() {
|
||||
# Show help message
|
||||
show_help() {
|
||||
local version=$(get_version)
|
||||
local header="🤖 Zen MCP Server v$version"
|
||||
local header="🤖 PAL MCP Server v$version"
|
||||
echo "$header"
|
||||
printf '%*s\n' "${#header}" | tr ' ' '='
|
||||
echo ""
|
||||
@@ -2369,7 +2546,7 @@ show_help() {
|
||||
echo " $0 --clear-cache Clear Python cache (fixes import issues)"
|
||||
echo ""
|
||||
echo "For more information, visit:"
|
||||
echo " https://github.com/BeehiveInnovations/zen-mcp-server"
|
||||
echo " https://github.com/BeehiveInnovations/pal-mcp-server"
|
||||
}
|
||||
|
||||
# Show version only
|
||||
@@ -2444,7 +2621,7 @@ main() {
|
||||
esac
|
||||
|
||||
# Display header
|
||||
local main_header="🤖 Zen MCP Server"
|
||||
local main_header="🤖 PAL MCP Server"
|
||||
echo "$main_header"
|
||||
printf '%*s\n' "${#main_header}" | tr ' ' '='
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Integration test runner script for the Zen MCP server on Windows.
|
||||
Integration test runner script for the PAL MCP server on Windows.
|
||||
|
||||
.DESCRIPTION
|
||||
This PowerShell script prepares and runs integration tests for the Zen MCP server:
|
||||
This PowerShell script prepares and runs integration tests for the PAL MCP server:
|
||||
- Sets up the test environment
|
||||
- Installs required dependencies
|
||||
- Runs automated integration tests
|
||||
@@ -25,7 +25,7 @@
|
||||
Script Author : GiGiDKR (https://github.com/GiGiDKR)
|
||||
Date : 07-05-2025
|
||||
Version : See config.py (__version__)
|
||||
References : https://github.com/BeehiveInnovations/zen-mcp-server
|
||||
References : https://github.com/BeehiveInnovations/pal-mcp-server
|
||||
#>
|
||||
#Requires -Version 5.1
|
||||
[CmdletBinding()]
|
||||
@@ -64,13 +64,13 @@ function Write-Emoji {
|
||||
Write-ColorText $Text -Color $Color
|
||||
}
|
||||
|
||||
Write-Emoji "🧪" "Running Integration Tests for Zen MCP Server" -Color Cyan
|
||||
Write-Emoji "🧪" "Running Integration Tests for PAL MCP Server" -Color Cyan
|
||||
Write-ColorText "==============================================" -Color Cyan
|
||||
Write-ColorText "These tests use real API calls with your configured keys"
|
||||
Write-Host ""
|
||||
|
||||
# Check for virtual environment
|
||||
$venvPath = ".zen_venv"
|
||||
$venvPath = ".pal_venv"
|
||||
$activateScript = if ($IsWindows -or $env:OS -eq "Windows_NT") {
|
||||
"$venvPath\Scripts\Activate.ps1"
|
||||
} else {
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Zen MCP Server - Run Integration Tests
|
||||
# PAL MCP Server - Run Integration Tests
|
||||
# This script runs integration tests that require API keys
|
||||
# Run this locally on your Mac to ensure everything works end-to-end
|
||||
|
||||
set -e # Exit on any error
|
||||
|
||||
echo "🧪 Running Integration Tests for Zen MCP Server"
|
||||
echo "🧪 Running Integration Tests for PAL MCP Server"
|
||||
echo "=============================================="
|
||||
echo "These tests use real API calls with your configured keys"
|
||||
echo ""
|
||||
|
||||
# Activate virtual environment
|
||||
if [[ -f ".zen_venv/bin/activate" ]]; then
|
||||
source .zen_venv/bin/activate
|
||||
if [[ -f ".pal_venv/bin/activate" ]]; then
|
||||
source .pal_venv/bin/activate
|
||||
echo "✅ Using virtual environment"
|
||||
else
|
||||
echo "❌ No virtual environment found!"
|
||||
|
||||
30
server.py
30
server.py
@@ -1,5 +1,5 @@
|
||||
"""
|
||||
Zen MCP Server - Main server implementation
|
||||
PAL MCP Server - Main server implementation
|
||||
|
||||
This module implements the core MCP (Model Context Protocol) server that provides
|
||||
AI-powered tools for code analysis, review, and assistance using multiple AI models.
|
||||
@@ -152,17 +152,17 @@ except Exception as e:
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Log ZEN_MCP_FORCE_ENV_OVERRIDE configuration for transparency
|
||||
# Log PAL_MCP_FORCE_ENV_OVERRIDE configuration for transparency
|
||||
if env_override_enabled():
|
||||
logger.info("ZEN_MCP_FORCE_ENV_OVERRIDE enabled - .env file values will override system environment variables")
|
||||
logger.info("PAL_MCP_FORCE_ENV_OVERRIDE enabled - .env file values will override system environment variables")
|
||||
logger.debug("Environment override prevents conflicts between different AI tools passing cached API keys")
|
||||
else:
|
||||
logger.debug("ZEN_MCP_FORCE_ENV_OVERRIDE disabled - system environment variables take precedence")
|
||||
logger.debug("PAL_MCP_FORCE_ENV_OVERRIDE disabled - system environment variables take precedence")
|
||||
|
||||
|
||||
# Create the MCP server instance with a unique name identifier
|
||||
# This name is used by MCP clients to identify and connect to this specific server
|
||||
server: Server = Server("zen-server")
|
||||
server: Server = Server("pal-server")
|
||||
|
||||
|
||||
# Constants for tool filtering
|
||||
@@ -370,7 +370,7 @@ PROMPT_TEMPLATES = {
|
||||
"version": {
|
||||
"name": "version",
|
||||
"description": "Show server version and system information",
|
||||
"template": "Show Zen MCP Server version",
|
||||
"template": "Show PAL MCP Server version",
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1293,7 +1293,7 @@ async def handle_list_prompts() -> list[Prompt]:
|
||||
"""
|
||||
List all available prompts for CLI Code shortcuts.
|
||||
|
||||
This handler returns prompts that enable shortcuts like /zen:thinkdeeper.
|
||||
This handler returns prompts that enable shortcuts like /pal:thinkdeeper.
|
||||
We automatically generate prompts from all tools (1:1 mapping) plus add
|
||||
a few marketing aliases with richer templates for commonly used tools.
|
||||
|
||||
@@ -1343,7 +1343,7 @@ async def handle_get_prompt(name: str, arguments: dict[str, Any] = None) -> GetP
|
||||
"""
|
||||
Get prompt details and generate the actual prompt text.
|
||||
|
||||
This handler is called when a user invokes a prompt (e.g., /zen:thinkdeeper or /zen:chat:gpt5).
|
||||
This handler is called when a user invokes a prompt (e.g., /pal:thinkdeeper or /pal:chat:gpt5).
|
||||
It generates the appropriate text that CLI will then use to call the
|
||||
underlying tool.
|
||||
|
||||
@@ -1365,14 +1365,14 @@ async def handle_get_prompt(name: str, arguments: dict[str, Any] = None) -> GetP
|
||||
|
||||
# Handle special "continue" case
|
||||
if name.lower() == "continue":
|
||||
# This is "/zen:continue" - use chat tool as default for continuation
|
||||
# This is "/pal:continue" - use chat tool as default for continuation
|
||||
tool_name = "chat"
|
||||
template_info = {
|
||||
"name": "continue",
|
||||
"description": "Continue the previous conversation",
|
||||
"template": "Continue the conversation",
|
||||
}
|
||||
logger.debug("Using /zen:continue - defaulting to chat tool")
|
||||
logger.debug("Using /pal:continue - defaulting to chat tool")
|
||||
else:
|
||||
# Find the corresponding tool by checking prompt names
|
||||
tool_name = None
|
||||
@@ -1420,7 +1420,7 @@ async def handle_get_prompt(name: str, arguments: dict[str, Any] = None) -> GetP
|
||||
|
||||
# Generate tool call instruction
|
||||
if name.lower() == "continue":
|
||||
# "/zen:continue" case
|
||||
# "/pal:continue" case
|
||||
tool_instruction = (
|
||||
f"Continue the previous conversation using the {tool_name} tool. "
|
||||
"CRITICAL: You MUST provide the continuation_id from the previous response to maintain conversation context. "
|
||||
@@ -1461,7 +1461,7 @@ async def main():
|
||||
configure_providers()
|
||||
|
||||
# Log startup message
|
||||
logger.info("Zen MCP Server starting up...")
|
||||
logger.info("PAL MCP Server starting up...")
|
||||
logger.info(f"Log level: {log_level}")
|
||||
|
||||
# Note: MCP client info will be logged during the protocol handshake
|
||||
@@ -1487,7 +1487,7 @@ async def main():
|
||||
if IS_AUTO_MODE:
|
||||
handshake_instructions = (
|
||||
"When the user names a specific model (e.g. 'use chat with gpt5'), send that exact model in the tool call. "
|
||||
"When no model is mentioned, first use the `listmodels` tool from zen to obtain available models to choose the best one from."
|
||||
"When no model is mentioned, first use the `listmodels` tool from PAL to obtain available models to choose the best one from."
|
||||
)
|
||||
else:
|
||||
handshake_instructions = (
|
||||
@@ -1502,7 +1502,7 @@ async def main():
|
||||
read_stream,
|
||||
write_stream,
|
||||
InitializationOptions(
|
||||
server_name="zen",
|
||||
server_name="PAL",
|
||||
server_version=__version__,
|
||||
instructions=handshake_instructions,
|
||||
capabilities=ServerCapabilities(
|
||||
@@ -1514,7 +1514,7 @@ async def main():
|
||||
|
||||
|
||||
def run():
|
||||
"""Console script entry point for zen-mcp-server."""
|
||||
"""Console script entry point for pal-mcp-server."""
|
||||
try:
|
||||
asyncio.run(main())
|
||||
except KeyboardInterrupt:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"""
|
||||
Communication Simulator Tests Package
|
||||
|
||||
This package contains individual test modules for the Zen MCP Communication Simulator.
|
||||
This package contains individual test modules for the PAL MCP Communication Simulator.
|
||||
Each test is in its own file for better organization and maintainability.
|
||||
"""
|
||||
|
||||
|
||||
@@ -43,10 +43,10 @@ class BaseSimulatorTest:
|
||||
if os.path.exists(venv_python):
|
||||
return venv_python
|
||||
|
||||
# Try .zen_venv as fallback
|
||||
zen_venv_python = os.path.join(current_dir, ".zen_venv", "bin", "python")
|
||||
if os.path.exists(zen_venv_python):
|
||||
return zen_venv_python
|
||||
# Try .pal_venv as fallback
|
||||
pal_venv_python = os.path.join(current_dir, ".pal_venv", "bin", "python")
|
||||
if os.path.exists(pal_venv_python):
|
||||
return pal_venv_python
|
||||
|
||||
# Fallback to system python if venv doesn't exist
|
||||
self.logger.warning("Virtual environment not found, using system python")
|
||||
|
||||
@@ -31,7 +31,7 @@ review is essential - e.g., the issue spans multiple modules or exposes a system
|
||||
with partial analysis. Instead, respond ONLY with the JSON below (and nothing else). Clearly state the reason why
|
||||
you strongly feel this is necessary and ask the agent to inform the user why you're switching to a different tool:
|
||||
{"status": "full_codereview_required",
|
||||
"important": "Please use zen's codereview tool instead",
|
||||
"important": "Please use pal's codereview tool instead",
|
||||
"reason": "<brief, specific rationale for escalation>"}
|
||||
|
||||
SCOPE & FOCUS
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/review You are the Codex CLI code reviewer operating inside the Zen MCP server with full repository access.
|
||||
/review You are the Codex CLI code reviewer operating inside the PAL MCP server with full repository access.
|
||||
|
||||
- Inspect any relevant files directly—use your full repository access, run linters or tests as needed, and mention key commands when they inform your findings.
|
||||
- Report issues in severity order (Critical, High, Medium, Low) spanning security, correctness, performance, and maintainability while staying within scope.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
You are an external CLI agent operating inside the Zen MCP server with full repository access.
|
||||
You are an external CLI agent operating inside the PAL MCP server with full repository access.
|
||||
|
||||
- Use terminal tools to inspect files and gather context before responding; cite exact paths, symbols, or commands when they matter.
|
||||
- Provide concise, actionable responses in Markdown tailored to engineers working from the CLI.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
You are an external CLI code reviewer operating inside the Zen MCP server with full repository access.
|
||||
You are an external CLI code reviewer operating inside the PAL MCP server with full repository access.
|
||||
|
||||
- Inspect any relevant files directly—run linters or tests as needed—and mention important commands you rely on.
|
||||
- Report findings in severity order (Critical, High, Medium, Low) across security, correctness, performance, and maintainability while staying within the provided scope.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
You are the planning agent operating through the Zen MCP server.
|
||||
You are the planning agent operating through the PAL MCP server.
|
||||
|
||||
- Respond with JSON only using the planning schema fields (status, step_number, total_steps, metadata, plan_summary, etc.); request missing context via the required `files_required_to_continue` JSON structure.
|
||||
- Inspect any relevant files, scripts, or docs before outlining the plan; leverage your full CLI access for research.
|
||||
|
||||
@@ -1 +1 @@
|
||||
# Tests for Zen MCP Server
|
||||
# Tests for PAL MCP Server
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
"""
|
||||
Pytest configuration for Zen MCP Server tests
|
||||
Pytest configuration for PAL MCP Server tests
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
@@ -18,7 +18,7 @@ if str(parent_dir) not in sys.path:
|
||||
import utils.env as env_config # noqa: E402
|
||||
|
||||
# Ensure tests operate with runtime environment rather than .env overrides during imports
|
||||
env_config.reload_env({"ZEN_MCP_FORCE_ENV_OVERRIDE": "false"})
|
||||
env_config.reload_env({"PAL_MCP_FORCE_ENV_OVERRIDE": "false"})
|
||||
|
||||
# Set default model to a specific value for tests to avoid auto mode
|
||||
# This prevents all tests from failing due to missing model parameter
|
||||
@@ -187,8 +187,8 @@ def clear_model_restriction_env(monkeypatch):
|
||||
def disable_force_env_override(monkeypatch):
|
||||
"""Default tests to runtime environment visibility unless they explicitly opt in."""
|
||||
|
||||
monkeypatch.setenv("ZEN_MCP_FORCE_ENV_OVERRIDE", "false")
|
||||
env_config.reload_env({"ZEN_MCP_FORCE_ENV_OVERRIDE": "false"})
|
||||
monkeypatch.setenv("PAL_MCP_FORCE_ENV_OVERRIDE", "false")
|
||||
env_config.reload_env({"PAL_MCP_FORCE_ENV_OVERRIDE": "false"})
|
||||
monkeypatch.setenv("DEFAULT_MODEL", "gemini-2.5-flash")
|
||||
monkeypatch.setenv("MAX_CONVERSATION_TURNS", "50")
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
"temperature": 1.0,
|
||||
"candidateCount": 1,
|
||||
"thinkingConfig": {
|
||||
"thinkingBudget": 10813
|
||||
"thinking_budget": 10813
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
"temperature": 0.2,
|
||||
"candidateCount": 1,
|
||||
"thinkingConfig": {
|
||||
"thinkingBudget": 8110
|
||||
"thinking_budget": 8110
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,10 +23,10 @@
|
||||
}
|
||||
],
|
||||
"generationConfig": {
|
||||
"temperature": 0.2,
|
||||
"temperature": 1.0,
|
||||
"candidateCount": 1,
|
||||
"thinkingConfig": {
|
||||
"thinkingBudget": 8110
|
||||
"thinking_budget": 8110
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,12 +73,12 @@ def test_error_listing_respects_env_restrictions(monkeypatch, reset_registry):
|
||||
"AZURE_MODELS_CONFIG_PATH",
|
||||
):
|
||||
monkeypatch.delenv(azure_var, raising=False)
|
||||
monkeypatch.setenv("ZEN_MCP_FORCE_ENV_OVERRIDE", "false")
|
||||
env_config.reload_env({"ZEN_MCP_FORCE_ENV_OVERRIDE": "false"})
|
||||
monkeypatch.setenv("PAL_MCP_FORCE_ENV_OVERRIDE", "false")
|
||||
env_config.reload_env({"PAL_MCP_FORCE_ENV_OVERRIDE": "false"})
|
||||
try:
|
||||
import dotenv
|
||||
|
||||
monkeypatch.setattr(dotenv, "dotenv_values", lambda *_args, **_kwargs: {"ZEN_MCP_FORCE_ENV_OVERRIDE": "false"})
|
||||
monkeypatch.setattr(dotenv, "dotenv_values", lambda *_args, **_kwargs: {"PAL_MCP_FORCE_ENV_OVERRIDE": "false"})
|
||||
except ModuleNotFoundError:
|
||||
pass
|
||||
|
||||
@@ -151,7 +151,7 @@ def test_error_listing_without_restrictions_shows_full_catalog(monkeypatch, rese
|
||||
monkeypatch.setenv("OPENAI_API_KEY", "test-openai")
|
||||
monkeypatch.setenv("OPENROUTER_API_KEY", "test-openrouter")
|
||||
monkeypatch.setenv("XAI_API_KEY", "test-xai")
|
||||
monkeypatch.setenv("ZEN_MCP_FORCE_ENV_OVERRIDE", "false")
|
||||
monkeypatch.setenv("PAL_MCP_FORCE_ENV_OVERRIDE", "false")
|
||||
for azure_var in (
|
||||
"AZURE_OPENAI_API_KEY",
|
||||
"AZURE_OPENAI_ENDPOINT",
|
||||
@@ -159,11 +159,11 @@ def test_error_listing_without_restrictions_shows_full_catalog(monkeypatch, rese
|
||||
"AZURE_MODELS_CONFIG_PATH",
|
||||
):
|
||||
monkeypatch.delenv(azure_var, raising=False)
|
||||
env_config.reload_env({"ZEN_MCP_FORCE_ENV_OVERRIDE": "false"})
|
||||
env_config.reload_env({"PAL_MCP_FORCE_ENV_OVERRIDE": "false"})
|
||||
try:
|
||||
import dotenv
|
||||
|
||||
monkeypatch.setattr(dotenv, "dotenv_values", lambda *_args, **_kwargs: {"ZEN_MCP_FORCE_ENV_OVERRIDE": "false"})
|
||||
monkeypatch.setattr(dotenv, "dotenv_values", lambda *_args, **_kwargs: {"PAL_MCP_FORCE_ENV_OVERRIDE": "false"})
|
||||
except ModuleNotFoundError:
|
||||
pass
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ CASSETTE_REPLAY_ID = "chat_codegen/gemini25_pro_calculator/mldev"
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.no_mock_provider
|
||||
async def test_chat_codegen_saves_file(monkeypatch, tmp_path):
|
||||
"""Ensure Gemini 2.5 Pro responses create zen_generated.code when code is emitted."""
|
||||
"""Ensure Gemini 2.5 Pro responses create pal_generated.code when code is emitted."""
|
||||
|
||||
CASSETTE_PATH.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
@@ -65,7 +65,7 @@ async def test_chat_codegen_saves_file(monkeypatch, tmp_path):
|
||||
|
||||
working_dir = tmp_path / "codegen"
|
||||
working_dir.mkdir()
|
||||
preexisting = working_dir / "zen_generated.code"
|
||||
preexisting = working_dir / "pal_generated.code"
|
||||
preexisting.write_text("stale contents", encoding="utf-8")
|
||||
|
||||
chat_tool = ChatTool()
|
||||
@@ -102,7 +102,7 @@ async def test_chat_codegen_saves_file(monkeypatch, tmp_path):
|
||||
payload = json.loads(result[0].text)
|
||||
assert payload["status"] in {"success", "continuation_available"}
|
||||
|
||||
artifact_path = working_dir / "zen_generated.code"
|
||||
artifact_path = working_dir / "pal_generated.code"
|
||||
assert artifact_path.exists()
|
||||
saved = artifact_path.read_text()
|
||||
assert "<GENERATED-CODE>" in saved
|
||||
|
||||
@@ -133,7 +133,7 @@ class TestChatTool:
|
||||
assert "Evaluate this perspective" in formatted
|
||||
|
||||
def test_format_response_multiple_generated_code_blocks(self, tmp_path):
|
||||
"""All generated-code blocks should be combined and saved to zen_generated.code."""
|
||||
"""All generated-code blocks should be combined and saved to pal_generated.code."""
|
||||
tool = ChatTool()
|
||||
tool._model_context = SimpleNamespace(capabilities=SimpleNamespace(allow_code_generation=True))
|
||||
|
||||
@@ -148,7 +148,7 @@ class TestChatTool:
|
||||
|
||||
formatted = tool.format_response(response, request)
|
||||
|
||||
saved_path = tmp_path / "zen_generated.code"
|
||||
saved_path = tmp_path / "pal_generated.code"
|
||||
saved_content = saved_path.read_text(encoding="utf-8")
|
||||
|
||||
assert "print('world')" in saved_content
|
||||
@@ -172,7 +172,7 @@ class TestChatTool:
|
||||
|
||||
formatted = tool.format_response(response, request)
|
||||
|
||||
saved_path = tmp_path / "zen_generated.code"
|
||||
saved_path = tmp_path / "pal_generated.code"
|
||||
saved_content = saved_path.read_text(encoding="utf-8")
|
||||
|
||||
assert "print('only-once')" in saved_content
|
||||
@@ -191,7 +191,7 @@ class TestChatTool:
|
||||
|
||||
formatted = tool.format_response(response, request)
|
||||
|
||||
saved_path = tmp_path / "zen_generated.code"
|
||||
saved_path = tmp_path / "pal_generated.code"
|
||||
assert not saved_path.exists()
|
||||
assert "print('oops')" in formatted
|
||||
|
||||
@@ -206,7 +206,7 @@ class TestChatTool:
|
||||
|
||||
formatted = tool.format_response(response, request)
|
||||
|
||||
saved_path = tmp_path / "zen_generated.code"
|
||||
saved_path = tmp_path / "pal_generated.code"
|
||||
assert not saved_path.exists()
|
||||
assert "</GENERATED-CODE> just text" in formatted
|
||||
|
||||
|
||||
@@ -35,7 +35,9 @@ async def test_clink_gemini_single_digit_sum():
|
||||
assert status in {"success", "continuation_available"}
|
||||
|
||||
content = payload.get("content", "").strip()
|
||||
assert content == "4"
|
||||
# CLI may include additional metadata like <SUMMARY> tags; check first line or that "4" is present
|
||||
first_line = content.split("\n")[0].strip()
|
||||
assert first_line == "4" or "4" in content, f"Expected '4' in response, got: {content[:100]}"
|
||||
|
||||
if status == "continuation_available":
|
||||
offer = payload.get("continuation_offer") or {}
|
||||
|
||||
@@ -22,7 +22,7 @@ class TestDockerClaudeDesktopIntegration:
|
||||
"""Test MCP configuration for direct docker run"""
|
||||
config = {
|
||||
"mcpServers": {
|
||||
"zen-mcp": {
|
||||
"pal-mcp": {
|
||||
"command": "docker",
|
||||
"args": [
|
||||
"run",
|
||||
@@ -32,7 +32,7 @@ class TestDockerClaudeDesktopIntegration:
|
||||
"/path/to/.env",
|
||||
"-v",
|
||||
"/path/to/logs:/app/logs",
|
||||
"zen-mcp-server:latest",
|
||||
"pal-mcp-server:latest",
|
||||
],
|
||||
}
|
||||
}
|
||||
@@ -40,10 +40,10 @@ class TestDockerClaudeDesktopIntegration:
|
||||
|
||||
# Validate configuration structure
|
||||
assert "mcpServers" in config
|
||||
assert "zen-mcp" in config["mcpServers"]
|
||||
assert config["mcpServers"]["zen-mcp"]["command"] == "docker"
|
||||
assert "pal-mcp" in config["mcpServers"]
|
||||
assert config["mcpServers"]["pal-mcp"]["command"] == "docker"
|
||||
|
||||
args = config["mcpServers"]["zen-mcp"]["args"]
|
||||
args = config["mcpServers"]["pal-mcp"]["args"]
|
||||
assert "run" in args
|
||||
assert "--rm" in args
|
||||
assert "-i" in args
|
||||
@@ -53,27 +53,27 @@ class TestDockerClaudeDesktopIntegration:
|
||||
"""Test MCP configuration for docker-compose run"""
|
||||
config = {
|
||||
"mcpServers": {
|
||||
"zen-mcp": {
|
||||
"pal-mcp": {
|
||||
"command": "docker-compose",
|
||||
"args": ["-f", "/path/to/docker-compose.yml", "run", "--rm", "zen-mcp"],
|
||||
"args": ["-f", "/path/to/docker-compose.yml", "run", "--rm", "pal-mcp"],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Validate configuration structure
|
||||
assert config["mcpServers"]["zen-mcp"]["command"] == "docker-compose"
|
||||
assert config["mcpServers"]["pal-mcp"]["command"] == "docker-compose"
|
||||
|
||||
args = config["mcpServers"]["zen-mcp"]["args"]
|
||||
args = config["mcpServers"]["pal-mcp"]["args"]
|
||||
assert "-f" in args
|
||||
assert "run" in args
|
||||
assert "--rm" in args
|
||||
assert "zen-mcp" in args
|
||||
assert "pal-mcp" in args
|
||||
|
||||
def test_mcp_config_environment_variables(self):
|
||||
"""Test MCP configuration with inline environment variables"""
|
||||
config = {
|
||||
"mcpServers": {
|
||||
"zen-mcp": {
|
||||
"pal-mcp": {
|
||||
"command": "docker",
|
||||
"args": [
|
||||
"run",
|
||||
@@ -83,13 +83,13 @@ class TestDockerClaudeDesktopIntegration:
|
||||
"GEMINI_API_KEY=test_key",
|
||||
"-e",
|
||||
"LOG_LEVEL=INFO",
|
||||
"zen-mcp-server:latest",
|
||||
"pal-mcp-server:latest",
|
||||
],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
args = config["mcpServers"]["zen-mcp"]["args"]
|
||||
args = config["mcpServers"]["pal-mcp"]["args"]
|
||||
|
||||
# Check that environment variables are properly formatted
|
||||
env_args = [arg for arg in args if arg.startswith("-e")]
|
||||
@@ -103,23 +103,23 @@ class TestDockerClaudeDesktopIntegration:
|
||||
"""Test Windows-specific path formatting"""
|
||||
windows_config = {
|
||||
"mcpServers": {
|
||||
"zen-mcp": {
|
||||
"pal-mcp": {
|
||||
"command": "docker",
|
||||
"args": [
|
||||
"run",
|
||||
"--rm",
|
||||
"-i",
|
||||
"--env-file",
|
||||
"C:/Users/User/zen-mcp-server/.env",
|
||||
"C:/Users/User/pal-mcp-server/.env",
|
||||
"-v",
|
||||
"C:/Users/User/zen-mcp-server/logs:/app/logs",
|
||||
"zen-mcp-server:latest",
|
||||
"C:/Users/User/pal-mcp-server/logs:/app/logs",
|
||||
"pal-mcp-server:latest",
|
||||
],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
args = windows_config["mcpServers"]["zen-mcp"]["args"]
|
||||
args = windows_config["mcpServers"]["pal-mcp"]["args"]
|
||||
|
||||
# Check Windows path format
|
||||
windows_paths = [arg for arg in args if arg.startswith("C:/")]
|
||||
@@ -132,7 +132,7 @@ class TestDockerClaudeDesktopIntegration:
|
||||
"""Test validation of MCP configuration"""
|
||||
# Valid configuration
|
||||
valid_config = {
|
||||
"mcpServers": {"zen-mcp": {"command": "docker", "args": ["run", "--rm", "-i", "zen-mcp-server:latest"]}}
|
||||
"mcpServers": {"pal-mcp": {"command": "docker", "args": ["run", "--rm", "-i", "pal-mcp-server:latest"]}}
|
||||
}
|
||||
|
||||
# Validate JSON serialization
|
||||
@@ -144,19 +144,19 @@ class TestDockerClaudeDesktopIntegration:
|
||||
"""Test that MCP configuration supports stdio communication"""
|
||||
config = {
|
||||
"mcpServers": {
|
||||
"zen-mcp": {
|
||||
"pal-mcp": {
|
||||
"command": "docker",
|
||||
"args": [
|
||||
"run",
|
||||
"--rm",
|
||||
"-i", # Interactive mode for stdio
|
||||
"zen-mcp-server:latest",
|
||||
"pal-mcp-server:latest",
|
||||
],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
args = config["mcpServers"]["zen-mcp"]["args"]
|
||||
args = config["mcpServers"]["pal-mcp"]["args"]
|
||||
|
||||
# Check for interactive mode
|
||||
assert "-i" in args, "Interactive mode required for stdio communication"
|
||||
@@ -168,9 +168,9 @@ class TestDockerClaudeDesktopIntegration:
|
||||
def test_docker_image_reference(self):
|
||||
"""Test that Docker image is properly referenced"""
|
||||
configs = [
|
||||
{"image": "zen-mcp-server:latest"},
|
||||
{"image": "zen-mcp-server:v1.0.0"},
|
||||
{"image": "registry/zen-mcp-server:latest"},
|
||||
{"image": "pal-mcp-server:latest"},
|
||||
{"image": "pal-mcp-server:v1.0.0"},
|
||||
{"image": "registry/pal-mcp-server:latest"},
|
||||
]
|
||||
|
||||
for config in configs:
|
||||
@@ -185,9 +185,9 @@ class TestDockerClaudeDesktopIntegration:
|
||||
"""Create temporary MCP configuration file"""
|
||||
config = {
|
||||
"mcpServers": {
|
||||
"zen-mcp": {
|
||||
"pal-mcp": {
|
||||
"command": "docker",
|
||||
"args": ["run", "--rm", "-i", "--env-file", "/tmp/.env", "zen-mcp-server:latest"],
|
||||
"args": ["run", "--rm", "-i", "--env-file", "/tmp/.env", "pal-mcp-server:latest"],
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -206,7 +206,7 @@ class TestDockerClaudeDesktopIntegration:
|
||||
config = json.load(f)
|
||||
|
||||
assert "mcpServers" in config
|
||||
assert "zen-mcp" in config["mcpServers"]
|
||||
assert "pal-mcp" in config["mcpServers"]
|
||||
|
||||
def test_environment_file_integration(self):
|
||||
"""Test integration with .env file"""
|
||||
@@ -254,25 +254,25 @@ class TestDockerMCPErrorHandling:
|
||||
# This would test what happens when the image doesn't exist
|
||||
# In practice, Claude Desktop would show an error
|
||||
nonexistent_config = {
|
||||
"mcpServers": {"zen-mcp": {"command": "docker", "args": ["run", "--rm", "-i", "nonexistent:latest"]}}
|
||||
"mcpServers": {"pal-mcp": {"command": "docker", "args": ["run", "--rm", "-i", "nonexistent:latest"]}}
|
||||
}
|
||||
|
||||
# Configuration should be valid even if image doesn't exist
|
||||
assert "zen-mcp" in nonexistent_config["mcpServers"]
|
||||
assert "pal-mcp" in nonexistent_config["mcpServers"]
|
||||
|
||||
def test_invalid_env_file_path(self):
|
||||
"""Test handling of invalid .env file path"""
|
||||
config_with_invalid_env = {
|
||||
"mcpServers": {
|
||||
"zen-mcp": {
|
||||
"pal-mcp": {
|
||||
"command": "docker",
|
||||
"args": ["run", "--rm", "-i", "--env-file", "/nonexistent/.env", "zen-mcp-server:latest"],
|
||||
"args": ["run", "--rm", "-i", "--env-file", "/nonexistent/.env", "pal-mcp-server:latest"],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Configuration structure should still be valid
|
||||
args = config_with_invalid_env["mcpServers"]["zen-mcp"]["args"]
|
||||
args = config_with_invalid_env["mcpServers"]["pal-mcp"]["args"]
|
||||
assert "--env-file" in args
|
||||
|
||||
def test_docker_permission_issues(self):
|
||||
@@ -294,14 +294,14 @@ class TestDockerMCPErrorHandling:
|
||||
"""Test Docker resource limit configurations"""
|
||||
config_with_limits = {
|
||||
"mcpServers": {
|
||||
"zen-mcp": {
|
||||
"pal-mcp": {
|
||||
"command": "docker",
|
||||
"args": ["run", "--rm", "-i", "--memory=512m", "--cpus=1.0", "zen-mcp-server:latest"],
|
||||
"args": ["run", "--rm", "-i", "--memory=512m", "--cpus=1.0", "pal-mcp-server:latest"],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
args = config_with_limits["mcpServers"]["zen-mcp"]["args"]
|
||||
args = config_with_limits["mcpServers"]["pal-mcp"]["args"]
|
||||
|
||||
# Check for resource limits
|
||||
memory_limit = any("--memory" in arg for arg in args)
|
||||
|
||||
@@ -83,7 +83,7 @@ class TestDockerCommandValidation:
|
||||
mock_run.return_value.returncode = 0
|
||||
|
||||
# Standard build command
|
||||
build_cmd = ["docker", "build", "-t", "zen-mcp-server:latest", "."]
|
||||
build_cmd = ["docker", "build", "-t", "pal-mcp-server:latest", "."]
|
||||
|
||||
import subprocess
|
||||
|
||||
@@ -105,7 +105,7 @@ class TestDockerCommandValidation:
|
||||
".env",
|
||||
"-v",
|
||||
"logs:/app/logs",
|
||||
"zen-mcp-server:latest",
|
||||
"pal-mcp-server:latest",
|
||||
"python",
|
||||
"server.py",
|
||||
]
|
||||
@@ -128,7 +128,7 @@ class TestDockerCommandValidation:
|
||||
"/path/to/.env",
|
||||
"-v",
|
||||
"/path/to/logs:/app/logs",
|
||||
"zen-mcp-server:latest",
|
||||
"pal-mcp-server:latest",
|
||||
"python",
|
||||
"server.py",
|
||||
]
|
||||
@@ -139,7 +139,7 @@ class TestDockerCommandValidation:
|
||||
assert "--rm" in mcp_cmd # Automatic cleanup
|
||||
assert "-i" in mcp_cmd # Interactive mode
|
||||
assert "--env-file" in mcp_cmd # Environment variables
|
||||
assert "zen-mcp-server:latest" in mcp_cmd # Image
|
||||
assert "pal-mcp-server:latest" in mcp_cmd # Image
|
||||
|
||||
|
||||
class TestIntegrationChecks:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
"""
|
||||
Unit tests for Docker configuration and implementation of Zen MCP Server
|
||||
Unit tests for Docker configuration and implementation of PAL MCP Server
|
||||
|
||||
This module tests:
|
||||
- Docker and MCP configuration
|
||||
@@ -24,7 +24,7 @@ sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||
|
||||
|
||||
class TestDockerConfiguration:
|
||||
"""Tests for Docker configuration of Zen MCP Server"""
|
||||
"""Tests for Docker configuration of PAL MCP Server"""
|
||||
|
||||
def setup_method(self):
|
||||
"""Setup for each test"""
|
||||
@@ -51,7 +51,7 @@ class TestDockerConfiguration:
|
||||
# Basic YAML syntax check
|
||||
content = self.docker_compose_path.read_text()
|
||||
assert "services:" in content, "docker-compose.yml must have services"
|
||||
assert "zen-mcp" in content, "Service zen-mcp must be defined"
|
||||
assert "pal-mcp" in content, "Service pal-mcp must be defined"
|
||||
assert "build:" in content, "Build configuration must be present"
|
||||
|
||||
def test_environment_file_template(self):
|
||||
@@ -80,7 +80,7 @@ class TestDockerCommands:
|
||||
|
||||
# Simulate docker build
|
||||
subprocess.run(
|
||||
["docker", "build", "-t", "zen-mcp-server:latest", str(self.project_root)], capture_output=True, text=True
|
||||
["docker", "build", "-t", "pal-mcp-server:latest", str(self.project_root)], capture_output=True, text=True
|
||||
)
|
||||
|
||||
mock_run.assert_called_once()
|
||||
@@ -100,7 +100,7 @@ class TestDockerCommands:
|
||||
".env",
|
||||
"-v",
|
||||
"logs:/app/logs",
|
||||
"zen-mcp-server:latest",
|
||||
"pal-mcp-server:latest",
|
||||
"python",
|
||||
"server.py",
|
||||
]
|
||||
@@ -111,7 +111,7 @@ class TestDockerCommands:
|
||||
assert "--rm" in cmd, "Must contain --rm for cleanup"
|
||||
assert "-i" in cmd, "Must contain -i for stdio"
|
||||
assert "--env-file" in cmd, "Must contain --env-file"
|
||||
assert "zen-mcp-server:latest" in cmd, "Must reference the image"
|
||||
assert "pal-mcp-server:latest" in cmd, "Must reference the image"
|
||||
|
||||
@patch("subprocess.run")
|
||||
def test_docker_health_check(self, mock_run):
|
||||
@@ -121,7 +121,7 @@ class TestDockerCommands:
|
||||
|
||||
# Simulate health check
|
||||
subprocess.run(
|
||||
["docker", "run", "--rm", "zen-mcp-server:latest", "python", "/usr/local/bin/healthcheck.py"],
|
||||
["docker", "run", "--rm", "pal-mcp-server:latest", "python", "/usr/local/bin/healthcheck.py"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
@@ -187,7 +187,7 @@ class TestMCPIntegration:
|
||||
# Expected MCP configuration
|
||||
expected_config = {
|
||||
"servers": {
|
||||
"zen-docker": {
|
||||
"pal-docker": {
|
||||
"command": "docker",
|
||||
"args": [
|
||||
"run",
|
||||
@@ -197,7 +197,7 @@ class TestMCPIntegration:
|
||||
"/path/to/.env",
|
||||
"-v",
|
||||
"/path/to/logs:/app/logs",
|
||||
"zen-mcp-server:latest",
|
||||
"pal-mcp-server:latest",
|
||||
"python",
|
||||
"server.py",
|
||||
],
|
||||
@@ -208,11 +208,11 @@ class TestMCPIntegration:
|
||||
|
||||
# Check structure
|
||||
assert "servers" in expected_config
|
||||
zen_docker = expected_config["servers"]["zen-docker"]
|
||||
assert zen_docker["command"] == "docker"
|
||||
assert "run" in zen_docker["args"]
|
||||
assert "--rm" in zen_docker["args"]
|
||||
assert "-i" in zen_docker["args"]
|
||||
pal_docker = expected_config["servers"]["pal-docker"]
|
||||
assert pal_docker["command"] == "docker"
|
||||
assert "run" in pal_docker["args"]
|
||||
assert "--rm" in pal_docker["args"]
|
||||
assert "-i" in pal_docker["args"]
|
||||
|
||||
def test_stdio_communication_structure(self):
|
||||
"""Test structure of stdio communication"""
|
||||
@@ -279,7 +279,7 @@ class TestDockerPerformance:
|
||||
expected_max_size_mb = 500 # 500MB max
|
||||
|
||||
# In production, we would do:
|
||||
# result = subprocess.run(['docker', 'images', '--format', '{{.Size}}', 'zen-mcp-server:latest'])
|
||||
# result = subprocess.run(['docker', 'images', '--format', '{{.Size}}', 'pal-mcp-server:latest'])
|
||||
# Here we simulate
|
||||
simulated_size = "294MB" # Current observed size
|
||||
|
||||
@@ -346,7 +346,7 @@ LOG_LEVEL=INFO
|
||||
"-i",
|
||||
"--env-file",
|
||||
".env",
|
||||
"zen-mcp-server:latest",
|
||||
"pal-mcp-server:latest",
|
||||
"python",
|
||||
"server.py",
|
||||
]
|
||||
|
||||
@@ -39,7 +39,7 @@ class TestDockerMCPValidation:
|
||||
mock_run.return_value.returncode = 0
|
||||
|
||||
# Standard Docker MCP command
|
||||
cmd = ["docker", "run", "--rm", "-i", "--env-file", ".env", "zen-mcp-server:latest", "python", "server.py"]
|
||||
cmd = ["docker", "run", "--rm", "-i", "--env-file", ".env", "pal-mcp-server:latest", "python", "server.py"]
|
||||
|
||||
subprocess.run(cmd, capture_output=True)
|
||||
mock_run.assert_called_once_with(cmd, capture_output=True)
|
||||
|
||||
@@ -28,18 +28,18 @@ class TestDockerVolumePersistence:
|
||||
content = self.docker_compose_path.read_text()
|
||||
|
||||
# Check for named volume definition
|
||||
assert "zen-mcp-config:" in content, "zen-mcp-config volume must be defined"
|
||||
assert "pal-mcp-config:" in content, "pal-mcp-config volume must be defined"
|
||||
assert "driver: local" in content, "Named volume must use local driver"
|
||||
|
||||
# Check for volume mounts in service
|
||||
assert "./logs:/app/logs" in content, "Logs volume mount required"
|
||||
assert "zen-mcp-config:/app/conf" in content, "Config volume mount required"
|
||||
assert "pal-mcp-config:/app/conf" in content, "Config volume mount required"
|
||||
|
||||
def test_persistent_volume_creation(self):
|
||||
"""Test that persistent volumes are created correctly"""
|
||||
# This test checks that the volume configuration is valid
|
||||
# In a real environment, you might want to test actual volume creation
|
||||
volume_name = "zen-mcp-config"
|
||||
volume_name = "pal-mcp-config"
|
||||
|
||||
# Mock Docker command to check volume exists
|
||||
with patch("subprocess.run") as mock_run:
|
||||
@@ -84,7 +84,7 @@ class TestDockerVolumePersistence:
|
||||
"run",
|
||||
"--rm",
|
||||
"-v",
|
||||
"zen-mcp-config:/data",
|
||||
"pal-mcp-config:/data",
|
||||
"-v",
|
||||
"$(pwd):/backup",
|
||||
"alpine",
|
||||
@@ -97,7 +97,7 @@ class TestDockerVolumePersistence:
|
||||
]
|
||||
|
||||
# Verify command structure is valid
|
||||
assert "zen-mcp-config:/data" in backup_cmd
|
||||
assert "pal-mcp-config:/data" in backup_cmd
|
||||
assert "tar" in backup_cmd
|
||||
assert "czf" in backup_cmd
|
||||
|
||||
@@ -139,7 +139,7 @@ class TestDockerVolumeIntegration:
|
||||
# Verify that docker-compose run inherits volume configuration
|
||||
# This is more of a configuration validation test
|
||||
|
||||
compose_run_cmd = ["docker-compose", "run", "--rm", "zen-mcp"]
|
||||
compose_run_cmd = ["docker-compose", "run", "--rm", "pal-mcp"]
|
||||
|
||||
# The command should work with the existing volume configuration
|
||||
assert "docker-compose" in compose_run_cmd
|
||||
|
||||
@@ -335,7 +335,7 @@ Pour plus de détails sur chaque problème identifié, consultez les recommandat
|
||||
- [ ] Exécuter les tests de régression
|
||||
|
||||
---
|
||||
*Analyse générée automatiquement par MCP Zen* 🤖
|
||||
*Analyse générée automatiquement par MCP PAL* 🤖
|
||||
""",
|
||||
"metadata": {
|
||||
"tool_name": "analyze",
|
||||
@@ -459,13 +459,13 @@ def run_unit_tests():
|
||||
|
||||
def main():
|
||||
"""Main function."""
|
||||
print("🇫🇷 UTF-8 Integration Test - Zen MCP Server")
|
||||
print("🇫🇷 UTF-8 Integration Test - PAL MCP Server")
|
||||
print("=" * 60)
|
||||
|
||||
try:
|
||||
run_utf8_integration_tests()
|
||||
print("\n🎉 SUCCESS: All UTF-8 integration tests passed!")
|
||||
print("🚀 Zen MCP server fully supports French localization!")
|
||||
print("🚀 PAL MCP Server fully supports French localization!")
|
||||
return 0
|
||||
|
||||
except AssertionError as e:
|
||||
|
||||
@@ -5,7 +5,7 @@ This test verifies that when using continuation_id without specifying a model,
|
||||
the system correctly retrieves and uses the model from the previous conversation
|
||||
turn instead of defaulting to DEFAULT_MODEL or the custom provider's default.
|
||||
|
||||
Bug: https://github.com/BeehiveInnovations/zen-mcp-server/issues/111
|
||||
Bug: https://github.com/BeehiveInnovations/pal-mcp-server/issues/111
|
||||
"""
|
||||
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user