-
Notifications
You must be signed in to change notification settings - Fork 137
Expand file tree
/
Copy pathgetStoryboardXml.ts
More file actions
106 lines (97 loc) · 3.96 KB
/
Copy pathgetStoryboardXml.ts
File metadata and controls
106 lines (97 loc) · 3.96 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
import { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
import { resolveItemByNameOrId } from '../../../desktop/externalApi/toolUtils.js';
import { parseXML } from '../../../desktop/metadata/parser.js';
import { runExternalApiReadTool } from '../../../desktop/wrappers/readHarness.js';
import { UnknownError } from '../../../errors/mcpToolError.js';
import { DesktopMcpServer } from '../../../server.desktop.js';
import { artifactNameParam, sessionParam, xmlModeParam } from '../params.js';
import { DesktopTool } from '../tool.js';
import { finishXmlRead, XmlReadFileResult } from './xmlReadResult.js';
const paramsSchema = {
session: sessionParam(),
storyboardName: artifactNameParam('storyboard'),
mode: xmlModeParam(),
};
const title = 'Get Storyboard Document';
type InlineResult = { storyboardXml: string };
type GetStoryboardXmlToolResult = ({ message: string } & InlineResult) | XmlReadFileResult;
export const getStoryboardXmlTool = (
server: DesktopMcpServer,
): DesktopTool<typeof paramsSchema> => {
const getStoryboardXml = new DesktopTool({
server,
name: 'get-storyboard-xml',
title,
description: 'Get structure for an existing storyboard.',
paramsSchema,
annotations: {
readOnlyHint: false, // Writes to a cache file
destructiveHint: false,
idempotentHint: false,
openWorldHint: false,
},
callback: async ({ session, storyboardName, mode }, extra): Promise<CallToolResult> => {
return await getStoryboardXml.logAndExecute<GetStoryboardXmlToolResult>({
extra,
args: { session, storyboardName, mode },
callback: async () => {
return await runExternalApiReadTool({
session,
extra,
callback: async (_executor, _signal, read, resolvedSession) => {
// A storyboard serializes as a `<dashboard type='storyboard'>`, and its
// `/document` route returns that bare fragment directly. Resolve the name
// to an id, then fetch the document.
const listResult = await read(
'storyboard list',
async (executor, signal) => await executor.listStoryboards(signal),
);
if (listResult.isErr()) {
return listResult;
}
const storyboardResult = resolveItemByNameOrId(
'Storyboard',
storyboardName,
listResult.value.storyboards ?? [],
);
if (storyboardResult.isErr()) {
return storyboardResult.error.toErr();
}
const resolved = storyboardResult.value;
const documentResult = await read(
'storyboard document',
async (executor, signal) =>
await executor.getStoryboardDocument(resolved.id, signal),
);
if (documentResult.isErr()) {
return documentResult;
}
const storyboardXml = documentResult.value.xml;
if (!parseXML(storyboardXml).dashboard) {
return new UnknownError(
`No storyboard document subtree found for "${storyboardName}".`,
).toErr();
}
return finishXmlRead({
kind: 'storyboard',
// A storyboard has no dedicated ArtifactKind; it shares the dashboard summary shape.
artifactKind: 'dashboard',
label: `Storyboard "${resolved.name}"`,
inlineKey: 'storyboardXml',
toolName: 'get-storyboard-xml',
applyTool: 'apply-storyboard',
pathParam: 'storyboardFile',
cacheName: resolved.name,
xml: storyboardXml,
mode,
capBytes: extra.config.inlineXmlMaxBytes,
resolvedSession,
});
},
});
},
});
},
});
return getStoryboardXml;
};