From 410e95e100342908239118db395e8ede4e374b74 Mon Sep 17 00:00:00 2001 From: Teknium <127238744+teknium1@users.noreply.github.com> Date: Wed, 2 Sep 2026 16:01:37 -0700 Subject: [PATCH] refactor(mcp): restore E305 spacing after squeeze --- tools/mcp_tool_common.py | 5 +++++ tools/mcp_tool_config.py | 3 +++ tools/mcp_tool_lifecycle.py | 1 + tools/mcp_tool_schema.py | 4 ++++ 4 files changed, 13 insertions(+) diff --git a/tools/mcp_tool_common.py b/tools/mcp_tool_common.py index bdd91de8aa..0e96d04200 100644 --- a/tools/mcp_tool_common.py +++ b/tools/mcp_tool_common.py @@ -26,6 +26,7 @@ class _OriginProxy: return getattr(mcp_tool, name) + _core = _OriginProxy() _MISSING = object() @@ -41,6 +42,7 @@ def mcp_field(obj, snake: str, camel: str, default=None): value = getattr(obj, camel, _MISSING) return default if value is _MISSING else value + _DEFAULT_TOOL_TIMEOUT = 300 # seconds for tool calls @@ -61,6 +63,7 @@ def _resolve_tool_timeout(config: dict) -> float: logger.debug("mcp.tool_call timeout resolution failed", exc_info=True) return _DEFAULT_TOOL_TIMEOUT + # Jitter on reconnect backoff so servers that lost the same backend don't # retry in lockstep (thundering herd, synchronized log bursts). _BACKOFF_JITTER = 0.2 # +/-20% @@ -70,6 +73,7 @@ def _jittered(seconds: float) -> float: """``seconds`` with +/-20% uniform jitter, floored at 0.""" return max(0.0, seconds * random.uniform(1.0 - _BACKOFF_JITTER, 1.0 + _BACKOFF_JITTER)) + # Credential patterns to strip from error messages. _CREDENTIAL_PATTERN = re.compile( r"(?:" @@ -131,6 +135,7 @@ def _safe_numeric(value, default, coerce=int, minimum=1): except (TypeError, ValueError, OverflowError): return default + _TRUE_WORDS = frozenset({"true", "1", "yes", "on"}) _FALSE_WORDS = frozenset({"false", "0", "no", "off"}) diff --git a/tools/mcp_tool_config.py b/tools/mcp_tool_config.py index 940fdc0e9e..feede5259d 100644 --- a/tools/mcp_tool_config.py +++ b/tools/mcp_tool_config.py @@ -55,6 +55,7 @@ def _write_stderr_log_header(server_name: str) -> None: except Exception: pass + # Env vars safe to pass to stdio subprocesses (no secrets). _SAFE_ENV_KEYS = frozenset({"PATH", "HOME", "USER", "LANG", "LC_ALL", "TERM", "SHELL", "TMPDIR"}) @@ -91,6 +92,7 @@ def _workspace_basename() -> str: root = _core._workspace_folder() return os.path.basename(root.rstrip("/\\")) or root + # Cursor's case-sensitive context vars -> resolver. _CONTEXT_VAR_RESOLVERS = { "userHome": lambda: os.path.expanduser("~"), @@ -225,6 +227,7 @@ def _interpolate_env_vars(value): return [_interpolate_env_vars(v) for v in value] return value + # (server_name, dotted key path) pairs already warned about; config loads # happen on every discovery pass, so warn once per process. _whitespace_warned: Set[Tuple[str, str]] = set() diff --git a/tools/mcp_tool_lifecycle.py b/tools/mcp_tool_lifecycle.py index 45890dad4f..3b3f730780 100644 --- a/tools/mcp_tool_lifecycle.py +++ b/tools/mcp_tool_lifecycle.py @@ -57,6 +57,7 @@ def _snapshot_child_pids() -> set: return set() + # argv markers of non-MCP gateway children that can race into the snapshot # delta during an MCP spawn (defense-in-depth; LSP/slash_worker already use # start_new_session). Matched against argv[1:] because Python/Java children diff --git a/tools/mcp_tool_schema.py b/tools/mcp_tool_schema.py index 01e620d3ba..c654861636 100644 --- a/tools/mcp_tool_schema.py +++ b/tools/mcp_tool_schema.py @@ -43,6 +43,7 @@ def _scan_mcp_description(server_name: str, tool_name: str, description: str) -> ) return findings + _EMPTY_OBJECT_SCHEMA = {"type": "object", "properties": {}} @@ -123,6 +124,7 @@ def sanitize_mcp_name_component(value: str) -> str: the historical behavior) so generated names pass provider validation.""" return re.sub(r"[^A-Za-z0-9_]", "_", str(value or "")) + # ``mcp____``: the convention shared by Claude Code, Codex and # OpenCode. The double underscore disambiguates the server/tool boundary even # when either contains underscores, and matches the Anthropic-OAuth wire form. @@ -145,6 +147,7 @@ def _convert_mcp_schema(server_name: str, mcp_tool) -> dict: "parameters": _normalize_mcp_input_schema(mcp_field(mcp_tool, "input_schema", "inputSchema")), } + # Utility tools generated per server: handler_key -> (description template, # parameter properties, required names). Schemas are FROZEN wire bytes — the # key order emitted by ``_build_utility_schemas`` must not change. @@ -206,6 +209,7 @@ def matches_name_filter(tool_name: str, patterns: set[str]) -> bool: return True return any(fnmatch.fnmatchcase(tool_name, p) for p in patterns if "*" in p or "?" in p or "[" in p) + # Utility handler -> ClientSession method it needs (legacy gate when no # initialize_result was captured). _UTILITY_CAPABILITY_METHODS = {key: key for key, *_ in _UTILITY_TOOL_SPECS}