Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ permissionset 8350 "MCP - Objects"
Caption = 'MCP - Objects';

Permissions = table "MCP API Publisher Group" = X,
table "MCP API Version" = X,
table "MCP Configuration" = X,
table "MCP Configuration Tool" = X,
table "MCP Config Warning" = X,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ codeunit 8351 "MCP Config Implementation"
InvalidAPIVersionErr: Label 'Only API v2.0 pages are supported.';
DefaultMCPConfigurationDescriptionLbl: Label 'Default MCP configuration';
DynamicToolModeRequiredErr: Label 'Dynamic tool mode needs to be enabled to discover read-only objects.';
VersionNotValidErr: Label 'The API version is not valid for the selected tool.';
MCPConfigurationCreatedLbl: Label 'MCP Configuration created', Locked = true;
MCPConfigurationModifiedLbl: Label 'MCP Configuration modified', Locked = true;
MCPConfigurationDeletedLbl: Label 'MCP Configuration deleted', Locked = true;
Expand All @@ -45,7 +46,7 @@ codeunit 8351 "MCP Config Implementation"
MCPPrefixProdLbl: Label 'businesscentral', Locked = true;
MCPPrefixTIELbl: Label 'businesscentral-tie', Locked = true;
VSCodeAppNameLbl: Label 'VS Code', Locked = true;
VSCodeAppDescriptionLbl: Label 'Visual Studio Code';
VSCodeAppDescriptionLbl: Label 'Visual Studio Code', Locked = true;
VSCodeClientIdLbl: Label 'aebc6443-996d-45c2-90f0-388ff96faa56', Locked = true;

#region Configurations
Expand Down Expand Up @@ -359,19 +360,21 @@ codeunit 8351 "MCP Config Implementation"
var
MCPConfiguration: Record "MCP Configuration";
MCPConfigurationTool: Record "MCP Configuration Tool";
PageMetadata: Record "Page Metadata";
begin
if not MCPConfiguration.GetBySystemId(ConfigId) then
exit;

if IsDefaultConfiguration(MCPConfiguration) then
Error(ToolsCannotBeAddedToDefaultConfigErr);

ValidateAPITool(APIPageId, ValidateAPIPublisher);
PageMetadata := ValidateAPITool(APIPageId, ValidateAPIPublisher);

MCPConfigurationTool.ID := ConfigId;
MCPConfigurationTool."Object Type" := MCPConfigurationTool."Object Type"::Page;
MCPConfigurationTool."Object ID" := APIPageId;
MCPConfigurationTool."Allow Read" := true;
MCPConfigurationTool."API Version" := GetHighestAPIVersion(PageMetadata);
MCPConfigurationTool.Insert();
exit(MCPConfigurationTool.SystemId);
end;
Expand Down Expand Up @@ -518,7 +521,7 @@ codeunit 8351 "MCP Config Implementation"
APIGroup := MCPAPIPublisherGroup."API Group";
end;

internal procedure ValidateAPITool(PageId: Integer; ValidateAPIPublisher: Boolean)
internal procedure ValidateAPITool(PageId: Integer; ValidateAPIPublisher: Boolean): Record "Page Metadata"
var
PageMetadata: Record "Page Metadata";
begin
Expand All @@ -529,13 +532,15 @@ codeunit 8351 "MCP Config Implementation"
Error(InvalidPageTypeErr);

if not ValidateAPIPublisher then
exit;
exit(PageMetadata);

if PageMetadata.APIPublisher = 'microsoft' then
Error(InvalidAPIVersionErr);

if PageMetadata."AL Namespace" = 'Microsoft.API.V1' then
Error(InvalidAPIVersionErr);

exit(PageMetadata);
end;

internal procedure AddToolsByAPIGroup(ConfigId: Guid)
Expand Down Expand Up @@ -636,6 +641,102 @@ codeunit 8351 "MCP Config Implementation"
MCPSystemTool."Tool Description" := ToolDescription;
MCPSystemTool.Insert();
end;

internal procedure ValidateAPIVersion(ObjectId: Integer; APIVersion: Text)
var
PageMetadata: Record "Page Metadata";
Versions: List of [Text];
begin
if not PageMetadata.Get(ObjectId) then
exit;

