fa-mcp-sdk 0.3.16 → 0.3.18

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 (50) hide show
  1. package/README.md +1 -1
  2. package/cli-template/.claude/agents/architect.md +99 -99
  3. package/cli-template/.claude/agents/auditor.md +92 -92
  4. package/cli-template/.claude/agents/fa-mcp-sdk.md +1 -1
  5. package/cli-template/.claude/agents/planner.md +122 -122
  6. package/cli-template/.claude/agents/prd-writer.md +88 -88
  7. package/cli-template/.claude/agents/refactor.md +74 -74
  8. package/cli-template/.claude/agents/worker.md +132 -132
  9. package/cli-template/CLAUDE.md +1 -1
  10. package/cli-template/FA-MCP-SDK-DOC/01-getting-started.md +1 -1
  11. package/cli-template/FA-MCP-SDK-DOC/03-configuration.md +3 -0
  12. package/cli-template/FA-MCP-SDK-DOC/04-authentication.md +77 -4
  13. package/cli-template/FA-MCP-SDK-DOC/05-ad-authorization.md +35 -16
  14. package/cli-template/README.md +105 -105
  15. package/cli-template/package.json +2 -2
  16. package/cli-template/prompt-example-new-MCP.md +2 -1
  17. package/cli-template/prompt_2026-03-17_13-53.md +15 -0
  18. package/cli-template/r/TEST HTTP.xml +9 -9
  19. package/cli-template/r/TEST SSE.xml +5 -5
  20. package/cli-template/r/TEST STDIO.xml +5 -5
  21. package/cli-template/r/generate-token.xml +13 -13
  22. package/cli-template/r/lint-fix-build.xml +12 -12
  23. package/cli-template/r/remove-nul.xml +11 -11
  24. package/config/custom-environment-variables.yaml +1 -0
  25. package/config/default.yaml +3 -0
  26. package/config/development.yaml +4 -4
  27. package/config/production.yaml +4 -4
  28. package/dist/core/_types_/config.d.ts +1 -0
  29. package/dist/core/_types_/config.d.ts.map +1 -1
  30. package/dist/core/auth/ip-check.d.ts +18 -0
  31. package/dist/core/auth/ip-check.d.ts.map +1 -0
  32. package/dist/core/auth/ip-check.js +148 -0
  33. package/dist/core/auth/ip-check.js.map +1 -0
  34. package/dist/core/auth/jwt.d.ts +1 -0
  35. package/dist/core/auth/jwt.d.ts.map +1 -1
  36. package/dist/core/auth/jwt.js +15 -1
  37. package/dist/core/auth/jwt.js.map +1 -1
  38. package/dist/core/auth/multi-auth.d.ts.map +1 -1
  39. package/dist/core/auth/multi-auth.js +19 -14
  40. package/dist/core/auth/multi-auth.js.map +1 -1
  41. package/dist/core/auth/token-generator/ntlm/ntlm-templates.js +221 -221
  42. package/dist/core/web/static/token-gen/index.html +9 -0
  43. package/dist/core/web/static/token-gen/logout.svg +4 -4
  44. package/dist/core/web/static/token-gen/script.js +7 -1
  45. package/dist/core/web/static/token-gen/user.svg +4 -4
  46. package/package.json +1 -1
  47. package/scripts/publish.sh +78 -78
  48. package/scripts/update-doc.js +18 -18
  49. package/config/local-2.yaml +0 -20
  50. package/config/local.yaml +0 -101
@@ -3,244 +3,244 @@
3
3
  * Converted from pug templates in src/core/_ntlm_example/ntlm/views/
4
4
  */
5
5
  // CSS styles from src/core/_ntlm_example/style.css
