message / plugins /sandbox /mcp.py
hunian
refactor(plugins): 插件短名并统一 MCP tool 为 {plugin}-{tool}
cc826a1
Raw
History Blame Contribute Delete
6.29 kB
"""
沙盒MCP插件 MCP工具定义
"""
from app.mcp.decorators import mcp_tool
from pydantic import BaseModel, Field
from typing import List
from .main import plugin
from .sandbox.security import SecurityController
from .sandbox.file_ops import FileOperations
from .sandbox.command_exec import CommandExecutor
class ReadFileInput(BaseModel):
"""文件读取工具输入参数"""
path: str = Field(description="文件相对路径(相对于沙盒根目录)")
encoding: str = Field(default="utf-8", description="文件编码")
class ReadFileOutput(BaseModel):
"""文件读取工具输出结果"""
success: bool = Field(description="操作是否成功")
content: str | None = Field(default=None, description="文件内容")
size: int | None = Field(default=None, description="文件大小(字节)")
error: str | None = Field(default=None, description="错误信息")
class WriteFileInput(BaseModel):
"""文件写入工具输入参数"""
path: str = Field(description="文件相对路径(相对于沙盒根目录)")
content: str = Field(description="文件内容")
mode: str = Field(default="write", description="写入模式:write 或 append")
class WriteFileOutput(BaseModel):
"""文件写入工具输出结果"""
success: bool = Field(description="操作是否成功")
path: str | None = Field(default=None, description="写入的文件路径")
size: int | None = Field(default=None, description="文件大小(字节)")
error: str | None = Field(default=None, description="错误信息")
class ListFilesInput(BaseModel):
"""文件列表工具输入参数"""
path: str = Field(default="", description="目录相对路径(空表示沙盒根目录)")
pattern: str = Field(default="*", description="匹配模式(glob pattern)")
class ListFilesOutput(BaseModel):
"""文件列表工具输出结果"""
success: bool = Field(description="操作是否成功")
files: List[dict] | None = Field(default=None, description="文件列表")
error: str | None = Field(default=None, description="错误信息")
class ExecuteInput(BaseModel):
"""命令执行工具输入参数"""
command: str = Field(description="要执行的命令")
timeout: int = Field(default=30, description="超时时间(秒)")
cwd: str = Field(default="", description="工作目录(相对路径)")
class ExecuteOutput(BaseModel):
"""命令执行工具输出结果"""
success: bool = Field(description="操作是否成功")
stdout: str = Field(default="", description="标准输出")
stderr: str = Field(default="", description="标准错误")
exit_code: int = Field(default=-1, description="退出码")
error: str | None = Field(default=None, description="错误信息")
@mcp_tool(
name="sandbox-read",
title="沙盒文件读取",
description="从沙盒目录读取文件内容",
annotations={
"readOnlyHint": True,
"destructiveHint": False,
}
)
async def sandbox_read(path: str, encoding: str = "utf-8") -> ReadFileOutput:
"""从沙盒目录读取文件内容。
Args:
params: 包含文件路径和编码参数
Returns:
ReadFileOutput: 文件内容和相关信息
"""
security = SecurityController()
file_ops = FileOperations(security)
result = file_ops.read_file(path, encoding)
return ReadFileOutput(
success=result.get("success", False),
content=result.get("content"),
size=result.get("size"),
error=result.get("error"),
)
@mcp_tool(
name="sandbox-write",
title="沙盒文件写入",
description="向沙盒目录写入文件内容",
annotations={
"readOnlyHint": False,
"destructiveHint": False,
}
)
async def sandbox_write(
content: str,
path: str | None = None,
filename: str | None = None,
mode: str = "write",
) -> WriteFileOutput:
"""向沙盒目录写入文件内容。
Args:
params: 包含文件路径、内容和写入模式参数
Returns:
WriteFileOutput: 写入结果
"""
security = SecurityController()
file_ops = FileOperations(security)
target_path = path or filename
if not target_path:
return WriteFileOutput(
success=False,
error="缺少文件路径,请传入 path 或 filename",
)
result = file_ops.write_file(target_path, content, mode)
return WriteFileOutput(
success=result.get("success", False),
path=result.get("path"),
size=result.get("size"),
error=result.get("error"),
)
@mcp_tool(
name="sandbox-list",
title="沙盒文件列表",
description="列出沙盒目录中的文件和目录",
annotations={
"readOnlyHint": True,
"destructiveHint": False,
}
)
async def sandbox_list(path: str = "", pattern: str = "*") -> ListFilesOutput:
"""列出沙盒目录中的文件和目录。
Args:
params: 包含目录路径和匹配模式参数
Returns:
ListFilesOutput: 文件列表
"""
security = SecurityController()
file_ops = FileOperations(security)
result = file_ops.list_files(path, pattern)
return ListFilesOutput(
success=result.get("success", False),
files=result.get("files"),
error=result.get("error"),
)
@mcp_tool(
name="sandbox-exec",
title="沙盒命令执行",
description="在沙盒环境中安全执行命令",
annotations={
"readOnlyHint": False,
"destructiveHint": True,
}
)
async def sandbox_exec(command: str, timeout: int = 30, cwd: str = "") -> ExecuteOutput:
"""在沙盒环境中安全执行命令。
Args:
params: 包含命令、超时时间和工作目录参数
Returns:
ExecuteOutput: 命令执行结果
"""
security = SecurityController()
cmd_exec = CommandExecutor(security)
result = await cmd_exec.execute(command, timeout, cwd)
return ExecuteOutput(
success=result.get("success", False),
stdout=result.get("stdout", ""),
stderr=result.get("stderr", ""),
exit_code=result.get("exit_code", -1),
error=result.get("error"),
)