@telepath-computer/autofile 0.3.0 → 0.4.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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,yEAAyE;AAEzE,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC"}
package/dist/json.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- /** Shared compile-time types for the plain JSON crossing store boundaries. */
1
+ /** Shared JSON types and lossless input checks at the store boundary. */
2
2
  /** A scalar JSON value. */
3
3
  export type JsonPrimitive = string | number | boolean | null;
4
4
  /** Any value representable in JSON. */
@@ -7,3 +7,5 @@ export type JsonValue = JsonPrimitive | JsonObject | JsonValue[];
7
7
  export interface JsonObject {
8
8
  [key: string]: JsonValue;
9
9
  }
10
+ /** Returns why an input is not a plain JSON object, without calling getters or toJSON. */
11
+ export declare function jsonObjectProblem(value: unknown): string | undefined;
package/dist/json.js CHANGED
@@ -1,3 +1,82 @@
1
- /** Shared compile-time types for the plain JSON crossing store boundaries. */
2
- export {};
1
+ /** Shared JSON types and lossless input checks at the store boundary. */
2
+ import { isProxy } from "node:util/types";
3
+ const isRawJson = JSON.isRawJSON;
4
+ /** Returns why an input is not a plain JSON object, without calling getters or toJSON. */
5
+ export function jsonObjectProblem(value) {
6
+ if (isProxy(value))
7
+ return "JSON proxies are not supported";
8
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
9
+ return "must be a JSON object";
10
+ }
11
+ return jsonValueProblem(value, "", new Set());
12
+ }
13
+ function jsonValueProblem(value, path, ancestors) {
14
+ const location = `JSON value at ${JSON.stringify(path || "/")}`;
15
+ if (isProxy(value))
16
+ return `${location}: proxies are not supported`;
17
+ if (isRawJson?.(value))
18
+ return `${location}: raw JSON fragments are not supported`;
19
+ if (value === null || typeof value === "string" || typeof value === "boolean")
20
+ return undefined;
21
+ if (typeof value === "number") {
22
+ return Number.isFinite(value) && !Object.is(value, -0)
23
+ ? undefined
24
+ : `${location}: must be a finite number other than negative zero`;
25
+ }
26
+ if (typeof value !== "object")
27
+ return `${location}: ${typeof value} is not supported`;
28
+ const isArray = Array.isArray(value);
29
+ const prototype = Object.getPrototypeOf(value);
30
+ if (isArray ? prototype !== Array.prototype : prototype !== Object.prototype && prototype !== null) {
31
+ return `${location}: must be a plain object or ordinary array`;
32
+ }
33
+ // Built-in prototypes can carry serialization hooks too. Check descriptors so
34
+ // the JSON snapshot cannot invoke an inherited getter or rewrite the value.
35
+ if (!Object.hasOwn(value, "toJSON")) {
36
+ for (let parent = prototype; parent !== null; parent = Object.getPrototypeOf(parent)) {
37
+ const descriptor = Object.getOwnPropertyDescriptor(parent, "toJSON");
38
+ if (descriptor === undefined)
39
+ continue;
40
+ if (!("value" in descriptor) || typeof descriptor.value === "function") {
41
+ return `${location}: inherited JSON serialization hooks are not supported`;
42
+ }
43
+ break;
44
+ }
45
+ }
46
+ if (ancestors.has(value))
47
+ return `${location}: circular references are not supported`;
48
+ const keys = Reflect.ownKeys(value);
49
+ // Arrays serialize only their numbered elements. Inspect descriptors rather
50
+ // than reading properties so getters and toJSON can never change the input.
51
+ const length = isArray ? Object.getOwnPropertyDescriptor(value, "length").value : undefined;
52
+ if (length !== undefined && keys.length !== length + 1) {
53
+ return `${location}: arrays must be dense and have no extra properties`;
54
+ }
55
+ ancestors.add(value);
56
+ try {
57
+ for (const key of keys) {
58
+ if (typeof key === "symbol")
59
+ return `${location}: symbol properties are not supported`;
60
+ if (length !== undefined) {
61
+ if (key === "length")
62
+ continue;
63
+ if (!/^(?:0|[1-9]\d*)$/u.test(key) || Number(key) >= length) {
64
+ return `${location}: arrays must have no extra properties`;
65
+ }
66
+ }
67
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
68
+ if (!("value" in descriptor) || !descriptor.enumerable) {
69
+ return `${location}: properties must be enumerable data properties`;
70
+ }
71
+ const childPath = `${path}/${key.replaceAll("~", "~0").replaceAll("/", "~1")}`;
72
+ const problem = jsonValueProblem(descriptor.value, childPath, ancestors);
73
+ if (problem !== undefined)
74
+ return problem;
75
+ }
76
+ return undefined;
77
+ }
78
+ finally {
79
+ ancestors.delete(value);
80
+ }
81
+ }
3
82
  //# sourceMappingURL=json.js.map
