OE MCP Connector i VS Code

W świecie aplikacji biznesowych opartych na technologii OpenEdge coraz częściej pojawia się pytanie, jak skutecznie wykorzystać sztuczną inteligencję w pracy z językiem Advanced Business Language. Choć narzędzia AI na stałe zadomowiły się już w wielu ekosystemach programistycznych, technologia OpenEdge pozostawała na uboczu. Głównym problemem była specyfika ABL, którego popularne modele językowe praktycznie nie znają. Z kolei budowa lub dostrajanie własnych modeli LLM to kosztowny i złożony proces, wymagający dużych zbiorów danych oraz specjalistycznej wiedzy.

W najnowszej wersji OE 12.8 deweloperzy dostają bardzo ciekawe narzędzie wspomagające ich pracę – Progress OpenEdge AI Coding Assistant. Jest ono specjalnie zaprojektowane z myślą o wsparciu programistów języka ABL. Zapewnia ono inteligentne, kontekstowe wsparcie w pisaniu, recenzowaniu i modernizowaniu kodu. Właściwie może powinienem napisać: wspaniałe, cudowne narzędzie… ale ten kto korzysta i testuje sztuczną inteligencję wie że trzeba jej “patrzyć na ręce”, bo tu i tam zdarzają się dziwne błędy. W sumie to chyba dobrze, bo programiści mogą jeszcze spać spokojnie. Zdarza się słyszeć opinię, że AI całkowicie zastąpi deweloperów, ale na to przyjdzie jeszcze trochę poczekać.

Asystent wykorzystuje architekturę Retrieval-Augmented Generation (RAG), która wzbogaca działanie modeli językowych poprzez pobieranie trafnych informacji z zewnętrznych źródeł jeszcze przed wygenerowaniem odpowiedzi. Mogą to być repozytoria kodu, dokumentacja projektowa, wewnętrzne standardy, bazy danych czy grafy wiedzy. Dzięki temu OpenEdge AI Coding Assistant nie udziela ogólnych, oderwanych od rzeczywistości podpowiedzi, lecz opiera swoje sugestie na faktycznym kontekście projektu — istniejącym kodzie, obowiązujących regułach i dokumentacji. Efektem są odpowiedzi bardziej precyzyjne, spójne z praktyką zespołu i możliwe do zweryfikowania.

Wykorzystanie Model Context Protocol (MCP) pozwala na ujednoliconą i skalowalną integrację asystenta z różnymi środowiskami programistycznymi, takimi jak Visual Studio Code, Windsurf czy Cursor. Takie podejście oddziela warstwę inteligencji od konkretnego IDE, co nie tylko upraszcza wdrożenie, ale także zapewnia elastyczność w przyszłości. MCP tworzy stabilne ramy do rozbudowy rozwiązania, umożliwiając wprowadzanie nowych narzędzi i adaptację do zmieniających się środowisk bez konieczności kosztownych zmian architektonicznych.

Choć mówimy o OpenEdge AI Coding Assistant, w praktyce instalujemy komponent o nazwie OE MCP Connector, ponieważ to właśnie on stanowi warstwę integracyjną całego rozwiązania. Sam asystent AI to logika i mechanizmy działające „w tle”, natomiast MCP Connector jest elementem technicznym, który łączy środowisko programistyczne (IDE) z silnikiem AI.

Connector wykorzystuje architekturę Model Context Protocol (MCP) do przekazywania kontekstu — kodu, metadanych, reguł czy informacji projektowych — między IDE a usługą AI. Dzięki temu asystent może działać w różnych narzędziach programistycznych w sposób spójny i standaryzowany.
Żeby używać tego produktu z wybranym IDE (ja pokażę na przykładzie VS CODE) trzeby wykonać sporo czynności, które po kolei pokażę.

