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.
Files changed (198) hide show
  1. package/README.md +319 -314
  2. package/bin/fa-mcp.js +85 -68
  3. package/cli-template/.claude/agents/javascript-pro.md +276 -276
  4. package/cli-template/.claude/settings.json +50 -50
  5. package/cli-template/.claude/skills/upgrade-guide/SKILL.md +2 -1
  6. package/cli-template/.oxfmtrc.json +41 -0
  7. package/cli-template/.oxlintrc.json +120 -0
  8. package/cli-template/CLAUDE.md +358 -355
  9. package/cli-template/FA-MCP-SDK-DOC/00-FA-MCP-SDK-index.md +132 -132
  10. package/cli-template/FA-MCP-SDK-DOC/01-getting-started.md +146 -146
  11. package/cli-template/FA-MCP-SDK-DOC/02-1-tools-and-api.md +431 -431
  12. package/cli-template/FA-MCP-SDK-DOC/02-2-prompts-and-resources.md +201 -201
  13. package/cli-template/FA-MCP-SDK-DOC/03-configuration.md +384 -384
  14. package/cli-template/FA-MCP-SDK-DOC/04-authentication.md +412 -412
  15. package/cli-template/FA-MCP-SDK-DOC/05-ad-authorization.md +196 -196
  16. package/cli-template/FA-MCP-SDK-DOC/06-utilities.md +163 -163
  17. package/cli-template/FA-MCP-SDK-DOC/07-testing-and-operations.md +127 -127
  18. package/cli-template/jest.config.js +27 -30
  19. package/cli-template/package.json +10 -5
  20. package/cli-template/prompt-example-new-MCP.md +101 -101
  21. package/cli-template/readme-docs/SKILLS.md +1 -1
  22. package/cli-template/tsconfig.json +58 -58
  23. package/cli-template/update.cjs +41 -38
  24. package/config/custom-environment-variables.yaml +63 -63
  25. package/config/development.yaml +4 -4
  26. package/config/production.yaml +4 -4
  27. package/config/test.yaml +26 -26
  28. package/dist/core/_types_/TNtlm.d.ts.map +1 -1
  29. package/dist/core/_types_/active-directory-config.d.ts.map +1 -1
  30. package/dist/core/_types_/config.d.ts.map +1 -1
  31. package/dist/core/_types_/types.d.ts.map +1 -1
  32. package/dist/core/ad/group-checker.d.ts.map +1 -1
  33. package/dist/core/ad/group-checker.js.map +1 -1
  34. package/dist/core/agent-tester/agent-tester-router.d.ts.map +1 -1
  35. package/dist/core/agent-tester/agent-tester-router.js +6 -6
  36. package/dist/core/agent-tester/agent-tester-router.js.map +1 -1
  37. package/dist/core/agent-tester/check-llm.d.ts.map +1 -1
  38. package/dist/core/agent-tester/check-llm.js.map +1 -1
  39. package/dist/core/agent-tester/services/SummaryMemory.d.ts.map +1 -1
  40. package/dist/core/agent-tester/services/SummaryMemory.js +3 -9
  41. package/dist/core/agent-tester/services/SummaryMemory.js.map +1 -1
  42. package/dist/core/agent-tester/services/TesterAgentService.d.ts.map +1 -1
  43. package/dist/core/agent-tester/services/TesterAgentService.js +25 -27
  44. package/dist/core/agent-tester/services/TesterAgentService.js.map +1 -1
  45. package/dist/core/agent-tester/services/TesterMcpClientService.d.ts.map +1 -1
  46. package/dist/core/agent-tester/services/TesterMcpClientService.js +26 -25
  47. package/dist/core/agent-tester/services/TesterMcpClientService.js.map +1 -1
  48. package/dist/core/auth/admin-auth.d.ts.map +1 -1
  49. package/dist/core/auth/admin-auth.js +5 -5
  50. package/dist/core/auth/admin-auth.js.map +1 -1
  51. package/dist/core/auth/agent-tester-auth.d.ts.map +1 -1
  52. package/dist/core/auth/agent-tester-auth.js +1 -6
  53. package/dist/core/auth/agent-tester-auth.js.map +1 -1
  54. package/dist/core/auth/basic.d.ts.map +1 -1
  55. package/dist/core/auth/basic.js.map +1 -1
  56. package/dist/core/auth/ip-check.d.ts.map +1 -1
  57. package/dist/core/auth/ip-check.js +1 -1
  58. package/dist/core/auth/ip-check.js.map +1 -1
  59. package/dist/core/auth/jwt.d.ts.map +1 -1
  60. package/dist/core/auth/jwt.js +1 -1
  61. package/dist/core/auth/jwt.js.map +1 -1
  62. package/dist/core/auth/middleware.d.ts.map +1 -1
  63. package/dist/core/auth/middleware.js +9 -6
  64. package/dist/core/auth/middleware.js.map +1 -1
  65. package/dist/core/auth/multi-auth.d.ts.map +1 -1
  66. package/dist/core/auth/multi-auth.js +6 -6
  67. package/dist/core/auth/multi-auth.js.map +1 -1
  68. package/dist/core/auth/revocation.d.ts.map +1 -1
  69. package/dist/core/auth/revocation.js +2 -6
  70. package/dist/core/auth/revocation.js.map +1 -1
  71. package/dist/core/auth/token-generator/ntlm/ntlm-auth-options.d.ts.map +1 -1
  72. package/dist/core/auth/token-generator/ntlm/ntlm-auth-options.js +2 -2
  73. package/dist/core/auth/token-generator/ntlm/ntlm-auth-options.js.map +1 -1
  74. package/dist/core/auth/token-generator/ntlm/ntlm-domain-config.js +1 -1
  75. package/dist/core/auth/token-generator/ntlm/ntlm-domain-config.js.map +1 -1
  76. package/dist/core/auth/token-generator/ntlm/ntlm-integration.d.ts.map +1 -1
  77. package/dist/core/auth/token-generator/ntlm/ntlm-integration.js +4 -2
  78. package/dist/core/auth/token-generator/ntlm/ntlm-integration.js.map +1 -1
  79. package/dist/core/auth/token-generator/server.d.ts.map +1 -1
  80. package/dist/core/auth/token-generator/server.js.map +1 -1
  81. package/dist/core/bootstrap/init-config.d.ts.map +1 -1
  82. package/dist/core/bootstrap/init-config.js +2 -2
  83. package/dist/core/bootstrap/init-config.js.map +1 -1
  84. package/dist/core/bootstrap/startup-info.d.ts.map +1 -1
  85. package/dist/core/bootstrap/startup-info.js +3 -7
  86. package/dist/core/bootstrap/startup-info.js.map +1 -1
  87. package/dist/core/cache/cache.d.ts.map +1 -1
  88. package/dist/core/cache/cache.js +2 -2
  89. package/dist/core/cache/cache.js.map +1 -1
  90. package/dist/core/consul/deregister.d.ts.map +1 -1
  91. package/dist/core/consul/deregister.js.map +1 -1
  92. package/dist/core/consul/get-consul-api.d.ts.map +1 -1
  93. package/dist/core/consul/get-consul-api.js +1 -2
  94. package/dist/core/consul/get-consul-api.js.map +1 -1
  95. package/dist/core/db/pg-db.d.ts.map +1 -1
  96. package/dist/core/db/pg-db.js +3 -3
  97. package/dist/core/db/pg-db.js.map +1 -1
  98. package/dist/core/debug.d.ts.map +1 -1
  99. package/dist/core/debug.js.map +1 -1
  100. package/dist/core/errors/BaseMcpError.d.ts.map +1 -1
  101. package/dist/core/errors/BaseMcpError.js.map +1 -1
  102. package/dist/core/errors/ValidationError.d.ts.map +1 -1
  103. package/dist/core/errors/ValidationError.js.map +1 -1
  104. package/dist/core/errors/errors.d.ts.map +1 -1
  105. package/dist/core/errors/errors.js +1 -1
  106. package/dist/core/errors/errors.js.map +1 -1
  107. package/dist/core/index.d.ts +6 -6
  108. package/dist/core/index.d.ts.map +1 -1
  109. package/dist/core/index.js +5 -5
  110. package/dist/core/index.js.map +1 -1
  111. package/dist/core/init-mcp-server.d.ts.map +1 -1
  112. package/dist/core/init-mcp-server.js.map +1 -1
  113. package/dist/core/logger.d.ts.map +1 -1
  114. package/dist/core/logger.js +1 -1
  115. package/dist/core/logger.js.map +1 -1
  116. package/dist/core/mcp/create-mcp-server.d.ts.map +1 -1
  117. package/dist/core/mcp/create-mcp-server.js +1 -1
  118. package/dist/core/mcp/create-mcp-server.js.map +1 -1
  119. package/dist/core/mcp/prompts.d.ts.map +1 -1
  120. package/dist/core/mcp/prompts.js.map +1 -1
  121. package/dist/core/mcp/readme-assembler.d.ts.map +1 -1
  122. package/dist/core/mcp/readme-assembler.js +3 -1
  123. package/dist/core/mcp/readme-assembler.js.map +1 -1
  124. package/dist/core/mcp/resources.d.ts.map +1 -1
  125. package/dist/core/mcp/resources.js.map +1 -1
  126. package/dist/core/mcp/server-stdio.d.ts.map +1 -1
  127. package/dist/core/utils/formatToolResult.d.ts.map +1 -1
  128. package/dist/core/utils/formatToolResult.js.map +1 -1
  129. package/dist/core/utils/port-checker.d.ts.map +1 -1
  130. package/dist/core/utils/port-checker.js.map +1 -1
  131. package/dist/core/utils/rate-limit.d.ts.map +1 -1
  132. package/dist/core/utils/rate-limit.js +2 -8
  133. package/dist/core/utils/rate-limit.js.map +1 -1
  134. package/dist/core/utils/testing/BaseMcpClient.d.ts.map +1 -1
  135. package/dist/core/utils/testing/BaseMcpClient.js.map +1 -1
  136. package/dist/core/utils/testing/McpHttpClient.d.ts.map +1 -1
  137. package/dist/core/utils/testing/McpHttpClient.js +2 -2
  138. package/dist/core/utils/testing/McpHttpClient.js.map +1 -1
  139. package/dist/core/utils/testing/McpSseClient.d.ts.map +1 -1
  140. package/dist/core/utils/testing/McpSseClient.js +3 -8
  141. package/dist/core/utils/testing/McpSseClient.js.map +1 -1
  142. package/dist/core/utils/testing/McpStdioClient.d.ts.map +1 -1
  143. package/dist/core/utils/testing/McpStdioClient.js.map +1 -1
  144. package/dist/core/utils/testing/McpStreamableHttpClient.d.ts.map +1 -1
  145. package/dist/core/utils/testing/McpStreamableHttpClient.js +7 -8
  146. package/dist/core/utils/testing/McpStreamableHttpClient.js.map +1 -1
  147. package/dist/core/utils/utils.d.ts.map +1 -1
  148. package/dist/core/utils/utils.js +3 -5
  149. package/dist/core/utils/utils.js.map +1 -1
  150. package/dist/core/web/admin-router.d.ts.map +1 -1
  151. package/dist/core/web/admin-router.js +3 -3
  152. package/dist/core/web/admin-router.js.map +1 -1
  153. package/dist/core/web/cors.d.ts.map +1 -1
  154. package/dist/core/web/cors.js.map +1 -1
  155. package/dist/core/web/favicon-svg.d.ts.map +1 -1
  156. package/dist/core/web/favicon-svg.js +1 -5
  157. package/dist/core/web/favicon-svg.js.map +1 -1
  158. package/dist/core/web/home-api.d.ts.map +1 -1
  159. package/dist/core/web/home-api.js +7 -8
  160. package/dist/core/web/home-api.js.map +1 -1
  161. package/dist/core/web/openapi.d.ts.map +1 -1
  162. package/dist/core/web/openapi.js +1 -3
  163. package/dist/core/web/openapi.js.map +1 -1
  164. package/dist/core/web/server-http.d.ts.map +1 -1
  165. package/dist/core/web/server-http.js +4 -4
  166. package/dist/core/web/server-http.js.map +1 -1
  167. package/dist/core/web/static/agent-tester/index.html +323 -323
  168. package/dist/core/web/static/agent-tester/script.js +311 -200
  169. package/dist/core/web/static/agent-tester/styles.css +1840 -1840
  170. package/dist/core/web/static/home/index.html +220 -220
  171. package/dist/core/web/static/home/script.js +72 -43
  172. package/dist/core/web/static/styles.css +927 -927
  173. package/dist/core/web/static/token-gen/index.html +136 -136
  174. package/dist/core/web/static/token-gen/script.js +58 -56
  175. package/dist/core/web/svg-icons.d.ts.map +1 -1
  176. package/dist/core/web/svg-icons.js +1 -5
  177. package/dist/core/web/svg-icons.js.map +1 -1
  178. package/package.json +10 -5
  179. package/{cli-template/.claude/hooks/eslint-fix.cjs → scripts/cc-hook-oxlint-oxfmt-fix.cjs} +109 -100
  180. package/scripts/generate-jwt.js +5 -9
  181. package/scripts/kill-port.js +5 -2
  182. package/scripts/npm/run.js +1 -2
  183. package/scripts/remove-nul.js +1 -1
  184. package/scripts/update-sdk.js +36 -14
  185. package/src/template/api/router.ts +3 -3
  186. package/src/template/prompts/agent-brief.ts +0 -1
  187. package/src/template/start.ts +3 -8
  188. package/src/template/tools/handle-tool-call.ts +3 -3
  189. package/src/template/tools/tools.ts +3 -7
  190. package/src/tests/jest-simple-reporter.js +1 -1
  191. package/src/tests/mcp/sse/mcp-sse-client-handling.md +111 -111
  192. package/src/tests/mcp/sse/test-sse-npm-package.js +2 -3
  193. package/src/tests/mcp/test-cases.js +6 -7
  194. package/src/tests/mcp/test-http.js +2 -2
  195. package/src/tests/mcp/test-sse.js +9 -7
  196. package/src/tests/mcp/test-stdio.js +12 -8
  197. package/src/tests/utils.ts +4 -3
  198. package/cli-template/eslint.config.js +0 -27
