index.ts•8.73 kB
#!/usr/bin/env node
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { McpServerManager } from "./server-manager.js";
import {
CallToolParamsSchema,
FindToolsParamsSchema,
GetToolParamsSchema,
ListToolsInServerParamsSchema,
FindToolsInServerParamsSchema
} from "./types.js";
// Create MCP server manager instance (auto load enabled)
const serverManager = new McpServerManager({
autoLoad: true,
});
// Create MCP server
const server = new McpServer({
name: "MCP-Hub-Server",
version: "1.0.0",
description:
"Your central hub for ALL available tools. Use this server to discover and execute any tool you need. All system tools are accessible through here - search, find, and call them via this server.",
});
// Tool to return tools list from all servers
server.tool(
"list-all-tools",
"List ALL available tools from all connected servers. NOTE: For better performance, use find-tools with keywords first. Only use this when you need to see everything or if find-tools didn't find what you need",
{}, // Use empty object when there are no parameters
async (args, extra) => {
try {
const servers = serverManager.getConnectedServers();
if (servers.length === 0) {
return {
content: [
{
type: "text",
text: "No connected servers.",
},
],
};
}
const allTools: Record<string, any> = {};
// Get tools list from each server
for (const serverName of servers) {
try {
const toolsResponse = await serverManager.listTools(serverName);
// Filter to only include name and description
if (toolsResponse.tools && Array.isArray(toolsResponse.tools)) {
allTools[serverName] = {
tools: toolsResponse.tools.map((tool: any) => ({
name: tool.name,
description: tool.description,
}))
};
} else {
allTools[serverName] = toolsResponse;
}
} catch (error) {
allTools[serverName] = {
error: `Failed to get tools list: ${(error as Error).message}`,
};
}
}
return {
content: [
{
type: "text",
text: JSON.stringify(allTools, null, 2),
},
],
};
} catch (error) {
return {
content: [
{
type: "text",
text: `Failed to get tools list from all servers: ${
(error as Error).message
}`,
},
],
isError: true,
};
}
},
);
// Tool to call a specific tool from a specific server
server.tool(
"call-tool",
"Call a specific tool from a specific server. TIP: Use find-tools first to discover the tool and get the correct serverName and toolName",
{
serverName: CallToolParamsSchema.shape.serverName,
toolName: CallToolParamsSchema.shape.toolName,
toolArgs: CallToolParamsSchema.shape.toolArgs,
},
async (args, extra) => {
try {
const { serverName, toolName, toolArgs } = args;
const result = await serverManager.callTool(
serverName,
toolName,
toolArgs,
);
return {
content: [
{
type: "text",
text: JSON.stringify(result, null, 2),
},
],
};
} catch (error) {
return {
content: [
{
type: "text",
text: `Tool call failed: ${(error as Error).message}`,
},
],
isError: true,
};
}
},
);
// Tool to find tools matching a pattern across all servers
server.tool(
"find-tools",
`Use this tool to find best tools by searching with keywords or regex patterns.
If you don't have a specific tool for a task, this is the best way to discover what tools are available.
`,
{
pattern: FindToolsParamsSchema.shape.pattern,
searchIn: FindToolsParamsSchema.shape.searchIn,
caseSensitive: FindToolsParamsSchema.shape.caseSensitive,
},
async (args, extra) => {
try {
const { pattern, searchIn, caseSensitive } = args;
const results = await serverManager.findTools(pattern, {
searchIn,
caseSensitive,
});
return {
content: [
{
type: "text",
text: JSON.stringify(results, null, 2),
},
],
};
} catch (error) {
return {
content: [
{
type: "text",
text: `Failed to find tools: ${(error as Error).message}`,
},
],
isError: true,
};
}
},
);
// Tool to get detailed information about a specific tool
server.tool(
"get-tool",
"Get complete schema for a specific tool from a specific server, including inputSchema. TIP: Use find-tools first to discover the tool and get the correct serverName and toolName",
{
serverName: GetToolParamsSchema.shape.serverName,
toolName: GetToolParamsSchema.shape.toolName,
},
async (args, extra) => {
try {
const { serverName, toolName } = args;
const tool = await serverManager.getTool(serverName, toolName);
return {
content: [
{
type: "text",
text: JSON.stringify(tool, null, 2),
},
],
};
} catch (error) {
return {
content: [
{
type: "text",
text: `Error getting tool: ${(error as Error).message}`,
},
],
};
}
}
);
// Tool to list all tools from a specific server
server.tool(
"list-all-tools-in-server",
"List ALL tools from a specific MCP server (returns name and description only)",
{
serverName: ListToolsInServerParamsSchema.shape.serverName,
},
async (args, extra) => {
try {
const { serverName } = args;
const result = await serverManager.listToolsInServer(serverName);
return {
content: [
{
type: "text",
text: JSON.stringify(result, null, 2),
},
],
};
} catch (error) {
return {
content: [
{
type: "text",
text: `Error listing tools from server '${args.serverName}': ${(error as Error).message}`,
},
],
};
}
}
);
// Tool to find tools in a specific server
server.tool(
"find-tools-in-server",
"Find tools matching a pattern in a specific MCP server (returns name and description only)",
{
serverName: FindToolsInServerParamsSchema.shape.serverName,
pattern: FindToolsInServerParamsSchema.shape.pattern,
searchIn: FindToolsInServerParamsSchema.shape.searchIn,
caseSensitive: FindToolsInServerParamsSchema.shape.caseSensitive,
},
async (args, extra) => {
try {
const { serverName, pattern, searchIn, caseSensitive } = args;
const results = await serverManager.findToolsInServer(
serverName,
pattern,
searchIn,
caseSensitive
);
return {
content: [
{
type: "text",
text: JSON.stringify({ tools: results }, null, 2),
},
],
};
} catch (error) {
return {
content: [
{
type: "text",
text: `Error finding tools in server '${args.serverName}': ${(error as Error).message}`,
},
],
};
}
}
);
// Tool to list all connected servers
server.tool(
"list-servers",
"List all connected MCP servers",
{}, // No parameters needed
async (args, extra) => {
try {
const servers = serverManager.listServers();
return {
content: [
{
type: "text",
text: JSON.stringify({ servers }, null, 2),
},
],
};
} catch (error) {
return {
content: [
{
type: "text",
text: `Error listing servers: ${(error as Error).message}`,
},
],
};
}
}
);
// Start server
async function startServer() {
try {
// Communication through standard input/output
const transport = new StdioServerTransport();
await server.connect(transport);
// Disconnect all connections on process termination
process.on("SIGINT", async () => {
console.log("Shutting down server...");
await serverManager.disconnectAll();
process.exit(0);
});
} catch (error) {
console.error("Failed to start server:", error);
process.exit(1);
}
}
startServer();