SAP and m365 copilot sync Blog title

How to Integrate your live SAP HR Data into M365 Copilot - Part 1

SAP May 25, 2024

Actually, there is no other word so popular as AI! On each Keynote, Conference, Talk, and so on I hear the same about this. So I tried to investigate some Usecases for me.

Sure you can read about this in my last posts about this topic. But now I want a business use case for now.

But before I start, let's make it clear. I will divide this article into more than one post. Why? Because it is a complex topic. It's hard to write down at once. But I try to write it clearly enough to follow. At the end of this series (of a maximum of 3 posts). You will get the complete source code to create your own copilot extension.

The use case

So let's assume we have a list of employees who will work for a company as a consultant. So to get some work, the easiest way is to offer the consultants knowledge to a project on a project portal like gulp or

You can do this manually, but that takes more effort if your team will increase the amount of employees. So an AI solution is something like this:

  1. The salesman will take the offer
  2. It will ask the copilot for suggestions for employees
  3. Copilot will look into the SAP HCM for possible employees
  4. Copilot will send you a list of names with a matching score
  5. Also it will gather a CV to send to

So let's get started

How Microsoft Office 365 Copilot works

Before we can start, it is necessary to get an overview of how the Microsoft Copilot works.

Diagramm, das den Datenfluss zwischen Komponenten von Copilot und dem Microsoft 365-Γ–kosystem zeigt

The first step is the Microsoft 365 copilot will be triggered via a command like "Hey! Where is the Order for Customer X?". The next step is that Copilot uses the graph API for using the pre-processing. It will look there for the data that will be required for the answer. (Please note, that it will only be the data that is only accessible for you!). Also, this process will combined with a grounding of the data. The data result will be sent to the Large Language Model (LLM). This LLM will analyze the incoming data, wire the single sources together, and try to combine the data (like customers and orders) in a semantic way. This will be sent back to the copilot and will do a post-processing or enrich additional data. At least it will result in the data back to the copilot and sending it to the caller itself.

So Copilot can have as a source not only the Microsoft Graph, in the picture below you see that you can have several data sources.

Visuelle Darstellung des Copilot fΓΌr Microsoft 365 Systems: Grundlegende Modelle (LLMs) + Microsoft Graph (Ihre Daten) + Microsoft 365- und Drittanbieter-Apps

The Idea

So hey we now can try to identify which solution fits for us, but luckily Microsoft published a nice helper diagram to get the right choice of extension.

Chart with organizational 'Knowledge' as the x-axis and user 'Skills' as the y-axis showing that you can extend Copilot skills with plugins and extend Copilot knowledge with Graph connectors

In my case, I use a plugin. The knowledge will be available in the SAP System, so I need a skilled extension. For this, the diagram tells me that I need a Plugin. So we need a Plugin for Teams.

Install Prerequisites

Before we can start, we need some requirements

  • Visual Studio Code
    This will be your IDE. If you don't have it. Go get it! ;)
  • Teams Toolkit
    This Visual Studio Code extension will allow you to create an extension (in various ways) for your Teams. Please note that you must use the prerelease version.
  • Fun
    Yep, you need some fun ;)

Create our first Extension

So we are creating our first extension. So to integrate our Data into Teams, it is the best way to create a Teams bot app. For this, there exists a nice wizard that will guide you to the creation steps. After that, it will bootstrap the app itself. Look here


You can now start the application itself by starting it via the debugger tab. Here you have multiple options to debug. First, I suggest you do it in the test tool. This will open up a browser that will allow you to trigger your created extension.

"Wait a minute! We created only a bot?!"

Yes, that's true. You created a bot, and that bot will be asked by your copilot for results (more on it later). But that is the first magic behind the extension of the copilot itself.

The Project structure

So before we start, it is necessary to understand the project itself. Because there are some important things.

From top to bottom.

In the appPackage folder will be the result of the app. It will output the Extension file for teams and also the webapplication in which you have the logic to get the data from the system itself. It also contains the manifest.json. This JSON will be important for the copilot itself. But more on it later.

The env folder contains the env settings in this you will set the environment-specific configuration like API key and so on.

Next the infra folder. this contains the complete biceps definition for the required Azure infrastructure. At the starting point, it will create a web application together with an app service and it registers also an Enterprise Application into the EntraID.

