introduce market

This commit is contained in:
samanhappy
2025-04-20 13:58:52 +08:00
committed by GitHub
parent c4008f617d
commit 3d49c652ad
22 changed files with 76759 additions and 38 deletions

View File

@@ -0,0 +1,154 @@
import { Request, Response } from 'express';
import { ApiResponse } from '../types/index.js';
import {
getMarketServers,
getMarketServerByName,
getMarketCategories,
getMarketTags,
searchMarketServers,
filterMarketServersByCategory,
filterMarketServersByTag
} from '../services/marketService.js';
// Get all market servers
export const getAllMarketServers = (_: Request, res: Response): void => {
try {
const marketServers = Object.values(getMarketServers());
const response: ApiResponse = {
success: true,
data: marketServers,
};
res.json(response);
} catch (error) {
res.status(500).json({
success: false,
message: 'Failed to get market servers information',
});
}
};
// Get a specific market server by name
export const getMarketServer = (req: Request, res: Response): void => {
try {
const { name } = req.params;
if (!name) {
res.status(400).json({
success: false,
message: 'Server name is required',
});
return;
}
const server = getMarketServerByName(name);
if (!server) {
res.status(404).json({
success: false,
message: 'Market server not found',
});
return;
}
const response: ApiResponse = {
success: true,
data: server,
};
res.json(response);
} catch (error) {
res.status(500).json({
success: false,
message: 'Failed to get market server information',
});
}
};
// Get all market categories
export const getAllMarketCategories = (_: Request, res: Response): void => {
try {
const categories = getMarketCategories();
const response: ApiResponse = {
success: true,
data: categories,
};
res.json(response);
} catch (error) {
res.status(500).json({
success: false,
message: 'Failed to get market categories',
});
}
};
// Get all market tags
export const getAllMarketTags = (_: Request, res: Response): void => {
try {
const tags = getMarketTags();
const response: ApiResponse = {
success: true,
data: tags,
};
res.json(response);
} catch (error) {
res.status(500).json({
success: false,
message: 'Failed to get market tags',
});
}
};
// Search market servers
export const searchMarketServersByQuery = (req: Request, res: Response): void => {
try {
const { query } = req.query;
const searchQuery = typeof query === 'string' ? query : '';
const servers = searchMarketServers(searchQuery);
const response: ApiResponse = {
success: true,
data: servers,
};
res.json(response);
} catch (error) {
res.status(500).json({
success: false,
message: 'Failed to search market servers',
});
}
};
// Filter market servers by category
export const getMarketServersByCategory = (req: Request, res: Response): void => {
try {
const { category } = req.params;
const servers = filterMarketServersByCategory(category);
const response: ApiResponse = {
success: true,
data: servers,
};
res.json(response);
} catch (error) {
res.status(500).json({
success: false,
message: 'Failed to filter market servers by category',
});
}
};
// Filter market servers by tag
export const getMarketServersByTag = (req: Request, res: Response): void => {
try {
const { tag } = req.params;
const servers = filterMarketServersByTag(tag);
const response: ApiResponse = {
success: true,
data: servers,
};
res.json(response);
} catch (error) {
res.status(500).json({
success: false,
message: 'Failed to filter market servers by tag',
});
}
};

View File

