Generates mtad.yaml MTA deployment descriptor for SAP BTP Cloud Foundry from Neo-migrated Java apps, configuring modules, services like XSUAA/HANA, and bindings based on applied migration skills. Invoke last.
npx claudepluginhub sap-samples/btp-neo-java-app-migration --plugin sap-btp-neo-migrationThis skill is limited to using the following tools:
Generate a Multi-Target Application deployment descriptor (`mtad.yaml`) for deploying Neo-migrated applications to SAP BTP Cloud Foundry.
Guides Next.js Cache Components and Partial Prerendering (PPR): 'use cache' directives, cacheLife(), cacheTag(), revalidateTag() for caching, invalidation, static/dynamic optimization. Auto-activates on cacheComponents: true.
Processes PDFs: extracts text/tables/images, merges/splits/rotates pages, adds watermarks, creates/fills forms, encrypts/decrypts, OCRs scans. Activates on PDF mentions or output requests.
Share bugs, ideas, or general feedback.
Generate a Multi-Target Application deployment descriptor (mtad.yaml) for deploying Neo-migrated applications to SAP BTP Cloud Foundry.
Generate an mtad.yaml for my migrated application
Create MTA descriptor with XSUAA and HANA services
The MTA descriptor (mtad.yaml) defines:
This skill analyzes which migration skills were applied to your application and generates the appropriate mtad.yaml configuration.
Working directory: This skill must run inside the
-cf-migrationcopy of your app, created byjakarta-java25-migrationorneo-to-cf-migration-orchestrator. If your current directory does not end in-cf-migration, switch to it before proceeding.
Before invoking this skill, ensure you have invoked all required migration skills:
Use the jakarta-java25-migration skill (REQUIRED)Use the sdk-replacement skill (REQUIRED)Also required:
mvn clean compileBased on the migration skills you've applied, identify required CF services:
| Migration Skill Applied | Required CF Service | Service Type |
|---|---|---|
| authentication-xsuaa | XSUAA | org.cloudfoundry.managed-service |
| destinations | Destination | org.cloudfoundry.managed-service |
| connectivity-onpremise | Destination + Connectivity | org.cloudfoundry.managed-service |
| persistence-hana | HANA Schema | com.sap.xs.hana-schema |
| document-management-sdm | SDM | org.cloudfoundry.managed-service |
| mail-destinations | (uses Destination service) | - |
| keystore-credstore | Credential Store | org.cloudfoundry.managed-service |
| monitoring-logging | (built-in CF logging) | - |
| tomee-runtime | (requires TARGET_RUNTIME property) | - |
Choose the appropriate base template:
| Scenario | Template | When to Use |
|---|---|---|
| Basic app without web authentication | mtad-base.yaml | Internal services, background jobs, APIs with technical auth |
| App with XSUAA and Approuter | mtad-with-approuter.yaml | User-facing web applications requiring authentication |
| TomEE application | Add TARGET_RUNTIME: tomee | Apps using EJB or requiring TomEE runtime |
For applications without user authentication:
_schema-version: "3.3"
ID: my-app
version: 1.0.0
parameters:
parameters:
enable-parallel-deployments: true
modules:
- name: my-app-backend
type: java.tomcat
path: target/ROOT.war
parameters:
memory: 1024M
disk-quota: 1024M
buildpack: sap_java_buildpack_jakarta
properties:
JBP_CONFIG_COMPONENTS: "jres: ['com.sap.xs.java.buildpack.jdk.SAPMachineJDK']"
JBP_CONFIG_SAP_MACHINE_JDK: "{ version: 25.+ }"
TARGET_RUNTIME: tomcat
build-parameters:
builder: maven
build-result: target/*.war
provides:
- name: backend-api
properties:
url: ${default-url}
requires:
# Add service bindings here based on needs
- name: my-app-hana # If using persistence-hana
- name: my-app-destination # If using destinations
resources:
# Add required services here
For user-facing web applications:
_schema-version: "3.2"
ID: my-app
version: 0.0.1
parameters:
enable-parallel-deployments: true
modules:
# Approuter module for authentication
- name: my-app-approuter
type: nodejs
path: approuter
parameters:
memory: 256M
disk-quota: 256M
routes:
- route: '${protocol}://my-app.${default-domain}'
protocol: http1
properties:
XS_APP_LOG_LEVEL: debug
TENANT_HOST_PATTERN: '(.*).cfapps.sap.hana.ondemand.com'
CF_NODEJS_LOGGING_LEVEL: "info"
requires:
- name: my-app-xsuaa
- name: my-app-java-app
group: destinations
properties:
name: backend-app-destination
url: '~{neo-app-url}'
forwardAuthToken: true
# Backend Java application
- name: my-app-backend
type: java.tomcat
path: target/ROOT.war
parameters:
memory: 1024M
disk-quota: 1024M
buildpack: sap_java_buildpack_jakarta
properties:
ENABLE_SECURITY_JAVA_API_V2: true
JBP_CONFIG_COMPONENTS: "jres: ['com.sap.xs.java.buildpack.jdk.SAPMachineJDK']"
JBP_CONFIG_SAP_MACHINE_JDK: "{ version: 25.+ }"
TARGET_RUNTIME: tomcat
SET_LOGGING_LEVEL: 'ROOT: INFO'
provides:
- name: my-app-java-app
properties:
neo-app-url: '${default-url}'
requires:
- name: my-app-xsuaa
- name: my-app-destination
resources:
- name: my-app-xsuaa
type: org.cloudfoundry.managed-service
parameters:
service: xsuaa
service-plan: application
path: ./xs-security.json
- name: my-app-destination
type: org.cloudfoundry.managed-service
parameters:
service: destination
service-plan: lite
Critical: The Java backend
pathmust point totarget/ROOT.war(nottarget/myapp.war). See "WAR context path" in Troubleshooting below.
Note on
type: nodejsvstype: approuter.nodejs: Usetype: nodejswhen deploying the approuter with your ownapprouter/directory andpackage.json(which is the standard pattern for migrated Neo applications). The typeapprouter.nodejsis for the "managed approuter" pattern which is used only in specific multi-tenant scenarios.
Add these resource definitions based on services your application needs:
resources:
- name: ${app-name}-xsuaa
type: org.cloudfoundry.managed-service
parameters:
service: xsuaa
service-plan: application
path: ./xs-security.json # Created by authentication-xsuaa skill
Module requires:
requires:
- name: ${app-name}-xsuaa
resources:
- name: ${app-name}-destination
type: org.cloudfoundry.managed-service
parameters:
service: destination
service-plan: lite
Module requires:
requires:
- name: ${app-name}-destination
resources:
- name: ${app-name}-connectivity
type: org.cloudfoundry.managed-service
parameters:
service: connectivity
service-plan: lite
Module requires:
requires:
- name: ${app-name}-connectivity
- name: ${app-name}-destination # Connectivity requires Destination
resources:
- name: ${app-name}-hana
type: com.sap.xs.hana-schema
parameters:
schema-name: ${app-name}
properties:
hdi-service-name: ${service-name}
Module requires:
requires:
- name: ${app-name}-hana
properties:
TARGET_CONTAINER: ~{hdi-service-name}
resources:
- name: ${app-name}-sdm
type: org.cloudfoundry.managed-service
parameters:
service: sdm
service-plan: standard
Module requires:
requires:
- name: ${app-name}-sdm
resources:
- name: ${app-name}-credstore
type: org.cloudfoundry.managed-service
parameters:
service: credstore
service-plan: standard
config:
encryption:
user_key_name: "credstore-key"
Module requires:
requires:
- name: ${app-name}-credstore
Identify which services your application needs:
# Check for XSUAA dependencies
grep -r "com.sap.cloud.security.xsuaa" pom.xml
# Check for destination dependencies
grep -r "com.sap.cloud.sdk.cloudplatform.connectivity" pom.xml
# Check for HANA dependencies
grep -r "javax.sql.DataSource\|jakarta.persistence" src/main/java/
# Check for SDM dependencies
grep -r "com.sap.ecm.api" src/main/java/
Copy the appropriate template:
# For basic app
cp skills/mta-descriptor/assets/mtad-base.yaml mtad.yaml
# For app with authentication
cp skills/mta-descriptor/assets/mtad-with-approuter.yaml mtad.yaml
Update the mtad.yaml with your application details:
ID: my-application-name # Unique identifier
version: 1.0.0 # Your app version
modules:
- name: my-app-backend # Your module name
path: target/ROOT.war # ALWAYS use ROOT.war — see note below
parameters:
memory: 1024M # Adjust based on needs
disk-quota: 1024M # Minimum 1GB — 512M causes deployment errors
WAR naming: The SAP Java buildpack deploys the WAR using its filename as the Tomcat context path. A WAR named
auth.waris served at/auth, not/. Always configuremaven-war-pluginwith<warName>ROOT</warName>so the app is served at the root path, and referencetarget/ROOT.warinmtad.yaml.
Based on your analysis in step 1, add the necessary service resources and module requirements.
Example: App with XSUAA, Destination, and HANA:
modules:
- name: my-app-backend
# ... other properties ...
requires:
- name: my-app-xsuaa
- name: my-app-destination
- name: my-app-hana
resources:
- name: my-app-xsuaa
type: org.cloudfoundry.managed-service
parameters:
service: xsuaa
service-plan: application
path: ./xs-security.json
- name: my-app-destination
type: org.cloudfoundry.managed-service
parameters:
service: destination
service-plan: lite
- name: my-app-hana
type: com.sap.xs.hana-schema
If you used the tomee-runtime skill:
modules:
- name: my-app-backend
properties:
TARGET_RUNTIME: tomee # Change from 'tomcat' to 'tomee'
Check the syntax and structure:
# Validate YAML syntax
yamllint mtad.yaml
# Or use basic validation
python3 -c "import yaml; yaml.safe_load(open('mtad.yaml'))"
After generating the mtad.yaml:
# Build the MTA archive
mbt build
# This creates: mta_archives/my-app_1.0.0.mtar
# Deploy using MultiApps plugin
cf deploy mta_archives/my-app_1.0.0.mtar
# Or deploy directly from current directory
cf deploy .
# Check application status
cf apps
# Check service bindings
cf services
# View recent logs
cf logs my-app-backend --recent
modules:
- name: my-app-ui
type: html5
path: ui-module
- name: my-app-backend
type: java
path: backend-module
provides:
- name: backend-api
properties:
url: ${default-url}
- name: my-app-worker
type: java
path: worker-module
requires:
- name: backend-api
modules:
- name: my-app-backend
properties:
MY_CUSTOM_VAR: "production-value"
SPRING_PROFILES_ACTIVE: "cloud"
JBP_CONFIG_RESOURCE_CONFIGURATION: "[tomcat/webapps/ROOT/WEB-INF/web.xml: {'web-app/session-config/session-timeout': 60}]"
modules:
- name: my-app-backend
parameters:
health-check-type: http
health-check-http-endpoint: /actuator/health
health-check-timeout: 180
Symptom: Application fails to bind to services during deployment
Solution: Verify service names in requires match service names in resources:
# Resource name
resources:
- name: my-app-xsuaa # This name...
# Must match in module requires
modules:
- name: my-app-backend
requires:
- name: my-app-xsuaa # ...must match exactly here
Symptom: Build errors during cf deploy
Solution: Verify build parameters:
modules:
- name: my-app-backend
build-parameters:
builder: maven # Or 'npm', 'custom'
build-result: target/*.war # Verify path is correct
Symptom: Application crashes with out-of-memory errors
Solution: Increase memory allocation:
modules:
- name: my-app-backend
parameters:
memory: 2048M # Increase from 1024M
disk-quota: 1024M # Never use 512M — minimum is 1024M for Java buildpack
Symptom: App starts successfully but every request returns 404. Logs show Tomcat started but requests don't match any servlet.
Cause: WAR is named myapp.war so Tomcat serves it at /myapp, not /. All servlet URL patterns are relative to the context path.
Solution: Configure maven-war-plugin to produce ROOT.war:
<!-- pom.xml -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.4.0</version>
<configuration>
<warName>ROOT</warName>
</configuration>
</plugin>
Update mtad.yaml path to target/ROOT.war and rebuild.
Note:
<finalName>in<build>does NOT control the WAR name — only<warName>in the plugin configuration does.
Symptom: cf deploy fails with Routes quota exceeded for organization '<org>'. quota: SUBSCRIPTION_QUOTA — total memory: 0, routes: 0
Cause: The CF org uses SUBSCRIPTION_QUOTA which has 0 routes and 0 memory by default. This is set by SAP's entitlement system.
Solution: A Global Account Administrator must assign CF Runtime memory in BTP Cockpit:
<guid>-t-<subaccount-guid> and applies itNote: cf create-space-quota and cf create-quota do NOT fix this — org-level route limits cannot be overridden by space quotas, and creating new org quotas requires CF admin rights.
Cannot access defaults field of PropertiesSymptom: Maven build fails with this error when using Java 25.
Cause: Default maven-war-plugin:2.2 is incompatible with Java 25.
Solution: Explicitly pin maven-war-plugin to 3.4.0 in pom.xml.
After generating the mtad.yaml, use the cf-plugin skills for deployment:
# Use cf-plugin to deploy the MTA
/sap-btp-cf:cf-push-app my-app
# View deployment logs
/sap-btp-cf:cf-get-app-logs my-app
If using authentication-xsuaa:
If using destinations skill:
If using connectivity-onpremise: