diff --git a/v2/FuzzingBrain.sh b/v2/FuzzingBrain.sh
index 0592e45..e5824e0 100755
--- a/v2/FuzzingBrain.sh
+++ b/v2/FuzzingBrain.sh
@@ -265,7 +265,7 @@ start_mongodb() {
             --restart=always \
             -p 0.0.0.0:${MONGODB_PORT}:27017 \
             -v fuzzingbrain-mongodb-data:/data/db \
-            mongo:8.0 > /dev/null
+            mongo:8.2 > /dev/null
 
         # Wait for MongoDB to start
         print_info "Waiting for MongoDB to start..."
diff --git a/v2/docker-compose.yml b/v2/docker-compose.yml
index 3e16756..c6366a0 100644
--- a/v2/docker-compose.yml
+++ b/v2/docker-compose.yml
@@ -1,7 +1,7 @@
 # SPDX-License-Identifier: Apache-2.0
 services:
   fb-mongo:
-    image: mongo:8.0
+    image: mongo:8.2
     container_name: fb-mongo
     restart: unless-stopped
     volumes:
diff --git a/v2/fuzzingbrain/fuzzer/seed_tools.py b/v2/fuzzingbrain/fuzzer/seed_tools.py
index 63ee779..ebc9c8b 100644
--- a/v2/fuzzingbrain/fuzzer/seed_tools.py
+++ b/v2/fuzzingbrain/fuzzer/seed_tools.py
@@ -422,7 +422,7 @@ def create_seed_impl(
 # =============================================================================
 
 
-@tools_mcp.tool
+@tools_mcp.tool()
 def create_seed(
     generator_code: str,
     num_seeds: int = 5,
@@ -517,7 +517,7 @@ def create_seed(
     )
 
 
-@tools_mcp.tool
+@tools_mcp.tool()
 def get_seed_context_info() -> Dict[str, Any]:
     """
     Get current seed generation context information.
diff --git a/v2/fuzzingbrain/llms/__init__.py b/v2/fuzzingbrain/llms/__init__.py
index 85fcfdf..0b5e217 100644
--- a/v2/fuzzingbrain/llms/__init__.py
+++ b/v2/fuzzingbrain/llms/__init__.py
@@ -42,6 +42,7 @@ from .models import (
     GPT_5_2_INSTANT,
     GPT_5_2_PRO,
     GPT_5_2_CODEX,
+    KIMI_FOR_CODING,
     GPT_5_MINI,
     GPT_5,
     O3,
@@ -144,6 +145,7 @@ __all__ = [
     "GPT_5_2_INSTANT",
     "GPT_5_2_PRO",
     "GPT_5_2_CODEX",
+    "KIMI_FOR_CODING",
     "O3",
     "O3_MINI",
     "GPT_5_MINI",
diff --git a/v2/fuzzingbrain/llms/client.py b/v2/fuzzingbrain/llms/client.py
index d9fc2d3..1dd6285 100644
--- a/v2/fuzzingbrain/llms/client.py
+++ b/v2/fuzzingbrain/llms/client.py
@@ -58,6 +58,10 @@ def _calculate_cost(
     """
     # Try to get model info for pricing
     model_info = get_model_by_id(model_id)
+    if model_info is None and "/" in model_id:
+        # litellm-format IDs carry a provider prefix (openai/kimi-for-coding);
+        # the registry keys the bare ID.
+        model_info = get_model_by_id(model_id.split("/")[-1])
 
     if model_info:
         price_input = model_info.price_input  # per million
@@ -454,6 +458,11 @@ class LLMClient:
         if model.provider == Provider.ANTHROPIC:
             return model.id  # litellm uses raw anthropic IDs
         elif model.provider == Provider.OPENAI:
+            # kimi-for-coding is served by the OpenAI-compatible Kimi Code
+            # endpoint; force litellm's openai provider so it honors
+            # OPENAI_BASE_URL instead of guessing a moonshot route.
+            if model.id == "kimi-for-coding":
+                return f"openai/{model.id}"
             return model.id
         elif model.provider == Provider.GOOGLE:
             return f"gemini/{model.id}"
@@ -650,6 +659,11 @@ class LLMClient:
             "timeout": self.config.timeout,
         }
 
+        # The Kimi Code endpoint only accepts temperature=1; clamp to avoid
+        # 400s when strategies pass lower temperatures.
+        if model_id == "openai/kimi-for-coding":
+            params["temperature"] = 1.0
+
         # Retry transient errors (rate limit / 5xx / timeout) on the same model
         # with exponential backoff before falling back to another model. litellm
         # honors num_retries internally and respects Retry-After. Failed attempts
diff --git a/v2/fuzzingbrain/llms/models.py b/v2/fuzzingbrain/llms/models.py
index cd22c7d..4e1ad27 100644
--- a/v2/fuzzingbrain/llms/models.py
+++ b/v2/fuzzingbrain/llms/models.py
@@ -199,6 +199,22 @@ GPT_5_1_CODEX_MAX = ModelInfo(
     max_output=100_000,
 )
 
+
+# Kimi Code subscription endpoint (OpenAI-compatible, api.kimi.com/coding/v1).
+# Subscription quota, not per-token billing: zero prices, and the OpenAI SDK
+# reads OPENAI_BASE_URL for routing.
+KIMI_FOR_CODING = ModelInfo(
+    id="kimi-for-coding",
+    alias="kimi-for-coding",
+    provider=Provider.OPENAI,
+    name="Kimi K2.7 Code (subscription)",
+    description="Kimi Code membership endpoint, coding-tuned, 262k context",
+    price_input=0.0,
+    price_output=0.0,
+    context_window=262_144,
+    max_output=32_000,
+)
+
 OPENAI_MODELS = [
     GPT_5_2,
     GPT_5_2_INSTANT,
@@ -210,6 +226,7 @@ OPENAI_MODELS = [
     GPT_5,
     GPT_5_1,
     GPT_5_1_CODEX_MAX,
+    KIMI_FOR_CODING,
 ]
 
 
diff --git a/v2/fuzzingbrain/tools/analyzer.py b/v2/fuzzingbrain/tools/analyzer.py
index a236044..30de5f1 100644
--- a/v2/fuzzingbrain/tools/analyzer.py
+++ b/v2/fuzzingbrain/tools/analyzer.py
@@ -133,7 +133,7 @@ def _ensure_client() -> Dict[str, Any]:
 # =============================================================================
 
 
-@tools_mcp.tool
+@tools_mcp.tool()
 def analyzer_status() -> Dict[str, Any]:
     """
     Get Analysis Server status.
@@ -163,7 +163,7 @@ def analyzer_status() -> Dict[str, Any]:
 # =============================================================================
 
 
-@tools_mcp.tool
+@tools_mcp.tool()
 def get_function(function_name: str) -> Dict[str, Any]:
     """
     Get metadata about a function (file path, line numbers, complexity, parameters).
@@ -197,7 +197,7 @@ def get_function(function_name: str) -> Dict[str, Any]:
         }
 
 
-@tools_mcp.tool
+@tools_mcp.tool()
 def get_functions_by_file(file_path: str) -> Dict[str, Any]:
     """
     Get all functions defined in a specific file.
@@ -229,7 +229,7 @@ def get_functions_by_file(file_path: str) -> Dict[str, Any]:
         }
 
 
-@tools_mcp.tool
+@tools_mcp.tool()
 def search_functions(pattern: str, limit: int = 50) -> Dict[str, Any]:
     """
     Search for functions by name pattern.
@@ -261,7 +261,7 @@ def search_functions(pattern: str, limit: int = 50) -> Dict[str, Any]:
         }
 
 
-@tools_mcp.tool
+@tools_mcp.tool()
 def get_function_source(function_name: str) -> Dict[str, Any]:
     """
     Get the full source code of a function.
@@ -304,7 +304,7 @@ def get_function_source(function_name: str) -> Dict[str, Any]:
 # =============================================================================
 
 
-@tools_mcp.tool
+@tools_mcp.tool()
 def get_callers(function_name: str) -> Dict[str, Any]:
     """
     Get all functions that call the specified function (who calls this function?).
@@ -339,7 +339,7 @@ def get_callers(function_name: str) -> Dict[str, Any]:
         }
 
 
