@allourthings/mcp-server 0.1.1 → 0.3.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.
- package/dist/index.js +118 -151
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -11140,10 +11140,44 @@ class StdioServerTransport {
|
|
|
11140
11140
|
}
|
|
11141
11141
|
}
|
|
11142
11142
|
|
|
11143
|
-
// src/backends/
|
|
11144
|
-
import {
|
|
11145
|
-
|
|
11146
|
-
|
|
11143
|
+
// src/backends/native.ts
|
|
11144
|
+
import { createRequire } from "module";
|
|
11145
|
+
var require2 = createRequire(import.meta.url);
|
|
11146
|
+
var { JsCatalogStore } = require2("@allourthings/core");
|
|
11147
|
+
|
|
11148
|
+
class NativeBackend {
|
|
11149
|
+
store;
|
|
11150
|
+
constructor(dataDir) {
|
|
11151
|
+
this.store = new JsCatalogStore(dataDir);
|
|
11152
|
+
}
|
|
11153
|
+
async addItem(newItem) {
|
|
11154
|
+
return this.store.addItem(newItem);
|
|
11155
|
+
}
|
|
11156
|
+
async getItem(idOrName) {
|
|
11157
|
+
return this.store.getItem(idOrName);
|
|
11158
|
+
}
|
|
11159
|
+
async listItems(filter) {
|
|
11160
|
+
return this.store.listItems(filter ?? null);
|
|
11161
|
+
}
|
|
11162
|
+
async updateItem(id, updates) {
|
|
11163
|
+
return this.store.updateItem(id, updates);
|
|
11164
|
+
}
|
|
11165
|
+
async deleteItem(id) {
|
|
11166
|
+
return this.store.deleteItem(id);
|
|
11167
|
+
}
|
|
11168
|
+
async searchItems(query) {
|
|
11169
|
+
return this.store.searchItems(query);
|
|
11170
|
+
}
|
|
11171
|
+
async addAttachment(itemId, filename, kind, data, label) {
|
|
11172
|
+
return this.store.addAttachment(itemId, filename, kind, data, label ?? null);
|
|
11173
|
+
}
|
|
11174
|
+
async getAttachment(itemId, filename) {
|
|
11175
|
+
return this.store.getAttachment(itemId, filename);
|
|
11176
|
+
}
|
|
11177
|
+
async deleteAttachment(itemId, filename) {
|
|
11178
|
+
return this.store.deleteAttachment(itemId, filename);
|
|
11179
|
+
}
|
|
11180
|
+
}
|
|
11147
11181
|
|
|
11148
11182
|
// ../../node_modules/zod/v3/external.js
|
|
11149
11183
|
var exports_external = {};
|
|
@@ -15118,148 +15152,6 @@ var coerce = {
|
|
|
15118
15152
|
date: (arg) => ZodDate.create({ ...arg, coerce: true })
|
|
15119
15153
|
};
|
|
15120
15154
|
var NEVER2 = INVALID;
|
|
15121
|
-
// src/schema.ts
|
|
15122
|
-
var AttachmentSchema = exports_external.object({
|
|
15123
|
-
filename: exports_external.string(),
|
|
15124
|
-
type: exports_external.enum(["manual", "receipt", "photo", "warranty", "other"]),
|
|
15125
|
-
label: exports_external.string().optional()
|
|
15126
|
-
});
|
|
15127
|
-
var ItemSchema = exports_external.object({
|
|
15128
|
-
id: exports_external.string(),
|
|
15129
|
-
name: exports_external.string(),
|
|
15130
|
-
created_at: exports_external.string().datetime(),
|
|
15131
|
-
updated_at: exports_external.string().datetime(),
|
|
15132
|
-
category: exports_external.string().optional(),
|
|
15133
|
-
brand: exports_external.string().optional(),
|
|
15134
|
-
model: exports_external.string().optional(),
|
|
15135
|
-
purchase_date: exports_external.string().optional(),
|
|
15136
|
-
purchase_price: exports_external.number().optional(),
|
|
15137
|
-
currency: exports_external.string().optional(),
|
|
15138
|
-
warranty_expires: exports_external.string().optional(),
|
|
15139
|
-
retailer: exports_external.string().optional(),
|
|
15140
|
-
location: exports_external.string().optional(),
|
|
15141
|
-
features: exports_external.array(exports_external.string()).optional(),
|
|
15142
|
-
notes: exports_external.string().optional(),
|
|
15143
|
-
tags: exports_external.array(exports_external.string()).optional(),
|
|
15144
|
-
attachments: exports_external.array(AttachmentSchema).optional()
|
|
15145
|
-
}).passthrough();
|
|
15146
|
-
var NewItemSchema = ItemSchema.omit({
|
|
15147
|
-
id: true,
|
|
15148
|
-
created_at: true,
|
|
15149
|
-
updated_at: true
|
|
15150
|
-
}).passthrough();
|
|
15151
|
-
|
|
15152
|
-
// src/utils.ts
|
|
15153
|
-
import { randomBytes } from "crypto";
|
|
15154
|
-
function generateId() {
|
|
15155
|
-
return randomBytes(4).toString("hex");
|
|
15156
|
-
}
|
|
15157
|
-
function toSlug(name) {
|
|
15158
|
-
return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 50).replace(/-+$/, "");
|
|
15159
|
-
}
|
|
15160
|
-
|
|
15161
|
-
// src/backends/filesystem.ts
|
|
15162
|
-
class FilesystemBackend {
|
|
15163
|
-
dataDir;
|
|
15164
|
-
constructor(dataDir) {
|
|
15165
|
-
this.dataDir = dataDir;
|
|
15166
|
-
}
|
|
15167
|
-
get itemsDir() {
|
|
15168
|
-
return join(this.dataDir, "items");
|
|
15169
|
-
}
|
|
15170
|
-
itemDirPath(name, id) {
|
|
15171
|
-
return join(this.itemsDir, `${toSlug(name)}-${id}`);
|
|
15172
|
-
}
|
|
15173
|
-
async findDirById(id) {
|
|
15174
|
-
if (!existsSync(this.itemsDir))
|
|
15175
|
-
return null;
|
|
15176
|
-
const entries = await readdir(this.itemsDir);
|
|
15177
|
-
const match = entries.find((e) => e.slice(-8) === id);
|
|
15178
|
-
return match ? join(this.itemsDir, match) : null;
|
|
15179
|
-
}
|
|
15180
|
-
async readItemFromDir(dir) {
|
|
15181
|
-
const raw = await readFile(join(dir, "item.json"), "utf-8");
|
|
15182
|
-
return ItemSchema.parse(JSON.parse(raw));
|
|
15183
|
-
}
|
|
15184
|
-
async writeItemToDir(dir, item) {
|
|
15185
|
-
await mkdir(dir, { recursive: true });
|
|
15186
|
-
await writeFile(join(dir, "item.json"), JSON.stringify(item, null, 2));
|
|
15187
|
-
}
|
|
15188
|
-
async loadAll() {
|
|
15189
|
-
if (!existsSync(this.itemsDir))
|
|
15190
|
-
return [];
|
|
15191
|
-
const entries = await readdir(this.itemsDir);
|
|
15192
|
-
const items = [];
|
|
15193
|
-
for (const entry of entries) {
|
|
15194
|
-
const itemPath = join(this.itemsDir, entry, "item.json");
|
|
15195
|
-
if (!existsSync(itemPath))
|
|
15196
|
-
continue;
|
|
15197
|
-
try {
|
|
15198
|
-
const raw = await readFile(itemPath, "utf-8");
|
|
15199
|
-
items.push(ItemSchema.parse(JSON.parse(raw)));
|
|
15200
|
-
} catch {}
|
|
15201
|
-
}
|
|
15202
|
-
return items;
|
|
15203
|
-
}
|
|
15204
|
-
async addItem(newItem) {
|
|
15205
|
-
const id = generateId();
|
|
15206
|
-
const now = new Date().toISOString();
|
|
15207
|
-
const item = { ...newItem, id, created_at: now, updated_at: now };
|
|
15208
|
-
await this.writeItemToDir(this.itemDirPath(item.name, id), item);
|
|
15209
|
-
return item;
|
|
15210
|
-
}
|
|
15211
|
-
async getItem(idOrName) {
|
|
15212
|
-
const dirById = await this.findDirById(idOrName);
|
|
15213
|
-
if (dirById)
|
|
15214
|
-
return this.readItemFromDir(dirById);
|
|
15215
|
-
const items = await this.loadAll();
|
|
15216
|
-
const lower = idOrName.toLowerCase();
|
|
15217
|
-
return items.find((i) => i.name.toLowerCase() === lower) ?? items.find((i) => i.name.toLowerCase().includes(lower)) ?? null;
|
|
15218
|
-
}
|
|
15219
|
-
async listItems(filter) {
|
|
15220
|
-
let items = await this.loadAll();
|
|
15221
|
-
if (filter?.category) {
|
|
15222
|
-
items = items.filter((i) => i.category === filter.category);
|
|
15223
|
-
}
|
|
15224
|
-
if (filter?.location) {
|
|
15225
|
-
items = items.filter((i) => i.location?.toLowerCase() === filter.location.toLowerCase());
|
|
15226
|
-
}
|
|
15227
|
-
if (filter?.tags?.length) {
|
|
15228
|
-
items = items.filter((i) => filter.tags.every((tag) => i.tags?.includes(tag)));
|
|
15229
|
-
}
|
|
15230
|
-
return items;
|
|
15231
|
-
}
|
|
15232
|
-
async updateItem(id, updates) {
|
|
15233
|
-
const oldDir = await this.findDirById(id);
|
|
15234
|
-
if (!oldDir)
|
|
15235
|
-
return null;
|
|
15236
|
-
const existing = await this.readItemFromDir(oldDir);
|
|
15237
|
-
const updated = {
|
|
15238
|
-
...existing,
|
|
15239
|
-
...updates,
|
|
15240
|
-
id,
|
|
15241
|
-
updated_at: new Date().toISOString()
|
|
15242
|
-
};
|
|
15243
|
-
const newDir = this.itemDirPath(updated.name, id);
|
|
15244
|
-
if (oldDir !== newDir) {
|
|
15245
|
-
await rename(oldDir, newDir);
|
|
15246
|
-
}
|
|
15247
|
-
await this.writeItemToDir(newDir, updated);
|
|
15248
|
-
return updated;
|
|
15249
|
-
}
|
|
15250
|
-
async deleteItem(id) {
|
|
15251
|
-
const dir = await this.findDirById(id);
|
|
15252
|
-
if (!dir)
|
|
15253
|
-
return false;
|
|
15254
|
-
await rm(dir, { recursive: true });
|
|
15255
|
-
return true;
|
|
15256
|
-
}
|
|
15257
|
-
async searchItems(query) {
|
|
15258
|
-
const items = await this.loadAll();
|
|
15259
|
-
const lower = query.toLowerCase();
|
|
15260
|
-
return items.filter((i) => JSON.stringify(i).toLowerCase().includes(lower));
|
|
15261
|
-
}
|
|
15262
|
-
}
|
|
15263
15155
|
// ../../node_modules/@modelcontextprotocol/sdk/dist/esm/server/zod-compat.js
|
|
15264
15156
|
function isZ4Schema(s) {
|
|
15265
15157
|
const schema = s;
|
|
@@ -17905,7 +17797,6 @@ class Server extends Protocol {
|
|
|
17905
17797
|
return this.notification({ method: "notifications/prompts/list_changed" });
|
|
17906
17798
|
}
|
|
17907
17799
|
}
|
|
17908
|
-
|
|
17909
17800
|
// src/tools/add-item.ts
|
|
17910
17801
|
var addItemInputSchema = exports_external.object({
|
|
17911
17802
|
name: exports_external.string().describe("Name of the item"),
|
|
@@ -18031,6 +17922,61 @@ ${summary}` }]
|
|
|
18031
17922
|
};
|
|
18032
17923
|
}
|
|
18033
17924
|
|
|
17925
|
+
// src/tools/add-attachment.ts
|
|
17926
|
+
var addAttachmentInputSchema = exports_external.object({
|
|
17927
|
+
item_id: exports_external.string().describe("ID of the item to attach the file to"),
|
|
17928
|
+
filename: exports_external.string().describe("Filename to store the attachment as (e.g. manual.pdf)"),
|
|
17929
|
+
kind: exports_external.enum(["manual", "receipt", "photo", "warranty", "other"]).describe("Type of attachment"),
|
|
17930
|
+
data_base64: exports_external.string().describe("Base64-encoded file contents"),
|
|
17931
|
+
label: exports_external.string().optional().describe("Human-readable label (e.g. 'Washing machine manual')")
|
|
17932
|
+
});
|
|
17933
|
+
async function addAttachment(backend, input) {
|
|
17934
|
+
const data = Buffer.from(input.data_base64, "base64");
|
|
17935
|
+
const item = await backend.addAttachment(input.item_id, input.filename, input.kind, data, input.label);
|
|
17936
|
+
return {
|
|
17937
|
+
content: [
|
|
17938
|
+
{
|
|
17939
|
+
type: "text",
|
|
17940
|
+
text: JSON.stringify(item, null, 2)
|
|
17941
|
+
}
|
|
17942
|
+
]
|
|
17943
|
+
};
|
|
17944
|
+
}
|
|
17945
|
+
|
|
17946
|
+
// src/tools/get-attachment.ts
|
|
17947
|
+
var getAttachmentInputSchema = exports_external.object({
|
|
17948
|
+
item_id: exports_external.string().describe("ID of the item"),
|
|
17949
|
+
filename: exports_external.string().describe("Filename of the attachment to retrieve")
|
|
17950
|
+
});
|
|
17951
|
+
async function getAttachment(backend, input) {
|
|
17952
|
+
const data = await backend.getAttachment(input.item_id, input.filename);
|
|
17953
|
+
return {
|
|
17954
|
+
content: [
|
|
17955
|
+
{
|
|
17956
|
+
type: "text",
|
|
17957
|
+
text: data.toString("base64")
|
|
17958
|
+
}
|
|
17959
|
+
]
|
|
17960
|
+
};
|
|
17961
|
+
}
|
|
17962
|
+
|
|
17963
|
+
// src/tools/delete-attachment.ts
|
|
17964
|
+
var deleteAttachmentInputSchema = exports_external.object({
|
|
17965
|
+
item_id: exports_external.string().describe("ID of the item"),
|
|
17966
|
+
filename: exports_external.string().describe("Filename of the attachment to delete")
|
|
17967
|
+
});
|
|
17968
|
+
async function deleteAttachment(backend, input) {
|
|
17969
|
+
const item = await backend.deleteAttachment(input.item_id, input.filename);
|
|
17970
|
+
return {
|
|
17971
|
+
content: [
|
|
17972
|
+
{
|
|
17973
|
+
type: "text",
|
|
17974
|
+
text: item ? JSON.stringify(item, null, 2) : "Attachment deleted (item not found)"
|
|
17975
|
+
}
|
|
17976
|
+
]
|
|
17977
|
+
};
|
|
17978
|
+
}
|
|
17979
|
+
|
|
18034
17980
|
// src/server.ts
|
|
18035
17981
|
function createServer(backend) {
|
|
18036
17982
|
const server = new Server({ name: "allourthings", version: "0.1.0" }, { capabilities: { tools: {} } });
|
|
@@ -18065,6 +18011,21 @@ function createServer(backend) {
|
|
|
18065
18011
|
name: "search_items",
|
|
18066
18012
|
description: "Full-text search across all item fields",
|
|
18067
18013
|
inputSchema: zodToJsonSchema(searchItemsInputSchema)
|
|
18014
|
+
},
|
|
18015
|
+
{
|
|
18016
|
+
name: "add_attachment",
|
|
18017
|
+
description: "Attach a file (manual, receipt, photo, warranty, etc.) to an item. File contents must be base64-encoded.",
|
|
18018
|
+
inputSchema: zodToJsonSchema(addAttachmentInputSchema)
|
|
18019
|
+
},
|
|
18020
|
+
{
|
|
18021
|
+
name: "get_attachment",
|
|
18022
|
+
description: "Retrieve an attachment's contents as a base64-encoded string",
|
|
18023
|
+
inputSchema: zodToJsonSchema(getAttachmentInputSchema)
|
|
18024
|
+
},
|
|
18025
|
+
{
|
|
18026
|
+
name: "delete_attachment",
|
|
18027
|
+
description: "Delete an attachment from an item",
|
|
18028
|
+
inputSchema: zodToJsonSchema(deleteAttachmentInputSchema)
|
|
18068
18029
|
}
|
|
18069
18030
|
]
|
|
18070
18031
|
}));
|
|
@@ -18083,6 +18044,12 @@ function createServer(backend) {
|
|
|
18083
18044
|
return deleteItem(backend, deleteItemInputSchema.parse(args));
|
|
18084
18045
|
case "search_items":
|
|
18085
18046
|
return searchItems(backend, searchItemsInputSchema.parse(args));
|
|
18047
|
+
case "add_attachment":
|
|
18048
|
+
return addAttachment(backend, addAttachmentInputSchema.parse(args));
|
|
18049
|
+
case "get_attachment":
|
|
18050
|
+
return getAttachment(backend, getAttachmentInputSchema.parse(args));
|
|
18051
|
+
case "delete_attachment":
|
|
18052
|
+
return deleteAttachment(backend, deleteAttachmentInputSchema.parse(args));
|
|
18086
18053
|
default:
|
|
18087
18054
|
throw new Error(`Unknown tool: ${name}`);
|
|
18088
18055
|
}
|
|
@@ -18092,10 +18059,10 @@ function createServer(backend) {
|
|
|
18092
18059
|
|
|
18093
18060
|
// src/config.ts
|
|
18094
18061
|
import { homedir } from "os";
|
|
18095
|
-
import { join
|
|
18062
|
+
import { join } from "path";
|
|
18096
18063
|
function expandTilde(p) {
|
|
18097
18064
|
if (p === "~" || p.startsWith("~/")) {
|
|
18098
|
-
return
|
|
18065
|
+
return join(homedir(), p.slice(2));
|
|
18099
18066
|
}
|
|
18100
18067
|
return p;
|
|
18101
18068
|
}
|
|
@@ -18107,13 +18074,13 @@ function resolveDataDir(argv = process.argv, env = process.env) {
|
|
|
18107
18074
|
if (env.ALLOURTHINGS_DATA_DIR) {
|
|
18108
18075
|
return expandTilde(env.ALLOURTHINGS_DATA_DIR);
|
|
18109
18076
|
}
|
|
18110
|
-
return
|
|
18077
|
+
return join(homedir(), "Documents", "AllOurThings");
|
|
18111
18078
|
}
|
|
18112
18079
|
|
|
18113
18080
|
// src/index.ts
|
|
18114
18081
|
var dataDir = resolveDataDir();
|
|
18115
18082
|
console.error(`[allourthings] data directory: ${dataDir}`);
|
|
18116
|
-
var backend = new
|
|
18083
|
+
var backend = new NativeBackend(dataDir);
|
|
18117
18084
|
var server = createServer(backend);
|
|
18118
18085
|
var transport = new StdioServerTransport;
|
|
18119
18086
|
await server.connect(transport);
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@allourthings/mcp-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"mcpName": "io.allourthings/mcp-server",
|
|
5
5
|
"description": "MCP server for All Our Things — AI-powered household inventory",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
9
|
-
"url": "https://github.com/matt-harding/
|
|
9
|
+
"url": "https://github.com/matt-harding/allourthings-mcp.git"
|
|
10
10
|
},
|
|
11
11
|
"type": "module",
|
|
12
12
|
"files": [
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
27
|
+
"@allourthings/core": "^0.1.10",
|
|
27
28
|
"zod": "^3.24.0",
|
|
28
29
|
"zod-to-json-schema": "^3.25.1"
|
|
29
30
|
},
|