sap-ai-dev-toolkit 0.3.4 → 0.4.0

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 (35) hide show
  1. package/.github/agents/abap-developer.agent.md +5 -5
  2. package/.github/agents/abap-runtime-debugger.agent.md +10 -10
  3. package/.github/agents/hana-cloud-hdi-specialist.agent.md +22 -0
  4. package/.github/agents/rap-service-developer.agent.md +10 -10
  5. package/.github/agents/sap-solution-architect.agent.md +7 -6
  6. package/.github/skills/abap-debugging/SKILL.md +2 -2
  7. package/.github/skills/abap-runtime-analysis/SKILL.md +4 -4
  8. package/.github/skills/clean-core-extensibility/SKILL.md +1 -1
  9. package/.github/skills/hana-cloud-inspection/SKILL.md +35 -0
  10. package/.github/skills/hana-cloud-native-development/SKILL.md +26 -0
  11. package/.github/skills/hana-cloud-validation/SKILL.md +26 -0
  12. package/.github/skills/rap-development/SKILL.md +2 -2
  13. package/.github/skills/rap-service-delivery/SKILL.md +3 -3
  14. package/.github/skills/sap-sdlc-orchestration/SKILL.md +1 -1
  15. package/.github/skills/sap-standard-api-analysis/SKILL.md +1 -1
  16. package/.github/skills/sap-transport-release/SKILL.md +1 -1
  17. package/README.md +46 -22
  18. package/package.json +9 -4
  19. package/scripts/postinstall.mjs +3 -3
  20. package/src/hana-config.mjs +170 -0
  21. package/src/hana-database.mjs +150 -0
  22. package/src/hana-inspector.mjs +114 -0
  23. package/src/hana-tools.mjs +277 -0
  24. package/src/mcp-config.mjs +10 -1
  25. package/src/mcp-proxy.mjs +61 -0
  26. package/src/setup.mjs +3 -2
  27. package/test/copilot-content.test.mjs +48 -0
  28. package/test/hana-config.test.mjs +168 -0
  29. package/test/hana-inspector-stdio.test.mjs +44 -0
  30. package/test/hana-tools.test.mjs +206 -0
  31. package/test/live-s4h.test.mjs +202 -0
  32. package/test/mcp-config-cf.test.mjs +40 -0
  33. package/test/mcp-proxy.test.mjs +17 -31
  34. package/test/setup.test.mjs +10 -6
  35. package/tools.md +58 -50
@@ -5,24 +5,13 @@ import { tmpdir } from 'node:os';
5
5
  import { join } from 'node:path';
6
6
  import { fileURLToPath } from 'node:url';
7
7
  import { once } from 'node:events';
8
- import { childArguments, MCPProxy } from '../src/mcp-proxy.mjs';
8
+ import { childArguments, MCPProxy, PUBLIC_VSP_TOOLS } from '../src/mcp-proxy.mjs';
9
9
  import { PassThrough } from 'node:stream';
10
10
 
11
11
  const fixture = fileURLToPath(new URL('./fixtures/fake-vsp.mjs', import.meta.url));