-@tools_mcp.tool
+@tools_mcp.tool()
 def get_callees(function_name: str) -> Dict[str, Any]:
     """
     Get all functions called by the specified function (what does this function call?).
@@ -374,7 +374,7 @@ def get_callees(function_name: str) -> Dict[str, Any]:
         }
 
 
-@tools_mcp.tool
+@tools_mcp.tool()
 def get_call_graph(fuzzer_name: str, depth: int = 3) -> Dict[str, Any]:
     """
     Get the call graph starting from a fuzzer entry point.
@@ -409,7 +409,7 @@ def get_call_graph(fuzzer_name: str, depth: int = 3) -> Dict[str, Any]:
         }
 
 
-@tools_mcp.tool
+@tools_mcp.tool()
 def find_all_paths(
     from_function: str,
     to_function: str,
@@ -455,7 +455,7 @@ def find_all_paths(
 # =============================================================================
 
 
-@tools_mcp.tool
+@tools_mcp.tool()
 def check_reachability(fuzzer_name: str, function_name: str) -> Dict[str, Any]:
     """
     Check if a function is reachable from a fuzzer entry point.
@@ -494,7 +494,7 @@ def check_reachability(fuzzer_name: str, function_name: str) -> Dict[str, Any]:
         }
 
 
-@tools_mcp.tool
+@tools_mcp.tool()
 def get_reachable_functions(fuzzer_name: str) -> Dict[str, Any]:
     """
     Get all functions reachable from a fuzzer entry point.
@@ -528,7 +528,7 @@ def get_reachable_functions(fuzzer_name: str) -> Dict[str, Any]:
         }
 
 
-@tools_mcp.tool
+@tools_mcp.tool()
 def get_unreached_functions(fuzzer_name: str) -> Dict[str, Any]:
     """
     Get functions NOT reachable from a fuzzer (coverage gaps).
@@ -567,7 +567,7 @@ def get_unreached_functions(fuzzer_name: str) -> Dict[str, Any]:
 # =============================================================================
 
 
-@tools_mcp.tool
+@tools_mcp.tool()
 def get_fuzzers() -> Dict[str, Any]:
     """
     Get list of all built fuzzers.
@@ -594,7 +594,7 @@ def get_fuzzers() -> Dict[str, Any]:
         }
 
 
