@documonster/mcp 0.8.0-canary.sha.09791dab
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/LICENSE +205 -0
- package/README.md +253 -0
- package/dist/capabilities.d.ts +29 -0
- package/dist/capabilities.d.ts.map +1 -0
- package/dist/capabilities.js +188 -0
- package/dist/capabilities.js.map +1 -0
- package/dist/cli.d.ts +13 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +64 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +65 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +189 -0
- package/dist/config.js.map +1 -0
- package/dist/errors.d.ts +66 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +96 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/sandbox.d.ts +86 -0
- package/dist/sandbox.d.ts.map +1 -0
- package/dist/sandbox.js +224 -0
- package/dist/sandbox.js.map +1 -0
- package/dist/server.d.ts +22 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +66 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/archive-read.d.ts +31 -0
- package/dist/tools/archive-read.d.ts.map +1 -0
- package/dist/tools/archive-read.js +315 -0
- package/dist/tools/archive-read.js.map +1 -0
- package/dist/tools/archive-write.d.ts +9 -0
- package/dist/tools/archive-write.d.ts.map +1 -0
- package/dist/tools/archive-write.js +219 -0
- package/dist/tools/archive-write.js.map +1 -0
- package/dist/tools/chart.d.ts +93 -0
- package/dist/tools/chart.d.ts.map +1 -0
- package/dist/tools/chart.js +263 -0
- package/dist/tools/chart.js.map +1 -0
- package/dist/tools/doc-convert.d.ts +13 -0
- package/dist/tools/doc-convert.d.ts.map +1 -0
- package/dist/tools/doc-convert.js +209 -0
- package/dist/tools/doc-convert.js.map +1 -0
- package/dist/tools/doc-paginate.d.ts +14 -0
- package/dist/tools/doc-paginate.d.ts.map +1 -0
- package/dist/tools/doc-paginate.js +153 -0
- package/dist/tools/doc-paginate.js.map +1 -0
- package/dist/tools/doc-read.d.ts +14 -0
- package/dist/tools/doc-read.d.ts.map +1 -0
- package/dist/tools/doc-read.js +175 -0
- package/dist/tools/doc-read.js.map +1 -0
- package/dist/tools/doc-review.d.ts +17 -0
- package/dist/tools/doc-review.d.ts.map +1 -0
- package/dist/tools/doc-review.js +249 -0
- package/dist/tools/doc-review.js.map +1 -0
- package/dist/tools/doc-search.d.ts +20 -0
- package/dist/tools/doc-search.d.ts.map +1 -0
- package/dist/tools/doc-search.js +268 -0
- package/dist/tools/doc-search.js.map +1 -0
- package/dist/tools/doc-write.d.ts +11 -0
- package/dist/tools/doc-write.d.ts.map +1 -0
- package/dist/tools/doc-write.js +81 -0
- package/dist/tools/doc-write.js.map +1 -0
- package/dist/tools/document.d.ts +74 -0
- package/dist/tools/document.d.ts.map +1 -0
- package/dist/tools/document.js +157 -0
- package/dist/tools/document.js.map +1 -0
- package/dist/tools/form-fill.d.ts +20 -0
- package/dist/tools/form-fill.d.ts.map +1 -0
- package/dist/tools/form-fill.js +270 -0
- package/dist/tools/form-fill.js.map +1 -0
- package/dist/tools/formula-evaluate.d.ts +14 -0
- package/dist/tools/formula-evaluate.d.ts.map +1 -0
- package/dist/tools/formula-evaluate.js +192 -0
- package/dist/tools/formula-evaluate.js.map +1 -0
- package/dist/tools/fs-helpers.d.ts +106 -0
- package/dist/tools/fs-helpers.d.ts.map +1 -0
- package/dist/tools/fs-helpers.js +257 -0
- package/dist/tools/fs-helpers.js.map +1 -0
- package/dist/tools/help.d.ts +227 -0
- package/dist/tools/help.d.ts.map +1 -0
- package/dist/tools/help.js +262 -0
- package/dist/tools/help.js.map +1 -0
- package/dist/tools/index.d.ts +33 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +78 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/inspect.d.ts +14 -0
- package/dist/tools/inspect.d.ts.map +1 -0
- package/dist/tools/inspect.js +463 -0
- package/dist/tools/inspect.js.map +1 -0
- package/dist/tools/pdf-edit.d.ts +26 -0
- package/dist/tools/pdf-edit.d.ts.map +1 -0
- package/dist/tools/pdf-edit.js +390 -0
- package/dist/tools/pdf-edit.js.map +1 -0
- package/dist/tools/result.d.ts +25 -0
- package/dist/tools/result.d.ts.map +1 -0
- package/dist/tools/result.js +43 -0
- package/dist/tools/result.js.map +1 -0
- package/dist/tools/sheet-edit.d.ts +16 -0
- package/dist/tools/sheet-edit.d.ts.map +1 -0
- package/dist/tools/sheet-edit.js +325 -0
- package/dist/tools/sheet-edit.js.map +1 -0
- package/dist/tools/sheet-read.d.ts +10 -0
- package/dist/tools/sheet-read.d.ts.map +1 -0
- package/dist/tools/sheet-read.js +139 -0
- package/dist/tools/sheet-read.js.map +1 -0
- package/dist/tools/sheet-write.d.ts +15 -0
- package/dist/tools/sheet-write.d.ts.map +1 -0
- package/dist/tools/sheet-write.js +290 -0
- package/dist/tools/sheet-write.js.map +1 -0
- package/dist/tools/spreadsheet.d.ts +100 -0
- package/dist/tools/spreadsheet.d.ts.map +1 -0
- package/dist/tools/spreadsheet.js +210 -0
- package/dist/tools/spreadsheet.js.map +1 -0
- package/dist/tools/template.d.ts +18 -0
- package/dist/tools/template.d.ts.map +1 -0
- package/dist/tools/template.js +209 -0
- package/dist/tools/template.js.map +1 -0
- package/dist/tools/types.d.ts +79 -0
- package/dist/tools/types.d.ts.map +1 -0
- package/dist/tools/types.js +18 -0
- package/dist/tools/types.js.map +1 -0
- package/package.json +74 -0
package/dist/errors.js
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error model.
|
|
3
|
+
*
|
|
4
|
+
* A tool error is not a crash — it is a message to the model, and the model
|
|
5
|
+
* will try again based on what it reads. So every error carries a machine
|
|
6
|
+
* `code` plus, wherever we can produce one, a `hint` telling the model what to
|
|
7
|
+
* do differently. Error text quality directly determines retry success rate,
|
|
8
|
+
* which makes this file part of the product rather than plumbing.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* An error that is safe and useful to hand back to a model.
|
|
12
|
+
*
|
|
13
|
+
* Anything thrown that is NOT an `McpToolError` is treated as unclassified and
|
|
14
|
+
* reported as `internal` — so a stack-leaking library error can never be
|
|
15
|
+
* mistaken for a designed, model-facing message.
|
|
16
|
+
*/
|
|
17
|
+
export class McpToolError extends Error {
|
|
18
|
+
name = "McpToolError";
|
|
19
|
+
code;
|
|
20
|
+
hint;
|
|
21
|
+
constructor(code, message, options = {}) {
|
|
22
|
+
super(message, options);
|
|
23
|
+
this.code = code;
|
|
24
|
+
this.hint = options.hint;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Convenience constructors for the codes used most often.
|
|
29
|
+
*
|
|
30
|
+
* Each takes an optional `cause`, because documonster's own errors chain via
|
|
31
|
+
* `{ cause }` and the innermost message is usually the one naming the cell,
|
|
32
|
+
* OOXML part or ZIP entry that actually failed — dropping it would leave the
|
|
33
|
+
* model with a generic message it cannot act on.
|
|
34
|
+
*/
|
|
35
|
+
export const toolError = {
|
|
36
|
+
invalidInput(message, hint, options) {
|
|
37
|
+
return new McpToolError("invalid_input", message, { hint, ...options });
|
|
38
|
+
},
|
|
39
|
+
notFound(message, hint, options) {
|
|
40
|
+
return new McpToolError("not_found", message, { hint, ...options });
|
|
41
|
+
},
|
|
42
|
+
outsideRoot(message, hint, options) {
|
|
43
|
+
return new McpToolError("outside_root", message, { hint, ...options });
|
|
44
|
+
},
|
|
45
|
+
readonly(message, hint, options) {
|
|
46
|
+
return new McpToolError("readonly", message, { hint, ...options });
|
|
47
|
+
},
|
|
48
|
+
tooLarge(message, hint, options) {
|
|
49
|
+
return new McpToolError("too_large", message, { hint, ...options });
|
|
50
|
+
},
|
|
51
|
+
unsupported(message, hint, options) {
|
|
52
|
+
return new McpToolError("unsupported", message, { hint, ...options });
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* Render any thrown value as the text body of an `isError` tool result.
|
|
57
|
+
*
|
|
58
|
+
* Includes the `cause` chain because documonster's own errors chain via
|
|
59
|
+
* `{ cause }`, and the innermost message is usually the one that says which
|
|
60
|
+
* cell, part or ZIP entry actually failed.
|
|
61
|
+
*/
|
|
62
|
+
export function formatToolError(error) {
|
|
63
|
+
if (error instanceof McpToolError) {
|
|
64
|
+
const lines = [`[${error.code}] ${error.message}`];
|
|
65
|
+
const chain = describeCauseChain(error.cause);
|
|
66
|
+
if (chain !== undefined) {
|
|
67
|
+
lines.push(`Caused by: ${chain}`);
|
|
68
|
+
}
|
|
69
|
+
if (error.hint !== undefined) {
|
|
70
|
+
lines.push(`Hint: ${error.hint}`);
|
|
71
|
+
}
|
|
72
|
+
return lines.join("\n");
|
|
73
|
+
}
|
|
74
|
+
if (error instanceof Error) {
|
|
75
|
+
const lines = [`[internal] ${error.name}: ${error.message}`];
|
|
76
|
+
const chain = describeCauseChain(error.cause);
|
|
77
|
+
if (chain !== undefined) {
|
|
78
|
+
lines.push(`Caused by: ${chain}`);
|
|
79
|
+
}
|
|
80
|
+
return lines.join("\n");
|
|
81
|
+
}
|
|
82
|
+
return `[internal] ${String(error)}`;
|
|
83
|
+
}
|
|
84
|
+
/** Flatten `cause` links into `A: msg -> B: msg`, with a depth guard. */
|
|
85
|
+
function describeCauseChain(cause, depth = 0) {
|
|
86
|
+
if (cause === undefined || cause === null || depth >= 5) {
|
|
87
|
+
return undefined;
|
|
88
|
+
}
|
|
89
|
+
if (!(cause instanceof Error)) {
|
|
90
|
+
return String(cause);
|
|
91
|
+
}
|
|
92
|
+
const head = `${cause.name}: ${cause.message}`;
|
|
93
|
+
const tail = describeCauseChain(cause.cause, depth + 1);
|
|
94
|
+
return tail === undefined ? head : `${head} -> ${tail}`;
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@documonster/mcp` — programmatic entry point.
|
|
3
|
+
*
|
|
4
|
+
* Importing this package lets you embed the server in your own process (for
|
|
5
|
+
* example to attach a different transport, or to drive it from an agent
|
|
6
|
+
* framework) instead of spawning the `documonster-mcp` executable.
|
|
7
|
+
*
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { createServer, resolveConfig } from "@documonster/mcp";
|
|
10
|
+
*
|
|
11
|
+
* const server = createServer(resolveConfig(["--root", "./workspace", "--readonly"]));
|
|
12
|
+
* await server.connect(myTransport);
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export { ConfigError, readMetaFlags, resolveConfig, TOOL_GROUPS, usage } from "./config.js";
|
|
16
|
+
export type { ResolveConfigOptions, ServerConfig, ToolGroup } from "./config.js";
|
|
17
|
+
export { formatToolError, McpToolError, toolError } from "./errors.js";
|
|
18
|
+
export type { McpToolErrorOptions, ToolErrorCode } from "./errors.js";
|
|
19
|
+
export { assertWritable, isInside, resolveInRoot } from "./sandbox.js";
|
|
20
|
+
export type { ResolveOptions } from "./sandbox.js";
|
|
21
|
+
export { createServer } from "./server.js";
|
|
22
|
+
export type { ServerIdentity } from "./server.js";
|
|
23
|
+
export { ALL_TOOLS, selectTools } from "./tools/index.js";
|
|
24
|
+
export type { AnyToolDefinition, ToolContext, ToolDefinition } from "./tools/types.js";
|
|
25
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,aAAa,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAC5F,YAAY,EAAE,oBAAoB,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACjF,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACvE,YAAY,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACtE,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACvE,YAAY,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC1D,YAAY,EAAE,iBAAiB,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@documonster/mcp` — programmatic entry point.
|
|
3
|
+
*
|
|
4
|
+
* Importing this package lets you embed the server in your own process (for
|
|
5
|
+
* example to attach a different transport, or to drive it from an agent
|
|
6
|
+
* framework) instead of spawning the `documonster-mcp` executable.
|
|
7
|
+
*
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { createServer, resolveConfig } from "@documonster/mcp";
|
|
10
|
+
*
|
|
11
|
+
* const server = createServer(resolveConfig(["--root", "./workspace", "--readonly"]));
|
|
12
|
+
* await server.connect(myTransport);
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export { ConfigError, readMetaFlags, resolveConfig, TOOL_GROUPS, usage } from "./config.js";
|
|
16
|
+
export { formatToolError, McpToolError, toolError } from "./errors.js";
|
|
17
|
+
export { assertWritable, isInside, resolveInRoot } from "./sandbox.js";
|
|
18
|
+
export { createServer } from "./server.js";
|
|
19
|
+
export { ALL_TOOLS, selectTools } from "./tools/index.js";
|
|
20
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,aAAa,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAE5F,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAEvE,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAEvE,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Path sandbox.
|
|
3
|
+
*
|
|
4
|
+
* The single most important file in this package. An MCP server hands a model
|
|
5
|
+
* the ability to name files, so every path a tool touches must go through
|
|
6
|
+
* {@link resolveInRoot} — there is no other legitimate way to turn a
|
|
7
|
+
* model-supplied string into a filesystem path.
|
|
8
|
+
*
|
|
9
|
+
* Two attacks this defends against:
|
|
10
|
+
*
|
|
11
|
+
* 1. Traversal — `../../.ssh/id_rsa`, or a plain absolute path. Handled by
|
|
12
|
+
* resolving against the root and then checking containment.
|
|
13
|
+
* 2. Symlink escape — a link inside the root pointing outside it. Handled by
|
|
14
|
+
* realpath'ing the deepest part of the path that actually exists, which is
|
|
15
|
+
* why the check cannot be a naive `startsWith` on the raw string.
|
|
16
|
+
*
|
|
17
|
+
* Do NOT rely on the MCP client's tool-approval prompt for this. Programmatic
|
|
18
|
+
* clients have no prompt.
|
|
19
|
+
*/
|
|
20
|
+
import type { ServerConfig } from "./config.js";
|
|
21
|
+
export interface ResolveOptions {
|
|
22
|
+
/**
|
|
23
|
+
* When true, the path must already exist. Use for inputs; leave false for
|
|
24
|
+
* write targets, whose parent is checked instead.
|
|
25
|
+
*/
|
|
26
|
+
readonly mustExist?: boolean;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Turn a model-supplied path into an absolute path guaranteed to sit inside
|
|
30
|
+
* `config.root`.
|
|
31
|
+
*
|
|
32
|
+
* @throws {McpToolError} `invalid_input` for a URL or empty string,
|
|
33
|
+
* `not_found` when `mustExist` is set and it is not there, and
|
|
34
|
+
* `outside_root` for anything that escapes the sandbox.
|
|
35
|
+
*/
|
|
36
|
+
export declare function resolveInRoot(config: ServerConfig, userPath: string, options?: ResolveOptions): Promise<string>;
|
|
37
|
+
/**
|
|
38
|
+
* Resolve a path a tool is about to write to, plus its sidecar files.
|
|
39
|
+
*
|
|
40
|
+
* A write target needs more than containment: every path the tool derives from
|
|
41
|
+
* it — a `.bak`, a temporary file — must be confined too, or a pre-planted
|
|
42
|
+
* symlink at `report.xlsx.bak` lets an in-place edit write outside the root.
|
|
43
|
+
*/
|
|
44
|
+
export declare function resolveWriteTarget(config: ServerConfig, userPath: string, options?: {
|
|
45
|
+
readonly inPlace?: boolean;
|
|
46
|
+
}): Promise<WriteTarget>;
|
|
47
|
+
/** Resolve a write destination inside the disjoint output root. */
|
|
48
|
+
export declare function resolveOutputPath(config: ServerConfig, userPath: string): Promise<string>;
|
|
49
|
+
/** Public display spelling for a path under the output root. */
|
|
50
|
+
export declare function outputDisplay(userPath: string): string;
|
|
51
|
+
export interface WriteTarget {
|
|
52
|
+
/** Confined absolute path to write. */
|
|
53
|
+
readonly path: string;
|
|
54
|
+
/** Confined absolute path for the `.bak` sidecar. */
|
|
55
|
+
readonly backupPath: string;
|
|
56
|
+
/** The caller's spelling, for messages. */
|
|
57
|
+
readonly display: string;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Choose the destination for a tool that edits an existing file.
|
|
61
|
+
*
|
|
62
|
+
* Files already under `@output/` may be edited in place because that root is
|
|
63
|
+
* the server's private writable workspace. Input files require an explicit
|
|
64
|
+
* `out` unless the operator enabled the compatibility escape hatch.
|
|
65
|
+
*/
|
|
66
|
+
export declare function resolveEditTarget(config: ServerConfig, sourcePath: string, out: string | undefined): Promise<WriteTarget>;
|
|
67
|
+
/**
|
|
68
|
+
* Assert the server is allowed to mutate the filesystem.
|
|
69
|
+
*
|
|
70
|
+
* Mutating tools are already withheld from `tools/list` under `--readonly`;
|
|
71
|
+
* this is the second line of defence for a client that calls a tool it was
|
|
72
|
+
* never told about.
|
|
73
|
+
*
|
|
74
|
+
* @remarks
|
|
75
|
+
* Called by every mutating tool (`sheet_write`, `archive_read` when extracting)
|
|
76
|
+
* before it touches the disk. `selectTools` filtering is the other half.
|
|
77
|
+
*/
|
|
78
|
+
export declare function assertWritable(config: ServerConfig): void;
|
|
79
|
+
/**
|
|
80
|
+
* True when `child` is `parent` itself or lives beneath it.
|
|
81
|
+
*
|
|
82
|
+
* Compares path segments rather than raw strings, so `/root-2` is correctly
|
|
83
|
+
* rejected as a sibling of `/root` instead of matching a `startsWith("/root")`.
|
|
84
|
+
*/
|
|
85
|
+
export declare function isInside(parent: string, child: string): boolean;
|
|
86
|
+
//# sourceMappingURL=sandbox.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sandbox.d.ts","sourceRoot":"","sources":["../src/sandbox.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAKH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAShD,MAAM,WAAW,cAAc;IAC7B;;;OAGG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED;;;;;;;GAOG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,YAAY,EACpB,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,MAAM,CAAC,CAmCjB;AAED;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,YAAY,EACpB,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE;IAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAO,GAC3C,OAAO,CAAC,WAAW,CAAC,CA2BtB;AAED,mEAAmE;AACnE,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAiB/F;AAyBD,gEAAgE;AAChE,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGtD;AAED,MAAM,WAAW,WAAW;IAC1B,uCAAuC;IACvC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,qDAAqD;IACrD,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,2CAA2C;IAC3C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,YAAY,EACpB,UAAU,EAAE,MAAM,EAClB,GAAG,EAAE,MAAM,GAAG,SAAS,GACtB,OAAO,CAAC,WAAW,CAAC,CAQtB;AAYD;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,CAOzD;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAW/D"}
|
package/dist/sandbox.js
ADDED
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Path sandbox.
|
|
3
|
+
*
|
|
4
|
+
* The single most important file in this package. An MCP server hands a model
|
|
5
|
+
* the ability to name files, so every path a tool touches must go through
|
|
6
|
+
* {@link resolveInRoot} — there is no other legitimate way to turn a
|
|
7
|
+
* model-supplied string into a filesystem path.
|
|
8
|
+
*
|
|
9
|
+
* Two attacks this defends against:
|
|
10
|
+
*
|
|
11
|
+
* 1. Traversal — `../../.ssh/id_rsa`, or a plain absolute path. Handled by
|
|
12
|
+
* resolving against the root and then checking containment.
|
|
13
|
+
* 2. Symlink escape — a link inside the root pointing outside it. Handled by
|
|
14
|
+
* realpath'ing the deepest part of the path that actually exists, which is
|
|
15
|
+
* why the check cannot be a naive `startsWith` on the raw string.
|
|
16
|
+
*
|
|
17
|
+
* Do NOT rely on the MCP client's tool-approval prompt for this. Programmatic
|
|
18
|
+
* clients have no prompt.
|
|
19
|
+
*/
|
|
20
|
+
import fs from "node:fs/promises";
|
|
21
|
+
import path from "node:path";
|
|
22
|
+
import { toolError } from "./errors.js";
|
|
23
|
+
/** Symlink hops allowed before a path is treated as a loop. */
|
|
24
|
+
const MAX_SYMLINK_DEPTH = 32;
|
|
25
|
+
/** Matches a URL scheme (`http:`, `file:`) without matching a Windows drive letter (`C:`). */
|
|
26
|
+
const URL_SCHEME_RE = /^[a-zA-Z][a-zA-Z0-9+.-]+:/;
|
|
27
|
+
/**
|
|
28
|
+
* Turn a model-supplied path into an absolute path guaranteed to sit inside
|
|
29
|
+
* `config.root`.
|
|
30
|
+
*
|
|
31
|
+
* @throws {McpToolError} `invalid_input` for a URL or empty string,
|
|
32
|
+
* `not_found` when `mustExist` is set and it is not there, and
|
|
33
|
+
* `outside_root` for anything that escapes the sandbox.
|
|
34
|
+
*/
|
|
35
|
+
export async function resolveInRoot(config, userPath, options = {}) {
|
|
36
|
+
if (typeof userPath !== "string" || userPath.trim().length === 0) {
|
|
37
|
+
throw toolError.invalidInput("path must be a non-empty string");
|
|
38
|
+
}
|
|
39
|
+
if (URL_SCHEME_RE.test(userPath)) {
|
|
40
|
+
throw toolError.invalidInput(`path must be a local path inside the sandbox, not a URL: ${userPath}`, "Use a path relative to the server root. This server reads local files only.");
|
|
41
|
+
}
|
|
42
|
+
const outputRelative = outputPathPart(userPath);
|
|
43
|
+
const base = outputRelative === undefined ? config.root : config.outputRoot;
|
|
44
|
+
const relative = outputRelative ?? userPath;
|
|
45
|
+
const candidate = path.resolve(base, relative);
|
|
46
|
+
const resolved = await resolveSegments(candidate);
|
|
47
|
+
if (!isInside(base, resolved)) {
|
|
48
|
+
throw toolError.outsideRoot(`path resolves outside the server root: ${userPath}`, outputRelative === undefined
|
|
49
|
+
? "Only paths inside the configured --root are readable. Ask the user to restart the server with a wider root if this file is genuinely needed."
|
|
50
|
+
: "Only paths inside --output-root are accessible through @output/.");
|
|
51
|
+
}
|
|
52
|
+
if (options.mustExist === true && !(await pathExists(resolved))) {
|
|
53
|
+
throw toolError.notFound(`no such file or directory: ${userPath}`, "Call doc_inspect on the parent directory to see what is actually there.");
|
|
54
|
+
}
|
|
55
|
+
return resolved;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Resolve a path a tool is about to write to, plus its sidecar files.
|
|
59
|
+
*
|
|
60
|
+
* A write target needs more than containment: every path the tool derives from
|
|
61
|
+
* it — a `.bak`, a temporary file — must be confined too, or a pre-planted
|
|
62
|
+
* symlink at `report.xlsx.bak` lets an in-place edit write outside the root.
|
|
63
|
+
*/
|
|
64
|
+
export async function resolveWriteTarget(config, userPath, options = {}) {
|
|
65
|
+
if (options.inPlace === true) {
|
|
66
|
+
const outputRelative = outputPathPart(userPath);
|
|
67
|
+
if (outputRelative !== undefined) {
|
|
68
|
+
const target = await resolveOutputPath(config, outputRelative);
|
|
69
|
+
const backup = await resolveOutputPath(config, `${outputRelative}.bak`);
|
|
70
|
+
return {
|
|
71
|
+
path: target,
|
|
72
|
+
backupPath: backup,
|
|
73
|
+
display: `@output/${normaliseDisplay(outputRelative)}`
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
if (!config.allowInPlace) {
|
|
77
|
+
throw toolError.readonly("in-place edits are disabled", "Provide an `out` path to write safely under @output/, or restart the server with --allow-in-place.");
|
|
78
|
+
}
|
|
79
|
+
const target = await resolveInRoot(config, userPath);
|
|
80
|
+
const backup = await resolveInputSidecar(config, `${userPath}.bak`);
|
|
81
|
+
return { path: target, backupPath: backup, display: userPath };
|
|
82
|
+
}
|
|
83
|
+
const relative = outputPathPart(userPath) ?? userPath;
|
|
84
|
+
const target = await resolveOutputPath(config, relative);
|
|
85
|
+
const backup = await resolveOutputPath(config, `${relative}.bak`);
|
|
86
|
+
return { path: target, backupPath: backup, display: `@output/${normaliseDisplay(relative)}` };
|
|
87
|
+
}
|
|
88
|
+
/** Resolve a write destination inside the disjoint output root. */
|
|
89
|
+
export async function resolveOutputPath(config, userPath) {
|
|
90
|
+
const relative = outputPathPart(userPath) ?? userPath;
|
|
91
|
+
if (path.isAbsolute(relative)) {
|
|
92
|
+
throw toolError.invalidInput(`output path must be relative: ${userPath}`, "Write paths are relative to --output-root and are returned as @output/<path>.");
|
|
93
|
+
}
|
|
94
|
+
const candidate = path.resolve(config.outputRoot, relative);
|
|
95
|
+
const resolved = await resolveSegments(candidate);
|
|
96
|
+
if (!isInside(config.outputRoot, resolved)) {
|
|
97
|
+
throw toolError.outsideRoot(`output path resolves outside --output-root: ${userPath}`, "Use a relative output path without `..`.");
|
|
98
|
+
}
|
|
99
|
+
return resolved;
|
|
100
|
+
}
|
|
101
|
+
/** Resolve a sidecar beside an input file; available only in explicit in-place mode. */
|
|
102
|
+
async function resolveInputSidecar(config, userPath) {
|
|
103
|
+
const candidate = path.resolve(config.root, userPath);
|
|
104
|
+
const resolved = await resolveSegments(candidate);
|
|
105
|
+
if (!isInside(config.root, resolved)) {
|
|
106
|
+
throw toolError.outsideRoot(`sidecar path resolves outside --root: ${userPath}`);
|
|
107
|
+
}
|
|
108
|
+
return resolved;
|
|
109
|
+
}
|
|
110
|
+
/** Return the path after the virtual @output/ prefix, or undefined for input. */
|
|
111
|
+
function outputPathPart(userPath) {
|
|
112
|
+
const normalised = userPath.replace(/\\/g, "/");
|
|
113
|
+
if (normalised === "@output") {
|
|
114
|
+
return ".";
|
|
115
|
+
}
|
|
116
|
+
return normalised.startsWith("@output/") ? normalised.slice("@output/".length) : undefined;
|
|
117
|
+
}
|
|
118
|
+
function normaliseDisplay(relative) {
|
|
119
|
+
return relative.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
120
|
+
}
|
|
121
|
+
/** Public display spelling for a path under the output root. */
|
|
122
|
+
export function outputDisplay(userPath) {
|
|
123
|
+
const relative = outputPathPart(userPath) ?? userPath;
|
|
124
|
+
return `@output/${normaliseDisplay(relative)}`;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Choose the destination for a tool that edits an existing file.
|
|
128
|
+
*
|
|
129
|
+
* Files already under `@output/` may be edited in place because that root is
|
|
130
|
+
* the server's private writable workspace. Input files require an explicit
|
|
131
|
+
* `out` unless the operator enabled the compatibility escape hatch.
|
|
132
|
+
*/
|
|
133
|
+
export async function resolveEditTarget(config, sourcePath, out) {
|
|
134
|
+
if (out !== undefined) {
|
|
135
|
+
return await resolveWriteTarget(config, out);
|
|
136
|
+
}
|
|
137
|
+
if (outputPathPart(sourcePath) !== undefined) {
|
|
138
|
+
return await resolveWriteTarget(config, sourcePath, { inPlace: true });
|
|
139
|
+
}
|
|
140
|
+
return await resolveWriteTarget(config, sourcePath, { inPlace: true });
|
|
141
|
+
}
|
|
142
|
+
/** True when a path exists, following symlinks. */
|
|
143
|
+
async function pathExists(target) {
|
|
144
|
+
try {
|
|
145
|
+
await fs.stat(target);
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Assert the server is allowed to mutate the filesystem.
|
|
154
|
+
*
|
|
155
|
+
* Mutating tools are already withheld from `tools/list` under `--readonly`;
|
|
156
|
+
* this is the second line of defence for a client that calls a tool it was
|
|
157
|
+
* never told about.
|
|
158
|
+
*
|
|
159
|
+
* @remarks
|
|
160
|
+
* Called by every mutating tool (`sheet_write`, `archive_read` when extracting)
|
|
161
|
+
* before it touches the disk. `selectTools` filtering is the other half.
|
|
162
|
+
*/
|
|
163
|
+
export function assertWritable(config) {
|
|
164
|
+
if (config.readonly) {
|
|
165
|
+
throw toolError.readonly("this server is running in --readonly mode", "Report to the user that writing is disabled; do not retry.");
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* True when `child` is `parent` itself or lives beneath it.
|
|
170
|
+
*
|
|
171
|
+
* Compares path segments rather than raw strings, so `/root-2` is correctly
|
|
172
|
+
* rejected as a sibling of `/root` instead of matching a `startsWith("/root")`.
|
|
173
|
+
*/
|
|
174
|
+
export function isInside(parent, child) {
|
|
175
|
+
if (child === parent) {
|
|
176
|
+
return true;
|
|
177
|
+
}
|
|
178
|
+
const relative = path.relative(parent, child);
|
|
179
|
+
return (relative.length > 0 &&
|
|
180
|
+
!relative.startsWith(`..${path.sep}`) &&
|
|
181
|
+
relative !== ".." &&
|
|
182
|
+
!path.isAbsolute(relative));
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Realpath every segment of `target`, following symlinks explicitly.
|
|
186
|
+
*
|
|
187
|
+
* `fs.realpath` cannot be used for the whole path: it throws `ENOENT` both for
|
|
188
|
+
* "this does not exist" and for "this is a symlink whose target does not
|
|
189
|
+
* exist". Treating the second case as the first is a sandbox escape — a
|
|
190
|
+
* dangling link pointing outside the root would be reported as an ordinary
|
|
191
|
+
* not-yet-existing path inside it, and the tool would then create the file at
|
|
192
|
+
* the link's real destination.
|
|
193
|
+
*
|
|
194
|
+
* So each segment is resolved in turn: an existing symlink is read and its
|
|
195
|
+
* target resolved recursively, whether or not that target exists yet, while a
|
|
196
|
+
* genuinely missing segment is simply appended.
|
|
197
|
+
*/
|
|
198
|
+
async function resolveSegments(target, depth = 0) {
|
|
199
|
+
if (depth > MAX_SYMLINK_DEPTH) {
|
|
200
|
+
throw toolError.invalidInput(`too many symbolic links while resolving ${target}`, "The path contains a symlink loop.");
|
|
201
|
+
}
|
|
202
|
+
const parent = path.dirname(target);
|
|
203
|
+
// `path.dirname` is a fixed point at the filesystem root, which ends recursion.
|
|
204
|
+
const resolvedParent = parent === target ? target : await resolveSegments(parent, depth + 1);
|
|
205
|
+
const candidate = path.join(resolvedParent, path.basename(target));
|
|
206
|
+
let stats;
|
|
207
|
+
try {
|
|
208
|
+
stats = await fs.lstat(candidate);
|
|
209
|
+
}
|
|
210
|
+
catch (cause) {
|
|
211
|
+
if (cause.code === "ENOENT") {
|
|
212
|
+
// Genuinely absent: a valid write target, and nothing left to follow.
|
|
213
|
+
return candidate;
|
|
214
|
+
}
|
|
215
|
+
throw cause;
|
|
216
|
+
}
|
|
217
|
+
if (!stats.isSymbolicLink()) {
|
|
218
|
+
return candidate;
|
|
219
|
+
}
|
|
220
|
+
const link = await fs.readlink(candidate);
|
|
221
|
+
const absolute = path.isAbsolute(link) ? link : path.join(resolvedParent, link);
|
|
222
|
+
return await resolveSegments(absolute, depth + 1);
|
|
223
|
+
}
|
|
224
|
+
//# sourceMappingURL=sandbox.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sandbox.js","sourceRoot":"","sources":["../src/sandbox.ts"],"names":[],"mappings":"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"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server assembly.
|
|
3
|
+
*
|
|
4
|
+
* Deliberately transport-agnostic: this builds an `McpServer` with tools
|
|
5
|
+
* registered and hands it back. `cli.ts` attaches stdio; tests attach an
|
|
6
|
+
* in-memory transport. Keeping the two apart is what makes protocol-level
|
|
7
|
+
* tests possible without spawning a process, and leaves room to add a
|
|
8
|
+
* Streamable HTTP entry point later without touching tool code.
|
|
9
|
+
*/
|
|
10
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
11
|
+
import type { ServerConfig } from "./config.js";
|
|
12
|
+
/** Package identity reported during the MCP handshake. */
|
|
13
|
+
export interface ServerIdentity {
|
|
14
|
+
readonly name: string;
|
|
15
|
+
readonly version: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Build a configured MCP server. Nothing is connected yet — call
|
|
19
|
+
* `server.connect(transport)`.
|
|
20
|
+
*/
|
|
21
|
+
export declare function createServer(config: ServerConfig, identity?: ServerIdentity): McpServer;
|
|
22
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIpE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAMhD,0DAA0D;AAC1D,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAcD;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,YAAY,EACpB,QAAQ,GAAE,cAAiC,GAC1C,SAAS,CAgCX"}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server assembly.
|
|
3
|
+
*
|
|
4
|
+
* Deliberately transport-agnostic: this builds an `McpServer` with tools
|
|
5
|
+
* registered and hands it back. `cli.ts` attaches stdio; tests attach an
|
|
6
|
+
* in-memory transport. Keeping the two apart is what makes protocol-level
|
|
7
|
+
* tests possible without spawning a process, and leaves room to add a
|
|
8
|
+
* Streamable HTTP entry point later without touching tool code.
|
|
9
|
+
*/
|
|
10
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
11
|
+
import { registerPrompts, registerResources } from "./capabilities.js";
|
|
12
|
+
import { formatToolError } from "./errors.js";
|
|
13
|
+
import { selectTools } from "./tools/index.js";
|
|
14
|
+
import { errorResult } from "./tools/result.js";
|
|
15
|
+
/**
|
|
16
|
+
* Fallback identity for programmatic callers that do not supply one.
|
|
17
|
+
*
|
|
18
|
+
* Deliberately not a plausible version number: the executable reads the real
|
|
19
|
+
* one from the package manifest, so anything reporting `0.0.0-unknown` in a
|
|
20
|
+
* client's logs is an embedder that should pass its own identity.
|
|
21
|
+
*/
|
|
22
|
+
const DEFAULT_IDENTITY = {
|
|
23
|
+
name: "documonster",
|
|
24
|
+
version: "0.0.0-unknown"
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Build a configured MCP server. Nothing is connected yet — call
|
|
28
|
+
* `server.connect(transport)`.
|
|
29
|
+
*/
|
|
30
|
+
export function createServer(config, identity = DEFAULT_IDENTITY) {
|
|
31
|
+
const server = new McpServer({ name: identity.name, version: identity.version }, {
|
|
32
|
+
instructions: "Document toolkit for Excel, Word, PDF, CSV and ZIP files. Plain paths read from the input root; writes go to a separate output root and are returned as @output/<path>, which later tools can read. Input files are never modified unless the operator explicitly enabled in-place writes. Call doc_inspect before reading any document, and read narrow ranges rather than whole files. Call documonster_help for detailed guidance.",
|
|
33
|
+
capabilities: { tools: {}, resources: {}, prompts: {} }
|
|
34
|
+
});
|
|
35
|
+
// Resources publish the help topics at stable URIs, and prompts encode the
|
|
36
|
+
// inspect-then-read-then-verify order that the tool descriptions can only hint
|
|
37
|
+
// at. Neither costs a slot in the model's tool list.
|
|
38
|
+
registerResources(server);
|
|
39
|
+
registerPrompts(server, config);
|
|
40
|
+
const context = { config };
|
|
41
|
+
for (const tool of selectTools(config)) {
|
|
42
|
+
server.registerTool(tool.name, {
|
|
43
|
+
title: tool.title,
|
|
44
|
+
description: tool.description,
|
|
45
|
+
inputSchema: tool.inputSchema,
|
|
46
|
+
...(tool.annotations === undefined ? {} : { annotations: tool.annotations })
|
|
47
|
+
}, async (args) => runTool(tool, args, context));
|
|
48
|
+
}
|
|
49
|
+
return server;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Invoke a tool, converting any throw into an `isError` result.
|
|
53
|
+
*
|
|
54
|
+
* A thrown exception would surface as a protocol-level failure, which tells
|
|
55
|
+
* the model nothing it can act on. An `isError` result carries the code and
|
|
56
|
+
* hint, which is what lets it correct itself and retry.
|
|
57
|
+
*/
|
|
58
|
+
async function runTool(tool, args, context) {
|
|
59
|
+
try {
|
|
60
|
+
return await tool.handler(args, context);
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
return errorResult(formatToolError(error));
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAGpE,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAEvE,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAShD;;;;;;GAMG;AACH,MAAM,gBAAgB,GAAmB;IACvC,IAAI,EAAE,aAAa;IACnB,OAAO,EAAE,eAAe;CACzB,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,YAAY,CAC1B,MAAoB,EACpB,QAAQ,GAAmB,gBAAgB;IAE3C,MAAM,MAAM,GAAG,IAAI,SAAS,CAC1B,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,CAAC,OAAO,EAAE,EAClD;QACE,YAAY,EACV,uaAAua;QACza,YAAY,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;KACxD,CACF,CAAC;IAEF,2EAA2E;IAC3E,+EAA+E;IAC/E,qDAAqD;IACrD,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAC1B,eAAe,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEhC,MAAM,OAAO,GAAgB,EAAE,MAAM,EAAE,CAAC;IAExC,KAAK,MAAM,IAAI,IAAI,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC;QACvC,MAAM,CAAC,YAAY,CACjB,IAAI,CAAC,IAAI,EACT;YACE,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,GAAG,CAAC,IAAI,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC;SAC7E,EACD,KAAK,EAAE,IAA6B,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,CACtE,CAAC;IACJ,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;;GAMG;AACH,KAAK,UAAU,OAAO,CACpB,IAAuB,EACvB,IAA6B,EAC7B,OAAoB;IAEpB,IAAI,CAAC;QACH,OAAO,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAC3C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,WAAW,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC;IAC7C,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `archive_read` — list or extract a ZIP/TAR archive.
|
|
3
|
+
*
|
|
4
|
+
* The entry point to most real work: documents arrive as email attachments and
|
|
5
|
+
* export bundles, and a model cannot open a binary container by itself. It is
|
|
6
|
+
* also where the security surface is widest, so three guards apply beyond the
|
|
7
|
+
* generic path sandbox:
|
|
8
|
+
*
|
|
9
|
+
* 1. **Traversal, including through existing links.** Entries are written one at
|
|
10
|
+
* a time and every destination goes through `resolveInRoot`, so an entry name
|
|
11
|
+
* with `..` is rejected *and* so is an entry whose path passes through a
|
|
12
|
+
* symlink already sitting in the destination directory. Delegating to the
|
|
13
|
+
* library's `extractTo` was not enough: it validates entry names against the
|
|
14
|
+
* target directory but writes through a pre-existing `out/link -> /elsewhere`,
|
|
15
|
+
* which was verified to escape the sandbox.
|
|
16
|
+
* 2. **Decompression bombs** — the archive file's own size is checked before it
|
|
17
|
+
* is opened, and the declared uncompressed sizes before anything is written.
|
|
18
|
+
* 3. **Symlink and special entries** — never materialised. A `link ->
|
|
19
|
+
* /etc/passwd` entry would otherwise leave a live escape hatch inside the
|
|
20
|
+
* sandbox for a later tool to follow.
|
|
21
|
+
* 4. **Permissions** — extracted files get the process default rather than the
|
|
22
|
+
* archive's mode bits, so an untrusted archive cannot produce something
|
|
23
|
+
* executable or world-writable.
|
|
24
|
+
*
|
|
25
|
+
* Encryption is not reported when listing: `ArchiveEntryInfo` carries an
|
|
26
|
+
* `isEncrypted` flag at runtime but does not declare it, and this package reads
|
|
27
|
+
* only documented public surface. Encryption therefore surfaces as a failed
|
|
28
|
+
* extraction with a hint to pass `password`. (Worth declaring upstream.)
|
|
29
|
+
*/
|
|
30
|
+
export declare const archiveReadTool: import("./types.js").AnyToolDefinition;
|
|
31
|
+
//# sourceMappingURL=archive-read.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"archive-read.d.ts","sourceRoot":"","sources":["../../src/tools/archive-read.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAwBH,eAAO,MAAM,eAAe,wCAoN1B,CAAC"}
|