sap-ai-dev-toolkit 0.9.9913 → 0.9.9914
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/.github/agents/sap-integration-architect.agent.md +38 -0
- package/.github/agents/sap-integration-developer.agent.md +31 -0
- package/.github/agents/sap-solution-architect.agent.md +1 -0
- package/.github/skills/integration-suite-delivery/SKILL.md +74 -0
- package/.github/skills/sap-integration-architect/SKILL.md +76 -0
- package/NOTICE +10 -0
- package/README.md +34 -8
- package/dist/checksums.txt +5 -5
- package/dist/vsp-darwin-arm64 +0 -0
- package/dist/vsp-darwin-x64 +0 -0
- package/dist/vsp-linux-arm64 +0 -0
- package/dist/vsp-linux-x64 +0 -0
- package/dist/vsp-win32-x64.exe +0 -0
- package/inventory.md +62 -0
- package/package.json +5 -2
- package/scripts/run-live-integration.mjs +1079 -0
- package/src/apim-bundle.mjs +381 -0
- package/src/apim-tools.mjs +641 -0
- package/src/cpi-tools.mjs +1042 -0
- package/src/iflow-bundle.mjs +282 -0
- package/src/integration-common.mjs +232 -0
- package/src/integration-config.mjs +167 -0
- package/src/integration-credentials.mjs +65 -0
- package/src/integration-http.mjs +266 -0
- package/src/integration-server.mjs +125 -0
- package/src/integration-templates/https-request-reply-http.iflw +391 -0
- package/src/integration-tools.mjs +27 -0
- package/src/integration-verify.mjs +118 -0
- package/src/launcher.mjs +14 -2
- package/src/mcp-config.mjs +18 -3
- package/src/setup.mjs +189 -11
- package/tools.md +76 -0
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?><bpmn2:definitions xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:ifl="http:///com.sap.ifl.model/Ifl.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="Definitions_1">
|
|
2
|
+
<bpmn2:collaboration id="Collaboration_1" name="Default Collaboration">
|
|
3
|
+
<bpmn2:extensionElements>
|
|
4
|
+
<ifl:property>
|
|
5
|
+
<key>namespaceMapping</key>
|
|
6
|
+
<value/>
|
|
7
|
+
</ifl:property>
|
|
8
|
+
<ifl:property>
|
|
9
|
+
<key>httpSessionHandling</key>
|
|
10
|
+
<value>None</value>
|
|
11
|
+
</ifl:property>
|
|
12
|
+
<ifl:property>
|
|
13
|
+
<key>accessControlMaxAge</key>
|
|
14
|
+
<value/>
|
|
15
|
+
</ifl:property>
|
|
16
|
+
<ifl:property>
|
|
17
|
+
<key>returnExceptionToSender</key>
|
|
18
|
+
<value>false</value>
|
|
19
|
+
</ifl:property>
|
|
20
|
+
<ifl:property>
|
|
21
|
+
<key>log</key>
|
|
22
|
+
<value>All events</value>
|
|
23
|
+
</ifl:property>
|
|
24
|
+
<ifl:property>
|
|
25
|
+
<key>corsEnabled</key>
|
|
26
|
+
<value/>
|
|
27
|
+
</ifl:property>
|
|
28
|
+
<ifl:property>
|
|
29
|
+
<key>exposedHeaders</key>
|
|
30
|
+
<value/>
|
|
31
|
+
</ifl:property>
|
|
32
|
+
<ifl:property>
|
|
33
|
+
<key>componentVersion</key>
|
|
34
|
+
<value>1.2</value>
|
|
35
|
+
</ifl:property>
|
|
36
|
+
<ifl:property>
|
|
37
|
+
<key>allowedHeaderList</key>
|
|
38
|
+
<value/>
|
|
39
|
+
</ifl:property>
|
|
40
|
+
<ifl:property>
|
|
41
|
+
<key>ServerTrace</key>
|
|
42
|
+
<value>false</value>
|
|
43
|
+
</ifl:property>
|
|
44
|
+
<ifl:property>
|
|
45
|
+
<key>allowedOrigins</key>
|
|
46
|
+
<value/>
|
|
47
|
+
</ifl:property>
|
|
48
|
+
<ifl:property>
|
|
49
|
+
<key>accessControlAllowCredentials</key>
|
|
50
|
+
<value/>
|
|
51
|
+
</ifl:property>
|
|
52
|
+
<ifl:property>
|
|
53
|
+
<key>allowedHeaders</key>
|
|
54
|
+
<value/>
|
|
55
|
+
</ifl:property>
|
|
56
|
+
<ifl:property>
|
|
57
|
+
<key>allowedMethods</key>
|
|
58
|
+
<value/>
|
|
59
|
+
</ifl:property>
|
|
60
|
+
<ifl:property>
|
|
61
|
+
<key>cmdVariantUri</key>
|
|
62
|
+
<value>ctype::IFlowVariant/cname::IFlowConfiguration/version::1.2.3</value>
|
|
63
|
+
</ifl:property>
|
|
64
|
+
</bpmn2:extensionElements>
|
|
65
|
+
<bpmn2:participant id="Participant_1" ifl:type="EndpointSender" name="Sender">
|
|
66
|
+
<bpmn2:extensionElements>
|
|
67
|
+
<ifl:property>
|
|
68
|
+
<key>enableBasicAuthentication</key>
|
|
69
|
+
<value>false</value>
|
|
70
|
+
</ifl:property>
|
|
71
|
+
<ifl:property>
|
|
72
|
+
<key>ifl:type</key>
|
|
73
|
+
<value>EndpointSender</value>
|
|
74
|
+
</ifl:property>
|
|
75
|
+
</bpmn2:extensionElements>
|
|
76
|
+
</bpmn2:participant>
|
|
77
|
+
<bpmn2:participant id="Participant_2" ifl:type="EndpointRecevier" name="Receiver">
|
|
78
|
+
<bpmn2:extensionElements>
|
|
79
|
+
<ifl:property>
|
|
80
|
+
<key>ifl:type</key>
|
|
81
|
+
<value>EndpointRecevier</value>
|
|
82
|
+
</ifl:property>
|
|
83
|
+
</bpmn2:extensionElements>
|
|
84
|
+
</bpmn2:participant>
|
|
85
|
+
<bpmn2:participant id="Participant_Process_1" ifl:type="IntegrationProcess" name="Integration Process" processRef="Process_1">
|
|
86
|
+
<bpmn2:extensionElements/>
|
|
87
|
+
</bpmn2:participant>
|
|
88
|
+
<bpmn2:messageFlow id="MessageFlow_4" name="HTTPS" sourceRef="Participant_1" targetRef="StartEvent_2">
|
|
89
|
+
<bpmn2:extensionElements>
|
|
90
|
+
<ifl:property>
|
|
91
|
+
<key>ComponentType</key>
|
|
92
|
+
<value>HTTPS</value>
|
|
93
|
+
</ifl:property>
|
|
94
|
+
<ifl:property>
|
|
95
|
+
<key>Description</key>
|
|
96
|
+
<value/>
|
|
97
|
+
</ifl:property>
|
|
98
|
+
<ifl:property>
|
|
99
|
+
<key>maximumBodySize</key>
|
|
100
|
+
<value>40</value>
|
|
101
|
+
</ifl:property>
|
|
102
|
+
<ifl:property>
|
|
103
|
+
<key>ComponentNS</key>
|
|
104
|
+
<value>sap</value>
|
|
105
|
+
</ifl:property>
|
|
106
|
+
<ifl:property>
|
|
107
|
+
<key>componentVersion</key>
|
|
108
|
+
<value>1.4</value>
|
|
109
|
+
</ifl:property>
|
|
110
|
+
<ifl:property>
|
|
111
|
+
<key>urlPath</key>
|
|
112
|
+
<value>{{Sender_Path}}</value>
|
|
113
|
+
</ifl:property>
|
|
114
|
+
<ifl:property>
|
|
115
|
+
<key>Name</key>
|
|
116
|
+
<value>HTTPS</value>
|
|
117
|
+
</ifl:property>
|
|
118
|
+
<ifl:property>
|
|
119
|
+
<key>TransportProtocolVersion</key>
|
|
120
|
+
<value>1.4.3</value>
|
|
121
|
+
</ifl:property>
|
|
122
|
+
<ifl:property>
|
|
123
|
+
<key>ComponentSWCVName</key>
|
|
124
|
+
<value>external</value>
|
|
125
|
+
</ifl:property>
|
|
126
|
+
<ifl:property>
|
|
127
|
+
<key>system</key>
|
|
128
|
+
<value>Sender</value>
|
|
129
|
+
</ifl:property>
|
|
130
|
+
<ifl:property>
|
|
131
|
+
<key>xsrfProtection</key>
|
|
132
|
+
<value>0</value>
|
|
133
|
+
</ifl:property>
|
|
134
|
+
<ifl:property>
|
|
135
|
+
<key>TransportProtocol</key>
|
|
136
|
+
<value>HTTPS</value>
|
|
137
|
+
</ifl:property>
|
|
138
|
+
<ifl:property>
|
|
139
|
+
<key>cmdVariantUri</key>
|
|
140
|
+
<value>ctype::AdapterVariant/cname::sap:HTTPS/tp::HTTPS/mp::None/direction::Sender/version::1.4.3</value>
|
|
141
|
+
</ifl:property>
|
|
142
|
+
<ifl:property>
|
|
143
|
+
<key>userRole</key>
|
|
144
|
+
<value>ESBMessaging.send</value>
|
|
145
|
+
</ifl:property>
|
|
146
|
+
<ifl:property>
|
|
147
|
+
<key>senderAuthType</key>
|
|
148
|
+
<value>RoleBased</value>
|
|
149
|
+
</ifl:property>
|
|
150
|
+
<ifl:property>
|
|
151
|
+
<key>MessageProtocol</key>
|
|
152
|
+
<value>None</value>
|
|
153
|
+
</ifl:property>
|
|
154
|
+
<ifl:property>
|
|
155
|
+
<key>MessageProtocolVersion</key>
|
|
156
|
+
<value>1.4.3</value>
|
|
157
|
+
</ifl:property>
|
|
158
|
+
<ifl:property>
|
|
159
|
+
<key>ComponentSWCVId</key>
|
|
160
|
+
<value>1.4.3</value>
|
|
161
|
+
</ifl:property>
|
|
162
|
+
<ifl:property>
|
|
163
|
+
<key>direction</key>
|
|
164
|
+
<value>Sender</value>
|
|
165
|
+
</ifl:property>
|
|
166
|
+
<ifl:property>
|
|
167
|
+
<key>clientCertificates</key>
|
|
168
|
+
<value/>
|
|
169
|
+
</ifl:property>
|
|
170
|
+
</bpmn2:extensionElements>
|
|
171
|
+
</bpmn2:messageFlow>
|
|
172
|
+
<bpmn2:messageFlow id="MessageFlow_7" name="HTTP" sourceRef="ServiceTask_1" targetRef="Participant_2">
|
|
173
|
+
<bpmn2:extensionElements>
|
|
174
|
+
<ifl:property>
|
|
175
|
+
<key>Description</key>
|
|
176
|
+
<value/>
|
|
177
|
+
</ifl:property>
|
|
178
|
+
<ifl:property>
|
|
179
|
+
<key>methodSourceExpression</key>
|
|
180
|
+
<value/>
|
|
181
|
+
</ifl:property>
|
|
182
|
+
<ifl:property>
|
|
183
|
+
<key>ComponentNS</key>
|
|
184
|
+
<value>sap</value>
|
|
185
|
+
</ifl:property>
|
|
186
|
+
<ifl:property>
|
|
187
|
+
<key>privateKeyAlias</key>
|
|
188
|
+
<value/>
|
|
189
|
+
</ifl:property>
|
|
190
|
+
<ifl:property>
|
|
191
|
+
<key>httpMethod</key>
|
|
192
|
+
<value>{{Receiver_Method}}</value>
|
|
193
|
+
</ifl:property>
|
|
194
|
+
<ifl:property>
|
|
195
|
+
<key>Name</key>
|
|
196
|
+
<value>HTTP</value>
|
|
197
|
+
</ifl:property>
|
|
198
|
+
<ifl:property>
|
|
199
|
+
<key>TransportProtocolVersion</key>
|
|
200
|
+
<value>1.7.2</value>
|
|
201
|
+
</ifl:property>
|
|
202
|
+
<ifl:property>
|
|
203
|
+
<key>ComponentSWCVName</key>
|
|
204
|
+
<value>external</value>
|
|
205
|
+
</ifl:property>
|
|
206
|
+
<ifl:property>
|
|
207
|
+
<key>proxyPort</key>
|
|
208
|
+
<value/>
|
|
209
|
+
</ifl:property>
|
|
210
|
+
<ifl:property>
|
|
211
|
+
<key>httpAddressQuery</key>
|
|
212
|
+
<value>{{Receiver_Query}}</value>
|
|
213
|
+
</ifl:property>
|
|
214
|
+
<ifl:property>
|
|
215
|
+
<key>httpRequestTimeout</key>
|
|
216
|
+
<value>{{Receiver_Timeout}}</value>
|
|
217
|
+
</ifl:property>
|
|
218
|
+
<ifl:property>
|
|
219
|
+
<key>MessageProtocol</key>
|
|
220
|
+
<value>None</value>
|
|
221
|
+
</ifl:property>
|
|
222
|
+
<ifl:property>
|
|
223
|
+
<key>ComponentSWCVId</key>
|
|
224
|
+
<value>1.7.2</value>
|
|
225
|
+
</ifl:property>
|
|
226
|
+
<ifl:property>
|
|
227
|
+
<key>direction</key>
|
|
228
|
+
<value>Receiver</value>
|
|
229
|
+
</ifl:property>
|
|
230
|
+
<ifl:property>
|
|
231
|
+
<key>ComponentType</key>
|
|
232
|
+
<value>HTTP</value>
|
|
233
|
+
</ifl:property>
|
|
234
|
+
<ifl:property>
|
|
235
|
+
<key>httpShouldSendBody</key>
|
|
236
|
+
<value>true</value>
|
|
237
|
+
</ifl:property>
|
|
238
|
+
<ifl:property>
|
|
239
|
+
<key>proxyType</key>
|
|
240
|
+
<value>{{Receiver_Proxy_Type}}</value>
|
|
241
|
+
</ifl:property>
|
|
242
|
+
<ifl:property>
|
|
243
|
+
<key>componentVersion</key>
|
|
244
|
+
<value>1.7</value>
|
|
245
|
+
</ifl:property>
|
|
246
|
+
<ifl:property>
|
|
247
|
+
<key>proxyHost</key>
|
|
248
|
+
<value/>
|
|
249
|
+
</ifl:property>
|
|
250
|
+
<ifl:property>
|
|
251
|
+
<key>system</key>
|
|
252
|
+
<value>Receiver</value>
|
|
253
|
+
</ifl:property>
|
|
254
|
+
<ifl:property>
|
|
255
|
+
<key>authenticationMethod</key>
|
|
256
|
+
<value>{{Receiver_Authentication}}</value>
|
|
257
|
+
</ifl:property>
|
|
258
|
+
<ifl:property>
|
|
259
|
+
<key>locationID</key>
|
|
260
|
+
<value>{{Receiver_Location_ID}}</value>
|
|
261
|
+
</ifl:property>
|
|
262
|
+
<ifl:property>
|
|
263
|
+
<key>TransportProtocol</key>
|
|
264
|
+
<value>HTTP</value>
|
|
265
|
+
</ifl:property>
|
|
266
|
+
<ifl:property>
|
|
267
|
+
<key>cmdVariantUri</key>
|
|
268
|
+
<value>ctype::AdapterVariant/cname::sap:HTTP/tp::HTTP/mp::None/direction::Receiver/version::1.7.2</value>
|
|
269
|
+
</ifl:property>
|
|
270
|
+
<ifl:property>
|
|
271
|
+
<key>credentialName</key>
|
|
272
|
+
<value>{{Receiver_Credential_Name}}</value>
|
|
273
|
+
</ifl:property>
|
|
274
|
+
<ifl:property>
|
|
275
|
+
<key>MessageProtocolVersion</key>
|
|
276
|
+
<value>1.7.2</value>
|
|
277
|
+
</ifl:property>
|
|
278
|
+
<ifl:property>
|
|
279
|
+
<key>httpAddressWithoutQuery</key>
|
|
280
|
+
<value>{{Receiver_Address}}</value>
|
|
281
|
+
</ifl:property>
|
|
282
|
+
</bpmn2:extensionElements>
|
|
283
|
+
</bpmn2:messageFlow>
|
|
284
|
+
</bpmn2:collaboration>
|
|
285
|
+
<bpmn2:process id="Process_1" name="Integration Process">
|
|
286
|
+
<bpmn2:extensionElements>
|
|
287
|
+
<ifl:property>
|
|
288
|
+
<key>transactionTimeout</key>
|
|
289
|
+
<value>30</value>
|
|
290
|
+
</ifl:property>
|
|
291
|
+
<ifl:property>
|
|
292
|
+
<key>componentVersion</key>
|
|
293
|
+
<value>1.2</value>
|
|
294
|
+
</ifl:property>
|
|
295
|
+
<ifl:property>
|
|
296
|
+
<key>cmdVariantUri</key>
|
|
297
|
+
<value>ctype::FlowElementVariant/cname::IntegrationProcess/version::1.2.1</value>
|
|
298
|
+
</ifl:property>
|
|
299
|
+
<ifl:property>
|
|
300
|
+
<key>transactionalHandling</key>
|
|
301
|
+
<value>Not Required</value>
|
|
302
|
+
</ifl:property>
|
|
303
|
+
</bpmn2:extensionElements>
|
|
304
|
+
<bpmn2:startEvent id="StartEvent_2" name="Start">
|
|
305
|
+
<bpmn2:extensionElements>
|
|
306
|
+
<ifl:property>
|
|
307
|
+
<key>componentVersion</key>
|
|
308
|
+
<value>1.0</value>
|
|
309
|
+
</ifl:property>
|
|
310
|
+
<ifl:property>
|
|
311
|
+
<key>cmdVariantUri</key>
|
|
312
|
+
<value>ctype::FlowstepVariant/cname::MessageStartEvent/version::1.0</value>
|
|
313
|
+
</ifl:property>
|
|
314
|
+
</bpmn2:extensionElements>
|
|
315
|
+
<bpmn2:outgoing>SequenceFlow_3</bpmn2:outgoing>
|
|
316
|
+
<bpmn2:messageEventDefinition/>
|
|
317
|
+
</bpmn2:startEvent>
|
|
318
|
+
<bpmn2:endEvent id="EndEvent_2" name="End">
|
|
319
|
+
<bpmn2:extensionElements>
|
|
320
|
+
<ifl:property>
|
|
321
|
+
<key>componentVersion</key>
|
|
322
|
+
<value>1.1</value>
|
|
323
|
+
</ifl:property>
|
|
324
|
+
<ifl:property>
|
|
325
|
+
<key>cmdVariantUri</key>
|
|
326
|
+
<value>ctype::FlowstepVariant/cname::MessageEndEvent/version::1.1.0</value>
|
|
327
|
+
</ifl:property>
|
|
328
|
+
</bpmn2:extensionElements>
|
|
329
|
+
<bpmn2:incoming>SequenceFlow_6</bpmn2:incoming>
|
|
330
|
+
<bpmn2:messageEventDefinition/>
|
|
331
|
+
</bpmn2:endEvent>
|
|
332
|
+
<bpmn2:serviceTask id="ServiceTask_1" name="Request Reply 1">
|
|
333
|
+
<bpmn2:extensionElements>
|
|
334
|
+
<ifl:property>
|
|
335
|
+
<key>componentVersion</key>
|
|
336
|
+
<value>1.0</value>
|
|
337
|
+
</ifl:property>
|
|
338
|
+
<ifl:property>
|
|
339
|
+
<key>activityType</key>
|
|
340
|
+
<value>ExternalCall</value>
|
|
341
|
+
</ifl:property>
|
|
342
|
+
<ifl:property>
|
|
343
|
+
<key>cmdVariantUri</key>
|
|
344
|
+
<value>ctype::FlowstepVariant/cname::ExternalCall/version::1.0.4</value>
|
|
345
|
+
</ifl:property>
|
|
346
|
+
</bpmn2:extensionElements>
|
|
347
|
+
<bpmn2:incoming>SequenceFlow_3</bpmn2:incoming>
|
|
348
|
+
<bpmn2:outgoing>SequenceFlow_6</bpmn2:outgoing>
|
|
349
|
+
</bpmn2:serviceTask>
|
|
350
|
+
<bpmn2:sequenceFlow id="SequenceFlow_3" sourceRef="StartEvent_2" targetRef="ServiceTask_1"/>
|
|
351
|
+
<bpmn2:sequenceFlow id="SequenceFlow_6" sourceRef="ServiceTask_1" targetRef="EndEvent_2"/>
|
|
352
|
+
</bpmn2:process>
|
|
353
|
+
<bpmndi:BPMNDiagram id="BPMNDiagram_1" name="Default Collaboration Diagram">
|
|
354
|
+
<bpmndi:BPMNPlane bpmnElement="Collaboration_1" id="BPMNPlane_1">
|
|
355
|
+
<bpmndi:BPMNShape bpmnElement="EndEvent_2" id="BPMNShape_EndEvent_2">
|
|
356
|
+
<dc:Bounds height="32.0" width="32.0" x="703.0" y="142.0"/>
|
|
357
|
+
</bpmndi:BPMNShape>
|
|
358
|
+
<bpmndi:BPMNShape bpmnElement="StartEvent_2" id="BPMNShape_StartEvent_2">
|
|
359
|
+
<dc:Bounds height="32.0" width="32.0" x="292.0" y="142.0"/>
|
|
360
|
+
</bpmndi:BPMNShape>
|
|
361
|
+
<bpmndi:BPMNShape bpmnElement="ServiceTask_1" id="BPMNShape_ServiceTask_1">
|
|
362
|
+
<dc:Bounds height="60.0" width="100.0" x="412.0" y="132.0"/>
|
|
363
|
+
</bpmndi:BPMNShape>
|
|
364
|
+
<bpmndi:BPMNShape bpmnElement="Participant_2" id="BPMNShape_Participant_2">
|
|
365
|
+
<dc:Bounds height="140.0" width="100.0" x="900.0" y="100.0"/>
|
|
366
|
+
</bpmndi:BPMNShape>
|
|
367
|
+
<bpmndi:BPMNShape bpmnElement="Participant_1" id="BPMNShape_Participant_1">
|
|
368
|
+
<dc:Bounds height="140.0" width="100.0" x="40.0" y="100.0"/>
|
|
369
|
+
</bpmndi:BPMNShape>
|
|
370
|
+
<bpmndi:BPMNShape bpmnElement="Participant_Process_1" id="BPMNShape_Participant_Process_1">
|
|
371
|
+
<dc:Bounds height="220.0" width="540.0" x="250.0" y="60.0"/>
|
|
372
|
+
</bpmndi:BPMNShape>
|
|
373
|
+
<bpmndi:BPMNEdge bpmnElement="SequenceFlow_6" id="BPMNEdge_SequenceFlow_6" sourceElement="BPMNShape_ServiceTask_1" targetElement="BPMNShape_EndEvent_2">
|
|
374
|
+
<di:waypoint x="462.0" xsi:type="dc:Point" y="160.0"/>
|
|
375
|
+
<di:waypoint x="719.0" xsi:type="dc:Point" y="160.0"/>
|
|
376
|
+
</bpmndi:BPMNEdge>
|
|
377
|
+
<bpmndi:BPMNEdge bpmnElement="SequenceFlow_3" id="BPMNEdge_SequenceFlow_3" sourceElement="BPMNShape_StartEvent_2" targetElement="BPMNShape_ServiceTask_1">
|
|
378
|
+
<di:waypoint x="308.0" xsi:type="dc:Point" y="160.0"/>
|
|
379
|
+
<di:waypoint x="462.0" xsi:type="dc:Point" y="160.0"/>
|
|
380
|
+
</bpmndi:BPMNEdge>
|
|
381
|
+
<bpmndi:BPMNEdge bpmnElement="MessageFlow_4" id="BPMNEdge_MessageFlow_4" sourceElement="BPMNShape_Participant_1" targetElement="BPMNShape_StartEvent_2">
|
|
382
|
+
<di:waypoint x="90.0" xsi:type="dc:Point" y="170.0"/>
|
|
383
|
+
<di:waypoint x="308.0" xsi:type="dc:Point" y="158.0"/>
|
|
384
|
+
</bpmndi:BPMNEdge>
|
|
385
|
+
<bpmndi:BPMNEdge bpmnElement="MessageFlow_7" id="BPMNEdge_MessageFlow_7" sourceElement="BPMNShape_ServiceTask_1" targetElement="BPMNShape_Participant_2">
|
|
386
|
+
<di:waypoint x="462.0" xsi:type="dc:Point" y="162.0"/>
|
|
387
|
+
<di:waypoint x="950.0" xsi:type="dc:Point" y="170.0"/>
|
|
388
|
+
</bpmndi:BPMNEdge>
|
|
389
|
+
</bpmndi:BPMNPlane>
|
|
390
|
+
</bpmndi:BPMNDiagram>
|
|
391
|
+
</bpmn2:definitions>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// MCP tools for SAP Integration Suite: Cloud Integration (CPI) and API Management (APIM).
|
|
2
|
+
// Writes cover create, update, deploy and undeploy — there are no delete tools — and every write
|
|
3
|
+
// checks an exact confirmation string before any network call. Secrets are write-only.
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import { apimToolNames, registerApimTools } from './apim-tools.mjs';
|
|
6
|
+
import { cpiToolNames, registerCpiTools } from './cpi-tools.mjs';
|
|
7
|
+
import { READ_ONLY_ANNOTATIONS, resultOf } from './integration-common.mjs';
|
|
8
|
+
|
|
9
|
+
export { INTEGRATION_MAX_OUTPUT_BYTES } from './integration-common.mjs';
|
|
10
|
+
|
|
11
|
+
export const INTEGRATION_TOOL_NAMES = Object.freeze(['integration_connection_info', ...cpiToolNames(), ...apimToolNames()]);
|
|
12
|
+
|
|
13
|
+
/** Register Integration Suite tools; cpi_* and apim_* only appear when their client is configured. */
|
|
14
|
+
export function registerIntegrationTools(server, { cpi, apim, summary, verify, pollIntervalMs = 2000, readBackDelayMs = 5000 } = {}) {
|
|
15
|
+
const register = (name, title, description, inputSchema, annotations, handler) => {
|
|
16
|
+
server.registerTool(name, { title, description, inputSchema, annotations }, async args => resultOf(() => handler(args)));
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
register('integration_connection_info', 'Integration Suite connection info',
|
|
20
|
+
'Return which Integration Suite services (CPI, APIM) are configured, their credential source and tenant hosts. With verify: true it also signs in and runs one read per tool area (packages, deployed artifacts, message logs, security material, number ranges, Partner Directory, data stores, JMS; API proxies, providers, products, key value maps, virtual hosts, and policy readiness via an API proxy bundle export) and reports areas whose role is missing. Never returns client ids or secrets.',
|
|
21
|
+
{ verify: z.boolean().default(false) },
|
|
22
|
+
READ_ONLY_ANNOTATIONS,
|
|
23
|
+
async ({ verify: online }) => (online && verify ? { ...summary, verification: await verify() } : summary));
|
|
24
|
+
|
|
25
|
+
if (cpi) registerCpiTools(register, cpi, { pollIntervalMs });
|
|
26
|
+
if (apim) registerApimTools(register, apim, { readBackDelayMs });
|
|
27
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
// Online check of CPI/APIM credentials: sign in, then one read-only request per tool area so a
|
|
2
|
+
// missing role shows up as a named area instead of a failing tool call later. Never writes.
|
|
3
|
+
import { createServiceClient } from './integration-http.mjs';
|
|
4
|
+
|
|
5
|
+
const CSRF_PATHS = Object.freeze({ CPI: '/api/v1/', APIM: '/apiportal/api/1.0/Management.svc/' });
|
|
6
|
+
const APIM_BASE = '/apiportal/api/1.0/Management.svc';
|
|
7
|
+
|
|
8
|
+
const PROBES = Object.freeze({
|
|
9
|
+
CPI: [
|
|
10
|
+
{ area: 'Packages and iFlows', path: '/api/v1/IntegrationPackages', query: { $top: 1 }, core: true },
|
|
11
|
+
{ area: 'Deployed artifacts', path: '/api/v1/IntegrationRuntimeArtifacts', query: { $top: 1 } },
|
|
12
|
+
{ area: 'Message logs', path: '/api/v1/MessageProcessingLogs', query: { $top: 1 } },
|
|
13
|
+
{ area: 'Security material', path: '/api/v1/UserCredentials' },
|
|
14
|
+
{ area: 'Number ranges', path: '/api/v1/NumberRanges' },
|
|
15
|
+
{ area: 'Partner Directory', path: '/api/v1/StringParameters', query: { $top: 1 } },
|
|
16
|
+
{ area: 'Data stores', path: '/api/v1/DataStores' },
|
|
17
|
+
{ area: 'JMS queues', path: "/api/v1/JmsBrokers('Broker1')" }
|
|
18
|
+
],
|
|
19
|
+
APIM: [
|
|
20
|
+
{ area: 'API proxies', path: `${APIM_BASE}/APIProxies`, query: { $top: 1, $select: 'name' }, core: true },
|
|
21
|
+
{ area: 'API providers', path: `${APIM_BASE}/APIProviders`, query: { $top: 1, $select: 'name' } },
|
|
22
|
+
{ area: 'API products', path: `${APIM_BASE}/APIProducts`, query: { $top: 1, $select: 'name' } },
|
|
23
|
+
{ area: 'Key value maps', path: `${APIM_BASE}/KeyMapEntries`, query: { $top: 1, $select: 'name' } },
|
|
24
|
+
{ area: 'Virtual hosts', path: `${APIM_BASE}/VirtualHosts` }
|
|
25
|
+
]
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
// Statuses accepted as answers so they can be classified instead of thrown.
|
|
29
|
+
const OBSERVED = [200, 204, 400, 401, 403, 404, 405, 500, 501, 502, 503, 504];
|
|
30
|
+
|
|
31
|
+
function classify(status) {
|
|
32
|
+
if (status >= 200 && status < 300) return { result: 'ok', detail: 'readable' };
|
|
33
|
+
if (status === 401 || status === 403) return { result: 'forbidden', detail: `HTTP ${status}: the service key lacks the role for this area` };
|
|
34
|
+
if (status === 404 || status === 501) return { result: 'unavailable', detail: `HTTP ${status}: not available on this tenant or plan` };
|
|
35
|
+
return { result: 'error', detail: `HTTP ${status}` };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** OAuth clients for the resolved CPI/APIM config (null for an unconfigured side). */
|
|
39
|
+
export function createIntegrationClients(config, { env = process.env, fetchImpl } = {}) {
|
|
40
|
+
const clientFor = (label, side) => (side
|
|
41
|
+
? createServiceClient({
|
|
42
|
+
label,
|
|
43
|
+
url: side.url,
|
|
44
|
+
tokenUrl: side.tokenUrl,
|
|
45
|
+
clientId: side.clientId,
|
|
46
|
+
clientSecret: side.clientSecret,
|
|
47
|
+
csrfPath: CSRF_PATHS[label],
|
|
48
|
+
env,
|
|
49
|
+
...(fetchImpl ? { fetchImpl } : {})
|
|
50
|
+
})
|
|
51
|
+
: null);
|
|
52
|
+
return { cpi: clientFor('CPI', config?.cpi), apim: clientFor('APIM', config?.apim) };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Policies are attached by exporting the proxy bundle (Transport.svc), editing it and re-importing it.
|
|
56
|
+
// The export of an existing proxy proves the read half without writing; no proxy means nothing to test.
|
|
57
|
+
async function policyCheck(client, coreText) {
|
|
58
|
+
const area = 'Policies (proxy bundle export)';
|
|
59
|
+
let name;
|
|
60
|
+
try {
|
|
61
|
+
const parsed = JSON.parse(coreText);
|
|
62
|
+
name = (parsed?.d?.results ?? parsed?.d ?? parsed?.value ?? [])[0]?.name;
|
|
63
|
+
} catch {
|
|
64
|
+
// Unparseable list: reported as unavailable below.
|
|
65
|
+
}
|
|
66
|
+
if (typeof name !== 'string' || !name) return { area, status: null, result: 'unavailable', detail: 'no API proxy exists yet to test the export with' };
|
|
67
|
+
try {
|
|
68
|
+
const { status, data } = await client.request('GET', '/apiportal/api/1.0/Transport.svc/APIProxies', {
|
|
69
|
+
query: { name }, expect: OBSERVED, withStatus: true, responseType: 'bytes', accept: 'application/zip, application/octet-stream'
|
|
70
|
+
});
|
|
71
|
+
const zip = data instanceof Uint8Array && data[0] === 0x50 && data[1] === 0x4b;
|
|
72
|
+
if (status >= 200 && status < 300 && !zip) return { area, status, result: 'error', detail: `HTTP ${status} but the export is not a zip bundle` };
|
|
73
|
+
return { area, status, ...classify(status) };
|
|
74
|
+
} catch (error) {
|
|
75
|
+
return { area, status: null, result: 'error', detail: String(error?.message || 'request failed').slice(0, 300) };
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async function verifySide(label, client) {
|
|
80
|
+
if (!client) return { configured: false };
|
|
81
|
+
const probes = PROBES[label];
|
|
82
|
+
const run = async probe => {
|
|
83
|
+
try {
|
|
84
|
+
const { status, data } = await client.request('GET', probe.path, { query: probe.query, expect: OBSERVED, withStatus: true, responseType: 'text', accept: 'application/json' });
|
|
85
|
+
return { area: probe.area, status, ...classify(status), text: data };
|
|
86
|
+
} catch (error) {
|
|
87
|
+
return { area: probe.area, status: null, result: 'error', detail: String(error?.message || 'request failed').slice(0, 300) };
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
const { text: coreText, ...core } = await run(probes[0]);
|
|
91
|
+
// The core probe also fetches the token: a thrown request is a token or network failure, reported once.
|
|
92
|
+
if (core.status === null) {
|
|
93
|
+
return { configured: true, signed_in: false, ok: false, error: core.detail, checks: [] };
|
|
94
|
+
}
|
|
95
|
+
const others = probes.slice(1).map(run);
|
|
96
|
+
if (label === 'APIM' && core.result === 'ok') others.push(policyCheck(client, coreText));
|
|
97
|
+
const checks = [core, ...(await Promise.all(others)).map(({ text, ...check }) => check)];
|
|
98
|
+
return { configured: true, signed_in: true, ok: core.result === 'ok', checks };
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** Verify the configured sides online; `ok` means every configured side signed in and passed its core read. */
|
|
102
|
+
export async function verifyIntegrationClients({ cpi, apim } = {}) {
|
|
103
|
+
const [cpiResult, apimResult] = await Promise.all([verifySide('CPI', cpi), verifySide('APIM', apim)]);
|
|
104
|
+
const sides = [cpiResult, apimResult].filter(side => side.configured);
|
|
105
|
+
return { ok: sides.length > 0 && sides.every(side => side.ok), cpi: cpiResult, apim: apimResult };
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/** Human-readable lines for one verified side (no secrets: only host, area names and HTTP statuses). */
|
|
109
|
+
export function verificationLines(label, host, side) {
|
|
110
|
+
if (!side?.configured) return [];
|
|
111
|
+
if (!side.signed_in) return [`✗ ${label} ${host}: sign-in failed — ${side.error}`];
|
|
112
|
+
const lines = [`${side.ok ? '✓' : '✗'} ${label} ${host}: signed in`];
|
|
113
|
+
for (const check of side.checks) {
|
|
114
|
+
const mark = check.result === 'ok' ? '✓' : (check.result === 'unavailable' ? '–' : '✗');
|
|
115
|
+
lines.push(` ${mark} ${check.area}${check.result === 'ok' ? '' : ` — ${check.detail}`}`);
|
|
116
|
+
}
|
|
117
|
+
return lines;
|
|
118
|
+
}
|
package/src/launcher.mjs
CHANGED
|
@@ -10,7 +10,7 @@ import { adtBaseUrl, adtPort, detectAdtUrl, discoverSapGuiSystems, hasExplicitPo
|
|
|
10
10
|
import { binaryTarget, cacheDirectory, downloadBinary, findBinary } from './binary.mjs';
|
|
11
11
|
import { MCPProxy } from './mcp-proxy.mjs';
|
|
12
12
|
import { configuredVersionHandoff, installMcpConfig, npxPackageLauncher, repairManagedMcpConfig } from './mcp-config.mjs';
|
|
13
|
-
import { runSetup } from './setup.mjs';
|
|
13
|
+
import { runIntegrationSuiteSetup, runSetup } from './setup.mjs';
|
|
14
14
|
import { runHarnessSetup } from './harness-setup.mjs';
|
|
15
15
|
import { resolveConfiguredCloudFoundryDestination } from './cf-destination.mjs';
|
|
16
16
|
import { createTlsServerNameAdtProxy } from './tls-adt-proxy.mjs';
|
|
@@ -37,6 +37,7 @@ function usage() {
|
|
|
37
37
|
'Options:',
|
|
38
38
|
' --setup Configure generated BAS MCP servers',
|
|
39
39
|
' --tools Also offer full-stack SAP companion MCP servers (use with --setup)',
|
|
40
|
+
' --setup-integration Only set up the Integration Suite MCP server: paste CPI/APIM service keys and verify them online',
|
|
40
41
|
' --npx Launch configured MCP servers through the pinned npm package (use with --setup)',
|
|
41
42
|
' --list-destinations List discovered BAS destinations',
|
|
42
43
|
' --list-destinations --json Print redacted JSON status',
|
|
@@ -369,6 +370,7 @@ async function configuredLocalSapGuiDestination(env) {
|
|
|
369
370
|
}
|
|
370
371
|
|
|
371
372
|
async function main() {
|
|
373
|
+
const setupIntegration = hasFlag('--setup-integration');
|
|
372
374
|
const setup = hasFlag('--setup');
|
|
373
375
|
const check = hasFlag('--check');
|
|
374
376
|
const list = hasFlag('--list-destinations');
|
|
@@ -378,7 +380,7 @@ async function main() {
|
|
|
378
380
|
process.stdout.write(usage());
|
|
379
381
|
return;
|
|
380
382
|
}
|
|
381
|
-
if (!setup && !check && !list && !doctor && !demo && await handOffToConfiguredVersion()) return;
|
|
383
|
+
if (!setup && !setupIntegration && !check && !list && !doctor && !demo && await handOffToConfiguredVersion()) return;
|
|
382
384
|
if (doctor && demo) throw new Error('Use either --doctor or --demo, not both.');
|
|
383
385
|
if (demo) {
|
|
384
386
|
await runOfflineDemo();
|
|
@@ -407,6 +409,16 @@ async function main() {
|
|
|
407
409
|
if (!report.ok) process.exitCode = 1;
|
|
408
410
|
return;
|
|
409
411
|
}
|
|
412
|
+
if (setupIntegration) {
|
|
413
|
+
const options = {};
|
|
414
|
+
if (hasFlag('--npx')) {
|
|
415
|
+
const launcher = npxPackageLauncher(pkg.version);
|
|
416
|
+
options.install = (selected, installOptions) => installMcpConfig(selected, { ...installOptions, ...launcher });
|
|
417
|
+
}
|
|
418
|
+
const result = await runIntegrationSuiteSetup(options);
|
|
419
|
+
if (!result?.skipped) await runHarnessSetup(result?.servers, { env: runtimeEnv, root });
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
410
422
|
if (setup) {
|
|
411
423
|
const setupOptions = {
|
|
412
424
|
includeSapDevelopmentToolsPrompt: hasFlag('--tools') || hasFlag('--companion-tools'),
|
package/src/mcp-config.mjs
CHANGED
|
@@ -12,7 +12,7 @@ const LEGACY_MCP_SERVER_PREFIXES = ['sapAiDev_', 'basVspMcp_'];
|
|
|
12
12
|
const COMPANION_SERVER_KIND = 'sap-development-companion';
|
|
13
13
|
const packageRoot = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
14
14
|
|
|
15
|
-
// The self-package
|
|
15
|
+
// The self-package companions (HANA inspector, Integration Suite) must launch the exact version
|
|
16
16
|
// the user installed; an unpinned `npx sap-ai-dev-toolkit` would re-resolve
|
|
17
17
|
// executable code from the registry at every MCP host start.
|
|
18
18
|
let selfPackageVersion;
|
|
@@ -67,6 +67,15 @@ export const SAP_DEVELOPMENT_MCP_SERVERS = Object.freeze([
|
|
|
67
67
|
bin: 'sap-ai-hana',
|
|
68
68
|
ignoreScripts: true,
|
|
69
69
|
priority: 'optional'
|
|
70
|
+
}),
|
|
71
|
+
Object.freeze({
|
|
72
|
+
id: 'integration-suite',
|
|
73
|
+
name: 'Integration Suite (CPI + API Management)',
|
|
74
|
+
description: 'Build, deploy and monitor Cloud Integration content and manage API Management providers, proxies, policies, products and key value maps, using service keys from the host environment or pasted and verified with sap-ai-dev --setup-integration.',
|
|
75
|
+
packageName: 'sap-ai-dev-toolkit',
|
|
76
|
+
bin: 'sap-ai-integration',
|
|
77
|
+
ignoreScripts: true,
|
|
78
|
+
priority: 'optional'
|
|
70
79
|
})
|
|
71
80
|
]);
|
|
72
81
|
|
|
@@ -596,7 +605,11 @@ export async function installMcpConfig(destinationsOrOptions, options = {}) {
|
|
|
596
605
|
// instead of failing the whole setup (self-healing).
|
|
597
606
|
const config = await readConfig(path, { recoverInvalid: true, warnings: installWarnings });
|
|
598
607
|
const selfVersion = await runningPackageVersion();
|
|
599
|
-
|
|
608
|
+
// Values are full npx package specs; a bare version would become --package=<version>.
|
|
609
|
+
const selfSpec = selfVersion ? `sap-ai-dev-toolkit@${selfVersion}` : '';
|
|
610
|
+
const companionVersions = selfSpec
|
|
611
|
+
? { 'sap-ai-dev-toolkit': selfSpec, 'hana-cloud-inspector': selfSpec, 'integration-suite': selfSpec }
|
|
612
|
+
: {};
|
|
600
613
|
const generated = {
|
|
601
614
|
...buildMcpEntries(destinations, env),
|
|
602
615
|
...buildSapDevelopmentMcpEntries(options.sapDevelopmentServers || [], { packageVersions: companionVersions })
|
|
@@ -642,7 +655,9 @@ export async function installMcpConfig(destinationsOrOptions, options = {}) {
|
|
|
642
655
|
const exactManagedUpdate = managed && generatedNames.has(name)
|
|
643
656
|
&& destinationValue(entry.env) === generated[name]?.env?.SAP_AI_DEV_TOOLKIT_DESTINATION
|
|
644
657
|
&& destinationSource(entry.env) === generated[name]?.env?.SAP_AI_DEV_TOOLKIT_DESTINATION_SOURCE;
|
|
645
|
-
|
|
658
|
+
// A companion that is being regenerated is replaced (version refresh), not retained as a conflict.
|
|
659
|
+
const regeneratedCompanion = isCompanionServer(entry) && generatedNames.has(name) && isCompanionServer(generated[name]);
|
|
660
|
+
if (additive && (managed || isCompanionServer(entry)) && !exactManagedUpdate && !regeneratedCompanion) managedEntries.push([name, entry]);
|
|
646
661
|
else if (!managed && !isCompanionServer(entry) && !LEGACY_MCP_SERVER_PREFIXES.some(prefix => name.startsWith(prefix))) servers[name] = entry;
|
|
647
662
|
}
|
|
648
663
|
const retainedNames = new Set(managedEntries.map(([name]) => name));
|