Skip to content

Commit 50c7b6a

Browse files
authored
chore: more polishing on MCP logs UX (#2535)
1 parent 623b4aa commit 50c7b6a

File tree

13 files changed

+207
-1180
lines changed

13 files changed

+207
-1180
lines changed

docs/openapi.json

Lines changed: 0 additions & 560 deletions
Large diffs are not rendered by default.

platform/backend/src/routes/mcp-server.ts

Lines changed: 27 additions & 161 deletions
Original file line numberDiff line numberDiff line change
@@ -910,48 +910,6 @@ const mcpServerRoutes: FastifyPluginAsyncZod = async (fastify) => {
910910
},
911911
);
912912

913-
fastify.post(
914-
"/api/mcp_server/:id/restart",
915-
{
916-
schema: {
917-
operationId: RouteId.RestartMcpServer,
918-
description: "Restart a single MCP server deployment",
919-
tags: ["MCP Server"],
920-
params: z.object({
921-
id: UuidIdSchema,
922-
}),
923-
response: constructResponseSchema(
924-
z.object({
925-
success: z.boolean(),
926-
message: z.string(),
927-
}),
928-
),
929-
},
930-
},
931-
async ({ params: { id } }, reply) => {
932-
try {
933-
await McpServerRuntimeManager.restartServer(id);
934-
return reply.send({
935-
success: true,
936-
message: `MCP server ${id} restarted successfully`,
937-
});
938-
} catch (error) {
939-
fastify.log.error(
940-
`Failed to restart MCP server ${id}: ${error instanceof Error ? error.message : "Unknown error"}`,
941-
);
942-
943-
if (error instanceof Error && error.message?.includes("not found")) {
944-
throw new ApiError(404, error.message);
945-
}
946-
947-
throw new ApiError(
948-
500,
949-
`Failed to restart MCP server: ${error instanceof Error ? error.message : "Unknown error"}`,
950-
);
951-
}
952-
},
953-
);
954-
955913
/**
956914
* Reinstall an MCP server without losing tool assignments and policies.
957915
*
@@ -1148,140 +1106,48 @@ const mcpServerRoutes: FastifyPluginAsyncZod = async (fastify) => {
11481106
});
11491107
}
11501108

1151-
// Refetch the server with potentially updated secretId
1109+
// Set status to "pending" immediately so UI shows progress bar
1110+
await McpServerModel.update(id, {
1111+
localInstallationStatus: "pending",
1112+
localInstallationError: null,
1113+
});
1114+
1115+
// Refetch the server with updated status
11521116
const updatedServer = await McpServerModel.findById(id);
11531117
if (!updatedServer) {
11541118
throw new ApiError(500, "Server not found after update");
11551119
}
11561120

1157-
// Perform the reinstall
1158-
try {
1159-
await autoReinstallServer(updatedServer, catalogItem);
1160-
logger.info(
1161-
{ serverId: id, serverName: mcpServer.name },
1162-
"MCP server reinstalled successfully",
1163-
);
1164-
} catch (error) {
1165-
logger.error(
1166-
{ err: error, serverId: id },
1167-
"Failed to reinstall MCP server",
1168-
);
1169-
throw new ApiError(
1170-
500,
1171-
`Failed to reinstall MCP server: ${error instanceof Error ? error.message : "Unknown error"}`,
1172-
);
1173-
}
1174-
1175-
// Return the updated server
1176-
const finalServer = await McpServerModel.findById(id);
1177-
if (!finalServer) {
1178-
throw new ApiError(500, "Server not found after reinstall");
1179-
}
1180-
return reply.send(finalServer);
1181-
},
1182-
);
1183-
1184-
fastify.post(
1185-
"/api/mcp_catalog/:catalogId/restart-all-installations",
1186-
{
1187-
schema: {
1188-
operationId: RouteId.RestartAllMcpServerInstallations,
1189-
description:
1190-
"Restart all MCP server installations for a given catalog item",
1191-
tags: ["MCP Server"],
1192-
params: z.object({
1193-
catalogId: UuidIdSchema,
1194-
}),
1195-
response: constructResponseSchema(
1196-
z.object({
1197-
success: z.boolean(),
1198-
message: z.string(),
1199-
results: z.array(
1200-
z.object({
1201-
serverId: z.string(),
1202-
serverName: z.string(),
1203-
success: z.boolean(),
1204-
error: z.string().optional(),
1205-
}),
1206-
),
1207-
summary: z.object({
1208-
total: z.number(),
1209-
succeeded: z.number(),
1210-
failed: z.number(),
1211-
}),
1212-
}),
1213-
),
1214-
},
1215-
},
1216-
async ({ params: { catalogId } }, reply) => {
1217-
// Verify the catalog item exists
1218-
const catalogItem = await InternalMcpCatalogModel.findById(catalogId);
1219-
if (!catalogItem) {
1220-
throw new ApiError(404, `Catalog item ${catalogId} not found`);
1221-
}
1222-
1223-
// Find all MCP server installations for this catalog item
1224-
const servers = await McpServerModel.findByCatalogId(catalogId);
1225-
1226-
if (servers.length === 0) {
1227-
return reply.send({
1228-
success: true,
1229-
message: "No installations found for this catalog item",
1230-
results: [],
1231-
summary: { total: 0, succeeded: 0, failed: 0 },
1232-
});
1233-
}
1234-
1235-
// Restart each server sequentially
1236-
const results: Array<{
1237-
serverId: string;
1238-
serverName: string;
1239-
success: boolean;
1240-
error?: string;
1241-
}> = [];
1242-
1243-
for (const server of servers) {
1121+
// Perform the reinstall asynchronously (don't block the response)
1122+
// Use setImmediate to fully detach from the request lifecycle
1123+
// This allows the frontend to show the progress bar immediately
1124+
setImmediate(async () => {
12441125
try {
1245-
await McpServerRuntimeManager.restartServer(server.id);
1246-
results.push({
1247-
serverId: server.id,
1248-
serverName: server.name,
1249-
success: true,
1126+
await autoReinstallServer(updatedServer, catalogItem);
1127+
// Set status to success when done
1128+
await McpServerModel.update(id, {
1129+
localInstallationStatus: "success",
12501130
});
12511131
logger.info(
1252-
`Restarted MCP server ${server.id} (${server.name}) as part of restart-all for catalog ${catalogId}`,
1132+
{ serverId: id, serverName: mcpServer.name },
1133+
"MCP server reinstalled successfully",
12531134
);
12541135
} catch (error) {
1255-
const errorMessage =
1256-
error instanceof Error ? error.message : "Unknown error";
1257-
results.push({
1258-
serverId: server.id,
1259-
serverName: server.name,
1260-
success: false,
1261-
error: errorMessage,
1136+
// Set status to error if reinstall fails
1137+
await McpServerModel.update(id, {
1138+
localInstallationStatus: "error",
1139+
localInstallationError:
1140+
error instanceof Error ? error.message : "Unknown error",
12621141
});
12631142
logger.error(
1264-
`Failed to restart MCP server ${server.id} (${server.name}): ${errorMessage}`,
1143+
{ err: error, serverId: id },
1144+
"Failed to reinstall MCP server",
12651145
);
12661146
}
1267-
}
1268-
1269-
const succeeded = results.filter((r) => r.success).length;
1270-
const failed = results.filter((r) => !r.success).length;
1271-
1272-
return reply.send({
1273-
success: failed === 0,
1274-
message:
1275-
failed === 0
1276-
? `Successfully restarted all ${succeeded} installation(s)`
1277-
: `Restarted ${succeeded} of ${servers.length} installation(s), ${failed} failed`,
1278-
results,
1279-
summary: {
1280-
total: servers.length,
1281-
succeeded,
1282-
failed,
1283-
},
12841147
});
1148+
1149+
// Return the server immediately with "pending" status
1150+
return reply.send(updatedServer);
12851151
},
12861152
);
12871153
};

platform/e2e-tests/tests/api/fixtures.ts

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ export interface TestFixtures {
3030
deleteMcpCatalogItem: typeof deleteMcpCatalogItem;
3131
installMcpServer: typeof installMcpServer;
3232
uninstallMcpServer: typeof uninstallMcpServer;
33-
restartMcpServer: typeof restartMcpServer;
3433
createRole: typeof createRole;
3534
deleteRole: typeof deleteRole;
3635
waitForAgentTool: typeof waitForAgentTool;
@@ -309,17 +308,6 @@ const uninstallMcpServer = async (
309308
urlSuffix: `/api/mcp_server/${serverId}`,
310309
});
311310

312-
/**
313-
* Restart an MCP server (local servers only)
314-
* (authnz is handled by the authenticated session)
315-
*/
316-
const restartMcpServer = async (request: APIRequestContext, serverId: string) =>
317-
makeApiRequest({
318-
request,
319-
method: "post",
320-
urlSuffix: `/api/mcp_server/${serverId}/restart`,
321-
});
322-
323311
/**
324312
* Create a custom role
325313
* (authnz is handled by the authenticated session)
@@ -821,9 +809,6 @@ export const test = base.extend<TestFixtures>({
821809
uninstallMcpServer: async ({}, use) => {
822810
await use(uninstallMcpServer);
823811
},
824-
restartMcpServer: async ({}, use) => {
825-
await use(restartMcpServer);
826-
},
827812
createRole: async ({}, use) => {
828813
await use(createRole);
829814
},

platform/e2e-tests/tests/api/orchestrator.spec.ts

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -231,37 +231,6 @@ test.describe("Orchestrator - MCP Server Installation and Execution", () => {
231231
);
232232
expect(testTool).toBeDefined();
233233
});
234-
235-
test("should restart local MCP server successfully", async ({
236-
request,
237-
makeApiRequest,
238-
restartMcpServer,
239-
}) => {
240-
// Get tools count before restart
241-
const toolsBefore = await getMcpServerTools(
242-
request,
243-
makeApiRequest,
244-
serverId,
245-
);
246-
const toolsCountBefore = toolsBefore.length;
247-
248-
// Restart the MCP server
249-
const restartResponse = await restartMcpServer(request, serverId);
250-
expect(restartResponse.status()).toBe(200);
251-
const restartResult = await restartResponse.json();
252-
expect(restartResult.success).toBe(true);
253-
254-
// Wait for the server to be ready after restart
255-
await waitForServerInstallation(request, serverId);
256-
257-
// Verify tools are still available after restart
258-
const toolsAfter = await getMcpServerTools(
259-
request,
260-
makeApiRequest,
261-
serverId,
262-
);
263-
expect(toolsAfter.length).toBe(toolsCountBefore);
264-
});
265234
});
266235

267236
test.describe("Local MCP Server - Docker Image", () => {

0 commit comments

Comments
 (0)