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,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
|
+
```
|