Versions := PageMetadata.APIVersion.Split(',');
if not Versions.Contains(APIVersion) then
Error(VersionNotValidErr);
end;

internal procedure LookupAPIVersions(PageId: Integer; var APIVersion: Text[30])
var
PageMetadata: Record "Page Metadata";
MCPAPIVersion: Record "MCP API Version";
Versions: List of [Text];
Version: Text[30];
begin
if not PageMetadata.Get(PageId) then
exit;

Versions := PageMetadata.APIVersion.Split(',');
foreach Version in Versions do begin
MCPAPIVersion."API Version" := Version;
MCPAPIVersion.Insert();
end;

if Page.RunModal(Page::"MCP API Version Lookup", MCPAPIVersion) = Action::LookupOK then
APIVersion := MCPAPIVersion."API Version";
end;

internal procedure GetHighestAPIVersion(PageMetadata: Record "Page Metadata"): Text[30]
var
Versions: List of [Text];
Version: Text;
HighestVersion: Text;
HighestMajor: Integer;
HighestMinor: Integer;
CurrentMajor: Integer;
CurrentMinor: Integer;
begin
if PageMetadata.APIVersion = '' then
exit('');

Versions := PageMetadata.APIVersion.Split(',');

if Versions.Count() = 1 then
exit(CopyStr(Versions.Get(1), 1, 30));

HighestMajor := -1;
HighestMinor := -1;

foreach Version in Versions do
if TryParseVersion(Version, CurrentMajor, CurrentMinor) then
if (CurrentMajor > HighestMajor) or ((CurrentMajor = HighestMajor) and (CurrentMinor > HighestMinor)) then begin
HighestMajor := CurrentMajor;
HighestMinor := CurrentMinor;
HighestVersion := Version;
end;

exit(CopyStr(HighestVersion, 1, 30));
end;

local procedure TryParseVersion(Version: Text; var Major: Integer; var Minor: Integer): Boolean
var
VersionParts: List of [Text];
VersionNumber: Text;
begin
// 'beta' is treated as lowest priority
if Version.ToLower() = 'beta' then begin
Major := -1;
Minor := -1;
exit(true);
end;

// Expected format: vMajor.Minor (e.g., v1.0, v2.0)
if not Version.StartsWith('v') then
exit(false);

VersionNumber := Version.Substring(2); // Remove 'v'
VersionParts := VersionNumber.Split('.');

if VersionParts.Count() <> 2 then
exit(false);

if not Evaluate(Major, VersionParts.Get(1)) then
exit(false);

if not Evaluate(Minor, VersionParts.Get(2)) then
exit(false);

exit(true);
end;
#endregion

#region Connection String
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ codeunit 8354 "MCP Config Missing Parent" implements "MCP Config Warning"
repeat
if PageMetadata.Get(MCPConfigurationTool."Object ID") then
if PageMetadata.PageType = PageMetadata.PageType::API then
PageIdVersions.Add(MCPConfigurationTool."Object ID", PageMetadata.APIVersion);
PageIdVersions.Add(MCPConfigurationTool."Object ID", MCPConfigurationTool."API Version");
until MCPConfigurationTool.Next() = 0;

// Get parent mappings from platform
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// ------------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
// ------------------------------------------------------------------------------------------------

namespace System.MCP;

using System.Reflection;
using System.Upgrade;