6
- const ntlmStyles = `
7
- body, html {
8
- height: 100%;
9
- margin: 0;
10
- font-family: "Roboto", "-apple-system", "Helvetica Neue", Helvetica, Arial, sans-serif;
11
- }
12
-
13
- .views-outer-container {
14
- height: 100%;
15
- display: flex;
16
- justify-content: center;
17
- align-items: center;
18
- font-size: 14px;
19
- }
20
-
21
- .views-auth-container {
22
- text-align: center;
23
- position: absolute;
24
- top: calc(38vh - 130px);
25
- }
26
-
27
- .views-auth-container svg {
28
- width: 70px;
29
- fill: rgba(194, 57, 52, 0.58);
30
- }
31
-
32
- .views-auth-block {
33
- border: 1px solid #d0d0d0;
34
- padding: 20px;
35
- display: flex;
36
- flex-direction: column;
37
- align-items: center;
38
- }
39
-
40
- .views-input-group {
41
- display: flex;
42
- align-items: center;
43
- margin-bottom: 10px;
44
- }
45
-
46
- .views-input-group label {
47
- width: 80px;
48
- text-align: left;
49
- margin-right: 10px;
50
- }
51
-
52
- .views-input-group input {
53
- padding: 5px;
54
- width: 200px;
55
- }
56
-
57
- .views-input-group input::placeholder {
58
- color: #e5e5e5;
59
- }
60
-
61
- input {
62
- outline: none;
63
- border: 1px solid #b0b0b0;
64
- }
65
-
66
- input:focus {
67
- border: 1px solid #ff5500;
68
- }
69
-
70
- .views-button-container {
71
- display: flex;
72
- width: 100%;
73
- flex-direction: column;
74
- align-items: end;
75
- }
76
-
77
- .views-button-container button {
78
- padding: 3px;
79
- width: 105px;
80
- }
6
+ const ntlmStyles = `
7
+ body, html {
8
+ height: 100%;
9
+ margin: 0;
10
+ font-family: "Roboto", "-apple-system", "Helvetica Neue", Helvetica, Arial, sans-serif;
11
+ }
12
+
13
+ .views-outer-container {
14
+ height: 100%;
15
+ display: flex;
16
+ justify-content: center;
17
+ align-items: center;
18
+ font-size: 14px;
19
+ }
20
+
21
+ .views-auth-container {
22
+ text-align: center;
23
+ position: absolute;
24
+ top: calc(38vh - 130px);
25
+ }
26
+
27
+ .views-auth-container svg {
28
+ width: 70px;
29
+ fill: rgba(194, 57, 52, 0.58);
30
+ }
31
+
32
+ .views-auth-block {
33
+ border: 1px solid #d0d0d0;
34
+ padding: 20px;
35
+ display: flex;
36
+ flex-direction: column;
37
+ align-items: center;
38
+ }
39
+
40
+ .views-input-group {
41
+ display: flex;
42
+ align-items: center;
43
+ margin-bottom: 10px;
44
+ }
45
+
46
+ .views-input-group label {
47
+ width: 80px;
48
+ text-align: left;
49
+ margin-right: 10px;
50
+ }
51
+
52
+ .views-input-group input {
53
+ padding: 5px;
54
+ width: 200px;
55
+ }
56
+
57
+ .views-input-group input::placeholder {
58
+ color: #e5e5e5;
59
+ }
60
+
61
+ input {
62
+ outline: none;
63
+ border: 1px solid #b0b0b0;
64
+ }
65
+
66
+ input:focus {
67
+ border: 1px solid #ff5500;
68
+ }
69
+
70
+ .views-button-container {
71
+ display: flex;
72
+ width: 100%;
73
+ flex-direction: column;
74
+ align-items: end;
75
+ }
76
+
77
+ .views-button-container button {
78
+ padding: 3px;
79
+ width: 105px;
80
+ }
81
81
  `;
82
82
  // SVG icon from src/core/_ntlm_example/block-visitor.svg
83
- const blockVisitorSvg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
84
- <path fill="#c23934" d="M29.9 8.8V9v-.2z"/>
85
- <path fill="#c23934"
86
- d="M10.2 17.1c0-1.3.4-2.7 1-3.8.8-1.4 1.7-1.9 2.4-3 1.1-1.7 1.4-4.1.6-6-.7-1.9-2.5-3-4.5-2.9S6 2.7 5.4 4.6c-.8 2-.5 4.5 1.2 6.1.7.7 1.3 1.7 1 2.6-.4 1-1.5 1.4-2.2 1.7-1.8.8-4 1.9-4.4 4.1-.4 1.7.8 3.5 2.7 3.5h7.9c.4 0 .6-.4.4-.7-1.2-1.4-1.8-3.1-1.8-4.8zm11.3-3.9c-2.2-2.2-5.7-2.2-7.9 0s-2.2 5.6 0 7.8 5.7 2.2 7.9 0 2.1-5.7 0-7.8zm-6.6 1.2c1.3-1.2 3.1-1.4 4.5-.5l-5 5.1c-.9-1.5-.7-3.3.5-4.6zm5.3 5.3c-1.3 1.2-3.1 1.4-4.6.6l5.1-5.1c.9 1.4.7 3.3-.5 4.5z"/>
83
+ const blockVisitorSvg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
84
+ <path fill="#c23934" d="M29.9 8.8V9v-.2z"/>
85
+ <path fill="#c23934"
86
+ d="M10.2 17.1c0-1.3.4-2.7 1-3.8.8-1.4 1.7-1.9 2.4-3 1.1-1.7 1.4-4.1.6-6-.7-1.9-2.5-3-4.5-2.9S6 2.7 5.4 4.6c-.8 2-.5 4.5 1.2 6.1.7.7 1.3 1.7 1 2.6-.4 1-1.5 1.4-2.2 1.7-1.8.8-4 1.9-4.4 4.1-.4 1.7.8 3.5 2.7 3.5h7.9c.4 0 .6-.4.4-.7-1.2-1.4-1.8-3.1-1.8-4.8zm11.3-3.9c-2.2-2.2-5.7-2.2-7.9 0s-2.2 5.6 0 7.8 5.7 2.2 7.9 0 2.1-5.7 0-7.8zm-6.6 1.2c1.3-1.2 3.1-1.4 4.5-.5l-5 5.1c-.9-1.5-.7-3.3.5-4.6zm5.3 5.3c-1.3 1.2-3.1 1.4-4.6.6l5.1-5.1c.9 1.4.7 3.3-.5 4.5z"/>
87
87
  </svg>`;
