@topgunbuild/mcp-server 0.9.0 → 0.10.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.d.mts CHANGED
@@ -120,7 +120,7 @@ interface QueryToolArgs {
120
120
  order: 'asc' | 'desc';
121
121
  };
122
122
  limit?: number;
123
- offset?: number;
123
+ cursor?: string;
124
124
  }
125
125
  /**
126
126
  * Mutate tool arguments
@@ -347,6 +347,8 @@ declare function createHTTPServer(mcpServer: TopGunMCPServer, config?: HTTPServe
347
347
 
348
348
  /**
349
349
  * topgun_query - Query data from a TopGun map with filters
350
+ *
351
+ * Phase 14.1: Updated to use cursor-based pagination via QueryHandle.
350
352
  */
351
353
 
352
354
  declare const queryTool: MCPTool;
package/dist/index.d.ts CHANGED
@@ -120,7 +120,7 @@ interface QueryToolArgs {
120
120
  order: 'asc' | 'desc';
121
121
  };
122
122
  limit?: number;
123
- offset?: number;
123
+ cursor?: string;
124
124
  }
125
125
  /**
126
126
  * Mutate tool arguments
@@ -347,6 +347,8 @@ declare function createHTTPServer(mcpServer: TopGunMCPServer, config?: HTTPServe
347
347
 
348
348
  /**
349
349
  * topgun_query - Query data from a TopGun map with filters
350
+ *
351
+ * Phase 14.1: Updated to use cursor-based pagination via QueryHandle.
350
352
  */
351
353
 
352
354
  declare const queryTool: MCPTool;
package/dist/index.js CHANGED
@@ -23,7 +23,7 @@ var QueryArgsSchema = zod.z.object({
23
23
  order: zod.z.enum(["asc", "desc"]).describe("Sort order: ascending or descending")
24
24
  }).optional().describe("Sort configuration"),
25
25
  limit: zod.z.number().optional().default(10).describe("Maximum number of results to return"),
26
- offset: zod.z.number().optional().default(0).describe("Number of results to skip (for pagination)")
26
+ cursor: zod.z.string().optional().describe("Opaque cursor for pagination (from previous response nextCursor)")
27
27
  });
28
28
  var MutateArgsSchema = zod.z.object({
29
29
  map: zod.z.string().describe("Name of the map to modify (e.g., 'tasks', 'users')"),
@@ -77,7 +77,7 @@ var toolSchemas = {
77
77
  description: "Sort configuration"
78
78
  },
79
79
  limit: { type: "number", description: "Maximum number of results to return", default: 10 },
80
- offset: { type: "number", description: "Number of results to skip (for pagination)", default: 0 }
80
+ cursor: { type: "string", description: "Opaque cursor for pagination (from previous response nextCursor)" }
81
81
  },
82
82
  required: ["map"]
83
83
  },
@@ -167,7 +167,7 @@ var toolSchemas = {
167
167
  // src/tools/query.ts
168
168
  var queryTool = {
169
169
  name: "topgun_query",
170
- description: "Query data from a TopGun map with filters and sorting. Use this to read data from the database. Supports filtering by field values and sorting by any field.",
170
+ description: "Query data from a TopGun map with filters and sorting. Use this to read data from the database. Supports filtering by field values, sorting, and cursor-based pagination.",
171
171
  inputSchema: toolSchemas.query
172
172
  };
173
173
  async function handleQuery(rawArgs, ctx) {
@@ -179,7 +179,7 @@ async function handleQuery(rawArgs, ctx) {
179
179
  isError: true
180
180
  };
181
181
  }
182
- const { map, filter, sort, limit, offset } = parseResult.data;
182
+ const { map, filter, sort, limit, cursor } = parseResult.data;
183
183
  if (ctx.config.allowedMaps && !ctx.config.allowedMaps.includes(map)) {
184
184
  return {
185
185
  content: [
@@ -192,39 +192,26 @@ async function handleQuery(rawArgs, ctx) {
192
192
  };
193
193
  }
194
194
  const effectiveLimit = Math.min(limit ?? ctx.config.defaultLimit, ctx.config.maxLimit);
195
- const effectiveOffset = offset ?? 0;
196
195
  try {
197
- const lwwMap = ctx.client.getMap(map);
198
- const allEntries = [];
199
- for (const [key, value] of lwwMap.entries()) {
200
- if (value !== null && typeof value === "object") {
201
- let matches = true;
202
- if (filter) {
203
- for (const [filterKey, filterValue] of Object.entries(filter)) {
204
- if (value[filterKey] !== filterValue) {
205
- matches = false;
206
- break;
207
- }
208
- }
209
- }
210
- if (matches) {
211
- allEntries.push({ key: String(key), value });
212
- }
213
- }
214
- }
196
+ const queryFilter = {
197
+ where: filter,
198
+ limit: effectiveLimit
199
+ };
215
200
  if (sort?.field) {
216
- allEntries.sort((a, b) => {
217
- const aVal = a.value[sort.field];
218
- const bVal = b.value[sort.field];
219
- if (aVal === bVal) return 0;
220
- if (aVal === void 0 || aVal === null) return 1;
221
- if (bVal === void 0 || bVal === null) return -1;
222
- const comparison = aVal < bVal ? -1 : 1;
223
- return sort.order === "desc" ? -comparison : comparison;
224
- });
201
+ queryFilter.sort = { [sort.field]: sort.order };
225
202
  }
226
- const paginatedEntries = allEntries.slice(effectiveOffset, effectiveOffset + effectiveLimit);
227
- if (paginatedEntries.length === 0) {
203
+ if (cursor) {
204
+ queryFilter.cursor = cursor;
205
+ }
206
+ const handle = ctx.client.query(map, queryFilter);
207
+ const results = await new Promise((resolve) => {
208
+ const unsubscribe = handle.subscribe((data) => {
209
+ unsubscribe();
210
+ resolve(data);
211
+ });
212
+ });
213
+ const paginationInfo = handle.getPaginationInfo();
214
+ if (results.length === 0) {
228
215
  return {
229
216
  content: [
230
217
  {
@@ -234,17 +221,24 @@ async function handleQuery(rawArgs, ctx) {
234
221
  ]
235
222
  };
236
223
  }
237
- const formatted = paginatedEntries.map((entry, idx) => `${idx + 1 + effectiveOffset}. [${entry.key}]: ${JSON.stringify(entry.value, null, 2)}`).join("\n\n");
238
- const totalInfo = allEntries.length > effectiveLimit ? `
224
+ const formatted = results.map((entry, idx) => {
225
+ const { _key, ...value } = entry;
226
+ return `${idx + 1}. [${_key}]: ${JSON.stringify(value, null, 2)}`;
227
+ }).join("\n\n");
228
+ let paginationText = "";
229
+ if (paginationInfo.hasMore && paginationInfo.nextCursor) {
230
+ paginationText = `
239
231
 
240
- (Showing ${effectiveOffset + 1}-${effectiveOffset + paginatedEntries.length} of ${allEntries.length} total)` : "";
232
+ ---
233
+ More results available. Use cursor: "${paginationInfo.nextCursor}" to fetch next page.`;
234
+ }
241
235
  return {
242
236
  content: [
243
237
  {
244
238
  type: "text",
245
- text: `Found ${paginatedEntries.length} result(s) in map '${map}':
239
+ text: `Found ${results.length} result(s) in map '${map}':
246
240
 
247
- ${formatted}${totalInfo}`
241
+ ${formatted}${paginationText}`
248
242
  }
249
243
  ]
250
244
  };