@@ -1,384 +1,384 @@
1
- # Configuration, Cache, and Access Points
2
-
3
- ## Custom Startup Diagnostics
4
-
5
- You can add custom key-value pairs to the startup diagnostic output by passing `customStartupInfo` to `McpServerData`:
6
-
7
- ```typescript
8
- const serverData: McpServerData = {
9
- // ... other options
10
-
11
- // Custom startup diagnostic info displayed in the console at server start
12
- customStartupInfo: [
13
- ['Custom param', 'any value'],
14
- ['Environment', process.env.MY_ENV || 'default'],
15
- ['Feature Flag', isFeatureEnabled ? 'enabled' : 'disabled'],
16
- ],
17
- };
18
- ```
19
-
20
- These values will appear in the startup info block alongside built-in diagnostics like `MCP Auth`, `Admin Auth`, etc.
21
-
22
- ## Configuration
23
-
24
- ### appConfig Access
25
-
26
- ```typescript
27
- import { appConfig } from 'fa-mcp-sdk';
28
-
29
- const port = appConfig.webServer.port;
30
- const dbEnabled = appConfig.isMainDBUsed;
31
- const transport = appConfig.mcp.transportType; // 'stdio' | 'http'
32
- ```
33
-
34
- ### Service Identification
35
-
36
- | Variable | Source | Usage |
37
- |----------|--------|-------|
38
- | `appConfig.name` | `SERVICE_NAME` env or `package.json.name` | Consul, JWT, logs, MCP server ID |
39
- | `appConfig.shortName` | name without "mcp" | Cache key prefix |
40
- | `appConfig.productName` | `PRODUCT_NAME` env or `package.json.productName` | Swagger title, UI header |
41
-
42
- ### config/default.yaml
43
-
44
- ```yaml
45
- accessPoints:
46
- myService:
47
- title: 'Remote service'
48
- host: <host>
49
- port: 9999
50
- token: '***'
51
- noConsul: true
52
- consulServiceName: <name>
53
-
54
- cache:
55
- ttlSeconds: 300
56
- maxItems: 1000
57
-
58
- consul:
59
- check:
60
- interval: '10s'
61
- timeout: '5s'
62
- deregistercriticalserviceafter: '3m'
63
- agent:
64
- dev: # DEV DC credentials
65
- dc: '{{consul.agent.dev.dc}}'
66
- host: '{{consul.agent.dev.host}}'
67
- port: 443
68
- secure: true
69
- token: '***'
70
- prd: # PROD DC credentials
71
- dc: '{{consul.agent.prd.dc}}'
72
- host: '{{consul.agent.prd.host}}'
73
- port: 443
74
- secure: true
75
- token: '***'
76
- reg: # Service registration
77
- host: null # null = use current server
78
- port: 8500
79
- secure: false
80
- token: '***'
81
- service:
82
- enable: {{consul.service.enable}}
83
- name: <name> # from package.json
84
- instance: '{{SERVICE_INSTANCE}}'
85
- version: <version> # from package.json
86
- description: <description> # from package.json
87
- tags: [] # null/empty = from package.keywords
88
- meta:
89
- who: 'http://{address}:{port}/'
90
- envCode:
91
- prod: {{consul.envCode.prod}}
92
- dev: {{consul.envCode.dev}}
93
-
94
- db:
95
- postgres:
96
- dbs:
97
- main:
98
- label: 'My Database'
99
- host: '' # Empty = DB disabled
100
- port: 5432
101
- database: <database>
102
- user: <user>
103
- password: <password>
104
-
105
- logger:
106
- level: info
107
- useFileLogger: {{logger.useFileLogger}}
108
- dir: '{{logger.dir}}'
109
-
110
- mcp:
111
- transportType: http # stdio | http
112
- rateLimit:
113
- maxRequests: 100
114
- windowMs: 60000
115
- tools:
116
- answerAs: text # text | structuredContent
117
- hideAnnotations: false # true — strip `annotations` from tool listings
118
-
119
- swagger:
120
- servers:
121
- - url: https://{{mcp.domain}}
122
- description: "PROD server"
123
-
124
- homePage:
125
- helpLink:
126
- href: '' # If empty — help link is not shown in footer
127
- text: 'Help' # Link text (default: "Help")
128
- maintainer:
129
- href: '' # If empty — Support link is not shown in footer
130
- text: 'Support' # Link text (default: "Help")
131
-
132
- uiColor:
133
- # Font color of the header and a number of interface elements on the HOME page
134
- primary: '#0f65dc'
135
-
136
- webServer:
137
- host: '0.0.0.0'
138
- port: {{port}}
139
- # array of hosts that CORS skips
140
- originHosts: ['localhost', '0.0.0.0']
141
- # Authentication is configured here only when accessing the MCP server
142
- # Authentication in services that enable tools, resources, and prompts
143
- # is implemented more deeply. To do this, you need to use the information passed in HTTP headers
144
- # You can also use a custom authorization function
145
- auth:
146
- enabled: false # Enables/disables authorization
147
- # ========================================================================
148
- # PERMANENT SERVER TOKENS
149
- # Static tokens for server-to-server communication
150
- # CPU cost: O(1) - fastest authentication method
151
- #
152
- # To enable this authentication, you need to set auth.enabled = true
153
- # and set one token of at least 20 characters in length
154
- # ========================================================================
155
- permanentServerTokens: [ ] # Add your server tokens here: ['token1', 'token2']
156
-
157
- # ========================================================================
158
- # JWT TOKEN WITH SYMMETRIC ENCRYPTION
159
- # Custom JWT tokens with AES-256 encryption
160
- # CPU cost: Medium - decryption + JSON parsing
161
- #
162
- # To enable this authentication, you need to set auth.enabled = true and set
163
- # encryptKey to at least 20 characters
164
- # ========================================================================
165
- jwtToken:
166
- # Symmetric encryption key to generate a token for this MCP (minimum 8 chars)
167
- encryptKey: '***'
168
- # If webServer.auth.enabled and the parameter true, the service name and the service specified in the token will be checked
169
- checkMCPName: true
170
- # If true and JWT token contains non-empty 'ip' field,
171
- # the client IP will be checked against the allowed list in the token
172
- isCheckIP: false
173
-
174
- # ========================================================================
175
- # Basic Authentication - Base64 encoded username:password
176
- # CPU cost: Medium - Base64 decoding + string comparison
177
- # To enable this authentication, you need to set auth.enabled = true
178
- # and set username and password to valid values
179
- # ========================================================================
180
- basic:
181
- username: ''
182
- password: '***'
183
-
184
- ```
185
-
186
- ## Access Points
187
-
188
- If your MCP server talks to third-party / external services (REST APIs, legacy systems, partner endpoints, etc.),
189
- declare their connection attributes (`host`, `port`, `protocol`, `token`, credentials, custom fields) under the
190
- top-level `accessPoints` block in the config — **not** scattered through code or ad-hoc config sections. Benefits:
191
-
192
- - Single registry of outbound dependencies visible in diagnostics and admin pages.
193
- - Automatic `host`/`port` resolution via Consul for services registered there.
194
- - Uniform access pattern (`appConfig.accessPoints.<alias>`) across all tools and modules.
195
- - Runtime updates — the SDK periodically refreshes dynamic access points from Consul without restarting the server.
196
-
197
- The SDK automatically wraps `appConfig.accessPoints` in an `AccessPoints` instance on startup and starts the Consul
198
- updater — **do not call `new AccessPoints(...)` or `accessPointUpdater.start()` manually**.
199
-
200
- ### Declaring Access Points
201
-
202
- ```yaml
203
- accessPoints:
204
- # Dynamic AP — host/port resolved from Consul
205
- wso2siAPI:
206
- title: 'WSO2 SI API'
207
- consulServiceName: 'dev01-wso2si-d2'
208
- host: null # filled in from Consul
209
- port: 9443 # fallback; also used when Consul meta specifies a different port
210
- protocol: 'https'
211
- user: 'admin'
212
- pass: '***'
213
- myProp: 'anyValue' # any custom field is preserved and available at runtime
214
-
215
- # Static AP — Consul is NOT used
216
- externalAPI:
217
- noConsul: true
218
- host: 'api.partner.com'
219
- port: 443
220
- protocol: 'https'
221
- token: '***'
222
- timeoutMs: 5000
223
- ```
224
-
225
- ### Using Access Points in Code
226
-
227
- ```typescript
228
- import { appConfig } from 'fa-mcp-sdk';
229
-
230
- // Direct access — always works, for dynamic and static APs alike
231
- const ap = appConfig.accessPoints.wso2siAPI;
232
- const url = `${ap.protocol}://${ap.host}:${ap.port}`;
233
- const token = ap.token; // custom fields available
234
- const custom = ap.myProp;
235
-
236
- // "Clean" copy without service fields
237
- const ap2 = appConfig.accessPoints.getAP('wso2siAPI');
238
-
239
- // All access points at once
240
- const all = appConfig.accessPoints.get();
241
-
242
- // For dynamic APs — wait until host/port are resolved from Consul (first run)
243
- await ap.waitForHostPortUpdated(5000);
244
- ```
245
-
246
- **Strict typing for custom fields:**
247
-
248
- ```typescript
249
- import type { IAccessPoint } from 'fa-consul';
250
-
251
- interface IWso2AP extends IAccessPoint {
252
- user: string;
253
- pass: string;
254
- myProp: string;
255
- }
256
-
257
- const ap = appConfig.accessPoints.wso2siAPI as IWso2AP;
258
- ```
259
-
260
- ### Access Point Properties
261
-
262
- **User-defined (configured in YAML):**
263
-
264
- | Property | Required | Purpose |
265
- |----------------------------------|-----------------|---------------------------------------------------------------------------------------|
266
- | `consulServiceName` | yes for dynamic | Consul service name used to resolve `host`/`port` |
267
- | `host` | — | IP/hostname. Dynamic: usually `null`, filled from Consul. Static (`noConsul`): manual |
268
- | `port` | — | TCP port. Coerced to `Number` or `null`. Dynamic: from Consul (or `meta.port`) |
269
- | `protocol` | — | `http` or `https`. Anything other than `https?` is coerced to `http`, lowercased |
270
- | `title` | — | Human-readable name (defaults to the AP key) |
271
- | `noConsul` | — | `true` → static AP: Consul is not polled, `consulServiceName` is not required |
272
- | `retrieveProps` | — | `(host, meta) => ({host, port})`. Custom extractor for Consul response |
273
- | `updateIntervalIfSuccessMillis` | — | Interval between successful Consul polls for this AP (default 2 min) |
274
- | `user`, `pass`, `token`, any key | — | Application fields — stored as-is and available at runtime |
275
-
276
- **Service fields (added automatically by the SDK for dynamic APs):**
277
-
278
- | Property | Purpose |
279
- |------------------------------|-------------------------------------------------------------------------|
280
- | `id` | The AP key from the config |
281
- | `isAP` | Marker for a dynamic AP; absent on `noConsul` APs |
282
- | `meta` | Filled from `Service.Meta` of the Consul service on successful poll |
283
- | `isReachable` | `true` if the last Consul poll returned data |
284
- | `lastSuccessUpdate` | Timestamp of the last successful update |
285
- | `idHostPortUpdated` | `true` once `host` + `port` have been populated at least once |
286
- | `setProps(data)` | Method for externally updating AP fields |
287
- | `waitForHostPortUpdated(ms)` | Promise that resolves when `host`/`port` have been populated |
288
- | `getChanges()` | Returns `[propName, oldValue, newValue][]` for the last `setProps` call |
289
-
290
- ### `noConsul` Access Points
291
-
292
- Setting `noConsul: true` makes the access point **static** — its address is not resolved through Consul. Typical use
293
- cases: partner APIs, legacy systems, or services with fixed addresses that cannot (or should not) be registered in
294
- Consul.
295
-
296
- Differences from a dynamic AP:
297
-
298
- - `consulServiceName` is not required.
299
- - The AP object is stored **as-is** — no normalization of `port`/`protocol`, no service fields (`isAP`, `setProps`,
300
- `waitForHostPortUpdated`, etc.) are added.
301
- - The AP is excluded from Consul polling; `host`/`port` are never overwritten.
302
- - `getAP('key')` and `get()` do **not** return static APs by default (they filter on `isAP`). Pass `andNotIsAP = true`
303
- to include them, or use direct access — `appConfig.accessPoints.externalAPI` — which always works.
304
-
305
- ```typescript
306
- appConfig.accessPoints.getAP('externalAPI', true); // include static AP in lookup
307
- appConfig.accessPoints.externalAPI; // direct access always works
308
- ```
309
-
310
- ### Custom Fields
311
-
312
- Any additional property on an AP (`apiKey`, `timeoutMs`, `headers: {...}`, etc.) is preserved verbatim and accessible at
313
- runtime:
314
-
315
- - On creation, all fields from the config are copied onto the AP object.
316
- - Periodic Consul updates only refresh `host`/`port` (and optionally `meta`) — other properties are **never
317
- overwritten**.
318
- - `get()` / `getAP()` copy all enumerable properties except `undefined` and functions.
319
- - Nested objects are copied shallowly — if a custom field is an object, its inner references are shared with the
320
- original config.
321
- - Only `port` (coerced to `Number`) and `protocol` (coerced to `http`/`https`) are normalized; all other fields are
322
- left untouched.
323
-
324
- ### Subscribing to Updates
325
-
326
- When a dynamic AP is refreshed from Consul, events are emitted on the SDK's `eventEmitter`
327
- (see "Event System" in `06-utilities.md`):
328
-
329
- ```typescript
330
- import { eventEmitter } from 'fa-mcp-sdk';
331
-
332
- eventEmitter.on('access-point-updated', ({ accessPoint, changes }) => {
333
- // changes: [propName, oldValue, newValue][]
334
- });
335
- eventEmitter.on('access-points-updated', () => { /* any AP was updated this cycle */ });
336
- ```
337
-
338
- ## Cache
339
-
340
- ```typescript
341
- import { getCache } from 'fa-mcp-sdk';
342
-
343
- const cache = getCache(); // Default options
344
- const cache = getCache({ ttlSeconds: 600, maxItems: 5000 });
345
-
346
- // Methods
347
- cache.set('key', value, ttlSeconds?);
348
- cache.get<T>('key');
349
- cache.has('key');
350
- cache.del('key');
351
- cache.take<T>('key'); // Get and delete
352
- cache.mget<T>(['k1', 'k2']);
353
- cache.mset([{ key: 'a', val: 1 }, { key: 'b', val: 2, ttl: 600 }]);
354
- cache.keys();
355
- cache.flush();
356
- cache.ttl('key', seconds); // Update TTL
357
- cache.getTtl('key');
358
- cache.getStats(); // { hitRate, keys, vsize }
359
- cache.close();
360
-
361
- // Get-or-set pattern
362
- const data = await cache.getOrSet('key', async () => await fetchData(), 3600);
363
- ```
364
-
365
- ## Database
366
-
367
- PostgreSQL integration (including the `MAIN` sugar layer — `queryMAIN`, `execMAIN`, `getMergeSqlMAIN`,
368
- `mergeByBatch`, `pgvector` support, etc.) is documented in [09-database.md](09-database.md).
369
-
370
- Minimal config snippet (see [09-database.md](09-database.md) for the full reference):
371
-
372
- ```yaml
373
- db:
374
- postgres:
375
- dbs:
376
- main:
377
- label: 'My Database'
378
- host: '' # empty string disables DB (isMainDBUsed = false)
379
- port: 5432
380
- database: <database>
381
- user: <user>
382
- password: <password>
383
- usedExtensions: [] # e.g. [pgvector]
384
- ```
1
+ # Configuration, Cache, and Access Points
2
+
3
+ ## Custom Startup Diagnostics
4
+
5
+ You can add custom key-value pairs to the startup diagnostic output by passing `customStartupInfo` to `McpServerData`:
6
+
7
+ ```typescript
8
+ const serverData: McpServerData = {
9
+ // ... other options
10
+
11
+ // Custom startup diagnostic info displayed in the console at server start
12
+ customStartupInfo: [
13
+ ['Custom param', 'any value'],
14
+ ['Environment', process.env.MY_ENV || 'default'],
15
+ ['Feature Flag', isFeatureEnabled ? 'enabled' : 'disabled'],
16
+ ],
17
+ };
18
+ ```
19
+
20
+ These values will appear in the startup info block alongside built-in diagnostics like `MCP Auth`, `Admin Auth`, etc.
21
+
22
+ ## Configuration
23
+
24
+ ### appConfig Access
25
+
26
+ ```typescript
27
+ import { appConfig } from 'fa-mcp-sdk';
28
+
29
+ const port = appConfig.webServer.port;
30
+ const dbEnabled = appConfig.isMainDBUsed;
31
+ const transport = appConfig.mcp.transportType; // 'stdio' | 'http'
32
+ ```
33
+
34
+ ### Service Identification
35
+
36
+ | Variable | Source | Usage |
37
+ |----------|--------|-------|
38
+ | `appConfig.name` | `SERVICE_NAME` env or `package.json.name` | Consul, JWT, logs, MCP server ID |
39
+ | `appConfig.shortName` | name without "mcp" | Cache key prefix |
40
+ | `appConfig.productName` | `PRODUCT_NAME` env or `package.json.productName` | Swagger title, UI header |
41
+
42
+ ### config/default.yaml
43
+
44
+ ```yaml
45
+ accessPoints:
46
+ myService:
47
+ title: 'Remote service'
48
+ host: <host>
49
+ port: 9999
50
+ token: '***'
51
+ noConsul: true
52
+ consulServiceName: <name>
53
+
54
+ cache:
55
+ ttlSeconds: 300
56
+ maxItems: 1000
57
+
58
+ consul:
59
+ check:
60
+ interval: '10s'
61
+ timeout: '5s'
62
+ deregistercriticalserviceafter: '3m'
63
+ agent:
64
+ dev: # DEV DC credentials
65
+ dc: '{{consul.agent.dev.dc}}'
66
+ host: '{{consul.agent.dev.host}}'
67
+ port: 443
68
+ secure: true
69
+ token: '***'
70
+ prd: # PROD DC credentials
71
+ dc: '{{consul.agent.prd.dc}}'
72
+ host: '{{consul.agent.prd.host}}'
73
+ port: 443
74
+ secure: true
75
+ token: '***'
76
+ reg: # Service registration
77
+ host: null # null = use current server
78
+ port: 8500
79
+ secure: false
80
+ token: '***'
81
+ service:
82
+ enable: {{consul.service.enable}}
83
+ name: <name> # from package.json
84
+ instance: '{{SERVICE_INSTANCE}}'
85
+ version: <version> # from package.json
86
+ description: <description> # from package.json
87
+ tags: [] # null/empty = from package.keywords
88
+ meta:
89
+ who: 'http://{address}:{port}/'
90
+ envCode:
91
+ prod: {{consul.envCode.prod}}
92
+ dev: {{consul.envCode.dev}}
93
+
94
+ db:
95
+ postgres:
96
+ dbs:
97
+ main:
98
+ label: 'My Database'
99
+ host: '' # Empty = DB disabled
100
+ port: 5432
101
+ database: <database>
102
+ user: <user>
103
+ password: <password>
104
+
105
+ logger:
106
+ level: info
107
+ useFileLogger: {{logger.useFileLogger}}
108
+ dir: '{{logger.dir}}'
109
+
110
+ mcp:
111
+ transportType: http # stdio | http
112
+ rateLimit:
113
+ maxRequests: 100
114
+ windowMs: 60000
115
+ tools:
116
+ answerAs: text # text | structuredContent
117
+ hideAnnotations: false # true — strip `annotations` from tool listings
118
+
119
+ swagger:
120
+ servers:
121
+ - url: https://{{mcp.domain}}
122
+ description: "PROD server"
123
+
124
+ homePage:
125
+ helpLink:
126
+ href: '' # If empty — help link is not shown in footer
127
+ text: 'Help' # Link text (default: "Help")
128
+ maintainer:
129
+ href: '' # If empty — Support link is not shown in footer
130
+ text: 'Support' # Link text (default: "Help")
131
+
132
+ uiColor:
133
+ # Font color of the header and a number of interface elements on the HOME page
134
+ primary: '#0f65dc'
135
+
136
+ webServer:
137
+ host: '0.0.0.0'
138
+ port: {{port}}
139
+ # array of hosts that CORS skips
140
+ originHosts: ['localhost', '0.0.0.0']
141
+ # Authentication is configured here only when accessing the MCP server
142
+ # Authentication in services that enable tools, resources, and prompts
143
+ # is implemented more deeply. To do this, you need to use the information passed in HTTP headers
144
+ # You can also use a custom authorization function
145
+ auth:
146
+ enabled: false # Enables/disables authorization
147
+ # ========================================================================
148
+ # PERMANENT SERVER TOKENS
149
+ # Static tokens for server-to-server communication
150
+ # CPU cost: O(1) - fastest authentication method
151
+ #
152
+ # To enable this authentication, you need to set auth.enabled = true
153
+ # and set one token of at least 20 characters in length
154
+ # ========================================================================
155
+ permanentServerTokens: [ ] # Add your server tokens here: ['token1', 'token2']
156
+
157
+ # ========================================================================
158
+ # JWT TOKEN WITH SYMMETRIC ENCRYPTION
159
+ # Custom JWT tokens with AES-256 encryption
160
+ # CPU cost: Medium - decryption + JSON parsing
161
+ #
162
+ # To enable this authentication, you need to set auth.enabled = true and set
163
+ # encryptKey to at least 20 characters
164
+ # ========================================================================
165
+ jwtToken:
166
+ # Symmetric encryption key to generate a token for this MCP (minimum 8 chars)
167
+ encryptKey: '***'
168
+ # If webServer.auth.enabled and the parameter true, the service name and the service specified in the token will be checked
169
+ checkMCPName: true
170
+ # If true and JWT token contains non-empty 'ip' field,
171
+ # the client IP will be checked against the allowed list in the token
172
+ isCheckIP: false
173
+
174
+ # ========================================================================
175
+ # Basic Authentication - Base64 encoded username:password
176
+ # CPU cost: Medium - Base64 decoding + string comparison
177
+ # To enable this authentication, you need to set auth.enabled = true
178
+ # and set username and password to valid values
179
+ # ========================================================================
180
+ basic:
181
+ username: ''
182
+ password: '***'
183
+
184
+ ```
185
+
186
+ ## Access Points
187
+
188
+ If your MCP server talks to third-party / external services (REST APIs, legacy systems, partner endpoints, etc.),
189
+ declare their connection attributes (`host`, `port`, `protocol`, `token`, credentials, custom fields) under the
190
+ top-level `accessPoints` block in the config — **not** scattered through code or ad-hoc config sections. Benefits:
191
+
192
+ - Single registry of outbound dependencies visible in diagnostics and admin pages.
193
+ - Automatic `host`/`port` resolution via Consul for services registered there.
194
+ - Uniform access pattern (`appConfig.accessPoints.<alias>`) across all tools and modules.
195
+ - Runtime updates — the SDK periodically refreshes dynamic access points from Consul without restarting the server.
196
+
197
+ The SDK automatically wraps `appConfig.accessPoints` in an `AccessPoints` instance on startup and starts the Consul
198
+ updater — **do not call `new AccessPoints(...)` or `accessPointUpdater.start()` manually**.
199
+
200
+ ### Declaring Access Points
201
+
202
+ ```yaml
203
+ accessPoints:
204
+ # Dynamic AP — host/port resolved from Consul
205
+ wso2siAPI:
206
+ title: 'WSO2 SI API'
207
+ consulServiceName: 'dev01-wso2si-d2'
208
+ host: null # filled in from Consul
209
+ port: 9443 # fallback; also used when Consul meta specifies a different port
210
+ protocol: 'https'
211
+ user: 'admin'
212
+ pass: '***'
213
+ myProp: 'anyValue' # any custom field is preserved and available at runtime
214
+
215
+ # Static AP — Consul is NOT used
216
+ externalAPI:
217
+ noConsul: true
218
+ host: 'api.partner.com'
219
+ port: 443
220
+ protocol: 'https'
221
+ token: '***'
222
+ timeoutMs: 5000
223
+ ```
224
+
225
+ ### Using Access Points in Code
226
+
227
+ ```typescript
228
+ import { appConfig } from 'fa-mcp-sdk';
229
+
230
+ // Direct access — always works, for dynamic and static APs alike
231
+ const ap = appConfig.accessPoints.wso2siAPI;
232
+ const url = `${ap.protocol}://${ap.host}:${ap.port}`;
233
+ const token = ap.token; // custom fields available
234
+ const custom = ap.myProp;
235
+
236
+ // "Clean" copy without service fields
237
+ const ap2 = appConfig.accessPoints.getAP('wso2siAPI');
238
+
239
+ // All access points at once
240
+ const all = appConfig.accessPoints.get();
241
+
242
+ // For dynamic APs — wait until host/port are resolved from Consul (first run)
243
+ await ap.waitForHostPortUpdated(5000);
244
+ ```
245
+
246
+ **Strict typing for custom fields:**
247
+
248
+ ```typescript
249
+ import type { IAccessPoint } from 'fa-consul';
250
+
251
+ interface IWso2AP extends IAccessPoint {
252
+ user: string;
253
+ pass: string;
254
+ myProp: string;
255
+ }
256
+
257
+ const ap = appConfig.accessPoints.wso2siAPI as IWso2AP;
258
+ ```
259
+
260
+ ### Access Point Properties
261
+
262
+ **User-defined (configured in YAML):**
263
+
264
+ | Property | Required | Purpose |
265
+ |----------------------------------|-----------------|---------------------------------------------------------------------------------------|
266
+ | `consulServiceName` | yes for dynamic | Consul service name used to resolve `host`/`port` |
267
+ | `host` | — | IP/hostname. Dynamic: usually `null`, filled from Consul. Static (`noConsul`): manual |
268
+ | `port` | — | TCP port. Coerced to `Number` or `null`. Dynamic: from Consul (or `meta.port`) |
269
+ | `protocol` | — | `http` or `https`. Anything other than `https?` is coerced to `http`, lowercased |
270
+ | `title` | — | Human-readable name (defaults to the AP key) |
271
+ | `noConsul` | — | `true` → static AP: Consul is not polled, `consulServiceName` is not required |
272
+ | `retrieveProps` | — | `(host, meta) => ({host, port})`. Custom extractor for Consul response |
273
+ | `updateIntervalIfSuccessMillis` | — | Interval between successful Consul polls for this AP (default 2 min) |
274
+ | `user`, `pass`, `token`, any key | — | Application fields — stored as-is and available at runtime |
275
+
276
+ **Service fields (added automatically by the SDK for dynamic APs):**
277
+
278
+ | Property | Purpose |
279
+ |------------------------------|-------------------------------------------------------------------------|
280
+ | `id` | The AP key from the config |
281
+ | `isAP` | Marker for a dynamic AP; absent on `noConsul` APs |
282
+ | `meta` | Filled from `Service.Meta` of the Consul service on successful poll |
283
+ | `isReachable` | `true` if the last Consul poll returned data |
284
+ | `lastSuccessUpdate` | Timestamp of the last successful update |
285
+ | `idHostPortUpdated` | `true` once `host` + `port` have been populated at least once |
286
+ | `setProps(data)` | Method for externally updating AP fields |
287
+ | `waitForHostPortUpdated(ms)` | Promise that resolves when `host`/`port` have been populated |
288
+ | `getChanges()` | Returns `[propName, oldValue, newValue][]` for the last `setProps` call |
289
+
290
+ ### `noConsul` Access Points
291
+
292
+ Setting `noConsul: true` makes the access point **static** — its address is not resolved through Consul. Typical use
293
+ cases: partner APIs, legacy systems, or services with fixed addresses that cannot (or should not) be registered in
294
+ Consul.
295
+
296
+ Differences from a dynamic AP:
297
+
298
+ - `consulServiceName` is not required.
299
+ - The AP object is stored **as-is** — no normalization of `port`/`protocol`, no service fields (`isAP`, `setProps`,
300
+ `waitForHostPortUpdated`, etc.) are added.
301
+ - The AP is excluded from Consul polling; `host`/`port` are never overwritten.
302
+ - `getAP('key')` and `get()` do **not** return static APs by default (they filter on `isAP`). Pass `andNotIsAP = true`
303
+ to include them, or use direct access — `appConfig.accessPoints.externalAPI` — which always works.
304
+
305
+ ```typescript
306
+ appConfig.accessPoints.getAP('externalAPI', true); // include static AP in lookup
307
+ appConfig.accessPoints.externalAPI; // direct access always works
308
+ ```
309
+
310
+ ### Custom Fields
311
+
312
+ Any additional property on an AP (`apiKey`, `timeoutMs`, `headers: {...}`, etc.) is preserved verbatim and accessible at
313
+ runtime:
314
+
315
+ - On creation, all fields from the config are copied onto the AP object.
316
+ - Periodic Consul updates only refresh `host`/`port` (and optionally `meta`) — other properties are **never
317
+ overwritten**.
318
+ - `get()` / `getAP()` copy all enumerable properties except `undefined` and functions.
319
+ - Nested objects are copied shallowly — if a custom field is an object, its inner references are shared with the
320
+ original config.
321
+ - Only `port` (coerced to `Number`) and `protocol` (coerced to `http`/`https`) are normalized; all other fields are
322
+ left untouched.
323
+
324
+ ### Subscribing to Updates
325
+
326
+ When a dynamic AP is refreshed from Consul, events are emitted on the SDK's `eventEmitter`
327
+ (see "Event System" in `06-utilities.md`):
328
+
329
+ ```typescript
330
+ import { eventEmitter } from 'fa-mcp-sdk';
331
+
332
+ eventEmitter.on('access-point-updated', ({ accessPoint, changes }) => {
333
+ // changes: [propName, oldValue, newValue][]
334
+ });
335
+ eventEmitter.on('access-points-updated', () => { /* any AP was updated this cycle */ });
336
+ ```
337
+
338
+ ## Cache
339
+
340
+ ```typescript
341
+ import { getCache } from 'fa-mcp-sdk';
342
+
343
+ const cache = getCache(); // Default options
344
+ const cache = getCache({ ttlSeconds: 600, maxItems: 5000 });
345
+
346
+ // Methods
347
+ cache.set('key', value, ttlSeconds?);
348
+ cache.get<T>('key');
349
+ cache.has('key');
350
+ cache.del('key');
351
+ cache.take<T>('key'); // Get and delete
352
+ cache.mget<T>(['k1', 'k2']);
353
+ cache.mset([{ key: 'a', val: 1 }, { key: 'b', val: 2, ttl: 600 }]);
354
+ cache.keys();
355
+ cache.flush();
356
+ cache.ttl('key', seconds); // Update TTL
357
+ cache.getTtl('key');
358
+ cache.getStats(); // { hitRate, keys, vsize }
359
+ cache.close();
360
+
361
+ // Get-or-set pattern
362
+ const data = await cache.getOrSet('key', async () => await fetchData(), 3600);
363
+ ```
364
+
365
+ ## Database
366
+
367
+ PostgreSQL integration (including the `MAIN` sugar layer — `queryMAIN`, `execMAIN`, `getMergeSqlMAIN`,
368
+ `mergeByBatch`, `pgvector` support, etc.) is documented in [09-database.md](09-database.md).
369
+
370
+ Minimal config snippet (see [09-database.md](09-database.md) for the full reference):
371
+
372
+ ```yaml
373
+ db:
374
+ postgres:
375
+ dbs:
376
+ main:
377
+ label: 'My Database'
378
+ host: '' # empty string disables DB (isMainDBUsed = false)
379
+ port: 5432
380
+ database: <database>
381
+ user: <user>
382
+ password: <password>
383
+ usedExtensions: [] # e.g. [pgvector]
384
+ ```