-@tools_mcp.tool
+@tools_mcp.tool()
 def get_fuzzer_source(fuzzer_name: str) -> Dict[str, Any]:
     """
     Get the source code of a fuzzer/harness.
@@ -633,7 +633,7 @@ def get_fuzzer_source(fuzzer_name: str) -> Dict[str, Any]:
         }
 
 
-@tools_mcp.tool
+@tools_mcp.tool()
 def get_build_paths() -> Dict[str, Any]:
     """
     Get build output paths for each sanitizer.
diff --git a/v2/fuzzingbrain/tools/code_viewer.py b/v2/fuzzingbrain/tools/code_viewer.py
index fb0cad2..8eb704e 100644
--- a/v2/fuzzingbrain/tools/code_viewer.py
+++ b/v2/fuzzingbrain/tools/code_viewer.py
@@ -129,7 +129,7 @@ def _ensure_context() -> Optional[Dict[str, Any]]:
 # =============================================================================
 
 
-@tools_mcp.tool
+@tools_mcp.tool()
 def get_diff() -> Dict[str, Any]:
     """
     Read the diff file for the current task.
@@ -199,7 +199,7 @@ def get_diff_impl() -> Dict[str, Any]:
 # =============================================================================
 
 
-@tools_mcp.tool
+@tools_mcp.tool()
 def get_file_content(
     file_path: str,
     start_line: Optional[int] = None,
@@ -432,7 +432,7 @@ def get_file_content_impl(
 # =============================================================================
 
 
-@tools_mcp.tool
+@tools_mcp.tool()
 def search_code(
     pattern: str,
     file_pattern: Optional[str] = None,
@@ -782,7 +782,7 @@ def search_code_impl(
 # =============================================================================
 
 
-@tools_mcp.tool
+@tools_mcp.tool()
 def list_files(
     directory: str = "",
     pattern: Optional[str] = None,
diff --git a/v2/fuzzingbrain/tools/coverage.py b/v2/fuzzingbrain/tools/coverage.py
index 05e452f..c620aa8 100644
--- a/v2/fuzzingbrain/tools/coverage.py
+++ b/v2/fuzzingbrain/tools/coverage.py
@@ -863,7 +863,7 @@ def _get_context_ranges(
 # =============================================================================
 
 
-@tools_mcp.tool
+@tools_mcp.tool()
 def run_coverage(
     fuzzer_name: str,
     input_data_base64: str,
@@ -969,7 +969,7 @@ def _run_coverage_in_dir(
     )
 
 
-@tools_mcp.tool
+@tools_mcp.tool()
 def check_pov_reaches_target(
     fuzzer_name: str,
     pov_data_base64: str,
@@ -1000,7 +1000,7 @@ def check_pov_reaches_target(
     }
 
 
-@tools_mcp.tool
+@tools_mcp.tool()
 def list_available_fuzzers() -> Dict[str, Any]:
     """
     List all available coverage-instrumented fuzzers.
@@ -1075,7 +1075,7 @@ def list_available_fuzzers() -> Dict[str, Any]:
     }
 
 