codeunit 8356 "MCP Upgrade"
{
Subtype = Upgrade;
InherentEntitlements = X;
InherentPermissions = X;

trigger OnUpgradePerDatabase()
begin
UpgradeMCPAPIToolVersion();
end;

internal procedure UpgradeMCPAPIToolVersion()
var
MCPConfigurationTool: Record "MCP Configuration Tool";
PageMetadata: Record "Page Metadata";
MCPConfigImplementation: Codeunit "MCP Config Implementation";
UpgradeTag: Codeunit "Upgrade Tag";
begin
if UpgradeTag.HasDatabaseUpgradeTag(GetMCPAPIToolVersionUpgradeTag()) then
exit;

MCPConfigurationTool.SetRange("API Version", '');
if MCPConfigurationTool.FindSet() then
repeat
if not PageMetadata.Get(MCPConfigurationTool."Object ID") then
continue;

if PageMetadata.PageType <> PageMetadata.PageType::API then
continue;

MCPConfigurationTool."API Version" := MCPConfigImplementation.GetHighestAPIVersion(PageMetadata);
MCPConfigurationTool.Modify();
until MCPConfigurationTool.Next() = 0;

UpgradeTag.SetUpgradeTag(GetMCPAPIToolVersionUpgradeTag());
end;

[EventSubscriber(ObjectType::Codeunit, Codeunit::"Upgrade Tag", OnGetPerDatabaseUpgradeTags, '', false, false)]
local procedure RegisterUpgradeTags(var PerDatabaseUpgradeTags: List of [Code[250]])
begin
PerDatabaseUpgradeTags.Add(GetMCPAPIToolVersionUpgradeTag());
end;

local procedure GetMCPAPIToolVersionUpgradeTag(): Text[250]
begin
exit('MS-619475-MCPAPIToolVersion-20260126');
end;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// ------------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
// ------------------------------------------------------------------------------------------------

namespace System.MCP;

page 8366 "MCP API Version Lookup"
{
PageType = List;
ApplicationArea = All;
SourceTable = "MCP API Version";
Caption = 'API Versions';
Extensible = false;
Editable = false;
InsertAllowed = false;
ModifyAllowed = false;
DeleteAllowed = false;
InherentEntitlements = X;
InherentPermissions = X;

layout
{
area(Content)
{
repeater(Control1)
{
field("API Version"; Rec."API Version")
{
Caption = 'API Version';
ToolTip = 'Specifies the API version.';
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,11 @@ page 8352 "MCP Config Tool List"
end;

trigger OnValidate()
var
PageMetadata: Record "Page Metadata";
begin
MCPConfigImplementation.ValidateAPITool(Rec."Object Id", true);
PageMetadata := MCPConfigImplementation.ValidateAPITool(Rec."Object Id", true);
Rec."API Version" := MCPConfigImplementation.GetHighestAPIVersion(PageMetadata);
SetPermissions();
end;
}
Expand All @@ -61,6 +64,28 @@ page 8352 "MCP Config Tool List"
Editable = false;
ToolTip = 'Specifies the name of the object.';
}
field("API Version"; Rec."API Version")
{
Caption = 'API Version';
ToolTip = 'Specifies the API version of the tool.';

trigger OnLookup(var Text: Text): Boolean
var
APIVersion: Text[30];
begin
if Rec."Object ID" = 0 then
exit;

MCPConfigImplementation.LookupAPIVersions(Rec."Object Id", APIVersion);
if APIVersion <> '' then
Rec."API Version" := APIVersion;
end;

trigger OnValidate()
begin
MCPConfigImplementation.ValidateAPIVersion(Rec."Object Id", Rec."API Version");
end;
}
field("Allow Read"; Rec."Allow Read") { }
field("Allow Create"; Rec."Allow Create")
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,10 @@ table 8350 "MCP API Publisher Group"
{
field(1; "API Publisher"; Text[40])
{
DataClassification = ToBeClassified;
Caption = 'API Publisher';
}
field(2; "API Group"; Text[40])
{
DataClassification = ToBeClassified;
Caption = 'API Group';
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// ------------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
// ------------------------------------------------------------------------------------------------

namespace System.MCP;

table 8354 "MCP API Version"
{
Access = Internal;
DataClassification = SystemMetadata;
TableType = Temporary;

fields
{
field(1; "API Version"; Text[30])
{
Caption = 'API Version';
}
}

keys
{
key(Key1; "API Version")
{
Clustered = true;
}
}

fieldgroups
{
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,9 @@ codeunit 130131 "MCP Config Test Library"
MCPConfigImplementation.GetAPIPublishers(MCPAPIPublisherGroup);
MCPConfigImplementation.LookupAPIGroup(MCPAPIPublisherGroup, APIPublisher, APIGroup);
end;

procedure GetHighestAPIVersion(PageMetadata: Record "Page Metadata"): Text[30]
begin
exit(MCPConfigImplementation.GetHighestAPIVersion(PageMetadata));
end;
}
Loading
Loading