sogo-mcp-server 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 DataRM
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import '../dist/index.js';
@@ -0,0 +1,23 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+
3
+ /**
4
+ * ---
5
+ * @anchor: .patterns/mcp-tool
6
+ * @spec: specs/mcp-server.md#server-setup
7
+ * @task: TASK-008
8
+ * @validated: null
9
+ * ---
10
+ */
11
+
12
+ interface ServerContext {
13
+ globalPath: string;
14
+ workspacePath: string;
15
+ scanDepth: number;
16
+ }
17
+
18
+ declare function createServer(): {
19
+ server: McpServer;
20
+ ctx: ServerContext;
21
+ };
22
+
23
+ export { createServer };
package/dist/index.js ADDED
@@ -0,0 +1,383 @@
1
+ // src/index.ts
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+
5
+ // src/context.ts
6
+ import { homedir } from "os";
7
+ import { scanAll, readDatabaseFile, writeDatabaseFile, getGlobalDatabasePath } from "sogo-db-core";
8
+ function expandTilde(p) {
9
+ return p.startsWith("~") ? p.replace("~", homedir()) : p;
10
+ }
11
+ function createContext() {
12
+ const raw = process.env.SOGO_GLOBAL_PATH;
13
+ return {
14
+ globalPath: raw ? expandTilde(raw) : getGlobalDatabasePath(),
15
+ workspacePath: expandTilde(process.env.SOGO_WORKSPACE_PATH ?? process.cwd()),
16
+ scanDepth: parseInt(process.env.SOGO_SCAN_DEPTH ?? "3", 10)
17
+ };
18
+ }
19
+ async function loadAllDatabases(ctx) {
20
+ return scanAll(ctx.workspacePath, ctx.globalPath, ctx.scanDepth);
21
+ }
22
+ async function findDatabase(ctx, idOrName) {
23
+ const all = await loadAllDatabases(ctx);
24
+ const byId = all.find((e) => e.db.id === idOrName);
25
+ if (byId) return byId;
26
+ const lower = idOrName.toLowerCase();
27
+ return all.find((e) => e.db.name.toLowerCase() === lower) ?? all.find((e) => e.db.name.toLowerCase().includes(lower));
28
+ }
29
+ async function saveDatabase(db, path) {
30
+ await writeDatabaseFile(db, path);
31
+ }
32
+
33
+ // src/fieldResolver.ts
34
+ function resolveField(schema, name) {
35
+ const lower = name.toLowerCase();
36
+ const matches = schema.filter((f) => f.name.toLowerCase() === lower);
37
+ if (matches.length === 1) return matches[0];
38
+ if (matches.length > 1) {
39
+ throw new Error(`Ambiguous field name "${name}" \u2014 matches: ${matches.map((f) => f.name).join(", ")}`);
40
+ }
41
+ const partial = schema.filter((f) => f.name.toLowerCase().includes(lower));
42
+ if (partial.length === 1) return partial[0];
43
+ throw new Error(`Field "${name}" not found. Available: ${schema.map((f) => f.name).join(", ")}`);
44
+ }
45
+ function recordToNamedFields(record, schema) {
46
+ const result = { id: record.id };
47
+ for (const field of schema) {
48
+ const val = record[field.id];
49
+ if (val !== void 0) result[field.name] = val;
50
+ }
51
+ if (record._body !== void 0) result._body = record._body;
52
+ return result;
53
+ }
54
+ function namedFieldsToRecord(values, schema) {
55
+ const result = {};
56
+ for (const [key, val] of Object.entries(values)) {
57
+ if (key === "id" || key === "_body") {
58
+ result[key] = val;
59
+ continue;
60
+ }
61
+ const field = resolveField(schema, key);
62
+ result[field.id] = val;
63
+ }
64
+ return result;
65
+ }
66
+ function databaseSummary(db, scope) {
67
+ return {
68
+ id: db.id,
69
+ name: db.name,
70
+ scope,
71
+ fields: db.schema.map((f) => ({ name: f.name, type: f.type })),
72
+ recordCount: db.records.length,
73
+ views: db.views.map((v) => ({ name: v.name, type: v.type }))
74
+ };
75
+ }
76
+
77
+ // src/tools/listDatabases.ts
78
+ function registerListDatabases(server, ctx) {
79
+ server.tool("list_databases", "List all databases (global + workspace) with schemas", {}, async () => {
80
+ const entries = await loadAllDatabases(ctx);
81
+ const results = entries.map((e) => databaseSummary(e.db, e.scope));
82
+ return { content: [{ type: "text", text: JSON.stringify(results, null, 2) }] };
83
+ });
84
+ }
85
+
86
+ // src/tools/getDatabaseSchema.ts
87
+ import { z } from "zod";
88
+ function registerGetDatabaseSchema(server, ctx) {
89
+ server.tool(
90
+ "get_database_schema",
91
+ "Get field definitions and views for a database",
92
+ { database: z.string().describe("Database ID or name (fuzzy match)") },
93
+ async ({ database }) => {
94
+ const entry = await findDatabase(ctx, database);
95
+ if (!entry) {
96
+ return { content: [{ type: "text", text: JSON.stringify({ error: `Database "${database}" not found` }) }] };
97
+ }
98
+ const result = {
99
+ id: entry.db.id,
100
+ name: entry.db.name,
101
+ scope: entry.scope,
102
+ fields: entry.db.schema.map((f) => ({
103
+ name: f.name,
104
+ type: f.type,
105
+ options: f.options,
106
+ relation: f.relation,
107
+ rollup: f.rollup,
108
+ formula: f.formula
109
+ })),
110
+ views: entry.db.views.map((v) => ({
111
+ name: v.name,
112
+ type: v.type,
113
+ groupBy: v.groupBy ? entry.db.schema.find((f) => f.id === v.groupBy)?.name : void 0
114
+ }))
115
+ };
116
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
117
+ }
118
+ );
119
+ }
120
+
121
+ // src/tools/listRecords.ts
122
+ import { z as z2 } from "zod";
123
+ import { applySorts, applyFilters } from "sogo-db-core";
124
+ function registerListRecords(server, ctx) {
125
+ server.tool(
126
+ "list_records",
127
+ "List records with optional filter, sort, and pagination",
128
+ {
129
+ database: z2.string().describe("Database ID or name"),
130
+ filter: z2.array(z2.object({
131
+ field: z2.string(),
132
+ op: z2.string(),
133
+ value: z2.string()
134
+ })).optional().describe("Filters by field name"),
135
+ sort: z2.array(z2.object({
136
+ field: z2.string(),
137
+ direction: z2.enum(["asc", "desc"])
138
+ })).optional().describe("Sort by field name"),
139
+ page: z2.number().int().min(1).optional().default(1),
140
+ pageSize: z2.number().int().min(1).max(200).optional().default(50)
141
+ },
142
+ async ({ database, filter, sort, page, pageSize }) => {
143
+ const entry = await findDatabase(ctx, database);
144
+ if (!entry) {
145
+ return { content: [{ type: "text", text: JSON.stringify({ error: `Database "${database}" not found` }) }] };
146
+ }
147
+ const { db } = entry;
148
+ let records = db.records;
149
+ if (filter?.length) {
150
+ const resolvedFilters = filter.map((f) => ({
151
+ fieldId: resolveField(db.schema, f.field).id,
152
+ op: f.op,
153
+ value: f.value
154
+ }));
155
+ records = applyFilters(records, resolvedFilters, db.schema, db);
156
+ }
157
+ if (sort?.length) {
158
+ const resolvedSorts = sort.map((s) => ({
159
+ fieldId: resolveField(db.schema, s.field).id,
160
+ direction: s.direction
161
+ }));
162
+ records = applySorts(records, resolvedSorts, db.schema, db);
163
+ }
164
+ const total = records.length;
165
+ const start = (page - 1) * pageSize;
166
+ const paged = records.slice(start, start + pageSize);
167
+ const namedRecords = paged.map((r) => recordToNamedFields(r, db.schema));
168
+ return {
169
+ content: [{
170
+ type: "text",
171
+ text: JSON.stringify({
172
+ database: db.name,
173
+ total,
174
+ page,
175
+ pageSize,
176
+ records: namedRecords
177
+ }, null, 2)
178
+ }]
179
+ };
180
+ }
181
+ );
182
+ }
183
+
184
+ // src/tools/createRecord.ts
185
+ import { z as z3 } from "zod";
186
+ function registerCreateRecord(server, ctx) {
187
+ server.tool(
188
+ "create_record",
189
+ "Create a new record using field names",
190
+ {
191
+ database: z3.string().describe("Database ID or name"),
192
+ values: z3.record(z3.unknown()).describe("Field values by name")
193
+ },
194
+ async ({ database, values }) => {
195
+ const entry = await findDatabase(ctx, database);
196
+ if (!entry) {
197
+ return { content: [{ type: "text", text: JSON.stringify({ error: `Database "${database}" not found` }) }] };
198
+ }
199
+ try {
200
+ const resolved = namedFieldsToRecord(values, entry.db.schema);
201
+ const record = {
202
+ id: crypto.randomUUID(),
203
+ ...resolved
204
+ };
205
+ entry.db.records.push(record);
206
+ await saveDatabase(entry.db, entry.path);
207
+ return {
208
+ content: [{
209
+ type: "text",
210
+ text: JSON.stringify({
211
+ created: recordToNamedFields(record, entry.db.schema)
212
+ }, null, 2)
213
+ }]
214
+ };
215
+ } catch (err) {
216
+ return { content: [{ type: "text", text: JSON.stringify({ error: String(err) }) }] };
217
+ }
218
+ }
219
+ );
220
+ }
221
+
222
+ // src/tools/updateRecord.ts
223
+ import { z as z4 } from "zod";
224
+ function registerUpdateRecord(server, ctx) {
225
+ server.tool(
226
+ "update_record",
227
+ "Update specific fields of a record by name",
228
+ {
229
+ database: z4.string().describe("Database ID or name"),
230
+ recordId: z4.string().describe("Record ID"),
231
+ values: z4.record(z4.unknown()).describe("Field values by name to update")
232
+ },
233
+ async ({ database, recordId, values }) => {
234
+ const entry = await findDatabase(ctx, database);
235
+ if (!entry) {
236
+ return { content: [{ type: "text", text: JSON.stringify({ error: `Database "${database}" not found` }) }] };
237
+ }
238
+ const record = entry.db.records.find((r) => r.id === recordId);
239
+ if (!record) {
240
+ return { content: [{ type: "text", text: JSON.stringify({ error: `Record "${recordId}" not found` }) }] };
241
+ }
242
+ try {
243
+ const resolved = namedFieldsToRecord(values, entry.db.schema);
244
+ for (const [key, val] of Object.entries(resolved)) {
245
+ if (key !== "id") record[key] = val;
246
+ }
247
+ await saveDatabase(entry.db, entry.path);
248
+ return {
249
+ content: [{
250
+ type: "text",
251
+ text: JSON.stringify({
252
+ updated: recordToNamedFields(record, entry.db.schema)
253
+ }, null, 2)
254
+ }]
255
+ };
256
+ } catch (err) {
257
+ return { content: [{ type: "text", text: JSON.stringify({ error: String(err) }) }] };
258
+ }
259
+ }
260
+ );
261
+ }
262
+
263
+ // src/tools/deleteRecord.ts
264
+ import { z as z5 } from "zod";
265
+ function registerDeleteRecord(server, ctx) {
266
+ server.tool(
267
+ "delete_record",
268
+ "Delete a record from a database",
269
+ {
270
+ database: z5.string().describe("Database ID or name"),
271
+ recordId: z5.string().describe("Record ID to delete")
272
+ },
273
+ async ({ database, recordId }) => {
274
+ const entry = await findDatabase(ctx, database);
275
+ if (!entry) {
276
+ return { content: [{ type: "text", text: JSON.stringify({ error: `Database "${database}" not found` }) }] };
277
+ }
278
+ const index = entry.db.records.findIndex((r) => r.id === recordId);
279
+ if (index === -1) {
280
+ return { content: [{ type: "text", text: JSON.stringify({ error: `Record "${recordId}" not found` }) }] };
281
+ }
282
+ entry.db.records.splice(index, 1);
283
+ await saveDatabase(entry.db, entry.path);
284
+ return {
285
+ content: [{
286
+ type: "text",
287
+ text: JSON.stringify({ deleted: recordId, database: entry.db.name })
288
+ }]
289
+ };
290
+ }
291
+ );
292
+ }
293
+
294
+ // src/tools/searchRecords.ts
295
+ import { z as z6 } from "zod";
296
+ function registerSearchRecords(server, ctx) {
297
+ server.tool(
298
+ "search_records",
299
+ "Full-text search across databases",
300
+ {
301
+ query: z6.string().describe("Search query"),
302
+ database: z6.string().optional().describe("Optional: limit to a specific database ID or name")
303
+ },
304
+ async ({ query, database }) => {
305
+ const lower = query.toLowerCase();
306
+ const entries = database ? await findDatabase(ctx, database).then((e) => e ? [e] : []) : await loadAllDatabases(ctx);
307
+ const results = [];
308
+ for (const entry of entries) {
309
+ const { db } = entry;
310
+ const searchableFieldIds = db.schema.filter((f) => ["text", "select", "status", "multiselect", "email", "url", "phone"].includes(f.type)).map((f) => f.id);
311
+ for (const record of db.records) {
312
+ const matches = searchableFieldIds.some((fid) => {
313
+ const val = record[fid];
314
+ if (val === null || val === void 0) return false;
315
+ const str = Array.isArray(val) ? val.join(" ") : String(val);
316
+ return str.toLowerCase().includes(lower);
317
+ });
318
+ if (matches) {
319
+ results.push({
320
+ database: db.name,
321
+ record: recordToNamedFields(record, db.schema)
322
+ });
323
+ }
324
+ }
325
+ }
326
+ return {
327
+ content: [{
328
+ type: "text",
329
+ text: JSON.stringify({
330
+ query,
331
+ total: results.length,
332
+ results: results.slice(0, 50)
333
+ }, null, 2)
334
+ }]
335
+ };
336
+ }
337
+ );
338
+ }
339
+
340
+ // src/resources.ts
341
+ function registerResources(server, ctx) {
342
+ server.resource(
343
+ "databases",
344
+ "sogo://databases",
345
+ { description: "List all databases", mimeType: "application/json" },
346
+ async () => {
347
+ const entries = await loadAllDatabases(ctx);
348
+ const summaries = entries.map((e) => databaseSummary(e.db, e.scope));
349
+ return { contents: [{ uri: "sogo://databases", text: JSON.stringify(summaries, null, 2), mimeType: "application/json" }] };
350
+ }
351
+ );
352
+ }
353
+
354
+ // src/index.ts
355
+ function createServer() {
356
+ const server = new McpServer({
357
+ name: "sogo-db",
358
+ version: "0.1.0"
359
+ });
360
+ const ctx = createContext();
361
+ registerListDatabases(server, ctx);
362
+ registerGetDatabaseSchema(server, ctx);
363
+ registerListRecords(server, ctx);
364
+ registerCreateRecord(server, ctx);
365
+ registerUpdateRecord(server, ctx);
366
+ registerDeleteRecord(server, ctx);
367
+ registerSearchRecords(server, ctx);
368
+ registerResources(server, ctx);
369
+ return { server, ctx };
370
+ }
371
+ async function main() {
372
+ const { server } = createServer();
373
+ const transport = new StdioServerTransport();
374
+ await server.connect(transport);
375
+ }
376
+ main().catch((err) => {
377
+ console.error("sogo-mcp-server failed to start:", err);
378
+ process.exit(1);
379
+ });
380
+ export {
381
+ createServer
382
+ };
383
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/context.ts","../src/fieldResolver.ts","../src/tools/listDatabases.ts","../src/tools/getDatabaseSchema.ts","../src/tools/listRecords.ts","../src/tools/createRecord.ts","../src/tools/updateRecord.ts","../src/tools/deleteRecord.ts","../src/tools/searchRecords.ts","../src/resources.ts"],"sourcesContent":["/**\n * ---\n * @anchor: .patterns/mcp-tool\n * @spec: specs/mcp-server.md#server-setup\n * @task: TASK-008\n * @validated: null\n * ---\n */\n\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { createContext } from './context.js';\nimport { registerListDatabases } from './tools/listDatabases.js';\nimport { registerGetDatabaseSchema } from './tools/getDatabaseSchema.js';\nimport { registerListRecords } from './tools/listRecords.js';\nimport { registerCreateRecord } from './tools/createRecord.js';\nimport { registerUpdateRecord } from './tools/updateRecord.js';\nimport { registerDeleteRecord } from './tools/deleteRecord.js';\nimport { registerSearchRecords } from './tools/searchRecords.js';\nimport { registerResources } from './resources.js';\n\nexport function createServer() {\n\tconst server = new McpServer({\n\t\tname: 'sogo-db',\n\t\tversion: '0.1.0',\n\t});\n\n\tconst ctx = createContext();\n\n\t// Register all tools\n\tregisterListDatabases(server, ctx);\n\tregisterGetDatabaseSchema(server, ctx);\n\tregisterListRecords(server, ctx);\n\tregisterCreateRecord(server, ctx);\n\tregisterUpdateRecord(server, ctx);\n\tregisterDeleteRecord(server, ctx);\n\tregisterSearchRecords(server, ctx);\n\n\t// Register resources\n\tregisterResources(server, ctx);\n\n\treturn { server, ctx };\n}\n\nasync function main() {\n\tconst { server } = createServer();\n\tconst transport = new StdioServerTransport();\n\tawait server.connect(transport);\n}\n\nmain().catch(err => {\n\tconsole.error('sogo-mcp-server failed to start:', err);\n\tprocess.exit(1);\n});\n","/**\n * ---\n * @anchor: .patterns/mcp-tool\n * @spec: specs/mcp-server.md#server-setup\n * @task: TASK-008\n * @validated: null\n * ---\n */\n\nimport { homedir } from 'node:os';\nimport { scanAll, readDatabaseFile, writeDatabaseFile, getGlobalDatabasePath } from 'sogo-db-core';\nimport type { Database } from 'sogo-db-core';\n\nexport interface ServerContext {\n\tglobalPath: string;\n\tworkspacePath: string;\n\tscanDepth: number;\n}\n\nfunction expandTilde(p: string): string {\n\treturn p.startsWith('~') ? p.replace('~', homedir()) : p;\n}\n\nexport function createContext(): ServerContext {\n\tconst raw = process.env.SOGO_GLOBAL_PATH;\n\treturn {\n\t\tglobalPath: raw ? expandTilde(raw) : getGlobalDatabasePath(),\n\t\tworkspacePath: expandTilde(process.env.SOGO_WORKSPACE_PATH ?? process.cwd()),\n\t\tscanDepth: parseInt(process.env.SOGO_SCAN_DEPTH ?? '3', 10),\n\t};\n}\n\nexport interface DatabaseEntry {\n\tdb: Database;\n\tpath: string;\n\tscope: 'global' | 'workspace';\n}\n\nexport async function loadAllDatabases(ctx: ServerContext): Promise<DatabaseEntry[]> {\n\treturn scanAll(ctx.workspacePath, ctx.globalPath, ctx.scanDepth);\n}\n\nexport async function findDatabase(\n\tctx: ServerContext,\n\tidOrName: string,\n): Promise<DatabaseEntry | undefined> {\n\tconst all = await loadAllDatabases(ctx);\n\t// Try exact ID match first\n\tconst byId = all.find(e => e.db.id === idOrName);\n\tif (byId) return byId;\n\t// Then case-insensitive name match\n\tconst lower = idOrName.toLowerCase();\n\treturn all.find(e => e.db.name.toLowerCase() === lower)\n\t\t?? all.find(e => e.db.name.toLowerCase().includes(lower));\n}\n\nexport async function reloadDatabase(entry: DatabaseEntry): Promise<Database> {\n\treturn readDatabaseFile(entry.path);\n}\n\nexport async function saveDatabase(db: Database, path: string): Promise<void> {\n\tawait writeDatabaseFile(db, path);\n}\n","/**\n * ---\n * @anchor: .patterns/mcp-tool\n * @spec: specs/mcp-server.md#field-name-resolution\n * @task: TASK-013\n * @validated: null\n * ---\n */\n\nimport type { Database, DBRecord, Field } from 'sogo-db-core';\n\n/**\n * Resolve a field name (case-insensitive) to a Field object.\n * Throws if not found or ambiguous.\n */\nexport function resolveField(schema: Field[], name: string): Field {\n\tconst lower = name.toLowerCase();\n\tconst matches = schema.filter(f => f.name.toLowerCase() === lower);\n\tif (matches.length === 1) return matches[0];\n\tif (matches.length > 1) {\n\t\tthrow new Error(`Ambiguous field name \"${name}\" — matches: ${matches.map(f => f.name).join(', ')}`);\n\t}\n\t// Try partial match\n\tconst partial = schema.filter(f => f.name.toLowerCase().includes(lower));\n\tif (partial.length === 1) return partial[0];\n\tthrow new Error(`Field \"${name}\" not found. Available: ${schema.map(f => f.name).join(', ')}`);\n}\n\n/**\n * Convert a record from field-ID keys to field-name keys.\n */\nexport function recordToNamedFields(record: DBRecord, schema: Field[]): Record<string, unknown> {\n\tconst result: Record<string, unknown> = { id: record.id };\n\tfor (const field of schema) {\n\t\tconst val = record[field.id];\n\t\tif (val !== undefined) result[field.name] = val;\n\t}\n\tif (record._body !== undefined) result._body = record._body;\n\treturn result;\n}\n\n/**\n * Convert field-name keys to field-ID keys for a record.\n */\nexport function namedFieldsToRecord(\n\tvalues: Record<string, unknown>,\n\tschema: Field[],\n): Record<string, unknown> {\n\tconst result: Record<string, unknown> = {};\n\tfor (const [key, val] of Object.entries(values)) {\n\t\tif (key === 'id' || key === '_body') {\n\t\t\tresult[key] = val;\n\t\t\tcontinue;\n\t\t}\n\t\tconst field = resolveField(schema, key);\n\t\tresult[field.id] = val;\n\t}\n\treturn result;\n}\n\n/**\n * Build a summary of a database for listing.\n */\nexport function databaseSummary(db: Database, scope: string) {\n\treturn {\n\t\tid: db.id,\n\t\tname: db.name,\n\t\tscope,\n\t\tfields: db.schema.map(f => ({ name: f.name, type: f.type })),\n\t\trecordCount: db.records.length,\n\t\tviews: db.views.map(v => ({ name: v.name, type: v.type })),\n\t};\n}\n","/**\n * ---\n * @anchor: .patterns/mcp-tool\n * @spec: specs/mcp-server.md#tool-list_databases\n * @task: TASK-008\n * @validated: null\n * ---\n */\n\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { z } from 'zod';\nimport type { ServerContext } from '../context.js';\nimport { loadAllDatabases } from '../context.js';\nimport { databaseSummary } from '../fieldResolver.js';\n\nexport function registerListDatabases(server: McpServer, ctx: ServerContext) {\n\tserver.tool('list_databases', 'List all databases (global + workspace) with schemas', {}, async () => {\n\t\tconst entries = await loadAllDatabases(ctx);\n\t\tconst results = entries.map(e => databaseSummary(e.db, e.scope));\n\t\treturn { content: [{ type: 'text', text: JSON.stringify(results, null, 2) }] };\n\t});\n}\n","/**\n * ---\n * @anchor: .patterns/mcp-tool\n * @spec: specs/mcp-server.md#tool-get_database_schema\n * @task: TASK-008\n * @validated: null\n * ---\n */\n\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { z } from 'zod';\nimport type { ServerContext } from '../context.js';\nimport { findDatabase } from '../context.js';\n\nexport function registerGetDatabaseSchema(server: McpServer, ctx: ServerContext) {\n\tserver.tool(\n\t\t'get_database_schema',\n\t\t'Get field definitions and views for a database',\n\t\t{ database: z.string().describe('Database ID or name (fuzzy match)') },\n\t\tasync ({ database }) => {\n\t\t\tconst entry = await findDatabase(ctx, database);\n\t\t\tif (!entry) {\n\t\t\t\treturn { content: [{ type: 'text', text: JSON.stringify({ error: `Database \"${database}\" not found` }) }] };\n\t\t\t}\n\t\t\tconst result = {\n\t\t\t\tid: entry.db.id,\n\t\t\t\tname: entry.db.name,\n\t\t\t\tscope: entry.scope,\n\t\t\t\tfields: entry.db.schema.map(f => ({\n\t\t\t\t\tname: f.name,\n\t\t\t\t\ttype: f.type,\n\t\t\t\t\toptions: f.options,\n\t\t\t\t\trelation: f.relation,\n\t\t\t\t\trollup: f.rollup,\n\t\t\t\t\tformula: f.formula,\n\t\t\t\t})),\n\t\t\t\tviews: entry.db.views.map(v => ({\n\t\t\t\t\tname: v.name,\n\t\t\t\t\ttype: v.type,\n\t\t\t\t\tgroupBy: v.groupBy ? entry.db.schema.find(f => f.id === v.groupBy)?.name : undefined,\n\t\t\t\t})),\n\t\t\t};\n\t\t\treturn { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };\n\t\t},\n\t);\n}\n","/**\n * ---\n * @anchor: .patterns/mcp-tool\n * @spec: specs/mcp-server.md#tool-list_records\n * @task: TASK-009\n * @validated: null\n * ---\n */\n\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { z } from 'zod';\nimport { applySorts, applyFilters } from 'sogo-db-core';\nimport type { ServerContext } from '../context.js';\nimport { findDatabase } from '../context.js';\nimport { resolveField, recordToNamedFields } from '../fieldResolver.js';\n\nexport function registerListRecords(server: McpServer, ctx: ServerContext) {\n\tserver.tool(\n\t\t'list_records',\n\t\t'List records with optional filter, sort, and pagination',\n\t\t{\n\t\t\tdatabase: z.string().describe('Database ID or name'),\n\t\t\tfilter: z.array(z.object({\n\t\t\t\tfield: z.string(),\n\t\t\t\top: z.string(),\n\t\t\t\tvalue: z.string(),\n\t\t\t})).optional().describe('Filters by field name'),\n\t\t\tsort: z.array(z.object({\n\t\t\t\tfield: z.string(),\n\t\t\t\tdirection: z.enum(['asc', 'desc']),\n\t\t\t})).optional().describe('Sort by field name'),\n\t\t\tpage: z.number().int().min(1).optional().default(1),\n\t\t\tpageSize: z.number().int().min(1).max(200).optional().default(50),\n\t\t},\n\t\tasync ({ database, filter, sort, page, pageSize }) => {\n\t\t\tconst entry = await findDatabase(ctx, database);\n\t\t\tif (!entry) {\n\t\t\t\treturn { content: [{ type: 'text', text: JSON.stringify({ error: `Database \"${database}\" not found` }) }] };\n\t\t\t}\n\t\t\tconst { db } = entry;\n\t\t\tlet records = db.records;\n\n\t\t\tif (filter?.length) {\n\t\t\t\tconst resolvedFilters = filter.map(f => ({\n\t\t\t\t\tfieldId: resolveField(db.schema, f.field).id,\n\t\t\t\t\top: f.op,\n\t\t\t\t\tvalue: f.value,\n\t\t\t\t}));\n\t\t\t\trecords = applyFilters(records, resolvedFilters, db.schema, db);\n\t\t\t}\n\n\t\t\tif (sort?.length) {\n\t\t\t\tconst resolvedSorts = sort.map(s => ({\n\t\t\t\t\tfieldId: resolveField(db.schema, s.field).id,\n\t\t\t\t\tdirection: s.direction as 'asc' | 'desc',\n\t\t\t\t}));\n\t\t\t\trecords = applySorts(records, resolvedSorts, db.schema, db);\n\t\t\t}\n\n\t\t\tconst total = records.length;\n\t\t\tconst start = (page - 1) * pageSize;\n\t\t\tconst paged = records.slice(start, start + pageSize);\n\t\t\tconst namedRecords = paged.map(r => recordToNamedFields(r, db.schema));\n\n\t\t\treturn {\n\t\t\t\tcontent: [{\n\t\t\t\t\ttype: 'text',\n\t\t\t\t\ttext: JSON.stringify({\n\t\t\t\t\t\tdatabase: db.name,\n\t\t\t\t\t\ttotal,\n\t\t\t\t\t\tpage,\n\t\t\t\t\t\tpageSize,\n\t\t\t\t\t\trecords: namedRecords,\n\t\t\t\t\t}, null, 2),\n\t\t\t\t}],\n\t\t\t};\n\t\t},\n\t);\n}\n","/**\n * ---\n * @anchor: .patterns/mcp-tool\n * @spec: specs/mcp-server.md#tool-create_record\n * @task: TASK-010\n * @validated: null\n * ---\n */\n\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { z } from 'zod';\nimport type { DBRecord } from 'sogo-db-core';\nimport type { ServerContext } from '../context.js';\nimport { findDatabase, saveDatabase } from '../context.js';\nimport { namedFieldsToRecord, recordToNamedFields } from '../fieldResolver.js';\n\nexport function registerCreateRecord(server: McpServer, ctx: ServerContext) {\n\tserver.tool(\n\t\t'create_record',\n\t\t'Create a new record using field names',\n\t\t{\n\t\t\tdatabase: z.string().describe('Database ID or name'),\n\t\t\tvalues: z.record(z.unknown()).describe('Field values by name'),\n\t\t},\n\t\tasync ({ database, values }) => {\n\t\t\tconst entry = await findDatabase(ctx, database);\n\t\t\tif (!entry) {\n\t\t\t\treturn { content: [{ type: 'text', text: JSON.stringify({ error: `Database \"${database}\" not found` }) }] };\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst resolved = namedFieldsToRecord(values, entry.db.schema);\n\t\t\t\tconst record: DBRecord = {\n\t\t\t\t\tid: crypto.randomUUID(),\n\t\t\t\t\t...resolved,\n\t\t\t\t} as DBRecord;\n\n\t\t\t\tentry.db.records.push(record);\n\t\t\t\tawait saveDatabase(entry.db, entry.path);\n\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{\n\t\t\t\t\t\ttype: 'text',\n\t\t\t\t\t\ttext: JSON.stringify({\n\t\t\t\t\t\t\tcreated: recordToNamedFields(record, entry.db.schema),\n\t\t\t\t\t\t}, null, 2),\n\t\t\t\t\t}],\n\t\t\t\t};\n\t\t\t} catch (err) {\n\t\t\t\treturn { content: [{ type: 'text', text: JSON.stringify({ error: String(err) }) }] };\n\t\t\t}\n\t\t},\n\t);\n}\n","/**\n * ---\n * @anchor: .patterns/mcp-tool\n * @spec: specs/mcp-server.md#tool-update_record\n * @task: TASK-010\n * @validated: null\n * ---\n */\n\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { z } from 'zod';\nimport type { ServerContext } from '../context.js';\nimport { findDatabase, saveDatabase } from '../context.js';\nimport { namedFieldsToRecord, recordToNamedFields } from '../fieldResolver.js';\n\nexport function registerUpdateRecord(server: McpServer, ctx: ServerContext) {\n\tserver.tool(\n\t\t'update_record',\n\t\t'Update specific fields of a record by name',\n\t\t{\n\t\t\tdatabase: z.string().describe('Database ID or name'),\n\t\t\trecordId: z.string().describe('Record ID'),\n\t\t\tvalues: z.record(z.unknown()).describe('Field values by name to update'),\n\t\t},\n\t\tasync ({ database, recordId, values }) => {\n\t\t\tconst entry = await findDatabase(ctx, database);\n\t\t\tif (!entry) {\n\t\t\t\treturn { content: [{ type: 'text', text: JSON.stringify({ error: `Database \"${database}\" not found` }) }] };\n\t\t\t}\n\n\t\t\tconst record = entry.db.records.find(r => r.id === recordId);\n\t\t\tif (!record) {\n\t\t\t\treturn { content: [{ type: 'text', text: JSON.stringify({ error: `Record \"${recordId}\" not found` }) }] };\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst resolved = namedFieldsToRecord(values, entry.db.schema);\n\t\t\t\tfor (const [key, val] of Object.entries(resolved)) {\n\t\t\t\t\tif (key !== 'id') (record as Record<string, unknown>)[key] = val;\n\t\t\t\t}\n\t\t\t\tawait saveDatabase(entry.db, entry.path);\n\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{\n\t\t\t\t\t\ttype: 'text',\n\t\t\t\t\t\ttext: JSON.stringify({\n\t\t\t\t\t\t\tupdated: recordToNamedFields(record, entry.db.schema),\n\t\t\t\t\t\t}, null, 2),\n\t\t\t\t\t}],\n\t\t\t\t};\n\t\t\t} catch (err) {\n\t\t\t\treturn { content: [{ type: 'text', text: JSON.stringify({ error: String(err) }) }] };\n\t\t\t}\n\t\t},\n\t);\n}\n","/**\n * ---\n * @anchor: .patterns/mcp-tool\n * @spec: specs/mcp-server.md#tool-delete_record\n * @task: TASK-010\n * @validated: null\n * ---\n */\n\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { z } from 'zod';\nimport type { ServerContext } from '../context.js';\nimport { findDatabase, saveDatabase } from '../context.js';\n\nexport function registerDeleteRecord(server: McpServer, ctx: ServerContext) {\n\tserver.tool(\n\t\t'delete_record',\n\t\t'Delete a record from a database',\n\t\t{\n\t\t\tdatabase: z.string().describe('Database ID or name'),\n\t\t\trecordId: z.string().describe('Record ID to delete'),\n\t\t},\n\t\tasync ({ database, recordId }) => {\n\t\t\tconst entry = await findDatabase(ctx, database);\n\t\t\tif (!entry) {\n\t\t\t\treturn { content: [{ type: 'text', text: JSON.stringify({ error: `Database \"${database}\" not found` }) }] };\n\t\t\t}\n\n\t\t\tconst index = entry.db.records.findIndex(r => r.id === recordId);\n\t\t\tif (index === -1) {\n\t\t\t\treturn { content: [{ type: 'text', text: JSON.stringify({ error: `Record \"${recordId}\" not found` }) }] };\n\t\t\t}\n\n\t\t\tentry.db.records.splice(index, 1);\n\t\t\tawait saveDatabase(entry.db, entry.path);\n\n\t\t\treturn {\n\t\t\t\tcontent: [{\n\t\t\t\t\ttype: 'text',\n\t\t\t\t\ttext: JSON.stringify({ deleted: recordId, database: entry.db.name }),\n\t\t\t\t}],\n\t\t\t};\n\t\t},\n\t);\n}\n","/**\n * ---\n * @anchor: .patterns/mcp-tool\n * @spec: specs/mcp-server.md#tool-search_records\n * @task: TASK-011\n * @validated: null\n * ---\n */\n\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { z } from 'zod';\nimport type { ServerContext } from '../context.js';\nimport { findDatabase, loadAllDatabases } from '../context.js';\nimport { recordToNamedFields } from '../fieldResolver.js';\n\nexport function registerSearchRecords(server: McpServer, ctx: ServerContext) {\n\tserver.tool(\n\t\t'search_records',\n\t\t'Full-text search across databases',\n\t\t{\n\t\t\tquery: z.string().describe('Search query'),\n\t\t\tdatabase: z.string().optional().describe('Optional: limit to a specific database ID or name'),\n\t\t},\n\t\tasync ({ query, database }) => {\n\t\t\tconst lower = query.toLowerCase();\n\t\t\tconst entries = database\n\t\t\t\t? await findDatabase(ctx, database).then(e => e ? [e] : [])\n\t\t\t\t: await loadAllDatabases(ctx);\n\n\t\t\tconst results: Array<{ database: string; record: Record<string, unknown> }> = [];\n\n\t\t\tfor (const entry of entries) {\n\t\t\t\tconst { db } = entry;\n\t\t\t\tconst searchableFieldIds = db.schema\n\t\t\t\t\t.filter(f => ['text', 'select', 'status', 'multiselect', 'email', 'url', 'phone'].includes(f.type))\n\t\t\t\t\t.map(f => f.id);\n\n\t\t\t\tfor (const record of db.records) {\n\t\t\t\t\tconst matches = searchableFieldIds.some(fid => {\n\t\t\t\t\t\tconst val = record[fid];\n\t\t\t\t\t\tif (val === null || val === undefined) return false;\n\t\t\t\t\t\tconst str = Array.isArray(val) ? val.join(' ') : String(val);\n\t\t\t\t\t\treturn str.toLowerCase().includes(lower);\n\t\t\t\t\t});\n\t\t\t\t\tif (matches) {\n\t\t\t\t\t\tresults.push({\n\t\t\t\t\t\t\tdatabase: db.name,\n\t\t\t\t\t\t\trecord: recordToNamedFields(record, db.schema),\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tcontent: [{\n\t\t\t\t\ttype: 'text',\n\t\t\t\t\ttext: JSON.stringify({\n\t\t\t\t\t\tquery,\n\t\t\t\t\t\ttotal: results.length,\n\t\t\t\t\t\tresults: results.slice(0, 50),\n\t\t\t\t\t}, null, 2),\n\t\t\t\t}],\n\t\t\t};\n\t\t},\n\t);\n}\n","/**\n * ---\n * @anchor: .patterns/mcp-tool\n * @spec: specs/mcp-server.md#resources\n * @task: TASK-012\n * @validated: null\n * ---\n */\n\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { ServerContext } from './context.js';\nimport { loadAllDatabases, findDatabase } from './context.js';\nimport { databaseSummary, recordToNamedFields } from './fieldResolver.js';\n\nexport function registerResources(server: McpServer, ctx: ServerContext) {\n\t// sogo://databases — list all databases\n\tserver.resource(\n\t\t'databases',\n\t\t'sogo://databases',\n\t\t{ description: 'List all databases', mimeType: 'application/json' },\n\t\tasync () => {\n\t\t\tconst entries = await loadAllDatabases(ctx);\n\t\t\tconst summaries = entries.map(e => databaseSummary(e.db, e.scope));\n\t\t\treturn { contents: [{ uri: 'sogo://databases', text: JSON.stringify(summaries, null, 2), mimeType: 'application/json' }] };\n\t\t},\n\t);\n}\n"],"mappings":"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","names":["z","z","z","z","z","z","z","z","z","z"]}
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "sogo-mcp-server",
3
+ "version": "0.1.0",
4
+ "description": "MCP server for Sogo DB — AI agent access to Notion-style .db.json databases",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "author": "DataRM",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/shucho/sogo-db.git",
11
+ "directory": "packages/mcp-server"
12
+ },
13
+ "homepage": "https://github.com/shucho/sogo-db#readme",
14
+ "keywords": [
15
+ "mcp",
16
+ "model-context-protocol",
17
+ "database",
18
+ "notion",
19
+ "ai",
20
+ "agent",
21
+ "claude"
22
+ ],
23
+ "main": "dist/index.js",
24
+ "types": "dist/index.d.ts",
25
+ "bin": {
26
+ "sogo-mcp-server": "bin/sogo-mcp-server.js"
27
+ },
28
+ "exports": {
29
+ ".": {
30
+ "import": "./dist/index.js",
31
+ "types": "./dist/index.d.ts"
32
+ }
33
+ },
34
+ "files": [
35
+ "dist",
36
+ "bin"
37
+ ],
38
+ "dependencies": {
39
+ "@modelcontextprotocol/sdk": "^1.12.0",
40
+ "zod": "^3.24.0",
41
+ "sogo-db-core": "0.1.0"
42
+ },
43
+ "devDependencies": {
44
+ "@types/node": "^22.0.0",
45
+ "tsup": "^8.0.0",
46
+ "typescript": "^5.7.0",
47
+ "vitest": "^3.0.0"
48
+ },
49
+ "scripts": {
50
+ "build": "tsup",
51
+ "dev": "tsup --watch",
52
+ "test": "vitest run",
53
+ "typecheck": "tsc --noEmit",
54
+ "lint": "tsc --noEmit"
55
+ }
56
+ }