@softacus-software/elwis-docs-mcp 0.1.1 → 0.2.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 +122 -43
- package/dist/app-scope.js +92 -0
- package/dist/app-scope.js.map +1 -0
- package/dist/artifact-read.js +114 -0
- package/dist/artifact-read.js.map +1 -0
- package/dist/cli/client-configs.js +86 -0
- package/dist/cli/client-configs.js.map +1 -0
- package/dist/cli/login.js +64 -0
- package/dist/cli/login.js.map +1 -0
- package/dist/cli/prompter.js +85 -0
- package/dist/cli/prompter.js.map +1 -0
- package/dist/cli/setup.js +152 -0
- package/dist/cli/setup.js.map +1 -0
- package/dist/config.js +39 -0
- package/dist/config.js.map +1 -0
- package/dist/elwis-api.js +68 -0
- package/dist/elwis-api.js.map +1 -0
- package/dist/entity-read.js +192 -0
- package/dist/entity-read.js.map +1 -0
- package/dist/http-client.js +140 -0
- package/dist/http-client.js.map +1 -0
- package/dist/index.js +8 -1
- package/dist/index.js.map +1 -1
- package/dist/jwt.js +18 -0
- package/dist/jwt.js.map +1 -0
- package/dist/prune.js +9 -0
- package/dist/prune.js.map +1 -0
- package/dist/resolve.js +71 -0
- package/dist/resolve.js.map +1 -0
- package/dist/result.js +16 -0
- package/dist/result.js.map +1 -0
- package/dist/server.js +51 -0
- package/dist/server.js.map +1 -1
- package/dist/session-store.js +51 -0
- package/dist/session-store.js.map +1 -0
- package/dist/tools/explain-access.js +36 -0
- package/dist/tools/explain-access.js.map +1 -0
- package/dist/tools/get-entity.js +36 -0
- package/dist/tools/get-entity.js.map +1 -0
- package/dist/tools/get-page.js +75 -0
- package/dist/tools/get-page.js.map +1 -0
- package/dist/tools/list-apps.js +22 -0
- package/dist/tools/list-apps.js.map +1 -0
- package/dist/tools/list-entities.js +43 -0
- package/dist/tools/list-entities.js.map +1 -0
- package/dist/tools/read-artifacts.js +197 -0
- package/dist/tools/read-artifacts.js.map +1 -0
- package/dist/tools/resolve-entity.js +22 -0
- package/dist/tools/resolve-entity.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { request as httpRequest } from 'node:http';
|
|
2
|
+
import { request as httpsRequest } from 'node:https';
|
|
3
|
+
import { URL } from 'node:url';
|
|
4
|
+
const REFRESH_PATH = '/api/tenant/session/refresh';
|
|
5
|
+
const REQUEST_TIMEOUT_MS = 30000;
|
|
6
|
+
export class ElwisHttpError extends Error {
|
|
7
|
+
status;
|
|
8
|
+
path;
|
|
9
|
+
body;
|
|
10
|
+
constructor(status, path, body) {
|
|
11
|
+
super(`ELWIS API ${status} for ${path}`);
|
|
12
|
+
this.name = 'ElwisHttpError';
|
|
13
|
+
this.status = status;
|
|
14
|
+
this.path = path;
|
|
15
|
+
this.body = body;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export class SessionExpiredError extends Error {
|
|
19
|
+
constructor() {
|
|
20
|
+
super('Your ELWIS session has expired or was revoked. Open Terminal and run: npx @softacus-software/elwis-docs-mcp@latest login');
|
|
21
|
+
this.name = 'SessionExpiredError';
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
export function HttpErrorDetail(error) {
|
|
25
|
+
return error instanceof ElwisHttpError && error.body !== undefined ? `: ${JSON.stringify(error.body)}` : '';
|
|
26
|
+
}
|
|
27
|
+
export function CookieToken(setCookies) {
|
|
28
|
+
for (const cookie of setCookies) {
|
|
29
|
+
const match = /^session-jwt=([^;]+)/.exec(cookie);
|
|
30
|
+
if (match && match[1].length > 0)
|
|
31
|
+
return match[1];
|
|
32
|
+
}
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
export class ElwisHttpClient {
|
|
36
|
+
cfg;
|
|
37
|
+
opts;
|
|
38
|
+
refreshing = null;
|
|
39
|
+
constructor(cfg, opts = {}) {
|
|
40
|
+
this.cfg = cfg;
|
|
41
|
+
this.opts = opts;
|
|
42
|
+
}
|
|
43
|
+
get(path) { return this.send('GET', path); }
|
|
44
|
+
post(path, body) { return this.send('POST', path, body); }
|
|
45
|
+
async send(method, path, body, isRetry = false) {
|
|
46
|
+
const tokenAtSend = this.cfg.token;
|
|
47
|
+
const res = await this.request(method, path, body);
|
|
48
|
+
this.adoptRotatedToken(res.setCookies);
|
|
49
|
+
if (res.status >= 200 && res.status < 300)
|
|
50
|
+
return res.parsed;
|
|
51
|
+
const original = new ElwisHttpError(res.status, path, res.parsed);
|
|
52
|
+
if (res.status === 401 && this.opts.refresh && !isRetry && path !== REFRESH_PATH) {
|
|
53
|
+
if (this.cfg.token !== tokenAtSend)
|
|
54
|
+
return this.send(method, path, body, true);
|
|
55
|
+
try {
|
|
56
|
+
await this.refreshToken();
|
|
57
|
+
}
|
|
58
|
+
catch (e) {
|
|
59
|
+
if (e instanceof SessionExpiredError)
|
|
60
|
+
throw e;
|
|
61
|
+
throw original;
|
|
62
|
+
}
|
|
63
|
+
return this.send(method, path, body, true);
|
|
64
|
+
}
|
|
65
|
+
throw original;
|
|
66
|
+
}
|
|
67
|
+
adoptRotatedToken(setCookies) {
|
|
68
|
+
if (!this.opts.refresh)
|
|
69
|
+
return;
|
|
70
|
+
const rotated = CookieToken(setCookies);
|
|
71
|
+
if (!rotated || rotated === this.cfg.token)
|
|
72
|
+
return;
|
|
73
|
+
this.cfg.token = rotated;
|
|
74
|
+
try {
|
|
75
|
+
this.opts.persist?.(rotated);
|
|
76
|
+
}
|
|
77
|
+
catch (e) {
|
|
78
|
+
process.stderr.write(`could not save the refreshed session: ${e.message}\n`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
refreshToken() {
|
|
82
|
+
this.refreshing = this.refreshing ?? this.doRefresh().finally(() => { this.refreshing = null; });
|
|
83
|
+
return this.refreshing;
|
|
84
|
+
}
|
|
85
|
+
async doRefresh() {
|
|
86
|
+
const onDisk = this.opts.reload?.() ?? null;
|
|
87
|
+
if (onDisk && onDisk !== this.cfg.token) {
|
|
88
|
+
this.cfg.token = onDisk;
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
const res = await this.request('PATCH', REFRESH_PATH);
|
|
92
|
+
const fromCookie = CookieToken(res.setCookies);
|
|
93
|
+
const fromBody = res.parsed?.clientData?.sessionJwt;
|
|
94
|
+
const token = fromCookie ?? (typeof fromBody === 'string' && fromBody.length > 0 ? fromBody : null);
|
|
95
|
+
if (res.status === 401)
|
|
96
|
+
throw new SessionExpiredError();
|
|
97
|
+
if (res.status < 200 || res.status >= 300 || !token)
|
|
98
|
+
throw new Error(`session refresh answered ${res.status}`);
|
|
99
|
+
this.adoptRotatedToken([`session-jwt=${token}`]);
|
|
100
|
+
}
|
|
101
|
+
request(method, path, body) {
|
|
102
|
+
const url = new URL(this.cfg.baseUrl + path);
|
|
103
|
+
const payload = body === undefined ? undefined : Buffer.from(JSON.stringify(body), 'utf8');
|
|
104
|
+
const requester = url.protocol === 'https:' ? httpsRequest : httpRequest;
|
|
105
|
+
const headers = { Cookie: `session-jwt=${this.cfg.token}`, Origin: this.cfg.baseUrl };
|
|
106
|
+
if (payload) {
|
|
107
|
+
headers['content-type'] = 'application/json';
|
|
108
|
+
headers['content-length'] = String(payload.length);
|
|
109
|
+
}
|
|
110
|
+
return new Promise((resolveValue, reject) => {
|
|
111
|
+
const req = requester(url, { method, headers }, res => {
|
|
112
|
+
const chunks = [];
|
|
113
|
+
res.on('data', (c) => chunks.push(c));
|
|
114
|
+
res.on('end', () => {
|
|
115
|
+
const text = Buffer.concat(chunks).toString('utf8');
|
|
116
|
+
resolveValue({
|
|
117
|
+
status: res.statusCode ?? 0,
|
|
118
|
+
setCookies: res.headers['set-cookie'] ?? [],
|
|
119
|
+
parsed: text.length ? SafeJson(text) : undefined,
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
res.on('error', reject);
|
|
123
|
+
});
|
|
124
|
+
req.setTimeout(REQUEST_TIMEOUT_MS, () => req.destroy(new Error(`ELWIS did not answer within ${REQUEST_TIMEOUT_MS / 1000}s for ${path}`)));
|
|
125
|
+
req.on('error', reject);
|
|
126
|
+
if (payload)
|
|
127
|
+
req.write(payload);
|
|
128
|
+
req.end();
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
function SafeJson(text) {
|
|
133
|
+
try {
|
|
134
|
+
return JSON.parse(text);
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
return text;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=http-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-client.js","sourceRoot":"","sources":["../src/http-client.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -2,12 +2,19 @@
|
|
|
2
2
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
3
3
|
import { BuildServer } from './server.js';
|
|
4
4
|
async function Main() {
|
|
5
|
+
if (process.argv[2]) {
|
|
6
|
+
const { RunCli } = await import('./cli/setup.js');
|
|
7
|
+
if (await RunCli(process.argv))
|
|
8
|
+
return;
|
|
9
|
+
process.stderr.write(`Unknown command "${process.argv[2]}". Try: elwis-docs-mcp help\n`);
|
|
10
|
+
process.exit(2);
|
|
11
|
+
}
|
|
5
12
|
const server = BuildServer();
|
|
6
13
|
const transport = new StdioServerTransport();
|
|
7
14
|
await server.connect(transport);
|
|
8
15
|
}
|
|
9
16
|
Main().catch(e => {
|
|
10
|
-
|
|
17
|
+
process.stderr.write(`${e instanceof Error ? e.message : String(e)}\n`);
|
|
11
18
|
process.exit(1);
|
|
12
19
|
});
|
|
13
20
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,KAAK,UAAU,IAAI;IACjB,MAAM,MAAM,GAAG,WAAW,EAAE,CAAC;IAC7B,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;IACf,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,KAAK,UAAU,IAAI;IACjB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QACpB,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,gBAAgB,CAAC,CAAC;QAClD,IAAI,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;YAAE,OAAO;QACvC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,oBAAoB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,+BAA+B,CAAC,CAAC;QACzF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,MAAM,MAAM,GAAG,WAAW,EAAE,CAAC;IAC7B,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;IACf,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACxE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
package/dist/jwt.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export function DecodeJwtClaims(token) {
|
|
2
|
+
const parts = token.split('.');
|
|
3
|
+
if (parts.length < 2)
|
|
4
|
+
return {};
|
|
5
|
+
try {
|
|
6
|
+
const json = Buffer.from(parts[1], 'base64url').toString('utf8');
|
|
7
|
+
const obj = JSON.parse(json);
|
|
8
|
+
return {
|
|
9
|
+
sub: typeof obj.sub === 'string' ? obj.sub : undefined,
|
|
10
|
+
tenant: typeof obj.tenant === 'string' ? obj.tenant : undefined,
|
|
11
|
+
exp: typeof obj.exp === 'number' ? obj.exp : undefined,
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return {};
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=jwt.js.map
|
package/dist/jwt.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jwt.js","sourceRoot":"","sources":["../src/jwt.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,eAAe,CAAC,KAAa;IAC3C,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC/B,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IAChC,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QACjE,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAA4B,CAAC;QACxD,OAAO;YACL,GAAG,EAAE,OAAO,GAAG,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS;YACtD,MAAM,EAAE,OAAO,GAAG,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS;YAC/D,GAAG,EAAE,OAAO,GAAG,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS;SACvD,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QAAC,OAAO,EAAE,CAAC;IAAC,CAAC;AACxB,CAAC"}
|
package/dist/prune.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prune.js","sourceRoot":"","sources":["../src/prune.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,KAAK,CAAC,GAA4B;IAChD,MAAM,GAAG,GAA4B,EAAE,CAAC;IACxC,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACzC,IAAI,CAAC,KAAK,SAAS;YAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAClC,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
|
package/dist/resolve.js
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { ElwisHttpError } from './http-client.js';
|
|
2
|
+
const OID = /^[a-f0-9]{24}$/i;
|
|
3
|
+
export function IsObjectId(value) {
|
|
4
|
+
return OID.test(value);
|
|
5
|
+
}
|
|
6
|
+
export async function RequireApplicationId(api, ref) {
|
|
7
|
+
const appRef = ref.applicationId ?? ref.applicationName;
|
|
8
|
+
if (!appRef)
|
|
9
|
+
throw new Error('Provide applicationId or applicationName');
|
|
10
|
+
return ResolveApplicationId(api, appRef);
|
|
11
|
+
}
|
|
12
|
+
export class AmbiguityError extends Error {
|
|
13
|
+
candidates;
|
|
14
|
+
constructor(message, candidates) {
|
|
15
|
+
super(message);
|
|
16
|
+
this.name = 'AmbiguityError';
|
|
17
|
+
this.candidates = candidates;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export async function ResolveEntity(api, kind, applicationId, nameOrAlias) {
|
|
21
|
+
const scope = { applicationId: { $oid: applicationId } };
|
|
22
|
+
let rows;
|
|
23
|
+
try {
|
|
24
|
+
rows = await api.list(kind, { ...scope, $or: [{ name: nameOrAlias }, { alias: nameOrAlias }] });
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
if (error instanceof ElwisHttpError && error.status === 400) {
|
|
28
|
+
rows = await api.list(kind, { ...scope, name: nameOrAlias });
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
throw error;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return { matches: rows.map(r => ({ id: r.id, name: r.name, alias: r.alias, kind })) };
|
|
35
|
+
}
|
|
36
|
+
export async function ResolveOneId(api, kind, applicationId, ref) {
|
|
37
|
+
if (IsObjectId(ref))
|
|
38
|
+
return ref;
|
|
39
|
+
const { matches } = await ResolveEntity(api, kind, applicationId, ref);
|
|
40
|
+
if (matches.length === 1)
|
|
41
|
+
return matches[0].id;
|
|
42
|
+
if (matches.length === 0)
|
|
43
|
+
throw new AmbiguityError(`No active ${kind} named "${ref}" in the application`, []);
|
|
44
|
+
throw new AmbiguityError(`Multiple ${kind} entries named "${ref}" in the application; pass an explicit id`, matches.map(m => ({ id: m.id, name: m.name })));
|
|
45
|
+
}
|
|
46
|
+
export async function ResolveArtifactByRef(api, nameAttributeId, artifactTypeId, ref, label) {
|
|
47
|
+
if (IsObjectId(ref)) {
|
|
48
|
+
const artifact = await api.getOne('artifact', ref);
|
|
49
|
+
return { id: ref, name: artifact.attributes?.[nameAttributeId]?.value ?? ref };
|
|
50
|
+
}
|
|
51
|
+
const filter = { [`attributes.${nameAttributeId}.value`]: ref };
|
|
52
|
+
if (artifactTypeId)
|
|
53
|
+
filter.artifactTypeId = { $oid: artifactTypeId };
|
|
54
|
+
const page = await api.listRecords('artifact', filter, { limit: 2 });
|
|
55
|
+
if (page.data.length === 1)
|
|
56
|
+
return { id: page.data[0].id, name: ref };
|
|
57
|
+
if (page.data.length === 0)
|
|
58
|
+
throw new Error(`No ${label} artifact named "${ref}"${artifactTypeId ? ' in the restricted artifact type' : ''}`);
|
|
59
|
+
throw new AmbiguityError(`Multiple ${label} artifacts named "${ref}"; pass an explicit id`, page.data.map(a => ({ id: a.id, name: ref })));
|
|
60
|
+
}
|
|
61
|
+
export async function ResolveApplicationId(api, applicationIdOrName) {
|
|
62
|
+
if (IsObjectId(applicationIdOrName))
|
|
63
|
+
return applicationIdOrName;
|
|
64
|
+
const rows = await api.list('application', { name: applicationIdOrName });
|
|
65
|
+
if (rows.length === 1)
|
|
66
|
+
return rows[0].id;
|
|
67
|
+
if (rows.length === 0)
|
|
68
|
+
throw new AmbiguityError(`No active application named "${applicationIdOrName}"`, []);
|
|
69
|
+
throw new AmbiguityError(`Multiple active applications named "${applicationIdOrName}"; pass an explicit applicationId`, rows.map(r => ({ id: r.id, name: r.name })));
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=resolve.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve.js","sourceRoot":"","sources":["../src/resolve.ts"],"names":[],"mappings":"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"}
|
package/dist/result.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { AmbiguityError } from './resolve.js';
|
|
2
|
+
import { ElwisHttpError } from './http-client.js';
|
|
3
|
+
export function Text(value, isError = false) {
|
|
4
|
+
const result = { content: [{ type: 'text', text: JSON.stringify(value, null, 2) }] };
|
|
5
|
+
if (isError)
|
|
6
|
+
result.isError = true;
|
|
7
|
+
return result;
|
|
8
|
+
}
|
|
9
|
+
export function ErrorResult(error) {
|
|
10
|
+
if (error instanceof AmbiguityError)
|
|
11
|
+
return Text({ status: 'error', error: error.message, candidates: error.candidates }, true);
|
|
12
|
+
if (error instanceof ElwisHttpError)
|
|
13
|
+
return Text({ status: 'error', error: error.message, status_code: error.status, detail: error.body }, true);
|
|
14
|
+
return Text({ status: 'error', error: error.message }, true);
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=result.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"result.js","sourceRoot":"","sources":["../src/result.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,MAAM,UAAU,IAAI,CAAC,KAAc,EAAE,OAAO,GAAG,KAAK;IAClD,MAAM,MAAM,GAAqE,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;IACvJ,IAAI,OAAO;QAAE,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC;IACnC,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,IAAI,KAAK,YAAY,cAAc;QAAE,OAAO,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,OAAO,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE,EAAE,IAAI,CAAC,CAAC;IAChI,IAAI,KAAK,YAAY,cAAc;QAAE,OAAO,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,OAAO,EAAE,WAAW,EAAE,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,IAAI,EAAE,EAAE,IAAI,CAAC,CAAC;IACjJ,OAAO,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAG,KAAe,CAAC,OAAO,EAAE,EAAE,IAAI,CAAC,CAAC;AAC1E,CAAC"}
|
package/dist/server.js
CHANGED
|
@@ -5,6 +5,18 @@ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
|
5
5
|
import { z } from 'zod';
|
|
6
6
|
import { DataStore } from './data-store.js';
|
|
7
7
|
import { SearchOperations } from './search.js';
|
|
8
|
+
import { LoadConfigOrNull } from './config.js';
|
|
9
|
+
import { ElwisHttpClient } from './http-client.js';
|
|
10
|
+
import { LoadSession, SaveSession } from './session-store.js';
|
|
11
|
+
import { ElwisApi } from './elwis-api.js';
|
|
12
|
+
import { AppScope } from './app-scope.js';
|
|
13
|
+
import { RegisterExplainAccess } from './tools/explain-access.js';
|
|
14
|
+
import { RegisterListApps } from './tools/list-apps.js';
|
|
15
|
+
import { RegisterListEntities } from './tools/list-entities.js';
|
|
16
|
+
import { RegisterResolveEntity } from './tools/resolve-entity.js';
|
|
17
|
+
import { RegisterGetEntity } from './tools/get-entity.js';
|
|
18
|
+
import { RegisterReadArtifacts } from './tools/read-artifacts.js';
|
|
19
|
+
import { RegisterGetPage } from './tools/get-page.js';
|
|
8
20
|
function PackageRoot() {
|
|
9
21
|
return resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
|
10
22
|
}
|
|
@@ -67,6 +79,45 @@ export function BuildServer() {
|
|
|
67
79
|
const e = store.GetExamples(operationId);
|
|
68
80
|
return e ? Text(e) : ErrorText(`Unknown operationId: ${operationId}`);
|
|
69
81
|
});
|
|
82
|
+
RegisterLiveReadTools(server);
|
|
70
83
|
return server;
|
|
71
84
|
}
|
|
85
|
+
function RegisterLiveReadTools(server) {
|
|
86
|
+
const { config: cfg, reason } = LoadConfigOrNull();
|
|
87
|
+
if (!cfg) {
|
|
88
|
+
server.registerTool('explain_elwis_access', {
|
|
89
|
+
description: 'Report whether this server is connected to a live ELWIS. The API documentation tools always work; the live read tools need a sign-in.',
|
|
90
|
+
annotations: READ_ONLY,
|
|
91
|
+
}, async () => Text({ connected: false, readOnly: true, note: reason }));
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
const client = new ElwisHttpClient(cfg, cfg.authMode === 'session'
|
|
95
|
+
? {
|
|
96
|
+
refresh: true,
|
|
97
|
+
reload: () => LoadSession(cfg.baseUrl)?.token ?? null,
|
|
98
|
+
persist: (token) => {
|
|
99
|
+
const existing = LoadSession(cfg.baseUrl);
|
|
100
|
+
SaveSession({
|
|
101
|
+
host: cfg.baseUrl,
|
|
102
|
+
token,
|
|
103
|
+
tenantId: existing?.tenantId ?? null,
|
|
104
|
+
email: existing?.email ?? null,
|
|
105
|
+
updatedAt: new Date().toISOString(),
|
|
106
|
+
});
|
|
107
|
+
},
|
|
108
|
+
}
|
|
109
|
+
: {});
|
|
110
|
+
const api = new ElwisApi(client, cfg.expectedTenant);
|
|
111
|
+
const scope = new AppScope(api, cfg.allowedApps, cfg.expectedTenant);
|
|
112
|
+
if (!cfg.expectedTenant) {
|
|
113
|
+
process.stderr.write('WARNING: no ELWIS_TENANT set, live read tools are disabled until a tenant is configured (explain_elwis_access shows the id, or re-run setup)\n');
|
|
114
|
+
}
|
|
115
|
+
RegisterExplainAccess(server, cfg, api, scope);
|
|
116
|
+
RegisterListApps(server, api, scope);
|
|
117
|
+
RegisterListEntities(server, api, scope);
|
|
118
|
+
RegisterResolveEntity(server, api, scope);
|
|
119
|
+
RegisterGetEntity(server, api, scope);
|
|
120
|
+
RegisterReadArtifacts(server, api, scope);
|
|
121
|
+
RegisterGetPage(server, api, scope);
|
|
122
|
+
}
|
|
72
123
|
//# sourceMappingURL=server.js.map
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { chmodSync, mkdirSync, readdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { homedir } from 'node:os';
|
|
4
|
+
import { dirname, join } from 'node:path';
|
|
5
|
+
export function DefaultSessionsDir() {
|
|
6
|
+
return process.env.ELWIS_SESSIONS_DIR?.trim() || join(homedir(), '.elwis', 'sessions');
|
|
7
|
+
}
|
|
8
|
+
export function SessionPath(host, dir = DefaultSessionsDir()) {
|
|
9
|
+
const key = createHash('sha256').update(host.replace(/\/$/, '')).digest('hex').slice(0, 12);
|
|
10
|
+
return join(dir, `${key}.json`);
|
|
11
|
+
}
|
|
12
|
+
export function LoadSession(host, dir) {
|
|
13
|
+
try {
|
|
14
|
+
const record = JSON.parse(readFileSync(SessionPath(host, dir), 'utf8'));
|
|
15
|
+
return typeof record.token === 'string' && record.token.length > 0 ? record : null;
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export function ListSessions(dir = DefaultSessionsDir()) {
|
|
22
|
+
try {
|
|
23
|
+
return readdirSync(dir)
|
|
24
|
+
.filter(name => name.endsWith('.json'))
|
|
25
|
+
.map(name => {
|
|
26
|
+
try {
|
|
27
|
+
return JSON.parse(readFileSync(join(dir, name), 'utf8'));
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
})
|
|
33
|
+
.filter((record) => record !== null && typeof record.token === 'string');
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return [];
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
export function SaveSession(record, dir) {
|
|
40
|
+
const path = SessionPath(record.host, dir);
|
|
41
|
+
const parent = dirname(path);
|
|
42
|
+
mkdirSync(parent, { recursive: true, mode: 0o700 });
|
|
43
|
+
chmodSync(parent, 0o700);
|
|
44
|
+
writeFileSync(path, `${JSON.stringify(record, null, 2)}\n`, { mode: 0o600 });
|
|
45
|
+
chmodSync(path, 0o600);
|
|
46
|
+
return path;
|
|
47
|
+
}
|
|
48
|
+
export function DeleteSession(host, dir) {
|
|
49
|
+
rmSync(SessionPath(host, dir), { force: true });
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=session-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-store.js","sourceRoot":"","sources":["../src/session-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { DecodeJwtClaims } from '../jwt.js';
|
|
2
|
+
import { Text } from '../result.js';
|
|
3
|
+
export function RegisterExplainAccess(server, cfg, api, scope) {
|
|
4
|
+
server.registerTool('explain_elwis_access', {
|
|
5
|
+
description: 'Report who the configured login acts as (verified against the backend), the tenant and whether it matches the tenant this connection is pinned to, the application allowlist, token expiry, and the tenant system attribute ids (Name, Sequence, Primary Text). This server is read-only: it can never create, change, or delete anything. Never returns the token itself. Call this first to check connectivity.',
|
|
6
|
+
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: true },
|
|
7
|
+
}, async () => {
|
|
8
|
+
const c = DecodeJwtClaims(cfg.token);
|
|
9
|
+
let identity;
|
|
10
|
+
let connected = true;
|
|
11
|
+
try {
|
|
12
|
+
identity = await api.whoAmI();
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
connected = false;
|
|
16
|
+
identity = { userId: c.sub ?? null, email: null, tenantId: c.tenant ?? null, tenantAdmin: null };
|
|
17
|
+
}
|
|
18
|
+
const systemAttributes = connected ? await api.systemAttributes().catch(() => null) : null;
|
|
19
|
+
return Text({
|
|
20
|
+
systemAttributes,
|
|
21
|
+
connected,
|
|
22
|
+
readOnly: true,
|
|
23
|
+
host: cfg.baseUrl,
|
|
24
|
+
user: identity.userId,
|
|
25
|
+
email: identity.email,
|
|
26
|
+
tenant: identity.tenantId,
|
|
27
|
+
tenantBinding: cfg.expectedTenant
|
|
28
|
+
? { pinned: true, expected: cfg.expectedTenant, matches: identity.tenantId === cfg.expectedTenant }
|
|
29
|
+
: { pinned: false, note: `No tenant is set, so the data tools are disabled, I cannot tell which ELWIS environment to read from. Set ELWIS_TENANT to ${identity.tenantId ?? 'the tenant this login belongs to'} (that is the tenant of the account you signed in with), or re-run the setup wizard, which fills it in automatically.` },
|
|
30
|
+
rights: identity.tenantAdmin === null ? 'unknown' : identity.tenantAdmin ? 'tenant-admin' : 'user',
|
|
31
|
+
appScope: scope.describe(),
|
|
32
|
+
tokenExpiry: c.exp ? new Date(c.exp * 1000).toISOString() : 'never',
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=explain-access.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"explain-access.js","sourceRoot":"","sources":["../../src/tools/explain-access.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAEpC,MAAM,UAAU,qBAAqB,CAAC,MAAiB,EAAE,GAAgB,EAAE,GAAa,EAAE,KAAe;IACvG,MAAM,CAAC,YAAY,CACjB,sBAAsB,EACtB;QACE,WAAW,EAAE,mZAAmZ;QACha,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE;KAC/E,EACD,KAAK,IAAI,EAAE;QACT,MAAM,CAAC,GAAG,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACrC,IAAI,QAA+G,CAAC;QACpH,IAAI,SAAS,GAAG,IAAI,CAAC;QACrB,IAAI,CAAC;YACH,QAAQ,GAAG,MAAM,GAAG,CAAC,MAAM,EAAE,CAAC;QAChC,CAAC;QAAC,MAAM,CAAC;YACP,SAAS,GAAG,KAAK,CAAC;YAClB,QAAQ,GAAG,EAAE,MAAM,EAAG,CAAC,CAAC,GAAc,IAAI,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAG,CAAC,CAAC,MAAiB,IAAI,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;QAC3H,CAAC;QACD,MAAM,gBAAgB,GAAG,SAAS,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,gBAAgB,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAC3F,OAAO,IAAI,CAAC;YACV,gBAAgB;YAChB,SAAS;YACT,QAAQ,EAAE,IAAI;YACd,IAAI,EAAE,GAAG,CAAC,OAAO;YACjB,IAAI,EAAE,QAAQ,CAAC,MAAM;YACrB,KAAK,EAAE,QAAQ,CAAC,KAAK;YACrB,MAAM,EAAE,QAAQ,CAAC,QAAQ;YACzB,aAAa,EAAE,GAAG,CAAC,cAAc;gBAC/B,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,CAAC,cAAc,EAAE,OAAO,EAAE,QAAQ,CAAC,QAAQ,KAAK,GAAG,CAAC,cAAc,EAAE;gBACnG,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,6HAA6H,QAAQ,CAAC,QAAQ,IAAI,kCAAkC,uHAAuH,EAAE;YACxU,MAAM,EAAE,QAAQ,CAAC,WAAW,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,MAAM;YAClG,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE;YAC1B,WAAW,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,OAAO;SACpE,CAAC,CAAC;IACL,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { ENTITY_KINDS, ResolveDocument } from '../entity-read.js';
|
|
3
|
+
import { RequireApplicationId, ResolveApplicationId } from '../resolve.js';
|
|
4
|
+
import { Text, ErrorResult } from '../result.js';
|
|
5
|
+
const GetEntityInput = z.object({
|
|
6
|
+
entity: z.enum(ENTITY_KINDS),
|
|
7
|
+
applicationId: z.string().optional(),
|
|
8
|
+
applicationName: z.string().optional(),
|
|
9
|
+
target: z.string().min(1).describe('Entity name, alias, or 24-char hex id (links by id only)'),
|
|
10
|
+
});
|
|
11
|
+
const OMITTED_FIELDS = ['acl'];
|
|
12
|
+
export function RegisterGetEntity(server, api, scope) {
|
|
13
|
+
server.registerTool('get_elwis_entity', {
|
|
14
|
+
description: 'Read the full body of one configuration entity: an application, data type, attribute, artifact type, link type, workflow, page, or link. Shows a data type\'s enum values, an artifact type\'s attribute assignments, a workflow\'s triggers and actions. For entity "application", target IS the application. Access control lists are omitted.',
|
|
15
|
+
inputSchema: GetEntityInput.shape,
|
|
16
|
+
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
17
|
+
}, async (raw) => {
|
|
18
|
+
try {
|
|
19
|
+
const applicationId = raw.entity === 'application'
|
|
20
|
+
? await ResolveApplicationId(api, raw.target)
|
|
21
|
+
: await RequireApplicationId(api, raw);
|
|
22
|
+
await scope.assertAllowed(applicationId);
|
|
23
|
+
const doc = await ResolveDocument(api, raw.entity, { applicationId, restricted: scope.restricted }, raw.target);
|
|
24
|
+
const body = {};
|
|
25
|
+
for (const [key, value] of Object.entries(doc)) {
|
|
26
|
+
if (!OMITTED_FIELDS.includes(key))
|
|
27
|
+
body[key] = value;
|
|
28
|
+
}
|
|
29
|
+
return Text({ status: 'ok', entity: raw.entity, body });
|
|
30
|
+
}
|
|
31
|
+
catch (e) {
|
|
32
|
+
return ErrorResult(e);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=get-entity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-entity.js","sourceRoot":"","sources":["../../src/tools/get-entity.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAClE,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAC3E,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEjD,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9B,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC;IAC5B,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACpC,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACtC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,0DAA0D,CAAC;CAC/F,CAAC,CAAC;AAEH,MAAM,cAAc,GAAG,CAAC,KAAK,CAAC,CAAC;AAE/B,MAAM,UAAU,iBAAiB,CAAC,MAAiB,EAAE,GAAa,EAAE,KAAe;IACjF,MAAM,CAAC,YAAY,CACjB,kBAAkB,EAClB;QACE,WAAW,EAAE,kVAAkV;QAC/V,WAAW,EAAE,cAAc,CAAC,KAAK;QACjC,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE;KACvG,EACD,KAAK,EAAE,GAAG,EAAE,EAAE;QACZ,IAAI,CAAC;YACH,MAAM,aAAa,GAAG,GAAG,CAAC,MAAM,KAAK,aAAa;gBAChD,CAAC,CAAC,MAAM,oBAAoB,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC;gBAC7C,CAAC,CAAC,MAAM,oBAAoB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;YACzC,MAAM,KAAK,CAAC,aAAa,CAAC,aAAa,CAAC,CAAC;YACzC,MAAM,GAAG,GAAG,MAAM,eAAe,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,EAAE,EAAE,aAAa,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;YAChH,MAAM,IAAI,GAA4B,EAAE,CAAC;YACzC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC/C,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,GAAG,CAAC;oBAAE,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;YACvD,CAAC;YACD,OAAO,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1D,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO,WAAW,CAAC,CAAC,CAAC,CAAC;QACxB,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { RequireApplicationId } from '../resolve.js';
|
|
3
|
+
import { FindPage } from '../entity-read.js';
|
|
4
|
+
import { Text, ErrorResult } from '../result.js';
|
|
5
|
+
const EXCERPT_LIMIT = 160;
|
|
6
|
+
function Excerpt(value) {
|
|
7
|
+
const text = value?.model?.text;
|
|
8
|
+
if (typeof text !== 'string')
|
|
9
|
+
return null;
|
|
10
|
+
const plain = text.replace(/<style[\s\S]*?<\/style>/gi, '').replace(/<[^>]+>/g, ' ').replace(/\s+/g, ' ').trim();
|
|
11
|
+
return plain.length > EXCERPT_LIMIT ? `${plain.slice(0, EXCERPT_LIMIT)}…` : plain;
|
|
12
|
+
}
|
|
13
|
+
function FullText(value) {
|
|
14
|
+
const text = value?.model?.text;
|
|
15
|
+
return typeof text === 'string' ? text : null;
|
|
16
|
+
}
|
|
17
|
+
export function RegisterGetPage(server, api, scope) {
|
|
18
|
+
server.registerTool('get_elwis_page', {
|
|
19
|
+
title: 'Get one ELWIS page structure',
|
|
20
|
+
description: 'Get the structure of one page: sections with their styles, rows with column layouts, and every widget with its id, code, and a short text excerpt. Section, row, and column numbers are 1-based counted from the top. Use this BEFORE update_elwis_page to find which section or widget the user means ("the header" is usually section 1, "the footer" the last section) and to get the widget ids that widgetTexts requires. The excerpt identifies a widget but is NOT its content: before editing a widget\'s text, call again with fullTextWidgets set to that widget id and modify the returned fullText, never regenerate a widget from the excerpt.',
|
|
21
|
+
inputSchema: {
|
|
22
|
+
applicationId: z.string().optional(),
|
|
23
|
+
applicationName: z.string().optional(),
|
|
24
|
+
page: z.string().describe('Page name, alias, or 24-char hex id'),
|
|
25
|
+
fullTextWidgets: z.array(z.string()).max(10).optional().describe('Widget ids whose complete HTML content to return as fullText (TEXT widgets only)'),
|
|
26
|
+
},
|
|
27
|
+
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
28
|
+
}, async (raw) => {
|
|
29
|
+
try {
|
|
30
|
+
const applicationId = await RequireApplicationId(api, raw);
|
|
31
|
+
await scope.assertAllowed(applicationId);
|
|
32
|
+
const page = await FindPage(api, applicationId, raw.page);
|
|
33
|
+
const widgetIds = [];
|
|
34
|
+
const sections = (page.sections ?? []).map((s, si) => ({
|
|
35
|
+
section: si + 1,
|
|
36
|
+
styles: s.styles ?? {},
|
|
37
|
+
rows: (s.rows ?? []).map((r, ri) => ({
|
|
38
|
+
row: ri + 1,
|
|
39
|
+
layout: r.layout,
|
|
40
|
+
columns: (r.blocks ?? []).map((b, bi) => ({
|
|
41
|
+
column: bi + 1,
|
|
42
|
+
widgets: (b.parts ?? [])
|
|
43
|
+
.filter((p) => typeof p.widget?.widgetId === 'string' && p.widget.widgetId.length > 0)
|
|
44
|
+
.map((p) => {
|
|
45
|
+
widgetIds.push(p.widget.widgetId);
|
|
46
|
+
return { widgetId: p.widget.widgetId };
|
|
47
|
+
}),
|
|
48
|
+
})),
|
|
49
|
+
})),
|
|
50
|
+
}));
|
|
51
|
+
const unique = [...new Set(widgetIds)];
|
|
52
|
+
const wantFull = new Set(raw.fullTextWidgets ?? []);
|
|
53
|
+
const docs = new Map();
|
|
54
|
+
const rows = unique.length ? await api.list('widget', { _id: { $in: unique.map(id => ({ $oid: id })) } }, unique.length + 1) : [];
|
|
55
|
+
for (const w of rows) {
|
|
56
|
+
docs.set(String(w.id), {
|
|
57
|
+
code: w.code,
|
|
58
|
+
excerpt: Excerpt(w.value),
|
|
59
|
+
...(wantFull.has(String(w.id)) ? { fullText: FullText(w.value) } : {}),
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
for (const s of sections)
|
|
63
|
+
for (const r of s.rows)
|
|
64
|
+
for (const c of r.columns)
|
|
65
|
+
for (const w of c.widgets) {
|
|
66
|
+
Object.assign(w, docs.get(String(w.widgetId)) ?? { code: 'UNKNOWN', excerpt: null });
|
|
67
|
+
}
|
|
68
|
+
return Text({ status: 'ok', id: page.id, name: page.name, alias: page.alias ?? null, isPublic: page.isPublic ?? false, sections });
|
|
69
|
+
}
|
|
70
|
+
catch (e) {
|
|
71
|
+
return ErrorResult(e);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=get-page.js.map
|