[DEV] Tool _webmcp_server-info: estado del servidor MCP
Muestra version, commit git, host, puerto, canales activos, clientes conectados, registry (tools/prompts/resources), uptime y requests pendientes. Solo modo dev.
This commit is contained in:
@@ -10784,7 +10784,7 @@ var wrapper_default = import_websocket.default;
|
||||
// src/websocket-server.js
|
||||
import { createServer } from "http";
|
||||
import { parse as parse3 } from "url";
|
||||
import { fork } from "child_process";
|
||||
import { fork, execSync as execSync2 } from "child_process";
|
||||
|
||||
// node_modules/zod/v3/helpers/util.js
|
||||
var util;
|
||||
@@ -25197,6 +25197,31 @@ ${token}`
|
||||
return { content: [{ type: "text", text: `Error: ${e.message}` }], isError: true };
|
||||
}
|
||||
}
|
||||
if (request.params.name === "_webmcp_server-info") {
|
||||
if (!CONFIG.dev) {
|
||||
return { content: [{ type: "text", text: "server-info solo esta disponible en modo desarrollo (--dev)" }], isError: true };
|
||||
}
|
||||
if (!wsClient || wsClient.readyState !== wrapper_default.OPEN) {
|
||||
return { content: [{ type: "text", text: "No hay conexion al servidor WebSocket" }], isError: true };
|
||||
}
|
||||
const requestId2 = (requestIdCounter++).toString();
|
||||
const responsePromise2 = new Promise((resolve, reject) => {
|
||||
pendingRequests.set(requestId2, { resolve, reject });
|
||||
setTimeout(() => {
|
||||
if (pendingRequests.has(requestId2)) {
|
||||
pendingRequests.delete(requestId2);
|
||||
reject(new Error("Timeout obteniendo info del servidor"));
|
||||
}
|
||||
}, 1e4);
|
||||
});
|
||||
try {
|
||||
await sendMessage({ id: requestId2, type: "getServerInfo" });
|
||||
const result = await responsePromise2;
|
||||
return result;
|
||||
} catch (e) {
|
||||
return { content: [{ type: "text", text: `Error: ${e.message}` }], isError: true };
|
||||
}
|
||||
}
|
||||
if (!wsClient || wsClient.readyState !== wrapper_default.OPEN) {
|
||||
return {
|
||||
content: [{
|
||||
@@ -25288,6 +25313,14 @@ mcpServer.setRequestHandler(ListToolsRequestSchema, async () => {
|
||||
todas: { type: "boolean", description: "Si es true, quita todas las herramientas" }
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "_webmcp_server-info",
|
||||
description: "[DEV] Muestra estado del servidor @nucleoriofrio/webmcp: version, commit, host, puerto, canales activos, clientes, registry de tools/prompts/resources, uptime y requests pendientes.",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: {}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -25548,6 +25581,12 @@ function sendNotification(clientWs, channelPath, notificationType, data, mcpOnly
|
||||
var toolsRegistry = {};
|
||||
var promptsRegistry = {};
|
||||
var resourcesRegistry = {};
|
||||
var serverStartTime = Date.now();
|
||||
var gitCommit = "unknown";
|
||||
try {
|
||||
gitCommit = execSync2("git rev-parse --short HEAD", { stdio: ["pipe", "pipe", "ignore"] }).toString().trim();
|
||||
} catch (e) {
|
||||
}
|
||||
var requestIdCounter2 = 1;
|
||||
var pendingRequests2 = {};
|
||||
async function verifyClientToken(info, callback) {
|
||||
@@ -25738,6 +25777,9 @@ wss.on("connection", (ws, req) => {
|
||||
case "getClientInfo":
|
||||
handleGetClientInfo(ws, clientChannel, data);
|
||||
break;
|
||||
case "getServerInfo":
|
||||
handleGetServerInfo(ws, data);
|
||||
break;
|
||||
case "clearRegistry":
|
||||
handleClearRegistry(ws, data);
|
||||
break;
|
||||
@@ -26123,6 +26165,45 @@ function handleGetClientInfo(ws, callerChannel, data) {
|
||||
result: { content: [{ type: "text", text }] }
|
||||
}));
|
||||
}
|
||||
function handleGetServerInfo(ws, data) {
|
||||
const { id } = data;
|
||||
const uptimeMs = Date.now() - serverStartTime;
|
||||
const uptimeSec = Math.floor(uptimeMs / 1e3);
|
||||
const hours = Math.floor(uptimeSec / 3600);
|
||||
const minutes = Math.floor(uptimeSec % 3600 / 60);
|
||||
const seconds = uptimeSec % 60;
|
||||
const channelsList = {};
|
||||
for (const [channelPath, channelClients] of Object.entries(channels)) {
|
||||
channelsList[channelPath] = channelClients.size;
|
||||
}
|
||||
const info = {
|
||||
server: `@nucleoriofrio/webmcp v0.2.0`,
|
||||
commit: gitCommit,
|
||||
host: HOST,
|
||||
port: CONFIG.port,
|
||||
dev: !!CONFIG.dev,
|
||||
uptime: `${hours}h ${minutes}m ${seconds}s`,
|
||||
uptimeMs,
|
||||
channels: channelsList,
|
||||
totalClients: Object.values(channels).reduce((sum, ch) => sum + ch.size, 0),
|
||||
registry: {
|
||||
tools: Object.keys(toolsRegistry).length,
|
||||
prompts: Object.keys(promptsRegistry).length,
|
||||
resources: Object.keys(resourcesRegistry).length
|
||||
},
|
||||
toolsList: Object.entries(toolsRegistry).map(([id2, info2]) => ({
|
||||
id: id2,
|
||||
name: info2.originalName,
|
||||
channel: info2.channel
|
||||
})),
|
||||
pendingRequests: Object.keys(pendingRequests2).length
|
||||
};
|
||||
ws.send(JSON.stringify({
|
||||
id,
|
||||
type: "toolResponse",
|
||||
result: { content: [{ type: "text", text: JSON.stringify(info, null, 2) }] }
|
||||
}));
|
||||
}
|
||||
function handleClearRegistry(ws, data) {
|
||||
const { id } = data;
|
||||
let toolCount = Object.keys(toolsRegistry).length;
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -407,6 +407,34 @@ mcpServer.setRequestHandler(CallToolRequestSchema, async (request) => {
|
||||
}
|
||||
}
|
||||
|
||||
if (request.params.name === "_webmcp_server-info") {
|
||||
if (!CONFIG.dev) {
|
||||
return { content: [{ type: "text", text: "server-info solo esta disponible en modo desarrollo (--dev)" }], isError: true };
|
||||
}
|
||||
if (!wsClient || wsClient.readyState !== WebSocket.OPEN) {
|
||||
return { content: [{ type: "text", text: "No hay conexion al servidor WebSocket" }], isError: true };
|
||||
}
|
||||
|
||||
const requestId = (requestIdCounter++).toString();
|
||||
const responsePromise = new Promise((resolve, reject) => {
|
||||
pendingRequests.set(requestId, { resolve, reject });
|
||||
setTimeout(() => {
|
||||
if (pendingRequests.has(requestId)) {
|
||||
pendingRequests.delete(requestId);
|
||||
reject(new Error('Timeout obteniendo info del servidor'));
|
||||
}
|
||||
}, 10000);
|
||||
});
|
||||
|
||||
try {
|
||||
await sendMessage({ id: requestId, type: 'getServerInfo' });
|
||||
const result = await responsePromise;
|
||||
return result;
|
||||
} catch (e) {
|
||||
return { content: [{ type: "text", text: `Error: ${e.message}` }], isError: true };
|
||||
}
|
||||
}
|
||||
|
||||
if (!wsClient || wsClient.readyState !== WebSocket.OPEN) {
|
||||
return {
|
||||
content: [{
|
||||
@@ -513,6 +541,14 @@ mcpServer.setRequestHandler(ListToolsRequestSchema, async () => {
|
||||
todas: { type: "boolean", description: "Si es true, quita todas las herramientas" }
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "_webmcp_server-info",
|
||||
description: "[DEV] Muestra estado del servidor @nucleoriofrio/webmcp: version, commit, host, puerto, canales activos, clientes, registry de tools/prompts/resources, uptime y requests pendientes.",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: {},
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import * as fs from 'fs/promises';
|
||||
import {WebSocketServer, WebSocket} from 'ws';
|
||||
import {createServer} from 'http';
|
||||
import {parse} from 'url';
|
||||
import {fork} from 'child_process';
|
||||
import {fork, execSync} from 'child_process';
|
||||
import {runMcpServer} from './server.js';
|
||||
import {
|
||||
clearTokens,
|
||||
@@ -97,6 +97,17 @@ const toolsRegistry = {};
|
||||
const promptsRegistry = {};
|
||||
const resourcesRegistry = {};
|
||||
|
||||
// Server start timestamp for uptime calculation
|
||||
const serverStartTime = Date.now();
|
||||
|
||||
// Git commit hash (read once at startup)
|
||||
let gitCommit = 'unknown';
|
||||
try {
|
||||
gitCommit = execSync('git rev-parse --short HEAD', { stdio: ['pipe', 'pipe', 'ignore'] }).toString().trim();
|
||||
} catch (e) {
|
||||
// Not in a git repo or git not available
|
||||
}
|
||||
|
||||
// Request counter for unique IDs
|
||||
let requestIdCounter = 1;
|
||||
|
||||
@@ -371,6 +382,10 @@ wss.on('connection', (ws, req) => {
|
||||
handleGetClientInfo(ws, clientChannel, data);
|
||||
break;
|
||||
|
||||
case 'getServerInfo':
|
||||
handleGetServerInfo(ws, data);
|
||||
break;
|
||||
|
||||
case 'clearRegistry':
|
||||
handleClearRegistry(ws, data);
|
||||
break;
|
||||
@@ -875,6 +890,51 @@ function handleGetClientInfo(ws, callerChannel, data) {
|
||||
}));
|
||||
}
|
||||
|
||||
// Handle getServerInfo request - return server status and stats
|
||||
function handleGetServerInfo(ws, data) {
|
||||
const { id } = data;
|
||||
|
||||
const uptimeMs = Date.now() - serverStartTime;
|
||||
const uptimeSec = Math.floor(uptimeMs / 1000);
|
||||
const hours = Math.floor(uptimeSec / 3600);
|
||||
const minutes = Math.floor((uptimeSec % 3600) / 60);
|
||||
const seconds = uptimeSec % 60;
|
||||
|
||||
const channelsList = {};
|
||||
for (const [channelPath, channelClients] of Object.entries(channels)) {
|
||||
channelsList[channelPath] = channelClients.size;
|
||||
}
|
||||
|
||||
const info = {
|
||||
server: `@nucleoriofrio/webmcp v0.2.0`,
|
||||
commit: gitCommit,
|
||||
host: HOST,
|
||||
port: CONFIG.port,
|
||||
dev: !!CONFIG.dev,
|
||||
uptime: `${hours}h ${minutes}m ${seconds}s`,
|
||||
uptimeMs,
|
||||
channels: channelsList,
|
||||
totalClients: Object.values(channels).reduce((sum, ch) => sum + ch.size, 0),
|
||||
registry: {
|
||||
tools: Object.keys(toolsRegistry).length,
|
||||
prompts: Object.keys(promptsRegistry).length,
|
||||
resources: Object.keys(resourcesRegistry).length,
|
||||
},
|
||||
toolsList: Object.entries(toolsRegistry).map(([id, info]) => ({
|
||||
id,
|
||||
name: info.originalName,
|
||||
channel: info.channel,
|
||||
})),
|
||||
pendingRequests: Object.keys(pendingRequests).length,
|
||||
};
|
||||
|
||||
ws.send(JSON.stringify({
|
||||
id,
|
||||
type: 'toolResponse',
|
||||
result: { content: [{ type: 'text', text: JSON.stringify(info, null, 2) }] }
|
||||
}));
|
||||
}
|
||||
|
||||
// Handle clearing all registries
|
||||
function handleClearRegistry(ws, data) {
|
||||
const {id} = data;
|
||||
|
||||
Reference in New Issue
Block a user