One year ago, Martin Häuser blogged about the newly released JavaScript-to-TypeScript conversion feature of Joule in SAP Build. Now, with the new release 0.2.0, the UI5 MCP server has also received such a feature. Here I write about the experience while validating the feature and give hints about what to expect and how to get the most out of it.
This article is for UI5 developers familiar with TypeScript basics who are considering converting existing JavaScript applications. If you want to check out the basics of MCP servers before continuing, read our initial release blog post. For comprehensive UI5-specific TypeScript information see this page.
TL;DR: Scroll down to the end of this article when you are only interested in the learnings and hints, without all the technical details of getting there and tweaking the feature.
Much has been written about the value, efficiency, and developer happiness that comes with using TypeScript when writing UI5 applications. Don't take my word for it, just see this blog post for a real-world report of a team which migrated or this one for a similar opinion. Read how people "wouldn't go back for anything in the world" and "won't go back once you try it". Frankly, all feedback I heard was very positive.
I'm often asked whether all UI5 applications should be changed to TypeScript. While I definitely recommend it for new apps, I usually answered that the migration effort for an existing app only pays off when a certain amount of future development or maintenance effort is expected to be spent on it.
This equation has now shifted!
With the newest feature of the UI5 MCP server, UI5-specific TypeScript conversion assistance is now available to AI coding agents, which means a powerful boost for such an endeavor. As part of development, I tested it with the most complex UI5 app I had written myself (14 controllers, 7 custom controls). It had grown for almost eight years to a state which made me shy away from TypeScript conversion even though it was sorely needed. The result of using the MCP server: I literally told a colleague that I was getting goosebumps as it was plowing through the code of this app.
I have to start by saying that the app is not on GitHub and not open-source. It isn't suitable for end-users without personal support, and its setup requires experts. It's the kind of app you start writing just for yourself but turned out to be so useful that it was used to manage the speakers and sessions and agendas of the last seven UI5con conferences we organized as well as the sibling conferences reCAP and HANA Tech Con, the UI5cons in India and several "SAP Inside Track" events across Europe. So it's a productively used app that better doesn't break down.
You use it when you suggest session proposals (and the jury rates the proposals in this app), but at its heart, it looks like this for event admins:
And it comes with a drag&drop agenda planner developed as custom controls (not much of an agenda there right now, as no UI5con is currently planned):
When the time had come to give the new MCP server feature a real-life check and some fine-tuning, this app with its history and quirks was just the right choice.
As preparation, I had an AI agent look at all files of the project and create an "AGENTS.md" file summing up its functionality and how things are working. This is not required specifically for TypeScript conversion, but probably useful anyway when an agent works with a project, as it gets an overview without having to first look around every time it starts a task.
The prompt I then used to launch the conversion was:
@/AGENTS.md Convert the SAPUI5 UI of this project to TypeScript.
Use the MCP tool to get conversion guidelines. Ignore the tests for the time being.
By the way, I used Cline with Anthropic's Claude 4.5 Sonnet LLM, but it would work similarly with other LLMs and agents like GitHub Copilot, Cursor, Windsurf,... I explicitly mentioned the MCP tool and added AGENTS.md in the prompt as references. Probably that's not needed, but when starting a task that may run for an hour and may save days of work, then requesting precisely what I want doesn't hurt.
It started reasonably by calling the MCP tool and looking around in central project files like package.json, ui5.yaml and other top-level configuration files.
It then came up with a conversion plan—for the project setup in "phase 1", then for the concrete JS files.
These steps and this order make sense and this is no coincidence: of course the MCP tool suggests how to best proceed and what to do. The agent went through "phase 1" and "phase 2", then stopped with a summary of the achievements so far, so I asked it to proceed with the custom controls.
Starting with central reuse modules on which the other files depend (in terms of TypeScript: depend on their typed APIs) is what I also suggest to humans doing the conversion. A half-converted project works just fine like this and allows working in several steps instead of one big-bang conversion.
This message during the custom control conversion made me admire its coolness and understanding of the process:
Before converting the controllers, it again paused with a summary, but after a while, before the largest controller files, it explained that it could not continue like this due to a filled-up context window — oops!
This is something to keep in mind despite all the grace and wonders of AI agents: technically, they are still based on algorithms which predict the next part of a word from all the preceding words. The more conversation history there is, the more computationally complex (and expensive and to some degree slower) the response will be. Also: the fuller the context is, the less will this prediction be able to precisely take into account each single piece of the past conversation. Or in more human terms: it won't remember all details when it is flooded with too much unrelated stuff like contents of files which have already been converted. For sure, the AI coding agents apply clever measures to clean unneeded content from the context, but in general it makes sense to start from scratch when doing a different task, even when not being alerted like this. And in this case of one huge task the agent itself had to remind me that it could no longer digest all that input.
In such a case, start a new conversation. I copied 1.) the original prompt, followed by 2.) a hint that the conversion has already started and 3.) the conversion status up to this point. It was luckily provided by the agent, but if not: simply ask for it. The new conversation resumed smoothly from the point where the old one ended.
Remember, this was not a TypeScript conversion to get the job done, but one for validating the MCP tool! The real work just started when the agent declared the job done.
Result of the very first run:
The conversion guidelines tool in the MCP server was then tweaked to prevent these issues and the process was re-started. The number of "any" casts for example was then drastically reduced and the strange "unknown"-plus-custom-type casts mentioned above were completely gone. Of course this tweaking was an iterative process.
In other iterations, it...
One of the fixes for these issues was adding code to the MCP tool which fetches the actual latest version of the @ui5/ts-interface-generator at tool invocation time (like it was already done for the other dependencies).
Despite all the tweaking of the tool, working with LLMs always means working with probabilities! As sad as it is, you cannot expect such a tool to work 100% as expected, or to report a bug when it doesn't and get this bug then analyzed, understood, and fixed for good. You might even encounter the above issues again when using the tool and there is NO way we could ensure it won't ever happen again.
In one iteration, the agent even got on a bad track right from the start. It set up the tsconfig.json file in a weirdly wrong way, resulting in the UI5 types not being found. They were installed, they were there and referenced, but neither the agent nor I, I have to admit, understood why they weren't applied. After seeing the agent trying to solve the problem in truly strange ways, I aborted this conversion attempt. Remember the thing about LLM contexts: when there is too much weird and wrong content in the conversation history which influences every single token it spits out as the process continues, then it is sometimes better to re-start cleanly.
When the agent declares the conversion done, there are often a few dozen TypeScript errors left. Sometimes, those are errors which are NOT thrown by the TypeScript transpiler, but only displayed by the code editor (in my case Microsoft VS Code), as they sometimes use different settings (maybe due to the different tsconfig.json files for different project parts in my case).
You can ask the agent to work on those issues, but in my experience it will often not find good solutions for those, but rather take the "any" type shortcut. Those issues are worth to look at manually. Sometimes they actually reveal bugs in the app or the UI5 types!
With large amounts of code converted and moved from a *.js to a *.ts file, it's hard for humans to review the result. You cannot easily diff them with a focus on actual logic—even though much of the code should still be the same. The structural changes are just too large.
But remember: in the end, the TypeScript code is transpiled to JavaScript during the build because this is what browsers execute! As TypeScript is basically just JavaScript plus types, the pure logic of the transpilation result should be the same as it was before. In addition, the structural changes of proprietary UI5 class and module definition syntax to ECMAScript modules and classes will also be reverted. Hence, ideally the transpiled TypeScript should look pretty much like the original JavaScript—at least close enough to spot potential conversion problems much easier in an interpretable diff.
So you can use any diff tool to compare the build result of the TypeScript app with the original JavaScript sources. In my case, 14 of 39 files in total had a difference. Most differences were trivial, like "var" converted to "const", "function"s converted to arrow functions, anonymous functions converted to named functions and "use strict" moved. Others introduced additional null checks or other changes related to the stricter typing. In some places the "_interopRequireDefault" function dealing with module exports was added.
One surprise was that the converted controls had also their control renderer migrated from the old string-based APIs like
renderer: function (oRm, oControl) {
oRm.write('<div');
oRm.writeControlData(oControl);
...renderer: {
apiVersion: 2,
render: function (oRm, oControl) {
oRm.openStart('div', oControl);
...Despite of all this talk about errors and issues, the conversion is a process that takes maybe an hour with an AI agent (plus a few hours of manual polishing afterwards), but would have taken days when done manually. And potentially saves many days of work down the road as TypeScript greatly helps with development and maintenance efficiency.
Speaking of value, there is also monetary cost involved. A potential license fee of the AI agent tool itself might already include some or all of the AI tokens consumed by the conversion process. But to give an example for the imaginary isolated token cost, the conversion of this 14-controller-7-controls app consumed about 16 million input tokens (oops!) and (only!) 90k output tokens.
Using the current end-user API pricing of Anthropic ($3 per million input tokens and $15 per million output tokens) this sums up to about $50, which is likely not the biggest cost factor considering the invested (and saved!) working hours. Of course different models have different costs—and results. Google's Gemini 2.5 pro would only cost a bit more than $20, the still experimental Gemini 3.0 pro about $33, Anthropic's smaller Claude 4.5 Haiku less than $17, the bigger Claude 4.5 Opus more than $80.
Personally, I'd probably go for one of the best available models because saving $10 for the conversion may lead to having a less optimal codebase for years to come. The current top models can be seen in e.g. the LMArena leaderboard, so you can pick models with a good performance/price ratio.
From trying different AI agents and LLMs in the past, I also have to say that they all have different "personalities" and approaches with regards to communicating and reading/changing files. One model may do all changes in a file in one go, another model I have seen doing a dozen single-line changes one-by-one, with a full (costly!) LLM round trip for each modification. Sometimes models are more paranoid, inspecting files again and again, looking around to make sure they are not missing anything. This means that an isolated look at the token prices does not give the complete picture.
All in all, here’s how to get the most out of the UI5 MCP server’s TypeScript conversion feature:
Create project documentation - Have an AI agent generate an AGENTS.md file summarizing your app’s architecture (or write it yourself). This gives valuable context for the conversion and all future work.
Choose the best model - Don’t save $20-30 on a cheaper model when the result affects your codebase for years. Claude 4.5 Sonnet has worked well, Gemini 3.0 might even have a better performance/price ratio.
Commit everything - Ensure you can easily revert or compare changes if needed. Also commit before you do additional manual changes or the agent starts its next phase, so you can revert or re-check in isolation.
Trust the process - Let the agent follow the MCP tool’s suggested order: project setup → central modules → custom controls → controllers. But:
Don’t hesitate to restart - If the agent makes systematic mistakes (wrong tsconfig, excessive "any" casts), abort and restart cleanly with additional hints in your prompt if needed. It’s faster than correcting a bad track when all the code has been touched. Or interrupt and adjust the guidance when you see a trend of minor issues.
Watch for context limits - When the agent signals a full context window (or when you feel/know/see it is), start fresh with: original prompt + note that conversion is in progress + current status summary.
Expect remaining errors - Budget some hours for manual polishing. This is normal and valuable.
Fix errors properly:
Route$PatternMatchedEvent) not generic Event. The tool tells the agent to do so, but the LLM often doesn't know all those types, so you are likely to see some of these issues remaining.Do not expect a perfect result! This tool (or rather the AI coding agent instructed by this tool) doesn’t produce perfect TypeScript, but it gives you a massive head start. A several-day manual conversion becomes an hour of agent work plus some hours of polishing with the benefits adding up afterwards day by day. That’s a big productivity gain.
The equation has changed: even legacy apps in maintenance mode can now benefit from TypeScript conversion. The barrier that once made me postpone converting my own 8-year-old app has been lowered dramatically.
What the tool does: Removes the tedious part of the work so you can focus on fixing meaningful type errors, creating proper domain types, and improving code quality where it matters.
What you still need: TypeScript knowledge and careful code review. The agent handles the tedious conversion; you handle the intelligent refinement.
If you have a JavaScript UI5 app that could benefit from TypeScript, there’s never been a better time to make the switch.
Try it yourself: The UI5 MCP server can be used with all AI coding assistants supporting MCP, is available via npm, and installation instructions and its code are at GitHub. Questions? Share your experience in the comments below or suggest improvements at GitHub.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
| User | Count |
|---|---|
| 38 | |
| 21 | |
| 19 | |
| 18 | |
| 18 | |
| 18 | |
| 17 | |
| 16 | |
| 16 | |
| 14 |