fa-mcp-sdk 0.2.125 → 0.2.131
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/fa-mcp.js +43 -12
- package/cli-template/config/_local.yaml +29 -11
- package/cli-template/config/custom-environment-variables.yaml +0 -6
- package/cli-template/config/default.yaml +34 -14
- package/cli-template/fa-mcp-sdk-spec.md +396 -189
- package/dist/core/_types_/config.d.ts +4 -17
- package/dist/core/_types_/config.d.ts.map +1 -1
- package/dist/core/_types_/types.d.ts +12 -15
- package/dist/core/_types_/types.d.ts.map +1 -1
- package/dist/core/auth/middleware.d.ts +9 -37
- package/dist/core/auth/middleware.d.ts.map +1 -1
- package/dist/core/auth/middleware.js +31 -146
- package/dist/core/auth/middleware.js.map +1 -1
- package/dist/core/auth/multi-auth.d.ts +10 -14
- package/dist/core/auth/multi-auth.d.ts.map +1 -1
- package/dist/core/auth/multi-auth.js +133 -220
- package/dist/core/auth/multi-auth.js.map +1 -1
- package/dist/core/auth/types.d.ts +1 -7
- package/dist/core/auth/types.d.ts.map +1 -1
- package/dist/core/auth/types.js +1 -10
- package/dist/core/auth/types.js.map +1 -1
- package/dist/core/bootstrap/init-config.d.ts.map +1 -1
- package/dist/core/bootstrap/init-config.js +4 -0
- package/dist/core/bootstrap/init-config.js.map +1 -1
- package/dist/core/index.d.ts +6 -6
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +5 -4
- package/dist/core/index.js.map +1 -1
- package/dist/core/utils/utils.d.ts +6 -0
- package/dist/core/utils/utils.d.ts.map +1 -1
- package/dist/core/utils/utils.js +25 -0
- package/dist/core/utils/utils.js.map +1 -1
- package/dist/core/web/server-http.d.ts.map +1 -1
- package/dist/core/web/server-http.js +32 -18
- package/dist/core/web/server-http.js.map +1 -1
- package/package.json +1 -1
- package/cli-template/src/_examples/custom-basic-auth-example.ts +0 -252
- package/cli-template/src/_examples/multi-auth-examples.ts +0 -333
- package/cli-template/src/_types_/common.d.ts +0 -27
- package/cli-template/src/api/router.ts +0 -35
- package/cli-template/src/api/swagger.ts +0 -167
- package/cli-template/src/asset/favicon.svg +0 -3
- package/cli-template/src/custom-resources.ts +0 -12
- package/cli-template/src/prompts/agent-brief.ts +0 -8
- package/cli-template/src/prompts/agent-prompt.ts +0 -10
- package/cli-template/src/prompts/custom-prompts.ts +0 -12
- package/cli-template/src/start.ts +0 -71
- package/cli-template/src/tools/handle-tool-call.ts +0 -55
- package/cli-template/src/tools/tools.ts +0 -88
- package/cli-template/tests/jest-simple-reporter.js +0 -10
- package/cli-template/tests/mcp/sse/mcp-sse-client-handling.md +0 -111
- package/cli-template/tests/mcp/sse/test-sse-npm-package.js +0 -96
- package/cli-template/tests/mcp/test-cases.js +0 -143
- package/cli-template/tests/mcp/test-http.js +0 -63
- package/cli-template/tests/mcp/test-sse.js +0 -67
- package/cli-template/tests/mcp/test-stdio.js +0 -78
- package/cli-template/tests/utils.ts +0 -154
- package/cli-template/yarn.lock +0 -6375
|
@@ -1,333 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Примеры использования системы мультиаутентификации fa-mcp-sdk
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import express from 'express';
|
|
6
|
-
// @ts-ignore
|
|
7
|
-
import { appConfig, enhancedAuthTokenMW, createConfigurableAuthMiddleware, getMultiAuthError, getAuthInfo, checkMultiAuth, detectAuthConfiguration, logAuthConfiguration } from 'fa-mcp-sdk';
|
|
8
|
-
|
|
9
|
-
// ========================================================================
|
|
10
|
-
// ПРИМЕР 1: ПРОСТАЯ ЗАМЕНА MIDDLEWARE
|
|
11
|
-
// ========================================================================
|
|
12
|
-
|
|
13
|
-
const app = express();
|
|
14
|
-
|
|
15
|
-
// Вместо старого authTokenMW используем enhancedAuthTokenMW
|
|
16
|
-
app.use('/api', enhancedAuthTokenMW);
|
|
17
|
-
|
|
18
|
-
app.get('/api/protected', (req, res) => {
|
|
19
|
-
const authInfo = (req as any).authInfo;
|
|
20
|
-
res.json({
|
|
21
|
-
message: 'Access granted',
|
|
22
|
-
authType: authInfo?.authType,
|
|
23
|
-
username: authInfo?.username,
|
|
24
|
-
tokenType: authInfo?.tokenType,
|
|
25
|
-
});
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
// ========================================================================
|
|
29
|
-
// ПРИМЕР 2: КОНФИГУРИРУЕМЫЙ MIDDLEWARE
|
|
30
|
-
// ========================================================================
|
|
31
|
-
|
|
32
|
-
// Middleware с логированием конфигурации при запуске
|
|
33
|
-
const authWithLogging = createConfigurableAuthMiddleware({
|
|
34
|
-
logConfiguration: true,
|
|
35
|
-
forceMultiAuth: false, // Автоматически определяет нужна ли мультиаут
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
app.use('/api/v2', authWithLogging);
|
|
39
|
-
|
|
40
|
-
// ========================================================================
|
|
41
|
-
// ПРИМЕР 3: КАСТОМНАЯ ЛОГИКА АУТЕНТИФИКАЦИИ
|
|
42
|
-
// ========================================================================
|
|
43
|
-
|
|
44
|
-
app.use('/api/custom', async (req, res, next) => {
|
|
45
|
-
// Публичные эндпоинты
|
|
46
|
-
if (req.path.startsWith('/api/custom/public')) {
|
|
47
|
-
return next();
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// Для админских эндпоинтов требуем только permanent tokens
|
|
51
|
-
if (req.path.startsWith('/api/custom/admin')) {
|
|
52
|
-
const token = (req.headers.authorization || '').replace(/^Bearer */, '');
|
|
53
|
-
const auth = appConfig.webServer.auth;
|
|
54
|
-
|
|
55
|
-
if (auth.permanentServerTokens.includes(token)) {
|
|
56
|
-
return next();
|
|
57
|
-
} else {
|
|
58
|
-
return res.status(403).json({ error: 'Admin access required' });
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
try {
|
|
63
|
-
// Для остальных используем полную мультиаутентификацию
|
|
64
|
-
const authError = await getMultiAuthError(req);
|
|
65
|
-
if (authError) {
|
|
66
|
-
res.status(authError.code).send(authError.message);
|
|
67
|
-
return;
|
|
68
|
-
}
|
|
69
|
-
next();
|
|
70
|
-
} catch (error) {
|
|
71
|
-
res.status(500).send('Authentication error');
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
// ========================================================================
|
|
77
|
-
// ПРИМЕР 4: РОУТЕР С РАЗНЫМИ УРОВНЯМИ ДОСТУПА
|
|
78
|
-
// ========================================================================
|
|
79
|
-
|
|
80
|
-
const apiRouter = express.Router();
|
|
81
|
-
|
|
82
|
-
// Публичные роуты - без аутентификации
|
|
83
|
-
apiRouter.get('/health', (req, res) => {
|
|
84
|
-
res.json({ status: 'ok' });
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
apiRouter.get('/info', (req, res) => {
|
|
88
|
-
const authInfo = getAuthInfo();
|
|
89
|
-
res.json({
|
|
90
|
-
authEnabled: authInfo.enabled,
|
|
91
|
-
configuredTypes: authInfo.configured,
|
|
92
|
-
validTypes: authInfo.valid,
|
|
93
|
-
usingMultiAuth: authInfo.usingMultiAuth,
|
|
94
|
-
});
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
// Защищенные роуты - с мультиаутентификацией
|
|
98
|
-
apiRouter.use('/protected', enhancedAuthTokenMW);
|
|
99
|
-
|
|
100
|
-
apiRouter.get('/protected/profile', (req, res) => {
|
|
101
|
-
const authInfo = (req as any).authInfo;
|
|
102
|
-
res.json({
|
|
103
|
-
profile: {
|
|
104
|
-
authType: authInfo.authType,
|
|
105
|
-
username: authInfo.username || 'anonymous',
|
|
106
|
-
permissions: getPermissionsForAuthType(authInfo.authType),
|
|
107
|
-
},
|
|
108
|
-
});
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
apiRouter.get('/protected/data', (req, res) => {
|
|
112
|
-
const authInfo = (req as any).authInfo;
|
|
113
|
-
|
|
114
|
-
// Разные данные в зависимости от типа аутентификации
|
|
115
|
-
let data;
|
|
116
|
-
switch (authInfo.authType) {
|
|
117
|
-
case 'permanentServerTokens':
|
|
118
|
-
data = { level: 'server', access: 'full' };
|
|
119
|
-
break;
|
|
120
|
-
case 'oauth2':
|
|
121
|
-
data = { level: 'user', access: 'scoped', scopes: authInfo.payload?.scope };
|
|
122
|
-
break;
|
|
123
|
-
case 'basic':
|
|
124
|
-
data = { level: 'basic', access: 'limited', username: authInfo.username };
|
|
125
|
-
break;
|
|
126
|
-
case 'pat':
|
|
127
|
-
data = { level: 'api', access: 'token-based' };
|
|
128
|
-
break;
|
|
129
|
-
case 'jwtToken':
|
|
130
|
-
data = { level: 'jwt', access: 'custom', payload: authInfo.payload };
|
|
131
|
-
break;
|
|
132
|
-
default:
|
|
133
|
-
data = { level: 'unknown', access: 'none' };
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
res.json({ data, authInfo: authInfo.authType });
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
app.use('/api/v3', apiRouter);
|
|
140
|
-
|
|
141
|
-
// ========================================================================
|
|
142
|
-
// ПРИМЕР 5: ПРОГРАММНОЕ ТЕСТИРОВАНИЕ ТОКЕНОВ
|
|
143
|
-
// ========================================================================
|
|
144
|
-
|
|
145
|
-
app.post('/api/test-token', async (req, res) => {
|
|
146
|
-
const { token } = req.body;
|
|
147
|
-
|
|
148
|
-
if (!token) {
|
|
149
|
-
return res.status(400).json({ error: 'Token required' });
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
try {
|
|
153
|
-
const authConfig = appConfig.webServer.auth;
|
|
154
|
-
const result = await checkMultiAuth(token, authConfig);
|
|
155
|
-
|
|
156
|
-
return res.json({
|
|
157
|
-
valid: result.success,
|
|
158
|
-
authType: result.authType,
|
|
159
|
-
tokenType: result.tokenType,
|
|
160
|
-
error: result.error,
|
|
161
|
-
username: result.username,
|
|
162
|
-
hasPayload: !!result.payload,
|
|
163
|
-
});
|
|
164
|
-
} catch (error) {
|
|
165
|
-
return res.status(500).json({ error: 'Authentication test failed' });
|
|
166
|
-
}
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
// ========================================================================
|
|
170
|
-
// ПРИМЕР 6: MIDDLEWARE ДЛЯ РАЗНЫХ ТИПОВ API
|
|
171
|
-
// ========================================================================
|
|
172
|
-
|
|
173
|
-
// REST API - требует любую валидную аутентификацию
|
|
174
|
-
app.use('/rest', enhancedAuthTokenMW);
|
|
175
|
-
|
|
176
|
-
// GraphQL API - требует user-level аутентификацию (не server tokens)
|
|
177
|
-
app.use('/graphql', async (req, res, next) => {
|
|
178
|
-
try {
|
|
179
|
-
const authError = await getMultiAuthError(req);
|
|
180
|
-
if (authError) {
|
|
181
|
-
return res.status(authError.code).send(authError.message);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
const authInfo = (req as any).authInfo;
|
|
185
|
-
if (authInfo.authType === 'permanentServerTokens') {
|
|
186
|
-
return res.status(403).json({
|
|
187
|
-
error: 'GraphQL API requires user authentication, server tokens not allowed',
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
return next();
|
|
192
|
-
} catch (error) {
|
|
193
|
-
return res.status(500).send('Authentication error');
|
|
194
|
-
}
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
// WebSocket API - только JWT токены (для real-time connections)
|
|
198
|
-
app.use('/ws', async (req, res, next) => {
|
|
199
|
-
try {
|
|
200
|
-
const authError = await getMultiAuthError(req);
|
|
201
|
-
if (authError) {
|
|
202
|
-
return res.status(authError.code).send(authError.message);
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
const authInfo = (req as any).authInfo;
|
|
206
|
-
if (authInfo.authType !== 'jwtToken' && authInfo.authType !== 'oauth2') {
|
|
207
|
-
return res.status(403).json({
|
|
208
|
-
error: 'WebSocket API requires JWT or OAuth2 tokens for session management',
|
|
209
|
-
});
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
return next();
|
|
213
|
-
} catch {
|
|
214
|
-
return res.status(500).send('Authentication error');
|
|
215
|
-
}
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
// ========================================================================
|
|
219
|
-
// УТИЛИТНЫЕ ФУНКЦИИ
|
|
220
|
-
// ========================================================================
|
|
221
|
-
|
|
222
|
-
export function getPermissionsForAuthType (authType: string): string[] {
|
|
223
|
-
const permissions: Record<string, string[]> = {
|
|
224
|
-
'permanentServerTokens': ['read', 'write', 'admin', 'server'],
|
|
225
|
-
'oauth2': ['read', 'write', 'user'],
|
|
226
|
-
'jwtToken': ['read', 'write', 'session'],
|
|
227
|
-
'pat': ['read', 'write', 'api'],
|
|
228
|
-
'basic': ['read', 'basic'],
|
|
229
|
-
};
|
|
230
|
-
|
|
231
|
-
return permissions[authType] || ['read'];
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
// ========================================================================
|
|
235
|
-
// ПРИМЕР 7: ИНИЦИАЛИЗАЦИЯ С ДИАГНОСТИКОЙ
|
|
236
|
-
// ========================================================================
|
|
237
|
-
|
|
238
|
-
export function initializeAuthSystem () {
|
|
239
|
-
const authConfig = appConfig.webServer.auth;
|
|
240
|
-
|
|
241
|
-
console.log('🔐 Initializing Multi-Authentication System...');
|
|
242
|
-
|
|
243
|
-
// Диагностика конфигурации
|
|
244
|
-
const detection = detectAuthConfiguration(authConfig);
|
|
245
|
-
|
|
246
|
-
console.log('📊 Auth Configuration:');
|
|
247
|
-
console.log(` Enabled: ${authConfig.enabled}`);
|
|
248
|
-
console.log(` Configured: ${detection.configured.join(', ')}`);
|
|
249
|
-
console.log(` Valid: ${detection.valid.join(', ')}`);
|
|
250
|
-
|
|
251
|
-
if (Object.keys(detection.errors).length > 0) {
|
|
252
|
-
console.warn('⚠️ Configuration Issues:');
|
|
253
|
-
Object.entries(detection.errors).forEach(([type, errors]) => {
|
|
254
|
-
console.warn(` ${type}: ${(errors as string[]).join(', ')}`);
|
|
255
|
-
});
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
// Логирование для отладки
|
|
259
|
-
logAuthConfiguration(authConfig);
|
|
260
|
-
|
|
261
|
-
console.log('✅ Multi-Authentication System initialized successfully');
|
|
262
|
-
|
|
263
|
-
return {
|
|
264
|
-
configured: detection.configured,
|
|
265
|
-
valid: detection.valid,
|
|
266
|
-
errors: detection.errors,
|
|
267
|
-
usingMultiAuth: !!(authConfig.pat || authConfig.basic || authConfig.oauth2),
|
|
268
|
-
};
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
// ========================================================================
|
|
272
|
-
// ПРИМЕР 8: ТЕСТИРОВАНИЕ КОНФИГУРАЦИИ
|
|
273
|
-
// ========================================================================
|
|
274
|
-
|
|
275
|
-
export async function testAuthConfiguration () {
|
|
276
|
-
const authConfig = appConfig.webServer.auth;
|
|
277
|
-
|
|
278
|
-
console.log('🧪 Testing Authentication Configuration...');
|
|
279
|
-
|
|
280
|
-
const testCases = [
|
|
281
|
-
// Тест permanent token
|
|
282
|
-
{
|
|
283
|
-
name: 'Permanent Server Token',
|
|
284
|
-
token: authConfig.permanentServerTokens[0],
|
|
285
|
-
expectedType: 'permanentServerTokens',
|
|
286
|
-
},
|
|
287
|
-
// Тест PAT
|
|
288
|
-
{
|
|
289
|
-
name: 'Personal Access Token',
|
|
290
|
-
token: authConfig.pat,
|
|
291
|
-
expectedType: 'pat',
|
|
292
|
-
},
|
|
293
|
-
// Тест basic auth
|
|
294
|
-
{
|
|
295
|
-
name: 'Basic Authentication',
|
|
296
|
-
token: authConfig.basic
|
|
297
|
-
? Buffer.from(`${authConfig.basic.username}:${authConfig.basic.password}`).toString('base64')
|
|
298
|
-
: undefined,
|
|
299
|
-
expectedType: 'basic',
|
|
300
|
-
},
|
|
301
|
-
// Тест OAuth2
|
|
302
|
-
{
|
|
303
|
-
name: 'OAuth2 Bearer Token',
|
|
304
|
-
token: authConfig.oauth2 ? `Bearer ${authConfig.oauth2.accessToken}` : undefined,
|
|
305
|
-
expectedType: 'oauth2',
|
|
306
|
-
},
|
|
307
|
-
];
|
|
308
|
-
|
|
309
|
-
for (const testCase of testCases) {
|
|
310
|
-
if (!testCase.token) {
|
|
311
|
-
console.log(`⏭️ Skipping ${testCase.name}: not configured`);
|
|
312
|
-
continue;
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
try {
|
|
316
|
-
const result = await checkMultiAuth(testCase.token, authConfig);
|
|
317
|
-
|
|
318
|
-
if (result.success && result.authType === testCase.expectedType) {
|
|
319
|
-
console.log(`✅ ${testCase.name}: PASSED`);
|
|
320
|
-
} else {
|
|
321
|
-
console.log(`❌ ${testCase.name}: FAILED - ${result.error || 'Unexpected auth type'}`);
|
|
322
|
-
}
|
|
323
|
-
} catch (error) {
|
|
324
|
-
console.log(`❌ ${testCase.name}: FAILED - Authentication test error`);
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
console.log('🧪 Authentication testing completed');
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
// ========================================================================
|
|
332
|
-
// ЭКСПОРТ ДЛЯ ИСПОЛЬЗОВАНИЯ
|
|
333
|
-
// ========================================================================
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
export interface ISearchParams {
|
|
2
|
-
query: string; // Search query string
|
|
3
|
-
limit?: number; // Maximum number of results (default: 20)
|
|
4
|
-
threshold?: number; // Minimum similarity threshold (0-1)
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
export interface ISearchResultRow {
|
|
8
|
-
similarity_score: number;
|
|
9
|
-
word_similarity_score: number;
|
|
10
|
-
final_score: number;
|
|
11
|
-
similarity: number; // mapped from final_score
|
|
12
|
-
|
|
13
|
-
[prop: string]: number | string;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export interface ISearchResultRow {
|
|
17
|
-
similarity_score: number;
|
|
18
|
-
word_similarity_score: number;
|
|
19
|
-
final_score: number;
|
|
20
|
-
|
|
21
|
-
[prop: string]: number | string;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export type ISearchResult = {
|
|
25
|
-
similarity: number; // mapped from final_score
|
|
26
|
-
[prop: string]: number | string | undefined;
|
|
27
|
-
}[]
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { Router, Request, Response } from 'express';
|
|
2
|
-
import { logger, authTokenMW, IEndpointsOn404 } from 'fa-mcp-sdk';
|
|
3
|
-
|
|
4
|
-
export const apiRouter: Router | null = Router();
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Template for API routes
|
|
8
|
-
* Modify this file to implement your specific API endpoints
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
// Example protected endpoint using auth middleware
|
|
12
|
-
apiRouter.get('/example', authTokenMW, async (req: Request, res: Response) => {
|
|
13
|
-
try {
|
|
14
|
-
logger.info('Example endpoint called');
|
|
15
|
-
|
|
16
|
-
res.json({
|
|
17
|
-
success: true,
|
|
18
|
-
message: 'This is a template endpoint',
|
|
19
|
-
data: {
|
|
20
|
-
timestamp: new Date().toISOString(),
|
|
21
|
-
},
|
|
22
|
-
});
|
|
23
|
-
} catch (error) {
|
|
24
|
-
logger.error('Error in example endpoint:', error);
|
|
25
|
-
res.status(500).json({
|
|
26
|
-
success: false,
|
|
27
|
-
error: error instanceof Error ? error.message : 'Unknown error',
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
export const endpointsOn404: IEndpointsOn404 = {
|
|
33
|
-
myEndpoints1: ['/my-endpoint-1', '/my-endpoint-2'],
|
|
34
|
-
myEndpoint3: '/my-endpoint-3',
|
|
35
|
-
};
|
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
import swaggerJsdoc from 'swagger-jsdoc';
|
|
2
|
-
import swaggerUi from 'swagger-ui-express';
|
|
3
|
-
import { appConfig } from 'fa-mcp-sdk';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Generic Swagger configuration template for MCP Server
|
|
7
|
-
* Customize this file according to your API endpoints and schemas
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
// Build servers array from config with fallback
|
|
11
|
-
const buildServers = () => {
|
|
12
|
-
const servers = [];
|
|
13
|
-
|
|
14
|
-
// Use servers from config if available
|
|
15
|
-
if (appConfig.swagger?.servers?.length) {
|
|
16
|
-
appConfig.swagger.servers.forEach((server: any) => {
|
|
17
|
-
servers.push({
|
|
18
|
-
url: server.url,
|
|
19
|
-
description: server.description
|
|
20
|
-
});
|
|
21
|
-
});
|
|
22
|
-
} else {
|
|
23
|
-
// Fallback to default development server
|
|
24
|
-
servers.push({
|
|
25
|
-
url: `http://localhost:${appConfig.webServer.port}`,
|
|
26
|
-
description: 'Development server'
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
return servers;
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
const options = {
|
|
34
|
-
definition: {
|
|
35
|
-
openapi: '3.0.0',
|
|
36
|
-
info: {
|
|
37
|
-
title: 'MCP Server API',
|
|
38
|
-
version: appConfig.version,
|
|
39
|
-
description: `
|
|
40
|
-
REST API for your MCP Server. This is a template configuration.
|
|
41
|
-
Customize the endpoints, schemas, and documentation according to your needs.
|
|
42
|
-
`,
|
|
43
|
-
},
|
|
44
|
-
servers: buildServers(),
|
|
45
|
-
components: {
|
|
46
|
-
schemas: {
|
|
47
|
-
HealthResponse: {
|
|
48
|
-
type: 'object',
|
|
49
|
-
description: 'Health check response',
|
|
50
|
-
properties: {
|
|
51
|
-
status: {
|
|
52
|
-
type: 'string',
|
|
53
|
-
example: 'ok'
|
|
54
|
-
},
|
|
55
|
-
timestamp: {
|
|
56
|
-
type: 'string',
|
|
57
|
-
format: 'date-time',
|
|
58
|
-
example: '2024-11-05T12:00:00.000Z'
|
|
59
|
-
},
|
|
60
|
-
version: {
|
|
61
|
-
type: 'string',
|
|
62
|
-
example: '1.0.0'
|
|
63
|
-
}
|
|
64
|
-
},
|
|
65
|
-
required: ['status', 'timestamp', 'version']
|
|
66
|
-
},
|
|
67
|
-
ErrorResponse: {
|
|
68
|
-
type: 'object',
|
|
69
|
-
description: 'Error response format',
|
|
70
|
-
properties: {
|
|
71
|
-
success: {
|
|
72
|
-
type: 'boolean',
|
|
73
|
-
description: 'Indicates failed operation',
|
|
74
|
-
example: false
|
|
75
|
-
},
|
|
76
|
-
error: {
|
|
77
|
-
type: 'string',
|
|
78
|
-
description: 'Human-readable error message',
|
|
79
|
-
example: 'Validation failed'
|
|
80
|
-
},
|
|
81
|
-
code: {
|
|
82
|
-
type: 'string',
|
|
83
|
-
description: 'Error code for programmatic handling',
|
|
84
|
-
example: 'VALIDATION_ERROR'
|
|
85
|
-
}
|
|
86
|
-
},
|
|
87
|
-
required: ['success', 'error', 'code']
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
},
|
|
91
|
-
paths: {
|
|
92
|
-
'/health': {
|
|
93
|
-
get: {
|
|
94
|
-
summary: 'Health check',
|
|
95
|
-
description: 'Simple health check endpoint for monitoring',
|
|
96
|
-
tags: ['Server'],
|
|
97
|
-
responses: {
|
|
98
|
-
'200': {
|
|
99
|
-
description: 'Service is healthy',
|
|
100
|
-
content: {
|
|
101
|
-
'application/json': {
|
|
102
|
-
schema: {
|
|
103
|
-
$ref: '#/components/schemas/HealthResponse'
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
},
|
|
111
|
-
'/example': {
|
|
112
|
-
get: {
|
|
113
|
-
summary: 'Example endpoint',
|
|
114
|
-
description: 'Template endpoint - customize as needed',
|
|
115
|
-
tags: ['Example'],
|
|
116
|
-
responses: {
|
|
117
|
-
'200': {
|
|
118
|
-
description: 'Success response',
|
|
119
|
-
content: {
|
|
120
|
-
'application/json': {
|
|
121
|
-
schema: {
|
|
122
|
-
type: 'object',
|
|
123
|
-
properties: {
|
|
124
|
-
success: {
|
|
125
|
-
type: 'boolean',
|
|
126
|
-
example: true
|
|
127
|
-
},
|
|
128
|
-
message: {
|
|
129
|
-
type: 'string',
|
|
130
|
-
example: 'Template endpoint response'
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
},
|
|
137
|
-
'400': {
|
|
138
|
-
description: 'Bad request',
|
|
139
|
-
content: {
|
|
140
|
-
'application/json': {
|
|
141
|
-
schema: {
|
|
142
|
-
$ref: '#/components/schemas/ErrorResponse'
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
},
|
|
151
|
-
tags: [
|
|
152
|
-
{
|
|
153
|
-
name: 'Server',
|
|
154
|
-
description: 'Server management endpoints'
|
|
155
|
-
},
|
|
156
|
-
{
|
|
157
|
-
name: 'Example',
|
|
158
|
-
description: 'Template endpoints to customize'
|
|
159
|
-
}
|
|
160
|
-
]
|
|
161
|
-
},
|
|
162
|
-
apis: [] // Add your API files here if using JSDoc comments
|
|
163
|
-
};
|
|
164
|
-
|
|
165
|
-
const swaggerSpecs = swaggerJsdoc(options);
|
|
166
|
-
|
|
167
|
-
export const swagger = { swaggerSpecs, swaggerUi };
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
// @ts-ignore
|
|
2
|
-
import { IResourceData } from 'fa-mcp-sdk';
|
|
3
|
-
|
|
4
|
-
export const customResources: IResourceData[] = [
|
|
5
|
-
{
|
|
6
|
-
uri: 'custom-resource://resource1',
|
|
7
|
-
name: 'Custom Resource',
|
|
8
|
-
description: 'Custom resource description',
|
|
9
|
-
mimeType: 'text/plain',
|
|
10
|
-
content: 'Custom resource content',
|
|
11
|
-
}
|
|
12
|
-
];
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Level 2: Agent description This prompt becomes visible to the LLM after the
|
|
3
|
-
* agent router has selected this agent from among others based on their short
|
|
4
|
-
* descriptions. At that point, the LLM gains access to the full list of tools
|
|
5
|
-
* and this detailed prompt, which may include instructions on how to call those
|
|
6
|
-
* tools. In simple scenarios, this prompt can be very short or even empty if
|
|
7
|
-
* the tool descriptions alone are sufficient.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
export const AGENT_PROMPT = 'Agent Prompt';
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { IPromptData, IGetPromptRequest } from 'fa-mcp-sdk';
|
|
2
|
-
|
|
3
|
-
export const customPrompts: IPromptData[] = [
|
|
4
|
-
{
|
|
5
|
-
name: 'custom_prompt',
|
|
6
|
-
description: 'Custom prompt',
|
|
7
|
-
arguments: [],
|
|
8
|
-
content: (request: IGetPromptRequest) => {
|
|
9
|
-
return `Custom prompt content ${request.method}`;
|
|
10
|
-
},
|
|
11
|
-
},
|
|
12
|
-
];
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
// Import all project data from existing files
|
|
2
|
-
// @ts-ignore
|
|
3
|
-
import { appConfig, initMcpServer, McpServerData, getAsset } from 'fa-mcp-sdk';
|
|
4
|
-
import { tools } from './tools/tools.js';
|
|
5
|
-
import { handleToolCall } from './tools/handle-tool-call.js';
|
|
6
|
-
import { AGENT_BRIEF } from './prompts/agent-brief.js';
|
|
7
|
-
import { AGENT_PROMPT } from './prompts/agent-prompt.js';
|
|
8
|
-
import { customPrompts } from './prompts/custom-prompts.js';
|
|
9
|
-
import { customResources } from './custom-resources.js';
|
|
10
|
-
import { apiRouter, endpointsOn404 } from './api/router.js';
|
|
11
|
-
import { swagger } from './api/swagger.js';
|
|
12
|
-
|
|
13
|
-
const isConsulProd = (process.env.NODE_CONSUL_ENV || process.env.NODE_ENV) === 'production';
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Main function that assembles all project data and starts the MCP server
|
|
17
|
-
*/
|
|
18
|
-
const startProject = async (): Promise<void> => {
|
|
19
|
-
// Read favicon from assets
|
|
20
|
-
const favicon = getAsset('favicon.svg')!;
|
|
21
|
-
|
|
22
|
-
// Assemble all data to pass to the core
|
|
23
|
-
const serverData: McpServerData = {
|
|
24
|
-
// MCP components
|
|
25
|
-
tools,
|
|
26
|
-
toolHandler: handleToolCall,
|
|
27
|
-
|
|
28
|
-
// Prompts
|
|
29
|
-
agentBrief: AGENT_BRIEF,
|
|
30
|
-
agentPrompt: AGENT_PROMPT,
|
|
31
|
-
customPrompts,
|
|
32
|
-
requiredHttpHeaders: [{ name: 'Authorization', description: 'JWT Token issued on request' }],
|
|
33
|
-
// Resources
|
|
34
|
-
customResources,
|
|
35
|
-
|
|
36
|
-
// HTTP components
|
|
37
|
-
httpComponents: {
|
|
38
|
-
apiRouter,
|
|
39
|
-
endpointsOn404,
|
|
40
|
-
swagger: {
|
|
41
|
-
swaggerSpecs: swagger.swaggerSpecs,
|
|
42
|
-
swaggerUi: swagger.swaggerUi,
|
|
43
|
-
},
|
|
44
|
-
},
|
|
45
|
-
|
|
46
|
-
// Assets
|
|
47
|
-
assets: {
|
|
48
|
-
favicon,
|
|
49
|
-
maintainerHtml: '<a href="https://support.com/page/2805" target="_blank" rel="noopener" class="clickable">Support</a>',
|
|
50
|
-
},
|
|
51
|
-
// Function to get Consul UI address (if consul enabled: consul.service.enable = true)
|
|
52
|
-
getConsulUIAddress: (serviceId: string) => {
|
|
53
|
-
const { agent } = appConfig.consul || {};
|
|
54
|
-
if (!agent?.dev?.host || !agent?.prd?.host) {
|
|
55
|
-
return '--consul-ui-not-configured--';
|
|
56
|
-
}
|
|
57
|
-
return `${isConsulProd
|
|
58
|
-
? `https://${agent.prd.host}/ui/dc-msk-infra`
|
|
59
|
-
: `https://${agent.dev.host}/ui/dc-dev`
|
|
60
|
-
}/services/${serviceId}/instances`;
|
|
61
|
-
},
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
// Start MCP server with assembled data
|
|
65
|
-
await initMcpServer(serverData);
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
startProject().catch(error => {
|
|
69
|
-
console.error('Failed to start project:', error);
|
|
70
|
-
process.exit(1);
|
|
71
|
-
});
|