Add OpenAPI support and enhance settings aggregation (#500)

This commit is contained in:
samanhappy
2025-12-11 17:42:50 +08:00
committed by GitHub
parent 1dfa0a990b
commit 2028233b53
8 changed files with 274 additions and 74 deletions

View File

@@ -1,10 +1,18 @@
import { Request, Response } from 'express';
import config from '../config/index.js';
import { loadSettings, loadOriginalSettings } from '../config/index.js';
import { loadSettings } from '../config/index.js';
import { getDataService } from '../services/services.js';
import { DataService } from '../services/dataService.js';
import { IUser } from '../types/index.js';
import { getServerDao } from '../dao/DaoFactory.js';
import {
getGroupDao,
getOAuthClientDao,
getOAuthTokenDao,
getServerDao,
getSystemConfigDao,
getUserConfigDao,
getUserDao,
} from '../dao/DaoFactory.js';
const dataService: DataService = getDataService();
@@ -128,8 +136,33 @@ export const getMcpSettingsJson = async (req: Request, res: Response): Promise<v
},
});
} else {
// Return full settings
const settings = loadOriginalSettings();
// Return full settings via DAO layer (supports both file and database modes)
const [servers, users, groups, systemConfig, userConfigs, oauthClients, oauthTokens] =
await Promise.all([
getServerDao().findAll(),
getUserDao().findAll(),
getGroupDao().findAll(),
getSystemConfigDao().get(),
getUserConfigDao().getAll(),
getOAuthClientDao().findAll(),
getOAuthTokenDao().findAll(),
]);
const mcpServers: Record<string, any> = {};
for (const { name: serverConfigName, ...config } of servers) {
mcpServers[serverConfigName] = removeNullValues(config);
}
const settings = {
mcpServers,
users,
groups,
systemConfig,
userConfigs,
oauthClients,
oauthTokens,
};
res.json({
success: true,
data: settings,

View File

@@ -38,6 +38,7 @@ export class ServerDaoDbImpl implements ServerDao {
prompts: entity.prompts,
options: entity.options,
oauth: entity.oauth,
openapi: entity.openapi,
});
return this.mapToServerConfig(server);
}
@@ -61,6 +62,7 @@ export class ServerDaoDbImpl implements ServerDao {
prompts: entity.prompts,
options: entity.options,
oauth: entity.oauth,
openapi: entity.openapi,
});
return server ? this.mapToServerConfig(server) : null;
}
@@ -129,6 +131,7 @@ export class ServerDaoDbImpl implements ServerDao {
prompts?: Record<string, { enabled: boolean; description?: string }>;
options?: Record<string, any>;
oauth?: Record<string, any>;
openapi?: Record<string, any>;
}): ServerConfigWithName {
return {
name: server.name,
@@ -146,6 +149,7 @@ export class ServerDaoDbImpl implements ServerDao {
prompts: server.prompts,
options: server.options,
oauth: server.oauth,
openapi: server.openapi,
};
}
}

View File

@@ -59,6 +59,9 @@ export class Server {
@Column({ type: 'simple-json', nullable: true })
oauth?: Record<string, any>;
@Column({ type: 'simple-json', nullable: true })
openapi?: Record<string, any>;
@CreateDateColumn({ name: 'created_at', type: 'timestamp' })
createdAt: Date;

View File

@@ -614,9 +614,37 @@ export const registerAllTools = async (isInit: boolean, serverName?: string): Pr
export const getServersInfo = async (): Promise<Omit<ServerInfo, 'client' | 'transport'>[]> => {
const allServers: ServerConfigWithName[] = await getServerDao().findAll();
const dataService = getDataService();
// Ensure that servers recently added via DAO but not yet initialized in serverInfos
// are still visible in the servers list. This avoids a race condition where
// a POST /api/servers immediately followed by GET /api/servers would not
// return the newly created server until background initialization completes.
const combinedServerInfos: ServerInfo[] = [...serverInfos];
const existingNames = new Set(combinedServerInfos.map((s) => s.name));
for (const server of allServers) {
if (!existingNames.has(server.name)) {
const isEnabled = server.enabled === undefined ? true : server.enabled;
combinedServerInfos.push({
name: server.name,
owner: server.owner,
// Newly created servers that are enabled should appear as "connecting"
// until the MCP client initialization completes. Disabled servers remain
// in the "disconnected" state.
status: isEnabled ? 'connecting' : 'disconnected',
error: null,
tools: [],
prompts: [],
createTime: Date.now(),
enabled: isEnabled,
});
}
}
const filterServerInfos: ServerInfo[] = dataService.filterData
? dataService.filterData(serverInfos)
: serverInfos;
? dataService.filterData(combinedServerInfos)
: combinedServerInfos;
const infos = filterServerInfos.map(
({ name, status, tools, prompts, createTime, error, oauth }) => {
const serverConfig = allServers.find((server) => server.name === name);

View File

@@ -75,6 +75,7 @@ export async function migrateToDatabase(): Promise<boolean> {
prompts: config.prompts,
options: config.options,
oauth: config.oauth,
openapi: config.openapi,
});
console.log(` - Created server: ${name}`);
} else {