@jsondb-cloud/mcp 1.0.9 → 1.0.12

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 CHANGED
@@ -5,7 +5,11 @@ The official MCP (Model Context Protocol) server for [jsondb.cloud](https://json
5
5
  [![npm version](https://img.shields.io/npm/v/@jsondb-cloud/mcp)](https://www.npmjs.com/package/@jsondb-cloud/mcp)
6
6
  [![npm downloads](https://img.shields.io/npm/dm/@jsondb-cloud/mcp)](https://www.npmjs.com/package/@jsondb-cloud/mcp)
7
7
  [![CI](https://github.com/JsonDBCloud/mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/JsonDBCloud/mcp/actions)
8
- [![Node.js](https://img.shields.io/badge/node-%3E%3D18-brightgreen)](https://nodejs.org)
8
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5-blue)](https://www.typescriptlang.org/)
9
+ [![Node.js](https://img.shields.io/badge/node-%3E%3D20-brightgreen)](https://nodejs.org)
10
+ [![Bundle size](https://img.shields.io/bundlephobia/min/@jsondb-cloud/mcp)](https://bundlephobia.com/package/@jsondb-cloud/mcp)
11
+ [![GitHub stars](https://img.shields.io/github/stars/JsonDBCloud/mcp)](https://github.com/JsonDBCloud/mcp)
12
+ [![Last commit](https://img.shields.io/github/last-commit/JsonDBCloud/mcp)](https://github.com/JsonDBCloud/mcp)
9
13
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
10
14
 
11
15
  ## Install
@@ -77,64 +81,64 @@ Add to `.cursor/mcp.json`:
77
81
 
78
82
  ### Environment Variables
79
83
 
80
- | Variable | Required | Default | Description |
81
- |----------|----------|---------|-------------|
82
- | `JSONDB_API_KEY` | Yes | — | API key (`jdb_sk_live_...` or `jdb_sk_test_...`) |
83
- | `JSONDB_PROJECT` | No | `v1` | Project namespace |
84
- | `JSONDB_BASE_URL` | No | `https://api.jsondb.cloud` | API base URL |
84
+ | Variable | Required | Default | Description |
85
+ | ----------------- | -------- | -------------------------- | ------------------------------------------------ |
86
+ | `JSONDB_API_KEY` | Yes | — | API key (`jdb_sk_live_...` or `jdb_sk_test_...`) |
87
+ | `JSONDB_PROJECT` | No | `v1` | Project namespace |
88
+ | `JSONDB_BASE_URL` | No | `https://api.jsondb.cloud` | API base URL |
85
89
 
86
90
  ## Tools
87
91
 
88
92
  ### Documents
89
93
 
90
- | Tool | Description |
91
- |------|-------------|
92
- | `create_document` | Create a new document in a collection |
93
- | `get_document` | Read a single document by ID |
94
- | `list_documents` | List documents with filtering, sorting, and pagination |
95
- | `update_document` | Replace a document entirely |
96
- | `patch_document` | Partially update a document (merge patch) |
97
- | `delete_document` | Delete a document by ID |
98
- | `count_documents` | Count documents matching an optional filter |
99
- | `json_patch_document` | Apply RFC 6902 JSON Patch operations |
94
+ | Tool | Description |
95
+ | --------------------- | ------------------------------------------------------ |
96
+ | `create_document` | Create a new document in a collection |
97
+ | `get_document` | Read a single document by ID |
98
+ | `list_documents` | List documents with filtering, sorting, and pagination |
99
+ | `update_document` | Replace a document entirely |
100
+ | `patch_document` | Partially update a document (merge patch) |
101
+ | `delete_document` | Delete a document by ID |
102
+ | `count_documents` | Count documents matching an optional filter |
103
+ | `json_patch_document` | Apply RFC 6902 JSON Patch operations |
100
104
 
101
105
  ### Collections
102
106
 
103
- | Tool | Description |
104
- |------|-------------|
105
- | `list_collections` | List all collections in the current project |
106
- | `search_documents` | Search with advanced filters (`eq`, `gt`, `contains`, `in`, etc.) |
107
- | `import_documents` | Bulk import with conflict resolution (`fail`, `skip`, `overwrite`) |
108
- | `export_collection` | Export all documents as JSON |
107
+ | Tool | Description |
108
+ | ------------------- | ------------------------------------------------------------------ |
109
+ | `list_collections` | List all collections in the current project |
110
+ | `search_documents` | Search with advanced filters (`eq`, `gt`, `contains`, `in`, etc.) |
111
+ | `import_documents` | Bulk import with conflict resolution (`fail`, `skip`, `overwrite`) |
112
+ | `export_collection` | Export all documents as JSON |
109
113
 
110
114
  ### Schemas
111
115
 
112
- | Tool | Description |
113
- |------|-------------|
114
- | `get_schema` | Get the JSON Schema for a collection |
115
- | `set_schema` | Set a JSON Schema to enforce document structure |
116
- | `remove_schema` | Remove schema validation from a collection |
117
- | `validate_document` | Dry-run validate a document against the schema |
116
+ | Tool | Description |
117
+ | ------------------- | ----------------------------------------------- |
118
+ | `get_schema` | Get the JSON Schema for a collection |
119
+ | `set_schema` | Set a JSON Schema to enforce document structure |
120
+ | `remove_schema` | Remove schema validation from a collection |
121
+ | `validate_document` | Dry-run validate a document against the schema |
118
122
 
119
123
  ### Versions
120
124
 
121
- | Tool | Description |
122
- |------|-------------|
123
- | `list_versions` | List all stored versions of a document |
124
- | `get_version` | Retrieve a specific version snapshot |
125
- | `restore_version` | Restore a document to a previous version |
126
- | `diff_versions` | Compare two versions with a structured diff |
125
+ | Tool | Description |
126
+ | ----------------- | ------------------------------------------- |
127
+ | `list_versions` | List all stored versions of a document |
128
+ | `get_version` | Retrieve a specific version snapshot |
129
+ | `restore_version` | Restore a document to a previous version |
130
+ | `diff_versions` | Compare two versions with a structured diff |
127
131
 
128
132
  ### Webhooks
129
133
 
130
- | Tool | Description |
131
- |------|-------------|
132
- | `create_webhook` | Register a webhook for collection events |
133
- | `list_webhooks` | List all webhooks for a collection |
134
- | `get_webhook` | Get webhook details and recent delivery history |
135
- | `update_webhook` | Update webhook URL, events, or status |
136
- | `delete_webhook` | Delete a webhook |
137
- | `test_webhook` | Send a test event to verify delivery |
134
+ | Tool | Description |
135
+ | ---------------- | ----------------------------------------------- |
136
+ | `create_webhook` | Register a webhook for collection events |
137
+ | `list_webhooks` | List all webhooks for a collection |
138
+ | `get_webhook` | Get webhook details and recent delivery history |
139
+ | `update_webhook` | Update webhook URL, events, or status |
140
+ | `delete_webhook` | Delete a webhook |
141
+ | `test_webhook` | Send a test event to verify delivery |
138
142
 
139
143
  ## Documentation
140
144
 
@@ -142,12 +146,12 @@ Full documentation at [jsondb.cloud/docs](https://jsondb.cloud/docs).
142
146
 
143
147
  ## Related Packages
144
148
 
145
- | Package | Description |
146
- |---------|-------------|
147
- | [@jsondb-cloud/client](https://github.com/JsonDBCloud/node) | JavaScript/TypeScript SDK |
148
- | [@jsondb-cloud/mcp](https://github.com/JsonDBCloud/mcp) | MCP server for AI agents |
149
- | [@jsondb-cloud/cli](https://github.com/JsonDBCloud/cli) | CLI tool |
150
- | [jsondb-cloud](https://github.com/JsonDBCloud/python) (PyPI) | Python SDK |
149
+ | Package | Description |
150
+ | ------------------------------------------------------------ | ------------------------- |
151
+ | [@jsondb-cloud/client](https://github.com/JsonDBCloud/node) | JavaScript/TypeScript SDK |
152
+ | [@jsondb-cloud/mcp](https://github.com/JsonDBCloud/mcp) | MCP server for AI agents |
153
+ | [@jsondb-cloud/cli](https://github.com/JsonDBCloud/cli) | CLI tool |
154
+ | [jsondb-cloud](https://github.com/JsonDBCloud/python) (PyPI) | Python SDK |
151
155
 
152
156
  ## License
153
157
 
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
 
3
3
  // src/index.ts
4
- var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
4
+ var import_mcp2 = require("@modelcontextprotocol/sdk/server/mcp.js");
5
5
  var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
6
6
  var import_client = require("@jsondb-cloud/client");
7
7
 
@@ -30,9 +30,7 @@ function registerDocumentTools(server, db) {
30
30
  {
31
31
  collection: import_zod.z.string().describe("The collection name (e.g., 'users', 'posts', 'settings')"),
32
32
  data: import_zod.z.record(import_zod.z.string(), import_zod.z.any()).describe("The JSON document to store. Can contain any valid JSON."),
33
- id: import_zod.z.string().optional().describe(
34
- "Optional custom document ID. If not provided, an ID is auto-generated."
35
- )
33
+ id: import_zod.z.string().optional().describe("Optional custom document ID. If not provided, an ID is auto-generated.")
36
34
  },
37
35
  async ({ collection, data, id }) => {
38
36
  try {
@@ -107,9 +105,7 @@ function registerDocumentTools(server, db) {
107
105
  filter: import_zod.z.record(import_zod.z.string(), import_zod.z.any()).optional().describe(
108
106
  "Filter criteria. Keys are field names, values are match values. Use {field: {$gt: N}} for comparisons."
109
107
  ),
110
- sort: import_zod.z.string().optional().describe(
111
- "Field to sort by. Prefix with '-' for descending (e.g., '-$createdAt')"
112
- ),
108
+ sort: import_zod.z.string().optional().describe("Field to sort by. Prefix with '-' for descending (e.g., '-$createdAt')"),
113
109
  limit: import_zod.z.number().optional().describe("Max documents to return (default: 20, max: 100)"),
114
110
  offset: import_zod.z.number().optional().describe("Number of documents to skip for pagination"),
115
111
  select: import_zod.z.array(import_zod.z.string()).optional().describe(
@@ -143,9 +139,7 @@ function registerDocumentTools(server, db) {
143
139
  {
144
140
  collection: import_zod.z.string().describe("The collection name"),
145
141
  id: import_zod.z.string().describe("The document ID to replace"),
146
- data: import_zod.z.record(import_zod.z.string(), import_zod.z.any()).describe(
147
- "The complete new document data. This replaces all existing fields."
148
- )
142
+ data: import_zod.z.record(import_zod.z.string(), import_zod.z.any()).describe("The complete new document data. This replaces all existing fields.")
149
143
  },
150
144
  async ({ collection, id, data }) => {
151
145
  try {
@@ -379,7 +373,10 @@ function registerCollectionTools(server, db) {
379
373
  try {
380
374
  const apiKey = process.env.JSONDB_API_KEY || "";
381
375
  const project = process.env.JSONDB_PROJECT || process.env.JSONDB_NAMESPACE || "v1";
382
- const baseUrl = (process.env.JSONDB_BASE_URL || "https://api.jsondb.cloud").replace(/\/$/, "");
376
+ const baseUrl = (process.env.JSONDB_BASE_URL || "https://api.jsondb.cloud").replace(
377
+ /\/$/,
378
+ ""
379
+ );
383
380
  const res = await fetch(`${baseUrl}/${project}`, {
384
381
  headers: {
385
382
  Authorization: `Bearer ${apiKey}`,
@@ -388,7 +385,10 @@ function registerCollectionTools(server, db) {
388
385
  });
389
386
  if (!res.ok) {
390
387
  const body = await res.json().catch(() => ({}));
391
- throw { status: res.status, message: body.error || res.statusText };
388
+ throw {
389
+ status: res.status,
390
+ message: body.error || res.statusText
391
+ };
392
392
  }
393
393
  const data = await res.json();
394
394
  return success2(data);
@@ -409,26 +409,12 @@ function registerCollectionTools(server, db) {
409
409
  collection: import_zod2.z.string().describe("The collection name"),
410
410
  filters: import_zod2.z.array(
411
411
  import_zod2.z.object({
412
- field: import_zod2.z.string().describe(
413
- "Field path (supports dot notation for nested fields)"
414
- ),
415
- operator: import_zod2.z.enum([
416
- "eq",
417
- "neq",
418
- "gt",
419
- "gte",
420
- "lt",
421
- "lte",
422
- "contains",
423
- "in",
424
- "exists"
425
- ]).describe("Comparison operator"),
412
+ field: import_zod2.z.string().describe("Field path (supports dot notation for nested fields)"),
413
+ operator: import_zod2.z.enum(["eq", "neq", "gt", "gte", "lt", "lte", "contains", "in", "exists"]).describe("Comparison operator"),
426
414
  value: import_zod2.z.any().describe("Value to compare against")
427
415
  })
428
416
  ).describe("Array of filter conditions (combined with AND logic)"),
429
- sort: import_zod2.z.string().optional().describe(
430
- "Field to sort by. Prefix with '-' for descending (e.g., '-$createdAt')"
431
- ),
417
+ sort: import_zod2.z.string().optional().describe("Field to sort by. Prefix with '-' for descending (e.g., '-$createdAt')"),
432
418
  limit: import_zod2.z.number().optional().describe("Max documents to return (default: 20, max: 100)"),
433
419
  offset: import_zod2.z.number().optional().describe("Number of documents to skip for pagination")
434
420
  },
@@ -462,15 +448,16 @@ function registerCollectionTools(server, db) {
462
448
  onConflict: import_zod2.z.enum(["fail", "skip", "overwrite"]).optional().describe(
463
449
  "How to handle ID conflicts: 'fail' (default) rejects the batch, 'skip' ignores duplicates, 'overwrite' replaces existing documents"
464
450
  ),
465
- idField: import_zod2.z.string().optional().describe(
466
- "Field in each document to use as _id. If omitted, IDs are auto-generated."
467
- )
451
+ idField: import_zod2.z.string().optional().describe("Field in each document to use as _id. If omitted, IDs are auto-generated.")
468
452
  },
469
453
  async ({ collection, documents, onConflict, idField }) => {
470
454
  try {
471
455
  const apiKey = process.env.JSONDB_API_KEY || "";
472
456
  const project = process.env.JSONDB_PROJECT || process.env.JSONDB_NAMESPACE || "v1";
473
- const baseUrl = (process.env.JSONDB_BASE_URL || "https://api.jsondb.cloud").replace(/\/$/, "");
457
+ const baseUrl = (process.env.JSONDB_BASE_URL || "https://api.jsondb.cloud").replace(
458
+ /\/$/,
459
+ ""
460
+ );
474
461
  const params = new URLSearchParams();
475
462
  if (onConflict) params.set("onConflict", onConflict);
476
463
  if (idField) params.set("idField", idField);
@@ -532,7 +519,10 @@ function registerCollectionTools(server, db) {
532
519
  try {
533
520
  const apiKey = process.env.JSONDB_API_KEY || "";
534
521
  const project = process.env.JSONDB_PROJECT || process.env.JSONDB_NAMESPACE || "v1";
535
- const baseUrl = (process.env.JSONDB_BASE_URL || "https://api.jsondb.cloud").replace(/\/$/, "");
522
+ const baseUrl = (process.env.JSONDB_BASE_URL || "https://api.jsondb.cloud").replace(
523
+ /\/$/,
524
+ ""
525
+ );
536
526
  const params = new URLSearchParams();
537
527
  if (filter) {
538
528
  for (const [field, value] of Object.entries(filter)) {
@@ -753,10 +743,7 @@ function resolveEnv() {
753
743
  return {
754
744
  apiKey: process.env.JSONDB_API_KEY || "",
755
745
  project: process.env.JSONDB_PROJECT || process.env.JSONDB_NAMESPACE || "v1",
756
- baseUrl: (process.env.JSONDB_BASE_URL || "https://api.jsondb.cloud").replace(
757
- /\/$/,
758
- ""
759
- )
746
+ baseUrl: (process.env.JSONDB_BASE_URL || "https://api.jsondb.cloud").replace(/\/$/, "")
760
747
  };
761
748
  }
762
749
  async function versionFetch(url, apiKey, opts = {}) {
@@ -954,10 +941,7 @@ function resolveEnv2() {
954
941
  return {
955
942
  apiKey: process.env.JSONDB_API_KEY || "",
956
943
  project: process.env.JSONDB_PROJECT || process.env.JSONDB_NAMESPACE || "v1",
957
- baseUrl: (process.env.JSONDB_BASE_URL || "https://api.jsondb.cloud").replace(
958
- /\/$/,
959
- ""
960
- )
944
+ baseUrl: (process.env.JSONDB_BASE_URL || "https://api.jsondb.cloud").replace(/\/$/, "")
961
945
  };
962
946
  }
963
947
  async function webhookFetch(url, apiKey, method = "GET", body) {
@@ -982,11 +966,7 @@ async function webhookFetch(url, apiKey, method = "GET", body) {
982
966
  if (res.status === 204) return { ok: true };
983
967
  return res.json();
984
968
  }
985
- var webhookEventEnum = import_zod5.z.enum([
986
- "document.created",
987
- "document.updated",
988
- "document.deleted"
989
- ]);
969
+ var webhookEventEnum = import_zod5.z.enum(["document.created", "document.updated", "document.deleted"]);
990
970
  function registerWebhookTools(server, _db) {
991
971
  server.tool(
992
972
  "create_webhook",
@@ -1035,10 +1015,7 @@ function registerWebhookTools(server, _db) {
1035
1015
  async ({ collection }) => {
1036
1016
  try {
1037
1017
  const { apiKey, project, baseUrl } = resolveEnv2();
1038
- const data = await webhookFetch(
1039
- `${baseUrl}/${project}/${collection}/_webhooks`,
1040
- apiKey
1041
- );
1018
+ const data = await webhookFetch(`${baseUrl}/${project}/${collection}/_webhooks`, apiKey);
1042
1019
  return success5(data);
1043
1020
  } catch (err) {
1044
1021
  const e = err;
@@ -1093,7 +1070,14 @@ function registerWebhookTools(server, _db) {
1093
1070
  description: import_zod5.z.string().optional().describe("New description"),
1094
1071
  status: import_zod5.z.enum(["active", "disabled"]).optional().describe("Set to 'disabled' to pause delivery, 'active' to resume")
1095
1072
  },
1096
- async ({ collection, webhookId, url: webhookUrl, events, description, status: webhookStatus }) => {
1073
+ async ({
1074
+ collection,
1075
+ webhookId,
1076
+ url: webhookUrl,
1077
+ events,
1078
+ description,
1079
+ status: webhookStatus
1080
+ }) => {
1097
1081
  try {
1098
1082
  const { apiKey, project, baseUrl } = resolveEnv2();
1099
1083
  const body = {};
@@ -1194,12 +1178,12 @@ function registerWebhookTools(server, _db) {
1194
1178
  }
1195
1179
 
1196
1180
  // src/resources/collections.ts
1181
+ var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
1197
1182
  function registerCollectionResources(server, db) {
1198
1183
  server.resource(
1199
1184
  "collections-list",
1200
1185
  "jsondb://collections",
1201
1186
  {
1202
- name: "jsondb.cloud Collections",
1203
1187
  description: "List of all collections in the current project. Use this to discover what data is available.",
1204
1188
  mimeType: "application/json"
1205
1189
  },
@@ -1207,7 +1191,10 @@ function registerCollectionResources(server, db) {
1207
1191
  try {
1208
1192
  const apiKey = process.env.JSONDB_API_KEY || "";
1209
1193
  const project = process.env.JSONDB_PROJECT || process.env.JSONDB_NAMESPACE || "v1";
1210
- const baseUrl = (process.env.JSONDB_BASE_URL || "https://api.jsondb.cloud").replace(/\/$/, "");
1194
+ const baseUrl = (process.env.JSONDB_BASE_URL || "https://api.jsondb.cloud").replace(
1195
+ /\/$/,
1196
+ ""
1197
+ );
1211
1198
  const res = await fetch(`${baseUrl}/${project}`, {
1212
1199
  headers: {
1213
1200
  Authorization: `Bearer ${apiKey}`,
@@ -1246,11 +1233,7 @@ function registerCollectionResources(server, db) {
1246
1233
  {
1247
1234
  uri: "jsondb://collections",
1248
1235
  mimeType: "application/json",
1249
- text: JSON.stringify(
1250
- { error: e.message || "Failed to fetch collections" },
1251
- null,
1252
- 2
1253
- )
1236
+ text: JSON.stringify({ error: e.message || "Failed to fetch collections" }, null, 2)
1254
1237
  }
1255
1238
  ]
1256
1239
  };
@@ -1259,14 +1242,13 @@ function registerCollectionResources(server, db) {
1259
1242
  );
1260
1243
  server.resource(
1261
1244
  "collection-schema",
1262
- "jsondb://collections/{collection}/schema",
1245
+ new import_mcp.ResourceTemplate("jsondb://collections/{collection}/schema", { list: void 0 }),
1263
1246
  {
1264
- name: "Collection Schema",
1265
1247
  description: "JSON Schema for a specific collection (if set). Helps AI agents understand the expected document structure.",
1266
1248
  mimeType: "application/json"
1267
1249
  },
1268
- async (uri, params) => {
1269
- const collection = typeof params.collection === "string" ? params.collection : String(params.collection);
1250
+ async (uri, variables) => {
1251
+ const collection = typeof variables.collection === "string" ? variables.collection : String(variables.collection);
1270
1252
  try {
1271
1253
  const coll = db.collection(collection);
1272
1254
  const schema = await coll.getSchema();
@@ -1322,7 +1304,7 @@ async function main() {
1322
1304
  project,
1323
1305
  baseUrl
1324
1306
  });
1325
- const server = new import_mcp.McpServer({
1307
+ const server = new import_mcp2.McpServer({
1326
1308
  name: "jsondb-cloud",
1327
1309
  version: "1.0.0"
1328
1310
  });
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/index.ts
2
- import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { McpServer as McpServer2 } from "@modelcontextprotocol/sdk/server/mcp.js";
3
3
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
4
  import { JsonDB } from "@jsondb-cloud/client";
5
5
 
@@ -28,9 +28,7 @@ function registerDocumentTools(server, db) {
28
28
  {
29
29
  collection: z.string().describe("The collection name (e.g., 'users', 'posts', 'settings')"),
30
30
  data: z.record(z.string(), z.any()).describe("The JSON document to store. Can contain any valid JSON."),
31
- id: z.string().optional().describe(
32
- "Optional custom document ID. If not provided, an ID is auto-generated."
33
- )
31
+ id: z.string().optional().describe("Optional custom document ID. If not provided, an ID is auto-generated.")
34
32
  },
35
33
  async ({ collection, data, id }) => {
36
34
  try {
@@ -105,9 +103,7 @@ function registerDocumentTools(server, db) {
105
103
  filter: z.record(z.string(), z.any()).optional().describe(
106
104
  "Filter criteria. Keys are field names, values are match values. Use {field: {$gt: N}} for comparisons."
107
105
  ),
108
- sort: z.string().optional().describe(
109
- "Field to sort by. Prefix with '-' for descending (e.g., '-$createdAt')"
110
- ),
106
+ sort: z.string().optional().describe("Field to sort by. Prefix with '-' for descending (e.g., '-$createdAt')"),
111
107
  limit: z.number().optional().describe("Max documents to return (default: 20, max: 100)"),
112
108
  offset: z.number().optional().describe("Number of documents to skip for pagination"),
113
109
  select: z.array(z.string()).optional().describe(
@@ -141,9 +137,7 @@ function registerDocumentTools(server, db) {
141
137
  {
142
138
  collection: z.string().describe("The collection name"),
143
139
  id: z.string().describe("The document ID to replace"),
144
- data: z.record(z.string(), z.any()).describe(
145
- "The complete new document data. This replaces all existing fields."
146
- )
140
+ data: z.record(z.string(), z.any()).describe("The complete new document data. This replaces all existing fields.")
147
141
  },
148
142
  async ({ collection, id, data }) => {
149
143
  try {
@@ -377,7 +371,10 @@ function registerCollectionTools(server, db) {
377
371
  try {
378
372
  const apiKey = process.env.JSONDB_API_KEY || "";
379
373
  const project = process.env.JSONDB_PROJECT || process.env.JSONDB_NAMESPACE || "v1";
380
- const baseUrl = (process.env.JSONDB_BASE_URL || "https://api.jsondb.cloud").replace(/\/$/, "");
374
+ const baseUrl = (process.env.JSONDB_BASE_URL || "https://api.jsondb.cloud").replace(
375
+ /\/$/,
376
+ ""
377
+ );
381
378
  const res = await fetch(`${baseUrl}/${project}`, {
382
379
  headers: {
383
380
  Authorization: `Bearer ${apiKey}`,
@@ -386,7 +383,10 @@ function registerCollectionTools(server, db) {
386
383
  });
387
384
  if (!res.ok) {
388
385
  const body = await res.json().catch(() => ({}));
389
- throw { status: res.status, message: body.error || res.statusText };
386
+ throw {
387
+ status: res.status,
388
+ message: body.error || res.statusText
389
+ };
390
390
  }
391
391
  const data = await res.json();
392
392
  return success2(data);
@@ -407,26 +407,12 @@ function registerCollectionTools(server, db) {
407
407
  collection: z2.string().describe("The collection name"),
408
408
  filters: z2.array(
409
409
  z2.object({
410
- field: z2.string().describe(
411
- "Field path (supports dot notation for nested fields)"
412
- ),
413
- operator: z2.enum([
414
- "eq",
415
- "neq",
416
- "gt",
417
- "gte",
418
- "lt",
419
- "lte",
420
- "contains",
421
- "in",
422
- "exists"
423
- ]).describe("Comparison operator"),
410
+ field: z2.string().describe("Field path (supports dot notation for nested fields)"),
411
+ operator: z2.enum(["eq", "neq", "gt", "gte", "lt", "lte", "contains", "in", "exists"]).describe("Comparison operator"),
424
412
  value: z2.any().describe("Value to compare against")
425
413
  })
426
414
  ).describe("Array of filter conditions (combined with AND logic)"),
427
- sort: z2.string().optional().describe(
428
- "Field to sort by. Prefix with '-' for descending (e.g., '-$createdAt')"
429
- ),
415
+ sort: z2.string().optional().describe("Field to sort by. Prefix with '-' for descending (e.g., '-$createdAt')"),
430
416
  limit: z2.number().optional().describe("Max documents to return (default: 20, max: 100)"),
431
417
  offset: z2.number().optional().describe("Number of documents to skip for pagination")
432
418
  },
@@ -460,15 +446,16 @@ function registerCollectionTools(server, db) {
460
446
  onConflict: z2.enum(["fail", "skip", "overwrite"]).optional().describe(
461
447
  "How to handle ID conflicts: 'fail' (default) rejects the batch, 'skip' ignores duplicates, 'overwrite' replaces existing documents"
462
448
  ),
463
- idField: z2.string().optional().describe(
464
- "Field in each document to use as _id. If omitted, IDs are auto-generated."
465
- )
449
+ idField: z2.string().optional().describe("Field in each document to use as _id. If omitted, IDs are auto-generated.")
466
450
  },
467
451
  async ({ collection, documents, onConflict, idField }) => {
468
452
  try {
469
453
  const apiKey = process.env.JSONDB_API_KEY || "";
470
454
  const project = process.env.JSONDB_PROJECT || process.env.JSONDB_NAMESPACE || "v1";
471
- const baseUrl = (process.env.JSONDB_BASE_URL || "https://api.jsondb.cloud").replace(/\/$/, "");
455
+ const baseUrl = (process.env.JSONDB_BASE_URL || "https://api.jsondb.cloud").replace(
456
+ /\/$/,
457
+ ""
458
+ );
472
459
  const params = new URLSearchParams();
473
460
  if (onConflict) params.set("onConflict", onConflict);
474
461
  if (idField) params.set("idField", idField);
@@ -530,7 +517,10 @@ function registerCollectionTools(server, db) {
530
517
  try {
531
518
  const apiKey = process.env.JSONDB_API_KEY || "";
532
519
  const project = process.env.JSONDB_PROJECT || process.env.JSONDB_NAMESPACE || "v1";
533
- const baseUrl = (process.env.JSONDB_BASE_URL || "https://api.jsondb.cloud").replace(/\/$/, "");
520
+ const baseUrl = (process.env.JSONDB_BASE_URL || "https://api.jsondb.cloud").replace(
521
+ /\/$/,
522
+ ""
523
+ );
534
524
  const params = new URLSearchParams();
535
525
  if (filter) {
536
526
  for (const [field, value] of Object.entries(filter)) {
@@ -751,10 +741,7 @@ function resolveEnv() {
751
741
  return {
752
742
  apiKey: process.env.JSONDB_API_KEY || "",
753
743
  project: process.env.JSONDB_PROJECT || process.env.JSONDB_NAMESPACE || "v1",
754
- baseUrl: (process.env.JSONDB_BASE_URL || "https://api.jsondb.cloud").replace(
755
- /\/$/,
756
- ""
757
- )
744
+ baseUrl: (process.env.JSONDB_BASE_URL || "https://api.jsondb.cloud").replace(/\/$/, "")
758
745
  };
759
746
  }
760
747
  async function versionFetch(url, apiKey, opts = {}) {
@@ -952,10 +939,7 @@ function resolveEnv2() {
952
939
  return {
953
940
  apiKey: process.env.JSONDB_API_KEY || "",
954
941
  project: process.env.JSONDB_PROJECT || process.env.JSONDB_NAMESPACE || "v1",
955
- baseUrl: (process.env.JSONDB_BASE_URL || "https://api.jsondb.cloud").replace(
956
- /\/$/,
957
- ""
958
- )
942
+ baseUrl: (process.env.JSONDB_BASE_URL || "https://api.jsondb.cloud").replace(/\/$/, "")
959
943
  };
960
944
  }
961
945
  async function webhookFetch(url, apiKey, method = "GET", body) {
@@ -980,11 +964,7 @@ async function webhookFetch(url, apiKey, method = "GET", body) {
980
964
  if (res.status === 204) return { ok: true };
981
965
  return res.json();
982
966
  }
983
- var webhookEventEnum = z5.enum([
984
- "document.created",
985
- "document.updated",
986
- "document.deleted"
987
- ]);
967
+ var webhookEventEnum = z5.enum(["document.created", "document.updated", "document.deleted"]);
988
968
  function registerWebhookTools(server, _db) {
989
969
  server.tool(
990
970
  "create_webhook",
@@ -1033,10 +1013,7 @@ function registerWebhookTools(server, _db) {
1033
1013
  async ({ collection }) => {
1034
1014
  try {
1035
1015
  const { apiKey, project, baseUrl } = resolveEnv2();
1036
- const data = await webhookFetch(
1037
- `${baseUrl}/${project}/${collection}/_webhooks`,
1038
- apiKey
1039
- );
1016
+ const data = await webhookFetch(`${baseUrl}/${project}/${collection}/_webhooks`, apiKey);
1040
1017
  return success5(data);
1041
1018
  } catch (err) {
1042
1019
  const e = err;
@@ -1091,7 +1068,14 @@ function registerWebhookTools(server, _db) {
1091
1068
  description: z5.string().optional().describe("New description"),
1092
1069
  status: z5.enum(["active", "disabled"]).optional().describe("Set to 'disabled' to pause delivery, 'active' to resume")
1093
1070
  },
1094
- async ({ collection, webhookId, url: webhookUrl, events, description, status: webhookStatus }) => {
1071
+ async ({
1072
+ collection,
1073
+ webhookId,
1074
+ url: webhookUrl,
1075
+ events,
1076
+ description,
1077
+ status: webhookStatus
1078
+ }) => {
1095
1079
  try {
1096
1080
  const { apiKey, project, baseUrl } = resolveEnv2();
1097
1081
  const body = {};
@@ -1192,12 +1176,12 @@ function registerWebhookTools(server, _db) {
1192
1176
  }
1193
1177
 
1194
1178
  // src/resources/collections.ts
1179
+ import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
1195
1180
  function registerCollectionResources(server, db) {
1196
1181
  server.resource(
1197
1182
  "collections-list",
1198
1183
  "jsondb://collections",
1199
1184
  {
1200
- name: "jsondb.cloud Collections",
1201
1185
  description: "List of all collections in the current project. Use this to discover what data is available.",
1202
1186
  mimeType: "application/json"
1203
1187
  },
@@ -1205,7 +1189,10 @@ function registerCollectionResources(server, db) {
1205
1189
  try {
1206
1190
  const apiKey = process.env.JSONDB_API_KEY || "";
1207
1191
  const project = process.env.JSONDB_PROJECT || process.env.JSONDB_NAMESPACE || "v1";
1208
- const baseUrl = (process.env.JSONDB_BASE_URL || "https://api.jsondb.cloud").replace(/\/$/, "");
1192
+ const baseUrl = (process.env.JSONDB_BASE_URL || "https://api.jsondb.cloud").replace(
1193
+ /\/$/,
1194
+ ""
1195
+ );
1209
1196
  const res = await fetch(`${baseUrl}/${project}`, {
1210
1197
  headers: {
1211
1198
  Authorization: `Bearer ${apiKey}`,
@@ -1244,11 +1231,7 @@ function registerCollectionResources(server, db) {
1244
1231
  {
1245
1232
  uri: "jsondb://collections",
1246
1233
  mimeType: "application/json",
1247
- text: JSON.stringify(
1248
- { error: e.message || "Failed to fetch collections" },
1249
- null,
1250
- 2
1251
- )
1234
+ text: JSON.stringify({ error: e.message || "Failed to fetch collections" }, null, 2)
1252
1235
  }
1253
1236
  ]
1254
1237
  };
@@ -1257,14 +1240,13 @@ function registerCollectionResources(server, db) {
1257
1240
  );
1258
1241
  server.resource(
1259
1242
  "collection-schema",
1260
- "jsondb://collections/{collection}/schema",
1243
+ new ResourceTemplate("jsondb://collections/{collection}/schema", { list: void 0 }),
1261
1244
  {
1262
- name: "Collection Schema",
1263
1245
  description: "JSON Schema for a specific collection (if set). Helps AI agents understand the expected document structure.",
1264
1246
  mimeType: "application/json"
1265
1247
  },
1266
- async (uri, params) => {
1267
- const collection = typeof params.collection === "string" ? params.collection : String(params.collection);
1248
+ async (uri, variables) => {
1249
+ const collection = typeof variables.collection === "string" ? variables.collection : String(variables.collection);
1268
1250
  try {
1269
1251
  const coll = db.collection(collection);
1270
1252
  const schema = await coll.getSchema();
@@ -1320,7 +1302,7 @@ async function main() {
1320
1302
  project,
1321
1303
  baseUrl
1322
1304
  });
1323
- const server = new McpServer({
1305
+ const server = new McpServer2({
1324
1306
  name: "jsondb-cloud",
1325
1307
  version: "1.0.0"
1326
1308
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsondb-cloud/mcp",
3
- "version": "1.0.9",
3
+ "version": "1.0.12",
4
4
  "description": "MCP (Model Context Protocol) server for jsondb.cloud — lets AI agents interact with your JSON database",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -20,17 +20,29 @@
20
20
  ],
21
21
  "scripts": {
22
22
  "build": "tsup src/index.ts --format cjs,esm --clean",
23
- "dev": "tsup src/index.ts --format cjs,esm --watch"
23
+ "dev": "tsup src/index.ts --format cjs,esm --watch",
24
+ "lint": "eslint src/",
25
+ "format:check": "prettier --check .",
26
+ "test": "vitest run",
27
+ "prepare": "husky"
24
28
  },
25
29
  "dependencies": {
26
- "@modelcontextprotocol/sdk": "^1.0.0",
27
30
  "@jsondb-cloud/client": "*",
31
+ "@modelcontextprotocol/sdk": "^1.0.0",
28
32
  "zod": "^3.23.0"
29
33
  },
30
34
  "devDependencies": {
35
+ "@types/node": "^20.0.0",
36
+ "@typescript-eslint/eslint-plugin": "^8.56.1",
37
+ "@typescript-eslint/parser": "^8.56.1",
38
+ "eslint": "^10.0.2",
39
+ "eslint-config-prettier": "^10.1.8",
40
+ "husky": "^9.1.7",
41
+ "lint-staged": "^16.2.7",
42
+ "prettier": "^3.8.1",
31
43
  "tsup": "^8.0.0",
32
44
  "typescript": "^5.4.0",
33
- "@types/node": "^20.0.0"
45
+ "vitest": "^4.0.18"
34
46
  },
35
47
  "keywords": [
36
48
  "jsondb",
@@ -48,6 +60,12 @@
48
60
  "url": "git+https://github.com/JsonDBCloud/mcp.git"
49
61
  },
50
62
  "engines": {
51
- "node": ">=18.0.0"
63
+ "node": ">=20.19.0"
64
+ },
65
+ "lint-staged": {
66
+ "src/**/*.ts": [
67
+ "prettier --write",
68
+ "eslint --fix"
69
+ ]
52
70
  }
53
71
  }