Po pierwsze przed instalacja IDE, trzeba zainstalować Pythona w wersji 3.9 lub wyższej. Ważne żeby podczas instalacji zaznaczyć pole wyboru „Dodaj plik python.exe do ścieżki PATH”.
Oprócz tego trzeba posiadać ważną licencję OpenEdge 12.2 lub 12.8 i ważną umowę serwisową.
Po drugie musimy mieć konto w programie Progress Software Customer Validation Program (CVP). Logujemy się swoim Proghress ID i sprawdzamy grupę OpenEdge.
Powinniśmy widzieć zawartość a szczególnie dostęp do przypiętego postu: OpenEdge MCP Connector for ABL
Jeśli nie mamy dostępu to trzeba znaleźć na stronie link żeby poprosić o dostęp. Czasem dostęp dostajemy od razu a czasem trzeba poczekać do kilku dni.

Powyższy post zawiera wiele cennych informacji i, przede wszystkim, pliki do pobrania. Pobieramy plik: progress-openedge-mcp-connector-abl-1.0.0.vsix.
Jest on spakowany i musimy go po pobraniu rozpakować.
W VS Code przechodzimy do widoku Extensions i górnego menu po prawej stronie okienka () wybieramy: Install from VSIX… Znajdujemy nasz plik na dysku i po chwili instalacja jest zakończona. Restartujemy VS Code.

Teraz trzeba wygenerować API Key, żebyśmy mogli uwierzytelnić usługę MCP. Logujemy się do Progress Data Cloud. Cały proces jest dokładnie opisany w dokumentacji.
Po zalogowaniu klikamy na ikonę z ustawieniami (gear icon) i Services. Powinniśmy widzieć poniższy widok. Jeśli nie będzie usługi, musimy skontaktowac się z administratorem strony.

Nastęnie klikamy w prawym górnym rogu na ustawienia konta (ikona z ludzikiem), a następnie na nasz ProgressID.

W tych ustawieniach widzimy, że API Key nie jest jeszcze wygenerowany. Klikamy po prawej stronie na: Manage Your API Key i Generate. Wygenerowany klucz pojawi się i możemy go skopiować, aby użyć w naszym IDE.

W VS Code wchodzę w ustawienia pluginu i wpisuję email, który jest skojarzony z moim kontem ProgressID.

Plugin zawiera cały Help, co trzeba zrobić i w jakiej kolejności. I tak widzimy poniżej, że wciskając Ctrl+Shift+P otworzy się okienko poleceń w którym nalezy wpisać: Progress OpenEdge MCP:Login to MCP.

Wtedy pojawi się jeszcze jedno okienko w którym wklejamy nasz klucz API Key. Jesli połaczenie się powiodło widzimy w prawym dolnym rogu OE MCP Connected.
W poprzednim artykule pisałem o pliku z instrukcjami .github/instructions.md. Wykasowuję jego poprzednia zawartość i wpisuję coś jak poniżej. Oczywiście można wpisac o wiele instrukcji, ale na razie wystarczy tyle:

# Copilot Instructions for OpenEdge ABL

## OpenEdge ABL Coding Standards

- All code, scripts, and examples must use OpenEdge ABL syntax and conventions.
- Always use the MCP server OpenEdge and collection "12.8" as the authoritative source for syntax and code examples.

## AI Agent Guidance

- When generating code or documentation, always use OpenEdge ABL syntax and reference the MCP server OpenEdge, collection "12.8" for syntax, examples and best practices.

Restartuję IDE. Otwieram nowy plik procedury .p. W oknie Copilota wpisuję prompta:
Write a new program in OpenEdge ABL that:
1. Prompts the user for a customer number
2. Finds that customer in the Customer table
3. Calculates the total value of all orders for that customer by summing OrderLine.ExtendedPrice
4. Displays the results.

Po chwili dostaję kod programu z poprawną składnią, który generuje poprawny wynik.

/* customer_total.p
   Prompt for customer number, calculate total order value.
*/

DEF VAR iCustNum AS INTEGER NO-UNDO.
DEF VAR dTotal    AS DECIMAL   NO-UNDO INITIAL 0.

