Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions agent/app/dto/request/mcp_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
58 changes: 38 additions & 20 deletions agent/app/service/mcp_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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 {
Expand All @@ -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
}

Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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
}

Expand Down Expand Up @@ -896,25 +895,56 @@ func handleCreateParams(mcpServer *model.McpServer, environments []request.Envir
return 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
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 {
Expand Down Expand Up @@ -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())
}
}
1 change: 1 addition & 0 deletions frontend/src/api/interface/ai.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ export namespace AI {
type: string;
gatewayImage: string;
protocolVersion: string;
taskID?: string;
}

export interface McpServerSearch extends ReqPage {
Expand Down
9 changes: 8 additions & 1 deletion frontend/src/views/ai/mcp/server/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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>

Expand All @@ -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';
Expand All @@ -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[]>([]);
Expand Down Expand Up @@ -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({
Expand Down
9 changes: 7 additions & 2 deletions frontend/src/views/ai/mcp/server/operate/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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: '',
Expand All @@ -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],
Expand Down Expand Up @@ -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);
Expand All @@ -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;
Expand Down
Loading