fa-mcp-sdk 0.4.76 → 0.4.77
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/README.md +319 -314
- package/bin/fa-mcp.js +85 -68
- package/cli-template/.claude/agents/javascript-pro.md +276 -276
- package/cli-template/.claude/settings.json +50 -50
- package/cli-template/.claude/skills/upgrade-guide/SKILL.md +2 -1
- package/cli-template/.oxfmtrc.json +41 -0
- package/cli-template/.oxlintrc.json +120 -0
- package/cli-template/CLAUDE.md +358 -355
- package/cli-template/FA-MCP-SDK-DOC/00-FA-MCP-SDK-index.md +132 -132
- package/cli-template/FA-MCP-SDK-DOC/01-getting-started.md +146 -146
- package/cli-template/FA-MCP-SDK-DOC/02-1-tools-and-api.md +431 -431
- package/cli-template/FA-MCP-SDK-DOC/02-2-prompts-and-resources.md +201 -201
- package/cli-template/FA-MCP-SDK-DOC/03-configuration.md +384 -384
- package/cli-template/FA-MCP-SDK-DOC/04-authentication.md +412 -412
- package/cli-template/FA-MCP-SDK-DOC/05-ad-authorization.md +196 -196
- package/cli-template/FA-MCP-SDK-DOC/06-utilities.md +163 -163
- package/cli-template/FA-MCP-SDK-DOC/07-testing-and-operations.md +127 -127
- package/cli-template/jest.config.js +27 -30
- package/cli-template/package.json +10 -5
- package/cli-template/prompt-example-new-MCP.md +101 -101
- package/cli-template/readme-docs/SKILLS.md +1 -1
- package/cli-template/tsconfig.json +58 -58
- package/cli-template/update.cjs +41 -38
- package/config/custom-environment-variables.yaml +63 -63
- package/config/development.yaml +4 -4
- package/config/production.yaml +4 -4
- package/config/test.yaml +26 -26
- package/dist/core/_types_/TNtlm.d.ts.map +1 -1
- package/dist/core/_types_/active-directory-config.d.ts.map +1 -1
- package/dist/core/_types_/config.d.ts.map +1 -1
- package/dist/core/_types_/types.d.ts.map +1 -1
- package/dist/core/ad/group-checker.d.ts.map +1 -1
- package/dist/core/ad/group-checker.js.map +1 -1
- package/dist/core/agent-tester/agent-tester-router.d.ts.map +1 -1
- package/dist/core/agent-tester/agent-tester-router.js +6 -6
- package/dist/core/agent-tester/agent-tester-router.js.map +1 -1
- package/dist/core/agent-tester/check-llm.d.ts.map +1 -1
- package/dist/core/agent-tester/check-llm.js.map +1 -1
- package/dist/core/agent-tester/services/SummaryMemory.d.ts.map +1 -1
- package/dist/core/agent-tester/services/SummaryMemory.js +3 -9
- package/dist/core/agent-tester/services/SummaryMemory.js.map +1 -1
- package/dist/core/agent-tester/services/TesterAgentService.d.ts.map +1 -1
- package/dist/core/agent-tester/services/TesterAgentService.js +25 -27
- package/dist/core/agent-tester/services/TesterAgentService.js.map +1 -1
- package/dist/core/agent-tester/services/TesterMcpClientService.d.ts.map +1 -1
- package/dist/core/agent-tester/services/TesterMcpClientService.js +26 -25
- package/dist/core/agent-tester/services/TesterMcpClientService.js.map +1 -1
- package/dist/core/auth/admin-auth.d.ts.map +1 -1
- package/dist/core/auth/admin-auth.js +5 -5
- package/dist/core/auth/admin-auth.js.map +1 -1
- package/dist/core/auth/agent-tester-auth.d.ts.map +1 -1
- package/dist/core/auth/agent-tester-auth.js +1 -6
- package/dist/core/auth/agent-tester-auth.js.map +1 -1
- package/dist/core/auth/basic.d.ts.map +1 -1
- package/dist/core/auth/basic.js.map +1 -1
- package/dist/core/auth/ip-check.d.ts.map +1 -1
- package/dist/core/auth/ip-check.js +1 -1
- package/dist/core/auth/ip-check.js.map +1 -1
- package/dist/core/auth/jwt.d.ts.map +1 -1
- package/dist/core/auth/jwt.js +1 -1
- package/dist/core/auth/jwt.js.map +1 -1
- package/dist/core/auth/middleware.d.ts.map +1 -1
- package/dist/core/auth/middleware.js +9 -6
- 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 +6 -6
- package/dist/core/auth/multi-auth.js.map +1 -1
- package/dist/core/auth/revocation.d.ts.map +1 -1
- package/dist/core/auth/revocation.js +2 -6
- package/dist/core/auth/revocation.js.map +1 -1
- package/dist/core/auth/token-generator/ntlm/ntlm-auth-options.d.ts.map +1 -1
- package/dist/core/auth/token-generator/ntlm/ntlm-auth-options.js +2 -2
- package/dist/core/auth/token-generator/ntlm/ntlm-auth-options.js.map +1 -1
- package/dist/core/auth/token-generator/ntlm/ntlm-domain-config.js +1 -1
- package/dist/core/auth/token-generator/ntlm/ntlm-domain-config.js.map +1 -1
- package/dist/core/auth/token-generator/ntlm/ntlm-integration.d.ts.map +1 -1
- package/dist/core/auth/token-generator/ntlm/ntlm-integration.js +4 -2
- package/dist/core/auth/token-generator/ntlm/ntlm-integration.js.map +1 -1
- package/dist/core/auth/token-generator/server.d.ts.map +1 -1
- package/dist/core/auth/token-generator/server.js.map +1 -1
- package/dist/core/bootstrap/init-config.d.ts.map +1 -1
- package/dist/core/bootstrap/init-config.js +2 -2
- package/dist/core/bootstrap/init-config.js.map +1 -1
- package/dist/core/bootstrap/startup-info.d.ts.map +1 -1
- package/dist/core/bootstrap/startup-info.js +3 -7
- package/dist/core/bootstrap/startup-info.js.map +1 -1
- package/dist/core/cache/cache.d.ts.map +1 -1
- package/dist/core/cache/cache.js +2 -2
- package/dist/core/cache/cache.js.map +1 -1
- package/dist/core/consul/deregister.d.ts.map +1 -1
- package/dist/core/consul/deregister.js.map +1 -1
- package/dist/core/consul/get-consul-api.d.ts.map +1 -1
- package/dist/core/consul/get-consul-api.js +1 -2
- package/dist/core/consul/get-consul-api.js.map +1 -1
- package/dist/core/db/pg-db.d.ts.map +1 -1
- package/dist/core/db/pg-db.js +3 -3
- package/dist/core/db/pg-db.js.map +1 -1
- package/dist/core/debug.d.ts.map +1 -1
- package/dist/core/debug.js.map +1 -1
- package/dist/core/errors/BaseMcpError.d.ts.map +1 -1
- package/dist/core/errors/BaseMcpError.js.map +1 -1
- package/dist/core/errors/ValidationError.d.ts.map +1 -1
- package/dist/core/errors/ValidationError.js.map +1 -1
- package/dist/core/errors/errors.d.ts.map +1 -1
- package/dist/core/errors/errors.js +1 -1
- package/dist/core/errors/errors.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 -5
- package/dist/core/index.js.map +1 -1
- package/dist/core/init-mcp-server.d.ts.map +1 -1
- package/dist/core/init-mcp-server.js.map +1 -1
- package/dist/core/logger.d.ts.map +1 -1
- package/dist/core/logger.js +1 -1
- package/dist/core/logger.js.map +1 -1
- package/dist/core/mcp/create-mcp-server.d.ts.map +1 -1
- package/dist/core/mcp/create-mcp-server.js +1 -1
- package/dist/core/mcp/create-mcp-server.js.map +1 -1
- package/dist/core/mcp/prompts.d.ts.map +1 -1
- package/dist/core/mcp/prompts.js.map +1 -1
- package/dist/core/mcp/readme-assembler.d.ts.map +1 -1
- package/dist/core/mcp/readme-assembler.js +3 -1
- package/dist/core/mcp/readme-assembler.js.map +1 -1
- package/dist/core/mcp/resources.d.ts.map +1 -1
- package/dist/core/mcp/resources.js.map +1 -1
- package/dist/core/mcp/server-stdio.d.ts.map +1 -1
- package/dist/core/utils/formatToolResult.d.ts.map +1 -1
- package/dist/core/utils/formatToolResult.js.map +1 -1
- package/dist/core/utils/port-checker.d.ts.map +1 -1
- package/dist/core/utils/port-checker.js.map +1 -1
- package/dist/core/utils/rate-limit.d.ts.map +1 -1
- package/dist/core/utils/rate-limit.js +2 -8
- package/dist/core/utils/rate-limit.js.map +1 -1
- package/dist/core/utils/testing/BaseMcpClient.d.ts.map +1 -1
- package/dist/core/utils/testing/BaseMcpClient.js.map +1 -1
- package/dist/core/utils/testing/McpHttpClient.d.ts.map +1 -1
- package/dist/core/utils/testing/McpHttpClient.js +2 -2
- package/dist/core/utils/testing/McpHttpClient.js.map +1 -1
- package/dist/core/utils/testing/McpSseClient.d.ts.map +1 -1
- package/dist/core/utils/testing/McpSseClient.js +3 -8
- package/dist/core/utils/testing/McpSseClient.js.map +1 -1
- package/dist/core/utils/testing/McpStdioClient.d.ts.map +1 -1
- package/dist/core/utils/testing/McpStdioClient.js.map +1 -1
- package/dist/core/utils/testing/McpStreamableHttpClient.d.ts.map +1 -1
- package/dist/core/utils/testing/McpStreamableHttpClient.js +7 -8
- package/dist/core/utils/testing/McpStreamableHttpClient.js.map +1 -1
- package/dist/core/utils/utils.d.ts.map +1 -1
- package/dist/core/utils/utils.js +3 -5
- package/dist/core/utils/utils.js.map +1 -1
- package/dist/core/web/admin-router.d.ts.map +1 -1
- package/dist/core/web/admin-router.js +3 -3
- package/dist/core/web/admin-router.js.map +1 -1
- package/dist/core/web/cors.d.ts.map +1 -1
- package/dist/core/web/cors.js.map +1 -1
- package/dist/core/web/favicon-svg.d.ts.map +1 -1
- package/dist/core/web/favicon-svg.js +1 -5
- package/dist/core/web/favicon-svg.js.map +1 -1
- package/dist/core/web/home-api.d.ts.map +1 -1
- package/dist/core/web/home-api.js +7 -8
- package/dist/core/web/home-api.js.map +1 -1
- package/dist/core/web/openapi.d.ts.map +1 -1
- package/dist/core/web/openapi.js +1 -3
- package/dist/core/web/openapi.js.map +1 -1
- package/dist/core/web/server-http.d.ts.map +1 -1
- package/dist/core/web/server-http.js +4 -4
- package/dist/core/web/server-http.js.map +1 -1
- package/dist/core/web/static/agent-tester/index.html +323 -323
- package/dist/core/web/static/agent-tester/script.js +311 -200
- package/dist/core/web/static/agent-tester/styles.css +1840 -1840
- package/dist/core/web/static/home/index.html +220 -220
- package/dist/core/web/static/home/script.js +72 -43
- package/dist/core/web/static/styles.css +927 -927
- package/dist/core/web/static/token-gen/index.html +136 -136
- package/dist/core/web/static/token-gen/script.js +58 -56
- package/dist/core/web/svg-icons.d.ts.map +1 -1
- package/dist/core/web/svg-icons.js +1 -5
- package/dist/core/web/svg-icons.js.map +1 -1
- package/package.json +10 -5
- package/{cli-template/.claude/hooks/eslint-fix.cjs → scripts/cc-hook-oxlint-oxfmt-fix.cjs} +109 -100
- package/scripts/generate-jwt.js +5 -9
- package/scripts/kill-port.js +5 -2
- package/scripts/npm/run.js +1 -2
- package/scripts/remove-nul.js +1 -1
- package/scripts/update-sdk.js +36 -14
- package/src/template/api/router.ts +3 -3
- package/src/template/prompts/agent-brief.ts +0 -1
- package/src/template/start.ts +3 -8
- package/src/template/tools/handle-tool-call.ts +3 -3
- package/src/template/tools/tools.ts +3 -7
- package/src/tests/jest-simple-reporter.js +1 -1
- package/src/tests/mcp/sse/mcp-sse-client-handling.md +111 -111
- package/src/tests/mcp/sse/test-sse-npm-package.js +2 -3
- package/src/tests/mcp/test-cases.js +6 -7
- package/src/tests/mcp/test-http.js +2 -2
- package/src/tests/mcp/test-sse.js +9 -7
- package/src/tests/mcp/test-stdio.js +12 -8
- package/src/tests/utils.ts +4 -3
- package/cli-template/eslint.config.js +0 -27
|
@@ -1,163 +1,163 @@
|
|
|
1
|
-
# Utilities, Errors, and Logging
|
|
2
|
-
|
|
3
|
-
## Error Classes
|
|
4
|
-
|
|
5
|
-
```typescript
|
|
6
|
-
import { BaseMcpError, ToolExecutionError, ValidationError, ServerError } from 'fa-mcp-sdk';
|
|
7
|
-
|
|
8
|
-
throw new ValidationError('Input validation failed');
|
|
9
|
-
throw new ToolExecutionError('my_tool', 'Execution failed');
|
|
10
|
-
throw new ServerError('Database connection failed', { key: 'value' });
|
|
11
|
-
|
|
12
|
-
// Custom error
|
|
13
|
-
class MyError extends BaseMcpError {
|
|
14
|
-
constructor(msg: string) { super(msg, 'MY_ERROR'); }
|
|
15
|
-
}
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
**ServerError**: `code: 'SERVER_ERROR'`, `httpStatus: 500`
|
|
19
|
-
|
|
20
|
-
## Error Utilities
|
|
21
|
-
|
|
22
|
-
```typescript
|
|
23
|
-
import { createJsonRpcErrorResponse, toError, toStr, addErrorMessage } from 'fa-mcp-sdk';
|
|
24
|
-
|
|
25
|
-
// Create JSON-RPC error response
|
|
26
|
-
const response = createJsonRpcErrorResponse(error, 'request-123');
|
|
27
|
-
|
|
28
|
-
// Safe error conversion
|
|
29
|
-
const err = toError(anything); // → Error object
|
|
30
|
-
const msg = toStr(anything); // → string message
|
|
31
|
-
|
|
32
|
-
// Add context to error
|
|
33
|
-
addErrorMessage(error, 'Operation failed');
|
|
34
|
-
// error.message = 'Operation failed. Original message'
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
## Constants
|
|
38
|
-
|
|
39
|
-
```typescript
|
|
40
|
-
import { ROOT_PROJECT_DIR } from 'fa-mcp-sdk';
|
|
41
|
-
|
|
42
|
-
const configPath = path.join(ROOT_PROJECT_DIR, 'config', 'default.yaml');
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
## General Utilities
|
|
46
|
-
|
|
47
|
-
```typescript
|
|
48
|
-
import { trim, isMainModule, isObject, isNonEmptyObject, ppj, encodeSvgForDataUri, getAsset } from 'fa-mcp-sdk';
|
|
49
|
-
|
|
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
|
|
58
|
-
|
|
59
|
-
const encoded = encodeSvgForDataUri(svgContent);
|
|
60
|
-
const logo = getAsset('logo.svg'); // From src/asset/
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
## HTTP Utilities
|
|
64
|
-
|
|
65
|
-
```typescript
|
|
66
|
-
import { normalizeHeaders } from 'fa-mcp-sdk';
|
|
67
|
-
|
|
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' }
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
## Tool Utilities
|
|
77
|
-
|
|
78
|
-
```typescript
|
|
79
|
-
import { getTools, formatToolResult, getJsonFromResult, asTextContent, asJson } from 'fa-mcp-sdk';
|
|
80
|
-
|
|
81
|
-
const tools = await getTools(); // Get registered tools
|
|
82
|
-
|
|
83
|
-
// Format based on appConfig.mcp.tools.answerAs
|
|
84
|
-
const result = formatToolResult({ message: 'Done', data: {} });
|
|
85
|
-
|
|
86
|
-
// Returns structuredContent or JSON from text depending on appConfig.mcp.tools.answerAs
|
|
87
|
-
const original = getJsonFromResult<T>(result);
|
|
88
|
-
|
|
89
|
-
// Direct formatting helpers (ignore tools.answerAs config):
|
|
90
|
-
asTextContent('Hello'); // { content: [{ type: 'text', text: 'Hello' }] }
|
|
91
|
-
asJson({ status: 'ok' }); // { structuredContent: { status: 'ok' } }
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
### When to Use Which
|
|
95
|
-
|
|
96
|
-
- **`formatToolResult()`** — Primary choice in tool handlers. Respects `appConfig.mcp.tools.answerAs` config.
|
|
97
|
-
- **`asTextContent()` / `asJson()`** — Direct formatting, ignores `tools.answerAs`. Use when specific format needed.
|
|
98
|
-
- **`getJsonFromResult()`** — Inverse of `formatToolResult()`. Extracts JSON from either format. Use in tests.
|
|
99
|
-
|
|
100
|
-
## Network Utilities
|
|
101
|
-
|
|
102
|
-
```typescript
|
|
103
|
-
import { isPortAvailable, checkPortAvailability } from 'fa-mcp-sdk';
|
|
104
|
-
|
|
105
|
-
const available = await isPortAvailable(3000, 'localhost');
|
|
106
|
-
|
|
107
|
-
// Throws/exits if port busy
|
|
108
|
-
await checkPortAvailability(3000, 'localhost', true);
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
## Logging
|
|
112
|
-
|
|
113
|
-
```typescript
|
|
114
|
-
import { logger, fileLogger, Logger } from 'fa-mcp-sdk';
|
|
115
|
-
|
|
116
|
-
logger.info('Server started');
|
|
117
|
-
logger.warn('Warning');
|
|
118
|
-
logger.error('Error', error);
|
|
119
|
-
|
|
120
|
-
fileLogger.info('To file');
|
|
121
|
-
await fileLogger.asyncFinish(); // Flush before shutdown
|
|
122
|
-
|
|
123
|
-
// Logger type for typing custom logger references
|
|
124
|
-
const myLogger: Logger = logger;
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
**`Logger`** — The logger type from 'af-logger-ts' is used to type variables and function parameters.
|
|
128
|
-
|
|
129
|
-
## Event System
|
|
130
|
-
|
|
131
|
-
```typescript
|
|
132
|
-
import { eventEmitter } from 'fa-mcp-sdk';
|
|
133
|
-
|
|
134
|
-
eventEmitter.on('server:started', (data) => console.log(data));
|
|
135
|
-
eventEmitter.emit('custom:event', { data: 'example' });
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
## Consul Integration
|
|
139
|
-
|
|
140
|
-
```typescript
|
|
141
|
-
import { getConsulAPI, accessPointUpdater, deregisterServiceFromConsul } from 'fa-mcp-sdk';
|
|
142
|
-
|
|
143
|
-
const consul = await getConsulAPI();
|
|
144
|
-
const services = await consul.catalog.service.list();
|
|
145
|
-
|
|
146
|
-
// accessPointUpdater is started/stopped by the SDK automatically — see 03-configuration.md → "Access Points".
|
|
147
|
-
// The start()/stop() hooks below are exposed only for tests and diagnostics.
|
|
148
|
-
accessPointUpdater.start();
|
|
149
|
-
accessPointUpdater.stop();
|
|
150
|
-
|
|
151
|
-
await deregisterServiceFromConsul();
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
## Graceful Shutdown
|
|
155
|
-
|
|
156
|
-
```typescript
|
|
157
|
-
import { gracefulShutdown } from 'fa-mcp-sdk';
|
|
158
|
-
|
|
159
|
-
// Handles: Consul deregistration, DB close, log flush, etc.
|
|
160
|
-
process.on('SIGUSR2', () => gracefulShutdown('SIGUSR2', 0));
|
|
161
|
-
|
|
162
|
-
// SDK auto-registers SIGINT/SIGTERM handlers
|
|
163
|
-
```
|
|
1
|
+
# Utilities, Errors, and Logging
|
|
2
|
+
|
|
3
|
+
## Error Classes
|
|
4
|
+
|
|
5
|
+
```typescript
|
|
6
|
+
import { BaseMcpError, ToolExecutionError, ValidationError, ServerError } from 'fa-mcp-sdk';
|
|
7
|
+
|
|
8
|
+
throw new ValidationError('Input validation failed');
|
|
9
|
+
throw new ToolExecutionError('my_tool', 'Execution failed');
|
|
10
|
+
throw new ServerError('Database connection failed', { key: 'value' });
|
|
11
|
+
|
|
12
|
+
// Custom error
|
|
13
|
+
class MyError extends BaseMcpError {
|
|
14
|
+
constructor(msg: string) { super(msg, 'MY_ERROR'); }
|
|
15
|
+
}
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
**ServerError**: `code: 'SERVER_ERROR'`, `httpStatus: 500`
|
|
19
|
+
|
|
20
|
+
## Error Utilities
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
import { createJsonRpcErrorResponse, toError, toStr, addErrorMessage } from 'fa-mcp-sdk';
|
|
24
|
+
|
|
25
|
+
// Create JSON-RPC error response
|
|
26
|
+
const response = createJsonRpcErrorResponse(error, 'request-123');
|
|
27
|
+
|
|
28
|
+
// Safe error conversion
|
|
29
|
+
const err = toError(anything); // → Error object
|
|
30
|
+
const msg = toStr(anything); // → string message
|
|
31
|
+
|
|
32
|
+
// Add context to error
|
|
33
|
+
addErrorMessage(error, 'Operation failed');
|
|
34
|
+
// error.message = 'Operation failed. Original message'
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Constants
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
import { ROOT_PROJECT_DIR } from 'fa-mcp-sdk';
|
|
41
|
+
|
|
42
|
+
const configPath = path.join(ROOT_PROJECT_DIR, 'config', 'default.yaml');
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## General Utilities
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
import { trim, isMainModule, isObject, isNonEmptyObject, ppj, encodeSvgForDataUri, getAsset } from 'fa-mcp-sdk';
|
|
49
|
+
|
|
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
|
|
58
|
+
|
|
59
|
+
const encoded = encodeSvgForDataUri(svgContent);
|
|
60
|
+
const logo = getAsset('logo.svg'); // From src/asset/
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## HTTP Utilities
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
import { normalizeHeaders } from 'fa-mcp-sdk';
|
|
67
|
+
|
|
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' }
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Tool Utilities
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
import { getTools, formatToolResult, getJsonFromResult, asTextContent, asJson } from 'fa-mcp-sdk';
|
|
80
|
+
|
|
81
|
+
const tools = await getTools(); // Get registered tools
|
|
82
|
+
|
|
83
|
+
// Format based on appConfig.mcp.tools.answerAs
|
|
84
|
+
const result = formatToolResult({ message: 'Done', data: {} });
|
|
85
|
+
|
|
86
|
+
// Returns structuredContent or JSON from text depending on appConfig.mcp.tools.answerAs
|
|
87
|
+
const original = getJsonFromResult<T>(result);
|
|
88
|
+
|
|
89
|
+
// Direct formatting helpers (ignore tools.answerAs config):
|
|
90
|
+
asTextContent('Hello'); // { content: [{ type: 'text', text: 'Hello' }] }
|
|
91
|
+
asJson({ status: 'ok' }); // { structuredContent: { status: 'ok' } }
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### When to Use Which
|
|
95
|
+
|
|
96
|
+
- **`formatToolResult()`** — Primary choice in tool handlers. Respects `appConfig.mcp.tools.answerAs` config.
|
|
97
|
+
- **`asTextContent()` / `asJson()`** — Direct formatting, ignores `tools.answerAs`. Use when specific format needed.
|
|
98
|
+
- **`getJsonFromResult()`** — Inverse of `formatToolResult()`. Extracts JSON from either format. Use in tests.
|
|
99
|
+
|
|
100
|
+
## Network Utilities
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
import { isPortAvailable, checkPortAvailability } from 'fa-mcp-sdk';
|
|
104
|
+
|
|
105
|
+
const available = await isPortAvailable(3000, 'localhost');
|
|
106
|
+
|
|
107
|
+
// Throws/exits if port busy
|
|
108
|
+
await checkPortAvailability(3000, 'localhost', true);
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Logging
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
import { logger, fileLogger, Logger } from 'fa-mcp-sdk';
|
|
115
|
+
|
|
116
|
+
logger.info('Server started');
|
|
117
|
+
logger.warn('Warning');
|
|
118
|
+
logger.error('Error', error);
|
|
119
|
+
|
|
120
|
+
fileLogger.info('To file');
|
|
121
|
+
await fileLogger.asyncFinish(); // Flush before shutdown
|
|
122
|
+
|
|
123
|
+
// Logger type for typing custom logger references
|
|
124
|
+
const myLogger: Logger = logger;
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
**`Logger`** — The logger type from 'af-logger-ts' is used to type variables and function parameters.
|
|
128
|
+
|
|
129
|
+
## Event System
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
import { eventEmitter } from 'fa-mcp-sdk';
|
|
133
|
+
|
|
134
|
+
eventEmitter.on('server:started', (data) => console.log(data));
|
|
135
|
+
eventEmitter.emit('custom:event', { data: 'example' });
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Consul Integration
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
import { getConsulAPI, accessPointUpdater, deregisterServiceFromConsul } from 'fa-mcp-sdk';
|
|
142
|
+
|
|
143
|
+
const consul = await getConsulAPI();
|
|
144
|
+
const services = await consul.catalog.service.list();
|
|
145
|
+
|
|
146
|
+
// accessPointUpdater is started/stopped by the SDK automatically — see 03-configuration.md → "Access Points".
|
|
147
|
+
// The start()/stop() hooks below are exposed only for tests and diagnostics.
|
|
148
|
+
accessPointUpdater.start();
|
|
149
|
+
accessPointUpdater.stop();
|
|
150
|
+
|
|
151
|
+
await deregisterServiceFromConsul();
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Graceful Shutdown
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
import { gracefulShutdown } from 'fa-mcp-sdk';
|
|
158
|
+
|
|
159
|
+
// Handles: Consul deregistration, DB close, log flush, etc.
|
|
160
|
+
process.on('SIGUSR2', () => gracefulShutdown('SIGUSR2', 0));
|
|
161
|
+
|
|
162
|
+
// SDK auto-registers SIGINT/SIGTERM handlers
|
|
163
|
+
```
|
|
@@ -1,127 +1,127 @@
|
|
|
1
|
-
# Testing and Operations
|
|
2
|
-
|
|
3
|
-
## Test Clients
|
|
4
|
-
|
|
5
|
-
### STDIO Transport
|
|
6
|
-
|
|
7
|
-
```typescript
|
|
8
|
-
import { McpStdioClient } from 'fa-mcp-sdk';
|
|
9
|
-
import { spawn } from 'child_process';
|
|
10
|
-
|
|
11
|
-
const proc = spawn('node', ['dist/start.js', 'stdio'], {
|
|
12
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
13
|
-
env: { ...process.env, NODE_ENV: 'test' },
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
const client = new McpStdioClient(proc);
|
|
17
|
-
const result = await client.callTool('my_tool', { query: 'test' });
|
|
18
|
-
const prompt = await client.getPrompt('agent_brief');
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
### HTTP Transport
|
|
22
|
-
|
|
23
|
-
```typescript
|
|
24
|
-
import { McpHttpClient } from 'fa-mcp-sdk';
|
|
25
|
-
|
|
26
|
-
const client = new McpHttpClient('http://localhost:3000');
|
|
27
|
-
const result = await client.callTool('my_tool', { query: 'test' }, {
|
|
28
|
-
'Authorization': 'Bearer token'
|
|
29
|
-
});
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
### SSE Transport
|
|
33
|
-
|
|
34
|
-
```typescript
|
|
35
|
-
import { McpSseClient } from 'fa-mcp-sdk';
|
|
36
|
-
|
|
37
|
-
const client = new McpSseClient('http://localhost:3000');
|
|
38
|
-
const result = await client.callTool('my_tool', { query: 'test' });
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
### Streamable HTTP (MCP 2025)
|
|
42
|
-
|
|
43
|
-
```typescript
|
|
44
|
-
import { McpStreamableHttpClient } from 'fa-mcp-sdk';
|
|
45
|
-
|
|
46
|
-
const client = new McpStreamableHttpClient('http://localhost:3000', {
|
|
47
|
-
headers: { 'Authorization': 'Bearer token' },
|
|
48
|
-
requestTimeoutMs: 60000,
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
await client.initialize({
|
|
52
|
-
protocolVersion: '2024-11-05',
|
|
53
|
-
clientInfo: { name: 'test-client', version: '1.0.0' },
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
const result = await client.callTool('my_tool', { query: 'test' });
|
|
57
|
-
const prompt = await client.getPrompt('agent_brief');
|
|
58
|
-
const resources = await client.listResources();
|
|
59
|
-
const content = await client.readResource('custom://data');
|
|
60
|
-
|
|
61
|
-
// Notifications
|
|
62
|
-
const unsub = client.onNotification('notifications/tools/list_changed', (p) => console.log(p));
|
|
63
|
-
|
|
64
|
-
await client.close();
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
**Methods:** `initialize`, `close`, `callTool`, `getPrompt`, `listResources`, `readResource`, `listTools`, `listPrompts`, `sendRpc`, `notify`, `onNotification`
|
|
68
|
-
|
|
69
|
-
## Transport Types
|
|
70
|
-
|
|
71
|
-
| Transport | Config | Use Case |
|
|
72
|
-
|-----------|--------|----------|
|
|
73
|
-
| STDIO | `mcp.transportType: "stdio"` | CLI, local dev |
|
|
74
|
-
| HTTP | `mcp.transportType: "http"` | Web integrations, REST API |
|
|
75
|
-
| SSE | HTTP transport | Long-running ops, streaming |
|
|
76
|
-
|
|
77
|
-
## Running Tests
|
|
78
|
-
|
|
79
|
-
```bash
|
|
80
|
-
npm test # All tests (Jest)
|
|
81
|
-
npx jest tests/path/file.test.ts # Single file
|
|
82
|
-
npx jest --testNamePattern="pattern" # Filter by test name
|
|
83
|
-
npm run test:mcp # STDIO transport tests
|
|
84
|
-
npm run test:mcp-http # HTTP transport tests
|
|
85
|
-
npm run test:mcp-sse # SSE transport tests
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
### Auth Headers for Tests
|
|
89
|
-
|
|
90
|
-
```typescript
|
|
91
|
-
import { getAuthHeadersForTests } from 'fa-mcp-sdk';
|
|
92
|
-
|
|
93
|
-
const headers = getAuthHeadersForTests(); // Uses config auth settings
|
|
94
|
-
const result = await client.callTool('my_tool', { query: 'test' }, headers);
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
### What to Test
|
|
98
|
-
|
|
99
|
-
- **Happy path** — tool returns expected result for valid input
|
|
100
|
-
- **Error cases** — invalid params, missing required fields, service errors
|
|
101
|
-
- **Auth flows** — authenticated vs unauthenticated, different auth methods
|
|
102
|
-
- **Transport parity** — same behavior across STDIO, HTTP, SSE
|
|
103
|
-
- **Edge cases** — empty strings, large payloads, special characters
|
|
104
|
-
|
|
105
|
-
## Best Practices
|
|
106
|
-
|
|
107
|
-
### Project Organization
|
|
108
|
-
- One responsibility per tool
|
|
109
|
-
- Use TypeScript throughout
|
|
110
|
-
- Separate configs for dev/prod
|
|
111
|
-
|
|
112
|
-
### Tool Development
|
|
113
|
-
- Validate all inputs
|
|
114
|
-
- Use `formatToolResult()` for responses
|
|
115
|
-
- Use error classes for failures
|
|
116
|
-
- Log operations with `logger`
|
|
117
|
-
|
|
118
|
-
### Testing
|
|
119
|
-
- Test all transport types
|
|
120
|
-
- Include error cases
|
|
121
|
-
- Use provided test clients
|
|
122
|
-
|
|
123
|
-
### Security
|
|
124
|
-
- Environment variables for secrets
|
|
125
|
-
- Enable auth for production
|
|
126
|
-
- Validate all user inputs
|
|
127
|
-
- Don't leak sensitive info in errors
|
|
1
|
+
# Testing and Operations
|
|
2
|
+
|
|
3
|
+
## Test Clients
|
|
4
|
+
|
|
5
|
+
### STDIO Transport
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
import { McpStdioClient } from 'fa-mcp-sdk';
|
|
9
|
+
import { spawn } from 'child_process';
|
|
10
|
+
|
|
11
|
+
const proc = spawn('node', ['dist/start.js', 'stdio'], {
|
|
12
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
13
|
+
env: { ...process.env, NODE_ENV: 'test' },
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
const client = new McpStdioClient(proc);
|
|
17
|
+
const result = await client.callTool('my_tool', { query: 'test' });
|
|
18
|
+
const prompt = await client.getPrompt('agent_brief');
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### HTTP Transport
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
import { McpHttpClient } from 'fa-mcp-sdk';
|
|
25
|
+
|
|
26
|
+
const client = new McpHttpClient('http://localhost:3000');
|
|
27
|
+
const result = await client.callTool('my_tool', { query: 'test' }, {
|
|
28
|
+
'Authorization': 'Bearer token'
|
|
29
|
+
});
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### SSE Transport
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
import { McpSseClient } from 'fa-mcp-sdk';
|
|
36
|
+
|
|
37
|
+
const client = new McpSseClient('http://localhost:3000');
|
|
38
|
+
const result = await client.callTool('my_tool', { query: 'test' });
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Streamable HTTP (MCP 2025)
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
import { McpStreamableHttpClient } from 'fa-mcp-sdk';
|
|
45
|
+
|
|
46
|
+
const client = new McpStreamableHttpClient('http://localhost:3000', {
|
|
47
|
+
headers: { 'Authorization': 'Bearer token' },
|
|
48
|
+
requestTimeoutMs: 60000,
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
await client.initialize({
|
|
52
|
+
protocolVersion: '2024-11-05',
|
|
53
|
+
clientInfo: { name: 'test-client', version: '1.0.0' },
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
const result = await client.callTool('my_tool', { query: 'test' });
|
|
57
|
+
const prompt = await client.getPrompt('agent_brief');
|
|
58
|
+
const resources = await client.listResources();
|
|
59
|
+
const content = await client.readResource('custom://data');
|
|
60
|
+
|
|
61
|
+
// Notifications
|
|
62
|
+
const unsub = client.onNotification('notifications/tools/list_changed', (p) => console.log(p));
|
|
63
|
+
|
|
64
|
+
await client.close();
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
**Methods:** `initialize`, `close`, `callTool`, `getPrompt`, `listResources`, `readResource`, `listTools`, `listPrompts`, `sendRpc`, `notify`, `onNotification`
|
|
68
|
+
|
|
69
|
+
## Transport Types
|
|
70
|
+
|
|
71
|
+
| Transport | Config | Use Case |
|
|
72
|
+
|-----------|--------|----------|
|
|
73
|
+
| STDIO | `mcp.transportType: "stdio"` | CLI, local dev |
|
|
74
|
+
| HTTP | `mcp.transportType: "http"` | Web integrations, REST API |
|
|
75
|
+
| SSE | HTTP transport | Long-running ops, streaming |
|
|
76
|
+
|
|
77
|
+
## Running Tests
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
npm test # All tests (Jest)
|
|
81
|
+
npx jest tests/path/file.test.ts # Single file
|
|
82
|
+
npx jest --testNamePattern="pattern" # Filter by test name
|
|
83
|
+
npm run test:mcp # STDIO transport tests
|
|
84
|
+
npm run test:mcp-http # HTTP transport tests
|
|
85
|
+
npm run test:mcp-sse # SSE transport tests
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Auth Headers for Tests
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
import { getAuthHeadersForTests } from 'fa-mcp-sdk';
|
|
92
|
+
|
|
93
|
+
const headers = getAuthHeadersForTests(); // Uses config auth settings
|
|
94
|
+
const result = await client.callTool('my_tool', { query: 'test' }, headers);
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### What to Test
|
|
98
|
+
|
|
99
|
+
- **Happy path** — tool returns expected result for valid input
|
|
100
|
+
- **Error cases** — invalid params, missing required fields, service errors
|
|
101
|
+
- **Auth flows** — authenticated vs unauthenticated, different auth methods
|
|
102
|
+
- **Transport parity** — same behavior across STDIO, HTTP, SSE
|
|
103
|
+
- **Edge cases** — empty strings, large payloads, special characters
|
|
104
|
+
|
|
105
|
+
## Best Practices
|
|
106
|
+
|
|
107
|
+
### Project Organization
|
|
108
|
+
- One responsibility per tool
|
|
109
|
+
- Use TypeScript throughout
|
|
110
|
+
- Separate configs for dev/prod
|
|
111
|
+
|
|
112
|
+
### Tool Development
|
|
113
|
+
- Validate all inputs
|
|
114
|
+
- Use `formatToolResult()` for responses
|
|
115
|
+
- Use error classes for failures
|
|
116
|
+
- Log operations with `logger`
|
|
117
|
+
|
|
118
|
+
### Testing
|
|
119
|
+
- Test all transport types
|
|
120
|
+
- Include error cases
|
|
121
|
+
- Use provided test clients
|
|
122
|
+
|
|
123
|
+
### Security
|
|
124
|
+
- Environment variables for secrets
|
|
125
|
+
- Enable auth for production
|
|
126
|
+
- Validate all user inputs
|
|
127
|
+
- Don't leak sensitive info in errors
|
|
@@ -1,30 +1,27 @@
|
|
|
1
|
-
export default {
|
|
2
|
-
preset: 'ts-jest',
|
|
3
|
-
testEnvironment: 'node',
|
|
4
|
-
testMatch: ['**/tests/**/*.test.ts', '**/tests/**/*.spec.ts'],
|
|
5
|
-
collectCoverageFrom: [
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
detectOpenHandles: true,
|
|
29
|
-
testTimeout: 10000
|
|
30
|
-
};
|
|
1
|
+
export default {
|
|
2
|
+
preset: 'ts-jest',
|
|
3
|
+
testEnvironment: 'node',
|
|
4
|
+
testMatch: ['**/tests/**/*.test.ts', '**/tests/**/*.spec.ts'],
|
|
5
|
+
collectCoverageFrom: ['src/**/*.ts', '!src/**/*.d.ts', '!src/index.ts'],
|
|
6
|
+
coverageDirectory: 'coverage',
|
|
7
|
+
coverageReporters: ['text', 'lcov'],
|
|
8
|
+
verbose: false,
|
|
9
|
+
silent: true,
|
|
10
|
+
reporters: ['<rootDir>/tests/jest-simple-reporter.js'],
|
|
11
|
+
moduleNameMapper: {
|
|
12
|
+
'^(\\.{1,2}/.*)\\.js$': '$1',
|
|
13
|
+
},
|
|
14
|
+
transform: {
|
|
15
|
+
'^.+\\.ts$': [
|
|
16
|
+
'ts-jest',
|
|
17
|
+
{
|
|
18
|
+
useESM: true,
|
|
19
|
+
},
|
|
20
|
+
],
|
|
21
|
+
},
|
|
22
|
+
transformIgnorePatterns: ['node_modules/(?!(chalk|@modelcontextprotocol|af-.*)/)'],
|
|
23
|
+
extensionsToTreatAsEsm: ['.ts'],
|
|
24
|
+
forceExit: true,
|
|
25
|
+
detectOpenHandles: true,
|
|
26
|
+
testTimeout: 10000,
|
|
27
|
+
};
|