12
- const REQUESTED_TOOLS = [
13
- 'AnalyzeABAPCode', 'AnalyzeCallGraph', 'CodeCompletion', 'GetAbapHelp',
14
- 'GetCallGraph', 'GetCalleesOf', 'GetCallersOf', 'GetCodeCoverage',
15
- 'GetConnectionInfo', 'GetObjectStructure', 'GetTypeHierarchy', 'GetTypeInfo',
16
- 'GrepObject', 'GrepPackage', 'CallRFC', 'DebuggerAttach', 'DebuggerDetach',
17
- 'DebuggerGetStack', 'DebuggerGetVariables', 'DebuggerListen', 'DebuggerStep',
18
- 'DeleteBreakpoint', 'GetBreakpoints', 'GetDump', 'GetSQLTraceState', 'GetTrace',
19
- 'ListDumps', 'SetBreakpoint', 'CloneObject', 'CreateAndActivateProgram',
20
- 'CreateClassWithTests', 'CreateObject', 'CreateTestInclude', 'DeleteObject',
21
- 'ExecuteABAP', 'GetClass', 'GetClassComponents', 'GetClassInclude', 'GetFunction',
22
- 'GetInclude', 'GetInterface', 'GetProgram', 'GetStructure', 'GetTransaction',
23
- 'LockObject', 'MoveObject', 'RecoverFailedCreate', 'RenameObject', 'SaveToFile',
24
- 'UnlockObject', 'UpdateClassInclude', 'UpdateSource', 'WriteClass', 'WriteProgram',
25
- 'CreateTransport', 'ListDependencies', 'PublishServiceBinding', 'UnpublishServiceBinding'
12
+ const HIDDEN_VSP_TOOLS = [
13
+ 'AnalyzeABAPCode', 'DebuggerListen', 'DeleteBreakpoint', 'DeleteObject', 'ExecuteABAP', 'ReleaseTransport',
14
+ 'DeleteTransport', 'SAP', 'ListSQLTraces', 'PublishServiceBinding', 'UnpublishServiceBinding'
26
15
  ];
27
16
 
28
17
 
@@ -166,22 +155,23 @@ test('merges paged tools and routes calls to the selected child', async t => {
166
155
  assert.deepEqual(lintTool.inputSchema.required, ['files']);
167
156
  assert.deepEqual(lintTool.inputSchema.properties.files.items.required, ['filename', 'source']);
168
157
 
158
+ const localWorkflowTools = [
159
+ 'LintABAP', 'GetApplicationLog', 'PrepareABAPChangeSet', 'ApplyABAPChangeSet',
160
+ 'CheckTransportReadiness', 'PlanABAPCloudMigration', 'GenerateRAPRegressionSuite', 'RunRAPRegressionSuite'
161
+ ];
169
162
  for (const destination of ['alpha', 'beta']) {
170
- for (const toolName of REQUESTED_TOOLS) {
171
- assert.ok(names.has(`${destination}__${toolName}`), `${destination} exposes ${toolName}`);
163
+ for (const toolName of PUBLIC_VSP_TOOLS) {
164
+ assert.ok(names.has(`${destination}__${toolName}`), `${destination} exposes curated ${toolName}`);
172
165
  }
173
- for (const coreTool of [
174
- 'GetSource', 'RunQuery', 'GetSystemInfo', 'GetInstalledComponents',
175
- 'GetFeatures', 'GetAPIReleaseState', 'PrettyPrint', 'ListTransports',
176
- 'GetTransport', 'GetUserTransports', 'GetTransportInfo',
177
- 'GetApplicationLog', 'ActivateMultiple'
178
- ]) {
179
- assert.ok(names.has(`${destination}__${coreTool}`), `${destination} exposes ${coreTool}`);
166
+ for (const toolName of localWorkflowTools) {
167
+ assert.ok(names.has(`${destination}__${toolName}`), `${destination} exposes local ${toolName}`);
180
168
  }
181
- for (const formerlyExcludedTool of ['ListSQLTraces', 'ReleaseTransport', 'DeleteTransport', 'SAP']) {
182
- assert.ok(names.has(`${destination}__${formerlyExcludedTool}`), `${destination} exposes ${formerlyExcludedTool}`);
169
+ for (const hiddenTool of HIDDEN_VSP_TOOLS) {
170
+ assert.equal(names.has(`${destination}__${hiddenTool}`), false, `${destination} hides ${hiddenTool}`);
183
171
  }
184
172
  }
173
+ assert.equal(listed.result.tools.filter(tool => tool.name.startsWith('alpha__')).length, PUBLIC_VSP_TOOLS.size + localWorkflowTools.length);
174
+ assert.equal(PUBLIC_VSP_TOOLS.size + localWorkflowTools.length, 59);
185
175
 
186
176
  const requiredArguments = {
187
177
  GetFeatures: [],
@@ -234,11 +224,7 @@ test('merges paged tools and routes calls to the selected child', async t => {
234
224
  params: { type: 'delete' }
235
225
  }],
236
226
  ['ActivateMultiple', { objects: ['PROG ZDEMO'] }],
237
- ['CreateTransport', {}],
238
- ['ReleaseTransport', {}],
239
- ['DeleteTransport', {}],
240
- ['ListSQLTraces', {}],
241
- ['SAP', { action: 'analyze', params: { type: 'application_log' } }]
227
+ ['CreateTransport', {}]
242
228
  ];
243
229
  for (const [index, [name, arguments_]] of additionalCalls.entries()) {
244
230
  const response = await proxy.handle({
@@ -70,7 +70,7 @@ function runPostinstallInPty(env, keys, assetsAnswer = '\r') {
70
70
  selectionSent = true;
71
71
  child.stdin.write(keys);
72
72
  }
73
- if (!assetsAnswerSent && stdout.includes('Install the bundled agents and eleven skills')) {
73
+ if (!assetsAnswerSent && stdout.includes('Install the bundled agents and all skills')) {
74
74
  assetsAnswerSent = true;
75
75
  child.stdin.write(assetsAnswer);
76
76
  }
@@ -90,6 +90,7 @@ function runPostinstallInPty(env, keys, assetsAnswer = '\r') {
90
90
  async function assertUserCopilotAssets(home) {
91
91
  const copilotRoot = join(home, '.copilot');
92
92
  assert.equal((await stat(join(copilotRoot, 'agents', 'abap-developer.agent.md'))).isFile(), true);
93
+ assert.equal((await stat(join(copilotRoot, 'agents', 'hana-cloud-hdi-specialist.agent.md'))).isFile(), true);
93
94
  const skillNames = (await readdir(join(copilotRoot, 'skills'))).sort();
94
95
  assert.deepEqual(skillNames, [
95
96
  'abap-debugging',
@@ -98,6 +99,9 @@ async function assertUserCopilotAssets(home) {
98
99
  'abap-testing-quality',
99
100
  'cds-development',
100
101
  'clean-core-extensibility',
102
+ 'hana-cloud-inspection',
103
+ 'hana-cloud-native-development',
104
+ 'hana-cloud-validation',
101
105
  'rap-development',
102
106
  'rap-service-delivery',
103
107
  'sap-sdlc-orchestration',
@@ -279,13 +283,13 @@ test('global postinstall completes BAS selection before optional Copilot assets'
279
283
  const declineLogs = `${declined.stdout}\n${declined.stderr}`;
280
284
  assert.match(declineLogs, /Configured 0 MCP servers/);
281
285
  assert.match(declineLogs, /\[Y\/n\]/);
282
- assert.match(declineLogs, /Press Enter to install the bundled agents and eleven skills in the path shown below; type n then press Enter to skip/);
286
+ assert.match(declineLogs, /Press Enter to install the bundled agents and all skills in the path shown below; type n then press Enter to skip/);
283
287
  assert.match(declineLogs, /🤖 sap-ai-dev-toolkit/);
284
288
  assert.match(declineLogs, /\u001b\[1;35m/);
285
289
  assert.match(declineLogs, /Optional Copilot setup is waiting for your choice/);
286
290
  assert.match(declineLogs, /Copilot agent and skills were skipped\. Your files were not changed/);
287
291
  assert.ok(declineLogs.indexOf('Optional Copilot setup is waiting for your choice') > declineLogs.indexOf('Configured 0 MCP servers'), declineLogs);
288
- assert.ok(declineLogs.indexOf('Install the bundled agents and eleven skills') > declineLogs.indexOf('Optional Copilot setup is waiting for your choice'), declineLogs);
292
+ assert.ok(declineLogs.indexOf('Install the bundled agents and all skills') > declineLogs.indexOf('Optional Copilot setup is waiting for your choice'), declineLogs);
289
293
  assert.ok(declineLogs.indexOf('No MCP server entries are configured for this add-on.') > declineLogs.indexOf('Copilot agent and skills were skipped'), declineLogs);
290
294
  assert.ok(declineLogs.includes(`MCP config file: ${config}`), declineLogs);
291
295
  const configAfterDecline = JSON.parse(await readFile(config, 'utf8'));
@@ -297,9 +301,9 @@ test('global postinstall completes BAS selection before optional Copilot assets'
297
301
  assert.equal(accepted.selectionSent, true, accepted.stdout);
298
302
  assert.equal(accepted.assetsAnswerSent, true, accepted.stdout);
299
303
  const acceptLogs = `${accepted.stdout}\n${accepted.stderr}`;
300
- assert.ok(acceptLogs.indexOf('Install the bundled agents and eleven skills') > acceptLogs.indexOf('Configured 1 MCP server'), acceptLogs);
301
- assert.match(acceptLogs, /Installed 15 Copilot files/);
302
- assert.ok(acceptLogs.indexOf('Installation configuration summary') > acceptLogs.indexOf('Installed 15 Copilot files'), acceptLogs);
304
+ assert.ok(acceptLogs.indexOf('Install the bundled agents and all skills') > acceptLogs.indexOf('Configured 1 MCP server'), acceptLogs);
305
+ assert.match(acceptLogs, /Installed 19 Copilot files/);
306
+ assert.ok(acceptLogs.indexOf('Installation configuration summary') > acceptLogs.indexOf('Installed 19 Copilot files'), acceptLogs);
303
307
  assert.ok(acceptLogs.includes(`MCP config file: ${config}`), acceptLogs);
304
308
  assert.ok(acceptLogs.includes('Destination: BAS · alpha-system · client 100 · Basic'), acceptLogs);
305
309
  assert.ok(acceptLogs.includes('Launch: stdio · sap-ai-dev'), acceptLogs);
package/tools.md CHANGED
@@ -1,79 +1,87 @@
1
+ # Curated VSP tools exposed through the BAS proxy
1
2
 
2
- # Additional VSP tools exposed through the BAS proxy
3
+ The proxy no longer advertises every VSP tool. To keep the developer-lifecycle MCP surface manageable, each generated one-destination server exposes a cherry-picked set of VSP tools plus local workflow tools (currently 59 tools when all curated VSP capabilities are registered).
3
4
 
4
- The proxy forwards these tools when the installed VSP mode registers them. They extend its existing curated tool set.
5
+ Hidden upstream VSP tools are not directly callable through the proxy. Local workflow tools may still call hidden or non-advertised upstream operations internally when they are required for a bounded workflow.
5
6
 
6
- ## Analysis, metadata, debugging, and trace
7
+ ## Public VSP tools
7
8
 
8
- - `AnalyzeABAPCode`
9
- - `AnalyzeCallGraph`
10
- - `CodeCompletion`
11
- - `GetAbapHelp`
12
- - `GetCallGraph`
13
- - `GetCalleesOf`
14
- - `GetCallersOf`
15
- - `GetCodeCoverage`
16
- - `GetConnectionInfo`
17
- - `GetObjectStructure`
18
- - `GetTypeHierarchy`
19
- - `GetTypeInfo`
20
- - `GrepObject`
21
- - `GrepPackage`
22
- - `CallRFC`
9
+ - `Activate`
10
+ - `ActivateMultiple`
11
+ - `CompareSource`
12
+ - `CreateTransport`
23
13
  - `DebuggerAttach`
24
14
  - `DebuggerDetach`
25
15
  - `DebuggerGetStack`
26
16
  - `DebuggerGetVariables`
27
- - `DebuggerListen`
28
17
  - `DebuggerStep`
29
- - `DeleteBreakpoint`
18
+ - `EditSource`
19
+ - `FindDefinition`
20
+ - `FindReferences`
21
+ - `GetAPIReleaseState`
30
22
  - `GetBreakpoints`
31
- - `GetDump`
32
- - `GetSQLTraceState`
33
- - `GetTrace`
34
- - `ListDumps`
35
- - `SetBreakpoint`
36
-
37
- ## Object, source, transport, and service operations
38
-
39
- - `CloneObject`
40
- - `CreateAndActivateProgram`
41
- - `CreateClassWithTests`
42
- - `CreateObject`
43
- - `CreateTestInclude`
44
- - `DeleteObject`
45
- - `ExecuteABAP`
23
+ - `GetCDSDependencies`
24
+ - `GetCDSElementInfo`
25
+ - `GetCDSImpactAnalysis`
46
26
  - `GetClass`
47
27
  - `GetClassComponents`
48
28
  - `GetClassInclude`
29
+ - `GetClassInfo`
30
+ - `GetConnectionInfo`
31
+ - `GetContext`
32
+ - `GetFeatures`
49
33
  - `GetFunction`
34
+ - `GetFunctionGroup`
35
+ - `GetInactiveObjects`
50
36
  - `GetInclude`
37
+ - `GetInstalledComponents`
51
38
  - `GetInterface`
39
+ - `GetPackage`
52
40
  - `GetProgram`
53
- - `GetStructure`
54
- - `GetTransaction`
55
- - `LockObject`
56
- - `MoveObject`
57
- - `RecoverFailedCreate`
58
- - `RenameObject`
59
- - `SaveToFile`
60
- - `UnlockObject`
61
- - `UpdateClassInclude`
62
- - `UpdateSource`
63
- - `WriteClass`
64
- - `WriteProgram`
65
- - `CreateTransport`
41
+ - `GetSource`
42
+ - `GetSystemInfo`
43
+ - `GetTable`
44
+ - `GetTableContents`
45
+ - `GetTransport`
46
+ - `GetTransportInfo`
47
+ - `GetUserTransports`
48
+ - `GrepObjects`
49
+ - `GrepPackages`
66
50
  - `ListDependencies`
67
- - `PublishServiceBinding`
68
- - `UnpublishServiceBinding`
51
+ - `ListTransports`
52
+ - `PrettyPrint`
53
+ - `RunATCCheck`
54
+ - `RunQuery`
55
+ - `RunUnitTests`
56
+ - `SearchObject`
57
+ - `SetBreakpoint`
58
+ - `SyntaxCheck`
59
+ - `WriteSource`
60
+
61
+ ## Hidden from direct proxy calls
62
+
63
+ Broad/destructive surfaces such as object deletion, SQL trace, arbitrary SAP router calls, transport release/delete, RFC execution, debugger listen/delete-breakpoint helpers, and one-off generator/update helpers are intentionally not advertised by the BAS proxy.
69
64
 
70
65
  ## Destination-scoped workflow tools
71
66
 
72
67
  The proxy adds local multi-step tools to each destination when their required VSP capabilities are available:
73
68
 
69
+ - `LintABAP` — local in-memory ABAP linting.
70
+ - `GetApplicationLog` — bounded convenience mapping to the upstream SAP application-log route when available.
74
71
  - `PrepareABAPChangeSet` and `ApplyABAPChangeSet` — review full-source diffs and recheck source before explicit writes.
75
72
  - `CheckTransportReadiness` — collect a whitelisted bundle of transport, dependency, inactive-object, ABAP Unit, and ATC results.
76
73
  - `PlanABAPCloudMigration` — batch SAP API release-state checks and prioritize recognized unreleased results.
77
74
  - `GenerateRAPRegressionSuite` and `RunRAPRegressionSuite` — create and run reusable OData GET-only checks under the selected service root.
78
75
 
79
76
  `sap-ai-dev-toolkit --doctor` checks destination probing, VSP startup, `GetSystemInfo`, and MCP tool listing. `sap-ai-dev-toolkit --demo` runs the sample tools and OData fixtures without contacting SAP; demo writes and transport creation remain in memory until that process exits.
77
+
78
+ ## Separate optional HANA Cloud inspector
79
+
80
+ The optional `hana-cloud-inspector` companion starts `sap-ai-hana` as a separate stdio MCP server. It does not use the VSP proxy, BAS destination prefix, or ABAP SQL `RunQuery`. When selected and configured with a dedicated read-only identity, it exposes:
81
+
82
+ - `hana_connection_info` — verify the configured endpoint, service/binding, current user, schema, and TLS state without returning credentials.
83
+ - `hana_list_objects` — list tables/views in the bound HDI schema, with a 200-object maximum.
84
+ - `hana_describe_object` — inspect columns for a catalog-verified object in that schema.
85
+ - `hana_read_rows` — perform parameterized reads of selected columns, capped at 200 rows; credential-like columns are blocked and arbitrary SQL is not accepted.
86
+
87
+ Connection secrets are read from the MCP host environment via explicit `HANA_RO_*` variables or a selected `VCAP_SERVICES` binding and are not written to `mcp.json`. TLS certificate verification is mandatory. No HANA write, DDL/DML, deploy/undeploy, grants, or service-key tools are exposed; deployment remains a user-run project workflow.