In the src folder will be the complete application source. In this will be the message handler located that... yeah... handles the message itself from the system.

Next, there are some configs for configuring the application. Also, it contains the package.json for npm and the configuration for the build process (teamsapp*.yml)


This file is the central control file that will be used from the M365 Copilot. Let me share the basic implementation:

    "$schema": "",
    "manifestVersion": "1.16",
    "version": "1.0.0",
    "id": "${{TEAMS_APP_ID}}",
    "packageName": "",
    "name": {
        "short": "BlogDemo${{APP_NAME_SUFFIX}}",
        "full": "Employee HCM Bot"
    "description": {
        "short": "Getting details about Employes in the company",
        "full": "Plugin get skills and employees / members /colleagues and alsocurriculum vitae. It also delivers the skill level and availability for each entry. Together it will results the price / loan per hour."
    "accentColor": "#FFFFFF",
    "bots": [
            "botId": "${{BOT_ID}}",
            "scopes": [
            "supportsFiles": false,
            "isNotificationOnly": false
    "composeExtensions": [],
    "configurableTabs": [],
    "staticTabs": [],
    "permissions": [
    "validDomains": []

So that's the default one. But please note the description part

"description": {
        "short": "Getting details about Employes in the company",
        "full": "Plugin get skills and employees / members /colleagues and alsocurriculum vitae. It also delivers the skill level and availability for each entry. Together it will results the price / loan per hour."

It is required to be very precise about the description of your plugin. Because this will analyze the copilot. It decides on the user input if it will use your plugin.

So for example when the user inputs the following

"Tell me which use will have the most common SharePoint developing skills and give me the price per hour for him/her".

It will then recognize (against the description) that the copilot must use this bot to get the required data. Sure it will ask others too, but this is one of them.

Other example. When the user asks "Tell me who is not in a project at the moment" it cannot recognize your plugin to ask, because the description will not tell that it can deliver the answers to this question. So please think about well-descriptive descriptions.

How the Teams bot works

When you look into the index.ts file, you will see this:


Basically, it will host an API endpoint called /API/messages. It will take the request and will process it via the adapter instance.

"How will the bot know that it must send the data to this Endpoint?"

Good question. Do you remember the infra folder? In this will be done some registration, one of them is a bot registration. It will tell the bot registration to send a call request to this particular endpoint. It's like a wrapper for the bot. So it will know in a central instance where the endpoint of the application will be later on.

So what will be received through the bot?

Let's do a first try

Let's create a breakpoint at this point and after that hit F5.


It will start the local test tool after doing some registrations


Now let's enter some prompts. Try out "Say Hello"

Now the breakpoint will be hit, and when you jump to the next line, it will then read out the prompt. In this case "Say Hello"

In the example code, it will do some checks against local data and will return a text result between "<context>" - tags.

So your data will be wrapped in this later on. After that, it will be sent to the LLM and it will generate a descriptive answer.

"Okay, it's only a bot?"

Jep, that's a personal bot, chatbot/team bot. Nothing more for this example. So we need some more data. Especially from SAP HCM.

For that, I create a new Service Class to fetch data from the SAP Endpoint itself. It's called SapHcmService. This contains a method called fetch and will return an array of personal information

 public async Fetch(maxHourlyRate: number, requiredSkills:string): Promise<PersonalInformation[]> {
        let result: PersonalInformation[] = [];
        return result;

This will then fetch the required data from the SAP Endpoint. I don't want to go too deep in the detail here, because every SAP System contains other data structures (depending on their customization). Let's take this here as it is. It will respond to me with the following data structure

export interface Skill {
    name: string,
    matchscore: number
export interface PersonalInformation {
    Firstname: string,
    LastName: string,
    Cv: string,
    SkillsMatches: Skill[]

In the next blog post, I will describe how the magic happens and I extract the data from the tender description and try to figure out the best profiles with it.


Oh wow... you made it through this first post. So you learned many new things. One of them is how the Copilot itself works.

Next, you learn how to create a plugin from scratch and how the bot can be tested.

In the next blog post, I will go deeper with extracting the required data from the tender description and use it against the SAP System.

Please leave a comment about this article and what are missing, so that I can add it here and help you out.