-@tools_mcp.tool
+@tools_mcp.tool()
 def get_coverage_feedback(
     fuzzer_name: str,
     input_data_base64: str,
diff --git a/v2/fuzzingbrain/tools/directions.py b/v2/fuzzingbrain/tools/directions.py
index de1936a..a9cbb5b 100644
--- a/v2/fuzzingbrain/tools/directions.py
+++ b/v2/fuzzingbrain/tools/directions.py
@@ -160,7 +160,7 @@ def get_direction_impl(direction_id: str) -> Dict[str, Any]:
 # =============================================================================
 
 
-@tools_mcp.tool
+@tools_mcp.tool()
 def create_direction(
     name: str,
     risk_level: str,
@@ -243,7 +243,7 @@ def create_direction(
         }
 
 
-@tools_mcp.tool
+@tools_mcp.tool()
 def list_directions(
     status: str = None,
 ) -> Dict[str, Any]:
@@ -283,7 +283,7 @@ def list_directions(
         }
 
 
-@tools_mcp.tool
+@tools_mcp.tool()
 def get_direction(
     direction_id: str,
 ) -> Dict[str, Any]:
diff --git a/v2/fuzzingbrain/tools/mcp_factory.py b/v2/fuzzingbrain/tools/mcp_factory.py
index 185501a..b89a4c7 100644
--- a/v2/fuzzingbrain/tools/mcp_factory.py
+++ b/v2/fuzzingbrain/tools/mcp_factory.py
@@ -125,7 +125,7 @@ def _register_analyzer_tools(mcp: FastMCP) -> None:
                 logger.warning(f"Connection error, invalidated client cache: {e}")
         return {"success": False, "error": str(e)}
 
-    @mcp.tool
+    @mcp.tool()
     @async_tool
     def analyzer_status() -> Dict[str, Any]:
         """Get Analysis Server status."""
@@ -139,7 +139,7 @@ def _register_analyzer_tools(mcp: FastMCP) -> None:
         except Exception as e:
             return _handle_client_error(e)
 
-    @mcp.tool
+    @mcp.tool()
     @async_tool
     def get_function(function_name: str) -> Dict[str, Any]:
         """
@@ -166,7 +166,7 @@ def _register_analyzer_tools(mcp: FastMCP) -> None:
         except Exception as e:
             return _handle_client_error(e)
 
-    @mcp.tool
+    @mcp.tool()
     @async_tool
     def get_functions_by_file(file_path: str) -> Dict[str, Any]:
         """
@@ -192,7 +192,7 @@ def _register_analyzer_tools(mcp: FastMCP) -> None:
         except Exception as e:
             return _handle_client_error(e)
 
-    @mcp.tool
+    @mcp.tool()
     @async_tool
     def search_functions(pattern: str, limit: int = 50) -> Dict[str, Any]:
         """
@@ -217,7 +217,7 @@ def _register_analyzer_tools(mcp: FastMCP) -> None:
         except Exception as e:
             return _handle_client_error(e)
 
-    @mcp.tool
+    @mcp.tool()
     @async_tool
     def get_function_source(function_name: str) -> Dict[str, Any]:
         """
@@ -247,7 +247,7 @@ def _register_analyzer_tools(mcp: FastMCP) -> None:
         except Exception as e:
             return _handle_client_error(e)
 
-    @mcp.tool
+    @mcp.tool()
     @async_tool
     def get_callers(function_name: str) -> Dict[str, Any]:
         """
@@ -279,7 +279,7 @@ def _register_analyzer_tools(mcp: FastMCP) -> None:
         except Exception as e:
             return _handle_client_error(e)
 
-    @mcp.tool
+    @mcp.tool()
     @async_tool
     def get_callees(function_name: str) -> Dict[str, Any]:
         """
@@ -311,7 +311,7 @@ def _register_analyzer_tools(mcp: FastMCP) -> None:
         except Exception as e:
             return _handle_client_error(e)
 
-    @mcp.tool
+    @mcp.tool()
     @async_tool
     def get_call_graph(fuzzer_name: str, depth: int = 3) -> Dict[str, Any]:
         """
@@ -342,7 +342,7 @@ def _register_analyzer_tools(mcp: FastMCP) -> None:
         except Exception as e:
             return _handle_client_error(e)
 
-    @mcp.tool
+    @mcp.tool()
     @async_tool
     def find_all_paths(
         from_function: str, to_function: str, max_depth: int = 10, max_paths: int = 20
@@ -374,7 +374,7 @@ def _register_analyzer_tools(mcp: FastMCP) -> None:
         except Exception as e:
             return _handle_client_error(e)
 
-    @mcp.tool
+    @mcp.tool()
     @async_tool
     def check_reachability(fuzzer_name: str, function_name: str) -> Dict[str, Any]:
         """
@@ -411,7 +411,7 @@ def _register_analyzer_tools(mcp: FastMCP) -> None:
     # they return multi-MB responses that blow up the LLM context.
     # The underlying AnalysisClient methods remain available for internal use.
 
-    @mcp.tool
+    @mcp.tool()
     @async_tool
     def get_fuzzers() -> Dict[str, Any]:
         """Get list of all built fuzzers."""
@@ -425,7 +425,7 @@ def _register_analyzer_tools(mcp: FastMCP) -> None:
         except Exception as e:
             return _handle_client_error(e)
 
-    @mcp.tool
+    @mcp.tool()
     @async_tool
     def get_fuzzer_source(fuzzer_name: str) -> Dict[str, Any]:
         """
@@ -454,7 +454,7 @@ def _register_analyzer_tools(mcp: FastMCP) -> None:
         except Exception as e:
             return _handle_client_error(e)
 
-    @mcp.tool
+    @mcp.tool()
     @async_tool
     def get_build_paths() -> Dict[str, Any]:
         """Get build output paths for each sanitizer."""
@@ -480,7 +480,7 @@ def _register_code_viewer_tools(mcp: FastMCP) -> None:
         list_files_impl,
     )
 
-    @mcp.tool
+    @mcp.tool()
     @async_tool
     def get_diff() -> Dict[str, Any]:
         """
@@ -489,7 +489,7 @@ def _register_code_viewer_tools(mcp: FastMCP) -> None:
         """
         return get_diff_impl()
 
-    @mcp.tool
+    @mcp.tool()
     @async_tool
     def get_file_content(
         file_path: str, start_line: int = None, end_line: int = None
@@ -504,7 +504,7 @@ def _register_code_viewer_tools(mcp: FastMCP) -> None:
         """
         return get_file_content_impl(file_path, start_line, end_line)
 
-    @mcp.tool
+    @mcp.tool()
     @async_tool
     def search_code(
         pattern: str = None,
@@ -530,7 +530,7 @@ def _register_code_viewer_tools(mcp: FastMCP) -> None:
             actual_pattern, file_pattern, max_results, context_lines
         )
 
-    @mcp.tool
+    @mcp.tool()
     @async_tool
     def list_files(
         directory: str = "", pattern: str = None, recursive: bool = False
@@ -549,7 +549,7 @@ def _register_code_viewer_tools(mcp: FastMCP) -> None:
 def _register_sp_create_tools(mcp: FastMCP) -> None:
     """Register SP creation tool (only for SP Finding agents)."""
 
-    @mcp.tool
+    @mcp.tool()
     @async_tool
     def create_suspicious_point(
         function_name: str,
@@ -578,7 +578,7 @@ def _register_sp_create_tools(mcp: FastMCP) -> None:
 def _register_sp_read_update_tools(mcp: FastMCP) -> None:
     """Register SP read/update tools (for all agents that need SP access)."""
 
-    @mcp.tool
+    @mcp.tool()
     @async_tool
     def update_suspicious_point(
         suspicious_point_id: str,
@@ -622,7 +622,7 @@ def _register_sp_read_update_tools(mcp: FastMCP) -> None:
             reachability_reason,
         )
 
-    @mcp.tool
+    @mcp.tool()
     @async_tool
     def list_suspicious_points() -> Dict[str, Any]:
         """List all suspicious points for the current task."""
@@ -630,7 +630,7 @@ def _register_sp_read_update_tools(mcp: FastMCP) -> None:
 
         return list_suspicious_points_impl()
 
-    @mcp.tool
+    @mcp.tool()
     @async_tool
     def get_suspicious_point(suspicious_point_id: str) -> Dict[str, Any]:
         """
@@ -654,7 +654,7 @@ def _register_suspicious_point_tools(mcp: FastMCP) -> None:
 def _register_direction_tools(mcp: FastMCP) -> None:
     """Register direction tools (Full-scan mode)."""
 
-    @mcp.tool
+    @mcp.tool()
     @async_tool
     def create_direction(
         name: str,
@@ -681,7 +681,7 @@ def _register_direction_tools(mcp: FastMCP) -> None:
             name, risk_level, risk_reason, core_functions, entry_functions, code_summary
         )
 
-    @mcp.tool
+    @mcp.tool()
     @async_tool
     def list_directions() -> Dict[str, Any]:
         """List all directions for the current task."""
@@ -689,7 +689,7 @@ def _register_direction_tools(mcp: FastMCP) -> None:
 
         return list_directions_impl()
 
-    @mcp.tool
+    @mcp.tool()
     @async_tool
     def get_direction(direction_id: str) -> Dict[str, Any]:
         """
@@ -714,7 +714,7 @@ def _register_pov_tools(mcp: FastMCP, worker_id: str = None) -> None:
     # Capture worker_id in closure - each tool will use this specific worker_id
     bound_worker_id = worker_id
 
-    @mcp.tool
+    @mcp.tool()
     @async_tool
     def get_fuzzer_info() -> Dict[str, Any]:
         """
@@ -725,7 +725,7 @@ def _register_pov_tools(mcp: FastMCP, worker_id: str = None) -> None:
 
         return get_fuzzer_info_impl(worker_id=bound_worker_id)
 
-    @mcp.tool
+    @mcp.tool()
     @async_tool
     def create_pov(generator_code: str) -> Dict[str, Any]:
         """
@@ -738,7 +738,7 @@ def _register_pov_tools(mcp: FastMCP, worker_id: str = None) -> None:
 
         return create_pov_impl(generator_code, worker_id=bound_worker_id)
 
-    @mcp.tool
+    @mcp.tool()
     @async_tool
     def verify_pov(pov_id: str) -> Dict[str, Any]:
         """
@@ -751,7 +751,7 @@ def _register_pov_tools(mcp: FastMCP, worker_id: str = None) -> None:
 
         return verify_pov_impl(pov_id, worker_id=bound_worker_id)
 
-    @mcp.tool
+    @mcp.tool()
     @async_tool
     def trace_pov(
         generator_code: str, target_functions: list = None, agent_msg: str = None
@@ -774,7 +774,7 @@ def _register_pov_tools(mcp: FastMCP, worker_id: str = None) -> None:
 def _register_coverage_tools(mcp: FastMCP) -> None:
     """Register coverage analysis tools."""
 
-    @mcp.tool
+    @mcp.tool()
     @async_tool
     def run_coverage(
         fuzzer_name: str,
@@ -797,7 +797,7 @@ def _register_coverage_tools(mcp: FastMCP) -> None:
             fuzzer_name, input_data_base64, target_functions, target_files
         )
 
-    @mcp.tool
+    @mcp.tool()
     @async_tool
     def check_pov_reaches_target(
         fuzzer_name: str,
@@ -818,7 +818,7 @@ def _register_coverage_tools(mcp: FastMCP) -> None:
             fuzzer_name, pov_data_base64, target_function
         )
 
-    @mcp.tool
+    @mcp.tool()
     @async_tool
     def list_available_fuzzers() -> Dict[str, Any]:
         """
@@ -828,7 +828,7 @@ def _register_coverage_tools(mcp: FastMCP) -> None:
 
         return list_fuzzers_impl()
 
-    @mcp.tool
+    @mcp.tool()
     @async_tool
     def get_coverage_feedback(
         fuzzer_name: str,
@@ -861,7 +861,7 @@ def _register_seed_tools(mcp: FastMCP, worker_id: str = None) -> None:
     # Capture worker_id in closure
     bound_worker_id = worker_id
 
-    @mcp.tool
+    @mcp.tool()
     @async_tool
     def create_seed(
         generator_code: str,
diff --git a/v2/fuzzingbrain/tools/pov.py b/v2/fuzzingbrain/tools/pov.py
index 365ce4a..0ed9dff 100644
--- a/v2/fuzzingbrain/tools/pov.py
+++ b/v2/fuzzingbrain/tools/pov.py
@@ -642,7 +642,7 @@ def trace_pov_impl(
 # =============================================================================
 
 
-@tools_mcp.tool
+@tools_mcp.tool()
 def get_fuzzer_info() -> Dict[str, Any]:
     """
     Get the fuzzer harness source code and current sanitizer type.
@@ -1023,7 +1023,7 @@ def _create_pov_core(
     }
 
 
-@tools_mcp.tool
+@tools_mcp.tool()
 def create_pov(
     generator_code: str,
     description: str = "POV generated by AI agent",
@@ -1606,7 +1606,7 @@ def _verify_pov_core(pov_id: str, worker_id: str = None) -> Dict[str, Any]:
         }
 
 
-@tools_mcp.tool
+@tools_mcp.tool()
 def verify_pov(
     pov_id: str,
 ) -> Dict[str, Any]:
@@ -1865,7 +1865,7 @@ def _analyze_trace(
         return f"Analysis unavailable: {e}"
 
 
-@tools_mcp.tool
+@tools_mcp.tool()
 def trace_pov(
     generator_code: str,
     target_functions: Optional[List[str]] = None,
diff --git a/v2/fuzzingbrain/tools/suspicious_points.py b/v2/fuzzingbrain/tools/suspicious_points.py
index 2c8ea5a..b093c22 100644
--- a/v2/fuzzingbrain/tools/suspicious_points.py
+++ b/v2/fuzzingbrain/tools/suspicious_points.py
@@ -277,7 +277,7 @@ def get_suspicious_point_impl(suspicious_point_id: str) -> Dict[str, Any]:
 # =============================================================================
 
 
-@tools_mcp.tool
+@tools_mcp.tool()
 def create_suspicious_point(
     function_name: str,
     description: str,
@@ -358,7 +358,7 @@ def create_suspicious_point(
         return {"success": False, "error": str(e)[:100]}
 
 
-@tools_mcp.tool
+@tools_mcp.tool()
 def update_suspicious_point(
     suspicious_point_id: str,
     is_checked: bool = None,
@@ -454,7 +454,7 @@ def update_suspicious_point(
         }
 
 
-@tools_mcp.tool
+@tools_mcp.tool()
 def list_suspicious_points(
     filter_unchecked: bool = False,
     filter_real: bool = False,
@@ -499,7 +499,7 @@ def list_suspicious_points(
         }
 
 
-@tools_mcp.tool
+@tools_mcp.tool()
 def get_suspicious_point(suspicious_point_id: str) -> Dict[str, Any]:
     """
     Get details of a specific suspicious point.
diff --git a/v2/fuzzingbrain/tools/utils.py b/v2/fuzzingbrain/tools/utils.py
index d47e10b..647b09e 100644
--- a/v2/fuzzingbrain/tools/utils.py
+++ b/v2/fuzzingbrain/tools/utils.py
@@ -31,7 +31,7 @@ def async_tool(func: F) -> F:
     causing all concurrent agents to wait in a queue.
 
     Usage:
-        @mcp.tool
+        @mcp.tool()
         @async_tool
         def get_function_source(function_name: str) -> Dict[str, Any]:
             # ContextVars are preserved in the thread!
diff --git a/v2/fuzzingbrain/worker/pipeline.py b/v2/fuzzingbrain/worker/pipeline.py
index 18337cc..4fd05b7 100644
--- a/v2/fuzzingbrain/worker/pipeline.py
+++ b/v2/fuzzingbrain/worker/pipeline.py
@@ -30,7 +30,7 @@ from ..core.models import SPStatus
 from ..db import RepositoryManager
 from ..tools.analyzer import set_analyzer_context
 from ..fuzzer import FuzzerManager, get_fuzzer_manager
-from ..llms import CLAUDE_SONNET_4_5
+from ..llms import KIMI_FOR_CODING
 
 
 @dataclass
@@ -301,7 +301,7 @@ class AgentPipeline:
                     fuzzer=self.fuzzer,
                     sanitizer=self.sanitizer,
                     scan_mode=self.scan_mode,  # Use pipeline's scan_mode
-                    model=CLAUDE_SONNET_4_5,  # Force Sonnet for SP analysis
+                    model=KIMI_FOR_CODING,  # Force Sonnet for SP analysis
                     task_id=self.task_id,
                     worker_id=self.worker_id,  # Use actual worker_id, not agent_id
                     log_dir=self.log_dir,
@@ -521,7 +521,7 @@ class AgentPipeline:
                 pov_agent = POVAgent(
                     fuzzer=self.fuzzer,
                     sanitizer=self.sanitizer,
-                    model=CLAUDE_SONNET_4_5,  # Force Sonnet for POV generation
+                    model=KIMI_FOR_CODING,  # Force Sonnet for POV generation
                     task_id=self.task_id,
                     worker_id=self.worker_id,  # Use actual worker_id, not agent_id
                     output_dir=self.output_dir,
diff --git a/v2/fuzzingbrain/worker/strategies/pov_base.py b/v2/fuzzingbrain/worker/strategies/pov_base.py
index a56f907..4829c58 100644
--- a/v2/fuzzingbrain/worker/strategies/pov_base.py
+++ b/v2/fuzzingbrain/worker/strategies/pov_base.py
@@ -16,7 +16,7 @@ from ...core.models import SuspiciousPoint
 from ...tools.code_viewer import set_code_viewer_context
 from ...tools.analyzer import set_analyzer_context
 from ...tools.suspicious_points import set_sp_context
-from ...llms import CLAUDE_SONNET_4_5
+from ...llms import KIMI_FOR_CODING
 
 
 class POVBaseStrategy(BaseStrategy):
@@ -305,7 +305,7 @@ class POVBaseStrategy(BaseStrategy):
             fuzzer=self.fuzzer,
             sanitizer=self.sanitizer,
             scan_mode=self.scan_mode,  # Use strategy's scan_mode for verify prompt
-            model=CLAUDE_SONNET_4_5,
+            model=KIMI_FOR_CODING,
             verbose=True,
             task_id=self.task_id,
             worker_id=self.worker_id,
diff --git a/v2/fuzzingbrain/worker/strategies/pov_delta.py b/v2/fuzzingbrain/worker/strategies/pov_delta.py
index 9d06ea2..8502520 100644
--- a/v2/fuzzingbrain/worker/strategies/pov_delta.py
+++ b/v2/fuzzingbrain/worker/strategies/pov_delta.py
@@ -25,7 +25,7 @@ from ...analysis.diff_parser import (
 )
 from ...core.models import SuspiciousPoint
 from ...agents import DeltaSPGenerator
-from ...llms import CLAUDE_SONNET_4_5
+from ...llms import KIMI_FOR_CODING
 
 
 class POVDeltaStrategy(POVBaseStrategy):
@@ -61,7 +61,7 @@ class POVDeltaStrategy(POVBaseStrategy):
         self._sp_generator = DeltaSPGenerator(
             fuzzer=self.fuzzer,
             sanitizer=self.sanitizer,
-            model=CLAUDE_SONNET_4_5,
+            model=KIMI_FOR_CODING,
             verbose=True,
             task_id=self.task_id,
             worker_id=self.worker_id,
diff --git a/v2/fuzzingbrain/worker/strategies/pov_fullscan.py b/v2/fuzzingbrain/worker/strategies/pov_fullscan.py
index 7f1ed07..42e08f3 100644
--- a/v2/fuzzingbrain/worker/strategies/pov_fullscan.py
+++ b/v2/fuzzingbrain/worker/strategies/pov_fullscan.py
@@ -24,7 +24,7 @@ from ...agents import (
     FullSPGenerator,
     LargeFullSPGenerator,
 )
-from ...llms.models import CLAUDE_OPUS_4_5, CLAUDE_SONNET_4_5
+from ...llms.models import KIMI_FOR_CODING
 from ...tools.directions import set_direction_context
 from ...tools.suspicious_points import set_sp_context
 from ...fuzzer import SeedAgent
@@ -143,7 +143,7 @@ class POVFullscanStrategy(POVBaseStrategy):
         planning_agent = DirectionPlanningAgent(
             fuzzer=self.fuzzer,
             sanitizer=self.sanitizer,
-            model=CLAUDE_OPUS_4_5,  # Force Opus for direction planning
+            model=KIMI_FOR_CODING,  # Force Opus for direction planning
             task_id=self.task_id,
             worker_id=self.worker_id,
             log_dir=agent_log_dir,
@@ -183,7 +183,7 @@ class POVFullscanStrategy(POVBaseStrategy):
         planning_agent = DirectionPlanningAgent(
             fuzzer=self.fuzzer,
             sanitizer=self.sanitizer,
-            model=CLAUDE_OPUS_4_5,  # Force Opus for direction planning
+            model=KIMI_FOR_CODING,  # Force Opus for direction planning
             task_id=self.task_id,
             worker_id=self.worker_id,
             log_dir=agent_log_dir,
@@ -678,7 +678,7 @@ class POVFullscanStrategy(POVBaseStrategy):
                 callees=callees,
                 fuzzer=self.fuzzer,
                 sanitizer=self.sanitizer,
-                model=CLAUDE_OPUS_4_5,  # Force Opus for large function analysis
+                model=KIMI_FOR_CODING,  # Force Opus for large function analysis
                 direction_id=direction_id,
                 task_id=self.task_id,
                 worker_id=self.worker_id,
@@ -695,7 +695,7 @@ class POVFullscanStrategy(POVBaseStrategy):
                 callees=callees,
                 fuzzer=self.fuzzer,
                 sanitizer=self.sanitizer,
-                model=CLAUDE_SONNET_4_5,  # Force Sonnet for function analysis
+                model=KIMI_FOR_CODING,  # Force Sonnet for function analysis
                 direction_id=direction_id,
                 task_id=self.task_id,
                 worker_id=self.worker_id,
@@ -802,7 +802,7 @@ class POVFullscanStrategy(POVBaseStrategy):
                     worker_id=self.worker_id,  # ObjectId for MongoDB linking
                     fuzzer=self.fuzzer,
                     sanitizer=self.sanitizer,
-                    model=CLAUDE_OPUS_4_5,  # Force Opus for seed generation
+                    model=KIMI_FOR_CODING,  # Force Opus for seed generation
                     fuzzer_manager=fuzzer_manager,
                     repos=self.repos,
                     fuzzer_source=fuzzer_code,
diff --git a/v2/fuzzingbrain/worker/strategies/pov_strategy.py b/v2/fuzzingbrain/worker/strategies/pov_strategy.py
index 0cee2fd..82fe1d0 100644
--- a/v2/fuzzingbrain/worker/strategies/pov_strategy.py
+++ b/v2/fuzzingbrain/worker/strategies/pov_strategy.py
@@ -35,7 +35,7 @@ from ...tools.code_viewer import set_code_viewer_context
 from ...tools.directions import set_direction_context
 from ...tools.analyzer import set_analyzer_context
 from ...tools.suspicious_points import set_sp_context
-from ...llms import CLAUDE_SONNET_4_5
+from ...llms import KIMI_FOR_CODING
 
 
 class POVStrategy(BaseStrategy):
@@ -74,7 +74,7 @@ class POVStrategy(BaseStrategy):
         self._sp_generator = DeltaSPGenerator(
             fuzzer=self.fuzzer,
             sanitizer=self.sanitizer,
-            model=CLAUDE_SONNET_4_5,
+            model=KIMI_FOR_CODING,
             verbose=True,
             task_id=self.task_id,
             worker_id=self.worker_id,
@@ -86,7 +86,7 @@ class POVStrategy(BaseStrategy):
             fuzzer=self.fuzzer,
             sanitizer=self.sanitizer,
             scan_mode="delta",
-            model=CLAUDE_SONNET_4_5,
+            model=KIMI_FOR_CODING,
             verbose=True,
             task_id=self.task_id,
             worker_id=self.worker_id,