88
88
  /**
89
89
  * Basic login page template
90
90
  */
91
- export const getLoginPageHTML = (username = '') => `<!DOCTYPE html>
92
- <html>
93
- <head>
94
- <meta charset="UTF-8">
95
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
96
- <title>Sign in</title>
97
- <style>${ntlmStyles}</style>
98
- </head>
99
- <body>
100
- <script>
101
- const username = '${username}';
102
- function authenticate() {
103
- const wl = window.location;
104
- const login = document.getElementById('login').value;
105
- const password = document.getElementById('password').value;
106
-
107
- // Special handling for NTLM authentication
108
- // The @ symbol in passwords breaks URL construction, so we need proper URL encoding
109
- try {
110
- // Properly encode the credentials for URL
111
- const encodedLogin = encodeURIComponent(login);
112
- const encodedPassword = encodeURIComponent(password);
113
-
114
- console.log('Attempting authentication with:', { login: encodedLogin, passwordLength: password.length });
115
-
116
- // Navigate with properly encoded credentials
117
- window.location.href = wl.protocol + '//' + encodedLogin + ':' + encodedPassword + '@' + wl.hostname + ':' + wl.port;
118
- } catch (error) {
119
- console.error('Authentication error:', error);
120
- alert('Authentication failed: ' + error.message);
121
- }
122
- }
123
-
124
- // For testing: add direct NTLM trigger function
125
- function triggerNTLM() {
126
- // This will trigger the browser's native NTLM authentication dialog
127
- const wl = window.location;
128
- window.location.href = wl.origin + '/';
129
- }
130
-
131
- // Add additional button for testing
132
- document.addEventListener('DOMContentLoaded', function() {
133
- const buttonContainer = document.querySelector('.views-button-container');
134
- if (buttonContainer) {
135
- const ntlmButton = document.createElement('button');
136
- ntlmButton.type = 'button';
137
- ntlmButton.textContent = 'Trigger NTLM Dialog';
138
- ntlmButton.style.marginTop = '10px';
139
- ntlmButton.onclick = triggerNTLM;
140
- buttonContainer.appendChild(ntlmButton);
141
- }
142
- });
143
- </script>
144
- <div class="views-outer-container">
145
- <div class="views-auth-container">
146
- <div class="views-auth-block">
147
- <div class="views-input-group">
148
- <label for="login">Login:</label>
149
- <input type="text" id="login" value="${username}">
150
- </div>
151
- <div class="views-input-group">
152
- <label for="password">Password:</label>
153
- <input type="password" id="password">
154
- </div>
155
- <div class="views-button-container">
156
- <button type="button" onclick="authenticate()">Sign in</button>
157
- </div>
158
- </div>
159
- </div>
160
- </div>
161
- </body>
91
+ export const getLoginPageHTML = (username = '') => `<!DOCTYPE html>
92
+ <html>
93
+ <head>
94
+ <meta charset="UTF-8">
95
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
96
+ <title>Sign in</title>
97
+ <style>${ntlmStyles}</style>
98
+ </head>
99
+ <body>
100
+ <script>
101
+ const username = '${username}';
102
+ function authenticate() {
103
+ const wl = window.location;
104
+ const login = document.getElementById('login').value;
105
+ const password = document.getElementById('password').value;
106
+
107
+ // Special handling for NTLM authentication
108
+ // The @ symbol in passwords breaks URL construction, so we need proper URL encoding
109
+ try {
110
+ // Properly encode the credentials for URL
111
+ const encodedLogin = encodeURIComponent(login);
112
+ const encodedPassword = encodeURIComponent(password);
113
+
114
+ console.log('Attempting authentication with:', { login: encodedLogin, passwordLength: password.length });
115
+
116
+ // Navigate with properly encoded credentials
117
+ window.location.href = wl.protocol + '//' + encodedLogin + ':' + encodedPassword + '@' + wl.hostname + ':' + wl.port;
118
+ } catch (error) {
119
+ console.error('Authentication error:', error);
120
+ alert('Authentication failed: ' + error.message);
121
+ }
122
+ }
123
+
124
+ // For testing: add direct NTLM trigger function
125
+ function triggerNTLM() {
126
+ // This will trigger the browser's native NTLM authentication dialog
127
+ const wl = window.location;
128
+ window.location.href = wl.origin + '/';
129
+ }
130
+
131
+ // Add additional button for testing
132
+ document.addEventListener('DOMContentLoaded', function() {
133
+ const buttonContainer = document.querySelector('.views-button-container');
134
+ if (buttonContainer) {
135
+ const ntlmButton = document.createElement('button');
136
+ ntlmButton.type = 'button';
137
+ ntlmButton.textContent = 'Trigger NTLM Dialog';
138
+ ntlmButton.style.marginTop = '10px';
139
+ ntlmButton.onclick = triggerNTLM;
140
+ buttonContainer.appendChild(ntlmButton);
141
+ }
142
+ });
143
+ </script>
144
+ <div class="views-outer-container">
145
+ <div class="views-auth-container">
146
+ <div class="views-auth-block">
147
+ <div class="views-input-group">
148
+ <label for="login">Login:</label>
149
+ <input type="text" id="login" value="${username}">
150
+ </div>
151
+ <div class="views-input-group">
152
+ <label for="password">Password:</label>
153
+ <input type="password" id="password">
154
+ </div>
155
+ <div class="views-button-container">
156
+ <button type="button" onclick="authenticate()">Sign in</button>
157
+ </div>
158
+ </div>
159
+ </div>
160
+ </div>
161
+ </body>
162
162
  </html>`;
163
163
  /**
164
164
  * Not authenticated page template (wrong login/password)
165
165
  */
166
- export const getNotAuthenticatedPageHTML = (title = 'NOT AUTHENTICATED', protocol = '', hostname = '', username = '') => `<!DOCTYPE html>
167
- <html>
168
- <head>
169
- <meta charset="UTF-8">
170
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
171
- <title>${title}</title>
172
- <style>${ntlmStyles}</style>
173
- </head>
174
- <body>
175
- <script>
176
- const username = '${username}';
177
- function authenticate() {
178
- const protocol = '${protocol}';
179
- const hostname = '${hostname}';
180
- const login = document.getElementById('login').value;
181
- const password = document.getElementById('password').value;
182
- window.location.href = protocol + '://' + login + ':' + password + '@' + hostname;
183
- }
184
- </script>
185
- <div class="views-outer-container">
186
- <div class="views-auth-container">
187
- ${blockVisitorSvg}
188
- <p>Wrong login or password</p>
189
- <div class="views-auth-block">
190
- <div class="views-input-group">
191
- <label for="login">Login:</label>
192
- <input type="text" id="login" value="${username}">
193
- </div>
194
- <div class="views-input-group">
195
- <label for="password">Password:</label>
196
- <input type="password" id="password">
197
- </div>
198
- <div class="views-button-container">
199
- <button type="button" onclick="authenticate()">Sign in</button>
200
- </div>
201
- </div>
202
- </div>
203
- </div>
204
- </body>
166
+ export const getNotAuthenticatedPageHTML = (title = 'NOT AUTHENTICATED', protocol = '', hostname = '', username = '') => `<!DOCTYPE html>
167
+ <html>
168
+ <head>
169
+ <meta charset="UTF-8">
170
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
171
+ <title>${title}</title>
172
+ <style>${ntlmStyles}</style>
173
+ </head>
174
+ <body>
175
+ <script>
176
+ const username = '${username}';
177
+ function authenticate() {
178
+ const protocol = '${protocol}';
179
+ const hostname = '${hostname}';
180
+ const login = document.getElementById('login').value;
181
+ const password = document.getElementById('password').value;
182
+ window.location.href = protocol + '://' + login + ':' + password + '@' + hostname;
183
+ }
184
+ </script>
185
+ <div class="views-outer-container">
186
+ <div class="views-auth-container">
187
+ ${blockVisitorSvg}
188
+ <p>Wrong login or password</p>
189
+ <div class="views-auth-block">
190
+ <div class="views-input-group">
191
+ <label for="login">Login:</label>
192
+ <input type="text" id="login" value="${username}">
193
+ </div>
194
+ <div class="views-input-group">
195
+ <label for="password">Password:</label>
196
+ <input type="password" id="password">
197
+ </div>
198
+ <div class="views-button-container">
199
+ <button type="button" onclick="authenticate()">Sign in</button>
200
+ </div>
201
+ </div>
202
+ </div>
203
+ </div>
204
+ </body>
205
205
  </html>`;
