@1mcp/agent 0.35.0-beta.3 → 0.35.0-beta.4

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 (180) hide show
  1. package/build/admin/assets/admin-AboutRuntimeWorkspace-CM2ZafTJ.js +1 -0
  2. package/build/admin/assets/admin-BackendLogsWorkspace-CvJs1npx.js +1 -0
  3. package/build/admin/assets/admin-OAuthServicesWorkspace-BswG57Gm.js +1 -0
  4. package/build/admin/assets/admin-PresetAuthoringWorkspace-BIIRs_EN.js +1 -0
  5. package/build/admin/assets/admin-console-Brz9bnhv.css +1 -0
  6. package/build/admin/assets/{admin-console-Bbil6BQU.css → admin-console-DmRyrCWD.css} +1 -1
  7. package/build/admin/assets/admin-console-MT8QZmIC.js +3 -0
  8. package/build/admin/assets/admin-icons-D-JtMXSq.js +1 -0
  9. package/build/admin/assets/admin-mantine-DSFdoMaN.js +53 -0
  10. package/build/admin/assets/admin-react-BSaWeqgv.js +8 -0
  11. package/build/admin/assets/admin-rolldown-runtime-Bh1tDfsg.js +1 -0
  12. package/build/admin/favicon.svg +4 -0
  13. package/build/admin/index.html +8 -2
  14. package/build/auth/sessionTypes.d.ts +2 -0
  15. package/build/auth/sessionTypes.d.ts.map +1 -1
  16. package/build/auth/sessionTypes.js.map +1 -1
  17. package/build/commands/inspect/inspect.d.ts +1 -0
  18. package/build/commands/inspect/inspect.d.ts.map +1 -1
  19. package/build/commands/inspect/inspect.js +4 -1
  20. package/build/commands/inspect/inspect.js.map +1 -1
  21. package/build/commands/proxy/proxy.d.ts.map +1 -1
  22. package/build/commands/proxy/proxy.js +2 -0
  23. package/build/commands/proxy/proxy.js.map +1 -1
  24. package/build/commands/run/run.d.ts +1 -0
  25. package/build/commands/run/run.d.ts.map +1 -1
  26. package/build/commands/run/run.js +4 -1
  27. package/build/commands/run/run.js.map +1 -1
  28. package/build/commands/serve/index.d.ts +10 -0
  29. package/build/commands/serve/index.d.ts.map +1 -1
  30. package/build/commands/serve/index.js +10 -0
  31. package/build/commands/serve/index.js.map +1 -1
  32. package/build/commands/serve/serve.d.ts +3 -0
  33. package/build/commands/serve/serve.d.ts.map +1 -1
  34. package/build/commands/serve/serve.js +20 -0
  35. package/build/commands/serve/serve.js.map +1 -1
  36. package/build/commands/serve/serveBackground.d.ts.map +1 -1
  37. package/build/commands/serve/serveBackground.js +2 -0
  38. package/build/commands/serve/serveBackground.js.map +1 -1
  39. package/build/commands/serve/templateContextTrust.d.ts +12 -0
  40. package/build/commands/serve/templateContextTrust.d.ts.map +1 -0
  41. package/build/commands/serve/templateContextTrust.js +23 -0
  42. package/build/commands/serve/templateContextTrust.js.map +1 -0
  43. package/build/commands/shared/apiClient.d.ts +3 -0
  44. package/build/commands/shared/apiClient.d.ts.map +1 -1
  45. package/build/commands/shared/apiClient.js +6 -0
  46. package/build/commands/shared/apiClient.js.map +1 -1
  47. package/build/commands/shared/clientSurfaceAttachment.d.ts +11 -0
  48. package/build/commands/shared/clientSurfaceAttachment.d.ts.map +1 -1
  49. package/build/commands/shared/clientSurfaceAttachment.js +64 -6
  50. package/build/commands/shared/clientSurfaceAttachment.js.map +1 -1
  51. package/build/commands/shared/inspectApiSchemas.d.ts +8 -8
  52. package/build/commands/shared/serveClient.d.ts +2 -1
  53. package/build/commands/shared/serveClient.d.ts.map +1 -1
  54. package/build/commands/shared/serveClient.js +3 -1
  55. package/build/commands/shared/serveClient.js.map +1 -1
  56. package/build/commands/shared/serveTargetResolver.d.ts +4 -0
  57. package/build/commands/shared/serveTargetResolver.d.ts.map +1 -1
  58. package/build/commands/shared/serveTargetResolver.js +6 -1
  59. package/build/commands/shared/serveTargetResolver.js.map +1 -1
  60. package/build/commands/wait/wait.d.ts.map +1 -1
  61. package/build/commands/wait/wait.js +1 -0
  62. package/build/commands/wait/wait.js.map +1 -1
  63. package/build/constants/mcp.d.ts +1 -1
  64. package/build/constants/mcp.js +1 -1
  65. package/build/core/capabilities/capabilityCatalog.d.ts +23 -1
  66. package/build/core/capabilities/capabilityCatalog.d.ts.map +1 -1
  67. package/build/core/capabilities/capabilityCatalog.js +63 -1
  68. package/build/core/capabilities/capabilityCatalog.js.map +1 -1
  69. package/build/core/capabilities/capabilityPagination.d.ts +40 -0
  70. package/build/core/capabilities/capabilityPagination.d.ts.map +1 -0
  71. package/build/core/capabilities/capabilityPagination.js +285 -0
  72. package/build/core/capabilities/capabilityPagination.js.map +1 -0
  73. package/build/core/capabilities/capabilityVisibility.d.ts +2 -1
  74. package/build/core/capabilities/capabilityVisibility.d.ts.map +1 -1
  75. package/build/core/capabilities/capabilityVisibility.js +2 -1
  76. package/build/core/capabilities/capabilityVisibility.js.map +1 -1
  77. package/build/core/client/clientManager.d.ts.map +1 -1
  78. package/build/core/client/clientManager.js +5 -0
  79. package/build/core/client/clientManager.js.map +1 -1
  80. package/build/core/context/templateContextTrust.d.ts +66 -0
  81. package/build/core/context/templateContextTrust.d.ts.map +1 -0
  82. package/build/core/context/templateContextTrust.js +184 -0
  83. package/build/core/context/templateContextTrust.js.map +1 -0
  84. package/build/core/protocol/notificationHandlers.d.ts.map +1 -1
  85. package/build/core/protocol/notificationHandlers.js +26 -4
  86. package/build/core/protocol/notificationHandlers.js.map +1 -1
  87. package/build/core/protocol/promptRequestHandlers.d.ts.map +1 -1
  88. package/build/core/protocol/promptRequestHandlers.js +20 -11
  89. package/build/core/protocol/promptRequestHandlers.js.map +1 -1
  90. package/build/core/protocol/requestHandlerUtils.d.ts +4 -0
  91. package/build/core/protocol/requestHandlerUtils.d.ts.map +1 -1
  92. package/build/core/protocol/requestHandlerUtils.js +22 -2
  93. package/build/core/protocol/requestHandlerUtils.js.map +1 -1
  94. package/build/core/protocol/resourceRequestHandlers.d.ts.map +1 -1
  95. package/build/core/protocol/resourceRequestHandlers.js +38 -18
  96. package/build/core/protocol/resourceRequestHandlers.js.map +1 -1
  97. package/build/core/protocol/toolRequestHandlers.d.ts.map +1 -1
  98. package/build/core/protocol/toolRequestHandlers.js +62 -19
  99. package/build/core/protocol/toolRequestHandlers.js.map +1 -1
  100. package/build/core/server/agentConfig.d.ts +4 -0
  101. package/build/core/server/agentConfig.d.ts.map +1 -1
  102. package/build/core/server/agentConfig.js +3 -0
  103. package/build/core/server/agentConfig.js.map +1 -1
  104. package/build/core/server/connectionManager.d.ts.map +1 -1
  105. package/build/core/server/connectionManager.js +2 -0
  106. package/build/core/server/connectionManager.js.map +1 -1
  107. package/build/core/server/requestContextPreparation.d.ts +2 -1
  108. package/build/core/server/requestContextPreparation.d.ts.map +1 -1
  109. package/build/core/server/requestContextPreparation.js.map +1 -1
  110. package/build/core/server/runtimeScopeOwnership.js +1 -1
  111. package/build/core/server/runtimeScopeOwnership.js.map +1 -1
  112. package/build/core/server/templateServerManager.d.ts.map +1 -1
  113. package/build/core/server/templateServerManager.js +2 -0
  114. package/build/core/server/templateServerManager.js.map +1 -1
  115. package/build/core/tools/internal/schemas/discovery.d.ts +1 -1
  116. package/build/core/tools/internal/schemas/index.d.ts +7 -7
  117. package/build/core/tools/internal/schemas/installation.d.ts +3 -3
  118. package/build/core/tools/internal/schemas/management.d.ts +3 -3
  119. package/build/core/types/server.d.ts +2 -0
  120. package/build/core/types/server.d.ts.map +1 -1
  121. package/build/core/types/server.js.map +1 -1
  122. package/build/core/types/transport.d.ts +10 -0
  123. package/build/core/types/transport.d.ts.map +1 -1
  124. package/build/core/types/transport.js +5 -0
  125. package/build/core/types/transport.js.map +1 -1
  126. package/build/domains/admin/adminConfiguredServerService.d.ts +80 -0
  127. package/build/domains/admin/adminConfiguredServerService.d.ts.map +1 -1
  128. package/build/domains/admin/adminConfiguredServerService.js +507 -1
  129. package/build/domains/admin/adminConfiguredServerService.js.map +1 -1
  130. package/build/domains/backend-logs/backendLogSource.d.ts.map +1 -1
  131. package/build/domains/backend-logs/backendLogSource.js.map +1 -1
  132. package/build/domains/config-change/configChange.d.ts +2 -1
  133. package/build/domains/config-change/configChange.d.ts.map +1 -1
  134. package/build/domains/config-change/configChange.js +88 -0
  135. package/build/domains/config-change/configChange.js.map +1 -1
  136. package/build/domains/config-change/types.d.ts +5 -1
  137. package/build/domains/config-change/types.d.ts.map +1 -1
  138. package/build/domains/installation/serverInstallationSourceResolution.js +2 -0
  139. package/build/domains/installation/serverInstallationSourceResolution.js.map +1 -1
  140. package/build/domains/installation/serverInstallationTypes.d.ts +8 -0
  141. package/build/domains/installation/serverInstallationTypes.d.ts.map +1 -1
  142. package/build/domains/installation/serverInstallationWorkflow.js +16 -3
  143. package/build/domains/installation/serverInstallationWorkflow.js.map +1 -1
  144. package/build/transport/http/middlewares/httpRequestLogger.d.ts.map +1 -1
  145. package/build/transport/http/middlewares/httpRequestLogger.js +3 -2
  146. package/build/transport/http/middlewares/httpRequestLogger.js.map +1 -1
  147. package/build/transport/http/routes/adminRoutes.d.ts.map +1 -1
  148. package/build/transport/http/routes/adminRoutes.js +129 -14
  149. package/build/transport/http/routes/adminRoutes.js.map +1 -1
  150. package/build/transport/http/routes/inspectRequestContext.d.ts.map +1 -1
  151. package/build/transport/http/routes/inspectRequestContext.js +13 -4
  152. package/build/transport/http/routes/inspectRequestContext.js.map +1 -1
  153. package/build/transport/http/routes/streamableHttpRoutes.d.ts.map +1 -1
  154. package/build/transport/http/routes/streamableHttpRoutes.js +13 -4
  155. package/build/transport/http/routes/streamableHttpRoutes.js.map +1 -1
  156. package/build/transport/http/storage/streamableSessionRepository.d.ts.map +1 -1
  157. package/build/transport/http/storage/streamableSessionRepository.js +2 -0
  158. package/build/transport/http/storage/streamableSessionRepository.js.map +1 -1
  159. package/build/transport/http/streamableSessionLifecycle.d.ts +3 -1
  160. package/build/transport/http/streamableSessionLifecycle.d.ts.map +1 -1
  161. package/build/transport/http/streamableSessionLifecycle.js +23 -6
  162. package/build/transport/http/streamableSessionLifecycle.js.map +1 -1
  163. package/build/transport/http/utils/contextExtractor.d.ts +14 -16
  164. package/build/transport/http/utils/contextExtractor.d.ts.map +1 -1
  165. package/build/transport/http/utils/contextExtractor.js +124 -33
  166. package/build/transport/http/utils/contextExtractor.js.map +1 -1
  167. package/build/transport/http/utils/templateContextAuthority.d.ts +13 -0
  168. package/build/transport/http/utils/templateContextAuthority.d.ts.map +1 -0
  169. package/build/transport/http/utils/templateContextAuthority.js +121 -0
  170. package/build/transport/http/utils/templateContextAuthority.js.map +1 -0
  171. package/build/transport/stdioProxyTransport.d.ts +3 -0
  172. package/build/transport/stdioProxyTransport.d.ts.map +1 -1
  173. package/build/transport/stdioProxyTransport.js +7 -2
  174. package/build/transport/stdioProxyTransport.js.map +1 -1
  175. package/package.json +1 -1
  176. package/build/admin/assets/admin-console-BOl7XR0p.js +0 -61
  177. package/build/utils/ui/pagination.d.ts +0 -35
  178. package/build/utils/ui/pagination.d.ts.map +0 -1
  179. package/build/utils/ui/pagination.js +0 -166
  180. package/build/utils/ui/pagination.js.map +0 -1