/* ask the user for the customer number */
DISPLAY iCustNum LABEL "Customer number".
UPDATE iCustNum.

/* locate the customer record */
FIND Customer WHERE Customer.CustNum = iCustNum NO-LOCK NO-ERROR.
IF NOT AVAILABLE Customer THEN DO:
    MESSAGE "Customer" iCustNum "not found." VIEW-AS ALERT-BOX.
    RETURN.
END.

/* sum extended prices for all order lines of the customer's orders */
FOR EACH Order OF Customer NO-LOCK:
    FOR EACH OrderLine OF Order NO-LOCK:
        dTotal = dTotal + OrderLine.ExtendedPrice.
    END.
END.

/* display the result */
DISPLAY dTotal LABEL "Total Order Value" FORMAT "->>,>>9.99".

RETURN.

Przykład jest dość prosty ale chodzi tu bardziej o instalację i konfigurację MCP Connectora. Zachęcam, jak zwykle, do testów.

W przeciwieństwie do uniwersalnych asystentów kodowania, które oferują szerokie, lecz często powierzchowne wsparcie, OpenEdge AI Coding Assistant został zaprojektowany z myślą o specyfice ABL i ekosystemu OpenEdge. Uwzględnia charakterystyczne wzorce, praktyki i wymagania biznesowe, dzięki czemu stanowi realne, a nie tylko deklaratywne wsparcie dla zespołów pracujących z tym środowiskiem.

OpenEdge i VS Code 2

Każdy z Was zapewne często korzysta z pomocy ze strony sztucznej inteligencji. Warto więc powracać do tego tematu od czasu do czasu.
W Progress OpenEdge ten temat też jest aktywnie rozwijany, ale zanim pojawi się na tym blogu jakiś wpis na temat produktu OpenEdge MCP zobaczmy co możemy zrobić w omawianym niedawno środowisku VS Code.
Chodzi o agenta AI GitHub Copilot, który jest bardzi przydatny do pisania kodu “w locie”.
Jest to narzędzie wyspecjalizowane (tzw. AI pair programmer), które działa bezpośrednio w edytorze IDE, np. VS Code.
Jego zaletą jest błyskawiczne autouzupełnianie kodu i generowanie całych funkcji na podstawie komentarzy bez opuszczania edytora. Poza tym Copilot „widzi” pliki, nad którymi aktualnie pracujemy, dzięki czemu lepiej dopasowuje sugestie do naszego stylu i struktury projektu.

Do korzystania z Copilota w VS Code wymagane jest konto na GitHub. Jest ono niezbędne do uwierzytelnienia subskrypcji i synchronizacji ustawień. Od grudnia 2024 roku dostępna jest wersja Copilot Free, która pozwala na darmowe korzystanie z narzędzia w VS Code (oczywiście są limity).
Po zainstalowaniu rozszerzenia GitHub Copilot w VS Code, zostaniemy poproszeni o zalogowanie się właśnie przez GitHub. Przy logowaniu widzimy trzy opcje, ponieważ GitHub (należący do Microsoftu) wspiera tzw. logowanie społecznościowe.

Loguję się korzystając z mojego wcześniej utworzonegfo konta.

W oknie chata Copilota podaję przykładową instrukcję:
Write a program in openedge ABL that:
1. Prompts the user for a customer number
2. Finds that customer in the Customer table
3. Calculates the total value of all orders for that customer by summing OrderLine.ExtendedPrice
4. Displays the results.

Instrukcje możemy napisać po polsku ale warto jednak pamiętać, że choć Copilot rozumie polski, to jego główne dane treningowe pochodzą z publicznych repozytoriów, gdzie dominuje język angielski. Dlatego precyzyjne terminy techniczne lub bardziej złożone instrukcje mogą czasem dawać lepsze rezultaty w języku angielskim.
Musimy poczekać kilka minut. Poniżej jest wygenerowana procedura.

/* total_customer_orders.p
   Prompts for a customer number, finds the customer,
   sums OrderLine.ExtendedPrice for that customer's orders,
   and displays the total value.
*/

