mirror of
https://github.com/samanhappy/mcphub.git
synced 2025-12-24 02:39:19 -05:00
feat: integrate offcial mcp server registry (#374)
This commit is contained in:
169
src/controllers/registryController.ts
Normal file
169
src/controllers/registryController.ts
Normal file
@@ -0,0 +1,169 @@
|
||||
import { Request, Response } from 'express';
|
||||
import { ApiResponse } from '../types/index.js';
|
||||
|
||||
const REGISTRY_BASE_URL = 'https://registry.modelcontextprotocol.io/v0.1';
|
||||
|
||||
/**
|
||||
* Get all MCP servers from the official registry
|
||||
* Proxies the request to avoid CORS issues in the frontend
|
||||
* Supports cursor-based pagination
|
||||
*/
|
||||
export const getAllRegistryServers = async (req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const { cursor, limit, search } = req.query;
|
||||
|
||||
// Build URL with query parameters
|
||||
const url = new URL(`${REGISTRY_BASE_URL}/servers`);
|
||||
if (cursor && typeof cursor === 'string') {
|
||||
url.searchParams.append('cursor', cursor);
|
||||
}
|
||||
if (limit && typeof limit === 'string') {
|
||||
const limitNum = parseInt(limit, 10);
|
||||
if (!isNaN(limitNum) && limitNum > 0) {
|
||||
url.searchParams.append('limit', limit);
|
||||
}
|
||||
}
|
||||
if (search && typeof search === 'string') {
|
||||
url.searchParams.append('search', search);
|
||||
}
|
||||
|
||||
const response = await fetch(url.toString(), {
|
||||
headers: {
|
||||
Accept: 'application/json, application/problem+json',
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
const apiResponse: ApiResponse<typeof data> = {
|
||||
success: true,
|
||||
data: data,
|
||||
};
|
||||
|
||||
res.json(apiResponse);
|
||||
} catch (error) {
|
||||
console.error('Error fetching registry servers:', error);
|
||||
const errorMessage =
|
||||
error instanceof Error ? error.message : 'Failed to fetch registry servers';
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: errorMessage,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get all versions of a specific MCP server
|
||||
* Proxies the request to avoid CORS issues in the frontend
|
||||
*/
|
||||
export const getRegistryServerVersions = async (req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const { serverName } = req.params;
|
||||
|
||||
if (!serverName) {
|
||||
res.status(400).json({
|
||||
success: false,
|
||||
message: 'Server name is required',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// URL encode the server name
|
||||
const encodedName = encodeURIComponent(serverName);
|
||||
const response = await fetch(`${REGISTRY_BASE_URL}/servers/${encodedName}/versions`, {
|
||||
headers: {
|
||||
Accept: 'application/json, application/problem+json',
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
if (response.status === 404) {
|
||||
res.status(404).json({
|
||||
success: false,
|
||||
message: 'Server not found',
|
||||
});
|
||||
return;
|
||||
}
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
const apiResponse: ApiResponse<typeof data> = {
|
||||
success: true,
|
||||
data: data,
|
||||
};
|
||||
|
||||
res.json(apiResponse);
|
||||
} catch (error) {
|
||||
console.error('Error fetching registry server versions:', error);
|
||||
const errorMessage =
|
||||
error instanceof Error ? error.message : 'Failed to fetch registry server versions';
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: errorMessage,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a specific version of an MCP server
|
||||
* Proxies the request to avoid CORS issues in the frontend
|
||||
*/
|
||||
export const getRegistryServerVersion = async (req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const { serverName, version } = req.params;
|
||||
|
||||
if (!serverName || !version) {
|
||||
res.status(400).json({
|
||||
success: false,
|
||||
message: 'Server name and version are required',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// URL encode the server name and version
|
||||
const encodedName = encodeURIComponent(serverName);
|
||||
const encodedVersion = encodeURIComponent(version);
|
||||
const response = await fetch(
|
||||
`${REGISTRY_BASE_URL}/servers/${encodedName}/versions/${encodedVersion}`,
|
||||
{
|
||||
headers: {
|
||||
Accept: 'application/json, application/problem+json',
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
if (response.status === 404) {
|
||||
res.status(404).json({
|
||||
success: false,
|
||||
message: 'Server version not found',
|
||||
});
|
||||
return;
|
||||
}
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
const apiResponse: ApiResponse<typeof data> = {
|
||||
success: true,
|
||||
data: data,
|
||||
};
|
||||
|
||||
res.json(apiResponse);
|
||||
} catch (error) {
|
||||
console.error('Error fetching registry server version:', error);
|
||||
const errorMessage =
|
||||
error instanceof Error ? error.message : 'Failed to fetch registry server version';
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: errorMessage,
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -56,9 +56,18 @@ import {
|
||||
getCloudServerToolsList,
|
||||
callCloudTool,
|
||||
} from '../controllers/cloudController.js';
|
||||
import {
|
||||
getAllRegistryServers,
|
||||
getRegistryServerVersions,
|
||||
getRegistryServerVersion,
|
||||
} from '../controllers/registryController.js';
|
||||
import { login, register, getCurrentUser, changePassword } from '../controllers/authController.js';
|
||||
import { getAllLogs, clearLogs, streamLogs } from '../controllers/logController.js';
|
||||
import { getRuntimeConfig, getPublicConfig, getMcpSettingsJson } from '../controllers/configController.js';
|
||||
import {
|
||||
getRuntimeConfig,
|
||||
getPublicConfig,
|
||||
getMcpSettingsJson,
|
||||
} from '../controllers/configController.js';
|
||||
import { callTool } from '../controllers/toolController.js';
|
||||
import { getPrompt } from '../controllers/promptController.js';
|
||||
import { uploadDxtFile, uploadMiddleware } from '../controllers/dxtController.js';
|
||||
@@ -144,6 +153,11 @@ export const initRoutes = (app: express.Application): void => {
|
||||
router.get('/cloud/servers/:serverName/tools', getCloudServerToolsList);
|
||||
router.post('/cloud/servers/:serverName/tools/:toolName/call', callCloudTool);
|
||||
|
||||
// Registry routes (proxy to official MCP registry)
|
||||
router.get('/registry/servers', getAllRegistryServers);
|
||||
router.get('/registry/servers/:serverName/versions', getRegistryServerVersions);
|
||||
router.get('/registry/servers/:serverName/versions/:version', getRegistryServerVersion);
|
||||
|
||||
// Log routes
|
||||
router.get('/logs', getAllLogs);
|
||||
router.delete('/logs', clearLogs);
|
||||
|
||||
Reference in New Issue
Block a user