fa-mcp-sdk 0.2.249 → 0.2.258
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/cli-template/FA-MCP-SDK-DOC/00-FA-MCP-SDK-index.md +45 -161
- package/cli-template/FA-MCP-SDK-DOC/01-getting-started.md +71 -226
- package/cli-template/FA-MCP-SDK-DOC/02-1-tools-and-api.md +80 -360
- package/cli-template/FA-MCP-SDK-DOC/02-2-prompts-and-resources.md +191 -342
- package/cli-template/FA-MCP-SDK-DOC/03-configuration.md +141 -279
- package/cli-template/FA-MCP-SDK-DOC/04-authentication.md +73 -522
- package/cli-template/FA-MCP-SDK-DOC/05-ad-authorization.md +68 -419
- package/cli-template/FA-MCP-SDK-DOC/06-utilities.md +64 -447
- package/cli-template/FA-MCP-SDK-DOC/07-testing-and-operations.md +39 -196
- package/cli-template/package.json +2 -1
- package/config/local.yaml +1 -1
- package/dist/core/_types_/types.d.ts +36 -10
- package/dist/core/_types_/types.d.ts.map +1 -1
- package/dist/core/auth/admin-auth.js +1 -1
- package/dist/core/auth/admin-auth.js.map +1 -1
- package/dist/core/auth/middleware.js +8 -8
- package/dist/core/auth/middleware.js.map +1 -1
- package/dist/core/auth/multi-auth.d.ts.map +1 -1
- package/dist/core/auth/multi-auth.js +15 -14
- package/dist/core/auth/multi-auth.js.map +1 -1
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/mcp/create-mcp-server.js +8 -9
- package/dist/core/mcp/create-mcp-server.js.map +1 -1
- package/dist/core/mcp/prompts.d.ts +10 -5
- package/dist/core/mcp/prompts.d.ts.map +1 -1
- package/dist/core/mcp/prompts.js +17 -15
- package/dist/core/mcp/prompts.js.map +1 -1
- package/dist/core/mcp/resources.d.ts +4 -4
- package/dist/core/mcp/resources.d.ts.map +1 -1
- package/dist/core/mcp/resources.js +21 -20
- package/dist/core/mcp/resources.js.map +1 -1
- package/dist/core/utils/utils.d.ts +2 -1
- package/dist/core/utils/utils.d.ts.map +1 -1
- package/dist/core/utils/utils.js +2 -2
- package/dist/core/utils/utils.js.map +1 -1
- package/dist/core/web/home-api.d.ts.map +1 -1
- package/dist/core/web/home-api.js +4 -3
- package/dist/core/web/home-api.js.map +1 -1
- package/dist/core/web/server-http.d.ts.map +1 -1
- package/dist/core/web/server-http.js +36 -21
- package/dist/core/web/server-http.js.map +1 -1
- package/package.json +1 -1
- package/scripts/update-doc.js +21 -0
- package/src/template/start.ts +1 -1
|
@@ -1,529 +1,146 @@
|
|
|
1
1
|
# Utilities, Errors, and Logging
|
|
2
2
|
|
|
3
|
-
## Error
|
|
4
|
-
|
|
5
|
-
### Custom Error Classes
|
|
3
|
+
## Error Classes
|
|
6
4
|
|
|
7
5
|
```typescript
|
|
8
6
|
import { BaseMcpError, ToolExecutionError, ValidationError, ServerError } from 'fa-mcp-sdk';
|
|
9
7
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
super(message, 'CUSTOM_ERROR');
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
// Use built-in error types
|
|
18
|
-
if (!validInput) {
|
|
19
|
-
throw new ValidationError('Input validation failed');
|
|
20
|
-
}
|
|
8
|
+
throw new ValidationError('Input validation failed');
|
|
9
|
+
throw new ToolExecutionError('my_tool', 'Execution failed');
|
|
10
|
+
throw new ServerError('Database connection failed', { key: 'value' });
|
|
21
11
|
|
|
22
|
-
|
|
23
|
-
|
|
12
|
+
// Custom error
|
|
13
|
+
class MyError extends BaseMcpError {
|
|
14
|
+
constructor(msg: string) { super(msg, 'MY_ERROR'); }
|
|
24
15
|
}
|
|
25
16
|
```
|
|
26
17
|
|
|
27
|
-
|
|
18
|
+
**ServerError**: `code: 'SERVER_ERROR'`, `httpStatus: 500`
|
|
28
19
|
|
|
29
|
-
|
|
20
|
+
## Error Utilities
|
|
30
21
|
|
|
31
22
|
```typescript
|
|
32
|
-
import {
|
|
33
|
-
|
|
34
|
-
// Class Definition:
|
|
35
|
-
class ServerError extends BaseMcpError {
|
|
36
|
-
constructor(
|
|
37
|
-
message: string,
|
|
38
|
-
details?: Record<string, unknown>,
|
|
39
|
-
printed?: boolean
|
|
40
|
-
);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// Examples:
|
|
44
|
-
throw new ServerError('Database connection failed');
|
|
45
|
-
|
|
46
|
-
throw new ServerError('Configuration error', {
|
|
47
|
-
configKey: 'webServer.port',
|
|
48
|
-
expected: 'number',
|
|
49
|
-
received: 'string'
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
// With printed flag (prevents duplicate logging)
|
|
53
|
-
throw new ServerError('Internal error', undefined, true);
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
**Properties:**
|
|
57
|
-
- `code`: Always `'SERVER_ERROR'`
|
|
58
|
-
- `httpStatus`: Always `500`
|
|
59
|
-
- `details`: Optional additional error context
|
|
60
|
-
|
|
61
|
-
### Error Utilities
|
|
62
|
-
|
|
63
|
-
```typescript
|
|
64
|
-
import {
|
|
65
|
-
createJsonRpcErrorResponse,
|
|
66
|
-
toError,
|
|
67
|
-
toStr,
|
|
68
|
-
addErrorMessage
|
|
69
|
-
} from 'fa-mcp-sdk';
|
|
70
|
-
|
|
71
|
-
// createJsonRpcErrorResponse - create JSON-RPC 2.0 error response
|
|
72
|
-
// Function Signature:
|
|
73
|
-
function createJsonRpcErrorResponse (
|
|
74
|
-
error: Error | BaseMcpError,
|
|
75
|
-
requestId?: string | number | null,
|
|
76
|
-
): any {...}
|
|
77
|
-
|
|
78
|
-
// Example:
|
|
79
|
-
try {
|
|
80
|
-
// some operation
|
|
81
|
-
} catch (error) {
|
|
82
|
-
const jsonRpcError = createJsonRpcErrorResponse(error, 'request-123');
|
|
83
|
-
res.json(jsonRpcError);
|
|
84
|
-
}
|
|
23
|
+
import { createJsonRpcErrorResponse, toError, toStr, addErrorMessage } from 'fa-mcp-sdk';
|
|
85
24
|
|
|
86
|
-
//
|
|
87
|
-
|
|
88
|
-
const toError = (err: any): Error {...}
|
|
25
|
+
// Create JSON-RPC error response
|
|
26
|
+
const response = createJsonRpcErrorResponse(error, 'request-123');
|
|
89
27
|
|
|
90
|
-
//
|
|
91
|
-
const
|
|
92
|
-
const
|
|
93
|
-
const err3 = toError({ message: 'Object error' }); // Returns new Error('[object Object]')
|
|
28
|
+
// Safe error conversion
|
|
29
|
+
const err = toError(anything); // → Error object
|
|
30
|
+
const msg = toStr(anything); // → string message
|
|
94
31
|
|
|
95
|
-
//
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
// Examples:
|
|
100
|
-
const msg1 = toStr(new Error('Test error')); // Returns 'Test error'
|
|
101
|
-
const msg2 = toStr('String message'); // Returns 'String message'
|
|
102
|
-
const msg3 = toStr(null); // Returns 'Unknown error'
|
|
103
|
-
|
|
104
|
-
// addErrorMessage - add context to existing error message
|
|
105
|
-
// Function Signature:
|
|
106
|
-
const addErrorMessage = (err: any, msg: string): void {...}
|
|
107
|
-
|
|
108
|
-
// Example:
|
|
109
|
-
const originalError = new Error('Connection failed');
|
|
110
|
-
addErrorMessage(originalError, 'Database operation failed');
|
|
111
|
-
// originalError.message is now: 'Database operation failed. Connection failed'
|
|
32
|
+
// Add context to error
|
|
33
|
+
addErrorMessage(error, 'Operation failed');
|
|
34
|
+
// error.message = 'Operation failed. Original message'
|
|
112
35
|
```
|
|
113
36
|
|
|
114
|
-
---
|
|
115
|
-
|
|
116
37
|
## Constants
|
|
117
38
|
|
|
118
|
-
### `ROOT_PROJECT_DIR`
|
|
119
|
-
|
|
120
|
-
Absolute path to the project root directory. Calculated at runtime based on `process.cwd()`.
|
|
121
|
-
|
|
122
39
|
```typescript
|
|
123
40
|
import { ROOT_PROJECT_DIR } from 'fa-mcp-sdk';
|
|
124
41
|
|
|
125
|
-
// Constant Definition:
|
|
126
|
-
const ROOT_PROJECT_DIR: string = process.cwd();
|
|
127
|
-
|
|
128
|
-
// Example usage:
|
|
129
|
-
import * as path from 'path';
|
|
130
|
-
|
|
131
42
|
const configPath = path.join(ROOT_PROJECT_DIR, 'config', 'default.yaml');
|
|
132
|
-
const assetsPath = path.join(ROOT_PROJECT_DIR, 'src', 'assets');
|
|
133
|
-
|
|
134
|
-
console.log('Project root:', ROOT_PROJECT_DIR);
|
|
135
|
-
// Output: /home/user/my-mcp-server
|
|
136
43
|
```
|
|
137
44
|
|
|
138
|
-
|
|
139
|
-
- Building absolute paths to project files
|
|
140
|
-
- Locating configuration files
|
|
141
|
-
- Resolving asset paths
|
|
142
|
-
|
|
143
|
-
---
|
|
144
|
-
|
|
145
|
-
## Utility Functions
|
|
146
|
-
|
|
147
|
-
### General Utilities
|
|
45
|
+
## General Utilities
|
|
148
46
|
|
|
149
47
|
```typescript
|
|
150
|
-
import {
|
|
151
|
-
trim,
|
|
152
|
-
isMainModule,
|
|
153
|
-
isNonEmptyObject,
|
|
154
|
-
isObject,
|
|
155
|
-
ppj,
|
|
156
|
-
encodeSvgForDataUri,
|
|
157
|
-
getAsset
|
|
158
|
-
} from 'fa-mcp-sdk';
|
|
159
|
-
|
|
160
|
-
// trim - safely trim string with null/undefined handling
|
|
161
|
-
// Function Signature:
|
|
162
|
-
const trim = (s: any): string {...}
|
|
163
|
-
|
|
164
|
-
// Examples:
|
|
165
|
-
const cleanText1 = trim(' hello '); // Returns 'hello'
|
|
166
|
-
const cleanText2 = trim(null); // Returns ''
|
|
167
|
-
const cleanText3 = trim(undefined); // Returns ''
|
|
168
|
-
const cleanText4 = trim(123); // Returns '123'
|
|
169
|
-
|
|
170
|
-
// isMainModule - check if current module is the main entry point
|
|
171
|
-
// Function Signature:
|
|
172
|
-
const isMainModule = (url: string): boolean {...}
|
|
173
|
-
|
|
174
|
-
// Example:
|
|
175
|
-
if (isMainModule(import.meta.url)) {
|
|
176
|
-
console.log('Running as main module');
|
|
177
|
-
startServer();
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
// isObject - check if value is an object (not null, not array)
|
|
181
|
-
// Function Signature:
|
|
182
|
-
const isObject = (o: any): boolean {...}
|
|
183
|
-
|
|
184
|
-
// Examples:
|
|
185
|
-
isObject({}); // Returns true
|
|
186
|
-
isObject({ key: 'value' }); // Returns true
|
|
187
|
-
isObject([]); // Returns false
|
|
188
|
-
isObject(null); // Returns false
|
|
189
|
-
isObject('string'); // Returns false
|
|
190
|
-
|
|
191
|
-
// isNonEmptyObject - check if value is non-empty object with defined values
|
|
192
|
-
// Function Signature:
|
|
193
|
-
const isNonEmptyObject = (o: any): boolean {...}
|
|
194
|
-
|
|
195
|
-
// Examples:
|
|
196
|
-
isNonEmptyObject({ key: 'value' }); // Returns true
|
|
197
|
-
isNonEmptyObject({}); // Returns false
|
|
198
|
-
isNonEmptyObject({ key: undefined }); // Returns false
|
|
199
|
-
isNonEmptyObject([]); // Returns false
|
|
200
|
-
|
|
201
|
-
// ppj - pretty-print JSON with 2-space indentation
|
|
202
|
-
// Function Signature:
|
|
203
|
-
const ppj = (v: any): string {...}
|
|
204
|
-
|
|
205
|
-
// Example:
|
|
206
|
-
const formatted = ppj({ user: 'john', age: 30 });
|
|
207
|
-
// Returns:
|
|
208
|
-
// {
|
|
209
|
-
// "user": "john",
|
|
210
|
-
// "age": 30
|
|
211
|
-
// }
|
|
212
|
-
|
|
213
|
-
// encodeSvgForDataUri - encode SVG content for use in data URI
|
|
214
|
-
// Function Signature:
|
|
215
|
-
const encodeSvgForDataUri = (svg: string): string {...}
|
|
216
|
-
|
|
217
|
-
// Example:
|
|
218
|
-
const svgContent = '<svg xmlns="http://www.w3.org/2000/svg"><circle r="10"/></svg>';
|
|
219
|
-
const encoded = encodeSvgForDataUri(svgContent);
|
|
220
|
-
const dataUri = `data:image/svg+xml,${encoded}`;
|
|
48
|
+
import { trim, isMainModule, isObject, isNonEmptyObject, ppj, encodeSvgForDataUri, getAsset } from 'fa-mcp-sdk';
|
|
221
49
|
|
|
222
|
-
//
|
|
223
|
-
//
|
|
224
|
-
|
|
50
|
+
trim(' hello '); // 'hello'
|
|
51
|
+
trim(null); // ''
|
|
52
|
+
isMainModule(import.meta.url); // true if main entry
|
|
53
|
+
isObject({}); // true
|
|
54
|
+
isObject([]); // false
|
|
55
|
+
isNonEmptyObject({}); // false
|
|
56
|
+
isNonEmptyObject({ k: undefined }); // false
|
|
57
|
+
ppj({ user: 'john' }); // Pretty JSON string
|
|
225
58
|
|
|
226
|
-
|
|
227
|
-
const
|
|
228
|
-
const iconContent = getAsset('icons/star.svg'); // Reads from src/asset/icons/star.svg
|
|
59
|
+
const encoded = encodeSvgForDataUri(svgContent);
|
|
60
|
+
const logo = getAsset('logo.svg'); // From src/asset/
|
|
229
61
|
```
|
|
230
62
|
|
|
231
|
-
|
|
63
|
+
## HTTP Utilities
|
|
232
64
|
|
|
233
65
|
```typescript
|
|
234
66
|
import { normalizeHeaders } from 'fa-mcp-sdk';
|
|
235
67
|
|
|
236
|
-
//
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
//
|
|
242
|
-
// - Joins array values with ', ' separator
|
|
243
|
-
// - Filters out null/undefined values
|
|
244
|
-
// - Converts non-string values to strings
|
|
245
|
-
|
|
246
|
-
// Example:
|
|
247
|
-
const rawHeaders = {
|
|
248
|
-
'Authorization': 'Bearer token123',
|
|
249
|
-
'X-Custom-Header': 'value',
|
|
250
|
-
'Accept-Language': ['en', 'ru'],
|
|
251
|
-
'X-Null-Header': null,
|
|
252
|
-
};
|
|
253
|
-
|
|
254
|
-
const normalized = normalizeHeaders(rawHeaders);
|
|
255
|
-
// Result:
|
|
256
|
-
// {
|
|
257
|
-
// 'authorization': 'Bearer token123',
|
|
258
|
-
// 'x-custom-header': 'value',
|
|
259
|
-
// 'accept-language': 'en, ru'
|
|
260
|
-
// }
|
|
261
|
-
|
|
262
|
-
// Common use case - accessing headers in tool handler:
|
|
263
|
-
import { IToolHandlerParams } from 'fa-mcp-sdk';
|
|
264
|
-
|
|
265
|
-
export const handleToolCall = async (params: IToolHandlerParams): Promise<any> => {
|
|
266
|
-
const { headers } = params;
|
|
267
|
-
|
|
268
|
-
// Headers are already normalized by SDK, access with lowercase keys
|
|
269
|
-
const authHeader = headers?.authorization;
|
|
270
|
-
const userAgent = headers?.['user-agent'];
|
|
271
|
-
const clientIP = headers?.['x-real-ip'] || headers?.['x-forwarded-for'];
|
|
272
|
-
|
|
273
|
-
// ...
|
|
274
|
-
};
|
|
68
|
+
// Normalizes to lowercase, joins arrays with ', '
|
|
69
|
+
const normalized = normalizeHeaders({
|
|
70
|
+
'Authorization': 'Bearer token',
|
|
71
|
+
'Accept-Language': ['en', 'ru']
|
|
72
|
+
});
|
|
73
|
+
// { 'authorization': 'Bearer token', 'accept-language': 'en, ru' }
|
|
275
74
|
```
|
|
276
75
|
|
|
277
|
-
|
|
76
|
+
## Tool Utilities
|
|
278
77
|
|
|
279
78
|
```typescript
|
|
280
|
-
import { getTools } from 'fa-mcp-sdk';
|
|
281
|
-
import { Tool } from '@modelcontextprotocol/sdk/types.js';
|
|
79
|
+
import { getTools, formatToolResult, getJsonFromResult } from 'fa-mcp-sdk';
|
|
282
80
|
|
|
283
|
-
|
|
284
|
-
// Function Signature:
|
|
285
|
-
async function getTools(): Promise<Tool[]>;
|
|
81
|
+
const tools = await getTools(); // Get registered tools
|
|
286
82
|
|
|
287
|
-
//
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
// Example:
|
|
291
|
-
const tools = await getTools();
|
|
292
|
-
console.log(`Registered tools: ${tools.length}`);
|
|
293
|
-
tools.forEach(tool => {
|
|
294
|
-
console.log(`- ${tool.name}: ${tool.description}`);
|
|
295
|
-
});
|
|
83
|
+
// Format based on appConfig.mcp.toolAnswerAs
|
|
84
|
+
const result = formatToolResult({ message: 'Done', data: {} });
|
|
296
85
|
|
|
297
|
-
//
|
|
298
|
-
|
|
299
|
-
// - Dynamic tool documentation
|
|
300
|
-
// - Tool validation in tests
|
|
86
|
+
// Extract original JSON from formatted result
|
|
87
|
+
const original = getJsonFromResult<MyType>(result);
|
|
301
88
|
```
|
|
302
89
|
|
|
303
|
-
|
|
90
|
+
## Network Utilities
|
|
304
91
|
|
|
305
92
|
```typescript
|
|
306
93
|
import { isPortAvailable, checkPortAvailability } from 'fa-mcp-sdk';
|
|
307
94
|
|
|
308
|
-
|
|
309
|
-
// Function Signature:
|
|
310
|
-
function isPortAvailable (port: number, host: string = '0.0.0.0'): Promise<boolean> {...}
|
|
95
|
+
const available = await isPortAvailable(3000, 'localhost');
|
|
311
96
|
|
|
312
|
-
//
|
|
313
|
-
|
|
314
|
-
const available2 = await isPortAvailable(1234, 'localhost'); // Check on localhost
|
|
315
|
-
const available3 = await isPortAvailable(1234, '192.168.1.10'); // Check on specific IP
|
|
316
|
-
|
|
317
|
-
if (available1) {
|
|
318
|
-
console.log('Port 3000 is available');
|
|
319
|
-
} else {
|
|
320
|
-
console.log('Port 3000 is occupied');
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
// checkPortAvailability - check port with error handling
|
|
324
|
-
// Function Signature:
|
|
325
|
-
async function checkPortAvailability (
|
|
326
|
-
port: number,
|
|
327
|
-
host: string = '0.0.0.0',
|
|
328
|
-
exitOnError: boolean = true
|
|
329
|
-
): Promise<void> {...}
|
|
330
|
-
|
|
331
|
-
// Examples:
|
|
332
|
-
try {
|
|
333
|
-
// Throws error if port is busy
|
|
334
|
-
await checkPortAvailability(3000, 'localhost', true);
|
|
335
|
-
console.log('Port is available, can start server');
|
|
336
|
-
} catch (error) {
|
|
337
|
-
console.log('Port is busy:', error.message);
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
// Don't exit process on busy port
|
|
341
|
-
try {
|
|
342
|
-
await checkPortAvailability(3000, 'localhost', false);
|
|
343
|
-
console.log('Port is available');
|
|
344
|
-
} catch (error) {
|
|
345
|
-
console.log('Port is occupied, will use different port');
|
|
346
|
-
// Continue execution instead of exiting
|
|
347
|
-
}
|
|
97
|
+
// Throws/exits if port busy
|
|
98
|
+
await checkPortAvailability(3000, 'localhost', true);
|
|
348
99
|
```
|
|
349
100
|
|
|
350
|
-
### Tool Result Formatting
|
|
351
|
-
|
|
352
|
-
```typescript
|
|
353
|
-
import { formatToolResult, getJsonFromResult } from 'fa-mcp-sdk';
|
|
354
|
-
|
|
355
|
-
// formatToolResult - format tool execution results based on configuration
|
|
356
|
-
// Function Signature:
|
|
357
|
-
function formatToolResult (json: any): any {...}
|
|
358
|
-
|
|
359
|
-
// Behavior depends on appConfig.mcp.toolAnswerAs setting:
|
|
360
|
-
// - 'structuredContent': Returns { structuredContent: json }
|
|
361
|
-
// - 'text': Returns { content: [{ type: 'text', text: JSON.stringify(json, null, 2) }] }
|
|
362
|
-
|
|
363
|
-
// Examples:
|
|
364
|
-
const result = {
|
|
365
|
-
message: 'Operation completed',
|
|
366
|
-
data: { count: 42, items: ['a', 'b'] },
|
|
367
|
-
timestamp: new Date().toISOString(),
|
|
368
|
-
};
|
|
369
|
-
|
|
370
|
-
const formattedResult = formatToolResult(result);
|
|
371
|
-
|
|
372
|
-
// If toolAnswerAs = 'structuredContent':
|
|
373
|
-
// {
|
|
374
|
-
// structuredContent: {
|
|
375
|
-
// message: 'Operation completed',
|
|
376
|
-
// data: { count: 42, items: ['a', 'b'] },
|
|
377
|
-
// timestamp: '2025-01-01T12:00:00.000Z'
|
|
378
|
-
// }
|
|
379
|
-
// }
|
|
380
|
-
|
|
381
|
-
// If toolAnswerAs = 'text':
|
|
382
|
-
// {
|
|
383
|
-
// content: [{
|
|
384
|
-
// type: 'text',
|
|
385
|
-
// text: '{\n "message": "Operation completed",\n "data": {\n "count": 42,\n "items": ["a", "b"]\n },\n "timestamp": "2025-01-01T12:00:00.000Z"\n}'
|
|
386
|
-
// }]
|
|
387
|
-
// }
|
|
388
|
-
|
|
389
|
-
// getJsonFromResult - extract original JSON from formatted result
|
|
390
|
-
// Function Signature:
|
|
391
|
-
const getJsonFromResult = <T = any> (result: any): T {...}
|
|
392
|
-
|
|
393
|
-
// Examples:
|
|
394
|
-
const originalData1 = getJsonFromResult<MyDataType>(formattedResult);
|
|
395
|
-
|
|
396
|
-
// Works with both response formats:
|
|
397
|
-
const structuredResponse = { structuredContent: { user: 'john', age: 30 } };
|
|
398
|
-
const textResponse = {
|
|
399
|
-
content: [{ type: 'text', text: '{"user":"john","age":30}' }]
|
|
400
|
-
};
|
|
401
|
-
|
|
402
|
-
const data1 = getJsonFromResult(structuredResponse); // { user: 'john', age: 30 }
|
|
403
|
-
const data2 = getJsonFromResult(textResponse); // { user: 'john', age: 30 }
|
|
404
|
-
```
|
|
405
|
-
|
|
406
|
-
---
|
|
407
|
-
|
|
408
101
|
## Logging
|
|
409
102
|
|
|
410
103
|
```typescript
|
|
411
104
|
import { logger, fileLogger } from 'fa-mcp-sdk';
|
|
412
105
|
|
|
413
|
-
|
|
414
|
-
logger.
|
|
415
|
-
logger.
|
|
416
|
-
logger.error('Error occurred', error);
|
|
106
|
+
logger.info('Server started');
|
|
107
|
+
logger.warn('Warning');
|
|
108
|
+
logger.error('Error', error);
|
|
417
109
|
|
|
418
|
-
|
|
419
|
-
fileLogger.
|
|
420
|
-
|
|
421
|
-
// Ensure file logs are written before shutdown
|
|
422
|
-
await fileLogger.asyncFinish();
|
|
110
|
+
fileLogger.info('To file');
|
|
111
|
+
await fileLogger.asyncFinish(); // Flush before shutdown
|
|
423
112
|
```
|
|
424
113
|
|
|
425
|
-
---
|
|
426
|
-
|
|
427
114
|
## Event System
|
|
428
115
|
|
|
429
116
|
```typescript
|
|
430
117
|
import { eventEmitter } from 'fa-mcp-sdk';
|
|
431
118
|
|
|
432
|
-
|
|
433
|
-
eventEmitter.on('server:started', (data) => {
|
|
434
|
-
console.log('Server started with config:', data);
|
|
435
|
-
});
|
|
436
|
-
|
|
437
|
-
// Emit custom events
|
|
119
|
+
eventEmitter.on('server:started', (data) => console.log(data));
|
|
438
120
|
eventEmitter.emit('custom:event', { data: 'example' });
|
|
439
121
|
```
|
|
440
122
|
|
|
441
|
-
---
|
|
442
|
-
|
|
443
123
|
## Consul Integration
|
|
444
124
|
|
|
445
|
-
If using Consul for service discovery:
|
|
446
|
-
|
|
447
125
|
```typescript
|
|
448
|
-
import {
|
|
449
|
-
getConsulAPI,
|
|
450
|
-
accessPointUpdater,
|
|
451
|
-
deregisterServiceFromConsul
|
|
452
|
-
} from 'fa-mcp-sdk';
|
|
453
|
-
|
|
454
|
-
// getConsulAPI - get configured Consul client instance
|
|
455
|
-
// Function Signature:
|
|
456
|
-
const getConsulAPI = async (): Promise<any> {...}
|
|
457
|
-
|
|
458
|
-
// Returns Consul API client configured from appConfig.consul settings
|
|
459
|
-
// Example:
|
|
460
|
-
const consulApi = await getConsulAPI();
|
|
461
|
-
const services = await consulApi.catalog.service.list();
|
|
462
|
-
console.log('Available services:', services);
|
|
463
|
-
|
|
464
|
-
// deregisterServiceFromConsul - remove service registration from Consul
|
|
465
|
-
// Function Signature:
|
|
466
|
-
const deregisterServiceFromConsul = async (): Promise<void> {...}
|
|
467
|
-
|
|
468
|
-
// Note: This function reads serviceId from command line arguments (process.argv)
|
|
469
|
-
// Usage in command line context:
|
|
470
|
-
// node script.js <serviceId> [agentHost] [agentPort]
|
|
471
|
-
|
|
472
|
-
// Example programmatic usage:
|
|
473
|
-
await deregisterServiceFromConsul();
|
|
126
|
+
import { getConsulAPI, accessPointUpdater, deregisterServiceFromConsul } from 'fa-mcp-sdk';
|
|
474
127
|
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
const accessPointUpdater = {
|
|
478
|
-
start(): void; // Start automatic access point updates
|
|
479
|
-
stop(): void; // Stop automatic access point updates
|
|
480
|
-
}
|
|
128
|
+
const consul = await getConsulAPI();
|
|
129
|
+
const services = await consul.catalog.service.list();
|
|
481
130
|
|
|
482
|
-
//
|
|
483
|
-
accessPointUpdater.
|
|
484
|
-
accessPointUpdater.stop(); // Stop updates (called automatically on shutdown)
|
|
485
|
-
|
|
486
|
-
// Access point configuration in config/default.yaml:
|
|
487
|
-
// accessPoints:
|
|
488
|
-
// myService:
|
|
489
|
-
// title: 'My remote service'
|
|
490
|
-
// host: <host>
|
|
491
|
-
// port: 9999
|
|
492
|
-
// token: '***'
|
|
493
|
-
// noConsul: true
|
|
494
|
-
// consulServiceName: <consulServiceName>
|
|
495
|
-
```
|
|
131
|
+
accessPointUpdater.start(); // Auto-update access points
|
|
132
|
+
accessPointUpdater.stop();
|
|
496
133
|
|
|
497
|
-
|
|
134
|
+
await deregisterServiceFromConsul();
|
|
135
|
+
```
|
|
498
136
|
|
|
499
137
|
## Graceful Shutdown
|
|
500
138
|
|
|
501
139
|
```typescript
|
|
502
140
|
import { gracefulShutdown } from 'fa-mcp-sdk';
|
|
503
141
|
|
|
504
|
-
//
|
|
505
|
-
|
|
506
|
-
async function gracefulShutdown (signal: string, exitCode: number = 0): Promise<void> {...}
|
|
507
|
-
|
|
508
|
-
// Automatically handles:
|
|
509
|
-
// - Stopping Consul service registration
|
|
510
|
-
// - Closing database connections
|
|
511
|
-
// - Flushing file logs
|
|
512
|
-
// - Stopping access point updater
|
|
513
|
-
// - Process exit with specified code
|
|
514
|
-
|
|
515
|
-
// Examples:
|
|
516
|
-
// Manual shutdown
|
|
517
|
-
process.on('SIGUSR2', () => {
|
|
518
|
-
gracefulShutdown('SIGUSR2', 0);
|
|
519
|
-
});
|
|
520
|
-
|
|
521
|
-
// Emergency shutdown
|
|
522
|
-
process.on('uncaughtException', (error) => {
|
|
523
|
-
console.error('Uncaught exception:', error);
|
|
524
|
-
gracefulShutdown('UNCAUGHT_EXCEPTION', 1);
|
|
525
|
-
});
|
|
142
|
+
// Handles: Consul deregistration, DB close, log flush, etc.
|
|
143
|
+
process.on('SIGUSR2', () => gracefulShutdown('SIGUSR2', 0));
|
|
526
144
|
|
|
527
|
-
//
|
|
528
|
-
// in initMcpServer(), so manual registration is only needed for custom signals
|
|
145
|
+
// SDK auto-registers SIGINT/SIGTERM handlers
|
|
529
146
|
```
|