mirror of
https://github.com/samanhappy/mcphub.git
synced 2025-12-24 02:39:19 -05:00
feat: introduce cloud server market (#260)
This commit is contained in:
273
src/controllers/cloudController.ts
Normal file
273
src/controllers/cloudController.ts
Normal file
@@ -0,0 +1,273 @@
|
||||
import { Request, Response } from 'express';
|
||||
import { ApiResponse, CloudServer, CloudTool } from '../types/index.js';
|
||||
import {
|
||||
getCloudServers,
|
||||
getCloudServerByName,
|
||||
getCloudServerTools,
|
||||
callCloudServerTool,
|
||||
getCloudCategories,
|
||||
getCloudTags,
|
||||
searchCloudServers,
|
||||
filterCloudServersByCategory,
|
||||
filterCloudServersByTag,
|
||||
} from '../services/cloudService.js';
|
||||
|
||||
// Get all cloud market servers
|
||||
export const getAllCloudServers = async (_: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const cloudServers = await getCloudServers();
|
||||
const response: ApiResponse<CloudServer[]> = {
|
||||
success: true,
|
||||
data: cloudServers,
|
||||
};
|
||||
res.json(response);
|
||||
} catch (error) {
|
||||
console.error('Error getting cloud market servers:', error);
|
||||
const errorMessage =
|
||||
error instanceof Error ? error.message : 'Failed to get cloud market servers';
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: errorMessage,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Get a specific cloud market server by name
|
||||
export const getCloudServer = async (req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const { name } = req.params;
|
||||
if (!name) {
|
||||
res.status(400).json({
|
||||
success: false,
|
||||
message: 'Server name is required',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const server = await getCloudServerByName(name);
|
||||
if (!server) {
|
||||
res.status(404).json({
|
||||
success: false,
|
||||
message: 'Cloud server not found',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Fetch tools for this server
|
||||
try {
|
||||
const tools = await getCloudServerTools(server.server_key);
|
||||
server.tools = tools;
|
||||
} catch (toolError) {
|
||||
console.warn(`Failed to fetch tools for server ${server.name}:`, toolError);
|
||||
// Continue without tools
|
||||
}
|
||||
|
||||
const response: ApiResponse<CloudServer> = {
|
||||
success: true,
|
||||
data: server,
|
||||
};
|
||||
res.json(response);
|
||||
} catch (error) {
|
||||
console.error('Error getting cloud market server:', error);
|
||||
const errorMessage =
|
||||
error instanceof Error ? error.message : 'Failed to get cloud market server';
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: errorMessage,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Get all cloud market categories
|
||||
export const getAllCloudCategories = async (_: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const categories = await getCloudCategories();
|
||||
const response: ApiResponse<string[]> = {
|
||||
success: true,
|
||||
data: categories,
|
||||
};
|
||||
res.json(response);
|
||||
} catch (error) {
|
||||
console.error('Error getting cloud market categories:', error);
|
||||
const errorMessage =
|
||||
error instanceof Error ? error.message : 'Failed to get cloud market categories';
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: errorMessage,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Get all cloud market tags
|
||||
export const getAllCloudTags = async (_: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const tags = await getCloudTags();
|
||||
const response: ApiResponse<string[]> = {
|
||||
success: true,
|
||||
data: tags,
|
||||
};
|
||||
res.json(response);
|
||||
} catch (error) {
|
||||
console.error('Error getting cloud market tags:', error);
|
||||
const errorMessage = error instanceof Error ? error.message : 'Failed to get cloud market tags';
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: errorMessage,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Search cloud market servers
|
||||
export const searchCloudServersByQuery = async (req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const query = req.query.query as string;
|
||||
if (!query || query.trim() === '') {
|
||||
res.status(400).json({
|
||||
success: false,
|
||||
message: 'Search query is required',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const servers = await searchCloudServers(query);
|
||||
const response: ApiResponse<CloudServer[]> = {
|
||||
success: true,
|
||||
data: servers,
|
||||
};
|
||||
res.json(response);
|
||||
} catch (error) {
|
||||
console.error('Error searching cloud market servers:', error);
|
||||
const errorMessage =
|
||||
error instanceof Error ? error.message : 'Failed to search cloud market servers';
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: errorMessage,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Get cloud market servers by category
|
||||
export const getCloudServersByCategory = async (req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const { category } = req.params;
|
||||
if (!category) {
|
||||
res.status(400).json({
|
||||
success: false,
|
||||
message: 'Category is required',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const servers = await filterCloudServersByCategory(category);
|
||||
const response: ApiResponse<CloudServer[]> = {
|
||||
success: true,
|
||||
data: servers,
|
||||
};
|
||||
res.json(response);
|
||||
} catch (error) {
|
||||
console.error('Error getting cloud market servers by category:', error);
|
||||
const errorMessage =
|
||||
error instanceof Error ? error.message : 'Failed to get cloud market servers by category';
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: errorMessage,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Get cloud market servers by tag
|
||||
export const getCloudServersByTag = async (req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const { tag } = req.params;
|
||||
if (!tag) {
|
||||
res.status(400).json({
|
||||
success: false,
|
||||
message: 'Tag is required',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const servers = await filterCloudServersByTag(tag);
|
||||
const response: ApiResponse<CloudServer[]> = {
|
||||
success: true,
|
||||
data: servers,
|
||||
};
|
||||
res.json(response);
|
||||
} catch (error) {
|
||||
console.error('Error getting cloud market servers by tag:', error);
|
||||
const errorMessage =
|
||||
error instanceof Error ? error.message : 'Failed to get cloud market servers by tag';
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: errorMessage,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Get tools for a specific cloud server
|
||||
export const getCloudServerToolsList = 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;
|
||||
}
|
||||
|
||||
const tools = await getCloudServerTools(serverName);
|
||||
const response: ApiResponse<CloudTool[]> = {
|
||||
success: true,
|
||||
data: tools,
|
||||
};
|
||||
res.json(response);
|
||||
} catch (error) {
|
||||
console.error('Error getting cloud server tools:', error);
|
||||
const errorMessage =
|
||||
error instanceof Error ? error.message : 'Failed to get cloud server tools';
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: errorMessage,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Call a tool on a cloud server
|
||||
export const callCloudTool = async (req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const { serverName, toolName } = req.params;
|
||||
const { arguments: args } = req.body;
|
||||
|
||||
if (!serverName) {
|
||||
res.status(400).json({
|
||||
success: false,
|
||||
message: 'Server name is required',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!toolName) {
|
||||
res.status(400).json({
|
||||
success: false,
|
||||
message: 'Tool name is required',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const result = await callCloudServerTool(serverName, toolName, args || {});
|
||||
const response: ApiResponse = {
|
||||
success: true,
|
||||
data: result,
|
||||
};
|
||||
res.json(response);
|
||||
} catch (error) {
|
||||
console.error('Error calling cloud server tool:', error);
|
||||
const errorMessage =
|
||||
error instanceof Error ? error.message : 'Failed to call cloud server tool';
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: errorMessage,
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -505,7 +505,7 @@ export const updateToolDescription = async (req: Request, res: Response): Promis
|
||||
|
||||
export const updateSystemConfig = (req: Request, res: Response): void => {
|
||||
try {
|
||||
const { routing, install, smartRouting } = req.body;
|
||||
const { routing, install, smartRouting, mcpRouter } = req.body;
|
||||
const currentUser = (req as any).user;
|
||||
|
||||
if (
|
||||
@@ -524,7 +524,12 @@ export const updateSystemConfig = (req: Request, res: Response): void => {
|
||||
typeof smartRouting.dbUrl !== 'string' &&
|
||||
typeof smartRouting.openaiApiBaseUrl !== 'string' &&
|
||||
typeof smartRouting.openaiApiKey !== 'string' &&
|
||||
typeof smartRouting.openaiApiEmbeddingModel !== 'string'))
|
||||
typeof smartRouting.openaiApiEmbeddingModel !== 'string')) &&
|
||||
(!mcpRouter ||
|
||||
(typeof mcpRouter.apiKey !== 'string' &&
|
||||
typeof mcpRouter.referer !== 'string' &&
|
||||
typeof mcpRouter.title !== 'string' &&
|
||||
typeof mcpRouter.baseUrl !== 'string'))
|
||||
) {
|
||||
res.status(400).json({
|
||||
success: false,
|
||||
@@ -555,6 +560,12 @@ export const updateSystemConfig = (req: Request, res: Response): void => {
|
||||
openaiApiKey: '',
|
||||
openaiApiEmbeddingModel: '',
|
||||
},
|
||||
mcpRouter: {
|
||||
apiKey: '',
|
||||
referer: 'https://mcphub.app',
|
||||
title: 'MCPHub',
|
||||
baseUrl: 'https://api.mcprouter.to/v1',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -586,6 +597,15 @@ export const updateSystemConfig = (req: Request, res: Response): void => {
|
||||
};
|
||||
}
|
||||
|
||||
if (!settings.systemConfig.mcpRouter) {
|
||||
settings.systemConfig.mcpRouter = {
|
||||
apiKey: '',
|
||||
referer: 'https://mcphub.app',
|
||||
title: 'MCPHub',
|
||||
baseUrl: 'https://api.mcprouter.to/v1',
|
||||
};
|
||||
}
|
||||
|
||||
if (routing) {
|
||||
if (typeof routing.enableGlobalRoute === 'boolean') {
|
||||
settings.systemConfig.routing.enableGlobalRoute = routing.enableGlobalRoute;
|
||||
@@ -676,6 +696,21 @@ export const updateSystemConfig = (req: Request, res: Response): void => {
|
||||
needsSync = (!wasSmartRoutingEnabled && isNowEnabled) || (isNowEnabled && hasConfigChanged);
|
||||
}
|
||||
|
||||
if (mcpRouter) {
|
||||
if (typeof mcpRouter.apiKey === 'string') {
|
||||
settings.systemConfig.mcpRouter.apiKey = mcpRouter.apiKey;
|
||||
}
|
||||
if (typeof mcpRouter.referer === 'string') {
|
||||
settings.systemConfig.mcpRouter.referer = mcpRouter.referer;
|
||||
}
|
||||
if (typeof mcpRouter.title === 'string') {
|
||||
settings.systemConfig.mcpRouter.title = mcpRouter.title;
|
||||
}
|
||||
if (typeof mcpRouter.baseUrl === 'string') {
|
||||
settings.systemConfig.mcpRouter.baseUrl = mcpRouter.baseUrl;
|
||||
}
|
||||
}
|
||||
|
||||
if (saveSettings(settings, currentUser)) {
|
||||
res.json({
|
||||
success: true,
|
||||
|
||||
@@ -43,6 +43,17 @@ import {
|
||||
getMarketServersByCategory,
|
||||
getMarketServersByTag,
|
||||
} from '../controllers/marketController.js';
|
||||
import {
|
||||
getAllCloudServers,
|
||||
getCloudServer,
|
||||
getAllCloudCategories,
|
||||
getAllCloudTags,
|
||||
searchCloudServersByQuery,
|
||||
getCloudServersByCategory,
|
||||
getCloudServersByTag,
|
||||
getCloudServerToolsList,
|
||||
callCloudTool,
|
||||
} from '../controllers/cloudController.js';
|
||||
import { login, register, getCurrentUser, changePassword } from '../controllers/authController.js';
|
||||
import { getAllLogs, clearLogs, streamLogs } from '../controllers/logController.js';
|
||||
import { getRuntimeConfig, getPublicConfig } from '../controllers/configController.js';
|
||||
@@ -103,6 +114,17 @@ export const initRoutes = (app: express.Application): void => {
|
||||
router.get('/market/tags', getAllMarketTags);
|
||||
router.get('/market/tags/:tag', getMarketServersByTag);
|
||||
|
||||
// Cloud Market routes
|
||||
router.get('/cloud/servers', getAllCloudServers);
|
||||
router.get('/cloud/servers/search', searchCloudServersByQuery);
|
||||
router.get('/cloud/servers/:name', getCloudServer);
|
||||
router.get('/cloud/categories', getAllCloudCategories);
|
||||
router.get('/cloud/categories/:category', getCloudServersByCategory);
|
||||
router.get('/cloud/tags', getAllCloudTags);
|
||||
router.get('/cloud/tags/:tag', getCloudServersByTag);
|
||||
router.get('/cloud/servers/:serverName/tools', getCloudServerToolsList);
|
||||
router.post('/cloud/servers/:serverName/tools/:toolName/call', callCloudTool);
|
||||
|
||||
// Log routes
|
||||
router.get('/logs', getAllLogs);
|
||||
router.delete('/logs', clearLogs);
|
||||
|
||||
273
src/services/cloudService.ts
Normal file
273
src/services/cloudService.ts
Normal file
@@ -0,0 +1,273 @@
|
||||
import axios, { AxiosRequestConfig } from 'axios';
|
||||
import {
|
||||
CloudServer,
|
||||
CloudTool,
|
||||
MCPRouterResponse,
|
||||
MCPRouterListServersResponse,
|
||||
MCPRouterListToolsResponse,
|
||||
MCPRouterCallToolResponse,
|
||||
} from '../types/index.js';
|
||||
import { loadOriginalSettings } from '../config/index.js';
|
||||
|
||||
// MCPRouter API default base URL
|
||||
const DEFAULT_MCPROUTER_API_BASE = 'https://api.mcprouter.to/v1';
|
||||
|
||||
// Get MCPRouter API config from system configuration
|
||||
const getMCPRouterConfig = () => {
|
||||
const settings = loadOriginalSettings();
|
||||
const mcpRouterConfig = settings.systemConfig?.mcpRouter;
|
||||
|
||||
return {
|
||||
apiKey: mcpRouterConfig?.apiKey || process.env.MCPROUTER_API_KEY || '',
|
||||
referer: mcpRouterConfig?.referer || process.env.MCPROUTER_REFERER || 'https://mcphub.app',
|
||||
title: mcpRouterConfig?.title || process.env.MCPROUTER_TITLE || 'MCPHub',
|
||||
baseUrl:
|
||||
mcpRouterConfig?.baseUrl || process.env.MCPROUTER_API_BASE || DEFAULT_MCPROUTER_API_BASE,
|
||||
};
|
||||
};
|
||||
|
||||
// Get axios config with MCPRouter headers
|
||||
const getAxiosConfig = (): AxiosRequestConfig => {
|
||||
const mcpRouterConfig = getMCPRouterConfig();
|
||||
|
||||
return {
|
||||
headers: {
|
||||
Authorization: mcpRouterConfig.apiKey ? `Bearer ${mcpRouterConfig.apiKey}` : '',
|
||||
'HTTP-Referer': mcpRouterConfig.referer || 'https://mcphub.app',
|
||||
'X-Title': mcpRouterConfig.title || 'MCPHub',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
// List all available cloud servers
|
||||
export const getCloudServers = async (): Promise<CloudServer[]> => {
|
||||
try {
|
||||
const axiosConfig = getAxiosConfig();
|
||||
const mcpRouterConfig = getMCPRouterConfig();
|
||||
|
||||
const response = await axios.post<MCPRouterResponse<MCPRouterListServersResponse>>(
|
||||
`${mcpRouterConfig.baseUrl}/list-servers`,
|
||||
{},
|
||||
axiosConfig,
|
||||
);
|
||||
|
||||
const data = response.data;
|
||||
|
||||
if (data.code !== 0) {
|
||||
throw new Error(data.message || 'Failed to fetch servers');
|
||||
}
|
||||
|
||||
return data.data.servers || [];
|
||||
} catch (error) {
|
||||
console.error('Error fetching cloud market servers:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
// Get a specific cloud server by name
|
||||
export const getCloudServerByName = async (name: string): Promise<CloudServer | null> => {
|
||||
try {
|
||||
const servers = await getCloudServers();
|
||||
return servers.find((server) => server.name === name || server.config_name === name) || null;
|
||||
} catch (error) {
|
||||
console.error(`Error fetching cloud server ${name}:`, error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
// List tools for a specific cloud server
|
||||
export const getCloudServerTools = async (serverKey: string): Promise<CloudTool[]> => {
|
||||
try {
|
||||
const axiosConfig = getAxiosConfig();
|
||||
const mcpRouterConfig = getMCPRouterConfig();
|
||||
|
||||
if (
|
||||
!axiosConfig.headers?.['Authorization'] ||
|
||||
axiosConfig.headers['Authorization'] === 'Bearer '
|
||||
) {
|
||||
throw new Error('MCPROUTER_API_KEY_NOT_CONFIGURED');
|
||||
}
|
||||
|
||||
const response = await axios.post<MCPRouterResponse<MCPRouterListToolsResponse>>(
|
||||
`${mcpRouterConfig.baseUrl}/list-tools`,
|
||||
{
|
||||
server: serverKey,
|
||||
},
|
||||
axiosConfig,
|
||||
);
|
||||
|
||||
const data = response.data;
|
||||
if (data.code !== 0) {
|
||||
throw new Error(data.message || 'Failed to fetch tools');
|
||||
}
|
||||
|
||||
return data.data.tools || [];
|
||||
} catch (error) {
|
||||
console.error(`Error fetching tools for server ${serverKey}:`, error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
// Call a tool on a cloud server
|
||||
export const callCloudServerTool = async (
|
||||
serverName: string,
|
||||
toolName: string,
|
||||
args: Record<string, any>,
|
||||
): Promise<MCPRouterCallToolResponse> => {
|
||||
try {
|
||||
const axiosConfig = getAxiosConfig();
|
||||
const mcpRouterConfig = getMCPRouterConfig();
|
||||
|
||||
if (
|
||||
!axiosConfig.headers?.['Authorization'] ||
|
||||
axiosConfig.headers['Authorization'] === 'Bearer '
|
||||
) {
|
||||
throw new Error('MCPROUTER_API_KEY_NOT_CONFIGURED');
|
||||
}
|
||||
|
||||
const response = await axios.post<MCPRouterResponse<MCPRouterCallToolResponse>>(
|
||||
`${mcpRouterConfig.baseUrl}/call-tool`,
|
||||
{
|
||||
server: serverName,
|
||||
name: toolName,
|
||||
arguments: args,
|
||||
},
|
||||
axiosConfig,
|
||||
);
|
||||
|
||||
const data = response.data;
|
||||
|
||||
if (data.code !== 0) {
|
||||
throw new Error(data.message || 'Failed to call tool');
|
||||
}
|
||||
|
||||
return data.data;
|
||||
} catch (error) {
|
||||
console.error(`Error calling tool ${toolName} on server ${serverName}:`, error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
// Get all categories from cloud servers
|
||||
export const getCloudCategories = async (): Promise<string[]> => {
|
||||
try {
|
||||
const servers = await getCloudServers();
|
||||
const categories = new Set<string>();
|
||||
|
||||
servers.forEach((server) => {
|
||||
// Extract categories from content or description
|
||||
// This is a simple implementation, you might want to parse the content more sophisticatedly
|
||||
if (server.content) {
|
||||
const categoryMatches = server.content.match(/category[:\s]*([^,\n]+)/gi);
|
||||
if (categoryMatches) {
|
||||
categoryMatches.forEach((match) => {
|
||||
const category = match.replace(/category[:\s]*/i, '').trim();
|
||||
if (category) categories.add(category);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return Array.from(categories).sort();
|
||||
} catch (error) {
|
||||
console.error('Error fetching cloud market categories:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
// Get all tags from cloud servers
|
||||
export const getCloudTags = async (): Promise<string[]> => {
|
||||
try {
|
||||
const servers = await getCloudServers();
|
||||
const tags = new Set<string>();
|
||||
|
||||
servers.forEach((server) => {
|
||||
// Extract tags from content or description
|
||||
if (server.content) {
|
||||
const tagMatches = server.content.match(/tag[s]?[:\s]*([^,\n]+)/gi);
|
||||
if (tagMatches) {
|
||||
tagMatches.forEach((match) => {
|
||||
const tag = match.replace(/tag[s]?[:\s]*/i, '').trim();
|
||||
if (tag) tags.add(tag);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return Array.from(tags).sort();
|
||||
} catch (error) {
|
||||
console.error('Error fetching cloud market tags:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
// Search cloud servers by query
|
||||
export const searchCloudServers = async (query: string): Promise<CloudServer[]> => {
|
||||
try {
|
||||
const servers = await getCloudServers();
|
||||
const searchTerms = query
|
||||
.toLowerCase()
|
||||
.split(' ')
|
||||
.filter((term) => term.length > 0);
|
||||
|
||||
if (searchTerms.length === 0) {
|
||||
return servers;
|
||||
}
|
||||
|
||||
return servers.filter((server) => {
|
||||
const searchText = [
|
||||
server.name,
|
||||
server.title,
|
||||
server.description,
|
||||
server.content,
|
||||
server.author_name,
|
||||
]
|
||||
.join(' ')
|
||||
.toLowerCase();
|
||||
|
||||
return searchTerms.some((term) => searchText.includes(term));
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error searching cloud market servers:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
// Filter cloud servers by category
|
||||
export const filterCloudServersByCategory = async (category: string): Promise<CloudServer[]> => {
|
||||
try {
|
||||
const servers = await getCloudServers();
|
||||
|
||||
if (!category) {
|
||||
return servers;
|
||||
}
|
||||
|
||||
return servers.filter((server) => {
|
||||
const content = (server.content || '').toLowerCase();
|
||||
return content.includes(category.toLowerCase());
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error filtering cloud market servers by category:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
// Filter cloud servers by tag
|
||||
export const filterCloudServersByTag = async (tag: string): Promise<CloudServer[]> => {
|
||||
try {
|
||||
const servers = await getCloudServers();
|
||||
|
||||
if (!tag) {
|
||||
return servers;
|
||||
}
|
||||
|
||||
return servers.filter((server) => {
|
||||
const content = (server.content || '').toLowerCase();
|
||||
return content.includes(tag.toLowerCase());
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error filtering cloud market servers by tag:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
@@ -81,6 +81,49 @@ export interface MarketServer {
|
||||
is_official?: boolean;
|
||||
}
|
||||
|
||||
// Cloud Market Server types (for MCPRouter API)
|
||||
export interface CloudServer {
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
name: string;
|
||||
author_name: string;
|
||||
title: string;
|
||||
description: string;
|
||||
content: string;
|
||||
server_key: string;
|
||||
config_name: string;
|
||||
tools?: CloudTool[];
|
||||
}
|
||||
|
||||
export interface CloudTool {
|
||||
name: string;
|
||||
description: string;
|
||||
inputSchema: Record<string, any>;
|
||||
}
|
||||
|
||||
// MCPRouter API Response types
|
||||
export interface MCPRouterResponse<T = any> {
|
||||
code: number;
|
||||
message: string;
|
||||
data: T;
|
||||
}
|
||||
|
||||
export interface MCPRouterListServersResponse {
|
||||
servers: CloudServer[];
|
||||
}
|
||||
|
||||
export interface MCPRouterListToolsResponse {
|
||||
tools: CloudTool[];
|
||||
}
|
||||
|
||||
export interface MCPRouterCallToolResponse {
|
||||
content: Array<{
|
||||
type: string;
|
||||
text: string;
|
||||
}>;
|
||||
isError: boolean;
|
||||
}
|
||||
|
||||
export interface SystemConfig {
|
||||
routing?: {
|
||||
enableGlobalRoute?: boolean; // Controls whether the /sse endpoint without group is enabled
|
||||
@@ -95,6 +138,12 @@ export interface SystemConfig {
|
||||
baseUrl?: string; // Base URL for group card copy operations
|
||||
};
|
||||
smartRouting?: SmartRoutingConfig;
|
||||
mcpRouter?: {
|
||||
apiKey?: string; // MCPRouter API key for authentication
|
||||
referer?: string; // Referer header for MCPRouter API requests
|
||||
title?: string; // Title header for MCPRouter API requests
|
||||
baseUrl?: string; // Base URL for MCPRouter API (default: https://api.mcprouter.to/v1)
|
||||
};
|
||||
}
|
||||
|
||||
export interface UserConfig {
|
||||
|
||||
Reference in New Issue
Block a user