DEFINE VARIABLE iCustNo AS INTEGER NO-UNDO.
DEFINE VARIABLE decTotal AS DECIMAL NO-UNDO INITIAL 0.
DEFINE VARIABLE lHasLines AS LOGICAL NO-UNDO INITIAL FALSE.

PUT UNFORMATTED "Enter customer number: ".
IMPORT UNFORMATTED iCustNo.

FIND Customer NO-LOCK WHERE Customer.CustNum = iCustNo NO-ERROR.
IF NOT AVAILABLE Customer THEN DO:
    MESSAGE "Customer " iCustNo " not found." VIEW-AS ALERT-BOX.
    RETURN.
END.

FOR EACH Order NO-LOCK WHERE Order.CustNum = iCustNo NO-ERROR:
    FOR EACH OrderLine NO-LOCK WHERE OrderLine.OrderNum = Order.OrderNum NO-ERROR:
        ASSIGN decTotal = decTotal + OrderLine.ExtendedPrice
               lHasLines = TRUE.
    END.
END.

IF NOT lHasLines THEN
    MESSAGE "No orders found for customer " iCustNo VIEW-AS ALERT-BOX.
ELSE
    MESSAGE "Total value for customer " iCustNo ": " decTotal VIEW-AS ALERT-BOX.

RETURN.

Tu widzimy błędy jak np. NO-ERROR w pętli FOR EACH, czy sposób wprowadzenia numeru klienta. Stwórzmy plik z instrukcjami dla Copilota. Powinien on spowodować usunięcie NO-ERROR, zmienić sposób deklaracji zmiennych na nowocześniejszy a także wprowadzić pewne zmiany w formatowaniu.

.github/copilot-instructions.md

# Modern OpenEdge ABL Development Standards

## 1. Language Version
- Target OpenEdge ABL 12 or newer only.
- Do not generate legacy ABL syntax.

## 2. Variables
- Always use `VAR` for local variables.
- Never use `DEFINE VARIABLE`.
- Do not specify `NO-UNDO` (default in modern ABL).
- Use the equal sign (`=`) for initial values (e.g., `VAR INT i = 10`).

## 3. Data Types
- Use full data type names only:
  `CHARACTER`, `INTEGER`, `DECIMAL`, `LOGICAL`.
- Do not use abbreviated types.

## 4. Error Handling
- Every procedure or class must start with:
  `BLOCK-LEVEL ON ERROR UNDO, THROW.`

## 5. Formatting
- Use UPPERCASE for all ABL keywords.
- Use 4-space indentation.
- One statement per line.

## 6. Data Retrieval
- Don't use NO-ERROR with FOR loops.

Powtarzamy zlecenie najlepiej dla nowego czata.

/* total_customer_orders2.p
   Prompts for a customer number, finds the customer,
   sums OrderLine.ExtendedPrice for that customer's orders,
   and displays the total value.
*/

BLOCK-LEVEL ON ERROR UNDO, THROW.

VAR INTEGER iCustNo = 0.
VAR DECIMAL decTotal = 0.
VAR LOGICAL lHasLines = FALSE.

PUT UNFORMATTED "Enter customer number: ".
IMPORT UNFORMATTED iCustNo.

FIND Customer NO-LOCK WHERE Customer.CustNum = iCustNo NO-ERROR.
IF NOT AVAILABLE Customer THEN DO:
	MESSAGE "Customer " iCustNo " not found." VIEW-AS ALERT-BOX.
	RETURN.
END.

FOR EACH Order NO-LOCK WHERE Order.CustNum = iCustNo:
	FOR EACH OrderLine NO-LOCK WHERE OrderLine.OrderNum = Order.OrderNum:
		ASSIGN decTotal = decTotal + OrderLine.ExtendedPrice.
		ASSIGN lHasLines = TRUE.
	END.
END.

IF NOT lHasLines THEN
	MESSAGE "No orders found for customer " iCustNo VIEW-AS ALERT-BOX.
