@unraid-toolkit/mcp 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.
Files changed (95) hide show
  1. package/LICENSE +21 -0
  2. package/dist/.tsbuildinfo +1 -0
  3. package/dist/approval.d.ts +72 -0
  4. package/dist/approval.d.ts.map +1 -0
  5. package/dist/approval.js +106 -0
  6. package/dist/approval.js.map +1 -0
  7. package/dist/audit.d.ts +41 -0
  8. package/dist/audit.d.ts.map +1 -0
  9. package/dist/audit.js +38 -0
  10. package/dist/audit.js.map +1 -0
  11. package/dist/config.d.ts +38 -0
  12. package/dist/config.d.ts.map +1 -0
  13. package/dist/config.js +88 -0
  14. package/dist/config.js.map +1 -0
  15. package/dist/format.d.ts +14 -0
  16. package/dist/format.d.ts.map +1 -0
  17. package/dist/format.js +15 -0
  18. package/dist/format.js.map +1 -0
  19. package/dist/index.d.ts +12 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +72 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/log.d.ts +17 -0
  24. package/dist/log.d.ts.map +1 -0
  25. package/dist/log.js +36 -0
  26. package/dist/log.js.map +1 -0
  27. package/dist/server.d.ts +25 -0
  28. package/dist/server.d.ts.map +1 -0
  29. package/dist/server.js +16 -0
  30. package/dist/server.js.map +1 -0
  31. package/dist/tools/annotations.d.ts +38 -0
  32. package/dist/tools/annotations.d.ts.map +1 -0
  33. package/dist/tools/annotations.js +38 -0
  34. package/dist/tools/annotations.js.map +1 -0
  35. package/dist/tools/array.d.ts +10 -0
  36. package/dist/tools/array.d.ts.map +1 -0
  37. package/dist/tools/array.js +145 -0
  38. package/dist/tools/array.js.map +1 -0
  39. package/dist/tools/confirm.d.ts +14 -0
  40. package/dist/tools/confirm.d.ts.map +1 -0
  41. package/dist/tools/confirm.js +17 -0
  42. package/dist/tools/confirm.js.map +1 -0
  43. package/dist/tools/destructive.d.ts +34 -0
  44. package/dist/tools/destructive.d.ts.map +1 -0
  45. package/dist/tools/destructive.js +84 -0
  46. package/dist/tools/destructive.js.map +1 -0
  47. package/dist/tools/disks.d.ts +8 -0
  48. package/dist/tools/disks.d.ts.map +1 -0
  49. package/dist/tools/disks.js +17 -0
  50. package/dist/tools/disks.js.map +1 -0
  51. package/dist/tools/docker.d.ts +8 -0
  52. package/dist/tools/docker.d.ts.map +1 -0
  53. package/dist/tools/docker.js +105 -0
  54. package/dist/tools/docker.js.map +1 -0
  55. package/dist/tools/index.d.ts +9 -0
  56. package/dist/tools/index.d.ts.map +1 -0
  57. package/dist/tools/index.js +24 -0
  58. package/dist/tools/index.js.map +1 -0
  59. package/dist/tools/notifications.d.ts +8 -0
  60. package/dist/tools/notifications.d.ts.map +1 -0
  61. package/dist/tools/notifications.js +60 -0
  62. package/dist/tools/notifications.js.map +1 -0
  63. package/dist/tools/pagination.d.ts +14 -0
  64. package/dist/tools/pagination.d.ts.map +1 -0
  65. package/dist/tools/pagination.js +14 -0
  66. package/dist/tools/pagination.js.map +1 -0
  67. package/dist/tools/policy.d.ts +39 -0
  68. package/dist/tools/policy.d.ts.map +1 -0
  69. package/dist/tools/policy.js +72 -0
  70. package/dist/tools/policy.js.map +1 -0
  71. package/dist/tools/shares.d.ts +8 -0
  72. package/dist/tools/shares.d.ts.map +1 -0
  73. package/dist/tools/shares.js +17 -0
  74. package/dist/tools/shares.js.map +1 -0
  75. package/dist/tools/system.d.ts +9 -0
  76. package/dist/tools/system.d.ts.map +1 -0
  77. package/dist/tools/system.js +37 -0
  78. package/dist/tools/system.js.map +1 -0
  79. package/dist/tools/ups.d.ts +8 -0
  80. package/dist/tools/ups.d.ts.map +1 -0
  81. package/dist/tools/ups.js +17 -0
  82. package/dist/tools/ups.js.map +1 -0
  83. package/dist/tools/vm.d.ts +10 -0
  84. package/dist/tools/vm.d.ts.map +1 -0
  85. package/dist/tools/vm.js +64 -0
  86. package/dist/tools/vm.js.map +1 -0
  87. package/dist/transports/http.d.ts +18 -0
  88. package/dist/transports/http.d.ts.map +1 -0
  89. package/dist/transports/http.js +92 -0
  90. package/dist/transports/http.js.map +1 -0
  91. package/dist/transports/stdio.d.ts +10 -0
  92. package/dist/transports/stdio.d.ts.map +1 -0
  93. package/dist/transports/stdio.js +13 -0
  94. package/dist/transports/stdio.js.map +1 -0
  95. package/package.json +34 -0
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Shared MCP input fragment for the confirmation-token gate.
3
+ *
4
+ * Destructive tools accept an optional `confirm_token`. On a client without
5
+ * elicitation, the first call returns a token; the caller re-invokes with it to
6
+ * proceed. Elicitation-capable clients ignore this field (approval happens
7
+ * interactively).
8
+ */
9
+ import { z } from 'zod';
10
+ /** Adds the optional `confirm_token` field to a destructive tool's input. */
11
+ export const CONFIRM_TOKEN_INPUT = {
12
+ confirm_token: z
13
+ .string()
14
+ .optional()
15
+ .describe('Confirmation token from a prior call (token-gate fallback for clients without elicitation). Omit on the first call; re-invoke with the returned token to approve.'),
16
+ };
17
+ //# sourceMappingURL=confirm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"confirm.js","sourceRoot":"","sources":["../../src/tools/confirm.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,6EAA6E;AAC7E,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,aAAa,EAAE,CAAC;SACb,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CACP,mKAAmK,CACpK;CACJ,CAAC"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Orchestrates a destructive (Phase 3) MCP tool call through both safety layers
3
+ * and the audit log, so individual tools stay declarative.
4
+ *
5
+ * Flow per call:
6
+ * 1. Layer 1 (policy floor): read-only, deny-list, blast-radius — refuse hard.
7
+ * 2. Layer 2 (approval): elicitation when supported, else a token gate bound to
8
+ * the enumerated target set (confused-deputy guard).
9
+ * 3. On approval, run the SDK op and format its envelope.
10
+ * 4. Every branch writes an audit entry.
11
+ */
12
+ import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
13
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
14
+ import type { UnraidResult } from '@unraid-toolkit/sdk';
15
+ import type { ServerContext } from '../server.js';
16
+ /** Spec for a single destructive operation invocation. */
17
+ export interface DestructiveCall<T> {
18
+ /** The MCP tool name (binds audit + approval token). */
19
+ readonly tool: string;
20
+ /** Human sentence describing the impact, e.g. "Stop the array". */
21
+ readonly summary: string;
22
+ /** Enumerated targets the op affects (ids/names); drives caps, deny, hashing. */
23
+ readonly targets: readonly string[];
24
+ /** Caller-supplied confirmation token from a prior call, if any. */
25
+ readonly token?: string | undefined;
26
+ /** The SDK operation to run once approved. */
27
+ readonly run: () => Promise<UnraidResult<T>>;
28
+ }
29
+ /**
30
+ * Run a destructive operation through Layer 1 → Layer 2 → execute, auditing
31
+ * each outcome. Tools call this instead of touching the SDK directly.
32
+ */
33
+ export declare function runDestructive<T>(server: McpServer, ctx: ServerContext, call: DestructiveCall<T>): Promise<CallToolResult>;
34
+ //# sourceMappingURL=destructive.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"destructive.d.ts","sourceRoot":"","sources":["../../src/tools/destructive.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAIxD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD,0DAA0D;AAC1D,MAAM,WAAW,eAAe,CAAC,CAAC;IAChC,wDAAwD;IACxD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,mEAAmE;IACnE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,iFAAiF;IACjF,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,oEAAoE;IACpE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,8CAA8C;IAC9C,QAAQ,CAAC,GAAG,EAAE,MAAM,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;CAC9C;AAWD;;;GAGG;AACH,wBAAsB,cAAc,CAAC,CAAC,EACpC,MAAM,EAAE,SAAS,EACjB,GAAG,EAAE,aAAa,EAClB,IAAI,EAAE,eAAe,CAAC,CAAC,CAAC,GACvB,OAAO,CAAC,cAAc,CAAC,CA6DzB"}
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Orchestrates a destructive (Phase 3) MCP tool call through both safety layers
3
+ * and the audit log, so individual tools stay declarative.
4
+ *
5
+ * Flow per call:
6
+ * 1. Layer 1 (policy floor): read-only, deny-list, blast-radius — refuse hard.
7
+ * 2. Layer 2 (approval): elicitation when supported, else a token gate bound to
8
+ * the enumerated target set (confused-deputy guard).
9
+ * 3. On approval, run the SDK op and format its envelope.
10
+ * 4. Every branch writes an audit entry.
11
+ */
12
+ import { formatResult } from '../format.js';
13
+ import { layer1Block } from './policy.js';
14
+ import { resolveApproval } from '../approval.js';
15
+ /** Build a structured refusal `CallToolResult` (SDK envelope shape). */
16
+ function refusal(code, message) {
17
+ const envelope = { success: false, data: null, error: { code, message } };
18
+ return {
19
+ content: [{ type: 'text', text: JSON.stringify(envelope, null, 2) }],
20
+ isError: true,
21
+ };
22
+ }
23
+ /**
24
+ * Run a destructive operation through Layer 1 → Layer 2 → execute, auditing
25
+ * each outcome. Tools call this instead of touching the SDK directly.
26
+ */
27
+ export async function runDestructive(server, ctx, call) {
28
+ const stamp = () => new Date().toISOString();
29
+ // Layer 1 — policy floor.
30
+ const blocked = layer1Block(ctx, call.targets);
31
+ if (blocked) {
32
+ const detail = blocked.content[0];
33
+ await ctx.audit.record({
34
+ timestamp: stamp(),
35
+ tool: call.tool,
36
+ targets: call.targets,
37
+ approval: 'none',
38
+ outcome: 'refused',
39
+ detail: detail && 'text' in detail ? detail.text : 'policy refusal',
40
+ });
41
+ return blocked;
42
+ }
43
+ // Layer 2 — approval.
44
+ const decision = await resolveApproval(server, ctx.tokens, {
45
+ tool: call.tool,
46
+ summary: call.summary,
47
+ targets: call.targets,
48
+ token: call.token,
49
+ });
50
+ if (decision.status === 'declined') {
51
+ await ctx.audit.record({
52
+ timestamp: stamp(),
53
+ tool: call.tool,
54
+ targets: call.targets,
55
+ approval: 'elicitation',
56
+ outcome: 'refused',
57
+ detail: decision.reason,
58
+ });
59
+ return refusal('APPROVAL_DECLINED', decision.reason);
60
+ }
61
+ if (decision.status === 'needs-token') {
62
+ await ctx.audit.record({
63
+ timestamp: stamp(),
64
+ tool: call.tool,
65
+ targets: call.targets,
66
+ approval: 'token',
67
+ outcome: 'refused',
68
+ detail: 'confirmation token issued; awaiting re-invocation',
69
+ });
70
+ return refusal('CONFIRMATION_REQUIRED', decision.message);
71
+ }
72
+ // Approved — execute.
73
+ const result = await call.run();
74
+ await ctx.audit.record({
75
+ timestamp: stamp(),
76
+ tool: call.tool,
77
+ targets: call.targets,
78
+ approval: decision.source,
79
+ outcome: result.success ? 'succeeded' : 'failed',
80
+ ...(result.success ? {} : { detail: result.error.message }),
81
+ });
82
+ return formatResult(result);
83
+ }
84
+ //# sourceMappingURL=destructive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"destructive.js","sourceRoot":"","sources":["../../src/tools/destructive.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Disk tools. Thin adapter over the SDK disk operations.
3
+ */
4
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
5
+ import type { ServerContext } from '../server.js';
6
+ /** Register disk tools on the given server. */
7
+ export declare function registerDiskTools(server: McpServer, ctx: ServerContext): void;
8
+ //# sourceMappingURL=disks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"disks.d.ts","sourceRoot":"","sources":["../../src/tools/disks.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAKzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD,+CAA+C;AAC/C,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,aAAa,GAAG,IAAI,CAW7E"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Disk tools. Thin adapter over the SDK disk operations.
3
+ */
4
+ import { listDisks } from '@unraid-toolkit/sdk';
5
+ import { formatResult } from '../format.js';
6
+ import { READ_ONLY_ANNOTATIONS } from './annotations.js';
7
+ import { PAGINATION_INPUT } from './pagination.js';
8
+ /** Register disk tools on the given server. */
9
+ export function registerDiskTools(server, ctx) {
10
+ server.registerTool('unraid_list_disks', {
11
+ title: 'List Unraid Physical Disks',
12
+ description: `List the physical disks attached to the server: device path, model/vendor, size (bytes), interface (SATA/SAS/NVMe/USB), SMART status, temperature, and spin state. Use limit/offset to page.`,
13
+ inputSchema: { ...PAGINATION_INPUT },
14
+ annotations: READ_ONLY_ANNOTATIONS,
15
+ }, async ({ limit, offset }) => formatResult(await listDisks(ctx.client, { limit, offset })));
16
+ }
17
+ //# sourceMappingURL=disks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"disks.js","sourceRoot":"","sources":["../../src/tools/disks.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAGnD,+CAA+C;AAC/C,MAAM,UAAU,iBAAiB,CAAC,MAAiB,EAAE,GAAkB;IACrE,MAAM,CAAC,YAAY,CACjB,mBAAmB,EACnB;QACE,KAAK,EAAE,4BAA4B;QACnC,WAAW,EAAE,8LAA8L;QAC3M,WAAW,EAAE,EAAE,GAAG,gBAAgB,EAAE;QACpC,WAAW,EAAE,qBAAqB;KACnC,EACD,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,YAAY,CAAC,MAAM,SAAS,CAAC,GAAG,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,CAC1F,CAAC;AACJ,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Docker tools. Thin adapters over the SDK Docker operations.
3
+ */
4
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
5
+ import type { ServerContext } from '../server.js';
6
+ /** Register Docker tools on the given server. */
7
+ export declare function registerDockerTools(server: McpServer, ctx: ServerContext): void;
8
+ //# sourceMappingURL=docker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docker.d.ts","sourceRoot":"","sources":["../../src/tools/docker.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA2BzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAoClD,iDAAiD;AACjD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,aAAa,GAAG,IAAI,CAoG/E"}
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Docker tools. Thin adapters over the SDK Docker operations.
3
+ */
4
+ import { z } from 'zod';
5
+ import { listContainers, getContainer, getContainerLogs, getUpdateStatuses, startContainer, stopContainer, pauseContainer, unpauseContainer, updateContainer, updateAllContainers, removeContainer, } from '@unraid-toolkit/sdk';
6
+ import { formatResult } from '../format.js';
7
+ import { READ_ONLY_ANNOTATIONS, SAFE_WRITE_ANNOTATIONS, DESTRUCTIVE_ANNOTATIONS, } from './annotations.js';
8
+ import { PAGINATION_INPUT } from './pagination.js';
9
+ import { CONFIRM_TOKEN_INPUT } from './confirm.js';
10
+ import { readOnlyBlock } from './policy.js';
11
+ import { runDestructive } from './destructive.js';
12
+ /** Phase 2 single-container lifecycle controls, each a `(client, id)` op. */
13
+ const CONTAINER_ACTIONS = [
14
+ {
15
+ tool: 'unraid_docker_start',
16
+ title: 'Start Unraid Container',
17
+ verb: 'Start',
18
+ op: startContainer,
19
+ },
20
+ { tool: 'unraid_docker_stop', title: 'Stop Unraid Container', verb: 'Stop', op: stopContainer },
21
+ {
22
+ tool: 'unraid_docker_pause',
23
+ title: 'Pause Unraid Container',
24
+ verb: 'Pause (suspend)',
25
+ op: pauseContainer,
26
+ },
27
+ {
28
+ tool: 'unraid_docker_unpause',
29
+ title: 'Unpause Unraid Container',
30
+ verb: 'Unpause (resume)',
31
+ op: unpauseContainer,
32
+ },
33
+ {
34
+ tool: 'unraid_docker_update',
35
+ title: 'Update Unraid Container',
36
+ verb: 'Pull the latest image for and recreate',
37
+ op: updateContainer,
38
+ },
39
+ ];
40
+ /** Register Docker tools on the given server. */
41
+ export function registerDockerTools(server, ctx) {
42
+ server.registerTool('unraid_list_containers', {
43
+ title: 'List Unraid Docker Containers',
44
+ description: `List Docker containers with name, image, state (running/exited/paused), status text, autostart settings, update availability, and published ports. Use limit/offset to page.`,
45
+ inputSchema: { ...PAGINATION_INPUT },
46
+ annotations: READ_ONLY_ANNOTATIONS,
47
+ }, async ({ limit, offset }) => formatResult(await listContainers(ctx.client, { limit, offset })));
48
+ server.registerTool('unraid_get_container', {
49
+ title: 'Get Unraid Docker Container',
50
+ description: `Get detailed information about a single Docker container by id, including image, command, sizes, network mode, ports, autostart, template path, and WebUI/support URLs. Fails with NOT_FOUND if no container has that id.`,
51
+ inputSchema: { id: z.string().describe('The container id (PrefixedID)') },
52
+ annotations: READ_ONLY_ANNOTATIONS,
53
+ }, async ({ id }) => formatResult(await getContainer(ctx.client, id)));
54
+ server.registerTool('unraid_container_logs', {
55
+ title: 'Get Unraid Docker Container Logs',
56
+ description: `Fetch recent log lines for a container. Use 'tail' to limit to the last N lines and 'since' (ISO timestamp or cursor) to resume. Output is size-capped; 'truncated' indicates older lines were dropped to fit.`,
57
+ inputSchema: {
58
+ id: z.string().describe('The container id (PrefixedID)'),
59
+ tail: z.number().int().optional().describe('Return only the last N lines'),
60
+ since: z
61
+ .string()
62
+ .optional()
63
+ .describe('Only return lines after this ISO timestamp / cursor'),
64
+ },
65
+ annotations: READ_ONLY_ANNOTATIONS,
66
+ }, async ({ id, tail, since }) => formatResult(await getContainerLogs(ctx.client, { id, tail, since })));
67
+ server.registerTool('unraid_container_update_statuses', {
68
+ title: 'Get Unraid Container Update Statuses',
69
+ description: `Report per-container update availability (UP_TO_DATE / UPDATE_AVAILABLE / REBUILD_READY / UNKNOWN). Use limit/offset to page.`,
70
+ inputSchema: { ...PAGINATION_INPUT },
71
+ annotations: READ_ONLY_ANNOTATIONS,
72
+ }, async ({ limit, offset }) => formatResult(await getUpdateStatuses(ctx.client, { limit, offset })));
73
+ for (const { tool, title, verb, op } of CONTAINER_ACTIONS) {
74
+ server.registerTool(tool, {
75
+ title,
76
+ description: `${verb} the Docker container with the given id. Returns the container's resulting state.`,
77
+ inputSchema: { id: z.string().describe('The container id (PrefixedID)') },
78
+ annotations: SAFE_WRITE_ANNOTATIONS,
79
+ }, async ({ id }) => readOnlyBlock(ctx) ?? formatResult(await op(ctx.client, id)));
80
+ }
81
+ server.registerTool('unraid_docker_update_all', {
82
+ title: 'Update All Unraid Containers',
83
+ description: `Update every Docker container that has an available image update. Returns the resulting state of each updated container.`,
84
+ inputSchema: {},
85
+ annotations: SAFE_WRITE_ANNOTATIONS,
86
+ }, async () => readOnlyBlock(ctx) ?? formatResult(await updateAllContainers(ctx.client)));
87
+ // --- Phase 3: destructive container control ---
88
+ server.registerTool('unraid_docker_remove', {
89
+ title: 'Remove Unraid Container',
90
+ description: `Remove a Docker container, optionally deleting its backing image (withImage). Irreversible and destructive — requires human approval.`,
91
+ inputSchema: {
92
+ id: z.string().describe('The container id (PrefixedID)'),
93
+ withImage: z.boolean().optional().describe('Also remove the backing image (default false)'),
94
+ ...CONFIRM_TOKEN_INPUT,
95
+ },
96
+ annotations: DESTRUCTIVE_ANNOTATIONS,
97
+ }, async ({ id, withImage, confirm_token }) => runDestructive(server, ctx, {
98
+ tool: 'unraid_docker_remove',
99
+ summary: `Remove container ${id}${withImage === true ? ' and its image' : ''}`,
100
+ targets: [id],
101
+ token: confirm_token,
102
+ run: () => removeContainer(ctx.client, id, withImage ?? false),
103
+ }));
104
+ }
105
+ //# sourceMappingURL=docker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docker.js","sourceRoot":"","sources":["../../src/tools/docker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Tool registration dispatcher. Each domain has its own `register*Tools`
3
+ * function; this wires them all onto the server.
4
+ */
5
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
6
+ import type { ServerContext } from '../server.js';
7
+ /** Register every tool group on the given server. */
8
+ export declare function registerAllTools(server: McpServer, ctx: ServerContext): void;
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAUlD,qDAAqD;AACrD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,aAAa,GAAG,IAAI,CAS5E"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Tool registration dispatcher. Each domain has its own `register*Tools`
3
+ * function; this wires them all onto the server.
4
+ */
5
+ import { registerSystemTools } from './system.js';
6
+ import { registerArrayTools } from './array.js';
7
+ import { registerDiskTools } from './disks.js';
8
+ import { registerDockerTools } from './docker.js';
9
+ import { registerVmTools } from './vm.js';
10
+ import { registerShareTools } from './shares.js';
11
+ import { registerNotificationTools } from './notifications.js';
12
+ import { registerUpsTools } from './ups.js';
13
+ /** Register every tool group on the given server. */
14
+ export function registerAllTools(server, ctx) {
15
+ registerSystemTools(server, ctx);
16
+ registerArrayTools(server, ctx);
17
+ registerDiskTools(server, ctx);
18
+ registerDockerTools(server, ctx);
19
+ registerVmTools(server, ctx);
20
+ registerShareTools(server, ctx);
21
+ registerNotificationTools(server, ctx);
22
+ registerUpsTools(server, ctx);
23
+ }
24
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC1C,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAE5C,qDAAqD;AACrD,MAAM,UAAU,gBAAgB,CAAC,MAAiB,EAAE,GAAkB;IACpE,mBAAmB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACjC,kBAAkB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAChC,iBAAiB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC/B,mBAAmB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACjC,eAAe,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC7B,kBAAkB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAChC,yBAAyB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACvC,gBAAgB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AAChC,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Notification tools. Thin adapters over the SDK notification operations.
3
+ */
4
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
5
+ import type { ServerContext } from '../server.js';
6
+ /** Register notification tools on the given server. */
7
+ export declare function registerNotificationTools(server: McpServer, ctx: ServerContext): void;
8
+ //# sourceMappingURL=notifications.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notifications.d.ts","sourceRoot":"","sources":["../../src/tools/notifications.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAYzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD,uDAAuD;AACvD,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,aAAa,GAAG,IAAI,CA6ErF"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Notification tools. Thin adapters over the SDK notification operations.
3
+ */
4
+ import { z } from 'zod';
5
+ import { listNotifications, getNotificationOverview, createNotification, archiveNotification, unarchiveNotification, } from '@unraid-toolkit/sdk';
6
+ import { formatResult } from '../format.js';
7
+ import { READ_ONLY_ANNOTATIONS, SAFE_WRITE_ANNOTATIONS } from './annotations.js';
8
+ import { PAGINATION_INPUT } from './pagination.js';
9
+ import { readOnlyBlock } from './policy.js';
10
+ /** Register notification tools on the given server. */
11
+ export function registerNotificationTools(server, ctx) {
12
+ server.registerTool('unraid_list_notifications', {
13
+ title: 'List Unraid Notifications',
14
+ description: `List notifications filtered by queue ('UNREAD' default, or 'ARCHIVE') and optional severity ('INFO'/'WARNING'/'ALERT'). Use limit/offset to page. For aggregate counts use unraid_notifications_overview.`,
15
+ inputSchema: {
16
+ type: z
17
+ .enum(['UNREAD', 'ARCHIVE'])
18
+ .optional()
19
+ .describe('Which queue to read (default UNREAD)'),
20
+ importance: z
21
+ .enum(['INFO', 'WARNING', 'ALERT'])
22
+ .optional()
23
+ .describe('Filter to a single severity'),
24
+ ...PAGINATION_INPUT,
25
+ },
26
+ annotations: READ_ONLY_ANNOTATIONS,
27
+ }, async ({ type, importance, limit, offset }) => formatResult(await listNotifications(ctx.client, { type, importance, limit, offset })));
28
+ server.registerTool('unraid_notifications_overview', {
29
+ title: 'Get Unraid Notifications Overview',
30
+ description: `Get unread and archived notification counts broken down by severity (info/warning/alert/total). A fast way to check whether the server needs attention.`,
31
+ inputSchema: {},
32
+ annotations: READ_ONLY_ANNOTATIONS,
33
+ }, async () => formatResult(await getNotificationOverview(ctx.client)));
34
+ server.registerTool('unraid_create_notification', {
35
+ title: 'Create Unraid Notification',
36
+ description: `Create a notification on the server. Requires title, subject, description, and importance (INFO/WARNING/ALERT); link is optional.`,
37
+ inputSchema: {
38
+ title: z.string().describe('Short event title'),
39
+ subject: z.string().describe('Notification subject line'),
40
+ description: z.string().describe('Body text'),
41
+ importance: z.enum(['INFO', 'WARNING', 'ALERT']).describe('Severity'),
42
+ link: z.string().optional().describe('Optional link to more detail'),
43
+ },
44
+ annotations: SAFE_WRITE_ANNOTATIONS,
45
+ }, async ({ title, subject, description, importance, link }) => readOnlyBlock(ctx) ??
46
+ formatResult(await createNotification(ctx.client, { title, subject, description, importance, link })));
47
+ server.registerTool('unraid_archive_notification', {
48
+ title: 'Archive Unraid Notification',
49
+ description: `Archive a single notification by id (moves it out of the unread queue).`,
50
+ inputSchema: { id: z.string().describe('The notification id (PrefixedID)') },
51
+ annotations: SAFE_WRITE_ANNOTATIONS,
52
+ }, async ({ id }) => readOnlyBlock(ctx) ?? formatResult(await archiveNotification(ctx.client, id)));
53
+ server.registerTool('unraid_unarchive_notification', {
54
+ title: 'Unarchive Unraid Notification',
55
+ description: `Unarchive a single notification by id — marks it unread, moving it back to the unread queue.`,
56
+ inputSchema: { id: z.string().describe('The notification id (PrefixedID)') },
57
+ annotations: SAFE_WRITE_ANNOTATIONS,
58
+ }, async ({ id }) => readOnlyBlock(ctx) ?? formatResult(await unarchiveNotification(ctx.client, id)));
59
+ }
60
+ //# sourceMappingURL=notifications.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notifications.js","sourceRoot":"","sources":["../../src/tools/notifications.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Shared MCP input-schema fragment for paginated tools.
3
+ *
4
+ * Wrappers only parse the *shape* of input; semantic validation (positive
5
+ * limit, non-negative offset) is owned by the SDK, which returns a structured
6
+ * `VALIDATION_ERROR` envelope.
7
+ */
8
+ import { z } from 'zod';
9
+ /** Raw-shape fragment adding `limit`/`offset` to a tool's input schema. */
10
+ export declare const PAGINATION_INPUT: {
11
+ limit: z.ZodOptional<z.ZodNumber>;
12
+ offset: z.ZodOptional<z.ZodNumber>;
13
+ };
14
+ //# sourceMappingURL=pagination.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pagination.d.ts","sourceRoot":"","sources":["../../src/tools/pagination.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,2EAA2E;AAC3E,eAAO,MAAM,gBAAgB;;;CAG5B,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Shared MCP input-schema fragment for paginated tools.
3
+ *
4
+ * Wrappers only parse the *shape* of input; semantic validation (positive
5
+ * limit, non-negative offset) is owned by the SDK, which returns a structured
6
+ * `VALIDATION_ERROR` envelope.
7
+ */
8
+ import { z } from 'zod';
9
+ /** Raw-shape fragment adding `limit`/`offset` to a tool's input schema. */
10
+ export const PAGINATION_INPUT = {
11
+ limit: z.number().int().optional().describe('Maximum number of items to return'),
12
+ offset: z.number().int().optional().describe('Number of items to skip from the start'),
13
+ };
14
+ //# sourceMappingURL=pagination.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pagination.js","sourceRoot":"","sources":["../../src/tools/pagination.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,2EAA2E;AAC3E,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,mCAAmC,CAAC;IAChF,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,wCAAwC,CAAC;CACvF,CAAC"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Layer-1 policy floor for control tools (client- and model-independent).
3
+ *
4
+ * These guards run before any SDK call and cannot be bypassed by the LLM or a
5
+ * permissive client:
6
+ * - `MCP_READ_ONLY` disables every mutation.
7
+ * - the deny-list refuses named/patterned targets (e.g. protect `*-appdata`).
8
+ * - the blast-radius cap refuses batches larger than `MCP_MAX_BATCH`.
9
+ * - an audit log records every attempted mutation and its outcome.
10
+ *
11
+ * Each guard returns a refusal `CallToolResult` (so the caller can `?? proceed`)
12
+ * or `null` to allow the operation.
13
+ */
14
+ import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
15
+ import type { ServerContext } from '../server.js';
16
+ /**
17
+ * If the server is in read-only mode, return a refusal `CallToolResult`;
18
+ * otherwise return `null` so the caller proceeds with the mutation.
19
+ *
20
+ * Usage: `return readOnlyBlock(ctx) ?? formatResult(await op(...));`
21
+ */
22
+ export declare function readOnlyBlock(ctx: ServerContext): CallToolResult | null;
23
+ /**
24
+ * Refuse if any of `targets` matches the configured deny-list
25
+ * (`MCP_DENY_TOOLS`, reused here as protected resource patterns). Returns `null`
26
+ * when all targets are allowed.
27
+ */
28
+ export declare function denyListBlock(ctx: ServerContext, targets: readonly string[]): CallToolResult | null;
29
+ /**
30
+ * Refuse if a destructive batch affects more than `MCP_MAX_BATCH` items,
31
+ * regardless of approval. Returns `null` when within the cap.
32
+ */
33
+ export declare function blastRadiusBlock(ctx: ServerContext, count: number): CallToolResult | null;
34
+ /**
35
+ * Run all Layer-1 guards for a destructive operation in order: read-only, then
36
+ * deny-list, then blast-radius. Returns the first refusal, or `null` to proceed.
37
+ */
38
+ export declare function layer1Block(ctx: ServerContext, targets: readonly string[]): CallToolResult | null;
39
+ //# sourceMappingURL=policy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../../src/tools/policy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAWlD;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,aAAa,GAAG,cAAc,GAAG,IAAI,CAMvE;AAYD;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,GAAG,EAAE,aAAa,EAClB,OAAO,EAAE,SAAS,MAAM,EAAE,GACzB,cAAc,GAAG,IAAI,CAWvB;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAMzF;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,aAAa,EAAE,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,cAAc,GAAG,IAAI,CAEjG"}
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Layer-1 policy floor for control tools (client- and model-independent).
3
+ *
4
+ * These guards run before any SDK call and cannot be bypassed by the LLM or a
5
+ * permissive client:
6
+ * - `MCP_READ_ONLY` disables every mutation.
7
+ * - the deny-list refuses named/patterned targets (e.g. protect `*-appdata`).
8
+ * - the blast-radius cap refuses batches larger than `MCP_MAX_BATCH`.
9
+ * - an audit log records every attempted mutation and its outcome.
10
+ *
11
+ * Each guard returns a refusal `CallToolResult` (so the caller can `?? proceed`)
12
+ * or `null` to allow the operation.
13
+ */
14
+ /** Build a failure envelope `CallToolResult` mirroring the SDK error shape. */
15
+ function refusal(code, message) {
16
+ const envelope = { success: false, data: null, error: { code, message } };
17
+ return {
18
+ content: [{ type: 'text', text: JSON.stringify(envelope, null, 2) }],
19
+ isError: true,
20
+ };
21
+ }
22
+ /**
23
+ * If the server is in read-only mode, return a refusal `CallToolResult`;
24
+ * otherwise return `null` so the caller proceeds with the mutation.
25
+ *
26
+ * Usage: `return readOnlyBlock(ctx) ?? formatResult(await op(...));`
27
+ */
28
+ export function readOnlyBlock(ctx) {
29
+ if (!ctx.config.readOnly)
30
+ return null;
31
+ return refusal('READ_ONLY', 'Server is in read-only mode (MCP_READ_ONLY); control operations are disabled. Unset MCP_READ_ONLY to enable writes.');
32
+ }
33
+ /**
34
+ * Convert a deny-list entry to a matcher. An entry is a literal string, or a
35
+ * glob using `*` (matched case-insensitively against the whole target).
36
+ */
37
+ function denyMatches(pattern, target) {
38
+ // Escape regex metacharacters except `*`, then turn `*` into `.*`.
39
+ const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, '\\$&').replace(/\*/g, '.*');
40
+ return new RegExp(`^${escaped}$`, 'i').test(target);
41
+ }
42
+ /**
43
+ * Refuse if any of `targets` matches the configured deny-list
44
+ * (`MCP_DENY_TOOLS`, reused here as protected resource patterns). Returns `null`
45
+ * when all targets are allowed.
46
+ */
47
+ export function denyListBlock(ctx, targets) {
48
+ const patterns = ctx.config.denyTools;
49
+ if (patterns.length === 0)
50
+ return null;
51
+ const blocked = targets.filter((t) => patterns.some((p) => denyMatches(p, t)));
52
+ if (blocked.length === 0)
53
+ return null;
54
+ return refusal('DENIED', `Target(s) ${blocked.map((t) => `"${t}"`).join(', ')} are protected by the deny-list (MCP_DENY_TOOLS) and cannot be modified.`);
55
+ }
56
+ /**
57
+ * Refuse if a destructive batch affects more than `MCP_MAX_BATCH` items,
58
+ * regardless of approval. Returns `null` when within the cap.
59
+ */
60
+ export function blastRadiusBlock(ctx, count) {
61
+ if (count <= ctx.config.maxBatch)
62
+ return null;
63
+ return refusal('BLAST_RADIUS_EXCEEDED', `This operation affects ${String(count)} items, exceeding the blast-radius cap of ${String(ctx.config.maxBatch)} (MCP_MAX_BATCH). Reduce the batch or raise the cap deliberately.`);
64
+ }
65
+ /**
66
+ * Run all Layer-1 guards for a destructive operation in order: read-only, then
67
+ * deny-list, then blast-radius. Returns the first refusal, or `null` to proceed.
68
+ */
69
+ export function layer1Block(ctx, targets) {
70
+ return readOnlyBlock(ctx) ?? denyListBlock(ctx, targets) ?? blastRadiusBlock(ctx, targets.length);
71
+ }
72
+ //# sourceMappingURL=policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy.js","sourceRoot":"","sources":["../../src/tools/policy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,+EAA+E;AAC/E,SAAS,OAAO,CAAC,IAAY,EAAE,OAAe;IAC5C,MAAM,QAAQ,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,CAAC;IAC1E,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;QAC7E,OAAO,EAAE,IAAI;KACd,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,GAAkB;IAC9C,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ;QAAE,OAAO,IAAI,CAAC;IACtC,OAAO,OAAO,CACZ,WAAW,EACX,qHAAqH,CACtH,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,SAAS,WAAW,CAAC,OAAe,EAAE,MAAc;IAClD,mEAAmE;IACnE,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,oBAAoB,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IACnF,OAAO,IAAI,MAAM,CAAC,IAAI,OAAO,GAAG,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AACtD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAC3B,GAAkB,EAClB,OAA0B;IAE1B,MAAM,QAAQ,GAAG,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC;IACtC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAEvC,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/E,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAEtC,OAAO,OAAO,CACZ,QAAQ,EACR,aAAa,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,0EAA0E,CAC/H,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,GAAkB,EAAE,KAAa;IAChE,IAAI,KAAK,IAAI,GAAG,CAAC,MAAM,CAAC,QAAQ;QAAE,OAAO,IAAI,CAAC;IAC9C,OAAO,OAAO,CACZ,uBAAuB,EACvB,0BAA0B,MAAM,CAAC,KAAK,CAAC,6CAA6C,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,mEAAmE,CACnL,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,GAAkB,EAAE,OAA0B;IACxE,OAAO,aAAa,CAAC,GAAG,CAAC,IAAI,aAAa,CAAC,GAAG,EAAE,OAAO,CAAC,IAAI,gBAAgB,CAAC,GAAG,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;AACpG,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * User-share tools. Thin adapter over the SDK share operations.
3
+ */
4
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
5
+ import type { ServerContext } from '../server.js';
6
+ /** Register user-share tools on the given server. */
7
+ export declare function registerShareTools(server: McpServer, ctx: ServerContext): void;
8
+ //# sourceMappingURL=shares.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shares.d.ts","sourceRoot":"","sources":["../../src/tools/shares.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAKzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD,qDAAqD;AACrD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,aAAa,GAAG,IAAI,CAW9E"}