From 0237fb3419a70214ec9ee51130d0685cc2f15b00 Mon Sep 17 00:00:00 2001 From: Fahad Date: Thu, 26 Jun 2025 13:16:00 +0400 Subject: [PATCH 1/4] Set read-only annotation hints on each tool for security --- config.py | 4 ++-- server.py | 6 ++++++ tools/listmodels.py | 13 ++++++++----- tools/shared/base_tool.py | 13 +++++++++++++ tools/simple/base.py | 15 +++++++++++++++ tools/version.py | 13 ++++++++----- tools/workflow/base.py | 15 +++++++++++++++ 7 files changed, 67 insertions(+), 12 deletions(-) diff --git a/config.py b/config.py index 5e8667a..8a859be 100644 --- a/config.py +++ b/config.py @@ -14,9 +14,9 @@ import os # 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__ = "5.7.0" +__version__ = "5.7.1" # Last update date in ISO format -__updated__ = "2025-06-23" +__updated__ = "2025-06-26" # Primary maintainer __author__ = "Fahad Gilani" diff --git a/server.py b/server.py index ebb5ce2..32ec5b9 100644 --- a/server.py +++ b/server.py @@ -47,6 +47,7 @@ from mcp.types import ( # noqa: E402 ServerCapabilities, TextContent, Tool, + ToolAnnotations, ToolsCapability, ) @@ -559,11 +560,16 @@ async def handle_list_tools() -> list[Tool]: # Add all registered AI-powered tools from the TOOLS registry for tool in TOOLS.values(): + # Get optional annotations from the tool + annotations = tool.get_annotations() + tool_annotations = ToolAnnotations(**annotations) if annotations else None + tools.append( Tool( name=tool.name, description=tool.description, inputSchema=tool.get_input_schema(), + annotations=tool_annotations, ) ) diff --git a/tools/listmodels.py b/tools/listmodels.py index 621d4cd..2d47b0a 100644 --- a/tools/listmodels.py +++ b/tools/listmodels.py @@ -43,11 +43,11 @@ class ListModelsTool(BaseTool): def get_input_schema(self) -> dict[str, Any]: """Return the JSON schema for the tool's input""" - return { - "type": "object", - "properties": {"model": {"type": "string", "description": "Model to use (ignored by listmodels tool)"}}, - "required": [], - } + return {"type": "object", "properties": {}, "required": []} + + def get_annotations(self) -> Optional[dict[str, Any]]: + """Return tool annotations indicating this is a read-only tool""" + return {"readOnlyHint": True} def get_system_prompt(self) -> str: """No AI model needed for this tool""" @@ -57,6 +57,9 @@ class ListModelsTool(BaseTool): """Return the Pydantic model for request validation.""" return ToolRequest + def requires_model(self) -> bool: + return False + async def prepare_prompt(self, request: ToolRequest) -> str: """Not used for this utility tool""" return "" diff --git a/tools/shared/base_tool.py b/tools/shared/base_tool.py index 10b223f..f6cc658 100644 --- a/tools/shared/base_tool.py +++ b/tools/shared/base_tool.py @@ -153,6 +153,19 @@ class BaseTool(ABC): """ pass + def get_annotations(self) -> Optional[dict[str, Any]]: + """ + Return optional annotations for this tool. + + Annotations provide hints about tool behavior without being security-critical. + They help MCP clients make better decisions about tool usage. + + Returns: + Optional[dict]: Dictionary with annotation fields like readOnlyHint, destructiveHint, etc. + Returns None if no annotations are needed. + """ + return None + def requires_model(self) -> bool: """ Return whether this tool requires AI model access. diff --git a/tools/simple/base.py b/tools/simple/base.py index 31cd8b4..e001435 100644 --- a/tools/simple/base.py +++ b/tools/simple/base.py @@ -100,6 +100,21 @@ class SimpleTool(BaseTool): """ return [] + def get_annotations(self) -> Optional[dict[str, Any]]: + """ + Return tool annotations. Simple tools are read-only by default. + + All simple tools perform operations without modifying the environment. + They may call external AI models for analysis or conversation, but they + don't write files or make system changes. + + Override this method if your simple tool needs different annotations. + + Returns: + Dictionary with readOnlyHint set to True + """ + return {"readOnlyHint": True} + def format_response(self, response: str, request, model_info: Optional[dict] = None) -> str: """ Format the AI response before returning to the client. diff --git a/tools/version.py b/tools/version.py index 10886a9..1ce9311 100644 --- a/tools/version.py +++ b/tools/version.py @@ -147,11 +147,11 @@ class VersionTool(BaseTool): def get_input_schema(self) -> dict[str, Any]: """Return the JSON schema for the tool's input""" - return { - "type": "object", - "properties": {"model": {"type": "string", "description": "Model to use (ignored by version tool)"}}, - "required": [], - } + return {"type": "object", "properties": {}, "required": []} + + def get_annotations(self) -> Optional[dict[str, Any]]: + """Return tool annotations indicating this is a read-only tool""" + return {"readOnlyHint": True} def get_system_prompt(self) -> str: """No AI model needed for this tool""" @@ -161,6 +161,9 @@ class VersionTool(BaseTool): """Return the Pydantic model for request validation.""" return ToolRequest + def requires_model(self) -> bool: + return False + async def prepare_prompt(self, request: ToolRequest) -> str: """Not used for this utility tool""" return "" diff --git a/tools/workflow/base.py b/tools/workflow/base.py index 66a05d3..09d4172 100644 --- a/tools/workflow/base.py +++ b/tools/workflow/base.py @@ -110,6 +110,21 @@ class WorkflowTool(BaseTool, BaseWorkflowMixin): """ return [] + def get_annotations(self) -> Optional[dict[str, Any]]: + """ + Return tool annotations. Workflow tools are read-only by default. + + All workflow tools perform analysis and investigation without modifying + the environment. They may call external AI models for expert analysis, + but they don't write files or make system changes. + + Override this method if your workflow tool needs different annotations. + + Returns: + Dictionary with readOnlyHint set to True + """ + return {"readOnlyHint": True} + def get_input_schema(self) -> dict[str, Any]: """ Generate the complete input schema using SchemaBuilder. From 090931d7cf02b2e2d74ed04088bfa191024265bc Mon Sep 17 00:00:00 2001 From: Fahad Date: Fri, 27 Jun 2025 14:29:10 +0400 Subject: [PATCH 2/4] Fixed linebreaks Cleanup Pass excluded fields to the schema builder directly --- .../test_consensus_three_models.py | 2 +- tests/test_consensus.py | 9 +- tests/test_server.py | 7 +- tools/analyze.py | 28 ++--- tools/codereview.py | 28 ++--- tools/consensus.py | 100 ++++++++++-------- tools/planner.py | 54 +++++----- tools/precommit.py | 28 ++--- tools/refactor.py | 28 ++--- tools/secaudit.py | 28 ++--- tools/testgen.py | 14 +-- tools/tracer.py | 36 +++---- tools/version.py | 52 +-------- 13 files changed, 193 insertions(+), 221 deletions(-) diff --git a/simulator_tests/test_consensus_three_models.py b/simulator_tests/test_consensus_three_models.py index f14c8b9..8516eba 100644 --- a/simulator_tests/test_consensus_three_models.py +++ b/simulator_tests/test_consensus_three_models.py @@ -23,7 +23,7 @@ class TestConsensusThreeModels(BaseSimulatorTest): try: self.logger.info("Testing consensus tool with three models: flash:against, flash:for, local-llama:neutral") - # Send request with three ModelConfig objects using new workflow parameters + # Send request with three objects using new workflow parameters response, continuation_id = self.call_mcp_tool( "consensus", { diff --git a/tests/test_consensus.py b/tests/test_consensus.py index 5659ff3..39d0726 100644 --- a/tests/test_consensus.py +++ b/tests/test_consensus.py @@ -21,7 +21,7 @@ class TestConsensusTool: assert "COMPREHENSIVE CONSENSUS WORKFLOW" in tool.get_description() assert tool.get_default_temperature() == 0.2 # TEMPERATURE_ANALYTICAL assert tool.get_model_category() == ToolModelCategory.EXTENDED_REASONING - assert tool.requires_model() is True + assert tool.requires_model() is False # Consensus manages its own models def test_request_validation_step1(self): """Test Pydantic request model validation for step 1.""" @@ -119,8 +119,11 @@ class TestConsensusTool: # confidence field should be excluded assert "confidence" not in schema["properties"] assert "models" in schema["properties"] - # relevant_files should also be excluded - assert "relevant_files" not in schema["properties"] + # relevant_files should be present as it's used by consensus + assert "relevant_files" in schema["properties"] + + # model field should be present for Gemini compatibility (consensus uses 'models' as well) + assert "model" in schema["properties"] # Verify workflow fields that should NOT be present assert "files_checked" not in schema["properties"] diff --git a/tests/test_server.py b/tests/test_server.py index b09d954..8333e70 100644 --- a/tests/test_server.py +++ b/tests/test_server.py @@ -102,7 +102,6 @@ class TestServerTools: # Check for expected content in the markdown output assert "# Zen MCP Server Version" in content - assert "## Available Tools" in content - assert "thinkdeep" in content - assert "docgen" in content - assert "version" in content + assert "## Server Information" in content + assert "## Configuration" in content + assert "Current Version" in content diff --git a/tools/analyze.py b/tools/analyze.py index b766951..510e2d4 100644 --- a/tools/analyze.py +++ b/tools/analyze.py @@ -175,20 +175,20 @@ class AnalyzeTool(WorkflowTool): def get_description(self) -> str: return ( "COMPREHENSIVE ANALYSIS WORKFLOW - Step-by-step code analysis with expert validation. " - "This tool guides you through a systematic investigation process where you:\\n\\n" - "1. Start with step 1: describe your analysis investigation plan\\n" - "2. STOP and investigate code structure, patterns, and architectural decisions\\n" - "3. Report findings in step 2 with concrete evidence from actual code analysis\\n" - "4. Continue investigating between each step\\n" - "5. Track findings, relevant files, and insights throughout\\n" - "6. Update assessments as understanding evolves\\n" - "7. Once investigation is complete, always receive expert validation\\n\\n" - "IMPORTANT: This tool enforces investigation between steps:\\n" - "- After each call, you MUST investigate before calling again\\n" - "- Each step must include NEW evidence from code examination\\n" - "- No recursive calls without actual investigation work\\n" - "- The tool will specify which step number to use next\\n" - "- Follow the required_actions list for investigation guidance\\n\\n" + "This tool guides you through a systematic investigation process where you:\n\n" + "1. Start with step 1: describe your analysis investigation plan\n" + "2. STOP and investigate code structure, patterns, and architectural decisions\n" + "3. Report findings in step 2 with concrete evidence from actual code analysis\n" + "4. Continue investigating between each step\n" + "5. Track findings, relevant files, and insights throughout\n" + "6. Update assessments as understanding evolves\n" + "7. Once investigation is complete, always receive expert validation\n\n" + "IMPORTANT: This tool enforces investigation between steps:\n" + "- After each call, you MUST investigate before calling again\n" + "- Each step must include NEW evidence from code examination\n" + "- No recursive calls without actual investigation work\n" + "- The tool will specify which step number to use next\n" + "- Follow the required_actions list for investigation guidance\n\n" "Perfect for: comprehensive code analysis, architectural assessment, performance evaluation, " "security analysis, maintainability review, pattern detection, strategic planning." ) diff --git a/tools/codereview.py b/tools/codereview.py index ed87f7e..2913355 100644 --- a/tools/codereview.py +++ b/tools/codereview.py @@ -189,20 +189,20 @@ class CodeReviewTool(WorkflowTool): def get_description(self) -> str: return ( "COMPREHENSIVE CODE REVIEW WORKFLOW - Step-by-step code review with expert analysis. " - "This tool guides you through a systematic investigation process where you:\\n\\n" - "1. Start with step 1: describe your code review investigation plan\\n" - "2. STOP and investigate code structure, patterns, and potential issues\\n" - "3. Report findings in step 2 with concrete evidence from actual code analysis\\n" - "4. Continue investigating between each step\\n" - "5. Track findings, relevant files, and issues throughout\\n" - "6. Update assessments as understanding evolves\\n" - "7. Once investigation is complete, receive expert analysis\\n\\n" - "IMPORTANT: This tool enforces investigation between steps:\\n" - "- After each call, you MUST investigate before calling again\\n" - "- Each step must include NEW evidence from code examination\\n" - "- No recursive calls without actual investigation work\\n" - "- The tool will specify which step number to use next\\n" - "- Follow the required_actions list for investigation guidance\\n\\n" + "This tool guides you through a systematic investigation process where you:\n\n" + "1. Start with step 1: describe your code review investigation plan\n" + "2. STOP and investigate code structure, patterns, and potential issues\n" + "3. Report findings in step 2 with concrete evidence from actual code analysis\n" + "4. Continue investigating between each step\n" + "5. Track findings, relevant files, and issues throughout\n" + "6. Update assessments as understanding evolves\n" + "7. Once investigation is complete, receive expert analysis\n\n" + "IMPORTANT: This tool enforces investigation between steps:\n" + "- After each call, you MUST investigate before calling again\n" + "- Each step must include NEW evidence from code examination\n" + "- No recursive calls without actual investigation work\n" + "- The tool will specify which step number to use next\n" + "- Follow the required_actions list for investigation guidance\n\n" "Perfect for: comprehensive code review, security audits, performance analysis, " "architectural assessment, code quality evaluation, anti-pattern detection." ) diff --git a/tools/consensus.py b/tools/consensus.py index 874c300..8dcd21e 100644 --- a/tools/consensus.py +++ b/tools/consensus.py @@ -80,10 +80,6 @@ CONSENSUS_WORKFLOW_FIELD_DESCRIPTIONS = { } -class ModelConfig(dict): - """Model configuration for consensus workflow""" - - class ConsensusRequest(WorkflowRequest): """Request model for consensus workflow steps""" @@ -95,7 +91,7 @@ class ConsensusRequest(WorkflowRequest): # Investigation tracking fields findings: str = Field(..., description=CONSENSUS_WORKFLOW_FIELD_DESCRIPTIONS["findings"]) - confidence: str | None = Field("exploring", exclude=True) # Not used in consensus workflow + confidence: str = Field(default="exploring", exclude=True, description="Not used") # Consensus-specific fields (only needed in step 1) models: list[dict] | None = Field(None, description=CONSENSUS_WORKFLOW_FIELD_DESCRIPTIONS["models"]) @@ -114,8 +110,10 @@ class ConsensusRequest(WorkflowRequest): description=CONSENSUS_WORKFLOW_FIELD_DESCRIPTIONS["model_responses"], ) + # Optional images for visual debugging + images: list[str] | None = Field(default=None, description=CONSENSUS_WORKFLOW_FIELD_DESCRIPTIONS["images"]) + # Override inherited fields to exclude them from schema - model: str | None = Field(default=None, exclude=True) # Consensus uses 'models' field instead temperature: float | None = Field(default=None, exclude=True) thinking_mode: str | None = Field(default=None, exclude=True) use_websearch: bool | None = Field(default=None, exclude=True) @@ -126,7 +124,6 @@ class ConsensusRequest(WorkflowRequest): issues_found: list[dict] | None = Field(default_factory=list, exclude=True) hypothesis: str | None = Field(None, exclude=True) backtrack_from_step: int | None = Field(None, exclude=True) - images: list[str] | None = Field(default_factory=list) # Enable images for consensus workflow @model_validator(mode="after") def validate_step_one_requirements(self): @@ -174,19 +171,19 @@ class ConsensusTool(WorkflowTool): def get_description(self) -> str: return ( "COMPREHENSIVE CONSENSUS WORKFLOW - Step-by-step multi-model consensus with structured analysis. " - "This tool guides you through a systematic process where you:\\n\\n" - "1. Start with step 1: provide your own neutral analysis of the proposal\\n" - "2. The tool will then consult each specified model one by one\\n" - "3. You'll receive each model's response in subsequent steps\\n" - "4. Track and synthesize perspectives as they accumulate\\n" - "5. Final step: present comprehensive consensus and recommendations\\n\\n" - "IMPORTANT: This workflow enforces sequential model consultation:\\n" - "- Step 1 is always your independent analysis\\n" - "- Each subsequent step processes one model response\\n" - "- Total steps = number of models (each step includes consultation + response)\\n" - "- Models can have stances (for/against/neutral) for structured debate\\n" - "- Same model can be used multiple times with different stances\\n" - "- Each model + stance combination must be unique\\n\\n" + "This tool guides you through a systematic process where you:\n\n" + "1. Start with step 1: provide your own neutral analysis of the proposal\n" + "2. The tool will then consult each specified model one by one\n" + "3. You'll receive each model's response in subsequent steps\n" + "4. Track and synthesize perspectives as they accumulate\n" + "5. Final step: present comprehensive consensus and recommendations\n\n" + "IMPORTANT: This workflow enforces sequential model consultation:\n" + "- Step 1 is always your independent analysis\n" + "- Each subsequent step processes one model response\n" + "- Total steps = number of models (each step includes consultation + response)\n" + "- Models can have stances (for/against/neutral) for structured debate\n" + "- Same model can be used multiple times with different stances\n" + "- Each model + stance combination must be unique\n\n" "Perfect for: complex decisions, architectural choices, feature proposals, " "technology evaluations, strategic planning." ) @@ -230,8 +227,9 @@ of the evidence, even when it strongly points in one direction.""", """Generate input schema for consensus workflow.""" from .workflow.schema_builders import WorkflowSchemaBuilder - # Consensus workflow-specific field overrides + # Consensus tool-specific field definitions consensus_field_overrides = { + # Override standard workflow fields that need consensus-specific descriptions "step": { "type": "string", "description": CONSENSUS_WORKFLOW_FIELD_DESCRIPTIONS["step"], @@ -259,6 +257,7 @@ of the evidence, even when it strongly points in one direction.""", "items": {"type": "string"}, "description": CONSENSUS_WORKFLOW_FIELD_DESCRIPTIONS["relevant_files"], }, + # consensus-specific fields (not in base workflow) "models": { "type": "array", "items": { @@ -289,31 +288,33 @@ of the evidence, even when it strongly points in one direction.""", }, } - # Build schema without standard workflow fields we don't use + # Define excluded fields for consensus workflow + excluded_workflow_fields = [ + "files_checked", # Not used in consensus workflow + "relevant_context", # Not used in consensus workflow + "issues_found", # Not used in consensus workflow + "hypothesis", # Not used in consensus workflow + "backtrack_from_step", # Not used in consensus workflow + "confidence", # Not used in consensus workflow + ] + + excluded_common_fields = [ + "model", # Consensus uses 'models' field instead + "temperature", # Not used in consensus workflow + "thinking_mode", # Not used in consensus workflow + "use_websearch", # Not used in consensus workflow + ] + + # Build schema with proper field exclusion + # Note: We don't pass model_field_schema because consensus uses 'models' instead of 'model' schema = WorkflowSchemaBuilder.build_schema( tool_specific_fields=consensus_field_overrides, model_field_schema=self.get_model_field_schema(), auto_mode=self.is_effective_auto_mode(), tool_name=self.get_name(), + excluded_workflow_fields=excluded_workflow_fields, + excluded_common_fields=excluded_common_fields, ) - - # Remove unused workflow fields - if "properties" in schema: - for field in [ - "files_checked", - "relevant_context", - "issues_found", - "hypothesis", - "backtrack_from_step", - "confidence", # Not used in consensus workflow - "model", # Consensus uses 'models' field instead - "temperature", # Not used in consensus workflow - "thinking_mode", # Not used in consensus workflow - "use_websearch", # Not used in consensus workflow - "relevant_files", # Not used in consensus workflow - ]: - schema["properties"].pop(field, None) - return schema def get_required_actions( @@ -357,6 +358,17 @@ of the evidence, even when it strongly points in one direction.""", """Consensus workflow handles its own model consultations.""" return False + def requires_model(self) -> bool: + """ + Consensus tool doesn't require model resolution at the MCP boundary. + + Uses it's own set of models + + Returns: + bool: False + """ + return False + # Hook method overrides for consensus-specific behavior def prepare_step_data(self, request) -> dict: @@ -601,9 +613,7 @@ YOUR SUPPORTIVE ANALYSIS SHOULD: - Suggest optimizations that enhance value - Present realistic implementation pathways -Remember: Being "for" means finding the BEST possible version of the idea IF it has merit, not blindly supporting bad """ - "ideas." - "", +Remember: Being "for" means finding the BEST possible version of the idea IF it has merit, not blindly supporting bad ideas.""", "against": """CRITICAL PERSPECTIVE WITH RESPONSIBILITY You are tasked with critiquing this proposal, but with ESSENTIAL BOUNDARIES: @@ -627,9 +637,7 @@ YOUR CRITICAL ANALYSIS SHOULD: - Highlight potential negative consequences - Question assumptions that may be flawed -Remember: Being "against" means rigorous scrutiny to ensure quality, not undermining good ideas that deserve """ - "support." - "", +Remember: Being "against" means rigorous scrutiny to ensure quality, not undermining good ideas that deserve support.""", "neutral": """BALANCED PERSPECTIVE Provide objective analysis considering both positive and negative aspects. However, if there is overwhelming evidence diff --git a/tools/planner.py b/tools/planner.py index 5ab9540..bd83d34 100644 --- a/tools/planner.py +++ b/tools/planner.py @@ -21,7 +21,7 @@ architectural decisions, and breaking down large problems into manageable steps. """ import logging -from typing import TYPE_CHECKING, Any, Optional +from typing import TYPE_CHECKING, Any from pydantic import Field, field_validator @@ -67,12 +67,12 @@ class PlannerRequest(WorkflowRequest): next_step_required: bool = Field(..., description=PLANNER_FIELD_DESCRIPTIONS["next_step_required"]) # Optional revision/branching fields (planning-specific) - is_step_revision: Optional[bool] = Field(False, description=PLANNER_FIELD_DESCRIPTIONS["is_step_revision"]) - revises_step_number: Optional[int] = Field(None, description=PLANNER_FIELD_DESCRIPTIONS["revises_step_number"]) - is_branch_point: Optional[bool] = Field(False, description=PLANNER_FIELD_DESCRIPTIONS["is_branch_point"]) - branch_from_step: Optional[int] = Field(None, description=PLANNER_FIELD_DESCRIPTIONS["branch_from_step"]) - branch_id: Optional[str] = Field(None, description=PLANNER_FIELD_DESCRIPTIONS["branch_id"]) - more_steps_needed: Optional[bool] = Field(False, description=PLANNER_FIELD_DESCRIPTIONS["more_steps_needed"]) + is_step_revision: bool | None = Field(False, description=PLANNER_FIELD_DESCRIPTIONS["is_step_revision"]) + revises_step_number: int | None = Field(None, description=PLANNER_FIELD_DESCRIPTIONS["revises_step_number"]) + is_branch_point: bool | None = Field(False, description=PLANNER_FIELD_DESCRIPTIONS["is_branch_point"]) + branch_from_step: int | None = Field(None, description=PLANNER_FIELD_DESCRIPTIONS["branch_from_step"]) + branch_id: str | None = Field(None, description=PLANNER_FIELD_DESCRIPTIONS["branch_id"]) + more_steps_needed: bool | None = Field(False, description=PLANNER_FIELD_DESCRIPTIONS["more_steps_needed"]) # Exclude all investigation/analysis fields that aren't relevant to planning findings: str = Field( @@ -85,15 +85,15 @@ class PlannerRequest(WorkflowRequest): ) issues_found: list[dict] = Field(default_factory=list, exclude=True, description="Planning doesn't find issues") confidence: str = Field(default="planning", exclude=True, description="Planning uses different confidence model") - hypothesis: Optional[str] = Field(default=None, exclude=True, description="Planning doesn't use hypothesis") - backtrack_from_step: Optional[int] = Field(default=None, exclude=True, description="Planning uses revision instead") + hypothesis: str | None = Field(default=None, exclude=True, description="Planning doesn't use hypothesis") + backtrack_from_step: int | None = Field(default=None, exclude=True, description="Planning uses revision instead") # Exclude other non-planning fields - temperature: Optional[float] = Field(default=None, exclude=True) - thinking_mode: Optional[str] = Field(default=None, exclude=True) - use_websearch: Optional[bool] = Field(default=None, exclude=True) - use_assistant_model: Optional[bool] = Field(default=False, exclude=True, description="Planning is self-contained") - images: Optional[list] = Field(default=None, exclude=True, description="Planning doesn't use images") + temperature: float | None = Field(default=None, exclude=True) + thinking_mode: str | None = Field(default=None, exclude=True) + use_websearch: bool | None = Field(default=None, exclude=True) + use_assistant_model: bool | None = Field(default=False, exclude=True, description="Planning is self-contained") + images: list | None = Field(default=None, exclude=True, description="Planning doesn't use images") @field_validator("step_number") @classmethod @@ -184,10 +184,18 @@ class PlannerTool(WorkflowTool): """Return the planner-specific request model.""" return PlannerRequest - def get_tool_fields(self) -> dict[str, dict[str, Any]]: - """Return planning-specific field definitions beyond the standard workflow fields.""" - return { - # Planning-specific optional fields + def get_input_schema(self) -> dict[str, Any]: + """Generate input schema for planner workflow using override pattern.""" + from .workflow.schema_builders import WorkflowSchemaBuilder + + # Planner tool-specific field definitions + planner_field_overrides = { + # Override standard workflow fields that need planning-specific descriptions + "step": { + "type": "string", + "description": PLANNER_FIELD_DESCRIPTIONS["step"], # Very planning-specific instructions + }, + # NEW planning-specific fields (not in base workflow) "is_step_revision": { "type": "boolean", "description": PLANNER_FIELD_DESCRIPTIONS["is_step_revision"], @@ -216,11 +224,7 @@ class PlannerTool(WorkflowTool): }, } - def get_input_schema(self) -> dict[str, Any]: - """Generate input schema using WorkflowSchemaBuilder with field exclusion.""" - from .workflow.schema_builders import WorkflowSchemaBuilder - - # Exclude investigation-specific fields that planning doesn't need + # Define excluded fields for planner workflow excluded_workflow_fields = [ "findings", # Planning uses step content instead "files_checked", # Planning doesn't examine files @@ -232,7 +236,6 @@ class PlannerTool(WorkflowTool): "backtrack_from_step", # Planning uses revision instead ] - # Exclude common fields that planning doesn't need excluded_common_fields = [ "temperature", # Planning doesn't need temperature control "thinking_mode", # Planning doesn't need thinking mode @@ -241,8 +244,9 @@ class PlannerTool(WorkflowTool): "files", # Planning doesn't use files ] + # Build schema with proper field exclusion (following consensus pattern) return WorkflowSchemaBuilder.build_schema( - tool_specific_fields=self.get_tool_fields(), + tool_specific_fields=planner_field_overrides, required_fields=[], # No additional required fields beyond workflow defaults model_field_schema=self.get_model_field_schema(), auto_mode=self.is_effective_auto_mode(), diff --git a/tools/precommit.py b/tools/precommit.py index 9125bf1..6aed751 100644 --- a/tools/precommit.py +++ b/tools/precommit.py @@ -192,20 +192,20 @@ class PrecommitTool(WorkflowTool): def get_description(self) -> str: return ( "COMPREHENSIVE PRECOMMIT WORKFLOW - Step-by-step pre-commit validation with expert analysis. " - "This tool guides you through a systematic investigation process where you:\\n\\n" - "1. Start with step 1: describe your pre-commit validation plan\\n" - "2. STOP and investigate git changes, repository status, and file modifications\\n" - "3. Report findings in step 2 with concrete evidence from actual changes\\n" - "4. Continue investigating between each step\\n" - "5. Track findings, relevant files, and issues throughout\\n" - "6. Update assessments as understanding evolves\\n" - "7. Once investigation is complete, receive expert analysis\\n\\n" - "IMPORTANT: This tool enforces investigation between steps:\\n" - "- After each call, you MUST investigate before calling again\\n" - "- Each step must include NEW evidence from git analysis\\n" - "- No recursive calls without actual investigation work\\n" - "- The tool will specify which step number to use next\\n" - "- Follow the required_actions list for investigation guidance\\n\\n" + "This tool guides you through a systematic investigation process where you:\n\n" + "1. Start with step 1: describe your pre-commit validation plan\n" + "2. STOP and investigate git changes, repository status, and file modifications\n" + "3. Report findings in step 2 with concrete evidence from actual changes\n" + "4. Continue investigating between each step\n" + "5. Track findings, relevant files, and issues throughout\n" + "6. Update assessments as understanding evolves\n" + "7. Once investigation is complete, receive expert analysis\n\n" + "IMPORTANT: This tool enforces investigation between steps:\n" + "- After each call, you MUST investigate before calling again\n" + "- Each step must include NEW evidence from git analysis\n" + "- No recursive calls without actual investigation work\n" + "- The tool will specify which step number to use next\n" + "- Follow the required_actions list for investigation guidance\n\n" "Perfect for: comprehensive pre-commit validation, multi-repository analysis, " "security review, change impact assessment, completeness verification." ) diff --git a/tools/refactor.py b/tools/refactor.py index 75829d8..9aa60a3 100644 --- a/tools/refactor.py +++ b/tools/refactor.py @@ -188,20 +188,20 @@ class RefactorTool(WorkflowTool): def get_description(self) -> str: return ( "COMPREHENSIVE REFACTORING WORKFLOW - Step-by-step refactoring analysis with expert validation. " - "This tool guides you through a systematic investigation process where you:\\n\\n" - "1. Start with step 1: describe your refactoring investigation plan\\n" - "2. STOP and investigate code structure, patterns, and potential improvements\\n" - "3. Report findings in step 2 with concrete evidence from actual code analysis\\n" - "4. Continue investigating between each step\\n" - "5. Track findings, relevant files, and refactoring opportunities throughout\\n" - "6. Update assessments as understanding evolves\\n" - "7. Once investigation is complete, receive expert analysis\\n\\n" - "IMPORTANT: This tool enforces investigation between steps:\\n" - "- After each call, you MUST investigate before calling again\\n" - "- Each step must include NEW evidence from code examination\\n" - "- No recursive calls without actual investigation work\\n" - "- The tool will specify which step number to use next\\n" - "- Follow the required_actions list for investigation guidance\\n\\n" + "This tool guides you through a systematic investigation process where you:\n\n" + "1. Start with step 1: describe your refactoring investigation plan\n" + "2. STOP and investigate code structure, patterns, and potential improvements\n" + "3. Report findings in step 2 with concrete evidence from actual code analysis\n" + "4. Continue investigating between each step\n" + "5. Track findings, relevant files, and refactoring opportunities throughout\n" + "6. Update assessments as understanding evolves\n" + "7. Once investigation is complete, receive expert analysis\n\n" + "IMPORTANT: This tool enforces investigation between steps:\n" + "- After each call, you MUST investigate before calling again\n" + "- Each step must include NEW evidence from code examination\n" + "- No recursive calls without actual investigation work\n" + "- The tool will specify which step number to use next\n" + "- Follow the required_actions list for investigation guidance\n\n" "Perfect for: comprehensive refactoring analysis, code smell detection, decomposition planning, " "modernization opportunities, organization improvements, maintainability enhancements." ) diff --git a/tools/secaudit.py b/tools/secaudit.py index 075e932..35d04fc 100644 --- a/tools/secaudit.py +++ b/tools/secaudit.py @@ -218,20 +218,20 @@ class SecauditTool(WorkflowTool): """Return a description of the tool.""" return ( "COMPREHENSIVE SECURITY AUDIT WORKFLOW - Step-by-step security assessment with expert analysis. " - "This tool guides you through a systematic investigation process where you:\\n\\n" - "1. Start with step 1: describe your security investigation plan\\n" - "2. STOP and investigate code structure, patterns, and security issues\\n" - "3. Report findings in step 2 with concrete evidence from actual code analysis\\n" - "4. Continue investigating between each step\\n" - "5. Track findings, relevant files, and security issues throughout\\n" - "6. Update assessments as understanding evolves\\n" - "7. Once investigation is complete, receive expert security analysis\\n\\n" - "IMPORTANT: This tool enforces investigation between steps:\\n" - "- After each call, you MUST investigate before calling again\\n" - "- Each step must include NEW evidence from code examination\\n" - "- No recursive calls without actual investigation work\\n" - "- The tool will specify which step number to use next\\n" - "- Follow the required_actions list for investigation guidance\\n\\n" + "This tool guides you through a systematic investigation process where you:\n\n" + "1. Start with step 1: describe your security investigation plan\n" + "2. STOP and investigate code structure, patterns, and security issues\n" + "3. Report findings in step 2 with concrete evidence from actual code analysis\n" + "4. Continue investigating between each step\n" + "5. Track findings, relevant files, and security issues throughout\n" + "6. Update assessments as understanding evolves\n" + "7. Once investigation is complete, receive expert security analysis\n\n" + "IMPORTANT: This tool enforces investigation between steps:\n" + "- After each call, you MUST investigate before calling again\n" + "- Each step must include NEW evidence from code examination\n" + "- No recursive calls without actual investigation work\n" + "- The tool will specify which step number to use next\n" + "- Follow the required_actions list for investigation guidance\n\n" "Perfect for: comprehensive security assessment, OWASP Top 10 analysis, compliance evaluation, " "vulnerability identification, threat modeling, security architecture review." ) diff --git a/tools/testgen.py b/tools/testgen.py index 7118614..1ed8b7b 100644 --- a/tools/testgen.py +++ b/tools/testgen.py @@ -309,26 +309,26 @@ class TestGenTool(WorkflowTool): def prepare_expert_analysis_context(self, consolidated_findings) -> str: """Prepare context for external model call for test generation validation.""" context_parts = [ - f"=== TEST GENERATION REQUEST ===\\n{self.initial_request or 'Test generation workflow initiated'}\\n=== END REQUEST ===" + f"=== TEST GENERATION REQUEST ===\n{self.initial_request or 'Test generation workflow initiated'}\n=== END REQUEST ===" ] # Add investigation summary investigation_summary = self._build_test_generation_summary(consolidated_findings) context_parts.append( - f"\\n=== CLAUDE'S TEST PLANNING INVESTIGATION ===\\n{investigation_summary}\\n=== END INVESTIGATION ===" + f"\n=== CLAUDE'S TEST PLANNING INVESTIGATION ===\n{investigation_summary}\n=== END INVESTIGATION ===" ) # Add relevant code elements if available if consolidated_findings.relevant_context: - methods_text = "\\n".join(f"- {method}" for method in consolidated_findings.relevant_context) - context_parts.append(f"\\n=== CODE ELEMENTS TO TEST ===\\n{methods_text}\\n=== END CODE ELEMENTS ===") + methods_text = "\n".join(f"- {method}" for method in consolidated_findings.relevant_context) + context_parts.append(f"\n=== CODE ELEMENTS TO TEST ===\n{methods_text}\n=== END CODE ELEMENTS ===") # Add images if available if consolidated_findings.images: - images_text = "\\n".join(f"- {img}" for img in consolidated_findings.images) - context_parts.append(f"\\n=== VISUAL DOCUMENTATION ===\\n{images_text}\\n=== END VISUAL DOCUMENTATION ===") + images_text = "\n".join(f"- {img}" for img in consolidated_findings.images) + context_parts.append(f"\n=== VISUAL DOCUMENTATION ===\n{images_text}\n=== END VISUAL DOCUMENTATION ===") - return "\\n".join(context_parts) + return "\n".join(context_parts) def _build_test_generation_summary(self, consolidated_findings) -> str: """Prepare a comprehensive summary of the test generation investigation.""" diff --git a/tools/tracer.py b/tools/tracer.py index 03e6997..5c75def 100644 --- a/tools/tracer.py +++ b/tools/tracer.py @@ -181,24 +181,24 @@ class TracerTool(WorkflowTool): def get_description(self) -> str: return ( "STEP-BY-STEP CODE TRACING WORKFLOW - Systematic code analysis through guided investigation. " - "This tool guides you through a structured investigation process where you:\\n\\n" - "1. Start with step 1: describe your tracing plan and target\\n" - "2. STOP and investigate code structure, patterns, and relationships\\n" - "3. Report findings in step 2 with concrete evidence from actual code analysis\\n" - "4. Continue investigating between each step\\n" - "5. Track findings, relevant files, and code relationships throughout\\n" - "6. Build comprehensive understanding as analysis evolves\\n" - "7. Complete with detailed output formatted according to trace mode\\n\\n" - "IMPORTANT: This tool enforces investigation between steps:\\n" - "- After each call, you MUST investigate before calling again\\n" - "- Each step must include NEW evidence from code examination\\n" - "- No recursive calls without actual investigation work\\n" - "- The tool will specify which step number to use next\\n" - "- Follow the required_actions list for investigation guidance\\n\\n" - "TRACE MODES:\\n" - "- 'ask': Default mode - prompts you to choose between precision or dependencies modes with explanations\\n" - "- 'precision': For methods/functions - traces execution flow, call chains, and usage patterns\\n" - "- 'dependencies': For classes/modules - maps structural relationships and bidirectional dependencies\\n\\n" + "This tool guides you through a structured investigation process where you:\n\n" + "1. Start with step 1: describe your tracing plan and target\n" + "2. STOP and investigate code structure, patterns, and relationships\n" + "3. Report findings in step 2 with concrete evidence from actual code analysis\n" + "4. Continue investigating between each step\n" + "5. Track findings, relevant files, and code relationships throughout\n" + "6. Build comprehensive understanding as analysis evolves\n" + "7. Complete with detailed output formatted according to trace mode\n\n" + "IMPORTANT: This tool enforces investigation between steps:\n" + "- After each call, you MUST investigate before calling again\n" + "- Each step must include NEW evidence from code examination\n" + "- No recursive calls without actual investigation work\n" + "- The tool will specify which step number to use next\n" + "- Follow the required_actions list for investigation guidance\n\n" + "TRACE MODES:\n" + "- 'ask': Default mode - prompts you to choose between precision or dependencies modes with explanations\n" + "- 'precision': For methods/functions - traces execution flow, call chains, and usage patterns\n" + "- 'dependencies': For classes/modules - maps structural relationships and bidirectional dependencies\n\n" "Perfect for: method execution flow analysis, dependency mapping, call chain tracing, " "structural relationship analysis, architectural understanding, code comprehension." ) diff --git a/tools/version.py b/tools/version.py index 1ce9311..edbac8e 100644 --- a/tools/version.py +++ b/tools/version.py @@ -250,42 +250,6 @@ class VersionTool(BaseTool): output_lines.append("") - # Python and system information - output_lines.append("## System Information") - output_lines.append( - f"**Python Version**: {sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}" - ) - output_lines.append(f"**Platform**: {platform.system()} {platform.release()}") - output_lines.append(f"**Architecture**: {platform.machine()}") - output_lines.append("") - - # Available tools - try: - # Import here to avoid circular imports - from server import TOOLS - - tool_names = sorted(TOOLS.keys()) - output_lines.append("## Available Tools") - output_lines.append(f"**Total Tools**: {len(tool_names)}") - output_lines.append("\n**Tool List**:") - - for tool_name in tool_names: - tool = TOOLS[tool_name] - # Get the first line of the tool's description for a brief summary - description = tool.get_description().split("\n")[0] - # Truncate if too long - if len(description) > 80: - description = description[:77] + "..." - output_lines.append(f"- `{tool_name}` - {description}") - - output_lines.append("") - - except Exception as e: - logger.warning(f"Error loading tools list: {e}") - output_lines.append("## Available Tools") - output_lines.append("**Error**: Could not load tools list") - output_lines.append("") - # Configuration information output_lines.append("## Configuration") @@ -301,10 +265,11 @@ class VersionTool(BaseTool): ProviderType.GOOGLE, ProviderType.OPENAI, ProviderType.XAI, + ProviderType.DIAL, ProviderType.OPENROUTER, ProviderType.CUSTOM, ] - provider_names = ["Google Gemini", "OpenAI", "X.AI", "OpenRouter", "Custom/Local"] + provider_names = ["Google Gemini", "OpenAI", "X.AI", "DIAL", "OpenRouter", "Custom/Local"] for provider_type, provider_name in zip(provider_types, provider_names): provider = ModelProviderRegistry.get_provider(provider_type) @@ -317,23 +282,16 @@ class VersionTool(BaseTool): # Get total available models try: available_models = ModelProviderRegistry.get_available_models(respect_restrictions=True) - output_lines.append(f"\n**Available Models**: {len(available_models)}") + output_lines.append(f"\n\n**Available Models**: {len(available_models)}") except Exception: - output_lines.append("\n**Available Models**: Unknown") + output_lines.append("\n\n**Available Models**: Unknown") except Exception as e: logger.warning(f"Error checking provider configuration: {e}") - output_lines.append("**Providers**: Error checking configuration") + output_lines.append("\n\n**Providers**: Error checking configuration") output_lines.append("") - # Usage information - output_lines.append("## Usage") - output_lines.append("- Use `listmodels` tool to see all available AI models") - output_lines.append("- Use `chat` for interactive conversations and brainstorming") - output_lines.append("- Use workflow tools (`debug`, `codereview`, `docgen`, etc.) for systematic analysis") - output_lines.append("- Set DEFAULT_MODEL=auto to let Claude choose the best model for each task") - # Format output content = "\n".join(output_lines) From ca8479acc11abe647952316f6f3c7d7092e2f670 Mon Sep 17 00:00:00 2001 From: Fahad Date: Fri, 27 Jun 2025 18:33:21 +0400 Subject: [PATCH 3/4] Fixed https://github.com/BeehiveInnovations/zen-mcp-server/issues/147 --- config.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config.py b/config.py index 8a859be..1106d40 100644 --- a/config.py +++ b/config.py @@ -14,9 +14,9 @@ import os # 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__ = "5.7.1" +__version__ = "5.7.2" # Last update date in ISO format -__updated__ = "2025-06-26" +__updated__ = "2025-06-27" # Primary maintainer __author__ = "Fahad Gilani" From 71cbff539e837553065cf4781451dc39dba2a9b9 Mon Sep 17 00:00:00 2001 From: Fahad Date: Fri, 27 Jun 2025 19:04:22 +0400 Subject: [PATCH 4/4] Bump --- config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.py b/config.py index 2ac8a13..f995bc3 100644 --- a/config.py +++ b/config.py @@ -14,7 +14,7 @@ import os # 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__ = "5.7.2" +__version__ = "5.7.3" # Last update date in ISO format __updated__ = "2025-06-27" # Primary maintainer