@@ -1,7 +1,8 @@
1
1
  import { createHash } from 'node:crypto';
2
2
  import { mergeGlobalAndServerConfig } from '../../config/mcpConfigMerge.js';
3
3
  import { GLOBAL_TRANSPORT_CONFIG_KEYS, transportConfigSchema, } from '../../core/types/index.js';
4
- import { fingerprintConfiguredServerDefaults, fingerprintConfiguredServerSecretValue, fingerprintConfiguredServerTarget, isConfiguredServerTargetDisabled, } from '../../domains/config-change/configChange.js';
4
+ import { fingerprintConfiguredServerConfigDocument, fingerprintConfiguredServerDefaults, fingerprintConfiguredServerSecretValue, fingerprintConfiguredServerTarget, isConfiguredServerTargetDisabled, } from '../../domains/config-change/configChange.js';
5
+ import { createServerInstallationWorkflow, } from '../../domains/installation/serverInstallationWorkflow.js';
5
6
  import { z } from 'zod';
6
7
  const ENV_PLACEHOLDER_PATTERN = /\$\{[^}]+\}|\$[A-Za-z_][A-Za-z0-9_]*/u;
7
8
  const previewTransportConfigSchema = transportConfigSchema.extend({
@@ -12,6 +13,365 @@ const previewTransportConfigSchema = transportConfigSchema.extend({
12
13
  })
13
14
  .optional(),
14
15
  });