@@ -19,6 +19,15 @@ import {
getGroupServers,
updateGroupServersBatch
} from '../controllers/groupController.js';
import {
getAllMarketServers,
getMarketServer,
getAllMarketCategories,
getAllMarketTags,
searchMarketServersByQuery,
getMarketServersByCategory,
getMarketServersByTag
} from '../controllers/marketController.js';
import {
login,
register,
@@ -50,6 +59,15 @@ export const initRoutes = (app: express.Application): void => {
// New route for batch updating servers in a group
router.put('/groups/:id/servers/batch', updateGroupServersBatch);
// Market routes
router.get('/market/servers', getAllMarketServers);
router.get('/market/servers/search', searchMarketServersByQuery);
router.get('/market/servers/:name', getMarketServer);
router.get('/market/categories', getAllMarketCategories);
router.get('/market/categories/:category', getMarketServersByCategory);
router.get('/market/tags', getAllMarketTags);
router.get('/market/tags/:tag', getMarketServersByTag);
// Auth routes (these will NOT be protected by auth middleware)
app.post('/auth/login', [
check('username', 'Username is required').not().isEmpty(),

View File

@@ -0,0 +1,103 @@
import fs from 'fs';
import path from 'path';
import { MarketServer } from '../types/index.js';
// Get path to the servers.json file
export const getServersJsonPath = (): string => {
return path.resolve(process.cwd(), 'servers.json');
};
// Load all market servers from servers.json
export const getMarketServers = (): Record<string, MarketServer> => {
try {
const serversJsonPath = getServersJsonPath();
const data = fs.readFileSync(serversJsonPath, 'utf8');
return JSON.parse(data);
} catch (error) {
console.error('Failed to load servers from servers.json:', error);
return {};
}
};
// Get a specific market server by name
export const getMarketServerByName = (name: string): MarketServer | null => {
const servers = getMarketServers();
return servers[name] || null;
};
// Get all categories from market servers
export const getMarketCategories = (): string[] => {
const servers = getMarketServers();
const categories = new Set<string>();
Object.values(servers).forEach((server) => {
server.categories?.forEach((category) => {
categories.add(category);
});
});
return Array.from(categories).sort();
};
// Get all tags from market servers
export const getMarketTags = (): string[] => {
const servers = getMarketServers();
const tags = new Set<string>();
Object.values(servers).forEach((server) => {
server.tags?.forEach((tag) => {
tags.add(tag);
});
});
return Array.from(tags).sort();
};
// Search market servers by query
export const searchMarketServers = (query: string): MarketServer[] => {
const servers = getMarketServers();
const searchTerms = query.toLowerCase().split(' ').filter(term => term.length > 0);
if (searchTerms.length === 0) {
return Object.values(servers);
}
return Object.values(servers).filter((server) => {
// Search in name, display_name, description, categories, and tags
const searchableText = [
server.name,
server.display_name,
server.description,
...(server.categories || []),
...(server.tags || [])
].join(' ').toLowerCase();
return searchTerms.some(term => searchableText.includes(term));
});
};
// Filter market servers by category
export const filterMarketServersByCategory = (category: string): MarketServer[] => {
const servers = getMarketServers();
if (!category) {
return Object.values(servers);
}
return Object.values(servers).filter((server) => {
return server.categories?.includes(category);
});
};
// Filter market servers by tag
export const filterMarketServersByTag = (tag: string): MarketServer[] => {
const servers = getMarketServers();
if (!tag) {
return Object.values(servers);
}
return Object.values(servers).filter((server) => {
return server.tags?.includes(tag);
});
};

View File

@@ -17,6 +17,60 @@ export interface IGroup {
servers: string[]; // Array of server names that belong to this group
}
// Market server types
export interface MarketServerRepository {
type: string;
url: string;
}
export interface MarketServerAuthor {
name: string;
}
export interface MarketServerInstallation {
type: string;
command: string;
args: string[];
env?: Record<string, string>;
}
export interface MarketServerArgument {
description: string;
required: boolean;
example: string;
}
export interface MarketServerExample {
title: string;
description: string;
prompt: string;
}
export interface MarketServerTool {
name: string;
description: string;
inputSchema: Record<string, any>;
}
export interface MarketServer {
name: string;
display_name: string;
description: string;
repository: MarketServerRepository;
homepage: string;
author: MarketServerAuthor;
license: string;
categories: string[];
tags: string[];
examples: MarketServerExample[];
installations: {
[key: string]: MarketServerInstallation;
};
arguments: Record<string, MarketServerArgument>;
tools: MarketServerTool[];
is_official?: boolean;
}
// Represents the settings for MCP servers
export interface McpSettings {
users?: IUser[]; // Array of user credentials and permissions