feat: Add Custom CLI Arguments Field for MCP Server Configuration (#13265)

This commit is contained in:
CityFun
2026-07-15 15:53:44 +08:00
committed by GitHub
parent 9fd1f3e661
commit 2874849557
34 changed files with 617 additions and 34 deletions

View File

@@ -23,6 +23,7 @@ type McpServerCreate struct {
Type string `json:"type" validate:"required"`
GatewayImage string `json:"gatewayImage"`
ProtocolVersion string `json:"protocolVersion"`
GatewayArgs string `json:"gatewayArgs" validate:"max=4096"`
TaskID string `json:"taskID"`
}

View File

@@ -20,4 +20,5 @@ type McpServer struct {
Type string `json:"type"`
GatewayImage string `json:"gatewayImage"`
ProtocolVersion string `json:"protocolVersion"`
GatewayArgs string `json:"gatewayArgs"`
}

View File

@@ -644,7 +644,7 @@ func (u *CronjobService) HandleStop(id uint) error {
if len(record.TaskID) == 0 {
return nil
}
if cancel, ok := global.TaskCtxMap[record.TaskID]; ok {
if cancel, ok := global.LoadTaskCancel(record.TaskID); ok {
cancel()
}
return nil

View File

@@ -485,7 +485,7 @@ func preflightDecompressTool(decompressType files.CompressType) error {
}
func (f *FileService) StopCompress(taskID string) error {
if cancel, ok := global.TaskCtxMap[taskID]; ok {
if cancel, ok := global.LoadTaskCancel(taskID); ok {
cancel()
return nil
}
@@ -493,7 +493,7 @@ func (f *FileService) StopCompress(taskID string) error {
}
func (f *FileService) StopDeCompress(taskID string) error {
if cancel, ok := global.TaskCtxMap[taskID]; ok {
if cancel, ok := global.LoadTaskCancel(taskID); ok {
cancel()
return nil
}

View File

@@ -32,6 +32,7 @@ import (
"github.com/1Panel-dev/1Panel/agent/utils/nginx/components"
"github.com/1Panel-dev/1Panel/agent/utils/nginx/parser"
"github.com/docker/docker/api/types/container"
"github.com/mattn/go-shellwords"
"github.com/subosito/gotenv"
"gopkg.in/yaml.v3"
)
@@ -127,6 +128,7 @@ func (m McpServerService) Update(req request.McpServerUpdate) error {
mcpServer.Type = req.Type
mcpServer.GatewayImage = req.GatewayImage
mcpServer.ProtocolVersion = req.ProtocolVersion
mcpServer.GatewayArgs = req.GatewayArgs
normalizeMcpServerGateway(mcpServer)
if req.OutputTransport == mcpOutputTransportSSE {
mcpServer.SsePath = req.SsePath
@@ -191,6 +193,7 @@ func (m McpServerService) Create(create request.McpServerCreate) error {
Type: create.Type,
GatewayImage: create.GatewayImage,
ProtocolVersion: create.ProtocolVersion,
GatewayArgs: create.GatewayArgs,
}
normalizeMcpServerGateway(mcpServer)
if create.OutputTransport == mcpOutputTransportSSE {
@@ -738,7 +741,52 @@ func normalizeMcpServerGateway(mcpServer *model.McpServer) {
}
}
func buildSupergatewayCommand(mcpServer *model.McpServer) []string {
var managedMcpGatewayArgs = map[string]struct{}{
"--": {},
"stdio": {},
"sse": {},
"streamablehttp": {},
"outputtransport": {},
"port": {},
"baseurl": {},
"ssepath": {},
"messagepath": {},
"streamablehttppath": {},
"protocolversion": {},
}
func normalizeMcpGatewayArgName(name string) string {
if name == "--" || !strings.HasPrefix(name, "--") {
return name
}
name = strings.TrimPrefix(name, "--")
name = strings.TrimPrefix(name, "no-")
name = strings.SplitN(name, ".", 2)[0]
return strings.ToLower(strings.ReplaceAll(name, "-", ""))
}
func parseMcpGatewayArgs(raw string) ([]string, error) {
if strings.TrimSpace(raw) == "" {
return nil, nil
}
parser := shellwords.NewParser()
args, err := parser.Parse(raw)
if err != nil {
return nil, buserr.New("ErrMcpGatewayArgsParse")
}
if parser.Position >= 0 {
return nil, buserr.New("ErrMcpGatewayArgsParse")
}
for _, arg := range args {
name := strings.SplitN(arg, "=", 2)[0]
if _, ok := managedMcpGatewayArgs[normalizeMcpGatewayArgName(name)]; ok {
return nil, buserr.WithName("ErrMcpGatewayArgsConflict", name)
}
}
return args, nil
}
func buildSupergatewayCommand(mcpServer *model.McpServer) ([]string, error) {
normalizeMcpServerGateway(mcpServer)
command := []string{
"--stdio", mcpServer.Command,
@@ -746,14 +794,22 @@ func buildSupergatewayCommand(mcpServer *model.McpServer) []string {
"--port", strconv.Itoa(mcpServer.Port),
}
if mcpServer.OutputTransport == mcpOutputTransportSSE {
return append(command,
command = append(command,
"--baseUrl", mcpServer.BaseURL,
"--ssePath", mcpServer.SsePath,
"--messagePath", fmt.Sprintf("%s/messages", mcpServer.SsePath),
)
} else {
command = append(command,
"--streamableHttpPath", mcpServer.StreamableHttpPath,
"--protocolVersion", mcpServer.ProtocolVersion,
)
}
command = append(command, "--streamableHttpPath", mcpServer.StreamableHttpPath)
return append(command, "--protocolVersion", mcpServer.ProtocolVersion)
gatewayArgs, err := parseMcpGatewayArgs(mcpServer.GatewayArgs)
if err != nil {
return nil, err
}
return append(command, gatewayArgs...), nil
}
func buildMcpEndpoint(mcpServer *model.McpServer) string {
@@ -852,7 +908,11 @@ func handleCreateParams(mcpServer *model.McpServer, environments []request.Envir
delete(services, serviceName)
}
normalizeMcpServerGateway(mcpServer)
serviceValue["command"] = buildSupergatewayCommand(mcpServer)
command, err := buildSupergatewayCommand(mcpServer)
if err != nil {
return err
}
serviceValue["command"] = command
serviceValue["image"] = mcpServer.GatewayImage
serviceValue["ports"] = []string{
formatComposePortMapping("HOST_IP", "PANEL_APP_PORT_HTTP", "PANEL_APP_PORT_HTTP", ""),

View File

@@ -169,8 +169,8 @@ func NewTask(name, operate, taskScope, taskID string, resourceID uint) (*Task, e
}
taskRepo := repo.NewITaskRepo()
ctx, cancel := context.WithCancel(context.Background())
global.TaskCtxMap[taskID] = cancel
task := &Task{TaskCtx: ctx, Name: name, logFile: logFile, Logger: logger, taskRepo: taskRepo, Task: taskModel}
global.RegisterTaskCancel(taskID, cancel)
task := &Task{TaskCtx: ctx, TaskID: taskID, Name: name, logFile: logFile, Logger: logger, taskRepo: taskRepo, Task: taskModel}
return task, nil
}
@@ -200,7 +200,7 @@ func ReNewTask(name, operate, taskScope, taskID string, resourceID uint) (*Task,
logger.SetOutput(logFile)
logger.Print("\n --------------------------------------------------- \n")
taskItem.Status = constant.StatusExecuting
task := &Task{Name: name, logFile: logFile, Logger: logger, taskRepo: taskRepo, Task: &taskItem}
task := &Task{TaskID: taskID, Name: name, logFile: logFile, Logger: logger, taskRepo: taskRepo, Task: &taskItem}
task.updateTask(&taskItem)
return task, nil
}
@@ -231,7 +231,7 @@ func (t *Task) AddSubTaskWithIgnoreErr(name string, action ActionFunc) {
}
func (s *SubTask) Execute() error {
defer delete(global.TaskCtxMap, s.RootTask.TaskID)
defer global.RemoveTaskCancel(s.RootTask.TaskID)
subTaskName := s.Name
if s.Name == "" {
subTaskName = i18n.GetMsgByKey("SubTask")
@@ -302,7 +302,11 @@ func (t *Task) Execute() error {
continue
}
t.Task.ErrorMsg = err.Error()
t.Task.Status = constant.StatusFailed
if errors.Is(err, context.Canceled) {
t.Task.Status = constant.StatusCanceled
} else {
t.Task.Status = constant.StatusFailed
}
for _, rollback := range t.Rollbacks {
rollback(t)
}

View File

@@ -2,6 +2,7 @@ package global
import (
"context"
"sync"
badger_db "github.com/1Panel-dev/1Panel/agent/init/cache/db"
"github.com/go-playground/validator/v10"
@@ -39,8 +40,28 @@ var (
AlertResourceJobID cron.EntryID
TaskCtxMap = make(map[string]context.CancelFunc)
taskCtxMu sync.RWMutex
)
func RegisterTaskCancel(taskID string, cancel context.CancelFunc) {
taskCtxMu.Lock()
defer taskCtxMu.Unlock()
TaskCtxMap[taskID] = cancel
}
func LoadTaskCancel(taskID string) (context.CancelFunc, bool) {
taskCtxMu.RLock()
defer taskCtxMu.RUnlock()
cancel, ok := TaskCtxMap[taskID]
return cancel, ok
}
func RemoveTaskCancel(taskID string) {
taskCtxMu.Lock()
defer taskCtxMu.Unlock()
delete(TaskCtxMap, taskID)
}
func RepoURL() string {
if CONF.Base.IsEnterprise {
return "https://resource.fit2cloud.com/1panel/package/enterprise"

View File

@@ -27,6 +27,7 @@ require (
github.com/jinzhu/copier v0.4.0
github.com/joho/godotenv v1.5.1
github.com/klauspost/compress v1.19.0
github.com/mattn/go-shellwords v1.0.13
github.com/mholt/archiver/v4 v4.0.0-alpha.8
github.com/miekg/dns v1.1.72
github.com/minio/minio-go/v7 v7.2.1
@@ -150,7 +151,6 @@ require (
github.com/leodido/go-urn v1.4.0 // indirect
github.com/lufia/plan9stats v0.0.0-20260330125221-c963978e514e // indirect
github.com/mattn/go-isatty v0.0.22 // indirect
github.com/mattn/go-shellwords v1.0.13 // indirect
github.com/minio/crc64nvme v1.1.1 // indirect
github.com/minio/md5-simd v1.1.2 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect

View File

@@ -1,10 +1,17 @@
# base errors
ErrInvalidParams: 'Bad request: {{ .detail }}'
ErrMcpGatewayArgsParse: 'Invalid MCP custom argument format'
ErrMcpGatewayArgsConflict: 'Argument {{ .name }} is managed by 1Panel and cannot be set in custom arguments'
ErrTokenParse: 'Token error: {{ .detail }}'
ErrInitialPassword: 'Original password is incorrect'
ErrInternalServer: 'Internal server error: {{ .detail }}'
ErrRecordExist: 'Record already exists'
ErrRecordNotFound: 'Record not found'
WafLogExport: 'WAF log export'
MonitorLogExport: 'Website monitoring log export'
LogExportNoData: 'No logs match the selected filters'
LogExportDiskSpace: 'Less than 1 GiB of disk space is available; the export was stopped'
LogExportRetentionInvalid: 'Export record retention must be between 1 and 30 days'
ErrStructTransform: 'Type conversion failed: {{ .err }}'
ErrNotSupportType: 'Unsupported type: {{ .name }}'

View File

@@ -1,10 +1,17 @@
# errores básicos
ErrInvalidParams: 'Solicitud inválida: {{ .detail }}'
ErrMcpGatewayArgsParse: 'Formato de argumentos personalizados de MCP no válido'
ErrMcpGatewayArgsConflict: 'El argumento {{ .name }} está gestionado por 1Panel y no puede definirse en los argumentos personalizados'
ErrTokenParse: 'Token inválido: {{ .detail }}'
ErrInitialPassword: 'Contraseña original incorrecta'
ErrInternalServer: 'Error interno: {{ .detail }}'
ErrRecordExist: 'Registro ya existe'
ErrRecordNotFound: 'Registro no encontrado'
WafLogExport: 'Exportación de registros WAF'
MonitorLogExport: 'Exportación de registros de monitorización web'
LogExportNoData: 'Ningún registro coincide con los filtros seleccionados'
LogExportDiskSpace: 'Hay menos de 1 GiB disponible; la exportación se detuvo'
LogExportRetentionInvalid: 'La retención del historial de exportación debe ser de 1 a 30 días'
ErrStructTransform: 'Error de conversión: {{ .err }}'
ErrNotSupportType: 'Tipo no soportado: {{ .name }}'

View File

@@ -1,10 +1,17 @@
# خطاهای پایه
ErrInvalidParams: 'درخواست نامعتبر: {{ .detail }}'
ErrMcpGatewayArgsParse: 'قالب آرگومان‌های سفارشی MCP نامعتبر است'
ErrMcpGatewayArgsConflict: 'آرگومان {{ .name }} توسط 1Panel مدیریت می‌شود و نمی‌توان آن را در آرگومان‌های سفارشی تنظیم کرد'
ErrTokenParse: 'خطا در توکن: {{ .detail }}'
ErrInitialPassword: 'رمز عبور اصلی اشتباه است'
ErrInternalServer: 'خطای داخلی سرور: {{ .detail }}'
ErrRecordExist: 'رکورد از قبل وجود دارد'
ErrRecordNotFound: 'رکورد یافت نشد'
WafLogExport: 'خروجی لاگ WAF'
MonitorLogExport: 'خروجی لاگ پایش وب‌سایت'
LogExportNoData: 'هیچ لاگی با فیلترهای انتخاب‌شده مطابقت ندارد'
LogExportDiskSpace: 'فضای آزاد کمتر از ۱ گیگابایت است؛ خروجی متوقف شد'
LogExportRetentionInvalid: 'مدت نگهداری سوابق خروجی باید بین ۱ تا ۳۰ روز باشد'
ErrStructTransform: 'تبدیل نوع ناموفق بود: {{ .err }}'
ErrNotSupportType: 'نوع پشتیبانی نمی‌شود: {{ .name }}'

View File

@@ -1,10 +1,17 @@
# 基本エラー
ErrInvalidParams: '不正なリクエスト: {{ .detail }}'
ErrMcpGatewayArgsParse: 'MCP カスタム引数の形式が正しくありません'
ErrMcpGatewayArgsConflict: '引数 {{ .name }} は 1Panel によって管理されているため、カスタム引数には設定できません'
ErrTokenParse: 'トークンエラー: {{ .detail }}'
ErrInitialPassword: '元のパスワードが違います'
ErrInternalServer: '内部エラー: {{ .detail }}'
ErrRecordExist: 'レコードが既に存在します'
ErrRecordNotFound: 'レコードが見つかりません'
WafLogExport: 'WAF ログのエクスポート'
MonitorLogExport: 'Web サイト監視ログのエクスポート'
LogExportNoData: '条件に一致するログがありません'
LogExportDiskSpace: '空き容量が 1 GiB 未満のため、エクスポートを停止しました'
LogExportRetentionInvalid: 'エクスポート履歴の保持期間は 130 日にしてください'
ErrStructTransform: '型変換エラー: {{ .err }}'
ErrNotSupportType: '未対応のタイプ: {{ .name }}'

View File

@@ -1,10 +1,17 @@
# 기본 오류
ErrInvalidParams: '잘못된 요청: {{ .detail }}'
ErrMcpGatewayArgsParse: 'MCP 사용자 지정 인수 형식이 잘못되었습니다'
ErrMcpGatewayArgsConflict: '{{ .name }} 인수는 1Panel에서 관리하므로 사용자 지정 인수에 설정할 수 없습니다'
ErrTokenParse: '토큰 오류: {{ .detail }}'
ErrInitialPassword: '원래 비밀번호가 틀립니다'
ErrInternalServer: '서버 오류: {{ .detail }}'
ErrRecordExist: '레코드가 이미 있습니다'
ErrRecordNotFound: '레코드를 찾을 수 없습니다'
WafLogExport: 'WAF 로그 내보내기'
MonitorLogExport: '웹사이트 모니터링 로그 내보내기'
LogExportNoData: '선택한 조건과 일치하는 로그가 없습니다'
LogExportDiskSpace: '사용 가능한 공간이 1 GiB 미만이어서 내보내기를 중지했습니다'
LogExportRetentionInvalid: '내보내기 기록 보관 기간은 1일에서 30일 사이여야 합니다'
ErrStructTransform: '형 변환 실패: {{ .err }}'
ErrNotSupportType: '지원하지 않는 타입: {{ .name }}'

View File

@@ -1,10 +1,17 @@
# ralat asas
ErrInvalidParams: 'Permintaan tidak sah: {{ .detail }}'
ErrMcpGatewayArgsParse: 'Format argumen tersuai MCP tidak sah'
ErrMcpGatewayArgsConflict: 'Argumen {{ .name }} diurus oleh 1Panel dan tidak boleh ditetapkan dalam argumen tersuai'
ErrTokenParse: 'Token tidak sah: {{ .detail }}'
ErrInitialPassword: 'Kata laluan asal salah'
ErrInternalServer: 'Ralat pelayan: {{ .detail }}'
ErrRecordExist: 'Rekod sudah wujud'
ErrRecordNotFound: 'Rekod tidak ditemui'
WafLogExport: 'Eksport log WAF'
MonitorLogExport: 'Eksport log pemantauan laman web'
LogExportNoData: 'Tiada log yang sepadan dengan penapis dipilih'
LogExportDiskSpace: 'Ruang tersedia kurang daripada 1 GiB; eksport dihentikan'
LogExportRetentionInvalid: 'Tempoh simpanan rekod eksport mestilah antara 1 hingga 30 hari'
ErrStructTransform: 'Ralat penukaran: {{ .err }}'
ErrNotSupportType: 'Jenis tidak disokong: {{ .name }}'

View File

@@ -1,10 +1,17 @@
# erros básicos
ErrInvalidParams: 'Requisição inválida: {{ .detail }}'
ErrMcpGatewayArgsParse: 'Formato inválido dos argumentos personalizados do MCP'
ErrMcpGatewayArgsConflict: 'O argumento {{ .name }} é gerenciado pelo 1Panel e não pode ser definido nos argumentos personalizados'
ErrTokenParse: 'Erro de token: {{ .detail }}'
ErrInitialPassword: 'Senha original incorreta'
ErrInternalServer: 'Erro interno: {{ .detail }}'
ErrRecordExist: 'Registro já existe'
ErrRecordNotFound: 'Registro não encontrado'
WafLogExport: 'Exportação de logs do WAF'
MonitorLogExport: 'Exportação de logs de monitoramento de sites'
LogExportNoData: 'Nenhum log corresponde aos filtros selecionados'
LogExportDiskSpace: 'Há menos de 1 GiB disponível; a exportação foi interrompida'
LogExportRetentionInvalid: 'A retenção dos registros de exportação deve ser de 1 a 30 dias'
ErrStructTransform: 'Erro de conversão: {{ .err }}'
ErrNotSupportType: 'Tipo não suportado: {{ .name }}'

View File

@@ -1,10 +1,17 @@
# базовые ошибки
ErrInvalidParams: 'Неверный запрос: {{ .detail }}'
ErrMcpGatewayArgsParse: 'Неверный формат пользовательских аргументов MCP'
ErrMcpGatewayArgsConflict: 'Аргумент {{ .name }} управляется 1Panel и не может быть задан в пользовательских аргументах'
ErrTokenParse: 'Ошибка токена: {{ .detail }}'
ErrInitialPassword: 'Исходный пароль неверен'
ErrInternalServer: 'Внутренняя ошибка: {{ .detail }}'
ErrRecordExist: 'Запись уже существует'
ErrRecordNotFound: 'Запись не найдена'
WafLogExport: 'Экспорт журналов WAF'
MonitorLogExport: 'Экспорт журналов мониторинга веб-сайтов'
LogExportNoData: 'Нет журналов, соответствующих выбранным фильтрам'
LogExportDiskSpace: 'Доступно менее 1 GiB; экспорт остановлен'
LogExportRetentionInvalid: 'Срок хранения истории экспорта должен быть от 1 до 30 дней'
ErrStructTransform: 'Ошибка преобразования: {{ .err }}'
ErrNotSupportType: 'Тип не поддерживается: {{ .name }}'

View File

@@ -1,10 +1,17 @@
# temel hatalar
ErrInvalidParams: 'İstek geçersiz: {{ .detail }}'
ErrMcpGatewayArgsParse: 'MCP özel bağımsız değişken biçimi geçersiz'
ErrMcpGatewayArgsConflict: '{{ .name }} bağımsız değişkeni 1Panel tarafından yönetilir ve özel bağımsız değişkenlerde ayarlanamaz'
ErrTokenParse: 'Token hatası: {{ .detail }}'
ErrInitialPassword: 'Orijinal şifre yanlış'
ErrInternalServer: 'Sunucu hatası: {{ .detail }}'
ErrRecordExist: 'Kayıt zaten var'
ErrRecordNotFound: 'Kayıt bulunamadı'
WafLogExport: 'WAF günlüğü dışa aktarma'
MonitorLogExport: 'Web sitesi izleme günlüğü dışa aktarma'
LogExportNoData: 'Seçilen filtrelerle eşleşen günlük yok'
LogExportDiskSpace: 'Kullanılabilir alan 1 GiB altında; dışa aktarma durduruldu'
LogExportRetentionInvalid: 'Dışa aktarma kayıtları 1 ile 30 gün arasında saklanmalıdır'
ErrStructTransform: 'Dönüşüm hatası: {{ .err }}'
ErrNotSupportType: 'Bu tür desteklenmiyor: {{ .name }}'

View File

@@ -1,10 +1,17 @@
# 基礎錯誤
ErrInvalidParams: '請求參數錯誤: {{ .detail }}'
ErrMcpGatewayArgsParse: 'MCP 自訂參數格式錯誤'
ErrMcpGatewayArgsConflict: '參數 {{ .name }} 由 1Panel 管理,不能在自訂參數中設定'
ErrTokenParse: 'Token 產生錯誤: {{ .detail }}'
ErrInitialPassword: '原密碼錯誤'
ErrInternalServer: '服務內部錯誤: {{ .detail }}'
ErrRecordExist: '記錄已存在'
ErrRecordNotFound: '記錄未能找到'
WafLogExport: 'WAF 日誌匯出'
MonitorLogExport: '網站監控日誌匯出'
LogExportNoData: '沒有符合條件的日誌'
LogExportDiskSpace: '可用磁碟空間不足 1 GiB匯出任務已停止'
LogExportRetentionInvalid: '匯出記錄保留天數必須介於 1 到 30 天之間'
ErrStructTransform: '型別轉換失敗: {{ .err }}'
ErrNotSupportType: '系統暫不支援目前類型: {{ .name }}'

View File

@@ -1,10 +1,17 @@
# 基础错误
ErrInvalidParams: "参数错误: {{ .detail }}"
ErrMcpGatewayArgsParse: "MCP 自定义参数格式错误"
ErrMcpGatewayArgsConflict: "参数 {{ .name }} 由 1Panel 管理,不能在自定义参数中设置"
ErrTokenParse: "Token 错误: {{ .detail }}"
ErrInitialPassword: "原密码错误"
ErrInternalServer: "服务错误: {{ .detail }}"
ErrRecordExist: "记录已存在"
ErrRecordNotFound: "记录不存在"
WafLogExport: "WAF 日志导出"
MonitorLogExport: "网站监控日志导出"
LogExportNoData: "没有符合条件的日志"
LogExportDiskSpace: "可用磁盘空间不足 1 GiB导出任务已停止"
LogExportRetentionInvalid: "导出记录保留天数必须在 1 到 30 天之间"
ErrStructTransform: "类型转换失败: {{ .err }}"
ErrNotSupportType: "不支持当前类型: {{ .name }}"

View File

@@ -87,6 +87,7 @@ func InitAgentDB() {
migrations.AddFileShareTable,
migrations.AddFileHistoryTable,
migrations.MigrateLegoV5,
migrations.AddMcpServerGatewayArgs,
migrations.InitFirewallPortWhiteList,
})
if err := m.Migrate(); err != nil {

View File

@@ -1516,3 +1516,10 @@ var MigrateLegoV5 = &gormigrate.Migration{
return nil
},
}
var AddMcpServerGatewayArgs = &gormigrate.Migration{
ID: "20260714-add-mcp-server-gateway-args",
Migrate: func(tx *gorm.DB) error {
return tx.AutoMigrate(&model.McpServer{})
},
}

View File

@@ -182,6 +182,7 @@ export namespace AI {
type: string;
gatewayImage: string;
protocolVersion: string;
gatewayArgs: string;
taskID?: string;
}

View File

@@ -1398,6 +1398,8 @@ const message = {
protocolVersion: 'Protocol Version',
protocolVersionHelper:
'Only used by stateless Streamable HTTP to auto-initialize the downstream stdio MCP Server',
gatewayArgsHelper:
'Arguments are appended to the supergateway command. Transport, port, path, and protocol arguments managed by 1Panel cannot be changed',
testConnection: 'Test Connection',
connectionSuccess: 'Connection succeeded',
connectionFailed: 'Connection failed',
@@ -4686,6 +4688,26 @@ const message = {
qrCodeExpired: 'Refresh time',
apiLeakageHelper: 'Do not disclose the QR code. Ensure it is used only in trusted environments.',
},
logExport: {
title: 'Export Logs',
records: 'Export Records',
retentionDays: 'Export Record Retention',
timeRange: 'Time Range',
timeRequired: 'Select an export time range',
websiteRequired: 'Select a website',
blackStatus: 'Blacklist Status',
black: 'Blacklisted',
notBlack: 'Not Blacklisted',
fuzzy: 'Fuzzy Match',
regex: 'Regular Expression',
invalidRegex: 'Enter a valid RE2 regular expression with at most 256 characters',
created: 'Export task created',
fileName: 'File Name',
fileSize: 'File Size',
expiresAt: 'Expires At',
cancelConfirm: 'Cancel this export task?',
deleteConfirm: 'Delete this export record and file?',
},
waf: {
name: 'WAF',
blackWhite: 'Black and White List',
@@ -4747,7 +4769,11 @@ const message = {
'Set the method types that are allowed to access. If you want to restrict certain types of access, please turn off this type of button. For example: only GET type access is allowed, then you need to turn off other types of buttons except GET',
geoRule: 'Regional Access Restrictions',
geoHelper:
'Restrict access to your website from certain regions, for example: if access is allowed from mainland China, then requests from outside mainland China will be blocked',
'Combine region and province policies under one switch. Region rules run first, then province rules can further restrict Chinese provincial regions',
regionPolicy: 'Region policy',
provincePolicy: 'Province policy',
provinceRuleLabel: 'Province',
provinceVersionAlert: 'OpenResty must be newer than 1.31.1.1-0 for province policies to take effect.',
ipLocation: 'IP Location',
action: 'Action',
ruleType: 'Attack Type',
@@ -4779,6 +4805,7 @@ const message = {
fileExtHelper: 'Prohibited file extensions for upload',
deny: 'Forbidden',
allow: 'Allow',
allowOnly: 'Allow only',
field: 'Object',
pattern: 'Condition',
ruleContent: 'Content',
@@ -4852,7 +4879,7 @@ const message = {
geoRestrict: 'Regional access restriction',
attacklog: 'Interception Record',
unknownWebsite: 'Unauthorized domain name access',
geoRuleEmpty: 'Region cannot be empty',
geoRuleEmpty: 'Select at least one region or province',
unknown: 'Website Not Exist',
geo: 'Region Restriction',
revertHtml: 'restore {0} as the default page?',
@@ -4941,6 +4968,16 @@ const message = {
crlf: 'CRLF Injection',
strict: 'Strict Mode',
strictHelper: 'Use stricter rules to validate requests',
executionStrategy: 'Execution strategy',
detectionStrength: 'Detection strength',
protectionMode: 'Protection mode',
observationMode: 'Observation mode',
standardMode: 'Standard mode',
observationModeHelper: 'Detects and logs requests without blocking them',
observationModeConfirm:
'In observation mode, all WAF matches are logged without blocking requests. Continue?',
globalStrictRequired: 'Enable strict mode in global settings first',
observe: 'Observe',
saveLog: 'Save Log',
remoteURLHelper: 'The remote URL needs to ensure one IP per line and no other characters',
notFound: 'Not Found (404)',

View File

@@ -1417,6 +1417,8 @@ const message = {
protocolVersion: 'Protocol Version',
protocolVersionHelper:
'Only used by stateless Streamable HTTP to auto-initialize the downstream stdio MCP Server',
gatewayArgsHelper:
'Los argumentos se añaden al comando supergateway. No se pueden cambiar los argumentos de transporte, puerto, ruta y protocolo gestionados por 1Panel',
testConnection: 'Test Connection',
connectionSuccess: 'Connection succeeded',
connectionFailed: 'Connection failed',
@@ -4739,6 +4741,26 @@ const message = {
qrCodeExpired: 'Tiempo de refresco',
apiLeakageHelper: 'No divulgues el código QR. Úsalo solo en entornos de confianza.',
},
logExport: {
title: 'Exportar registros',
records: 'Historial de exportación',
retentionDays: 'Retención del historial de exportación',
timeRange: 'Intervalo de tiempo',
timeRequired: 'Selecciona el intervalo de exportación',
websiteRequired: 'Selecciona un sitio web',
blackStatus: 'Estado de lista negra',
black: 'Bloqueado',
notBlack: 'No bloqueado',
fuzzy: 'Coincidencia parcial',
regex: 'Expresión regular',
invalidRegex: 'Introduce una expresión RE2 válida de hasta 256 caracteres',
created: 'Tarea de exportación creada',
fileName: 'Nombre del archivo',
fileSize: 'Tamaño del archivo',
expiresAt: 'Caduca el',
cancelConfirm: '¿Cancelar esta tarea de exportación?',
deleteConfirm: '¿Eliminar este registro y archivo de exportación?',
},
waf: {
name: 'WAF',
blackWhite: 'Lista Blanca y Negra',
@@ -4798,7 +4820,13 @@ const message = {
httpHelper:
'Define qué métodos HTTP están permitidos. Ejemplo: solo GET. Para restringir, desactiva los métodos no deseados',
geoRule: 'Restricciones geográficas',
geoHelper: 'Restringe accesos desde ciertas regiones. Ejemplo: permitir solo China, bloqueando el resto',
geoHelper:
'Combina políticas de región y provincia con un solo interruptor. Primero se aplican las reglas regionales y después las provinciales',
regionPolicy: 'Política regional',
provincePolicy: 'Política provincial',
provinceRuleLabel: 'Provincia',
provinceVersionAlert:
'OpenResty debe ser posterior a la versión 1.31.1.1-0 para que se apliquen las políticas provinciales.',
ipLocation: 'Ubicación IP',
action: 'Acción',
ruleType: 'Tipo de ataque',
@@ -4830,6 +4858,7 @@ const message = {
fileExtHelper: 'Extensiones prohibidas para subir',
deny: 'Prohibir',
allow: 'Permitir',
allowOnly: 'Permitir solo lo seleccionado',
field: 'Objeto',
pattern: 'Condición',
ruleContent: 'Contenido',
@@ -4901,7 +4930,7 @@ const message = {
geoRestrict: 'Restricción geográfica',
attacklog: 'Registro de intercepciones',
unknownWebsite: 'Acceso a dominio no autorizado',
geoRuleEmpty: 'La región no puede estar vacía',
geoRuleEmpty: 'Selecciona al menos una región o provincia',
unknown: 'Sitio no existe',
geo: 'Restricción por región',
revertHtml: '¿Restaurar {0} como página por defecto?',
@@ -4986,6 +5015,16 @@ const message = {
crlf: 'Inyección CRLF',
strict: 'Modo estricto',
strictHelper: 'Usa reglas más estrictas para validar peticiones',
executionStrategy: 'Estrategia de ejecución',
detectionStrength: 'Nivel de detección',
protectionMode: 'Modo de protección',
observationMode: 'Modo de observación',
standardMode: 'Modo estándar',
observationModeHelper: 'Detecta y registra solicitudes sin bloquearlas',
observationModeConfirm:
'En el modo de observación, todas las coincidencias del WAF se registran sin bloquear solicitudes. ¿Continuar?',
globalStrictRequired: 'Primero habilite el modo estricto en la configuración global',
observe: 'Observar',
saveLog: 'Guardar log',
remoteURLHelper: 'La URL remota debe tener solo una IP por línea y sin otros caracteres',
notFound: 'No encontrado (404)',

View File

@@ -1387,6 +1387,8 @@ const message = {
protocolVersion: 'نسخه پروتکل',
protocolVersionHelper:
'فقط برای Streamable HTTP بدون حالت استفاده می‌شود تا سرور MCP stdio پایین‌دست را به طور خودکار راه‌اندازی کند',
gatewayArgsHelper:
'آرگومان‌ها به دستور راه‌اندازی supergateway افزوده می‌شوند. آرگومان‌های انتقال، پورت، مسیر و پروتکل که توسط 1Panel مدیریت می‌شوند قابل تغییر نیستند',
testConnection: 'تست اتصال',
connectionSuccess: 'اتصال با موفقیت برقرار شد',
connectionFailed: 'اتصال ناموفق بود',
@@ -4654,6 +4656,26 @@ const message = {
qrCodeExpired: 'زمان بازخوانی',
apiLeakageHelper: 'کد QR را افشا نکنید. مطمئن شوید که فقط در محیط‌های قابل اعتماد استفاده می‌شود.',
},
logExport: {
title: 'خروجی گرفتن از لاگ‌ها',
records: 'سوابق خروجی',
retentionDays: 'مدت نگهداری سوابق خروجی',
timeRange: 'بازه زمانی',
timeRequired: 'بازه زمانی خروجی را انتخاب کنید',
websiteRequired: 'یک وب‌سایت انتخاب کنید',
blackStatus: 'وضعیت فهرست سیاه',
black: 'مسدود شده',
notBlack: 'مسدود نشده',
fuzzy: 'تطبیق تقریبی',
regex: 'عبارت منظم',
invalidRegex: 'یک عبارت RE2 معتبر با حداکثر ۲۵۶ نویسه وارد کنید',
created: 'وظیفه خروجی ایجاد شد',
fileName: 'نام فایل',
fileSize: 'اندازه فایل',
expiresAt: 'زمان انقضا',
cancelConfirm: 'این وظیفه خروجی لغو شود؟',
deleteConfirm: 'این سابقه و فایل خروجی حذف شود؟',
},
waf: {
name: 'WAF',
blackWhite: 'لیست سیاه و سفید',

View File

@@ -1400,6 +1400,8 @@ const message = {
protocolVersion: 'Protocol Version',
protocolVersionHelper:
'Only used by stateless Streamable HTTP to auto-initialize the downstream stdio MCP Server',
gatewayArgsHelper:
'引数は supergateway の起動コマンドに追加されます。1Panel が管理する転送方式、ポート、パス、プロトコルの引数は変更できません',
testConnection: 'Test Connection',
connectionSuccess: 'Connection succeeded',
connectionFailed: 'Connection failed',
@@ -4707,6 +4709,26 @@ const message = {
qrCodeExpired: 'リフレッシュ時間',
apiLeakageHelper: 'QRコードを漏洩しないでください信頼できる環境でのみ使用してください',
},
logExport: {
title: 'ログをエクスポート',
records: 'エクスポート履歴',
retentionDays: 'エクスポート履歴の保持日数',
timeRange: '期間',
timeRequired: 'エクスポート期間を選択してください',
websiteRequired: 'Web サイトを選択してください',
blackStatus: 'ブラックリスト状態',
black: '登録済み',
notBlack: '未登録',
fuzzy: 'あいまい一致',
regex: '正規表現',
invalidRegex: '256 文字以内の有効な RE2 正規表現を入力してください',
created: 'エクスポートタスクを作成しました',
fileName: 'ファイル名',
fileSize: 'ファイルサイズ',
expiresAt: '有効期限',
cancelConfirm: 'このエクスポートタスクをキャンセルしますか',
deleteConfirm: 'このエクスポート履歴とファイルを削除しますか',
},
waf: {
name: 'WAF',
blackWhite: 'ブラックリストとホワイトリスト',
@@ -4767,7 +4789,12 @@ const message = {
'アクセスを許可するメソッドタイプを設定します特定のタイプのアクセスを制限したい場合はそのタイプのボタンをオフにしてください例えばGETタイプのみのアクセスを許可する場合はGET以外のボタンをオフにする必要があります',
geoRule: '地域アクセス制限',
geoHelper:
'特定の地域からのウェブサイトへのアクセスを制限します例えば中国本土からのアクセスを許可しそれ以外の地域からのリクエストをブロックすることができます',
'1つのスイッチで地域と省のポリシーを組み合わせます地域ルールを先に評価しその後に省ルールを適用します',
regionPolicy: '地域ポリシー',
provincePolicy: '省ポリシー',
provinceRuleLabel: '省',
provinceVersionAlert:
'省ポリシーを有効にするにはOpenResty のバージョンが 1.31.1.1-0 より新しい必要があります',
ipLocation: 'IP位置',
action: 'アクション',
ruleType: '攻撃タイプ',
@@ -4799,6 +4826,7 @@ const message = {
fileExtHelper: 'アップロード禁止ファイル拡張子',
deny: '禁止',
allow: '許可',
allowOnly: '選択項目のみ許可',
field: 'オブジェクト',
pattern: '条件',
ruleContent: 'コンテンツ',
@@ -4870,7 +4898,7 @@ const message = {
geoRestrict: '地域アクセス制限',
attacklog: '遮断記録',
unknownWebsite: '認証されていないドメイン名アクセス',
geoRuleEmpty: '地域は空にできません',
geoRuleEmpty: '地域または省を1つ以上選択してください',
unknown: 'ウェブサイトが存在しません',
geo: '地域制限',
revertHtml: '{0} をデフォルトページに戻しますか',
@@ -4958,6 +4986,16 @@ const message = {
crlf: 'CRLF インジェクション',
strict: '厳格モード',
strictHelper: 'より厳格なルールを使用してリクエストを検証します',
executionStrategy: '実行ポリシー',
detectionStrength: '検出強度',
protectionMode: '防御モード',
observationMode: '監視モード',
standardMode: '標準モード',
observationModeHelper: 'リクエストをブロックせず検出とログ記録のみを行います',
observationModeConfirm:
'監視モードではすべての WAF 検出をログに記録しリクエストをブロックしません続行しますか',
globalStrictRequired: '先にグローバル設定で厳格モードを有効にしてください',
observe: '監視',
saveLog: 'ログを保存',
remoteURLHelper: 'リモート URL 1行に1つのIPで他の文字がないことを保証する必要があります',
notFound: 'Not Found (404)',

View File

@@ -1381,6 +1381,8 @@ const message = {
protocolVersion: 'Protocol Version',
protocolVersionHelper:
'Only used by stateless Streamable HTTP to auto-initialize the downstream stdio MCP Server',
gatewayArgsHelper:
'인수는 supergateway 시작 명령에 추가됩니다. 1Panel에서 관리하는 전송, 포트, 경로 및 프로토콜 인수는 변경할 수 없습니다',
testConnection: 'Test Connection',
connectionSuccess: 'Connection succeeded',
connectionFailed: 'Connection failed',
@@ -4613,6 +4615,26 @@ const message = {
qrCodeExpired: '새로 고침 시간',
apiLeakageHelper: 'QR 코드를 누출하지 마십시오. 신뢰할 수 있는 환경에서만 사용하십시오.',
},
logExport: {
title: '로그 내보내기',
records: '내보내기 기록',
retentionDays: '내보내기 기록 보관 일수',
timeRange: '시간 범위',
timeRequired: '내보낼 시간 범위를 선택하세요',
websiteRequired: '웹사이트를 선택하세요',
blackStatus: '차단 목록 상태',
black: '차단됨',
notBlack: '차단되지 않음',
fuzzy: '부분 일치',
regex: '정규식',
invalidRegex: '256자 이하의 올바른 RE2 정규식을 입력하세요',
created: '내보내기 작업이 생성되었습니다',
fileName: '파일 이름',
fileSize: '파일 크기',
expiresAt: '만료 시간',
cancelConfirm: '이 내보내기 작업을 취소하시겠습니까?',
deleteConfirm: '이 내보내기 기록과 파일을 삭제하시겠습니까?',
},
waf: {
WAF: 'WAF',
blackWhite: '블랙 및 화이트 목록',
@@ -4672,7 +4694,11 @@ const message = {
'허용된 접근 방식 유형을 설정합니다. 특정 접근 방식을 제한하려면 해당 유형의 버튼을 끄십시오. 예를 들어: GET 방식만 허용하려면 GET 을 제외한 다른 방식의 버튼을 끄세요.',
geoRule: '지역별 접근 제한',
geoHelper:
'특정 지역에서만 웹사이트 접근을 허용하고 다른 지역에서의 접근을 차단할 수 있습니다. 예를 들어: 중국 본토에서만 접근을 허용하고, 그 외 지역에서의 접근을 차단할 수 있습니다.',
'하나의 스위치로 지역 및 성 정책을 결합합니다. 지역 규칙을 먼저 적용한 다음 성 규칙을 적용합니다.',
regionPolicy: '지역 정책',
provincePolicy: '성 정책',
provinceRuleLabel: '성',
provinceVersionAlert: '성 정책을 적용하려면 OpenResty 버전이 1.31.1.1-0보다 높아야 합니다.',
ipLocation: 'IP 위치',
action: '동작',
ruleType: '공격 유형',
@@ -4704,6 +4730,7 @@ const message = {
fileExtHelper: '업로드 제한 파일 확장자',
deny: '금지',
allow: '허용',
allowOnly: '선택 항목만 허용',
field: '객체',
pattern: '조건',
ruleContent: '내용',
@@ -4774,7 +4801,7 @@ const message = {
geoRestrict: '지역 접근 제한',
attacklog: '차단 기록',
unknownWebsite: '허가되지 않은 도메인 접근',
geoRuleEmpty: '지역은 비워 둘 수 없습니다.',
geoRuleEmpty: '지역 또는 성을 하나 이상 선택하세요.',
unknown: '웹사이트 없음',
geo: '지역 제한',
revertHtml: '{0}을 기본 페이지로 복원하시겠습니까?',
@@ -4860,6 +4887,16 @@ const message = {
crlf: 'CRLF 인젝션',
strict: '엄격 모드',
strictHelper: '더 엄격한 규칙을 사용하여 요청을 검증합니다',
executionStrategy: '실행 정책',
detectionStrength: '탐지 강도',
protectionMode: '보호 모드',
observationMode: '관찰 모드',
standardMode: '표준 모드',
observationModeHelper: '요청을 차단하지 않고 탐지 및 로그만 기록합니다',
observationModeConfirm:
'관찰 모드에서는 모든 WAF 탐지를 기록하지만 요청을 차단하지 않습니다. 계속하시겠습니까?',
globalStrictRequired: '먼저 전역 설정에서 엄격 모드를 활성화하세요',
observe: '관찰',
saveLog: '로그 저장',
remoteURLHelper: '원격 URL은 한 줄에 하나의 IP만 포함하고 다른 문자는 포함하지 않아야 합니다',
notFound: 'Not Found (404)',

View File

@@ -1411,6 +1411,8 @@ const message = {
protocolVersion: 'Protocol Version',
protocolVersionHelper:
'Only used by stateless Streamable HTTP to auto-initialize the downstream stdio MCP Server',
gatewayArgsHelper:
'Argumen ditambahkan pada arahan supergateway. Argumen pengangkutan, port, laluan dan protokol yang diurus oleh 1Panel tidak boleh diubah',
testConnection: 'Test Connection',
connectionSuccess: 'Connection succeeded',
connectionFailed: 'Connection failed',
@@ -4765,6 +4767,26 @@ const message = {
qrCodeExpired: 'Masa penyegaran',
apiLeakageHelper: 'Jangan dedahkan kod QR. Pastikan ia hanya digunakan di persekitaran yang dipercayai.',
},
logExport: {
title: 'Eksport Log',
records: 'Rekod Eksport',
retentionDays: 'Tempoh Simpanan Rekod Eksport',
timeRange: 'Julat Masa',
timeRequired: 'Pilih julat masa eksport',
websiteRequired: 'Pilih laman web',
blackStatus: 'Status Senarai Hitam',
black: 'Disenarai hitam',
notBlack: 'Tidak disenarai hitam',
fuzzy: 'Padanan Kabur',
regex: 'Ungkapan Biasa',
invalidRegex: 'Masukkan ungkapan RE2 yang sah, maksimum 256 aksara',
created: 'Tugas eksport telah dibuat',
fileName: 'Nama Fail',
fileSize: 'Saiz Fail',
expiresAt: 'Tamat Tempoh',
cancelConfirm: 'Batalkan tugas eksport ini?',
deleteConfirm: 'Padam rekod eksport dan fail ini?',
},
waf: {
name: 'WAF',
blackWhite: 'Senarai Hitam dan Putih',
@@ -4826,7 +4848,12 @@ const message = {
'Tetapkan jenis kaedah yang dibenarkan untuk diakses. Jika anda ingin mengehadkan jenis akses tertentu, sila matikan jenis butang ini. Contoh: hanya akses jenis GET dibenarkan, maka anda perlu matikan butang lain selain GET',
geoRule: 'Sekatan Akses Wilayah',
geoHelper:
'Sekat akses ke laman web anda dari wilayah tertentu, sebagai contoh: jika akses dibenarkan dari China Tanah Besar, maka permintaan dari luar China Tanah Besar akan disekat',
'Gabungkan dasar wilayah dan wilayah pentadbiran dalam satu suis. Peraturan wilayah dinilai sebelum peraturan wilayah pentadbiran',
regionPolicy: 'Dasar wilayah',
provincePolicy: 'Dasar wilayah pentadbiran',
provinceRuleLabel: 'Wilayah pentadbiran',
provinceVersionAlert:
'OpenResty mestilah lebih baharu daripada 1.31.1.1-0 untuk dasar wilayah pentadbiran berfungsi.',
ipLocation: 'Lokasi IP',
action: 'Tindakan',
ruleType: 'Jenis Serangan',
@@ -4858,6 +4885,7 @@ const message = {
fileExtHelper: 'Lanjaran fail yang dilarang untuk dimuat naik',
deny: 'Dilarang',
allow: 'Benarkan',
allowOnly: 'Benarkan yang dipilih sahaja',
field: 'Objek',
pattern: 'Keadaan',
ruleContent: 'Kandungan',
@@ -4931,7 +4959,7 @@ const message = {
geoRestrict: 'Sekatan Akses Wilayah',
attacklog: 'Rekod Sekat',
unknownWebsite: 'Akses domain yang tidak sah',
geoRuleEmpty: 'Wilayah tidak boleh kosong',
geoRuleEmpty: 'Pilih sekurang-kurangnya satu wilayah atau wilayah pentadbiran',
unknown: 'Laman Web Tidak Wujud',
geo: 'Sekatan Wilayah',
revertHtml: 'Adakah anda mahu memulihkan {0} sebagai halaman lalai?',
@@ -5019,6 +5047,16 @@ const message = {
crlf: 'Penyuntikan CRLF',
strict: 'Mod Strict',
strictHelper: 'Gunakan peraturan yang lebih ketat untuk mengesahkan permintaan',
executionStrategy: 'Strategi pelaksanaan',
detectionStrength: 'Kekuatan pengesanan',
protectionMode: 'Mod perlindungan',
observationMode: 'Mod pemerhatian',
standardMode: 'Mod standard',
observationModeHelper: 'Mengesan dan merekod permintaan tanpa menyekatnya',
observationModeConfirm:
'Dalam mod pemerhatian, semua padanan WAF direkod tanpa menyekat permintaan. Teruskan?',
globalStrictRequired: 'Dayakan mod strict dalam tetapan global terlebih dahulu',
observe: 'Perhati',
saveLog: 'Simpan Log',
remoteURLHelper: 'URL jauh perlu memastikan satu IP setiap baris dan tiada aksara lain',
notFound: 'Not Found (404)',

View File

@@ -1409,6 +1409,8 @@ const message = {
protocolVersion: 'Protocol Version',
protocolVersionHelper:
'Only used by stateless Streamable HTTP to auto-initialize the downstream stdio MCP Server',
gatewayArgsHelper:
'Os argumentos são adicionados ao comando supergateway. Os parâmetros de transporte, porta, caminho e protocolo gerenciados pelo 1Panel não podem ser alterados',
testConnection: 'Test Connection',
connectionSuccess: 'Connection succeeded',
connectionFailed: 'Connection failed',
@@ -4907,6 +4909,26 @@ const message = {
qrCodeExpired: 'Tempo de atualização',
apiLeakageHelper: 'Não revele o QR code. Garanta que ele seja usado apenas em ambientes confiáveis.',
},
logExport: {
title: 'Exportar logs',
records: 'Registros de exportação',
retentionDays: 'Retenção dos registros de exportação',
timeRange: 'Período',
timeRequired: 'Selecione o período da exportação',
websiteRequired: 'Selecione um site',
blackStatus: 'Status da lista de bloqueio',
black: 'Bloqueado',
notBlack: 'Não bloqueado',
fuzzy: 'Correspondência aproximada',
regex: 'Expressão regular',
invalidRegex: 'Insira uma expressão RE2 válida com no máximo 256 caracteres',
created: 'Tarefa de exportação criada',
fileName: 'Nome do arquivo',
fileSize: 'Tamanho do arquivo',
expiresAt: 'Expira em',
cancelConfirm: 'Cancelar esta tarefa de exportação?',
deleteConfirm: 'Excluir este registro e arquivo de exportação?',
},
waf: {
name: 'WAF',
blackWhite: 'Lista negra e branca',
@@ -4969,7 +4991,12 @@ const message = {
'Defina os tipos de métodos permitidos para acessar. Se você deseja restringir certos tipos de acesso, desative esse tipo de botão. Por exemplo: se apenas o acesso do tipo GET for permitido, desative todos os outros botões, exceto o GET',
geoRule: 'Restrições de acesso regional',
geoHelper:
'Restringe o acesso ao seu site a partir de certas regiões, por exemplo: se o acesso for permitido a partir da China continental, então requisições de fora da China continental serão bloqueadas',
'Combine políticas de região e província em um único controle. As regras de região são avaliadas antes das regras de província',
regionPolicy: 'Política regional',
provincePolicy: 'Política de província',
provinceRuleLabel: 'Província',
provinceVersionAlert:
'O OpenResty deve ser posterior à versão 1.31.1.1-0 para que as políticas de província funcionem.',
ipLocation: 'Localização do IP',
action: 'Ação',
ruleType: 'Tipo de ataque',
@@ -5001,6 +5028,7 @@ const message = {
fileExtHelper: 'Extensões de arquivos proibidas para upload',
deny: 'Proibido',
allow: 'Permitir',
allowOnly: 'Permitir apenas',
field: 'Objeto',
pattern: 'Condição',
ruleContent: 'Conteúdo',
@@ -5074,7 +5102,7 @@ const message = {
geoRestrict: 'Restrição de acesso regional',
attacklog: 'Registro de Interceptação',
unknownWebsite: 'Acesso a nome de domínio não autorizado',
geoRuleEmpty: 'A região não pode estar vazia',
geoRuleEmpty: 'Selecione pelo menos uma região ou província',
unknown: 'Site não existe',
geo: 'Restrição Regional',
revertHtml: 'Você deseja restaurar {0} como a página padrão?',
@@ -5164,6 +5192,16 @@ const message = {
crlf: 'Injeção CRLF',
strict: 'Modo estrito',
strictHelper: 'Usa regras mais rigorosas para validar solicitações',
executionStrategy: 'Estratégia de execução',
detectionStrength: 'Nível de detecção',
protectionMode: 'Modo de proteção',
observationMode: 'Modo de observação',
standardMode: 'Modo padrão',
observationModeHelper: 'Detecta e registra solicitações sem bloqueá-las',
observationModeConfirm:
'No modo de observação, todas as correspondências do WAF são registradas sem bloquear solicitações. Continuar?',
globalStrictRequired: 'Primeiro habilite o modo estrito nas configurações globais',
observe: 'Observar',
saveLog: 'Salvar log',
remoteURLHelper: 'O URL remoto precisa garantir um IP por linha e nenhum outro caractere',
notFound: 'Not Found (404)',

View File

@@ -1404,6 +1404,8 @@ const message = {
protocolVersion: 'Protocol Version',
protocolVersionHelper:
'Only used by stateless Streamable HTTP to auto-initialize the downstream stdio MCP Server',
gatewayArgsHelper:
'Аргументы добавляются к команде supergateway. Параметры транспорта, порта, пути и протокола, управляемые 1Panel, изменить нельзя',
testConnection: 'Test Connection',
connectionSuccess: 'Connection succeeded',
connectionFailed: 'Connection failed',
@@ -4758,6 +4760,26 @@ const message = {
qrCodeExpired: 'Время обновления',
apiLeakageHelper: 'Не раскрывайте QR-код. Убедитесь, что он используется только в доверенных средах.',
},
logExport: {
title: 'Экспорт журналов',
records: 'История экспорта',
retentionDays: 'Срок хранения истории экспорта',
timeRange: 'Диапазон времени',
timeRequired: 'Выберите диапазон времени экспорта',
websiteRequired: 'Выберите веб-сайт',
blackStatus: 'Статус черного списка',
black: 'Заблокирован',
notBlack: 'Не заблокирован',
fuzzy: 'Нечеткий поиск',
regex: 'Регулярное выражение',
invalidRegex: 'Введите корректное выражение RE2 длиной до 256 символов',
created: 'Задача экспорта создана',
fileName: 'Имя файла',
fileSize: 'Размер файла',
expiresAt: 'Срок действия',
cancelConfirm: 'Отменить эту задачу экспорта?',
deleteConfirm: 'Удалить эту запись экспорта и файл?',
},
waf: {
name: 'WAF',
blackWhite: 'Черный и белый список',
@@ -4819,7 +4841,11 @@ const message = {
'Установите типы методов, которые могут получить доступ. Если вы хотите ограничить определенные типы доступа, отключите эти кнопки. Например: если разрешен только доступ GET, то нужно отключить другие методы, кроме GET',
geoRule: 'Ограничения по региону',
geoHelper:
'Ограничьте доступ к вашему сайту с определенных регионов. Например, если доступ разрешен только из Китая, запросы из-за пределов Китая будут заблокированы',
'Объединяет правила регионов и провинций одним переключателем. Сначала применяются правила регионов, затем правила провинций',
regionPolicy: 'Правила регионов',
provincePolicy: 'Правила провинций',
provinceRuleLabel: 'Провинция',
provinceVersionAlert: 'Для работы правил провинций требуется версия OpenResty новее 1.31.1.1-0.',
ipLocation: 'Местоположение IP',
action: 'Действие',
ruleType: 'Тип атаки',
@@ -4851,6 +4877,7 @@ const message = {
fileExtHelper: 'Запрещенные расширения файлов для загрузки',
deny: 'Запрещено',
allow: 'Разрешить',
allowOnly: 'Разрешить только выбранное',
field: 'Объект',
pattern: 'Условие',
ruleContent: 'Содержание',
@@ -4923,7 +4950,7 @@ const message = {
geoRestrict: 'Ограничение по региону',
attacklog: 'Запись перехвата',
unknownWebsite: 'Неавторизованный доступ к домену',
geoRuleEmpty: 'Регион не может быть пустым',
geoRuleEmpty: 'Выберите хотя бы один регион или провинцию',
unknown: 'Сайт не существует',
geo: 'Ограничение по региону',
revertHtml: 'Вы хотите восстановить {0} как страницу по умолчанию?',
@@ -5013,6 +5040,16 @@ const message = {
crlf: 'Инъекция CRLF',
strict: 'Строгий режим',
strictHelper: 'Использует более строгие правила для проверки запросов',
executionStrategy: 'Стратегия выполнения',
detectionStrength: 'Уровень обнаружения',
protectionMode: 'Режим защиты',
observationMode: 'Режим наблюдения',
standardMode: 'Стандартный режим',
observationModeHelper: 'Обнаруживает и записывает запросы, не блокируя их',
observationModeConfirm:
'В режиме наблюдения все срабатывания WAF записываются без блокировки запросов. Продолжить?',
globalStrictRequired: 'Сначала включите строгий режим в глобальных настройках',
observe: 'Наблюдение',
saveLog: 'Сохранить лог',
remoteURLHelper: 'Удаленный URL должен содержать один IP на строку и не содержать других символов',
notFound: 'Not Found (404)',

View File

@@ -1409,6 +1409,8 @@ const message = {
protocolVersion: 'Protocol Version',
protocolVersionHelper:
'Only used by stateless Streamable HTTP to auto-initialize the downstream stdio MCP Server',
gatewayArgsHelper:
'Bağımsız değişkenler supergateway komutuna eklenir. 1Panel tarafından yönetilen aktarım, bağlantı noktası, yol ve protokol bağımsız değişkenleri değiştirilemez',
testConnection: 'Test Connection',
connectionSuccess: 'Connection succeeded',
connectionFailed: 'Connection failed',
@@ -4756,6 +4758,26 @@ const message = {
qrCodeExpired: 'Yenileme zamanı',
apiLeakageHelper: 'QR kodunu paylaşmayın. Yalnızca güvenilir ortamlarda kullanıldığından emin olun.',
},
logExport: {
title: 'Günlükleri Dışa Aktar',
records: 'Dışa Aktarma Kayıtları',
retentionDays: 'Dışa Aktarma Kaydı Saklama Süresi',
timeRange: 'Zaman Aralığı',
timeRequired: 'Dışa aktarma zaman aralığını seçin',
websiteRequired: 'Bir web sitesi seçin',
blackStatus: 'Kara Liste Durumu',
black: 'Kara listede',
notBlack: 'Kara listede değil',
fuzzy: 'Bulanık Eşleşme',
regex: 'Düzenli İfade',
invalidRegex: 'En fazla 256 karakterlik geçerli bir RE2 ifadesi girin',
created: 'Dışa aktarma görevi oluşturuldu',
fileName: 'Dosya Adı',
fileSize: 'Dosya Boyutu',
expiresAt: 'Son Kullanma',
cancelConfirm: 'Bu dışa aktarma görevi iptal edilsin mi?',
deleteConfirm: 'Bu dışa aktarma kaydı ve dosyası silinsin mi?',
},
waf: {
name: 'WAF',
blackWhite: 'Kara ve Beyaz Liste',
@@ -4816,7 +4838,12 @@ const message = {
'İzin verilen yöntem türlerini ayarlayın. Belirli erişim türlerini kısıtlamak istiyorsanız, bu tür düğmeyi kapatın. Örneğin: yalnızca GET türüne izin veriliyorsa, GET dışındaki diğer tür düğmeleri kapatmanız gerekir',
geoRule: 'Bölgesel Erişim Kısıtlamaları',
geoHelper:
'Web sitenize belirli bölgelerden erişimi kısıtlayın, örneğin: Çin anakarasına erişime izin veriliyorsa, Çin anakarası dışındaki istekler engellenir',
'Bölge ve il politikalarını tek anahtarda birleştirir. Önce bölge kuralları, ardından il kuralları uygulanır',
regionPolicy: 'Bölge politikası',
provincePolicy: 'İl politikası',
provinceRuleLabel: 'İl',
provinceVersionAlert:
'İl politikalarının çalışması için OpenResty sürümü 1.31.1.1-0 sürümünden daha yeni olmalıdır.',
ipLocation: 'IP Konumu',
action: 'Eylem',
ruleType: 'Saldırı Türü',
@@ -4848,6 +4875,7 @@ const message = {
fileExtHelper: 'Yükleme için yasak dosya uzantıları',
deny: 'Yasakla',
allow: 'İzin Ver',
allowOnly: 'Yalnızca seçilenlere izin ver',
field: 'Nesne',
pattern: 'Koşul',
ruleContent: 'İçerik',
@@ -4921,7 +4949,7 @@ const message = {
geoRestrict: 'Bölgesel erişim kısıtlaması',
attacklog: 'Engelleme Kaydı',
unknownWebsite: 'Yetkisiz alan adı erişimi',
geoRuleEmpty: 'Bölge boş olamaz',
geoRuleEmpty: 'En az bir bölge veya il seçin',
unknown: 'Web Sitesi Mevcut Değil',
geo: 'Bölge Kısıtlaması',
revertHtml: '{0}ı varsayılan sayfa olarak geri yüklemek istiyor musunuz?',
@@ -5009,6 +5037,16 @@ const message = {
crlf: 'CRLF Enjeksiyonu',
strict: 'Katı Mod',
strictHelper: 'İstekleri doğrulamak için daha katı kurallar kullanın',
executionStrategy: 'Yürütme stratejisi',
detectionStrength: 'Algılama düzeyi',
protectionMode: 'Koruma modu',
observationMode: 'Gözlem modu',
standardMode: 'Standart mod',
observationModeHelper: 'İstekleri engellemeden algılar ve günlüğe kaydeder',
observationModeConfirm:
'Gözlem modunda tüm WAF eşleşmeleri istekler engellenmeden kaydedilir. Devam edilsin mi?',
globalStrictRequired: 'Önce genel ayarlarda katı modu etkinleştirin',
observe: 'Gözlem',
saveLog: 'Günlüğü Kaydet',
remoteURLHelper: 'Uzak URL, her satırda bir IP içermeli ve başka karakter olmamalıdır',
notFound: 'Bulunamadı (404)',

View File

@@ -1325,6 +1325,8 @@ const message = {
uvxHelper: '適合 uvx 啟動的 mcp',
protocolVersion: '協議版本',
protocolVersionHelper: '僅用於無狀態 Streamable HTTP 自動初始化下游 stdio MCP Server',
gatewayArgsHelper:
'參數將附加到 supergateway 啟動命令,不支援修改由 1Panel 管理的傳輸、連接埠、路徑和協議參數',
testConnection: '測試連線',
connectionSuccess: '連線成功',
connectionFailed: '連線失敗',
@@ -4362,6 +4364,26 @@ const message = {
view: '檢視',
manage: '管理',
},
logExport: {
title: '匯出日誌',
records: '匯出記錄',
retentionDays: '匯出記錄保留天數',
timeRange: '時間範圍',
timeRequired: '請選擇匯出時間範圍',
websiteRequired: '請選擇網站',
blackStatus: '黑名單狀態',
black: '已封鎖',
notBlack: '未封鎖',
fuzzy: '模糊比對',
regex: '正則表示式',
invalidRegex: '請輸入有效的 RE2 正則表示式,最長 256 個字元',
created: '匯出任務已建立',
fileName: '檔案名稱',
fileSize: '檔案大小',
expiresAt: '過期時間',
cancelConfirm: '確認取消此匯出任務?',
deleteConfirm: '確認刪除此匯出記錄及檔案?',
},
waf: {
name: 'WAF',
blackWhite: '黑白名單',
@@ -4420,7 +4442,11 @@ const message = {
httpHelper:
'設定允許存取的方法類型,如果想限制某些類型瀏覽,請關閉這個類型的按鈕,例:僅允許 GET 類型瀏覽,那麼需要關閉除了 GET 之外的其他類型按鈕',
geoRule: '地區存取限制',
geoHelper: '限制某些地區瀏覽你的網站,例:允許中國大陸瀏覽,那麼中國大陸以外的請求都會被攔截',
geoHelper: '使用一個開關組合地區與省份策略,先執行地區規則,再由省份規則進一步限制中國省級區域',
regionPolicy: '地區策略',
provincePolicy: '省份策略',
provinceRuleLabel: '省份',
provinceVersionAlert: 'OpenResty 版本需高於 1.31.1.1-0省份策略才會生效。',
ipLocation: 'IP 歸屬地',
action: '動作',
ruleType: '攻擊類型',
@@ -4452,6 +4478,7 @@ const message = {
fileExtHelper: '禁止上傳的檔案副檔名',
deny: '禁止',
allow: '允許',
allowOnly: '僅放行',
field: '匹配物件',
pattern: '符合條件',
ruleContent: '符合內容',
@@ -4520,7 +4547,7 @@ const message = {
geoRestrict: '地區存取限制',
attacklog: '攔截紀錄',
unknownWebsite: '未授權網域存取',
geoRuleEmpty: '地區不能為空',
geoRuleEmpty: '地區或省份至少選擇一項',
unknown: '網站不存在',
geo: '地區限制',
revertHtml: '是否還原{0}為預設頁面?',
@@ -4602,6 +4629,15 @@ const message = {
crlf: 'CRLF 注入',
strict: '嚴格模式',
strictHelper: '使用更嚴格的規則來校驗請求',
executionStrategy: '執行策略',
detectionStrength: '檢測強度',
protectionMode: '防護模式',
observationMode: '觀察模式',
standardMode: '標準模式',
observationModeHelper: '僅檢測並記錄日誌,不會攔截請求',
observationModeConfirm: '開啟觀察模式後,所有 WAF 命中都只記錄日誌,不會攔截請求,是否繼續?',
globalStrictRequired: '需要先在全域設定中開啟嚴格模式',
observe: '觀察',
saveLog: '儲存日誌',
remoteURLHelper: '遠端 URL 需要保證每行一個 IP 並且沒有其他字元',
notFound: 'Not Found (404)',

View File

@@ -1319,6 +1319,8 @@ const message = {
uvxHelper: '适合 uvx 启动的 mcp',
protocolVersion: '协议版本',
protocolVersionHelper: '仅用于无状态 Streamable HTTP 自动初始化下游 stdio MCP Server',
gatewayArgsHelper:
'参数将追加到 supergateway 启动命令,不支持修改由 1Panel 管理的传输、端口、路径和协议参数',
testConnection: '测试连接',
connectionSuccess: '连接成功',
connectionFailed: '连接失败',
@@ -3818,6 +3820,26 @@ const message = {
menu: '高级功能',
upage: 'AI 建站',
proAlert: '升级商业版使用此功能',
logExport: {
title: '导出日志',
records: '导出记录',
retentionDays: '导出记录保留天数',
timeRange: '时间范围',
timeRequired: '请选择导出时间范围',
websiteRequired: '请选择网站',
blackStatus: '黑名单状态',
black: '已拉黑',
notBlack: '未拉黑',
fuzzy: '模糊匹配',
regex: '正则表达式',
invalidRegex: '请输入有效的 RE2 正则表达式,最长 256 个字符',
created: '导出任务已创建',
fileName: '文件名',
fileSize: '文件大小',
expiresAt: '过期时间',
cancelConfirm: '确认取消此导出任务?',
deleteConfirm: '确认删除此导出记录及文件?',
},
waf: {
name: 'WAF',
blackWhite: '黑白名单',
@@ -3875,7 +3897,11 @@ const message = {
httpHelper:
'设置允许访问的方法类型,如果想限制某些类型访问,请关闭这个类型的按钮,例如:仅允许 GET 类型访问,那么需要关闭除了 GET 之外的其他类型按钮',
geoRule: '地区访问限制',
geoHelper: '限制某些地区访问你的网站,例如:允许中国大陆访问,那么中国大陆以外的请求都会被拦截',
geoHelper: '使用一个开关组合地区和省份策略,地区规则先执行,省份规则可进一步限制中国省级区域',
regionPolicy: '地区策略',
provincePolicy: '省份策略',
provinceRuleLabel: '省份',
provinceVersionAlert: 'OpenResty 版本需高于 1.31.1.1-0省份策略才会生效。',
ipLocation: 'IP 归属地',
action: '动作',
ruleType: '攻击类型',
@@ -3907,6 +3933,7 @@ const message = {
fileExtHelper: '禁止上传的文件扩展名',
deny: '禁止',
allow: '允许',
allowOnly: '仅放行',
field: '匹配对象',
pattern: '匹配条件',
ruleContent: '匹配内容',
@@ -3975,7 +4002,7 @@ const message = {
geoRestrict: '地区访问限制',
attacklog: '拦截记录',
unknownWebsite: '未授权域名访问',
geoRuleEmpty: '地区不能为空',
geoRuleEmpty: '地区或省份至少选择一项',
unknown: '网站不存在',
geo: '地区限制',
revertHtml: '是否还原{0}为默认页面?',
@@ -4057,6 +4084,15 @@ const message = {
crlf: 'CRLF 注入',
strict: '严格模式',
strictHelper: '使用更严格的规则来校验请求',
executionStrategy: '执行策略',
detectionStrength: '检测强度',
protectionMode: '防护模式',
observationMode: '观察模式',
standardMode: '标准模式',
observationModeHelper: '仅检测并记录日志,不会拦截请求',
observationModeConfirm: '开启观察模式后,所有 WAF 命中都只记录日志,不会拦截请求,是否继续?',
globalStrictRequired: '需要先在全局设置中开启严格模式',
observe: '观察',
saveLog: '保存日志',
remoteURLHelper: '远程 URL 需要保证每行一个 IP 并且没有其他字符',
notFound: 'Not Found (404)',

View File

@@ -89,6 +89,18 @@
{{ $t('aiTools.mcp.protocolVersionHelper') }}
</span>
</el-form-item>
<el-form-item :label="$t('app.params')" prop="gatewayArgs">
<el-input
v-model="mcpServer.gatewayArgs"
type="textarea"
:rows="3"
:maxlength="4096"
placeholder='--header "x-user-id: 123" --logLevel debug'
/>
<span class="input-help">
{{ $t('aiTools.mcp.gatewayArgsHelper') }}
</span>
</el-form-item>
<el-form-item :label="$t('container.image')" prop="gatewayImage">
<el-input v-model.trim="mcpServer.gatewayImage" />
</el-form-item>
@@ -180,6 +192,7 @@ const newMcpServer = (): AI.McpServer => {
type: 'npx',
gatewayImage: defaultGatewayImages.npx,
protocolVersion: defaultProtocolVersion,
gatewayArgs: '',
taskID: '',
};
};
@@ -226,6 +239,7 @@ const acceptParams = async (params: AI.McpServer) => {
mcpServer.value.type = mcpServer.value.type || 'npx';
mcpServer.value.gatewayImage = mcpServer.value.gatewayImage || defaultGatewayImages[mcpServer.value.type];
mcpServer.value.protocolVersion = mcpServer.value.protocolVersion || defaultProtocolVersion;
mcpServer.value.gatewayArgs = mcpServer.value.gatewayArgs || '';
} else {
mcpServer.value = newMcpServer();
if (params.port) {