mirror of
https://hubproxy.babadafafafafa.cn/https://github.com/1Panel-dev/1Panel.git
synced 2026-09-20 08:03:55 +08:00
feat: Add TaskLog for MCP Servers (#13160)
This commit is contained in:
@@ -23,6 +23,7 @@ type McpServerCreate struct {
|
||||
Type string `json:"type" validate:"required"`
|
||||
GatewayImage string `json:"gatewayImage"`
|
||||
ProtocolVersion string `json:"protocolVersion"`
|
||||
TaskID string `json:"taskID"`
|
||||
}
|
||||
|
||||
type McpServerUpdate struct {
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/agent/app/dto/response"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/model"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/repo"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/task"
|
||||
"github.com/1Panel-dev/1Panel/agent/buserr"
|
||||
"github.com/1Panel-dev/1Panel/agent/cmd/server/ai"
|
||||
"github.com/1Panel-dev/1Panel/agent/cmd/server/nginx_conf"
|
||||
@@ -127,7 +128,6 @@ func (m McpServerService) Update(req request.McpServerUpdate) error {
|
||||
mcpServer.GatewayImage = req.GatewayImage
|
||||
mcpServer.ProtocolVersion = req.ProtocolVersion
|
||||
normalizeMcpServerGateway(mcpServer)
|
||||
go pullImage(mcpServer.GatewayImage)
|
||||
if req.OutputTransport == mcpOutputTransportSSE {
|
||||
mcpServer.SsePath = req.SsePath
|
||||
} else {
|
||||
@@ -150,7 +150,7 @@ func (m McpServerService) Update(req request.McpServerUpdate) error {
|
||||
if err := mcpServerRepo.Save(mcpServer); err != nil {
|
||||
return err
|
||||
}
|
||||
go startMcp(mcpServer)
|
||||
go runMcpServerTask(mcpServer, req.TaskID, task.TaskUpdate)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -193,7 +193,6 @@ func (m McpServerService) Create(create request.McpServerCreate) error {
|
||||
ProtocolVersion: create.ProtocolVersion,
|
||||
}
|
||||
normalizeMcpServerGateway(mcpServer)
|
||||
go pullImage(mcpServer.GatewayImage)
|
||||
if create.OutputTransport == mcpOutputTransportSSE {
|
||||
mcpServer.SsePath = create.SsePath
|
||||
} else {
|
||||
@@ -221,7 +220,7 @@ func (m McpServerService) Create(create request.McpServerCreate) error {
|
||||
return err
|
||||
}
|
||||
addProxy(mcpServer)
|
||||
go startMcp(mcpServer)
|
||||
go runMcpServerTask(mcpServer, create.TaskID, task.TaskCreate)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -896,25 +895,56 @@ func handleCreateParams(mcpServer *model.McpServer, environments []request.Envir
|
||||
return nil
|
||||
}
|
||||
|
||||
func startMcp(mcpServer *model.McpServer) {
|
||||
if err := refreshMcpServerFiles(mcpServer); err != nil {
|
||||
func runMcpServerTask(mcpServer *model.McpServer, taskID, operate string) {
|
||||
mcpTask, err := task.NewTaskWithOps(mcpServer.Name, operate, task.TaskScopeAI, taskID, mcpServer.ID)
|
||||
if err != nil {
|
||||
mcpServer.Status = constant.StatusError
|
||||
mcpServer.Message = err.Error()
|
||||
_ = mcpServerRepo.Save(mcpServer)
|
||||
return
|
||||
}
|
||||
mcpTask.AddSubTask(task.GetTaskName(mcpServer.Name, operate, task.TaskScopeAI), func(t *task.Task) error {
|
||||
return startMcpWithTask(mcpServer, t)
|
||||
}, nil)
|
||||
_ = mcpTask.Execute()
|
||||
}
|
||||
|
||||
func startMcp(mcpServer *model.McpServer) {
|
||||
_ = startMcpWithTask(mcpServer, nil)
|
||||
}
|
||||
|
||||
func startMcpWithTask(mcpServer *model.McpServer, taskItem *task.Task) error {
|
||||
if err := refreshMcpServerFiles(mcpServer); err != nil {
|
||||
mcpServer.Status = constant.StatusError
|
||||
mcpServer.Message = err.Error()
|
||||
_ = mcpServerRepo.Save(mcpServer)
|
||||
return err
|
||||
}
|
||||
composePath := path.Join(global.Dir.McpDir, mcpServer.Name, "docker-compose.yml")
|
||||
if mcpServer.Status != constant.StatusNormal {
|
||||
_, _ = compose.Down(composePath)
|
||||
}
|
||||
if out, err := compose.Up(composePath); err != nil {
|
||||
var err error
|
||||
var out string
|
||||
if taskItem != nil {
|
||||
err = compose.UpWithTask(composePath, taskItem, false)
|
||||
} else {
|
||||
out, err = compose.Up(composePath)
|
||||
}
|
||||
if err != nil {
|
||||
mcpServer.Status = constant.StatusError
|
||||
mcpServer.Message = out
|
||||
if out != "" {
|
||||
mcpServer.Message = out
|
||||
} else {
|
||||
mcpServer.Message = err.Error()
|
||||
}
|
||||
_ = mcpServerRepo.Save(mcpServer)
|
||||
return err
|
||||
} else {
|
||||
mcpServer.Status = constant.StatusRunning
|
||||
mcpServer.Message = ""
|
||||
}
|
||||
_ = syncMcpServerContainerStatus(mcpServer)
|
||||
return syncMcpServerContainerStatus(mcpServer)
|
||||
}
|
||||
|
||||
func syncMcpServerContainerStatus(mcpServer *model.McpServer) error {
|
||||
@@ -965,15 +995,3 @@ func GetWebsiteID() uint {
|
||||
websiteIDUint, _ := strconv.ParseUint(websiteID.Value, 10, 64)
|
||||
return uint(websiteIDUint)
|
||||
}
|
||||
|
||||
func pullImage(image string) {
|
||||
if global.CONF.Base.IsOffline {
|
||||
return
|
||||
}
|
||||
if image == "" {
|
||||
image = defaultMcpGatewayImageNpx
|
||||
}
|
||||
if err := docker.PullImage(image); err != nil {
|
||||
global.LOG.Errorf("docker pull mcp image error: %s", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,6 +182,7 @@ export namespace AI {
|
||||
type: string;
|
||||
gatewayImage: string;
|
||||
protocolVersion: string;
|
||||
taskID?: string;
|
||||
}
|
||||
|
||||
export interface McpServerSearch extends ReqPage {
|
||||
|
||||
@@ -88,11 +88,12 @@
|
||||
</ComplexTable>
|
||||
</template>
|
||||
</LayoutContent>
|
||||
<McpServerOperate ref="createRef" @close="searchWithTimeOut" />
|
||||
<McpServerOperate ref="createRef" @close="searchWithTimeOut" @task="openTaskLog" />
|
||||
<OpDialog ref="opRef" @search="search" />
|
||||
<ComposeLogs ref="composeLogRef" />
|
||||
<BindDomain ref="bindDomainRef" @close="searchWithTimeOut" />
|
||||
<Config ref="configRef" />
|
||||
<TaskLog ref="taskLogRef" width="70%" @close="search" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -111,6 +112,7 @@ import { onMounted, reactive, ref } from 'vue';
|
||||
import { dateFormat } from '@/utils/date';
|
||||
import McpServerOperate from './operate/index.vue';
|
||||
import ComposeLogs from '@/components/log/compose/index.vue';
|
||||
import TaskLog from '@/components/log/task/index.vue';
|
||||
import i18n from '@/lang';
|
||||
import { MsgError, MsgSuccess } from '@/utils/message';
|
||||
import BindDomain from './bind/index.vue';
|
||||
@@ -122,6 +124,7 @@ const loading = ref(false);
|
||||
const createRef = ref();
|
||||
const opRef = ref();
|
||||
const composeLogRef = ref();
|
||||
const taskLogRef = ref();
|
||||
const bindDomainRef = ref();
|
||||
const configRef = ref();
|
||||
const items = ref<AI.McpServer[]>([]);
|
||||
@@ -263,6 +266,10 @@ const openLog = (row: AI.McpServer) => {
|
||||
});
|
||||
};
|
||||
|
||||
const openTaskLog = (taskID: string) => {
|
||||
taskLogRef.value.openWithTaskID(taskID);
|
||||
};
|
||||
|
||||
const deleteServer = async (row: AI.McpServer) => {
|
||||
try {
|
||||
opRef.value.acceptParams({
|
||||
|
||||
@@ -141,6 +141,7 @@ import { AI } from '@/api/interface/ai';
|
||||
import { createMcpServer, getMcpDomain, updateMcpServer } from '@/api/modules/ai';
|
||||
import { Rules } from '@/global/form-rules';
|
||||
import i18n from '@/lang';
|
||||
import { newUUID } from '@/utils/id';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
import { FormInstance } from 'element-plus';
|
||||
import { ref, watch } from 'vue';
|
||||
@@ -158,7 +159,7 @@ const defaultGatewayImages: Record<string, string> = {
|
||||
npx: 'supercorp/supergateway:3.4.3',
|
||||
uvx: 'supercorp/supergateway:uvx',
|
||||
};
|
||||
const newMcpServer = () => {
|
||||
const newMcpServer = (): AI.McpServer => {
|
||||
return {
|
||||
id: 0,
|
||||
name: '',
|
||||
@@ -179,9 +180,10 @@ const newMcpServer = () => {
|
||||
type: 'npx',
|
||||
gatewayImage: defaultGatewayImages.npx,
|
||||
protocolVersion: defaultProtocolVersion,
|
||||
taskID: '',
|
||||
};
|
||||
};
|
||||
const em = defineEmits(['close']);
|
||||
const em = defineEmits(['close', 'task']);
|
||||
const mcpServer = ref(newMcpServer());
|
||||
const rules = ref({
|
||||
name: [Rules.requiredInput, Rules.appName],
|
||||
@@ -303,6 +305,8 @@ const submit = async (formEl: FormInstance | undefined) => {
|
||||
try {
|
||||
loading.value = true;
|
||||
normalizeGatewayConfig();
|
||||
const taskID = newUUID();
|
||||
mcpServer.value.taskID = taskID;
|
||||
mcpServer.value.baseUrl = mcpServer.value.protocol + mcpServer.value.url;
|
||||
if (mode.value == 'create') {
|
||||
await createMcpServer(mcpServer.value);
|
||||
@@ -311,6 +315,7 @@ const submit = async (formEl: FormInstance | undefined) => {
|
||||
await updateMcpServer(mcpServer.value);
|
||||
MsgSuccess(i18n.global.t('commons.msg.updateSuccess'));
|
||||
}
|
||||
em('task', taskID);
|
||||
handleClose();
|
||||
} finally {
|
||||
loading.value = false;
|
||||
|
||||
Reference in New Issue
Block a user