206
206
  /**
207
207
  * Not authorized page template (user doesn't have access)
208
208
  */
209
- export const getNotAuthorizedPageHTML = (title = 'NOT AUTHORIZED', username = '') => `<!DOCTYPE html>
210
- <html>
211
- <head>
212
- <meta charset="UTF-8">
213
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
214
- <title>${title}</title>
215
- <style>${ntlmStyles}</style>
216
- </head>
217
- <body>
218
- <div class="views-outer-container">
219
- <div class="views-auth-container">
220
- ${blockVisitorSvg}
221
- <p>No access for "${username}"</p>
222
- </div>
223
- </div>
224
- </body>
209
+ export const getNotAuthorizedPageHTML = (title = 'NOT AUTHORIZED', username = '') => `<!DOCTYPE html>
210
+ <html>
211
+ <head>
212
+ <meta charset="UTF-8">
213
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
214
+ <title>${title}</title>
215
+ <style>${ntlmStyles}</style>
216
+ </head>
217
+ <body>
218
+ <div class="views-outer-container">
219
+ <div class="views-auth-container">
220
+ ${blockVisitorSvg}
221
+ <p>No access for "${username}"</p>
222
+ </div>
223
+ </div>
224
+ </body>
225
225
  </html>`;
226
226
  /**
227
227
  * 404 page template
228
228
  */
229
- export const get404PageHTML = () => `<!DOCTYPE html>
230
- <html>
231
- <head>
232
- <meta charset="UTF-8">
233
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
234
- <title>404 - Page Not Found</title>
235
- <style>${ntlmStyles}</style>
236
- </head>
237
- <body>
238
- <div class="views-outer-container">
239
- <div class="views-auth-container">
240
- ${blockVisitorSvg}
241
- <p>404 - Page Not Found</p>
242
- </div>
243
- </div>
244
- </body>
229
+ export const get404PageHTML = () => `<!DOCTYPE html>
230
+ <html>
231
+ <head>
232
+ <meta charset="UTF-8">
233
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
234
+ <title>404 - Page Not Found</title>
235
+ <style>${ntlmStyles}</style>
236
+ </head>
237
+ <body>
238
+ <div class="views-outer-container">
239
+ <div class="views-auth-container">
240
+ ${blockVisitorSvg}
241
+ <p>404 - Page Not Found</p>
242
+ </div>
243
+ </div>
244
+ </body>
245
245
  </html>`;
