Skip to content

Commit bf3233a

Browse files
committed
refactor: replace CommandExecutor with BashSessionExecutor for persistent shell execution
BREAKING CHANGE: Removed CommandExecutor in favor of BashSessionExecutor. All shell tools now use persistent sessions by default. The run_command tool interface has been updated to support session-based execution with new parameters (is_input, blocking). CommandResult now includes additional metadata about the execution context.
1 parent 32769b5 commit bf3233a

24 files changed

+3320
-1539
lines changed

mcp_claude_code/server.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
from mcp_claude_code.tools import register_all_tools
99
from mcp_claude_code.tools.common.context import DocumentContext
1010
from mcp_claude_code.tools.common.permissions import PermissionManager
11-
from mcp_claude_code.tools.shell.command_executor import CommandExecutor
1211

1312

1413
@final

mcp_claude_code/tools/__init__.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
from mcp_claude_code.tools.filesystem import register_filesystem_tools
2020
from mcp_claude_code.tools.jupyter import register_jupyter_tools
2121
from mcp_claude_code.tools.shell import register_shell_tools
22-
from mcp_claude_code.tools.shell.command_executor import CommandExecutor
2322
from mcp_claude_code.tools.todo import register_todo_tools
2423

2524

@@ -77,7 +76,6 @@ def register_all_tools(
7776
mcp_server,
7877
document_context,
7978
permission_manager,
80-
CommandExecutor(permission_manager),
8179
agent_model=agent_model,
8280
agent_max_tokens=agent_max_tokens,
8381
agent_api_key=agent_api_key,

mcp_claude_code/tools/agent/__init__.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,12 @@
1010
from mcp_claude_code.tools.common.base import BaseTool, ToolRegistry
1111
from mcp_claude_code.tools.common.context import DocumentContext
1212
from mcp_claude_code.tools.common.permissions import PermissionManager
13-
from mcp_claude_code.tools.shell.command_executor import CommandExecutor
1413

1514

1615
def register_agent_tools(
1716
mcp_server: FastMCP,
1817
document_context: DocumentContext,
1918
permission_manager: PermissionManager,
20-
command_executor: CommandExecutor,
2119
agent_model: str | None = None,
2220
agent_max_tokens: int | None = None,
2321
agent_api_key: str | None = None,
@@ -31,7 +29,6 @@ def register_agent_tools(
3129
mcp_server: The FastMCP server instance
3230
document_context: Document context for tracking file contents
3331
permission_manager: Permission manager for access control
34-
command_executor: Command executor for running shell commands
3532
agent_model: Optional model name for agent tool in LiteLLM format
3633
agent_max_tokens: Optional maximum tokens for agent responses
3734
agent_api_key: Optional API key for the LLM provider
@@ -46,7 +43,6 @@ def register_agent_tools(
4643
agent_tool = AgentTool(
4744
document_context=document_context,
4845
permission_manager=permission_manager,
49-
command_executor=command_executor,
5046
model=agent_model,
5147
api_key=agent_api_key,
5248
base_url=agent_base_url,

mcp_claude_code/tools/agent/agent_tool.py

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@
3636
from mcp_claude_code.tools.common.permissions import PermissionManager
3737
from mcp_claude_code.tools.filesystem import get_read_only_filesystem_tools
3838
from mcp_claude_code.tools.jupyter import get_read_only_jupyter_tools
39-
from mcp_claude_code.tools.shell.command_executor import CommandExecutor
4039

4140
Prompt = Annotated[
4241
str,
@@ -107,7 +106,6 @@ def __init__(
107106
self,
108107
document_context: DocumentContext,
109108
permission_manager: PermissionManager,
110-
command_executor: CommandExecutor,
111109
model: str | None = None,
112110
api_key: str | None = None,
113111
base_url: str | None = None,
@@ -120,7 +118,6 @@ def __init__(
120118
Args:
121119
document_context: Document context for tracking file contents
122120
permission_manager: Permission manager for access control
123-
command_executor: Command executor for running shell commands
124121
model: Optional model name override in LiteLLM format (e.g., "openai/gpt-4o")
125122
api_key: Optional API key for the model provider
126123
base_url: Optional base URL for the model provider API endpoint
@@ -130,7 +127,6 @@ def __init__(
130127
"""
131128
self.document_context = document_context
132129
self.permission_manager = permission_manager
133-
self.command_executor = command_executor
134130
self.model_override = model
135131
self.api_key_override = api_key
136132
self.base_url_override = base_url
@@ -390,17 +386,10 @@ async def _execute_agent_with_tools(
390386

391387
# If we've reached the limit, add a warning and get final response
392388
if total_tool_use_count >= max_tool_uses or iteration_count >= max_iterations:
393-
limit_ = (
394-
"tool usage" if total_tool_use_count >= max_tool_uses else "iterations"
395-
)
396-
await tool_ctx.info(
397-
f"Reached maximum {limit_type} limit. Getting final response."
398-
)
399-
400389
messages.append(
401390
{
402391
"role": "system",
403-
"content": f"You have reached the maximum number of {limit_type}. Please provide your final response.",
392+
"content": "You have reached the maximum iteration. Please provide your final response.",
404393
}
405394
)
406395

@@ -416,7 +405,7 @@ async def _execute_agent_with_tools(
416405

417406
return (
418407
final_response.choices[0].message.content
419-
or f"Agent reached {limit_type} limit without a response."
408+
or "Agent reached max iteration limit without a response."
420409
) # pyright: ignore
421410
except Exception as e:
422411
await tool_ctx.error(f"Error in final model call: {str(e)}")

mcp_claude_code/tools/filesystem/grep.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414

1515
from fastmcp import Context as MCPContext
1616
from fastmcp import FastMCP
17-
from fastmcp.server.dependencies import get_context
1817
from pydantic import Field
1918

2019
from mcp_claude_code.tools.common.context import ToolContext
@@ -37,10 +36,10 @@
3736
]
3837

3938
Include = Annotated[
40-
str | None,
39+
str,
4140
Field(
4241
description='File pattern to include in the search (e.g. "*.js", "*.{ts,tsx}")',
43-
default=None,
42+
default="*",
4443
),
4544
]
4645

@@ -387,7 +386,7 @@ async def call(
387386
pattern = params.get("pattern")
388387
path: str = params.get("path", ".")
389388
# Support both 'include' and legacy 'file_pattern' parameter for backward compatibility
390-
include: str = params.get("include") or params.get("file_pattern", "*")
389+
include: str = params.get("include")
391390

392391
# Validate required parameters for direct calls (not through MCP framework)
393392
if pattern is None:

mcp_claude_code/tools/jupyter/notebook_edit.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,10 @@
3838
]
3939

4040
CellType = Annotated[
41-
Literal["code", "markdown"] | None,
41+
Literal["code", "markdown"],
4242
Field(
4343
description="The of the cell (code or markdown). If not specified, it defaults to the current cell type. If using edit_mode=insert, this is required.",
44-
default=None,
44+
default="code",
4545
),
4646
]
4747

mcp_claude_code/tools/shell/__init__.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@
77

88
from mcp_claude_code.tools.common.base import BaseTool, ToolRegistry
99
from mcp_claude_code.tools.common.permissions import PermissionManager
10-
from mcp_claude_code.tools.shell.command_executor import CommandExecutor
10+
from mcp_claude_code.tools.shell.bash_session_executor import BashSessionExecutor
1111
from mcp_claude_code.tools.shell.run_command import RunCommandTool
1212

1313
# Export all tool classes
1414
__all__ = [
1515
"RunCommandTool",
16-
"CommandExecutor",
16+
"BashSessionExecutor",
1717
"get_shell_tools",
1818
"register_shell_tools",
1919
]
@@ -31,7 +31,7 @@ def get_shell_tools(
3131
List of shell tool instances
3232
"""
3333
# Initialize the command executor
34-
command_executor = CommandExecutor(permission_manager)
34+
command_executor = BashSessionExecutor(permission_manager)
3535

3636
return [
3737
RunCommandTool(permission_manager, command_executor),

0 commit comments

Comments
 (0)