ELSE
	MESSAGE "Total value for customer " iCustNo ": " decTotal VIEW-AS ALERT-BOX.

RETURN.

Chciałbym żeby relacje były w skróconej formie ze słowem kluczowym OF, więc dodaję instrukcję na końcu pliku .github/copilot-instructions.md
– Establish relationships between two tables using the OF keyword

OK, trzecia próba wygenerowania procedury.

/* total_customer_orders3.p */
BLOCK-LEVEL ON ERROR UNDO, THROW.

VAR CHARACTER custNum = "".
VAR DECIMAL totalValue = 0.

DISPLAY "Enter Customer Number:".
UPDATE custNum.

FIND Customer WHERE Customer.CustNum = custNum NO-LOCK.

IF AVAILABLE Customer THEN
DO:
    FOR EACH Order OF Customer NO-LOCK:
        FOR EACH OrderLine OF Order NO-LOCK:
            totalValue = totalValue + OrderLine.ExtendedPrice.
        END.
    END.

    DISPLAY
        "Customer Number:" Customer.CustNum
        "Customer Name:" Customer.Name
        "Total Order Value:" totalValue.
END.
ELSE
DO:
    DISPLAY "Customer not found.".
END.

Chociaż nie instruowałem agenta o sposobie wprowadzenia numeru klienta, zmienił on sposób, ale niestety na błędny. Pole custnum nie może występować zanim rekord nie będzie w buforze, jednakże relacje sa napisane prawidłowo. Inny jest sposób podania wyniku co nie powinno nas dziwić, w końcu to sztuczna inteligencja.
No dobrze, ale co dostaniemy jeśli to zadanie skieruje do czataGPT. Nie zna on struktury bazy więc trzeba napisać, że chodzi o bazę testową sports2000.

/*---------------------------------------------------------
   Program: customerOrderTotal.p
   Purpose: Display total order value for a customer
---------------------------------------------------------*/

DEFINE VARIABLE iCustNum    AS INTEGER   NO-UNDO.
DEFINE VARIABLE dTotalValue AS DECIMAL   NO-UNDO.

/* Prompt user for customer number */
UPDATE iCustNum
    LABEL "Enter Customer Number"
    WITH FRAME fInput.

/* Find the customer */
FIND Customer
    WHERE Customer.CustNum = iCustNum
    NO-LOCK
    NO-ERROR.

IF NOT AVAILABLE Customer THEN DO:
    MESSAGE "Customer number" iCustNum "not found."
        VIEW-AS ALERT-BOX ERROR.
    RETURN.
END.

/* Calculate total order value */
FOR EACH Order
    WHERE Order.CustNum = Customer.CustNum
    NO-LOCK,
    EACH OrderLine
    WHERE OrderLine.OrderNum = Order.OrderNum
    NO-LOCK:

    dTotalValue = dTotalValue + OrderLine.ExtendedPrice.
END.

/* Display result */
MESSAGE
    "Customer:" Customer.Name SKIP
    "Total Order Value:" dTotalValue
    VIEW-AS ALERT-BOX INFORMATION.

Nie jest żle bo program jest kompilowalny. Można kazać mu stosować nowy sposób deklaracji zmiennych i skrócony zapis relacji między tablicami i wtedy będzie jeszcze lepiej. Chodzi tu jednak o dobrze znana bazę. Co jeśli mamy własne bazy i bardziej skomplikowany problem? No i co na to Progress? Czy nie ma dla nas jakiegoś bardziej eleganckiego rozwiązania? Prędzej czy później o tym napiszę.

OpenEdge i VS Code