246
246
  //# sourceMappingURL=ntlm-templates.js.map
@@ -75,6 +75,15 @@
75
75
  </div>
76
76
  </div>
77
77
  </div>
78
+ <div class="form-group">
79
+ <label for="tokenIp">Allowed IP addresses (optional):</label>
80
+ <input type="text" id="tokenIp" name="ip"
81
+ placeholder="e.g. 192.168.1.100, 10.0.0.0/24; 172.16.0.0/12">
82
+ <small style="color: #6b778c; margin-top: 4px; display: block;">
83
+ Comma, semicolon or space separated. Supports CIDR notation.
84
+ Leave empty to allow any IP.
85
+ </small>
86
+ </div>
78
87
  <div class="form-group">
79
88
  <label>Additional data (key-value):</label>
80
89
  <div id="keyValuePairs"></div>
@@ -1,4 +1,4 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
2
- <path fill="currentColor" d="M2 0h8.8a1 1 0 0 1 0 2.2H3.2v19.6h7.6a1 1 0 0 1 0 2.2H2.1A1 1 0 0 1 1 23V1a1 1 0 0 1 1-1"/>
3
- <path fill="currentColor" d="M16.6 8.4 19 11H6.5a1 1 0 0 0 0 2.2H19l-2.5 2.5A1 1 0 1 0 18 17l4.4-4.3a1 1 0 0 0 0-1.6L18.1 7a1 1 0 1 0-1.5 1.5"/>
4
- </svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
2
+ <path fill="currentColor" d="M2 0h8.8a1 1 0 0 1 0 2.2H3.2v19.6h7.6a1 1 0 0 1 0 2.2H2.1A1 1 0 0 1 1 23V1a1 1 0 0 1 1-1"/>
3
+ <path fill="currentColor" d="M16.6 8.4 19 11H6.5a1 1 0 0 0 0 2.2H19l-2.5 2.5A1 1 0 1 0 18 17l4.4-4.3a1 1 0 0 0 0-1.6L18.1 7a1 1 0 1 0-1.5 1.5"/>
4
+ </svg>
@@ -367,6 +367,11 @@ document.getElementById('generateForm').addEventListener('submit', async (e) =>
367
367
  }
