@seatable/mcp-seatable 0.9.5

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.
Files changed (193) hide show
  1. package/.env.example +11 -0
  2. package/LICENSE +21 -0
  3. package/README.md +302 -0
  4. package/bin/seatable-mcp.cjs +20 -0
  5. package/dist/auth/tokenValidator.d.ts +10 -0
  6. package/dist/auth/tokenValidator.d.ts.map +1 -0
  7. package/dist/auth/tokenValidator.js +55 -0
  8. package/dist/auth/tokenValidator.js.map +1 -0
  9. package/dist/config/env.d.ts +67 -0
  10. package/dist/config/env.d.ts.map +1 -0
  11. package/dist/config/env.js +105 -0
  12. package/dist/config/env.js.map +1 -0
  13. package/dist/errors.d.ts +8 -0
  14. package/dist/errors.d.ts.map +1 -0
  15. package/dist/errors.js +28 -0
  16. package/dist/errors.js.map +1 -0
  17. package/dist/http/httpServer.d.ts +7 -0
  18. package/dist/http/httpServer.d.ts.map +1 -0
  19. package/dist/http/httpServer.js +211 -0
  20. package/dist/http/httpServer.js.map +1 -0
  21. package/dist/http/sseServer.d.ts +11 -0
  22. package/dist/http/sseServer.d.ts.map +1 -0
  23. package/dist/http/sseServer.js +154 -0
  24. package/dist/http/sseServer.js.map +1 -0
  25. package/dist/index.d.ts +13 -0
  26. package/dist/index.d.ts.map +1 -0
  27. package/dist/index.js +86 -0
  28. package/dist/index.js.map +1 -0
  29. package/dist/logger.d.ts +5 -0
  30. package/dist/logger.d.ts.map +1 -0
  31. package/dist/logger.js +34 -0
  32. package/dist/logger.js.map +1 -0
  33. package/dist/mcp/server.d.ts +52 -0
  34. package/dist/mcp/server.d.ts.map +1 -0
  35. package/dist/mcp/server.js +222 -0
  36. package/dist/mcp/server.js.map +1 -0
  37. package/dist/mcp/tools/addRow.d.ts +3 -0
  38. package/dist/mcp/tools/addRow.d.ts.map +1 -0
  39. package/dist/mcp/tools/addRow.js +23 -0
  40. package/dist/mcp/tools/addRow.js.map +1 -0
  41. package/dist/mcp/tools/addSelectOption.d.ts +3 -0
  42. package/dist/mcp/tools/addSelectOption.d.ts.map +1 -0
  43. package/dist/mcp/tools/addSelectOption.js +27 -0
  44. package/dist/mcp/tools/addSelectOption.js.map +1 -0
  45. package/dist/mcp/tools/appendRows.d.ts +3 -0
  46. package/dist/mcp/tools/appendRows.d.ts.map +1 -0
  47. package/dist/mcp/tools/appendRows.js +27 -0
  48. package/dist/mcp/tools/appendRows.js.map +1 -0
  49. package/dist/mcp/tools/attachFileToRow.d.ts +3 -0
  50. package/dist/mcp/tools/attachFileToRow.d.ts.map +1 -0
  51. package/dist/mcp/tools/attachFileToRow.js +42 -0
  52. package/dist/mcp/tools/attachFileToRow.js.map +1 -0
  53. package/dist/mcp/tools/bulkSetSelectOptions.d.ts +3 -0
  54. package/dist/mcp/tools/bulkSetSelectOptions.d.ts.map +1 -0
  55. package/dist/mcp/tools/bulkSetSelectOptions.js +49 -0
  56. package/dist/mcp/tools/bulkSetSelectOptions.js.map +1 -0
  57. package/dist/mcp/tools/deleteRow.d.ts +3 -0
  58. package/dist/mcp/tools/deleteRow.d.ts.map +1 -0
  59. package/dist/mcp/tools/deleteRow.js +22 -0
  60. package/dist/mcp/tools/deleteRow.js.map +1 -0
  61. package/dist/mcp/tools/echoArgs.d.ts +3 -0
  62. package/dist/mcp/tools/echoArgs.d.ts.map +1 -0
  63. package/dist/mcp/tools/echoArgs.js +14 -0
  64. package/dist/mcp/tools/echoArgs.js.map +1 -0
  65. package/dist/mcp/tools/findRows.d.ts +9 -0
  66. package/dist/mcp/tools/findRows.d.ts.map +1 -0
  67. package/dist/mcp/tools/findRows.js +255 -0
  68. package/dist/mcp/tools/findRows.js.map +1 -0
  69. package/dist/mcp/tools/getRow.d.ts +3 -0
  70. package/dist/mcp/tools/getRow.d.ts.map +1 -0
  71. package/dist/mcp/tools/getRow.js +18 -0
  72. package/dist/mcp/tools/getRow.js.map +1 -0
  73. package/dist/mcp/tools/getSchema.d.ts +3 -0
  74. package/dist/mcp/tools/getSchema.d.ts.map +1 -0
  75. package/dist/mcp/tools/getSchema.js +16 -0
  76. package/dist/mcp/tools/getSchema.js.map +1 -0
  77. package/dist/mcp/tools/linkRows.d.ts +3 -0
  78. package/dist/mcp/tools/linkRows.d.ts.map +1 -0
  79. package/dist/mcp/tools/linkRows.js +23 -0
  80. package/dist/mcp/tools/linkRows.js.map +1 -0
  81. package/dist/mcp/tools/listBases.d.ts +3 -0
  82. package/dist/mcp/tools/listBases.d.ts.map +1 -0
  83. package/dist/mcp/tools/listBases.js +16 -0
  84. package/dist/mcp/tools/listBases.js.map +1 -0
  85. package/dist/mcp/tools/listCollaborators.d.ts +3 -0
  86. package/dist/mcp/tools/listCollaborators.d.ts.map +1 -0
  87. package/dist/mcp/tools/listCollaborators.js +16 -0
  88. package/dist/mcp/tools/listCollaborators.js.map +1 -0
  89. package/dist/mcp/tools/listRows.d.ts +3 -0
  90. package/dist/mcp/tools/listRows.d.ts.map +1 -0
  91. package/dist/mcp/tools/listRows.js +20 -0
  92. package/dist/mcp/tools/listRows.js.map +1 -0
  93. package/dist/mcp/tools/listTables.d.ts +3 -0
  94. package/dist/mcp/tools/listTables.d.ts.map +1 -0
  95. package/dist/mcp/tools/listTables.js +19 -0
  96. package/dist/mcp/tools/listTables.js.map +1 -0
  97. package/dist/mcp/tools/manageColumns.d.ts +3 -0
  98. package/dist/mcp/tools/manageColumns.d.ts.map +1 -0
  99. package/dist/mcp/tools/manageColumns.js +44 -0
  100. package/dist/mcp/tools/manageColumns.js.map +1 -0
  101. package/dist/mcp/tools/manageTables.d.ts +3 -0
  102. package/dist/mcp/tools/manageTables.d.ts.map +1 -0
  103. package/dist/mcp/tools/manageTables.js +36 -0
  104. package/dist/mcp/tools/manageTables.js.map +1 -0
  105. package/dist/mcp/tools/pingSeatable.d.ts +3 -0
  106. package/dist/mcp/tools/pingSeatable.d.ts.map +1 -0
  107. package/dist/mcp/tools/pingSeatable.js +37 -0
  108. package/dist/mcp/tools/pingSeatable.js.map +1 -0
  109. package/dist/mcp/tools/querySql.d.ts +3 -0
  110. package/dist/mcp/tools/querySql.d.ts.map +1 -0
  111. package/dist/mcp/tools/querySql.js +28 -0
  112. package/dist/mcp/tools/querySql.js.map +1 -0
  113. package/dist/mcp/tools/searchRows.d.ts +3 -0
  114. package/dist/mcp/tools/searchRows.d.ts.map +1 -0
  115. package/dist/mcp/tools/searchRows.js +18 -0
  116. package/dist/mcp/tools/searchRows.js.map +1 -0
  117. package/dist/mcp/tools/types.d.ts +90 -0
  118. package/dist/mcp/tools/types.d.ts.map +1 -0
  119. package/dist/mcp/tools/types.js +2 -0
  120. package/dist/mcp/tools/types.js.map +1 -0
  121. package/dist/mcp/tools/unlinkRows.d.ts +3 -0
  122. package/dist/mcp/tools/unlinkRows.d.ts.map +1 -0
  123. package/dist/mcp/tools/unlinkRows.js +23 -0
  124. package/dist/mcp/tools/unlinkRows.js.map +1 -0
  125. package/dist/mcp/tools/updateRow.d.ts +3 -0
  126. package/dist/mcp/tools/updateRow.d.ts.map +1 -0
  127. package/dist/mcp/tools/updateRow.js +32 -0
  128. package/dist/mcp/tools/updateRow.js.map +1 -0
  129. package/dist/mcp/tools/uploadFile.d.ts +3 -0
  130. package/dist/mcp/tools/uploadFile.d.ts.map +1 -0
  131. package/dist/mcp/tools/uploadFile.js +29 -0
  132. package/dist/mcp/tools/uploadFile.js.map +1 -0
  133. package/dist/mcp/tools/upsertRows.d.ts +3 -0
  134. package/dist/mcp/tools/upsertRows.d.ts.map +1 -0
  135. package/dist/mcp/tools/upsertRows.js +55 -0
  136. package/dist/mcp/tools/upsertRows.js.map +1 -0
  137. package/dist/ratelimit/connectionCounter.d.ts +11 -0
  138. package/dist/ratelimit/connectionCounter.d.ts.map +1 -0
  139. package/dist/ratelimit/connectionCounter.js +27 -0
  140. package/dist/ratelimit/connectionCounter.js.map +1 -0
  141. package/dist/ratelimit/index.d.ts +27 -0
  142. package/dist/ratelimit/index.d.ts.map +1 -0
  143. package/dist/ratelimit/index.js +50 -0
  144. package/dist/ratelimit/index.js.map +1 -0
  145. package/dist/ratelimit/rateLimiter.d.ts +18 -0
  146. package/dist/ratelimit/rateLimiter.d.ts.map +1 -0
  147. package/dist/ratelimit/rateLimiter.js +54 -0
  148. package/dist/ratelimit/rateLimiter.js.map +1 -0
  149. package/dist/schema/generic.d.ts +126 -0
  150. package/dist/schema/generic.d.ts.map +1 -0
  151. package/dist/schema/generic.js +45 -0
  152. package/dist/schema/generic.js.map +1 -0
  153. package/dist/schema/jsonSchemaToZod.d.ts +3 -0
  154. package/dist/schema/jsonSchemaToZod.d.ts.map +1 -0
  155. package/dist/schema/jsonSchemaToZod.js +53 -0
  156. package/dist/schema/jsonSchemaToZod.js.map +1 -0
  157. package/dist/schema/map.d.ts +3 -0
  158. package/dist/schema/map.d.ts.map +1 -0
  159. package/dist/schema/map.js +92 -0
  160. package/dist/schema/map.js.map +1 -0
  161. package/dist/schema/validate.d.ts +15 -0
  162. package/dist/schema/validate.d.ts.map +1 -0
  163. package/dist/schema/validate.js +170 -0
  164. package/dist/schema/validate.js.map +1 -0
  165. package/dist/seatable/client.d.ts +106 -0
  166. package/dist/seatable/client.d.ts.map +1 -0
  167. package/dist/seatable/client.js +378 -0
  168. package/dist/seatable/client.js.map +1 -0
  169. package/dist/seatable/clientRegistry.d.ts +11 -0
  170. package/dist/seatable/clientRegistry.d.ts.map +1 -0
  171. package/dist/seatable/clientRegistry.js +33 -0
  172. package/dist/seatable/clientRegistry.js.map +1 -0
  173. package/dist/seatable/contextualClient.d.ts +92 -0
  174. package/dist/seatable/contextualClient.d.ts.map +1 -0
  175. package/dist/seatable/contextualClient.js +42 -0
  176. package/dist/seatable/contextualClient.js.map +1 -0
  177. package/dist/seatable/mockClient.d.ts +68 -0
  178. package/dist/seatable/mockClient.d.ts.map +1 -0
  179. package/dist/seatable/mockClient.js +115 -0
  180. package/dist/seatable/mockClient.js.map +1 -0
  181. package/dist/seatable/tokenManager.d.ts +28 -0
  182. package/dist/seatable/tokenManager.d.ts.map +1 -0
  183. package/dist/seatable/tokenManager.js +92 -0
  184. package/dist/seatable/tokenManager.js.map +1 -0
  185. package/dist/seatable/types.d.ts +22 -0
  186. package/dist/seatable/types.d.ts.map +1 -0
  187. package/dist/seatable/types.js +3 -0
  188. package/dist/seatable/types.js.map +1 -0
  189. package/dist/seatable/utils.d.ts +7 -0
  190. package/dist/seatable/utils.d.ts.map +1 -0
  191. package/dist/seatable/utils.js +25 -0
  192. package/dist/seatable/utils.js.map +1 -0
  193. package/package.json +94 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manageTables.js","sourceRoot":"","sources":["../../../src/mcp/tools/manageTables.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC;IAC7B,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC9C,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC/B,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE;CAC7D,CAAC,CAAA;AAEF,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC;IACzB,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;CAC9C,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,oBAAoB,GAAkB,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,cAAc,EAAE,EAAE,EAAE;IACtF,MAAM,CAAC,YAAY,CACf,eAAe,EACf;QACI,KAAK,EAAE,eAAe;QACtB,WAAW,EAAE,oCAAoC;QACjD,WAAW,EAAE,cAAc,CAAC,WAAW,CAAC;KAC3C,EACD,KAAK,EAAE,IAAa,EAAE,EAAE;QACpB,MAAM,EAAE,UAAU,EAAE,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QAC9C,MAAM,OAAO,GAAG,EAAE,CAAA;QAClB,KAAK,MAAM,EAAE,IAAI,UAAU,EAAE,CAAC;YAC1B,IAAI,EAAE,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;gBACzB,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,CAAA;gBACzD,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAA;YAClE,CAAC;iBAAM,IAAI,EAAE,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;gBAChC,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,QAAS,CAAC,CAAA;gBAC3D,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAA;YACnF,CAAC;iBAAM,IAAI,EAAE,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;gBAChC,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,CAAA;gBAC7C,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAA;YAClE,CAAC;QACL,CAAC;QACD,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAA;IAC7E,CAAC,CACJ,CAAA;AACL,CAAC,CAAA"}