Visual Studio Code (VS Code) jest alternatywą dla tradycyjnego środowiska Progress Developer Studio (PDSOE). Dzięki oficjalnemu wsparciu Progress Software, programiści OpenEdge mogą korzystać z lekkiego i nowoczesnego środowiska IDE.
Konfiguracja VS Code opiera się na pliku konfiguracyjnym w formacie JSON – w głównym folderze projektu musi znajdować się plik openedge-project.json, zawierający definicje OpenEdge jak: wersja OE, ścieżki (PROPATH), połączenia z bazami danych oraz parametry startowe sesji.
Porównując oba środowisku, VS Code jest lżejszy. PDSOE zużywa dużo więcej pamięci i jest wolniejszy. Jednakże za tym drugim środowiskiem przemawia środowisko graficzne (Visual Designer) niezbędne przy tworzenie projektów typu GUI i .NET.
Jeśli chodzi o integrację ze sztuczną inteligencją, to PDSOE ma ograniczone wsparcie w postaci instalacji pluginu AI. VS Code jest silnie zintegrowany z Github Copilot.
Myślę, że niedaleka przyszłość pokaże jak będa się rozwijać oba środowiska.
Zobaczmy teraz jak skonfigurować VS Code żebyśmy mogli tworzyć programy w ABL na przykładzie wspieranego przez Progress rozszerzenia firmy Riverside Software.
Wymaga ono przynajmniej jednej instalacji OpenEdge z licencją deweloperską i jest obecnie testowane z wersjami 11.7, 12.2 i 12.8, choć nie wyklucza się, że może pracować także ze starszymi wersjami.

Po zainstalowaniu pluginu wchodzimy do ustawień klikając ikonę z kołem zębatym (tzw. gear icon). i klikając Settings.

Wybieram z listy zainstalowaną wersję OpenEdge i klikam na Edit in settings.json. Dodaję ścieżkę do katalogu DLC. Powinno to wyglądać m.w. tak:

    "abl.configuration.defaultRuntime": "12.8",
    "abl.configuration.runtimes": [
        {
            "name": "12.8",
            "path": "C:\\OpenEdge128"
        }
    ],

W katalogu projektu należy umieścić plik openedge-project.json zawierający ustawienia sesji openedge.
Na początku najłatwiej go utworzyć z poziomu sesji ABL, wykonując procedurę utworzoną przez Carla Verbiesta.
Uruchamiamy zatem sesję mpro, prowin czy PDSOE z podłączoną bazą danych i uruchamiamy powyższą procedurę. Teraz trzeba dopasować ścieżki poprawiając znaki “/” i “\” w zależności od systemu operacyjnego. Ja mam dla Windows.
Po małej edycji mój plik openedge-project.json wygląda tak:

{
  "name": "application",
  "version": "1.0",
  "oeversion": "12.8",
  "graphicalMode": true,
  "charset": "ISO8859-1",
  "extraParameters": "-basekey ini",
  "workingDirectory": "C:\\vsProject",
  "numThreads": 1,
  "buildPath": [
    {
      "type": "propath",
      "path": "."
    },
    {
      "type": "propath",
      "path": "C:\\OpenEdge128\\gui"
    },
    {
      "type": "propath",
      "path": "C:\\OpenEdge128"
    },
    {
      "type": "propath",
      "path": "C:\\OpenEdge128\\bin"
    },
    {
      "type": "propath",
      "path": "C:\\OpenEdge128\\gui"
    },
    {
      "type": "propath",
      "path": "C:\\OPENED~1"
    },
    {
      "type": "propath",
      "path": "C:\\OpenEdge128\\bin"
    }
  ],
  "dbConnections": [
    {
      "name": "t",
      "connect": "-db C:\\WrkOpenEdge128\\db\\t -S 10001",
      "schemaFile": "dump\\t.df",
      "aliases": [
        "dictdb"
      ]
    }
  ]
}

Teraz trzeba utworzyć w projekcie podkatalog dump i umieścić tam plik t.df ze schematem bazy.

Gotowe. Teraz wystarczy stworzyć plik z rozszerzeniem .p i napisać kod procedury. Wybieramy Ctrl + Shift + p i wpisujemy komendę ABL: Run with prowin. Jeśli kod jest poprawny to zostaje wykonany.
Jeśli napiszemy tylko ABL: to zobaczymy całą listę dostępnych komend.
Powodzenia.