368
368
  }
369
369
 
370
+ const ipValue = document.getElementById('tokenIp').value.trim();
371
+ if (ipValue) {
372
+ payload.ip = ipValue;
373
+ }
374
+
370
375
  const requestData = {
371
376
  user: formData.get('user'),
372
377
  timeValue: parseInt(formData.get('timeValue')),
@@ -435,7 +440,7 @@ document.getElementById('validateForm').addEventListener('submit', async (e) =>
435
440
 
436
441
  if (result.success) {
437
442
  const remainingTime = result.payload.expire - Date.now();
438
- const payloadKeys = Object.keys(result.payload).filter((k) => !/^(user|expire|iat|service)$/.test(k));
443
+ const payloadKeys = Object.keys(result.payload).filter((k) => !/^(user|expire|iat|service|ip)$/.test(k));
439
444
 
440
445
  let payloadHtml = '';
441
446
  if (payloadKeys.length > 0) {
@@ -455,6 +460,7 @@ document.getElementById('validateForm').addEventListener('submit', async (e) =>
455
460
  <h4>Token Information:</h4>
456
461
  <p><strong>User:</strong> ${result.payload.user}</p>
457
462
  ${result.payload.service ? `<p><strong>Service:</strong> ${result.payload.service}</p>` : ''}
463
+ ${result.payload.ip ? `<p><strong>Allowed IPs:</strong> ${result.payload.ip}</p>` : ''}
458
464
  <p><strong>Issued at:</strong> ${issuedAtTime}</p>
459
465
  <p><strong>Time remaining:</strong> ${formatTime(remainingTime)}</p>
460
466
  <p><strong>Expires:</strong> ${new Date(result.payload.expire).toLocaleString('ru-RU')}</p>
@@ -1,4 +1,4 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
2
- <path fill="currentColor"
3
- d="M24 20.5v1.1c0 1.3-1.1 2.4-2.4 2.4H2.4A2.45 2.45 0 0 1 0 21.6v-1.1c0-2.9 3.4-4.7 6.6-6.1l.3-.15c.25-.1.5-.1.75.05a7.75 7.75 0 0 0 8.6 0 .8.8 0 0 1 .75-.05l.3.15c3.3 1.4 6.7 3.15 6.7 6.1zM12 0c3.3 0 5.95 2.95 5.95 6.6 0 3.65-2.65 6.6-5.95 6.6-3.3 0-5.95-2.95-5.95-6.6C6.05 2.95 8.7 0 12 0Z"/>
4
- </svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
2
+ <path fill="currentColor"
3
+ d="M24 20.5v1.1c0 1.3-1.1 2.4-2.4 2.4H2.4A2.45 2.45 0 0 1 0 21.6v-1.1c0-2.9 3.4-4.7 6.6-6.1l.3-.15c.25-.1.5-.1.75.05a7.75 7.75 0 0 0 8.6 0 .8.8 0 0 1 .75-.05l.3.15c3.3 1.4 6.7 3.15 6.7 6.1zM12 0c3.3 0 5.95 2.95 5.95 6.6 0 3.65-2.65 6.6-5.95 6.6-3.3 0-5.95-2.95-5.95-6.6C6.05 2.95 8.7 0 12 0Z"/>
4
+ </svg>
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "fa-mcp-sdk",
3
3
  "productName": "FA MCP SDK",
4
- "version": "0.3.16",
4
+ "version": "0.3.18",
5
5
  "description": "Core infrastructure and templates for building Model Context Protocol (MCP) servers with TypeScript",
6
6
  "type": "module",
7
7
  "main": "dist/core/index.js",