@@ -0,0 +1,3 @@
1
+ import { ToolRegistrar } from './types.js';
2
+ export declare const registerPingSeatable: ToolRegistrar;
3
+ //# sourceMappingURL=pingSeatable.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pingSeatable.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/pingSeatable.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAI1C,eAAO,MAAM,oBAAoB,EAAE,aAoClC,CAAA"}
@@ -0,0 +1,37 @@
1
+ import { z } from 'zod';
2
+ const InputSchema = z.object({});
3
+ export const registerPingSeatable = (server, { client, getInputSchema }) => {
4
+ server.registerTool('ping_seatable', {
5
+ title: 'Ping SeaTable',
6
+ description: 'Health check that verifies connectivity and auth to SeaTable',
7
+ inputSchema: getInputSchema(InputSchema),
8
+ annotations: { readOnlyHint: true },
9
+ }, async () => {
10
+ const started = Date.now();
11
+ try {
12
+ // Prefer metadata endpoint for compatibility
13
+ await client.getMetadata();
14
+ const latencyMs = Date.now() - started;
15
+ return {
16
+ content: [
17
+ {
18
+ type: 'text',
19
+ text: JSON.stringify({ ok: true, latency_ms: latencyMs })
20
+ },
21
+ ],
22
+ };
23
+ }
24
+ catch (err) {
25
+ const latencyMs = Date.now() - started;
26
+ return {
27
+ content: [
28
+ {
29
+ type: 'text',
30
+ text: JSON.stringify({ ok: false, latency_ms: latencyMs, error: err.message })
31
+ },
32
+ ],
33
+ };
34
+ }
35
+ });
36
+ };
37
+ //# sourceMappingURL=pingSeatable.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pingSeatable.js","sourceRoot":"","sources":["../../../src/mcp/tools/pingSeatable.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;AAEhC,MAAM,CAAC,MAAM,oBAAoB,GAAkB,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,cAAc,EAAE,EAAE,EAAE;IACtF,MAAM,CAAC,YAAY,CACf,eAAe,EACf;QACI,KAAK,EAAE,eAAe;QACtB,WAAW,EAAE,8DAA8D;QAC3E,WAAW,EAAE,cAAc,CAAC,WAAW,CAAC;QACxC,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE;KACtC,EACD,KAAK,IAAI,EAAE;QACP,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;QAC1B,IAAI,CAAC;YACD,6CAA6C;YAC7C,MAAM,MAAM,CAAC,WAAW,EAAE,CAAA;YAC1B,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAA;YACtC,OAAO;gBACH,OAAO,EAAE;oBACL;wBACI,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC;qBAC5D;iBACJ;aACJ,CAAA;QACL,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACX,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAA;YACtC,OAAO;gBACH,OAAO,EAAE;oBACL;wBACI,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAG,GAAa,CAAC,OAAO,EAAE,CAAC;qBAC5F;iBACJ;aACJ,CAAA;QACL,CAAC;IACL,CAAC,CACJ,CAAA;AACL,CAAC,CAAA"}
@@ -0,0 +1,3 @@
1
+ import { ToolRegistrar } from './types.js';
2
+ export declare const registerQuerySql: ToolRegistrar;
3
+ //# sourceMappingURL=querySql.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"querySql.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/querySql.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAO1C,eAAO,MAAM,gBAAgB,EAAE,aAyB9B,CAAA"}
@@ -0,0 +1,28 @@
1
+ import { z } from 'zod';
2
+ const InputSchema = z.object({
3
+ sql: z.string().describe('SQL query (SELECT, INSERT, UPDATE, DELETE)').refine(sql => sql.trim().length > 0, 'SQL query cannot be empty'),
4
+ parameters: z.array(z.union([z.string(), z.number(), z.boolean(), z.null()])).optional().describe('Values for ? placeholders in the SQL query'),
5
+ });
6
+ export const registerQuerySql = (server, { client, getInputSchema }) => {
7
+ server.registerTool('query_sql', {
8
+ title: 'Query SQL',
9
+ description: 'Execute raw SQL queries against SeaTable. Supports SELECT, INSERT, UPDATE, DELETE. Use ? placeholders for parameters to prevent SQL injection.',
10
+ inputSchema: getInputSchema(InputSchema),
11
+ annotations: { readOnlyHint: false },
12
+ }, async (args) => {
13
+ const { sql, parameters } = InputSchema.parse(args);
14
+ const result = await client.querySql(sql, parameters);
15
+ return {
16
+ content: [{
17
+ type: 'text',
18
+ text: JSON.stringify({
19
+ metadata: result.metadata,
20
+ results: result.results,
21
+ query: sql,
22
+ parameters: parameters || [],
23
+ }),
24
+ }],
25
+ };
26
+ });
27
+ };
28
+ //# sourceMappingURL=querySql.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"querySql.js","sourceRoot":"","sources":["../../../src/mcp/tools/querySql.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC;IACzB,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,4CAA4C,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,2BAA2B,CAAC;IACxI,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,4CAA4C,CAAC;CAClJ,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAkB,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,cAAc,EAAE,EAAE,EAAE;IAClF,MAAM,CAAC,YAAY,CACf,WAAW,EACX;QACI,KAAK,EAAE,WAAW;QAClB,WAAW,EAAE,gJAAgJ;QAC7J,WAAW,EAAE,cAAc,CAAC,WAAW,CAAC;QACxC,WAAW,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE;KACvC,EACD,KAAK,EAAE,IAAa,EAAE,EAAE;QACpB,MAAM,EAAE,GAAG,EAAE,UAAU,EAAE,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QACnD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAC,CAAA;QACrD,OAAO;YACH,OAAO,EAAE,CAAC;oBACN,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;wBACjB,QAAQ,EAAE,MAAM,CAAC,QAAQ;wBACzB,OAAO,EAAE,MAAM,CAAC,OAAO;wBACvB,KAAK,EAAE,GAAG;wBACV,UAAU,EAAE,UAAU,IAAI,EAAE;qBAC/B,CAAC;iBACL,CAAC;SACL,CAAA;IACL,CAAC,CACJ,CAAA;AACL,CAAC,CAAA"}
@@ -0,0 +1,3 @@
1
+ import { ToolRegistrar } from './types.js';
2
+ export declare const registerSearchRows: ToolRegistrar;
3
+ //# sourceMappingURL=searchRows.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"searchRows.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/searchRows.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAO1C,eAAO,MAAM,kBAAkB,EAAE,aAehC,CAAA"}
@@ -0,0 +1,18 @@
1
+ import { z } from 'zod';
2
+ const InputSchema = z.object({
3
+ table: z.string().describe('Target table name'),
4
+ query: z.record(z.any()).describe('Filter object with column name -> value pairs'),
5
+ });
6
+ export const registerSearchRows = (server, { client, getInputSchema }) => {
7
+ server.registerTool('search_rows', {
8
+ title: 'Search Rows',
9
+ description: 'Search rows with a filter object',
10
+ inputSchema: getInputSchema(InputSchema),
11
+ annotations: { readOnlyHint: true },
12
+ }, async (args) => {
13
+ const parsed = InputSchema.parse(args);
14
+ const res = await client.searchRows(parsed.table, parsed.query);
15
+ return { content: [{ type: 'text', text: JSON.stringify(res) }] };
16
+ });
17
+ };
18
+ //# sourceMappingURL=searchRows.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"searchRows.js","sourceRoot":"","sources":["../../../src/mcp/tools/searchRows.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC;IACzB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,mBAAmB,CAAC;IAC/C,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,QAAQ,CAAC,+CAA+C,CAAC;CACrF,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAAkB,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,cAAc,EAAE,EAAE,EAAE;IACpF,MAAM,CAAC,YAAY,CACf,aAAa,EACb;QACI,KAAK,EAAE,aAAa;QACpB,WAAW,EAAE,kCAAkC;QAC/C,WAAW,EAAE,cAAc,CAAC,WAAW,CAAC;QACxC,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE;KACtC,EACD,KAAK,EAAE,IAAa,EAAE,EAAE;QACpB,MAAM,MAAM,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QACtC,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,CAAA;QAC/D,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAA;IACrE,CAAC,CACJ,CAAA;AACL,CAAC,CAAA"}
@@ -0,0 +1,90 @@
1
+ export type McpServerLike = {
2
+ registerTool: (...args: any[]) => any;
3
+ };
4
+ import type { Env } from '../../config/env.js';
5
+ export interface ClientLike {
6
+ listTables(): Promise<Array<{
7
+ name: string;
8
+ _id: string;
9
+ }>>;
10
+ getMetadata(): Promise<any>;
11
+ listRows(query: {
12
+ table: string;
13
+ page?: number;
14
+ page_size?: number;
15
+ view?: string;
16
+ }): Promise<{
17
+ rows: any[];
18
+ page?: number;
19
+ page_size?: number;
20
+ total?: number;
21
+ has_more?: boolean;
22
+ }>;
23
+ getRow(table: string, rowId: string): Promise<any>;
24
+ addRow(table: string, row: Record<string, unknown>): Promise<any>;
25
+ updateRow(table: string, rowId: string, row: Record<string, unknown>): Promise<any>;
26
+ deleteRow(table: string, rowId: string): Promise<{
27
+ success: boolean;
28
+ }>;
29
+ searchRows(table: string, query: Record<string, unknown>): Promise<{
30
+ rows: any[];
31
+ page?: number;
32
+ page_size?: number;
33
+ total?: number;
34
+ has_more?: boolean;
35
+ }>;
36
+ querySql(sql: string, parameters?: any[]): Promise<{
37
+ metadata: any;
38
+ results: any[];
39
+ }>;
40
+ listCollaborators(): Promise<Array<{
41
+ email: string;
42
+ name: string;
43
+ }>>;
44
+ createLinks(args: {
45
+ table: string;
46
+ linkColumn: string;
47
+ pairs: Array<{
48
+ fromRowId: string;
49
+ toRowId: string;
50
+ }>;
51
+ }): Promise<any>;
52
+ deleteLinks(args: {
53
+ table: string;
54
+ linkColumn: string;
55
+ pairs: Array<{
56
+ fromRowId: string;
57
+ toRowId: string;
58
+ }>;
59
+ }): Promise<any>;
60
+ addColumnOptions(args: {
61
+ table: string;
62
+ column: string;
63
+ options: Array<{
64
+ name: string;
65
+ color?: string;
66
+ textColor?: string;
67
+ }>;
68
+ }): Promise<any>;
69
+ uploadFile(args: {
70
+ table: string;
71
+ column: string;
72
+ rowId: string;
73
+ fileName: string;
74
+ fileData: string;
75
+ replace?: boolean;
76
+ }): Promise<{
77
+ file_name: string;
78
+ file_size: number;
79
+ asset_url: string;
80
+ column_type: string;
81
+ }>;
82
+ }
83
+ export type ToolDeps = {
84
+ client: ClientLike;
85
+ env: Env;
86
+ getInputSchema: (schema: any) => any;
87
+ baseNames?: string[];
88
+ };
89
+ export type ToolRegistrar = (server: McpServerLike, deps: ToolDeps) => void;
90
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/mcp/tools/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,3 @@
1
+ import { ToolRegistrar } from './types.js';
2
+ export declare const registerUnlinkRows: ToolRegistrar;
3
+ //# sourceMappingURL=unlinkRows.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unlinkRows.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/unlinkRows.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAQ1C,eAAO,MAAM,kBAAkB,EAAE,aAqBhC,CAAA"}
@@ -0,0 +1,23 @@
1
+ import { z } from 'zod';
2
+ const InputSchema = z.object({
3
+ table: z.string().describe('Source table name'),
4
+ link_column: z.string().describe('Name of the link column'),
5
+ pairs: z.array(z.object({ from_row_id: z.string().describe('Row ID in source table'), to_row_id: z.string().describe('Row ID in linked table') })).min(1).describe('Array of row ID pairs to unlink'),
6
+ });
7
+ export const registerUnlinkRows = (server, { client, getInputSchema }) => {
8
+ server.registerTool('unlink_rows', {
9
+ title: 'Unlink Rows',
10
+ description: 'Remove links between rows via the dedicated links endpoint. This is the ONLY way to remove links — link columns cannot be modified via update_rows.',
11
+ inputSchema: getInputSchema(InputSchema),
12
+ annotations: { readOnlyHint: false, destructiveHint: true },
13
+ }, async (args) => {
14
+ const { table, link_column, pairs } = InputSchema.parse(args);
15
+ const result = await client.deleteLinks({
16
+ table,
17
+ linkColumn: link_column,
18
+ pairs: pairs.map((p) => ({ fromRowId: p.from_row_id, toRowId: p.to_row_id })),
19
+ });
20
+ return { content: [{ type: 'text', text: JSON.stringify(result) }] };
21
+ });
22
+ };
23
+ //# sourceMappingURL=unlinkRows.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unlinkRows.js","sourceRoot":"","sources":["../../../src/mcp/tools/unlinkRows.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,mBAAmB,CAAC;IAC/C,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,yBAAyB,CAAC;IAC3D,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,wBAAwB,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,wBAAwB,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,iCAAiC,CAAC;CACtM,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAAkB,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,cAAc,EAAE,EAAE,EAAE;IACtF,MAAM,CAAC,YAAY,CACjB,aAAa,EACb;QACE,KAAK,EAAE,aAAa;QACpB,WAAW,EAAE,qJAAqJ;QAClK,WAAW,EAAE,cAAc,CAAC,WAAW,CAAC;QACxC,WAAW,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,eAAe,EAAE,IAAI,EAAE;KAC5D,EACD,KAAK,EAAE,IAAa,EAAE,EAAE;QACtB,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QAE7D,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC;YACtC,KAAK;YACL,UAAU,EAAE,WAAW;YACvB,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,WAAW,EAAE,OAAO,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC;SAC9E,CAAC,CAAA;QAEF,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAA;IACtE,CAAC,CACF,CAAA;AACH,CAAC,CAAA"}
@@ -0,0 +1,3 @@
1
+ import { ToolRegistrar } from './types.js';
2
+ export declare const registerUpdateRows: ToolRegistrar;
3
+ //# sourceMappingURL=updateRow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"updateRow.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/updateRow.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAY1C,eAAO,MAAM,kBAAkB,EAAE,aA4BhC,CAAA"}
@@ -0,0 +1,32 @@
1
+ import { z } from 'zod';
2
+ import { mapMetadataToGeneric } from '../../schema/map.js';
3
+ import { validateRowsAgainstSchema } from '../../schema/validate.js';
4
+ const UpdateItem = z.object({
5
+ row_id: z.string().describe('Row ID (_id field) to update'),
6
+ values: z.record(z.any()).describe('Column name -> new value pairs'),
7
+ });
8
+ const InputSchema = z.object({
9
+ table: z.string().describe('Target table name'),
10
+ updates: z.array(UpdateItem).min(1).describe('Array of updates, each with row_id and values'),
11
+ });
12
+ export const registerUpdateRows = (server, { client, getInputSchema }) => {
13
+ server.registerTool('update_rows', {
14
+ title: 'Update Rows',
15
+ description: 'Batch update rows. Rejects unknown columns. Link and file/image columns cannot be modified here — use link_rows/unlink_rows and upload_file instead.',
16
+ inputSchema: getInputSchema(InputSchema),
17
+ annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true },
18
+ }, async (args) => {
19
+ const { table, updates } = InputSchema.parse(args);
20
+ const metadata = await client.getMetadata();
21
+ const generic = mapMetadataToGeneric(metadata);
22
+ validateRowsAgainstSchema(generic, table, updates.map((u) => u.values));
23
+ const results = [];
24
+ for (const u of updates) {
25
+ await client.updateRow(table, u.row_id, u.values);
26
+ const fresh = await client.getRow(table, u.row_id);
27
+ results.push(fresh);
28
+ }
29
+ return { content: [{ type: 'text', text: JSON.stringify({ rows: results }) }] };
30
+ });
31
+ };
32
+ //# sourceMappingURL=updateRow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"updateRow.js","sourceRoot":"","sources":["../../../src/mcp/tools/updateRow.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AAC1D,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAA;AAGpE,MAAM,UAAU,GAAG,CAAC,CAAC,MAAM,CAAC;IACxB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,8BAA8B,CAAC;IAC3D,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,QAAQ,CAAC,gCAAgC,CAAC;CACvE,CAAC,CAAA;AAEF,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC;IACzB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,mBAAmB,CAAC;IAC/C,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,+CAA+C,CAAC;CAChG,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAAkB,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,cAAc,EAAE,EAAE,EAAE;IACpF,MAAM,CAAC,YAAY,CACf,aAAa,EACb;QACI,KAAK,EAAE,aAAa;QACpB,WAAW,EAAE,sJAAsJ;QACnK,WAAW,EAAE,cAAc,CAAC,WAAW,CAAC;QACxC,WAAW,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE;KACrF,EACD,KAAK,EAAE,IAAa,EAAE,EAAE;QACpB,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QAClD,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,WAAW,EAAE,CAAA;QAC3C,MAAM,OAAO,GAAG,oBAAoB,CAAC,QAAQ,CAAC,CAAA;QAC9C,yBAAyB,CACrB,OAAO,EACP,KAAK,EACL,OAAO,CAAC,GAAG,CAAC,CAAC,CAA6B,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAC3D,CAAA;QAED,MAAM,OAAO,GAAG,EAAW,CAAA;QAC3B,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;YACtB,MAAM,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAA;YACjD,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,CAAA;YAClD,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACvB,CAAC;QACD,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAA;IACnF,CAAC,CACJ,CAAA;AACL,CAAC,CAAA"}
@@ -0,0 +1,3 @@
1
+ import { ToolRegistrar } from './types.js';
2
+ export declare const registerUploadFile: ToolRegistrar;
3
+ //# sourceMappingURL=uploadFile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uploadFile.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/uploadFile.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAW1C,eAAO,MAAM,kBAAkB,EAAE,aAsBhC,CAAA"}
@@ -0,0 +1,29 @@
1
+ import { z } from 'zod';
2
+ const InputSchema = z.object({
3
+ table: z.string().describe('Target table name'),
4
+ column: z.string().describe('Name of the file or image column'),
5
+ row_id: z.string().describe('Row ID to attach the file to'),
6
+ file_name: z.string().describe('File name with extension (e.g. "report.pdf")'),
7
+ file_data: z.string().describe('Base64-encoded file content'),
8
+ replace: z.boolean().optional().default(false).describe('Replace existing files (default: append)'),
9
+ });
10
+ export const registerUploadFile = (server, { client, getInputSchema }) => {
11
+ server.registerTool('upload_file', {
12
+ title: 'Upload File',
13
+ description: 'Upload a file or image to a row. Accepts base64-encoded file data and attaches it to the specified file or image column. By default appends to existing files; set replace=true to overwrite.',
14
+ inputSchema: getInputSchema(InputSchema),
15
+ annotations: { readOnlyHint: false, destructiveHint: false },
16
+ }, async (args) => {
17
+ const { table, column, row_id, file_name, file_data, replace } = InputSchema.parse(args);
18
+ const result = await client.uploadFile({
19
+ table,
20
+ column,
21
+ rowId: row_id,
22
+ fileName: file_name,
23
+ fileData: file_data,
24
+ replace,
25
+ });
26
+ return { content: [{ type: 'text', text: JSON.stringify(result) }] };
27
+ });
28
+ };
29
+ //# sourceMappingURL=uploadFile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uploadFile.js","sourceRoot":"","sources":["../../../src/mcp/tools/uploadFile.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC;IACzB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,mBAAmB,CAAC;IAC/C,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,kCAAkC,CAAC;IAC/D,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,8BAA8B,CAAC;IAC3D,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,8CAA8C,CAAC;IAC9E,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,6BAA6B,CAAC;IAC7D,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,0CAA0C,CAAC;CACtG,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAAkB,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,cAAc,EAAE,EAAE,EAAE;IACpF,MAAM,CAAC,YAAY,CACf,aAAa,EACb;QACI,KAAK,EAAE,aAAa;QACpB,WAAW,EAAE,+LAA+L;QAC5M,WAAW,EAAE,cAAc,CAAC,WAAW,CAAC;QACxC,WAAW,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE;KAC/D,EACD,KAAK,EAAE,IAAa,EAAE,EAAE;QACpB,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QACxF,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC;YACnC,KAAK;YACL,MAAM;YACN,KAAK,EAAE,MAAM;YACb,QAAQ,EAAE,SAAS;YACnB,QAAQ,EAAE,SAAS;YACnB,OAAO;SACV,CAAC,CAAA;QACF,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAA;IACxE,CAAC,CACJ,CAAA;AACL,CAAC,CAAA"}
@@ -0,0 +1,3 @@
1
+ import { ToolRegistrar } from './types.js';
2
+ export declare const registerUpsertRows: ToolRegistrar;
3
+ //# sourceMappingURL=upsertRows.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upsertRows.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/upsertRows.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAQ1C,eAAO,MAAM,kBAAkB,EAAE,aAuDhC,CAAA"}
@@ -0,0 +1,55 @@
1
+ import { z } from 'zod';
2
+ import { makeError } from '../../errors.js';
3
+ import { mapMetadataToGeneric } from '../../schema/map.js';
4
+ import { validateRowsAgainstSchema } from '../../schema/validate.js';
5
+ const InputSchema = z.object({
6
+ table: z.string().describe('Target table name'),
7
+ key_columns: z.array(z.string()).min(1).describe('Columns to match on for finding existing rows'),
8
+ rows: z.array(z.record(z.string(), z.any())).min(1).describe('Array of row objects (column name -> value)'),
9
+ });
10
+ export const registerUpsertRows = (server, { client, getInputSchema }) => {
11
+ server.registerTool('upsert_rows', {
12
+ title: 'Batch Upsert Rows',
13
+ description: 'Batch upsert rows by matching on one or more key columns. If a match exists, update it; otherwise insert a new row. Rejects unknown columns. Link and file/image columns cannot be set here — use link_rows/unlink_rows and upload_file instead.',
14
+ inputSchema: getInputSchema(InputSchema),
15
+ annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true },
16
+ }, async (args) => {
17
+ const { table, key_columns, rows } = InputSchema.parse(args);
18
+ // Validate payload against schema
19
+ const metadata = await client.getMetadata();
20
+ const generic = mapMetadataToGeneric(metadata);
21
+ validateRowsAgainstSchema(generic, table, rows);
22
+ const results = [];
23
+ for (const row of rows) {
24
+ // Ensure all key columns present
25
+ for (const k of key_columns) {
26
+ if (!(k in row)) {
27
+ throw makeError('ERR_UPSERT_MISSING_KEY', `Missing key column in row: ${k}`, { key: k });
28
+ }
29
+ }
30
+ // Build simple equality filter
31
+ const filter = {};
32
+ for (const k of key_columns)
33
+ filter[k] = row[k];
34
+ const found = await client.searchRows(table, filter);
35
+ const matches = (found.rows || []).slice(0, 2);
36
+ if (matches.length > 1) {
37
+ throw makeError('ERR_UPSERT_AMBIGUOUS', 'Multiple matches for upsert key', {
38
+ key_columns,
39
+ filter,
40
+ });
41
+ }
42
+ if (matches.length === 1) {
43
+ await client.updateRow(table, matches[0]._id, row);
44
+ const updated = await client.getRow(table, matches[0]._id);
45
+ results.push({ action: 'updated', row: updated });
46
+ }
47
+ else {
48
+ const inserted = await client.addRow(table, row);
49
+ results.push({ action: 'inserted', row: inserted });
50
+ }
51
+ }
52
+ return { content: [{ type: 'text', text: JSON.stringify({ results }) }] };
53
+ });
54
+ };
55
+ //# sourceMappingURL=upsertRows.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upsertRows.js","sourceRoot":"","sources":["../../../src/mcp/tools/upsertRows.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Tracks concurrent connections per key with a configurable limit.
3
+ */
4
+ export declare class ConnectionCounter {
5
+ private readonly maxConnections;
6
+ private readonly counts;
7
+ constructor(maxConnections: number);
8
+ acquire(key: string): boolean;
9
+ release(key: string): void;
10
+ }
11
+ //# sourceMappingURL=connectionCounter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connectionCounter.d.ts","sourceRoot":"","sources":["../../src/ratelimit/connectionCounter.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,iBAAiB;IAC1B,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAQ;IACvC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA4B;gBAEvC,cAAc,EAAE,MAAM;IAIlC,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAO7B,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;CAQ7B"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Tracks concurrent connections per key with a configurable limit.
3
+ */
4
+ export class ConnectionCounter {
5
+ maxConnections;
6
+ counts = new Map();
7
+ constructor(maxConnections) {
8
+ this.maxConnections = maxConnections;
9
+ }
10
+ acquire(key) {
11
+ const current = this.counts.get(key) ?? 0;
12
+ if (current >= this.maxConnections)
13
+ return false;
14
+ this.counts.set(key, current + 1);
15
+ return true;
16
+ }
17
+ release(key) {
18
+ const current = this.counts.get(key) ?? 0;
19
+ if (current <= 1) {
20
+ this.counts.delete(key);
21
+ }
22
+ else {
23
+ this.counts.set(key, current - 1);
24
+ }
25
+ }
26
+ }
27
+ //# sourceMappingURL=connectionCounter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connectionCounter.js","sourceRoot":"","sources":["../../src/ratelimit/connectionCounter.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,OAAO,iBAAiB;IACT,cAAc,CAAQ;IACtB,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAA;IAEnD,YAAY,cAAsB;QAC9B,IAAI,CAAC,cAAc,GAAG,cAAc,CAAA;IACxC,CAAC;IAED,OAAO,CAAC,GAAW;QACf,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;QACzC,IAAI,OAAO,IAAI,IAAI,CAAC,cAAc;YAAE,OAAO,KAAK,CAAA;QAChD,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,GAAG,CAAC,CAAC,CAAA;QACjC,OAAO,IAAI,CAAA;IACf,CAAC;IAED,OAAO,CAAC,GAAW;QACf,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;QACzC,IAAI,OAAO,IAAI,CAAC,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QAC3B,CAAC;aAAM,CAAC;YACJ,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,GAAG,CAAC,CAAC,CAAA;QACrC,CAAC;IACL,CAAC;CACJ"}
@@ -0,0 +1,27 @@
1
+ import { ConnectionCounter } from './connectionCounter.js';
2
+ import { SlidingWindowLimiter } from './rateLimiter.js';
3
+ export { ConnectionCounter } from './connectionCounter.js';
4
+ export { SlidingWindowLimiter } from './rateLimiter.js';
5
+ export interface RateLimitResult {
6
+ allowed: true;
7
+ }
8
+ export interface RateLimitDenied {
9
+ allowed: false;
10
+ retryAfterMs: number;
11
+ reason: string;
12
+ }
13
+ export declare class RateLimitManager {
14
+ readonly perToken: SlidingWindowLimiter;
15
+ readonly perIp: SlidingWindowLimiter;
16
+ readonly global: SlidingWindowLimiter;
17
+ readonly connections: ConnectionCounter;
18
+ private cleanupInterval?;
19
+ constructor();
20
+ check(opts: {
21
+ ip: string;
22
+ token?: string;
23
+ }): RateLimitResult | RateLimitDenied;
24
+ private cleanup;
25
+ destroy(): void;
26
+ }
27
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ratelimit/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAA;AAEvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAA;AAEvD,MAAM,WAAW,eAAe;IAC5B,OAAO,EAAE,IAAI,CAAA;CAChB;AAED,MAAM,WAAW,eAAe;IAC5B,OAAO,EAAE,KAAK,CAAA;IACd,YAAY,EAAE,MAAM,CAAA;IACpB,MAAM,EAAE,MAAM,CAAA;CACjB;AAID,qBAAa,gBAAgB;IACzB,QAAQ,CAAC,QAAQ,uBAA2C;IAC5D,QAAQ,CAAC,KAAK,uBAA4C;IAC1D,QAAQ,CAAC,MAAM,uBAA6C;IAC5D,QAAQ,CAAC,WAAW,oBAA2B;IAE/C,OAAO,CAAC,eAAe,CAAC,CAAgC;;IASxD,KAAK,CAAC,IAAI,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,eAAe,GAAG,eAAe;IAwB9E,OAAO,CAAC,OAAO;IAMf,OAAO,IAAI,IAAI;CAMlB"}
@@ -0,0 +1,50 @@
1
+ import { ConnectionCounter } from './connectionCounter.js';
2
+ import { SlidingWindowLimiter } from './rateLimiter.js';
3
+ export { ConnectionCounter } from './connectionCounter.js';
4
+ export { SlidingWindowLimiter } from './rateLimiter.js';
5
+ const ONE_MINUTE = 60_000;
6
+ export class RateLimitManager {
7
+ perToken = new SlidingWindowLimiter(60, ONE_MINUTE);
8
+ perIp = new SlidingWindowLimiter(120, ONE_MINUTE);
9
+ global = new SlidingWindowLimiter(5000, ONE_MINUTE);
10
+ connections = new ConnectionCounter(5);
11
+ cleanupInterval;
12
+ constructor() {
13
+ this.cleanupInterval = setInterval(() => this.cleanup(), 60_000);
14
+ if (this.cleanupInterval.unref) {
15
+ this.cleanupInterval.unref();
16
+ }
17
+ }
18
+ check(opts) {
19
+ // Global limit
20
+ const globalResult = this.global.check('global');
21
+ if (!globalResult.allowed) {
22
+ return { allowed: false, retryAfterMs: globalResult.retryAfterMs, reason: 'Global rate limit exceeded' };
23
+ }
24
+ // Per-IP limit
25
+ const ipResult = this.perIp.check(opts.ip);
26
+ if (!ipResult.allowed) {
27
+ return { allowed: false, retryAfterMs: ipResult.retryAfterMs, reason: 'IP rate limit exceeded' };
28
+ }
29
+ // Per-token limit
30
+ if (opts.token) {
31
+ const tokenResult = this.perToken.check(opts.token);
32
+ if (!tokenResult.allowed) {
33
+ return { allowed: false, retryAfterMs: tokenResult.retryAfterMs, reason: 'Token rate limit exceeded' };
34
+ }
35
+ }
36
+ return { allowed: true };
37
+ }
38
+ cleanup() {
39
+ this.perToken.cleanup();
40
+ this.perIp.cleanup();
41
+ this.global.cleanup();
42
+ }
43
+ destroy() {
44
+ if (this.cleanupInterval) {
45
+ clearInterval(this.cleanupInterval);
46
+ this.cleanupInterval = undefined;
47
+ }
48
+ }
49
+ }
50
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ratelimit/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAA;AAEvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAA;AAYvD,MAAM,UAAU,GAAG,MAAM,CAAA;AAEzB,MAAM,OAAO,gBAAgB;IAChB,QAAQ,GAAG,IAAI,oBAAoB,CAAC,EAAE,EAAE,UAAU,CAAC,CAAA;IACnD,KAAK,GAAG,IAAI,oBAAoB,CAAC,GAAG,EAAE,UAAU,CAAC,CAAA;IACjD,MAAM,GAAG,IAAI,oBAAoB,CAAC,IAAI,EAAE,UAAU,CAAC,CAAA;IACnD,WAAW,GAAG,IAAI,iBAAiB,CAAC,CAAC,CAAC,CAAA;IAEvC,eAAe,CAAiC;IAExD;QACI,IAAI,CAAC,eAAe,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,MAAM,CAAC,CAAA;QAChE,IAAI,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,CAAC;YAC7B,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,CAAA;QAChC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,IAAoC;QACtC,eAAe;QACf,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAA;QAChD,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,CAAC;YACxB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,YAAY,CAAC,YAAY,EAAE,MAAM,EAAE,4BAA4B,EAAE,CAAA;QAC5G,CAAC;QAED,eAAe;QACf,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QAC1C,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,QAAQ,CAAC,YAAY,EAAE,MAAM,EAAE,wBAAwB,EAAE,CAAA;QACpG,CAAC;QAED,kBAAkB;QAClB,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACb,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YACnD,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC;gBACvB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,WAAW,CAAC,YAAY,EAAE,MAAM,EAAE,2BAA2B,EAAE,CAAA;YAC1G,CAAC;QACL,CAAC;QAED,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;IAC5B,CAAC;IAEO,OAAO;QACX,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAA;QACvB,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAA;QACpB,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAA;IACzB,CAAC;IAED,OAAO;QACH,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;YACvB,aAAa,CAAC,IAAI,CAAC,eAAe,CAAC,CAAA;YACnC,IAAI,CAAC,eAAe,GAAG,SAAS,CAAA;QACpC,CAAC;IACL,CAAC;CACJ"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Sliding-window rate limiter using fixed-window approximation.
3
+ * No external dependencies.
4
+ */
5
+ export declare class SlidingWindowLimiter {
6
+ private readonly maxRequests;
7
+ private readonly windowMs;
8
+ private readonly windows;
9
+ constructor(maxRequests: number, windowMs: number);
10
+ check(key: string): {
11
+ allowed: true;
12
+ } | {
13
+ allowed: false;
14
+ retryAfterMs: number;
15
+ };
16
+ cleanup(): void;
17
+ }
18
+ //# sourceMappingURL=rateLimiter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rateLimiter.d.ts","sourceRoot":"","sources":["../../src/ratelimit/rateLimiter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH,qBAAa,oBAAoB;IAC7B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAQ;IACpC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAQ;IACjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiC;gBAE7C,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;IAKjD,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG;QAAE,OAAO,EAAE,IAAI,CAAA;KAAE,GAAG;QAAE,OAAO,EAAE,KAAK,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE;IAoChF,OAAO,IAAI,IAAI;CASlB"}