@telepath-computer/autofile 0.4.0 → 0.5.1
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 +57 -38
- package/dist/blobs.d.ts +4 -6
- package/dist/blobs.js +48 -81
- package/dist/blobs.js.map +1 -1
- package/dist/cli.js +1 -1
- package/dist/cli.js.map +1 -1
- package/dist/http.d.ts +1 -1
- package/dist/http.js +131 -5
- package/dist/http.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/mcp-resources.d.ts +5 -1
- package/dist/mcp-resources.js +20 -4
- package/dist/mcp-resources.js.map +1 -1
- package/dist/mcp-tools.d.ts +4 -1
- package/dist/mcp-tools.js +11 -8
- package/dist/mcp-tools.js.map +1 -1
- package/dist/mcp-upload.d.ts +1 -1
- package/dist/mcp-upload.js +29 -29
- package/dist/mcp-upload.js.map +1 -1
- package/dist/mcp-watch.js +3 -3
- package/dist/mcp-watch.js.map +1 -1
- package/dist/server.d.ts +2 -1
- package/dist/server.js +26 -9
- package/dist/server.js.map +1 -1
- package/dist/store.d.ts +21 -1
- package/dist/store.js +274 -84
- package/dist/store.js.map +1 -1
- package/dist/watch.js +21 -24
- package/dist/watch.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,83 +1,98 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="assets/icon.svg" width="72" height="72" alt="Autofile icon">
|
|
3
|
+
</p>
|
|
2
4
|
|
|
3
|
-
Autofile
|
|
5
|
+
<h1 align="center">Autofile</h1>
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
<p align="center">
|
|
8
|
+
<strong>A portable, open filesystem for agents.</strong>
|
|
9
|
+
</p>
|
|
6
10
|
|
|
7
|
-
|
|
8
|
-
-
|
|
9
|
-
|
|
11
|
+
<p align="center">
|
|
12
|
+
<a href="https://www.npmjs.com/package/@telepath-computer/autofile"><img src="https://img.shields.io/npm/v/@telepath-computer/autofile" alt="npm version"></a>
|
|
13
|
+
<a href="LICENSE"><img src="https://img.shields.io/github/license/telepath-computer/autofile" alt="MIT licence"></a>
|
|
14
|
+
<img src="https://img.shields.io/badge/node-%E2%89%A524-339933" alt="Node 24 or later">
|
|
15
|
+
</p>
|
|
10
16
|
|
|
11
|
-
|
|
17
|
+
<p align="center">
|
|
18
|
+
<img src="assets/autofile-view.png" width="760" alt="A grid of records in Autofile: journal entries, contacts, events, topics and saved references">
|
|
19
|
+
<br>
|
|
20
|
+
<em>GUI currently sold separately. If you're interested, <a href="https://telepath.computer">get in touch</a>.</em>
|
|
21
|
+
</p>
|
|
12
22
|
|
|
13
|
-
|
|
23
|
+
Autofile is a simple, local store for the information your agents keep for you, with live updates for the apps that show it. It holds typed records and their attachments in plain files on your own machine, is deliberately small, and is designed for working with agents over [MCP](https://modelcontextprotocol.io) and the software and interfaces they generate.
|
|
14
24
|
|
|
15
|
-
|
|
25
|
+
Designed to work great with [Television](https://github.com/telepath-computer/television).
|
|
16
26
|
|
|
17
|
-
|
|
18
|
-
npm install -g @telepath-computer/autofile
|
|
19
|
-
```
|
|
27
|
+
## Design philosophy
|
|
20
28
|
|
|
21
|
-
|
|
29
|
+
**Your agents file consistently.** Each type says what belongs in it and has a JSON Schema for its fields, and every write is checked against that schema. Records link to each other, and agents find them by keyword, by field value or by following links.
|
|
22
30
|
|
|
23
|
-
|
|
31
|
+
**A live data layer for your apps.** Apps read and write the same records as agents, and are notified when a record changes. That makes it a good fit for artifacts and other software that agents generate.
|
|
24
32
|
|
|
25
|
-
|
|
33
|
+
**Plain files you own.** Records are JSON files and attachments are the original files, in one folder you can keep anywhere, such as Dropbox. This follows the [File over app](https://stephango.com/file-over-app) philosophy: think of it like Obsidian for data.
|
|
26
34
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
35
|
+
## Get started
|
|
36
|
+
|
|
37
|
+
You need Node.js 24 or later.
|
|
30
38
|
|
|
31
|
-
|
|
39
|
+
1. Install Autofile:
|
|
32
40
|
|
|
33
|
-
|
|
41
|
+
```sh
|
|
42
|
+
npm install -g @telepath-computer/autofile
|
|
43
|
+
```
|
|
34
44
|
|
|
35
|
-
|
|
45
|
+
2. Add it to your agent. For Claude Code:
|
|
36
46
|
|
|
37
|
-
|
|
47
|
+
```sh
|
|
48
|
+
claude mcp add autofile --scope user -- autofile
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
For another MCP client, add a server whose command is `autofile`, with no arguments.
|
|
52
|
+
|
|
53
|
+
3. Ask your agent to remember something.
|
|
54
|
+
|
|
55
|
+
Autofile starts empty. Your agent proposes types as it needs them, and creates each one once you agree.
|
|
38
56
|
|
|
39
57
|
## Serve over HTTP
|
|
40
58
|
|
|
41
|
-
For
|
|
59
|
+
For apps and agents that connect over HTTP, run:
|
|
42
60
|
|
|
43
61
|
```sh
|
|
44
62
|
autofile serve
|
|
45
63
|
```
|
|
46
64
|
|
|
47
|
-
This serves the same tools and resources at `http://127.0.0.1:7319/mcp
|
|
65
|
+
This serves the same tools and resources at `http://127.0.0.1:7319/mcp`, and attachments next to it. Autofile does not authenticate HTTP clients, so anything that can reach the address can read and change every record. It listens only on this machine by default. [Serving over HTTP](spec/index.md#serving-over-http) explains how to change the address and which web pages it accepts.
|
|
48
66
|
|
|
49
|
-
## Use as a library
|
|
67
|
+
## Use it as a library
|
|
50
68
|
|
|
51
|
-
|
|
69
|
+
Programs can use the same store directly:
|
|
70
|
+
|
|
71
|
+
```sh
|
|
72
|
+
npm install @telepath-computer/autofile
|
|
73
|
+
```
|
|
52
74
|
|
|
53
75
|
```js
|
|
54
76
|
import { Autofile } from "@telepath-computer/autofile";
|
|
55
77
|
|
|
56
78
|
const store = new Autofile({ folder: "./records" });
|
|
57
79
|
try {
|
|
58
|
-
const { records } = await store.records.find({ q: "
|
|
80
|
+
const { records } = await store.records.find({ q: "Ada Park" });
|
|
59
81
|
for (const record of records) console.log(record.title ?? record.uri);
|
|
60
82
|
} finally {
|
|
61
83
|
await store.close();
|
|
62
84
|
}
|
|
63
85
|
```
|
|
64
86
|
|
|
65
|
-
The
|
|
66
|
-
|
|
67
|
-
Record addresses use `autofile:///<type>/<key>`, type declarations use `autofile:///_types/<name>`, and attachments use `autofile:///_blobs/<hash>.<ext>`. Keep and reuse these addresses as opaque identifiers; they do not tell a client how data is stored.
|
|
68
|
-
|
|
69
|
-
Upload an attachment before writing the record that holds it. `blobs.put(bytes, mediaType)` takes a `Uint8Array` and returns an address; put that address in a field marked `"format": "blob"` in the type schema. For an open store with a `document` type that declares `title` and `attachment` fields:
|
|
87
|
+
The [Library API](spec/index.md#library-api) covers writing records, declaring types, attachments and watching for changes.
|
|
70
88
|
|
|
71
|
-
|
|
72
|
-
const uri = await store.blobs.put(new TextEncoder().encode("Meeting notes"), "text/plain");
|
|
73
|
-
await store.records.create("document", { title: "Meeting notes", attachment: uri });
|
|
74
|
-
```
|
|
89
|
+
## Status
|
|
75
90
|
|
|
76
|
-
|
|
91
|
+
Autofile is new and changing quickly. Until version 1.0, addresses, tools and the library API may change between minor versions.
|
|
77
92
|
|
|
78
93
|
## Specification
|
|
79
94
|
|
|
80
|
-
[spec/index.md](spec/index.md) describes records, types, links, attachments, the MCP tools and resources, and the commands. [Storage](spec/storage.md) specifies the
|
|
95
|
+
[spec/index.md](spec/index.md) describes records, types, links, attachments, the MCP tools and resources, and the commands. [Storage](spec/storage.md) specifies the folder format, and [Implementation](spec/implementation.md) describes the code.
|
|
81
96
|
|
|
82
97
|
## Development
|
|
83
98
|
|
|
@@ -87,3 +102,7 @@ npm test
|
|
|
87
102
|
```
|
|
88
103
|
|
|
89
104
|
`npm test` builds Autofile and runs the tests.
|
|
105
|
+
|
|
106
|
+
## Licence
|
|
107
|
+
|
|
108
|
+
[MIT](LICENSE)
|
package/dist/blobs.d.ts
CHANGED
|
@@ -1,18 +1,16 @@
|
|
|
1
1
|
/** Stores explicitly uploaded attachments and checks their canonical addresses. */
|
|
2
|
-
/** Largest blob that fits in one MCP message after base64 encoding. */
|
|
3
|
-
export declare const MAX_BLOB_BYTES = 7340032;
|
|
4
2
|
/** Canonical names Autofile recognizes in its blob folder. */
|
|
5
3
|
export declare const BLOB_NAME_PATTERN: RegExp;
|
|
6
4
|
/** Canonical URIs Autofile recognizes for stored blobs. */
|
|
7
5
|
export declare const BLOB_URI_PATTERN: RegExp;
|
|
8
|
-
/** Stores
|
|
6
|
+
/** Stores uploaded bytes through the same incremental writer as streamed sources. */
|
|
9
7
|
export declare function writeBlob(blobFolder: string, bytes: Buffer, mediaType: string): Promise<string>;
|
|
10
|
-
/**
|
|
8
|
+
/** Hashes and stores chunks in order, publishing only a complete attachment. */
|
|
9
|
+
export declare function writeBlobStream(blobFolder: string, chunks: AsyncIterable<Uint8Array>, mediaType: string): Promise<string>;
|
|
10
|
+
/** Checks attachment existence without opening or reading its bytes. */
|
|
11
11
|
export declare function blobReferenceProblem(blobFolder: string, uri: string): Promise<string | undefined>;
|
|
12
12
|
/** Checks the bare media type accepted by explicit uploads. */
|
|
13
13
|
export declare function isMediaType(value: unknown): value is string;
|
|
14
|
-
/** Gives the upload size and the accepted limit in the existing refusal form. */
|
|
15
|
-
export declare function blobSizeProblem(size: number): string;
|
|
16
14
|
/** Deletes the named canonical blob resources when they still exist. */
|
|
17
15
|
export declare function deleteBlobUris(blobFolder: string, uris: Iterable<string>): Promise<void>;
|
|
18
16
|
/** Returns the canonical blob name from a URI. */
|
package/dist/blobs.js
CHANGED
|
@@ -1,39 +1,68 @@
|
|
|
1
1
|
/** Stores explicitly uploaded attachments and checks their canonical addresses. */
|
|
2
2
|
import { createHash, randomUUID } from "node:crypto";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { basename, dirname, join } from "node:path";
|
|
3
|
+
import { chmod, lstat, mkdir, rename, unlink, writeFile } from "node:fs/promises";
|
|
4
|
+
import { join } from "node:path";
|
|
6
5
|
import { extension as extensionForMimeType } from "mime-types";
|
|
7
6
|
const BLOB_EXTENSION_PATTERN_SOURCE = "[a-z0-9_-]+";
|
|
8
|
-
/** Largest blob that fits in one MCP message after base64 encoding. */
|
|
9
|
-
export const MAX_BLOB_BYTES = 7_340_032;
|
|
10
7
|
/** Canonical names Autofile recognizes in its blob folder. */
|
|
11
8
|
export const BLOB_NAME_PATTERN = new RegExp(`^[a-f0-9]{64}(?:\\.${BLOB_EXTENSION_PATTERN_SOURCE})?$`, "u");
|
|
12
9
|
/** Canonical URIs Autofile recognizes for stored blobs. */
|
|
13
|
-
export const BLOB_URI_PATTERN = new RegExp(`^autofile:///
|
|
10
|
+
export const BLOB_URI_PATTERN = new RegExp(`^autofile:///blobs/([a-f0-9]{64}(?:\\.${BLOB_EXTENSION_PATTERN_SOURCE})?)$`, "u");
|
|
14
11
|
const blobExtensionPattern = new RegExp(`^${BLOB_EXTENSION_PATTERN_SOURCE}$`, "u");
|
|
15
|
-
/** Stores
|
|
12
|
+
/** Stores uploaded bytes through the same incremental writer as streamed sources. */
|
|
16
13
|
export async function writeBlob(blobFolder, bytes, mediaType) {
|
|
14
|
+
async function* chunks() { yield bytes; }
|
|
15
|
+
return writeBlobStream(blobFolder, chunks(), mediaType);
|
|
16
|
+
}
|
|
17
|
+
/** Hashes and stores chunks in order, publishing only a complete attachment. */
|
|
18
|
+
export async function writeBlobStream(blobFolder, chunks, mediaType) {
|
|
17
19
|
const extension = extensionForMimeType(mediaType.toLowerCase());
|
|
18
20
|
const suffix = extension === false ? undefined : normalizeExtension(extension);
|
|
19
|
-
const digest = createHash("sha256")
|
|
20
|
-
const name = `${digest}${suffix === undefined ? "" : `.${suffix}`}`;
|
|
21
|
+
const digest = createHash("sha256");
|
|
21
22
|
await mkdir(blobFolder, { recursive: true });
|
|
22
23
|
if (!await isDirectory(blobFolder)) {
|
|
23
24
|
throw Object.assign(new Error("blob folder is not a directory"), { code: "ENOTDIR" });
|
|
24
25
|
}
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
await
|
|
28
|
-
|
|
26
|
+
const temporaryPath = join(blobFolder, `.upload.${String(process.pid)}.${randomUUID()}`);
|
|
27
|
+
async function* hashedChunks() {
|
|
28
|
+
for await (const chunk of chunks) {
|
|
29
|
+
digest.update(chunk);
|
|
30
|
+
yield chunk;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
try {
|
|
34
|
+
// writeFile awaits each chunk write before advancing the iterable, so the
|
|
35
|
+
// source is backpressured and attachments never accumulate in memory.
|
|
36
|
+
await writeFile(temporaryPath, hashedChunks(), { flag: "wx" });
|
|
37
|
+
const name = `${digest.digest("hex")}${suffix === undefined ? "" : `.${suffix}`}`;
|
|
38
|
+
const path = join(blobFolder, name);
|
|
39
|
+
if (await isRegularFile(path)) {
|
|
40
|
+
await unlink(temporaryPath);
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
// Set the exact read-only mode before publishing the immutable attachment.
|
|
44
|
+
await chmod(temporaryPath, 0o444);
|
|
45
|
+
await rename(temporaryPath, path);
|
|
46
|
+
}
|
|
47
|
+
return blobUri(name);
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
try {
|
|
51
|
+
await unlink(temporaryPath);
|
|
52
|
+
}
|
|
53
|
+
catch (cleanupError) {
|
|
54
|
+
if (!hasCode(cleanupError, "ENOENT"))
|
|
55
|
+
throw cleanupError;
|
|
56
|
+
}
|
|
57
|
+
throw error;
|
|
58
|
+
}
|
|
29
59
|
}
|
|
30
|
-
/**
|
|
60
|
+
/** Checks attachment existence without opening or reading its bytes. */
|
|
31
61
|
export async function blobReferenceProblem(blobFolder, uri) {
|
|
32
62
|
const name = blobNameFromUri(uri);
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
return details.size > MAX_BLOB_BYTES ? blobSizeProblem(details.size) : undefined;
|
|
63
|
+
return name !== undefined && await isDirectory(blobFolder) && await isRegularFile(join(blobFolder, name))
|
|
64
|
+
? undefined
|
|
65
|
+
: `references a blob that does not exist: ${uri}`;
|
|
37
66
|
}
|
|
38
67
|
/** Checks the bare media type accepted by explicit uploads. */
|
|
39
68
|
export function isMediaType(value) {
|
|
@@ -42,10 +71,6 @@ export function isMediaType(value) {
|
|
|
42
71
|
const token = "[!#$%&'*+.^_`|~0-9A-Za-z-]+";
|
|
43
72
|
return new RegExp(`^${token}/${token}$`, "u").test(value);
|
|
44
73
|
}
|
|
45
|
-
/** Gives the upload size and the accepted limit in the existing refusal form. */
|
|
46
|
-
export function blobSizeProblem(size) {
|
|
47
|
-
return `blob is ${String(size)} bytes; limit is ${String(MAX_BLOB_BYTES)} bytes`;
|
|
48
|
-
}
|
|
49
74
|
/** Deletes the named canonical blob resources when they still exist. */
|
|
50
75
|
export async function deleteBlobUris(blobFolder, uris) {
|
|
51
76
|
if (!await isDirectory(blobFolder))
|
|
@@ -69,70 +94,12 @@ export function blobNameFromUri(uri) {
|
|
|
69
94
|
}
|
|
70
95
|
/** Builds the canonical URI for a recognized blob name. */
|
|
71
96
|
export function blobUri(name) {
|
|
72
|
-
return `autofile:///
|
|
97
|
+
return `autofile:///blobs/${name}`;
|
|
73
98
|
}
|
|
74
99
|
function normalizeExtension(extension) {
|
|
75
100
|
const normalized = extension.toLowerCase();
|
|
76
101
|
return blobExtensionPattern.test(normalized) ? normalized : undefined;
|
|
77
102
|
}
|
|
78
|
-
async function storedBlobDetails(blobFolder, name) {
|
|
79
|
-
if (!await isDirectory(blobFolder))
|
|
80
|
-
return undefined;
|
|
81
|
-
const file = await openRegularFile(join(blobFolder, name));
|
|
82
|
-
if (file === undefined)
|
|
83
|
-
return undefined;
|
|
84
|
-
try {
|
|
85
|
-
return { size: file.size };
|
|
86
|
-
}
|
|
87
|
-
finally {
|
|
88
|
-
await file.handle.close();
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
async function openRegularFile(path) {
|
|
92
|
-
let handle;
|
|
93
|
-
try {
|
|
94
|
-
handle = await open(path, constants.O_RDONLY | constants.O_NONBLOCK | constants.O_NOFOLLOW);
|
|
95
|
-
}
|
|
96
|
-
catch (error) {
|
|
97
|
-
if (hasCode(error, "ENOENT")
|
|
98
|
-
|| hasCode(error, "ENOTDIR")
|
|
99
|
-
|| hasCode(error, "ELOOP")
|
|
100
|
-
|| hasCode(error, "ENXIO")
|
|
101
|
-
|| hasCode(error, "ENODEV")) {
|
|
102
|
-
return undefined;
|
|
103
|
-
}
|
|
104
|
-
throw error;
|
|
105
|
-
}
|
|
106
|
-
try {
|
|
107
|
-
const details = await handle.stat();
|
|
108
|
-
if (!details.isFile()) {
|
|
109
|
-
await handle.close();
|
|
110
|
-
return undefined;
|
|
111
|
-
}
|
|
112
|
-
return { handle, size: details.size };
|
|
113
|
-
}
|
|
114
|
-
catch (error) {
|
|
115
|
-
await handle.close();
|
|
116
|
-
throw error;
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
async function writeBlobAtomically(path, bytes) {
|
|
120
|
-
const temporaryPath = join(dirname(path), `.${basename(path)}.${String(process.pid)}.${randomUUID()}`);
|
|
121
|
-
try {
|
|
122
|
-
await writeFile(temporaryPath, bytes, { flag: "wx" });
|
|
123
|
-
await rename(temporaryPath, path);
|
|
124
|
-
}
|
|
125
|
-
catch (error) {
|
|
126
|
-
try {
|
|
127
|
-
await unlink(temporaryPath);
|
|
128
|
-
}
|
|
129
|
-
catch (cleanupError) {
|
|
130
|
-
if (!hasCode(cleanupError, "ENOENT"))
|
|
131
|
-
throw cleanupError;
|
|
132
|
-
}
|
|
133
|
-
throw error;
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
103
|
async function isDirectory(path) {
|
|
137
104
|
try {
|
|
138
105
|
return (await lstat(path)).isDirectory();
|
package/dist/blobs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"blobs.js","sourceRoot":"","sources":["../src/blobs.ts"],"names":[],"mappings":"AAAA,mFAAmF;AAEnF,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"blobs.js","sourceRoot":"","sources":["../src/blobs.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.js
CHANGED
|
@@ -101,7 +101,7 @@ async function runStdio() {
|
|
|
101
101
|
throw error;
|
|
102
102
|
});
|
|
103
103
|
handle = serveStdio(async () => {
|
|
104
|
-
const server = await buildServer(store);
|
|
104
|
+
const server = await buildServer(store, { blobLocation: "stdio" });
|
|
105
105
|
connectedServer = server;
|
|
106
106
|
return server;
|
|
107
107
|
}, {
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/http.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/** Serves MCP requests and streamed blob downloads through the same HTTP checks. */
|
|
2
2
|
import { type HttpSettings } from "./config.js";
|
|
3
3
|
import type { Autofile } from "./index.js";
|
|
4
4
|
export interface RunningHttpServer {
|
package/dist/http.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/** Serves MCP requests and streamed blob downloads through the same HTTP checks. */
|
|
2
2
|
import { createServer } from "node:http";
|
|
3
|
+
import { Readable } from "node:stream";
|
|
4
|
+
import { pipeline } from "node:stream/promises";
|
|
3
5
|
import { toNodeHandler } from "@modelcontextprotocol/node";
|
|
4
6
|
import { createMcpHandler } from "@modelcontextprotocol/server";
|
|
5
7
|
import { normalizeHttpOrigin } from "./config.js";
|
|
@@ -7,9 +9,12 @@ import { buildServer } from "./server.js";
|
|
|
7
9
|
import { watchResources } from "./mcp-watch.js";
|
|
8
10
|
const MAX_REQUEST_BODY_BYTES = 64 * 1024 * 1024;
|
|
9
11
|
const CORS_ALLOW_HEADERS = "Content-Type, MCP-Protocol-Version, Mcp-Method, Mcp-Name";
|
|
12
|
+
const BLOB_METHODS = "GET, HEAD, OPTIONS";
|
|
13
|
+
const BLOB_EXPOSE_HEADERS = "Content-Length, Content-Range, Accept-Ranges, ETag";
|
|
14
|
+
const blobPathPattern = /^\/blobs\/([a-f0-9]{64})(?:\.[a-z0-9_-]+)?$/u;
|
|
10
15
|
/** Starts one modern-only Streamable HTTP endpoint around a process-shared store. */
|
|
11
16
|
export async function startHttpServer(store, settings, onError) {
|
|
12
|
-
const handler = createMcpHandler(() => buildServer(store), {
|
|
17
|
+
const handler = createMcpHandler(() => buildServer(store, { blobLocation: "http" }), {
|
|
13
18
|
legacy: "reject",
|
|
14
19
|
maxRequestBodySize: MAX_REQUEST_BODY_BYTES,
|
|
15
20
|
onerror: onError,
|
|
@@ -34,7 +39,23 @@ export async function startHttpServer(store, settings, onError) {
|
|
|
34
39
|
...settings.origins.map((origin) => new URL(origin).hostname.toLowerCase()),
|
|
35
40
|
]);
|
|
36
41
|
const httpServer = createServer((request, response) => {
|
|
37
|
-
void routeRequest(request, response, allowedOrigins, allowedHosts, serveMcp)
|
|
42
|
+
void routeRequest(request, response, allowedOrigins, allowedHosts, serveMcp, store).catch((error) => {
|
|
43
|
+
// Cancelling a download closes its pipeline. This is a normal client action,
|
|
44
|
+
// whereas storage and handler failures are reported without physical paths.
|
|
45
|
+
if (error instanceof Error && "code" in error
|
|
46
|
+
&& (error.code === "ERR_STREAM_PREMATURE_CLOSE" || error.code === "ECONNRESET"))
|
|
47
|
+
return;
|
|
48
|
+
onError(new Error("Could not serve HTTP request"));
|
|
49
|
+
if (response.headersSent || response.destroyed)
|
|
50
|
+
response.destroy();
|
|
51
|
+
else {
|
|
52
|
+
response.removeHeader("Content-Length");
|
|
53
|
+
response.removeHeader("Content-Range");
|
|
54
|
+
response.removeHeader("ETag");
|
|
55
|
+
response.removeHeader("Cache-Control");
|
|
56
|
+
refuse(response, 500, "Internal Server Error\n");
|
|
57
|
+
}
|
|
58
|
+
});
|
|
38
59
|
});
|
|
39
60
|
const closed = new Promise((resolveClosed) => httpServer.once("close", resolveClosed));
|
|
40
61
|
try {
|
|
@@ -69,7 +90,14 @@ export async function startHttpServer(store, settings, onError) {
|
|
|
69
90
|
await store.close();
|
|
70
91
|
}
|
|
71
92
|
}
|
|
72
|
-
async function routeRequest(request, response, allowedOrigins, allowedHosts, serveMcp) {
|
|
93
|
+
async function routeRequest(request, response, allowedOrigins, allowedHosts, serveMcp, store) {
|
|
94
|
+
const path = requestPath(request);
|
|
95
|
+
const isBlob = path?.startsWith("/blobs/") === true;
|
|
96
|
+
if (isBlob) {
|
|
97
|
+
response.setHeader("Vary", "Origin");
|
|
98
|
+
response.setHeader("X-Content-Type-Options", "nosniff");
|
|
99
|
+
response.setHeader("Content-Security-Policy", "sandbox");
|
|
100
|
+
}
|
|
73
101
|
if (!isAllowedHost(request.headers.host, allowedHosts)) {
|
|
74
102
|
refuse(response, 403, "Forbidden\n");
|
|
75
103
|
return;
|
|
@@ -79,12 +107,18 @@ async function routeRequest(request, response, allowedOrigins, allowedHosts, ser
|
|
|
79
107
|
refuse(response, 403, "Forbidden\n");
|
|
80
108
|
return;
|
|
81
109
|
}
|
|
82
|
-
if (
|
|
110
|
+
if (path !== "/mcp" && !isBlob) {
|
|
83
111
|
refuse(response, 404, "Not Found\n");
|
|
84
112
|
return;
|
|
85
113
|
}
|
|
86
114
|
if (origin !== undefined)
|
|
87
115
|
setCorsHeaders(response, origin);
|
|
116
|
+
if (isBlob && path !== undefined) {
|
|
117
|
+
if (origin !== undefined)
|
|
118
|
+
response.setHeader("Access-Control-Expose-Headers", BLOB_EXPOSE_HEADERS);
|
|
119
|
+
await serveBlob(request, response, path, store);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
88
122
|
if (request.method === "OPTIONS") {
|
|
89
123
|
response.setHeader("Connection", "close");
|
|
90
124
|
response.writeHead(204, {
|
|
@@ -95,6 +129,97 @@ async function routeRequest(request, response, allowedOrigins, allowedHosts, ser
|
|
|
95
129
|
}
|
|
96
130
|
await serveMcp(request, response);
|
|
97
131
|
}
|
|
132
|
+
async function serveBlob(request, response, path, store) {
|
|
133
|
+
if (request.method === "OPTIONS") {
|
|
134
|
+
response.writeHead(204, {
|
|
135
|
+
"Connection": "close",
|
|
136
|
+
"Access-Control-Allow-Methods": BLOB_METHODS,
|
|
137
|
+
"Access-Control-Allow-Headers": "Range, If-None-Match",
|
|
138
|
+
}).end();
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
if (request.method !== "GET" && request.method !== "HEAD") {
|
|
142
|
+
response.setHeader("Allow", BLOB_METHODS);
|
|
143
|
+
refuse(response, 405, "Method Not Allowed\n");
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
const hash = blobPathPattern.exec(path)?.[1];
|
|
147
|
+
const uri = `autofile://${path}`;
|
|
148
|
+
const details = hash === undefined ? undefined : await store.blobs.stat(uri);
|
|
149
|
+
if (details === undefined) {
|
|
150
|
+
refuse(response, 404, "Not Found\n");
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
const etag = `"${hash}"`;
|
|
154
|
+
response.setHeader("Content-Type", details.mimeType);
|
|
155
|
+
response.setHeader("Accept-Ranges", "bytes");
|
|
156
|
+
response.setHeader("ETag", etag);
|
|
157
|
+
response.setHeader("Cache-Control", "private, max-age=31536000, immutable");
|
|
158
|
+
if (matchesEtag(request.headers["if-none-match"], etag)) {
|
|
159
|
+
response.writeHead(304).end();
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
if (request.method === "HEAD") {
|
|
163
|
+
response.setHeader("Content-Length", details.size);
|
|
164
|
+
response.writeHead(200).end();
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
const ifRange = request.headers["if-range"];
|
|
168
|
+
const range = ifRange === undefined || ifRange === etag
|
|
169
|
+
? parseByteRange(request.headers.range, details.size)
|
|
170
|
+
: undefined;
|
|
171
|
+
if (range === "unsatisfiable") {
|
|
172
|
+
response.setHeader("Content-Range", `bytes */${details.size}`);
|
|
173
|
+
refuse(response, 416, "Range Not Satisfiable\n");
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
const body = await store.blobs.stream(uri, range);
|
|
177
|
+
if (body === undefined) {
|
|
178
|
+
response.removeHeader("ETag");
|
|
179
|
+
response.removeHeader("Cache-Control");
|
|
180
|
+
refuse(response, 404, "Not Found\n");
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
response.setHeader("Content-Length", range === undefined ? details.size : range.end - range.start);
|
|
184
|
+
if (range !== undefined) {
|
|
185
|
+
response.setHeader("Content-Range", `bytes ${range.start}-${range.end - 1}/${details.size}`);
|
|
186
|
+
}
|
|
187
|
+
response.writeHead(range === undefined ? 200 : 206);
|
|
188
|
+
// The pipeline propagates backpressure and cancels the store stream when the
|
|
189
|
+
// connection closes, keeping memory and file descriptors bounded.
|
|
190
|
+
// Node and DOM declarations describe the same Web stream with different
|
|
191
|
+
// iterator helpers. Only the Node adapter needs the richer Node declaration.
|
|
192
|
+
await pipeline(Readable.fromWeb(body), response);
|
|
193
|
+
}
|
|
194
|
+
function matchesEtag(header, etag) {
|
|
195
|
+
if (header === undefined)
|
|
196
|
+
return false;
|
|
197
|
+
return header.trim() === "*"
|
|
198
|
+
|| header.split(",").some((candidate) => candidate.trim().replace(/^W\//u, "") === etag);
|
|
199
|
+
}
|
|
200
|
+
function parseByteRange(header, size) {
|
|
201
|
+
const match = header === undefined ? null : /^bytes=(\d*)-(\d*)$/iu.exec(header);
|
|
202
|
+
const first = match?.[1];
|
|
203
|
+
const last = match?.[2];
|
|
204
|
+
if (first === undefined || last === undefined || (first === "" && last === ""))
|
|
205
|
+
return undefined;
|
|
206
|
+
// Decimal offsets can exceed JavaScript's integer precision. Compare before
|
|
207
|
+
// converting so even very large ranges can be clipped to the actual blob.
|
|
208
|
+
const length = BigInt(size);
|
|
209
|
+
if (first === "") {
|
|
210
|
+
const suffix = BigInt(last);
|
|
211
|
+
if (suffix === 0n || length === 0n)
|
|
212
|
+
return "unsatisfiable";
|
|
213
|
+
return { start: Number(suffix >= length ? 0n : length - suffix), end: size };
|
|
214
|
+
}
|
|
215
|
+
const start = BigInt(first);
|
|
216
|
+
const end = last === "" ? length : BigInt(last) + 1n;
|
|
217
|
+
if (last !== "" && end <= start)
|
|
218
|
+
return undefined;
|
|
219
|
+
if (start >= length)
|
|
220
|
+
return "unsatisfiable";
|
|
221
|
+
return { start: Number(start), end: Number(end > length ? length : end) };
|
|
222
|
+
}
|
|
98
223
|
function requestPath(request) {
|
|
99
224
|
try {
|
|
100
225
|
return new URL(request.url ?? "", "http://autofile.local").pathname;
|
|
@@ -145,6 +270,7 @@ function hostHeaderName(host) {
|
|
|
145
270
|
}
|
|
146
271
|
function refuse(response, status, body) {
|
|
147
272
|
response.setHeader("Connection", "close");
|
|
273
|
+
response.setHeader("Content-Type", "text/plain; charset=utf-8");
|
|
148
274
|
response.writeHead(status).end(body);
|
|
149
275
|
}
|
|
150
276
|
function setCorsHeaders(response, origin) {
|