package/dist/json.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"json.js","sourceRoot":"","sources":["../src/json.ts"],"names":[],"mappings":"AAAA,8EAA8E"}
1
+ {"version":3,"file":"json.js","sourceRoot":"","sources":["../src/json.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ /** Derives MCP resources from public Autofile records and type declarations. */
2
+ import { type Autofile } from "./index.js";
3
+ /** The public information used in an MCP resource listing. */
4
+ export interface StoreResource {
5
+ uri: string;
6
+ name: string;
7
+ mimeType: string;
8
+ title?: string;
9
+ description?: string;
10
+ }
11
+ /** The text or binary contents of one resource. */
12
+ export type StoreResourceContents = {
13
+ uri: string;
14
+ mimeType: string;
15
+ text: string;
16
+ } | {
17
+ uri: string;
18
+ mimeType: string;
19
+ blob: string;
20
+ };
21
+ /** Resource operations shared by the MCP server and its notification adapter. */
22
+ export interface Resources {
23
+ listResources(): Promise<StoreResource[]>;
24
+ getResourceMetadata(uri: string): Promise<StoreResource | undefined>;
25
+ listTypeResources(type: string): Promise<StoreResource[]>;
26
+ readResource(uri: string): Promise<StoreResourceContents | undefined>;
27
+ }
28
+ /** Builds resource operations using only the public library interface. */
29
+ export declare function buildResources(autofile: Autofile): Resources;
30
+ /** Checks addresses that can occur in an MCP resource-list cursor. */
31
+ export declare function isResourceUri(uri: string): boolean;
@@ -0,0 +1,111 @@
1
+ /** Derives MCP resources from public Autofile records and type declarations. */
2
+ import { AutofileError } from "./index.js";
3
+ const typeNamePattern = /^[a-z][a-z0-9-]*$/u;
4
+ const typeUriPattern = /^autofile:\/\/\/_types\/([a-z][a-z0-9-]*)$/u;
5
+ const recordUriPattern = /^autofile:\/\/\/[a-z][a-z0-9-]*\/[a-z0-9][a-z0-9-]*$/u;
6
+ const blobUriPattern = /^autofile:\/\/\/_blobs\/[^/]+$/u;
7
+ /** Builds resource operations using only the public library interface. */
8
+ export function buildResources(autofile) {
9
+ async function listResources() {
10
+ const resources = [];
11
+ for (const declaration of await autofile.types.list()) {
12
+ resources.push(...await listTypeResources(declaration.type));
13
+ }
14
+ return resources.sort(compareResources);
15
+ }
16
+ async function getResourceMetadata(uri) {
17
+ const type = typeUriPattern.exec(uri)?.[1];
18
+ if (type !== undefined) {
19
+ const declaration = await readable(() => autofile.types.get(type));
20
+ return declaration === undefined ? undefined : declarationResource(declaration);
21
+ }
22
+ if (!recordUriPattern.test(uri))
23
+ return undefined;
24
+ const record = await readable(() => autofile.records.get(uri));
25
+ return record === undefined ? undefined : recordResource(record);
26
+ }
27
+ async function listTypeResources(type) {
28
+ if (!typeNamePattern.test(type))
29
+ return [];
30
+ const declaration = await readable(() => autofile.types.get(type));
31
+ if (declaration === undefined)
32
+ return [];
33
+ const resources = [declarationResource(declaration)];
34
+ let cursor;
35
+ do {
36
+ const page = await readable(() => autofile.records.find({ type, limit: 200, cursor }));
37
+ if (page === undefined)
38
+ break;
39
+ resources.push(...page.records.map(recordResource));
40
+ // Queries exclude records that fail schema validation. A direct public
41
+ // read can still return them, including the problems needed to repair them.
42
+ for (const { uri } of page.unreadable) {
43
+ const record = await readable(() => autofile.records.get(uri));
44
+ if (record !== undefined)
45
+ resources.push(recordResource(record));
46
+ }
47
+ cursor = page.cursor;
48
+ } while (cursor !== undefined);
49
+ return resources.sort(compareResources);
50
+ }
51
+ async function readResource(uri) {
52
+ if (blobUriPattern.test(uri)) {
53
+ const blob = await autofile.blobs.get(uri);
54
+ return blob === undefined ? undefined : {
55
+ uri, mimeType: blob.mimeType, blob: Buffer.from(blob.bytes).toString("base64"),
56
+ };
57
+ }
58
+ const type = typeUriPattern.exec(uri)?.[1];
59
+ const document = type !== undefined
60
+ ? await readable(() => autofile.types.get(type))
61
+ : recordUriPattern.test(uri)
62
+ ? await readable(() => autofile.records.get(uri))
63
+ : undefined;
64
+ if (document === undefined)
65
+ return undefined;
66
+ return { uri, mimeType: "application/json", text: serialize(document) };
67
+ }
68
+ return { listResources, getResourceMetadata, listTypeResources, readResource };
69
+ }
70
+ /** Checks addresses that can occur in an MCP resource-list cursor. */
71
+ export function isResourceUri(uri) {
72
+ return typeUriPattern.test(uri) || recordUriPattern.test(uri);
73
+ }
74
+ function declarationResource(declaration) {
75
+ return {
76
+ uri: declaration.uri,
77
+ name: `Type: ${declaration.type}`,
78
+ mimeType: "application/json",
79
+ description: declaration.description,
80
+ ...(declaration.title === undefined ? {} : { title: declaration.title }),
81
+ };
82
+ }
83
+ function recordResource(record) {
84
+ return {
85
+ uri: record.uri,
86
+ name: `${record.type}: ${record.key}`,
87
+ mimeType: "application/json",
88
+ ...(record.title === undefined ? {} : { title: record.title }),
89
+ };
90
+ }
91
+ function serialize(value) {
92
+ return `${JSON.stringify(value, (_key, item) => {
93
+ if (typeof item !== "object" || item === null || Array.isArray(item))
94
+ return item;
95
+ return Object.fromEntries(Object.entries(item).sort(([left], [right]) => (left < right ? -1 : left > right ? 1 : 0)));
96
+ }, 2)}\n`;
97
+ }
98
+ function compareResources(left, right) {
99
+ return left.uri < right.uri ? -1 : left.uri > right.uri ? 1 : 0;
100
+ }
101
+ async function readable(read) {
102
+ try {
103
+ return await read();
104
+ }
105
+ catch (error) {
106
+ if (error instanceof AutofileError)
107
+ return undefined;
108
+ throw error;
109
+ }
110
+ }
111
+ //# sourceMappingURL=mcp-resources.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-resources.js","sourceRoot":"","sources":["../src/mcp-resources.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAEhF,OAAO,EAAE,aAAa,EAA4D,MAAM,YAAY,CAAC;AAErG,MAAM,eAAe,GAAG,oBAAoB,CAAC;AAC7C,MAAM,cAAc,GAAG,6CAA6C,CAAC;AACrE,MAAM,gBAAgB,GAAG,uDAAuD,CAAC;AACjF,MAAM,cAAc,GAAG,iCAAiC,CAAC;AAsBzD,0EAA0E;AAC1E,MAAM,UAAU,cAAc,CAAC,QAAkB;IAC/C,KAAK,UAAU,aAAa;QAC1B,MAAM,SAAS,GAAoB,EAAE,CAAC;QACtC,KAAK,MAAM,WAAW,IAAI,MAAM,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;YACtD,SAAS,CAAC,IAAI,CAAC,GAAG,MAAM,iBAAiB,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC;QAC/D,CAAC;QACD,OAAO,SAAS,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;IAC1C,CAAC;IAED,KAAK,UAAU,mBAAmB,CAAC,GAAW;QAC5C,MAAM,IAAI,GAAG,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC3C,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,MAAM,WAAW,GAAG,MAAM,QAAQ,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;YACnE,OAAO,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,mBAAmB,CAAC,WAAW,CAAC,CAAC;QAClF,CAAC;QACD,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,GAAG,CAAC;YAAE,OAAO,SAAS,CAAC;QAClD,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;QAC/D,OAAO,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;IACnE,CAAC;IAED,KAAK,UAAU,iBAAiB,CAAC,IAAY;QAC3C,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,OAAO,EAAE,CAAC;QAC3C,MAAM,WAAW,GAAG,MAAM,QAAQ,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;QACnE,IAAI,WAAW,KAAK,SAAS;YAAE,OAAO,EAAE,CAAC;QACzC,MAAM,SAAS,GAAG,CAAC,mBAAmB,CAAC,WAAW,CAAC,CAAC,CAAC;QACrD,IAAI,MAA0B,CAAC;QAC/B,GAAG,CAAC;YACF,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;YACvF,IAAI,IAAI,KAAK,SAAS;gBAAE,MAAM;YAC9B,SAAS,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC;YACpD,uEAAuE;YACvE,4EAA4E;YAC5E,KAAK,MAAM,EAAE,GAAG,EAAE,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;gBACtC,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;gBAC/D,IAAI,MAAM,KAAK,SAAS;oBAAE,SAAS,CAAC,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC;YACnE,CAAC;YACD,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QACvB,CAAC,QAAQ,MAAM,KAAK,SAAS,EAAE;QAC/B,OAAO,SAAS,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;IAC1C,CAAC;IAED,KAAK,UAAU,YAAY,CAAC,GAAW;QACrC,IAAI,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YAC7B,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAC3C,OAAO,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;gBACtC,GAAG,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC;aAC/E,CAAC;QACJ,CAAC;QACD,MAAM,IAAI,GAAG,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC3C,MAAM,QAAQ,GAAG,IAAI,KAAK,SAAS;YACjC,CAAC,CAAC,MAAM,QAAQ,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAChD,CAAC,CAAC,gBAAgB,CAAC,IAAI,CAAC,GAAG,CAAC;gBAC1B,CAAC,CAAC,MAAM,QAAQ,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;gBACjD,CAAC,CAAC,SAAS,CAAC;QAChB,IAAI,QAAQ,KAAK,SAAS;YAAE,OAAO,SAAS,CAAC;QAC7C,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,kBAAkB,EAAE,IAAI,EAAE,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC;IAC1E,CAAC;IAED,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,YAAY,EAAE,CAAC;AACjF,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,aAAa,CAAC,GAAW;IACvC,OAAO,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,gBAAgB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAChE,CAAC;AAED,SAAS,mBAAmB,CAAC,WAA4B;IACvD,OAAO;QACL,GAAG,EAAE,WAAW,CAAC,GAAG;QACpB,IAAI,EAAE,SAAS,WAAW,CAAC,IAAI,EAAE;QACjC,QAAQ,EAAE,kBAAkB;QAC5B,WAAW,EAAE,WAAW,CAAC,WAAW;QACpC,GAAG,CAAC,WAAW,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,WAAW,CAAC,KAAK,EAAE,CAAC;KACzE,CAAC;AACJ,CAAC;AAED,SAAS,cAAc,CAAC,MAAsB;IAC5C,OAAO;QACL,GAAG,EAAE,MAAM,CAAC,GAAG;QACf,IAAI,EAAE,GAAG,MAAM,CAAC,IAAI,KAAK,MAAM,CAAC,GAAG,EAAE;QACrC,QAAQ,EAAE,kBAAkB;QAC5B,GAAG,CAAC,MAAM,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC;KAC/D,CAAC;AACJ,CAAC;AAED,SAAS,SAAS,CAAC,KAAa;IAC9B,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,IAAa,EAAE,EAAE;QACtD,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;QAClF,OAAO,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,CACvE,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CACzC,CAAC,CAAC,CAAC;IACN,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC;AACZ,CAAC;AAED,SAAS,gBAAgB,CAAC,IAAmB,EAAE,KAAoB;IACjE,OAAO,IAAI,CAAC,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAClE,CAAC;AAED,KAAK,UAAU,QAAQ,CAAI,IAAsB;IAC/C,IAAI,CAAC;QACH,OAAO,MAAM,IAAI,EAAE,CAAC;IACtB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,aAAa;YAAE,OAAO,SAAS,CAAC;QACrD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC"}
@@ -0,0 +1,113 @@
1
+ /** Translates the library operations into the existing MCP tool result shapes. */
2
+ import { type Autofile, type JsonObject, type RecordQuery } from "./index.js";
3
+ import { type UploadBlobInput, type UploadBlobOptions } from "./mcp-upload.js";
4
+ export type { UploadBlobInput } from "./mcp-upload.js";
5
+ /** One reason a tool request was refused. */
6
+ export interface StoreError {
7
+ uri?: string;
8
+ message: string;
9
+ }
10
+ /** The MCP refusal body, before protocol formatting. */
11
+ export interface Refusal {
12
+ errors: StoreError[];
13
+ }
14
+ /** Arguments to find_records. */
15
+ export type FindRecordsInput = RecordQuery;
16
+ /** Arguments to get_record. */
17
+ export interface GetRecordInput {
18
+ uri: string;
19
+ }
20
+ /** Arguments to create_record. */
21
+ export interface CreateRecordInput {
22
+ type: string;
23
+ key?: string;
24
+ record: JsonObject;
25
+ }
26
+ /** Arguments to update_record. */
27
+ export interface UpdateRecordInput {
28
+ uri: string;
29
+ patch: JsonObject;
30
+ }
31
+ /** Arguments to delete_record. */
32
+ export interface DeleteRecordInput {
33
+ uri: string;
34
+ }
35
+ /** Arguments to get_type. */
36
+ export interface GetTypeInput {
37
+ type: string;
38
+ }
39
+ /** Arguments to create_type. */
40
+ export interface CreateTypeInput {
41
+ type: string;
42
+ description: string;
43
+ schema: JsonObject;
44
+ titleField?: string;
45
+ title?: string;
46
+ }
47
+ /** Arguments to update_type. */
48
+ export interface UpdateTypeInput {
49
+ type: string;
50
+ description?: string;
51
+ schema?: JsonObject;
52
+ titleField?: string | null;
53
+ title?: string | null;
54
+ }
55
+ /** Arguments to delete_type. */
56
+ export interface DeleteTypeInput {
57
+ type: string;
58
+ }
59
+ /** A successful MCP write names the changed resource. */
60
+ export interface UriResult {
61
+ uri: string;
62
+ }
63
+ /** A page returned by find_records. */
64
+ export interface FindRecordsResult {
65
+ records: RecordResult[];
66
+ errors: StoreError[];
67
+ cursor?: string;
68
+ }
69
+ /** The record envelope exposed by MCP tools. */
70
+ export interface RecordResult extends UriResult {
71
+ title?: string;
72
+ createdAt: string;
73
+ updatedAt: string;
74
+ value: JsonObject;
75
+ error?: string;
76
+ }
77
+ /** A declaration summary returned by list_types. */
78
+ export interface TypeSummary extends UriResult {
79
+ type: string;
80
+ description: string;
81
+ title?: string;
82
+ }
83
+ /** The list_types result body. */
84
+ export interface ListTypesResult {
85
+ types: TypeSummary[];
86
+ }
87
+ /** A full declaration returned by get_type. */
88
+ export interface TypeResult extends UriResult {
89
+ description: string;
90
+ schema: JsonObject;
91
+ titleField?: string;
92
+ title?: string;
93
+ }
94
+ /** A successful type update also reports records invalid under its schema. */
95
+ export interface UpdateTypeResult extends UriResult {
96
+ errors: StoreError[];
97
+ }
98
+ /** Plain tool handlers used by the protocol boundary. */
99
+ export interface Tools {
100
+ findRecords(input: FindRecordsInput): Promise<FindRecordsResult | Refusal>;
101
+ getRecord(input: GetRecordInput): Promise<RecordResult | Refusal>;
102
+ createRecord(input: CreateRecordInput): Promise<UriResult | Refusal>;
103
+ updateRecord(input: UpdateRecordInput): Promise<UriResult | Refusal>;
104
+ uploadBlob(input: UploadBlobInput, options?: UploadBlobOptions): Promise<UriResult | Refusal>;
105
+ deleteRecord(input: DeleteRecordInput): Promise<UriResult | Refusal>;
106
+ listTypes(input: Record<string, never>): Promise<ListTypesResult>;
107
+ getType(input: GetTypeInput): Promise<TypeResult | Refusal>;
108
+ createType(input: CreateTypeInput): Promise<UriResult | Refusal>;
109
+ updateType(input: UpdateTypeInput): Promise<UpdateTypeResult | Refusal>;
110
+ deleteType(input: DeleteTypeInput): Promise<UriResult | Refusal>;
111
+ }
112
+ /** Builds tool handlers that use the class for every store operation. */
113
+ export declare function buildTools(autofile: Autofile): Tools;
@@ -0,0 +1,89 @@
1
+ /** Translates the library operations into the existing MCP tool result shapes. */
2
+ import { AutofileError } from "./index.js";
3
+ import { uploadBlob } from "./mcp-upload.js";
4
+ /** Builds tool handlers that use the class for every store operation. */
5
+ export function buildTools(autofile) {
6
+ return {
7
+ findRecords: (input) => withRefusal(async () => {
8
+ const result = await autofile.records.find(input);
9
+ return {
10
+ records: result.records.map(recordResult),
11
+ errors: result.unreadable,
12
+ ...(result.cursor === undefined ? {} : { cursor: result.cursor }),
13
+ };
14
+ }),
15
+ getRecord: ({ uri }) => withRefusal(async () => {
16
+ const record = await autofile.records.get(uri);
17
+ if (record === undefined) {
18
+ // The library returns undefined for either missing part of this address;
19
+ // MCP has always named the missing declaration when the type is absent.
20
+ const type = uri.slice("autofile:///".length).split("/")[0];
21
+ if (await autofile.types.get(type) === undefined) {
22
+ return { errors: [{ uri: `autofile:///_types/${type}`, message: "type does not exist" }] };
23
+ }
24
+ return { errors: [{ uri, message: "record does not exist" }] };
25
+ }
26
+ return recordResult(record);
27
+ }),
28
+ createRecord: ({ type, record, key }) => withRefusal(async () => {
29
+ const created = await autofile.records.create(type, record, { key });
30
+ return { uri: created.uri };
31
+ }),
32
+ updateRecord: ({ uri, patch }) => withRefusal(async () => {
33
+ const updated = await autofile.records.update(uri, patch);
34
+ return { uri: updated.uri };
35
+ }),
36
+ uploadBlob: (input, options = {}) => withRefusal(() => uploadBlob(autofile, input, options)),
37
+ deleteRecord: ({ uri }) => withRefusal(async () => {
38
+ await autofile.records.delete(uri);
39
+ return { uri };
40
+ }),
41
+ async listTypes() {
42
+ const declarations = await autofile.types.list();
43
+ return {
44
+ types: declarations.map(({ uri, type, description, title }) => ({
45
+ uri, type, description,
46
+ ...(title === undefined ? {} : { title }),
47
+ })),
48
+ };
49
+ },
50
+ getType: ({ type }) => withRefusal(async () => {
51
+ const declaration = await autofile.types.get(type);
52
+ if (declaration === undefined) {
53
+ return { errors: [{ uri: `autofile:///_types/${type}`, message: "type does not exist" }] };
54
+ }
55
+ const { type: _type, ...result } = declaration;
56
+ return result;
57
+ }),
58
+ createType: ({ type, ...declaration }) => withRefusal(async () => {
59
+ const created = await autofile.types.create(type, declaration);
60
+ return { uri: created.uri };
61
+ }),
62
+ updateType: ({ type, ...changes }) => withRefusal(async () => {
63
+ const updated = await autofile.types.update(type, changes);
64
+ return { uri: updated.uri, errors: updated.problems ?? [] };
65
+ }),
66
+ deleteType: ({ type }) => withRefusal(async () => {
67
+ await autofile.types.delete(type);
68
+ return { uri: `autofile:///_types/${type}` };
69
+ }),
70
+ };
71
+ }
72
+ function recordResult(record) {
73
+ const { type: _type, key: _key, problems = [], ...result } = record;
74
+ return {
75
+ ...result,
76
+ ...(problems.length === 0 ? {} : { error: problems.map(({ message }) => message).join("; ") }),
77
+ };
78
+ }
79
+ async function withRefusal(operation) {
80
+ try {
81
+ return await operation();
82
+ }
83
+ catch (error) {
84
+ if (error instanceof AutofileError)
85
+ return { errors: error.problems };
86
+ throw error;
87
+ }
88
+ }
89
+ //# sourceMappingURL=mcp-tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-tools.js","sourceRoot":"","sources":["../src/mcp-tools.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /** Validates MCP upload sources and reads local files only for stdio requests. */
2
+ import { type Autofile } from "./index.js";
3
+ /** Arguments to upload_blob; exactly one source is required. */
4
+ export interface UploadBlobInput {
5
+ base64?: string;
6
+ path?: string;
7
+ mediaType?: string;
8
+ }
9
+ /** Local file access is granted only by the stdio transport. */
10
+ export interface UploadBlobOptions {
11
+ allowLocalPaths?: boolean;
12
+ }
13
+ /** Uploads decoded bytes through the library's public blob operation. */
14
+ export declare function uploadBlob(autofile: Autofile, input: UploadBlobInput, options: UploadBlobOptions): Promise<{
15
+ uri: string;
16
+ }>;
@@ -0,0 +1,81 @@
1
+ /** Validates MCP upload sources and reads local files only for stdio requests. */
2
+ import { constants } from "node:fs";
3
+ import { open } from "node:fs/promises";
4
+ import { isAbsolute } from "node:path";
5
+ import { lookup as lookupMimeType } from "mime-types";
6
+ import { AutofileError } from "./index.js";
7
+ // Bound transport decoding and file reads before handing bytes to the library.
8
+ const MAX_UPLOAD_BYTES = 7_340_032;
9
+ /** Uploads decoded bytes through the library's public blob operation. */
10
+ export async function uploadBlob(autofile, input, options) {
11
+ if ((input.base64 === undefined) === (input.path === undefined)) {
12
+ refuse("supply exactly one of base64 or path");
13
+ }
14
+ if (input.path !== undefined) {
15
+ if (options.allowLocalPaths !== true)
16
+ refuse("local paths are accepted only over stdio, not HTTP");
17
+ if (!isAbsolute(input.path))
18
+ refuse("local upload path must be absolute");
19
+ const mediaType = input.mediaType ?? (lookupMimeType(input.path) || "application/octet-stream");
20
+ let bytes;
21
+ try {
22
+ bytes = await readUpload(input.path);
23
+ }
24
+ catch (error) {
25
+ if (error instanceof AutofileError)
26
+ throw error;
27
+ return refuse("local upload source cannot be read");
28
+ }
29
+ return { uri: await autofile.blobs.put(bytes, mediaType) };
30
+ }
31
+ if (input.mediaType === undefined)
32
+ refuse("mediaType is required for base64 uploads");
33
+ const base64 = input.base64;
34
+ // Buffer's base64 decoder silently ignores invalid characters and accepts
35
+ // incomplete padding. Check syntax and the round trip to reject both those
36
+ // forms and nonzero unused bits in the final sextet.
37
+ if (base64.length % 4 !== 0 || !/^[A-Za-z0-9+/]*={0,2}$/u.test(base64)) {
38
+ refuse("base64 must be canonical base64");
39
+ }
40
+ const padding = base64.endsWith("==") ? 2 : base64.endsWith("=") ? 1 : 0;
41
+ const size = base64.length / 4 * 3 - padding;
42
+ if (size > MAX_UPLOAD_BYTES)
43
+ refuseSize(size);
44
+ const bytes = Buffer.from(base64, "base64");
45
+ if (bytes.toString("base64") !== base64)
46
+ refuse("base64 must be canonical base64");
47
+ return { uri: await autofile.blobs.put(bytes, input.mediaType) };
48
+ }
49
+ async function readUpload(path) {
50
+ // Nonblocking opens and a regular-file check keep devices, sockets and pipes
51
+ // from hanging a request. The extra byte also detects growth after stat.
52
+ const file = await open(path, constants.O_RDONLY | constants.O_NONBLOCK);
53
+ try {
54
+ const details = await file.stat();
55
+ if (!details.isFile())
56
+ refuse("local upload source must be a regular file");
57
+ if (details.size > MAX_UPLOAD_BYTES)
58
+ refuseSize(details.size);
59
+ const buffer = Buffer.alloc(MAX_UPLOAD_BYTES + 1);
60
+ let length = 0;
61
+ while (length < buffer.length) {
62
+ const { bytesRead } = await file.read(buffer, length, buffer.length - length, null);
63
+ if (bytesRead === 0)
64
+ break;
65
+ length += bytesRead;
66
+ }
67
+ if (length > MAX_UPLOAD_BYTES)
68
+ refuseSize(length);
69
+ return buffer.subarray(0, length);
70
+ }
71
+ finally {
72
+ await file.close();
73
+ }
74
+ }
75
+ function refuseSize(size) {
76
+ return refuse(`blob is ${String(size)} bytes; limit is ${String(MAX_UPLOAD_BYTES)} bytes`);
77
+ }
78
+ function refuse(message) {
79
+ throw new AutofileError([{ message }]);
80
+ }
81
+ //# sourceMappingURL=mcp-upload.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-upload.js","sourceRoot":"","sources":["../src/mcp-upload.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /** Derives MCP resource-list hints from the changes published by Autofile. */
2
+ import type { Autofile, ChangeEvent } from "./index.js";
3
+ import { type Resources } from "./mcp-resources.js";
4
+ /** One resource update and whether the batch changed the MCP resource list. */
5
+ export interface ResourceChange extends ChangeEvent {
6
+ listChanged: boolean;
7
+ }
8
+ /** Resource updates coalesced by the underlying Autofile watcher. */
9
+ export interface ResourceChangeBatch {
10
+ changes: ResourceChange[];
11
+ listChanged: boolean;
12
+ }
13
+ /** An MCP subscription to the store's shared watcher. */
14
+ export interface ResourceWatcher {
15
+ close(): Promise<void>;
16
+ }
17
+ /** Watches MCP metadata using the instance's existing change subscription API. */
18
+ export declare function watchResources(store: Autofile, onChange: (batch: ResourceChangeBatch) => void | Promise<void>, onError: (error: Error) => void, resources?: Resources): Promise<ResourceWatcher>;