@vjeko.com/al-object-id-ninja-mcp 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +115 -0
- package/dist/src/al-app/ALApp.d.ts +52 -0
- package/dist/src/al-app/ALApp.js +130 -0
- package/dist/src/al-app/ALApp.js.map +1 -0
- package/dist/src/al-app/ALAppManifest.d.ts +39 -0
- package/dist/src/al-app/ALAppManifest.js +114 -0
- package/dist/src/al-app/ALAppManifest.js.map +1 -0
- package/dist/src/al-app/AppResolver.d.ts +24 -0
- package/dist/src/al-app/AppResolver.js +100 -0
- package/dist/src/al-app/AppResolver.js.map +1 -0
- package/dist/src/al-app/ObjIdConfig.d.ts +23 -0
- package/dist/src/al-app/ObjIdConfig.js +84 -0
- package/dist/src/al-app/ObjIdConfig.js.map +1 -0
- package/dist/src/al-app/index.d.ts +4 -0
- package/dist/src/al-app/index.js +12 -0
- package/dist/src/al-app/index.js.map +1 -0
- package/dist/src/backend/BackendClient.d.ts +35 -0
- package/dist/src/backend/BackendClient.js +129 -0
- package/dist/src/backend/BackendClient.js.map +1 -0
- package/dist/src/backend/index.d.ts +1 -0
- package/dist/src/backend/index.js +6 -0
- package/dist/src/backend/index.js.map +1 -0
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.js +9 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/server.d.ts +3 -0
- package/dist/src/server.js +108 -0
- package/dist/src/server.js.map +1 -0
- package/dist/src/tools/AssignObjectIdTool.d.ts +16 -0
- package/dist/src/tools/AssignObjectIdTool.js +83 -0
- package/dist/src/tools/AssignObjectIdTool.js.map +1 -0
- package/dist/src/tools/UnassignObjectIdTool.d.ts +16 -0
- package/dist/src/tools/UnassignObjectIdTool.js +50 -0
- package/dist/src/tools/UnassignObjectIdTool.js.map +1 -0
- package/dist/src/tools/index.d.ts +3 -0
- package/dist/src/tools/index.js +8 -0
- package/dist/src/tools/index.js.map +1 -0
- package/dist/src/types/ALObjectType.d.ts +15 -0
- package/dist/src/types/ALObjectType.js +20 -0
- package/dist/src/types/ALObjectType.js.map +1 -0
- package/dist/src/types/ALRange.d.ts +7 -0
- package/dist/src/types/ALRange.js +3 -0
- package/dist/src/types/ALRange.js.map +1 -0
- package/dist/src/types/NextObjectIdInfo.d.ts +9 -0
- package/dist/src/types/NextObjectIdInfo.js +3 -0
- package/dist/src/types/NextObjectIdInfo.js.map +1 -0
- package/dist/src/types/NinjaALRange.d.ts +4 -0
- package/dist/src/types/NinjaALRange.js +3 -0
- package/dist/src/types/NinjaALRange.js.map +1 -0
- package/dist/src/types/PropertyBag.d.ts +3 -0
- package/dist/src/types/PropertyBag.js +3 -0
- package/dist/src/types/PropertyBag.js.map +1 -0
- package/dist/src/types/index.d.ts +5 -0
- package/dist/src/types/index.js +6 -0
- package/dist/src/types/index.js.map +1 -0
- package/dist/src/utils/getSha256.d.ts +1 -0
- package/dist/src/utils/getSha256.js +43 -0
- package/dist/src/utils/getSha256.js.map +1 -0
- package/dist/src/utils/index.d.ts +2 -0
- package/dist/src/utils/index.js +9 -0
- package/dist/src/utils/index.js.map +1 -0
- package/dist/src/utils/validation.d.ts +2 -0
- package/dist/src/utils/validation.js +20 -0
- package/dist/src/utils/validation.js.map +1 -0
- package/package.json +59 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.ObjIdConfig = void 0;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const comment_json_1 = require("comment-json");
|
|
39
|
+
/**
|
|
40
|
+
* Read-only representation of the .objidconfig file.
|
|
41
|
+
*/
|
|
42
|
+
class ObjIdConfig {
|
|
43
|
+
_path;
|
|
44
|
+
_config;
|
|
45
|
+
constructor(configPath) {
|
|
46
|
+
this._path = configPath;
|
|
47
|
+
this._config = this.read();
|
|
48
|
+
}
|
|
49
|
+
read() {
|
|
50
|
+
try {
|
|
51
|
+
const content = fs.readFileSync(this._path).toString() || "{}";
|
|
52
|
+
return (0, comment_json_1.parse)(content);
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return {};
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
get path() {
|
|
59
|
+
return this._path;
|
|
60
|
+
}
|
|
61
|
+
get authKey() {
|
|
62
|
+
return this._config.authKey || "";
|
|
63
|
+
}
|
|
64
|
+
get appPoolId() {
|
|
65
|
+
return this._config.appPoolId || "";
|
|
66
|
+
}
|
|
67
|
+
get idRanges() {
|
|
68
|
+
return [...(this._config.idRanges || [])];
|
|
69
|
+
}
|
|
70
|
+
get objectRanges() {
|
|
71
|
+
return this._config.objectRanges || {};
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Gets ranges for the specified object type.
|
|
75
|
+
* Falls back to idRanges if no object-specific ranges are defined.
|
|
76
|
+
* @param objectType Object type for which to get ranges
|
|
77
|
+
* @returns Ranges for the specified object type
|
|
78
|
+
*/
|
|
79
|
+
getObjectTypeRanges(objectType) {
|
|
80
|
+
return this.objectRanges[objectType] || this.idRanges;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
exports.ObjIdConfig = ObjIdConfig;
|
|
84
|
+
//# sourceMappingURL=ObjIdConfig.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ObjIdConfig.js","sourceRoot":"","sources":["../../../src/al-app/ObjIdConfig.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,uCAAyB;AACzB,+CAAqC;AAWrC;;GAEG;AACH,MAAa,WAAW;IACH,KAAK,CAAS;IACd,OAAO,CAAkB;IAE1C,YAAmB,UAAkB;QACjC,IAAI,CAAC,KAAK,GAAG,UAAU,CAAC;QACxB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC/B,CAAC;IAEO,IAAI;QACR,IAAI,CAAC;YACD,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,EAAE,IAAI,IAAI,CAAC;YAC/D,OAAO,IAAA,oBAAK,EAAC,OAAO,CAA+B,CAAC;QACxD,CAAC;QAAC,MAAM,CAAC;YACL,OAAO,EAAqB,CAAC;QACjC,CAAC;IACL,CAAC;IAED,IAAW,IAAI;QACX,OAAO,IAAI,CAAC,KAAK,CAAC;IACtB,CAAC;IAED,IAAW,OAAO;QACd,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC;IACtC,CAAC;IAED,IAAW,SAAS;QAChB,OAAO,IAAI,CAAC,OAAO,CAAC,SAAS,IAAI,EAAE,CAAC;IACxC,CAAC;IAED,IAAW,QAAQ;QACf,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,CAAC;IAC9C,CAAC;IAED,IAAW,YAAY;QACnB,OAAO,IAAI,CAAC,OAAO,CAAC,YAAY,IAAI,EAAE,CAAC;IAC3C,CAAC;IAED;;;;;OAKG;IACH,mBAAmB,CAAC,UAAkB;QAClC,OAAO,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC;IAC1D,CAAC;CACJ;AA/CD,kCA+CC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AppResolver = exports.ObjIdConfig = exports.ALAppManifest = exports.ALApp = void 0;
|
|
4
|
+
var ALApp_1 = require("./ALApp");
|
|
5
|
+
Object.defineProperty(exports, "ALApp", { enumerable: true, get: function () { return ALApp_1.ALApp; } });
|
|
6
|
+
var ALAppManifest_1 = require("./ALAppManifest");
|
|
7
|
+
Object.defineProperty(exports, "ALAppManifest", { enumerable: true, get: function () { return ALAppManifest_1.ALAppManifest; } });
|
|
8
|
+
var ObjIdConfig_1 = require("./ObjIdConfig");
|
|
9
|
+
Object.defineProperty(exports, "ObjIdConfig", { enumerable: true, get: function () { return ObjIdConfig_1.ObjIdConfig; } });
|
|
10
|
+
var AppResolver_1 = require("./AppResolver");
|
|
11
|
+
Object.defineProperty(exports, "AppResolver", { enumerable: true, get: function () { return AppResolver_1.AppResolver; } });
|
|
12
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/al-app/index.ts"],"names":[],"mappings":";;;AAAA,iCAAgC;AAAvB,8FAAA,KAAK,OAAA;AACd,iDAAgD;AAAvC,8GAAA,aAAa,OAAA;AACtB,6CAA4C;AAAnC,0GAAA,WAAW,OAAA;AACpB,6CAA4C;AAAnC,0GAAA,WAAW,OAAA"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { ALApp } from "../al-app/ALApp";
|
|
2
|
+
import { NinjaALRange } from "../types/NinjaALRange";
|
|
3
|
+
import { NextObjectIdInfo } from "../types/NextObjectIdInfo";
|
|
4
|
+
/**
|
|
5
|
+
* HTTP client for communicating with the AL Object ID Ninja backend API.
|
|
6
|
+
*/
|
|
7
|
+
export declare class BackendClient {
|
|
8
|
+
/**
|
|
9
|
+
* Gets the next available object ID from the backend.
|
|
10
|
+
* @param app The AL app
|
|
11
|
+
* @param type Object type (e.g., "table", "codeunit")
|
|
12
|
+
* @param ranges Ranges to allocate from
|
|
13
|
+
* @param commit Whether to commit the allocation
|
|
14
|
+
* @param require Optional specific range starting ID to require
|
|
15
|
+
* @returns NextObjectIdInfo or undefined on failure
|
|
16
|
+
*/
|
|
17
|
+
static getNextNo(app: ALApp, type: string, ranges: NinjaALRange[], commit: boolean, require?: number): Promise<NextObjectIdInfo | undefined>;
|
|
18
|
+
/**
|
|
19
|
+
* Removes (unassigns) an object ID assignment.
|
|
20
|
+
* @param app The AL app
|
|
21
|
+
* @param type Object type
|
|
22
|
+
* @param id Object ID to unassign
|
|
23
|
+
* @returns true if the assignment was removed, false otherwise
|
|
24
|
+
*/
|
|
25
|
+
static removeAssignment(app: ALApp, type: string, id: number): Promise<boolean>;
|
|
26
|
+
/**
|
|
27
|
+
* Sends a request to the backend API.
|
|
28
|
+
* @param path API endpoint path
|
|
29
|
+
* @param method HTTP method
|
|
30
|
+
* @param data Request body
|
|
31
|
+
* @param app ALApp for auth key and manifest info
|
|
32
|
+
* @returns Response data or undefined on error
|
|
33
|
+
*/
|
|
34
|
+
private static sendRequest;
|
|
35
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BackendClient = void 0;
|
|
4
|
+
const child_process_1 = require("child_process");
|
|
5
|
+
const BACKEND_URL = "https://backend.alid.ninja";
|
|
6
|
+
// Must be >= 3.1.0 to pass backend version check
|
|
7
|
+
const MCP_VERSION = "3.1.0";
|
|
8
|
+
/**
|
|
9
|
+
* Executes a git command and returns the output.
|
|
10
|
+
*/
|
|
11
|
+
function execGitCommand(command, cwd) {
|
|
12
|
+
return new Promise((resolve) => {
|
|
13
|
+
(0, child_process_1.exec)(`git ${command}`, { cwd, windowsHide: true }, (error, stdout) => {
|
|
14
|
+
if (error) {
|
|
15
|
+
resolve("");
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
resolve(stdout.trim());
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Gets git user info (name and email) for the given directory.
|
|
24
|
+
* Always reads fresh from git config - no caching.
|
|
25
|
+
*/
|
|
26
|
+
async function getGitUserInfo(cwd) {
|
|
27
|
+
const [name, email] = await Promise.all([
|
|
28
|
+
execGitCommand("config user.name", cwd),
|
|
29
|
+
execGitCommand("config user.email", cwd),
|
|
30
|
+
]);
|
|
31
|
+
return {
|
|
32
|
+
name,
|
|
33
|
+
email: email.toLowerCase(),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* HTTP client for communicating with the AL Object ID Ninja backend API.
|
|
38
|
+
*/
|
|
39
|
+
class BackendClient {
|
|
40
|
+
/**
|
|
41
|
+
* Gets the next available object ID from the backend.
|
|
42
|
+
* @param app The AL app
|
|
43
|
+
* @param type Object type (e.g., "table", "codeunit")
|
|
44
|
+
* @param ranges Ranges to allocate from
|
|
45
|
+
* @param commit Whether to commit the allocation
|
|
46
|
+
* @param require Optional specific range starting ID to require
|
|
47
|
+
* @returns NextObjectIdInfo or undefined on failure
|
|
48
|
+
*/
|
|
49
|
+
static async getNextNo(app, type, ranges, commit, require) {
|
|
50
|
+
const appId = app.config.appPoolId || app.hash;
|
|
51
|
+
const body = {
|
|
52
|
+
appId,
|
|
53
|
+
type,
|
|
54
|
+
ranges,
|
|
55
|
+
commit,
|
|
56
|
+
perRange: true,
|
|
57
|
+
};
|
|
58
|
+
if (commit && require) {
|
|
59
|
+
body.require = require;
|
|
60
|
+
}
|
|
61
|
+
const response = await this.sendRequest(`/api/v3/getNext/${appId}`, "POST", body, app);
|
|
62
|
+
return response;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Removes (unassigns) an object ID assignment.
|
|
66
|
+
* @param app The AL app
|
|
67
|
+
* @param type Object type
|
|
68
|
+
* @param id Object ID to unassign
|
|
69
|
+
* @returns true if the assignment was removed, false otherwise
|
|
70
|
+
*/
|
|
71
|
+
static async removeAssignment(app, type, id) {
|
|
72
|
+
const appId = app.config.appPoolId || app.hash;
|
|
73
|
+
const response = await this.sendRequest(`/api/v3/storeAssignment/${appId}/${type}/${id}/delete`, "POST", { appId }, app);
|
|
74
|
+
return !!response?.updated;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Sends a request to the backend API.
|
|
78
|
+
* @param path API endpoint path
|
|
79
|
+
* @param method HTTP method
|
|
80
|
+
* @param data Request body
|
|
81
|
+
* @param app ALApp for auth key and manifest info
|
|
82
|
+
* @returns Response data or undefined on error
|
|
83
|
+
*/
|
|
84
|
+
static async sendRequest(path, method, data, app) {
|
|
85
|
+
const url = `${BACKEND_URL}${path}`;
|
|
86
|
+
const headers = {
|
|
87
|
+
"Content-Type": "application/json",
|
|
88
|
+
};
|
|
89
|
+
// Add auth key if available
|
|
90
|
+
if (app.authKey) {
|
|
91
|
+
headers["Ninja-Auth-Key"] = app.authKey;
|
|
92
|
+
}
|
|
93
|
+
// Add app ID header
|
|
94
|
+
if (app.manifest.id) {
|
|
95
|
+
headers["Ninja-App-Id"] = app.manifest.id;
|
|
96
|
+
}
|
|
97
|
+
// Get git user info fresh for every request
|
|
98
|
+
const gitUser = await getGitUserInfo(app.rootPath);
|
|
99
|
+
// Build header payload (must include ninjaVersion >= 3.1.0)
|
|
100
|
+
const headerPayload = {
|
|
101
|
+
gitUserName: gitUser.name || undefined,
|
|
102
|
+
gitUserEmail: gitUser.email || undefined,
|
|
103
|
+
appPublisher: app.manifest.publisher,
|
|
104
|
+
appName: app.manifest.name,
|
|
105
|
+
appVersion: app.manifest.version,
|
|
106
|
+
ninjaVersion: MCP_VERSION,
|
|
107
|
+
source: "mcp",
|
|
108
|
+
};
|
|
109
|
+
headers["Ninja-Header-Payload"] = Buffer.from(JSON.stringify(headerPayload)).toString("base64");
|
|
110
|
+
try {
|
|
111
|
+
const response = await fetch(url, {
|
|
112
|
+
method,
|
|
113
|
+
headers,
|
|
114
|
+
body: data ? JSON.stringify(data) : undefined,
|
|
115
|
+
});
|
|
116
|
+
if (!response.ok) {
|
|
117
|
+
const body = await response.text();
|
|
118
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText} - ${body}`);
|
|
119
|
+
}
|
|
120
|
+
return await response.json();
|
|
121
|
+
}
|
|
122
|
+
catch (error) {
|
|
123
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
124
|
+
throw new Error(`Backend request failed: ${message}`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
exports.BackendClient = BackendClient;
|
|
129
|
+
//# sourceMappingURL=BackendClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BackendClient.js","sourceRoot":"","sources":["../../../src/backend/BackendClient.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { BackendClient } from "./BackendClient";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BackendClient = void 0;
|
|
4
|
+
var BackendClient_1 = require("./BackendClient");
|
|
5
|
+
Object.defineProperty(exports, "BackendClient", { enumerable: true, get: function () { return BackendClient_1.BackendClient; } });
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/backend/index.ts"],"names":[],"mappings":";;;AAAA,iDAAgD;AAAvC,8GAAA,aAAa,OAAA"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const server_1 = require("./server");
|
|
5
|
+
(0, server_1.runServer)().catch((error) => {
|
|
6
|
+
console.error("Failed to start MCP server:", error);
|
|
7
|
+
process.exit(1);
|
|
8
|
+
});
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;AAEA,qCAAqC;AAErC,IAAA,kBAAS,GAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACxB,OAAO,CAAC,KAAK,CAAC,6BAA6B,EAAE,KAAK,CAAC,CAAC;IACpD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACpB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createServer = createServer;
|
|
4
|
+
exports.runServer = runServer;
|
|
5
|
+
const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
|
|
6
|
+
const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
7
|
+
const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
|
|
8
|
+
const tools_1 = require("./tools");
|
|
9
|
+
function toCallToolResult(result) {
|
|
10
|
+
return {
|
|
11
|
+
content: result.content,
|
|
12
|
+
isError: result.isError,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
const TOOL_DEFINITIONS = [
|
|
16
|
+
{
|
|
17
|
+
name: "ninja_assignObjectId",
|
|
18
|
+
description: "Assigns and commits the next available AL object ID. " +
|
|
19
|
+
"The ID is reserved immediately and can be used in the AL object file. " +
|
|
20
|
+
"Use this when creating new AL objects that require IDs (tables, pages, codeunits, etc.).",
|
|
21
|
+
inputSchema: {
|
|
22
|
+
type: "object",
|
|
23
|
+
properties: {
|
|
24
|
+
objectType: {
|
|
25
|
+
type: "string",
|
|
26
|
+
description: "The AL object type. Valid types: codeunit, enum, enumextension, page, pageextension, " +
|
|
27
|
+
"permissionset, permissionsetextension, query, report, reportextension, table, " +
|
|
28
|
+
"tableextension, xmlport. For table fields use table_{tableId}, for enum values use enum_{enumId}.",
|
|
29
|
+
},
|
|
30
|
+
targetFilePath: {
|
|
31
|
+
type: "string",
|
|
32
|
+
description: "Absolute path to a file within the AL app. Used to identify which AL app to assign the ID for.",
|
|
33
|
+
},
|
|
34
|
+
rangeName: {
|
|
35
|
+
type: "string",
|
|
36
|
+
description: "Optional. Name of the logical range to use when multiple ranges are configured. " +
|
|
37
|
+
"Required when the app has multiple ranges defined for the object type.",
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
required: ["objectType", "targetFilePath"],
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
name: "ninja_unassignObjectId",
|
|
45
|
+
description: "Unassigns (releases) a previously assigned AL object ID, making it available for future assignments. " +
|
|
46
|
+
"Use this when deleting an AL object or when an ID was assigned by mistake.",
|
|
47
|
+
inputSchema: {
|
|
48
|
+
type: "object",
|
|
49
|
+
properties: {
|
|
50
|
+
objectType: {
|
|
51
|
+
type: "string",
|
|
52
|
+
description: "The AL object type. Valid types: codeunit, enum, enumextension, page, pageextension, " +
|
|
53
|
+
"permissionset, permissionsetextension, query, report, reportextension, table, " +
|
|
54
|
+
"tableextension, xmlport. For table fields use table_{tableId}, for enum values use enum_{enumId}.",
|
|
55
|
+
},
|
|
56
|
+
objectId: {
|
|
57
|
+
type: "number",
|
|
58
|
+
description: "The object ID to unassign. Must be a positive number.",
|
|
59
|
+
},
|
|
60
|
+
targetFilePath: {
|
|
61
|
+
type: "string",
|
|
62
|
+
description: "Absolute path to a file within the AL app. Used to identify which AL app to unassign the ID from.",
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
required: ["objectType", "objectId", "targetFilePath"],
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
];
|
|
69
|
+
function createServer() {
|
|
70
|
+
const server = new index_js_1.Server({
|
|
71
|
+
name: "AL Object ID Ninja",
|
|
72
|
+
version: "3.1.5",
|
|
73
|
+
}, {
|
|
74
|
+
capabilities: {
|
|
75
|
+
tools: {},
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
// List available tools
|
|
79
|
+
server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => {
|
|
80
|
+
return { tools: TOOL_DEFINITIONS };
|
|
81
|
+
});
|
|
82
|
+
// Handle tool calls
|
|
83
|
+
server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
84
|
+
const { name, arguments: args } = request.params;
|
|
85
|
+
switch (name) {
|
|
86
|
+
case "ninja_assignObjectId": {
|
|
87
|
+
const input = args;
|
|
88
|
+
return toCallToolResult(await (0, tools_1.assignObjectId)(input));
|
|
89
|
+
}
|
|
90
|
+
case "ninja_unassignObjectId": {
|
|
91
|
+
const input = args;
|
|
92
|
+
return toCallToolResult(await (0, tools_1.unassignObjectId)(input));
|
|
93
|
+
}
|
|
94
|
+
default:
|
|
95
|
+
return {
|
|
96
|
+
content: [{ type: "text", text: `Unknown tool: ${name}` }],
|
|
97
|
+
isError: true,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
return server;
|
|
102
|
+
}
|
|
103
|
+
async function runServer() {
|
|
104
|
+
const server = createServer();
|
|
105
|
+
const transport = new stdio_js_1.StdioServerTransport();
|
|
106
|
+
await server.connect(transport);
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface AssignObjectIdInput {
|
|
2
|
+
objectType: string;
|
|
3
|
+
targetFilePath: string;
|
|
4
|
+
rangeName?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface McpToolResult {
|
|
7
|
+
content: Array<{
|
|
8
|
+
type: "text";
|
|
9
|
+
text: string;
|
|
10
|
+
}>;
|
|
11
|
+
isError?: boolean;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Assigns and commits the next available AL object ID.
|
|
15
|
+
*/
|
|
16
|
+
export declare function assignObjectId(input: AssignObjectIdInput): Promise<McpToolResult>;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.assignObjectId = assignObjectId;
|
|
4
|
+
const AppResolver_1 = require("../al-app/AppResolver");
|
|
5
|
+
const BackendClient_1 = require("../backend/BackendClient");
|
|
6
|
+
const validation_1 = require("../utils/validation");
|
|
7
|
+
function makeResult(text, isError = false) {
|
|
8
|
+
return {
|
|
9
|
+
content: [{ type: "text", text }],
|
|
10
|
+
isError,
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Assigns and commits the next available AL object ID.
|
|
15
|
+
*/
|
|
16
|
+
async function assignObjectId(input) {
|
|
17
|
+
const { objectType, targetFilePath, rangeName } = input;
|
|
18
|
+
const type = objectType.toLowerCase();
|
|
19
|
+
// Validate object type
|
|
20
|
+
if (!(0, validation_1.isValidObjectType)(type)) {
|
|
21
|
+
return makeResult(`Error: Invalid object type "${objectType}". ${(0, validation_1.getValidTypesMessage)()}`, true);
|
|
22
|
+
}
|
|
23
|
+
// Resolve AL app from file path
|
|
24
|
+
const app = AppResolver_1.AppResolver.resolveFromPath(targetFilePath);
|
|
25
|
+
if (!app) {
|
|
26
|
+
return makeResult(`Error: No AL app found for path "${targetFilePath}". ` +
|
|
27
|
+
`The path must be within an AL app folder (a folder containing app.json).`, true);
|
|
28
|
+
}
|
|
29
|
+
// Get ranges for the object type
|
|
30
|
+
const ranges = app.getObjectTypeRanges(type);
|
|
31
|
+
if (ranges.length === 0) {
|
|
32
|
+
return makeResult(`Error: No ID ranges found for ${type}. ` +
|
|
33
|
+
`Configure ranges in app.json (idRanges property) or .objidconfig.`, true);
|
|
34
|
+
}
|
|
35
|
+
// Check if we need range selection
|
|
36
|
+
if (ranges.length > 1 && !rangeName) {
|
|
37
|
+
const rangeList = ranges
|
|
38
|
+
.map(r => `- "${r.description}": ${r.from}-${r.to}`)
|
|
39
|
+
.join("\n");
|
|
40
|
+
return makeResult(`Error: Multiple ranges available for ${type}. You must specify which range to use via the rangeName parameter.\n\n` +
|
|
41
|
+
`Available ranges:\n${rangeList}\n\n` +
|
|
42
|
+
`Either decide based on the object's purpose (e.g., "Temporary Tables" for temp tables) ` +
|
|
43
|
+
`or ask the user which range to use.`, true);
|
|
44
|
+
}
|
|
45
|
+
// Find the target range
|
|
46
|
+
let targetRange;
|
|
47
|
+
if (rangeName) {
|
|
48
|
+
const found = ranges.find(r => r.description?.toLowerCase() === rangeName.toLowerCase());
|
|
49
|
+
if (!found) {
|
|
50
|
+
const available = ranges.map(r => `"${r.description}"`).join(", ");
|
|
51
|
+
return makeResult(`Error: Range "${rangeName}" not found for ${type}. Available ranges: ${available}`, true);
|
|
52
|
+
}
|
|
53
|
+
targetRange = found;
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
targetRange = ranges[0];
|
|
57
|
+
}
|
|
58
|
+
try {
|
|
59
|
+
// Send request to backend with the target range
|
|
60
|
+
const singleRange = [targetRange];
|
|
61
|
+
const result = await BackendClient_1.BackendClient.getNextNo(app, type, singleRange, true, targetRange.from);
|
|
62
|
+
if (!result) {
|
|
63
|
+
return makeResult(`Error: Failed to get next ${type} ID. The backend did not return a result.`, true);
|
|
64
|
+
}
|
|
65
|
+
if (!result.available) {
|
|
66
|
+
return makeResult(`Error: No ${type} IDs available in range "${targetRange.description}" (${targetRange.from}-${targetRange.to}). ` +
|
|
67
|
+
`All IDs in this range have been consumed.`, true);
|
|
68
|
+
}
|
|
69
|
+
const id = Array.isArray(result.id) ? result.id[0] : result.id;
|
|
70
|
+
const rangeDisplay = targetRange.description
|
|
71
|
+
? `${targetRange.description} (${targetRange.from}-${targetRange.to})`
|
|
72
|
+
: `${targetRange.from}-${targetRange.to}`;
|
|
73
|
+
return makeResult(`Successfully committed ${type} ID: ${id}\n` +
|
|
74
|
+
`App: ${app.manifest.name}\n` +
|
|
75
|
+
`Range: ${rangeDisplay}\n` +
|
|
76
|
+
`This ID has been reserved and can be used immediately.`);
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
80
|
+
return makeResult(`Error: Failed to commit ${type} ID: ${errorMessage}`, true);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=AssignObjectIdTool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AssignObjectIdTool.js","sourceRoot":"","sources":["../../../src/tools/AssignObjectIdTool.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface UnassignObjectIdInput {
|
|
2
|
+
objectType: string;
|
|
3
|
+
objectId: number;
|
|
4
|
+
targetFilePath: string;
|
|
5
|
+
}
|
|
6
|
+
export interface McpToolResult {
|
|
7
|
+
content: Array<{
|
|
8
|
+
type: "text";
|
|
9
|
+
text: string;
|
|
10
|
+
}>;
|
|
11
|
+
isError?: boolean;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Unassigns (releases) a previously assigned AL object ID.
|
|
15
|
+
*/
|
|
16
|
+
export declare function unassignObjectId(input: UnassignObjectIdInput): Promise<McpToolResult>;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.unassignObjectId = unassignObjectId;
|
|
4
|
+
const AppResolver_1 = require("../al-app/AppResolver");
|
|
5
|
+
const BackendClient_1 = require("../backend/BackendClient");
|
|
6
|
+
const validation_1 = require("../utils/validation");
|
|
7
|
+
function makeResult(text, isError = false) {
|
|
8
|
+
return {
|
|
9
|
+
content: [{ type: "text", text }],
|
|
10
|
+
isError,
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Unassigns (releases) a previously assigned AL object ID.
|
|
15
|
+
*/
|
|
16
|
+
async function unassignObjectId(input) {
|
|
17
|
+
const { objectType, objectId, targetFilePath } = input;
|
|
18
|
+
const type = objectType.toLowerCase();
|
|
19
|
+
// Validate object type
|
|
20
|
+
if (!(0, validation_1.isValidObjectType)(type)) {
|
|
21
|
+
return makeResult(`Error: Invalid object type "${objectType}". ${(0, validation_1.getValidTypesMessage)()}`, true);
|
|
22
|
+
}
|
|
23
|
+
// Validate object ID
|
|
24
|
+
if (typeof objectId !== "number" || objectId <= 0) {
|
|
25
|
+
return makeResult(`Error: Invalid object ID "${objectId}". Must be a positive number.`, true);
|
|
26
|
+
}
|
|
27
|
+
// Resolve AL app from file path
|
|
28
|
+
const app = AppResolver_1.AppResolver.resolveFromPath(targetFilePath);
|
|
29
|
+
if (!app) {
|
|
30
|
+
return makeResult(`Error: No AL app found for path "${targetFilePath}". ` +
|
|
31
|
+
`The path must be within an AL app folder (a folder containing app.json).`, true);
|
|
32
|
+
}
|
|
33
|
+
try {
|
|
34
|
+
const success = await BackendClient_1.BackendClient.removeAssignment(app, type, objectId);
|
|
35
|
+
if (success) {
|
|
36
|
+
return makeResult(`Successfully unassigned ${type} ID: ${objectId}\n` +
|
|
37
|
+
`App: ${app.manifest.name}\n` +
|
|
38
|
+
`The ID has been released and is now available for future assignments.`);
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
return makeResult(`Warning: Unassign request for ${type} ID ${objectId} completed but no changes were made. ` +
|
|
42
|
+
`The ID may not have been assigned or was already unassigned.`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
47
|
+
return makeResult(`Error: Failed to unassign ${type} ID ${objectId}: ${errorMessage}`, true);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=UnassignObjectIdTool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UnassignObjectIdTool.js","sourceRoot":"","sources":["../../../src/tools/UnassignObjectIdTool.ts"],"names":[],"mappings":";;AAyBA,4CAoDC;AA7ED,uDAAoD;AACpD,4DAAyD;AACzD,oDAA8E;AAa9E,SAAS,UAAU,CAAC,IAAY,EAAE,OAAO,GAAG,KAAK;IAC7C,OAAO;QACH,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;QACjC,OAAO;KACV,CAAC;AACN,CAAC;AAED;;GAEG;AACI,KAAK,UAAU,gBAAgB,CAAC,KAA4B;IAC/D,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,cAAc,EAAE,GAAG,KAAK,CAAC;IACvD,MAAM,IAAI,GAAG,UAAU,CAAC,WAAW,EAAE,CAAC;IAEtC,uBAAuB;IACvB,IAAI,CAAC,IAAA,8BAAiB,EAAC,IAAI,CAAC,EAAE,CAAC;QAC3B,OAAO,UAAU,CACb,+BAA+B,UAAU,MAAM,IAAA,iCAAoB,GAAE,EAAE,EACvE,IAAI,CACP,CAAC;IACN,CAAC;IAED,qBAAqB;IACrB,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,IAAI,CAAC,EAAE,CAAC;QAChD,OAAO,UAAU,CACb,6BAA6B,QAAQ,+BAA+B,EACpE,IAAI,CACP,CAAC;IACN,CAAC;IAED,gCAAgC;IAChC,MAAM,GAAG,GAAG,yBAAW,CAAC,eAAe,CAAC,cAAc,CAAC,CAAC;IACxD,IAAI,CAAC,GAAG,EAAE,CAAC;QACP,OAAO,UAAU,CACb,oCAAoC,cAAc,KAAK;YACvD,0EAA0E,EAC1E,IAAI,CACP,CAAC;IACN,CAAC;IAED,IAAI,CAAC;QACD,MAAM,OAAO,GAAG,MAAM,6BAAa,CAAC,gBAAgB,CAAC,GAAG,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;QAE1E,IAAI,OAAO,EAAE,CAAC;YACV,OAAO,UAAU,CACb,2BAA2B,IAAI,QAAQ,QAAQ,IAAI;gBACnD,QAAQ,GAAG,CAAC,QAAQ,CAAC,IAAI,IAAI;gBAC7B,uEAAuE,CAC1E,CAAC;QACN,CAAC;aAAM,CAAC;YACJ,OAAO,UAAU,CACb,iCAAiC,IAAI,OAAO,QAAQ,uCAAuC;gBAC3F,8DAA8D,CACjE,CAAC;QACN,CAAC;IACL,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACb,MAAM,YAAY,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC5E,OAAO,UAAU,CACb,6BAA6B,IAAI,OAAO,QAAQ,KAAK,YAAY,EAAE,EACnE,IAAI,CACP,CAAC;IACN,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.unassignObjectId = exports.assignObjectId = void 0;
|
|
4
|
+
var AssignObjectIdTool_1 = require("./AssignObjectIdTool");
|
|
5
|
+
Object.defineProperty(exports, "assignObjectId", { enumerable: true, get: function () { return AssignObjectIdTool_1.assignObjectId; } });
|
|
6
|
+
var UnassignObjectIdTool_1 = require("./UnassignObjectIdTool");
|
|
7
|
+
Object.defineProperty(exports, "unassignObjectId", { enumerable: true, get: function () { return UnassignObjectIdTool_1.unassignObjectId; } });
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/tools/index.ts"],"names":[],"mappings":";;;AAAA,2DAA2E;AAAlE,oHAAA,cAAc,OAAA;AACvB,+DAAiF;AAAxE,wHAAA,gBAAgB,OAAA"}
|