16
+ const configuredServerCreateSecretSchema = z
17
+ .object({
18
+ fieldPath: z.array(z.string()).min(2),
19
+ action: z.literal('replace'),
20
+ replacement: z.object({
21
+ kind: z.enum(['environmentReference', 'inlineSecret']),
22
+ value: z.string(),
23
+ }),
24
+ })
25
+ .strict();
26
+ const configuredServerCreateDraftSchema = z
27
+ .object({
28
+ name: z.string(),
29
+ enabled: z.boolean().optional(),
30
+ tags: z.array(z.string()).optional(),
31
+ transport: z
32
+ .object({
33
+ type: z.enum(['stdio', 'http', 'sse']),
34
+ command: z.string().optional(),
35
+ url: z.string().optional(),
36
+ args: z.array(z.string()).optional(),
37
+ cwd: z.string().optional(),
38
+ env: z.record(z.string(), z.string()).optional(),
39
+ headers: z.record(z.string(), z.string()).optional(),
40
+ timeout: z.number().optional(),
41
+ connectionTimeout: z.number().optional(),
42
+ requestTimeout: z.number().optional(),
43
+ restartOnExit: z.boolean().optional(),
44
+ maxRestarts: z.number().optional(),
45
+ restartDelay: z.number().optional(),
46
+ })
47
+ .strict(),
48
+ secrets: z.array(configuredServerCreateSecretSchema).optional(),
49
+ })
50
+ .strict();
51
+ const CONFIGURED_SERVER_CREATE_TRANSPORT_FIELD_KEYS = new Set([
52
+ 'type',
53
+ 'timeout',
54
+ 'connectionTimeout',
55
+ 'requestTimeout',
56
+ 'url',
57
+ 'headers',
58
+ 'command',
59
+ 'args',
60
+ 'cwd',
61
+ 'env',
62
+ 'restartOnExit',
63
+ 'maxRestarts',
64
+ 'restartDelay',
65
+ ]);
66
+ function normalizeConfiguredServerCreateDraft(value) {
67
+ const parsed = configuredServerCreateDraftSchema.safeParse(value);
68
+ if (!parsed.success) {
69
+ const record = value && typeof value === 'object' && !Array.isArray(value) ? value : {};
70
+ const transport = record.transport && typeof record.transport === 'object' && !Array.isArray(record.transport)
71
+ ? record.transport
72
+ : {};
73
+ const transportType = transport.type === 'http' || transport.type === 'sse' ? transport.type : 'stdio';
74
+ return {
75
+ draft: {},
76
+ source: {
77
+ type: 'direct',
78
+ localName: typeof record.name === 'string' ? record.name : '',
79
+ transport: transportType,
80
+ },
81
+ validation: {
82
+ status: 'invalid',
83
+ errors: parsed.error.issues.map((issue) => ({
84
+ fieldPath: issue.path.map(String),
85
+ code: 'invalid_create_field',
86
+ message: issue.message,
87
+ })),
88
+ },
89
+ };
90
+ }
91
+ const { transport } = parsed.data;
92
+ const draft = {
93
+ name: parsed.data.name,
94
+ enabled: parsed.data.enabled,
95
+ tags: parsed.data.tags,
96
+ transport: { ...transport },
97
+ secrets: parsed.data.secrets,
98
+ };
99
+ const secretContainer = transport.type === 'stdio' ? 'env' : 'headers';
100
+ const secretValues = configuredServerCreateSecretValues(draft, secretContainer);
101
+ const source = {
102
+ type: 'direct',
103
+ localName: parsed.data.name,
104
+ transport: transport.type,
105
+ enabled: parsed.data.enabled,
106
+ tags: parsed.data.tags,
107
+ command: transport.command,
108
+ url: transport.url,
109
+ args: transport.args,
110
+ cwd: transport.cwd,
111
+ env: mergeConfiguredServerCreateRecord(transport.env, secretContainer === 'env' ? secretValues : undefined),
112
+ headers: mergeConfiguredServerCreateRecord(transport.headers, secretContainer === 'headers' ? secretValues : undefined),
113
+ timeout: transport.timeout,
114
+ connectionTimeout: transport.connectionTimeout,
115
+ requestTimeout: transport.requestTimeout,
116
+ autoRestart: transport.restartOnExit,
117
+ maxRestarts: transport.maxRestarts,
118
+ restartDelay: transport.restartDelay,
119
+ };
120
+ return { draft, source, validation: { status: 'valid', errors: [] } };
121
+ }
122
+ function configuredServerCreateSecretValues(draft, container) {
123
+ const values = {};
124
+ for (const secret of draft.secrets ?? []) {
125
+ if (secret.fieldPath.length !== 2 || secret.fieldPath[0] !== container || !isValidFieldPath(secret.fieldPath)) {
126
+ continue;
127
+ }
128
+ if (!secret.replacement)
129
+ continue;
130
+ values[secret.fieldPath[1]] = replacementValue(secret.replacement);
131
+ }
132
+ return values;
133
+ }
134
+ function mergeConfiguredServerCreateRecord(base, additions) {
135
+ const merged = { ...base, ...additions };
136
+ return Object.keys(merged).length > 0 ? merged : undefined;
137
+ }
138
+ function createWorkflowValidation(workflow, config) {
139
+ const errors = [];
140
+ for (const [field, messages] of Object.entries(workflow.fieldErrors ?? {})) {
141
+ for (const message of messages) {
142
+ errors.push({
143
+ fieldPath: field === 'localName' ? ['name'] : ['transport', field],
144
+ code: 'invalid_create_field',
145
+ message,
146
+ });
147
+ }
148
+ }
149
+ if (workflow.status === 'exists' || workflow.status === 'template_conflict') {
150
+ errors.push({
151
+ fieldPath: ['name'],
152
+ code: workflow.status === 'template_conflict' ? 'template_name_conflict' : 'configured_server_name_conflict',
153
+ message: 'A configured server or Template Server definition already uses this name.',
154
+ });
155
+ }
156
+ if (config) {
157
+ const parsed = previewTransportConfigSchema.safeParse(config);
158
+ if (!parsed.success) {
159
+ for (const issue of parsed.error.issues) {
160
+ errors.push({
161
+ fieldPath: ['transport', ...issue.path.map(String)],
162
+ code: 'invalid_transport_config',
163
+ message: issue.message,
164
+ });
165
+ }
166
+ }
167
+ }
168
+ return { status: errors.length === 0 ? 'valid' : 'invalid', errors };
169
+ }
170
+ function validateConfiguredServerCreateSecrets(draft) {
171
+ const errors = [];
172
+ const expectedContainer = draft.transport?.type === 'stdio' ? 'env' : 'headers';
173
+ for (const [index, secret] of (draft.secrets ?? []).entries()) {
174
+ const basePath = ['secrets', String(index)];
175
+ if (!isValidFieldPath(secret.fieldPath) ||
176
+ secret.fieldPath.length !== 2 ||
177
+ secret.fieldPath[0] !== expectedContainer) {
178
+ errors.push({
179
+ fieldPath: [...basePath, 'fieldPath'],
180
+ code: 'unsupported_secret_field',
181
+ message: `Secret replacement must target ${expectedContainer} for the selected transport.`,
182
+ });
183
+ }
184
+ if (!secret.replacement) {
185
+ errors.push({
186
+ fieldPath: [...basePath, 'replacement'],
187
+ code: 'missing_secret_replacement',
188
+ message: 'Create secret actions require a replacement.',
189
+ });
190
+ continue;
191
+ }
192
+ if (secret.replacement.kind === 'environmentReference' && !isEnvironmentReferenceInput(secret.replacement.value)) {
193
+ errors.push({
194
+ fieldPath: [...basePath, 'replacement', 'value'],
195
+ code: 'invalid_environment_reference',
196
+ message: 'Environment reference must be an environment variable name or substitution expression.',
197
+ });
198
+ }
199
+ if (secret.replacement.kind === 'inlineSecret' && secret.replacement.value.length === 0) {
200
+ errors.push({
201
+ fieldPath: [...basePath, 'replacement', 'value'],
202
+ code: 'empty_inline_secret',
203
+ message: 'Inline secret replacement cannot be empty.',
204
+ });
205
+ }
206
+ }
207
+ return { status: errors.length === 0 ? 'valid' : 'invalid', errors };
208
+ }
209
+ function createConfiguredServerCreateContract() {
210
+ const transportFields = TRANSPORT_FIELD_DEFINITIONS.filter((definition) => CONFIGURED_SERVER_CREATE_TRANSPORT_FIELD_KEYS.has(definition.key)).map((definition) => ({
211
+ fieldPath: ['transport', definition.key],
212
+ label: definition.label,
213
+ control: definition.control,
214
+ value: definition.defaultValue,
215
+ options: definition.key === 'type' ? ['stdio', 'http', 'sse'] : definition.options,
216
+ editable: true,
217
+ applicableTransportTypes: definition.applicableTransportTypes?.filter((type) => type !== 'streamableHttp'),
218
+ }));
219
+ return {
220
+ schemaVersion: 1,
221
+ capabilities: {
222
+ create: { supported: true },
223
+ forceReplacement: { supported: false },
224
+ rawJson: { supported: false },
225
+ preview: { supported: true },
226
+ apply: { supported: true },
227
+ },
228
+ secretPolicy: {
229
+ allowedActions: ['replace'],
230
+ environmentReference: {
231
+ recommended: true,
232
+ storesSecretMaterial: false,
233
+ guidance: 'Store an environment variable name or substitution expression instead of secret material.',
234
+ },
235
+ inlineReplacement: {
236
+ emphasis: 'secondary',
237
+ guidance: 'Inline secret material is stored in the Runtime Scope configuration.',
238
+ },
239
+ },
240
+ fieldGroups: [
241
+ {
242
+ id: 'identity',
243
+ label: 'Identity',
244
+ fields: [
245
+ { fieldPath: ['name'], label: 'Server Name', control: 'text', editable: true },
246
+ { fieldPath: ['enabled'], label: 'Enabled', control: 'switch', value: true, editable: true },
247
+ { fieldPath: ['tags'], label: 'Tags', control: 'tag-list', value: [], editable: true },
248
+ ],
249
+ },
250
+ { id: 'transport', label: 'Transport', fields: transportFields },
251
+ ],
252
+ };
253
+ }
254
+ function createConfiguredServerCreateDiff(proposed, draft) {
255
+ const diff = [
256
+ { fieldPath: ['name'], oldValue: undefined, newValue: proposed.id, riskFlags: [] },
257
+ { fieldPath: ['enabled'], oldValue: undefined, newValue: proposed.enabled, riskFlags: ['connection_critical'] },
258
+ { fieldPath: ['tags'], oldValue: undefined, newValue: proposed.tags, riskFlags: [] },
259
+ ];
260
+ for (const [key, value] of Object.entries(proposed.transport)) {
261
+ diff.push({
262
+ fieldPath: ['transport', key],
263
+ oldValue: undefined,
264
+ newValue: value,
265
+ riskFlags: previewRiskFlags([key]),
266
+ });
267
+ }
268
+ for (const secret of draft.secrets ?? []) {
269
+ diff.push({
270
+ fieldPath: secret.fieldPath,
271
+ oldValue: undefined,
272
+ newValue: previewSecretNewValue(secret),
273
+ secretAction: 'replace',
274
+ riskFlags: ['connection_critical', 'secret'],
275
+ });
276
+ }
277
+ return diff;
278
+ }
279
+ function previewSecretNewValue(secret) {
280
+ const replacement = secret.replacement;
281
+ if (!replacement)
282
+ return { present: false, value: '[REDACTED]', secret: true };
283
+ if (replacement.kind === 'environmentReference') {
284
+ return {
285
+ kind: 'environmentReference',
286
+ value: normalizeEnvironmentReference(replacement.value),
287
+ storesSecretMaterial: false,
288
+ };
289
+ }
290
+ return { present: true, value: '[REDACTED]', secret: true };
291
+ }
292
+ function configuredServerCreatePreviewFingerprint(input) {
293
+ const redactedDraft = {
294
+ ...input.draft,
295
+ secrets: input.draft.secrets?.map((secret) => ({
296
+ fieldPath: secret.fieldPath,
297
+ action: secret.action,
298
+ replacement: secret.replacement ? fingerprintSecretReplacement(secret.replacement) : undefined,
299
+ })),
300
+ };
301
+ return `preview_${createHash('sha256')
302
+ .update(stableStringify({
303
+ schemaVersion: 1,
304
+ configFingerprint: input.configFingerprint,
305
+ draft: redactedDraft,
306
+ proposed: input.proposed,
307
+ diff: input.diff,
308
+ validation: input.validation,
309
+ connectivityCheck: connectivityFingerprintFacts(input.connectivityCheck),
310
+ }))
311
+ .digest('hex')}`;
312
+ }
313
+ function connectivityFingerprintFacts(connectivityCheck) {
314
+ if (connectivityCheck.status !== 'passed')
315
+ return connectivityCheck;
316
+ return { status: connectivityCheck.status, mode: connectivityCheck.mode };
317
+ }
318
+ function previewCreateConfigChange(targetName, workflowStatus, changed) {
319
+ const status = workflowStatus === 'template_conflict'
320
+ ? 'template_conflict'
321
+ : workflowStatus === 'exists'
322
+ ? 'destination_conflict'
323
+ : changed
324
+ ? 'changed'
325
+ : 'failed';
326
+ return {
327
+ status,
328
+ operation: 'create_static',
329
+ configPath: '[redacted]',
330
+ target: {
331
+ name: targetName,
332
+ ...(workflowStatus === 'template_conflict'
333
+ ? { source: 'mcpTemplates' }
334
+ : workflowStatus === 'exists'
335
+ ? { source: 'mcpServers' }
336
+ : {}),
337
+ },
338
+ changed,
339
+ backup: { created: false },
340
+ retentionCleanup: { attempted: false, deletedPaths: [], warnings: [] },
341
+ reload: { status: 'skipped' },
342
+ warnings: [],
343
+ };
344
+ }
345
+ function createDraftCandidateName(value) {
346
+ if (!value || typeof value !== 'object' || Array.isArray(value))
347
+ return '';
348
+ const name = value.name;
349
+ return typeof name === 'string' ? name : '';
350
+ }
351
+ function sanitizeCreateConfirmationFacts(facts) {
352
+ if (!facts)
353
+ return undefined;
354
+ const allowed = [
355
+ 'previewConfirmed',
356
+ 'targetNameConfirmed',
357
+ 'secretChangeConfirmed',
358
+ 'connectionCriticalConfirmed',
359
+ 'connectivityFailureOverrideConfirmed',
360
+ ];
361
+ const sanitized = Object.fromEntries(allowed.filter((key) => key in facts).map((key) => [key, facts[key]]));
362
+ return Object.keys(sanitized).length ? sanitized : undefined;
363
+ }
364
+ function assertSuccessfulConfiguredServerCreate(configChange) {
365
+ if (configChange.status === 'changed')
366
+ return;
367
+ if (configChange.status === 'source_conflict') {
368
+ throw new AdminConfiguredServerApplyError('configured_server_stale_preview');
369
+ }
370
+ if (configChange.status === 'destination_conflict' || configChange.status === 'template_conflict') {
371
+ throw new AdminConfiguredServerApplyError('configured_server_destination_conflict');
372
+ }
373
+ throw new AdminConfiguredServerApplyError('configured_server_create_failed');
374
+ }
15
375
  export class AdminConfiguredServerNotFoundError extends Error {
16
376
  targetName;
17
377
  code = 'configured_server_not_found';
@@ -26,6 +386,88 @@ export class AdminConfiguredServerService {
26
386
  constructor(options) {
27
387
  this.options = options;
28
388
  }
389
+ async getConfiguredServerCreateContract(input) {
390
+ return this.options.operationService.executeReadOnly({
391
+ context: input.context,
392
+ operationName: 'getConfiguredServerCreateContract',
393
+ run: async () => createConfiguredServerCreateContract(),
394
+ });
395
+ }
396
+ async previewConfiguredServerCreate(input) {
397
+ return this.options.operationService.executeDryRun({
398
+ context: input.context,
399
+ operationName: 'previewConfiguredServerCreate',
400
+ run: async () => this.previewConfiguredServerCreateResult(input),
401
+ });
402
+ }
403
+ async applyConfiguredServerCreate(input) {
404
+ const candidateName = createDraftCandidateName(input.draft);
405
+ const context = {
406
+ ...input.context,
407
+ target: { type: 'configured_server', id: candidateName },
408
+ confirmationFacts: sanitizeCreateConfirmationFacts(input.context.confirmationFacts),
409
+ };
410
+ return this.options.operationService.executeMutation({
411
+ context,
412
+ operationName: 'applyConfiguredServerCreate',
413
+ prepare: async () => {
414
+ const document = this.options.readConfigDocument() ?? {};
415
+ const preview = await this.previewConfiguredServerCreateResult({ ...input, connectivityCheck: 'auto' }, true, document);
416
+ if (preview.previewFingerprint !== input.previewFingerprint) {
417
+ throw new AdminConfiguredServerApplyError('configured_server_stale_preview');
418
+ }
419
+ if (preview.validation.status !== 'valid' || !preview.configChange.changed) {
420
+ throw new AdminConfiguredServerApplyError('configured_server_create_invalid');
421
+ }
422
+ const prepared = await this.resolveConfiguredServerCreate(input.draft, document);
423
+ if (!prepared.config) {
424
+ throw new AdminConfiguredServerApplyError('configured_server_create_invalid');
425
+ }
426
+ if (prepared.enabled &&
427
+ !wouldUseLocalStdioTransport(prepared.config) &&
428
+ preview.connectivityCheck.status !== 'passed' &&
429
+ !(preview.connectivityCheck.status === 'skipped' && preview.connectivityCheck.reason === 'checker_unavailable') &&
430
+ !(preview.connectivityCheck.status === 'failed' &&
431
+ input.context.confirmationFacts?.connectivityFailureOverrideConfirmed === true)) {
432
+ throw new AdminConfiguredServerApplyError('configured_server_connectivity_blocked');
433
+ }
434
+ const secretChange = prepared.draft.secrets?.length;
435
+ const configFingerprint = fingerprintConfiguredServerConfigDocument(document);
436
+ return {
437
+ confirmationRequirements: [
438
+ { code: 'previewConfirmed', expected: input.previewFingerprint },
439
+ { code: 'targetNameConfirmed', expected: prepared.targetName },
440
+ { code: 'connectionCriticalConfirmed', expected: true },
441
+ ...(secretChange ? [{ code: 'secretChangeConfirmed', expected: true }] : []),
442
+ ...(preview.connectivityCheck.status === 'failed'
443
+ ? [{ code: 'connectivityFailureOverrideConfirmed', expected: true }]
444
+ : []),
445
+ ],
446
+ run: async () => {
447
+ let configChange;
448
+ try {
449
+ configChange = await this.options.configChangeService.createStaticConfiguredServerTarget({
450
+ targetName: prepared.targetName,
451
+ serverConfig: prepared.config,
452
+ operation: 'install',
453
+ backup: 'skip',
454
+ expectedConfigFingerprint: configFingerprint,
455
+ });
456
+ }
457
+ catch {
458
+ throw new AdminConfiguredServerApplyError('configured_server_create_failed');
459
+ }
460
+ assertSuccessfulConfiguredServerCreate(configChange);
461
+ return {
462
+ targetName: prepared.targetName,
463
+ previewFingerprint: preview.previewFingerprint,
464
+ configChange,
465
+ };
466
+ },
467
+ };
468
+ },
469
+ });
470
+ }
29
471
  async listConfiguredServers(input) {
30
472
  return this.options.operationService.executeReadOnly({
31
473
  context: input.context,
@@ -280,6 +722,70 @@ export class AdminConfiguredServerService {
280
722
  serverConfig: input.serverConfig,
281
723
  });
282
724
  }
725
+ async previewConfiguredServerCreateResult(input, forceConnectivity = false, document = this.options.readConfigDocument() ?? {}) {
726
+ const prepared = await this.resolveConfiguredServerCreate(input.draft, document);
727
+ const proposedReadModel = prepared.config
728
+ ? createConfiguredServerReadModel(prepared.targetName, mergeGlobalAndServerConfig(document.serverDefaults, prepared.config))
729
+ : undefined;
730
+ const validation = prepared.validation;
731
+ const diff = proposedReadModel ? createConfiguredServerCreateDiff(proposedReadModel, prepared.draft) : [];
732
+ const changed = validation.status === 'valid' && prepared.workflow.status === 'preview';
733
+ const connectivityCheck = prepared.config
734
+ ? await this.previewConnectivityCheck({
735
+ targetName: prepared.targetName,
736
+ serverConfig: prepared.config,
737
+ enabled: prepared.enabled,
738
+ validationStatus: validation.status,
739
+ connectionCriticalChanged: true,
740
+ force: forceConnectivity || input.connectivityCheck === 'manual',
741
+ endpointChangedWithPreservedSecrets: false,
742
+ })
743
+ : { status: 'skipped', reason: 'validation_failed' };
744
+ const preview = {
745
+ targetName: prepared.targetName,
746
+ previewFingerprint: configuredServerCreatePreviewFingerprint({
747
+ configFingerprint: fingerprintConfiguredServerConfigDocument(document),
748
+ draft: prepared.draft,
749
+ proposed: proposedReadModel,
750
+ diff,
751
+ validation,
752
+ connectivityCheck,
753
+ }),
754
+ validation,
755
+ diff,
756
+ configChange: previewCreateConfigChange(prepared.targetName, prepared.workflow.status, changed),
757
+ connectivityCheck,
758
+ expectedReload: {
759
+ policy: 'observe_after_write',
760
+ possibleStatuses: ['observed', 'runtime_not_running', 'reload_disabled', 'failed'],
761
+ },
762
+ };
763
+ return preview;
764
+ }
765
+ async resolveConfiguredServerCreate(draftValue, document = this.options.readConfigDocument() ?? {}) {
766
+ const normalized = normalizeConfiguredServerCreateDraft(draftValue);
767
+ const workflow = createServerInstallationWorkflow({
768
+ findConfiguredTarget: (targetName) => {
769
+ if (document.mcpTemplates?.[targetName])
770
+ return { name: targetName, source: 'mcpTemplates' };
771
+ if (document.mcpServers?.[targetName])
772
+ return { name: targetName, source: 'mcpServers' };
773
+ return null;
774
+ },
775
+ });
776
+ const workflowResult = await workflow.run({ mode: 'preview', source: normalized.source });
777
+ const config = workflowResult.config;
778
+ const validation = mergeValidation(mergeValidation(normalized.validation, validateConfiguredServerCreateSecrets(normalized.draft)), createWorkflowValidation(workflowResult, config));
779
+ return {
780
+ draft: normalized.draft,
781
+ source: normalized.source,
782
+ targetName: normalized.source.localName,
783
+ enabled: normalized.source.enabled !== false,
784
+ workflow: workflowResult,
785
+ config,
786
+ validation,
787
+ };
788
+ }
283
789
  }
284
790
  function assertSuccessfulConfigChange(configChange) {
285
791
  if (configChange.reload.status === 'failed') {