@rashidazarang/airtable-mcp 3.1.0 → 3.2.8

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 (106) hide show
  1. package/README.md +209 -334
  2. package/bin/airtable-mcp.js +12 -32
  3. package/dist/typescript/airtable-mcp-server.js +77 -0
  4. package/dist/typescript/airtable-mcp-server.js.map +1 -0
  5. package/dist/typescript/app/airtable-client.js +327 -0
  6. package/dist/typescript/app/airtable-client.js.map +1 -0
  7. package/dist/typescript/app/config.js +151 -0
  8. package/dist/typescript/app/config.js.map +1 -0
  9. package/dist/typescript/app/context.js +3 -0
  10. package/dist/typescript/app/context.js.map +1 -0
  11. package/dist/typescript/app/exceptions.js +85 -0
  12. package/dist/typescript/app/exceptions.js.map +1 -0
  13. package/dist/typescript/app/governance.js +58 -0
  14. package/dist/typescript/app/governance.js.map +1 -0
  15. package/dist/typescript/app/logger.js +47 -0
  16. package/dist/typescript/app/logger.js.map +1 -0
  17. package/dist/typescript/app/rateLimiter.js +37 -0
  18. package/dist/typescript/app/rateLimiter.js.map +1 -0
  19. package/dist/typescript/app/sanitize.js +95 -0
  20. package/dist/typescript/app/sanitize.js.map +1 -0
  21. package/dist/typescript/app/tools/create.js +55 -0
  22. package/dist/typescript/app/tools/create.js.map +1 -0
  23. package/dist/typescript/app/tools/describe.js +190 -0
  24. package/dist/typescript/app/tools/describe.js.map +1 -0
  25. package/dist/typescript/app/tools/handleError.js +205 -0
  26. package/dist/typescript/app/tools/handleError.js.map +1 -0
  27. package/dist/typescript/app/tools/index.js +24 -0
  28. package/dist/typescript/app/tools/index.js.map +1 -0
  29. package/dist/typescript/app/tools/listBases.js +47 -0
  30. package/dist/typescript/app/tools/listBases.js.map +1 -0
  31. package/dist/typescript/app/tools/listExceptions.js +16 -0
  32. package/dist/typescript/app/tools/listExceptions.js.map +1 -0
  33. package/dist/typescript/app/tools/listGovernance.js +15 -0
  34. package/dist/typescript/app/tools/listGovernance.js.map +1 -0
  35. package/dist/typescript/app/tools/query.js +133 -0
  36. package/dist/typescript/app/tools/query.js.map +1 -0
  37. package/dist/typescript/app/tools/response.js +21 -0
  38. package/dist/typescript/app/tools/response.js.map +1 -0
  39. package/dist/typescript/app/tools/update.js +57 -0
  40. package/dist/typescript/app/tools/update.js.map +1 -0
  41. package/dist/typescript/app/tools/upsert.js +66 -0
  42. package/dist/typescript/app/tools/upsert.js.map +1 -0
  43. package/dist/typescript/app/tools/webhooks.js +45 -0
  44. package/dist/typescript/app/tools/webhooks.js.map +1 -0
  45. package/dist/typescript/app/types.js +291 -0
  46. package/dist/typescript/app/types.js.map +1 -0
  47. package/dist/typescript/app/validateApiKey.js +75 -0
  48. package/dist/typescript/app/validateApiKey.js.map +1 -0
  49. package/dist/typescript/errors.js +75 -0
  50. package/dist/typescript/errors.js.map +1 -0
  51. package/dist/typescript/index.js +27 -0
  52. package/dist/typescript/index.js.map +1 -0
  53. package/package.json +49 -31
  54. package/tsconfig.json +10 -4
  55. package/types/typescript/airtable-mcp-server.d.ts +2 -0
  56. package/types/typescript/app/airtable-client.d.ts +50 -0
  57. package/types/typescript/app/config.d.ts +17 -0
  58. package/types/typescript/app/context.d.ts +12 -0
  59. package/types/typescript/app/exceptions.d.ts +12 -0
  60. package/types/typescript/app/governance.d.ts +18 -0
  61. package/types/typescript/app/logger.d.ts +13 -0
  62. package/types/typescript/app/rateLimiter.d.ts +13 -0
  63. package/types/typescript/app/sanitize.d.ts +50 -0
  64. package/types/typescript/app/tools/create.d.ts +3 -0
  65. package/types/typescript/app/tools/describe.d.ts +3 -0
  66. package/types/typescript/app/tools/handleError.d.ts +8 -0
  67. package/types/typescript/app/tools/index.d.ts +3 -0
  68. package/types/typescript/app/tools/listBases.d.ts +13 -0
  69. package/types/typescript/app/tools/listExceptions.d.ts +3 -0
  70. package/types/typescript/app/tools/listGovernance.d.ts +3 -0
  71. package/types/typescript/app/tools/query.d.ts +3 -0
  72. package/types/typescript/app/tools/response.d.ts +20 -0
  73. package/types/typescript/app/tools/update.d.ts +3 -0
  74. package/types/typescript/app/tools/upsert.d.ts +3 -0
  75. package/types/typescript/app/tools/webhooks.d.ts +3 -0
  76. package/types/typescript/app/types.d.ts +318 -0
  77. package/types/typescript/app/validateApiKey.d.ts +25 -0
  78. package/types/typescript/errors.d.ts +57 -0
  79. package/types/typescript/index.d.ts +10 -0
  80. package/types/typescript/prompt-templates.d.ts +5 -0
  81. package/types/typescript/tools-schemas.d.ts +5 -0
  82. package/airtable_simple.js +0 -1561
  83. package/airtable_simple_production.js +0 -1564
  84. package/dist/airtable-mcp-server.js +0 -660
  85. package/dist/airtable-mcp-server.js.map +0 -1
  86. package/dist/test-suite.js +0 -421
  87. package/dist/test-suite.js.map +0 -1
  88. package/examples/airtable-crud-example.js +0 -203
  89. package/examples/building-mcp.md +0 -6666
  90. package/examples/claude_config.json +0 -4
  91. package/examples/claude_simple_config.json +0 -7
  92. package/examples/env-demo.js +0 -172
  93. package/examples/example-tasks-update.json +0 -23
  94. package/examples/example-tasks.json +0 -26
  95. package/examples/example_usage.md +0 -124
  96. package/examples/python_debug_patch.txt +0 -27
  97. package/examples/sample-transform.js +0 -76
  98. package/examples/typescript/advanced-ai-prompts.ts +0 -447
  99. package/examples/typescript/basic-usage.ts +0 -174
  100. package/examples/typescript/claude-desktop-config.json +0 -29
  101. package/examples/windsurf_mcp_config.json +0 -17
  102. package/types/ai-prompts.d.ts +0 -321
  103. package/types/airtable-mcp-server.d.ts +0 -52
  104. package/types/index.d.ts +0 -357
  105. package/types/tools.d.ts +0 -514
  106. /package/types/{test-suite.d.ts → typescript/test-suite.d.ts} +0 -0
@@ -0,0 +1,205 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleToolError = handleToolError;
4
+ const errors_1 = require("../../errors");
5
+ function formatTokenWarnings(warnings) {
6
+ if (warnings.length === 0)
7
+ return '';
8
+ return '\n\nToken format issues detected:\n' + warnings.map((w) => `• ${w}`).join('\n');
9
+ }
10
+ function buildAuthErrorMessage(error, tokenWarnings) {
11
+ const errorType = error.context?.upstreamErrorType;
12
+ const baseId = error.context?.baseId;
13
+ const endpoint = error.context?.endpoint ?? '';
14
+ const isMetaApi = endpoint.includes('/meta/');
15
+ const isBaseSpecific = baseId && endpoint.includes(`/bases/${baseId}`);
16
+ const warningsText = formatTokenWarnings(tokenWarnings);
17
+ // Handle specific Airtable error types
18
+ if (errorType === 'AUTHENTICATION_REQUIRED') {
19
+ return `Authentication failed: Token is invalid or expired.
20
+
21
+ Troubleshooting:
22
+ 1. Verify your token at https://airtable.com/create/tokens
23
+ 2. Check that the token hasn't been revoked
24
+ 3. Ensure you copied the entire token (typically ~82 characters)${warningsText}`;
25
+ }
26
+ if (errorType === 'INVALID_PERMISSIONS_OR_MODEL_NOT_FOUND') {
27
+ if (baseId) {
28
+ return `Authentication failed for base "${baseId}".
29
+
30
+ Your token is valid but cannot access this specific base.
31
+
32
+ Troubleshooting:
33
+ 1. Run list_bases to see which bases your token can access
34
+ 2. If this base is not listed, regenerate your token with access to it
35
+ 3. Verify your token has the required scopes:
36
+ • schema.bases:read (for describe/list operations)
37
+ • data.records:read (for query operations)
38
+ • data.records:write (for create/update operations)${warningsText}`;
39
+ }
40
+ return `Authentication failed: Token lacks required permissions.
41
+
42
+ Troubleshooting:
43
+ 1. Verify your token has the "schema.bases:read" scope
44
+ 2. Check token permissions at https://airtable.com/create/tokens
45
+ 3. Regenerate token if scopes are missing${warningsText}`;
46
+ }
47
+ // Fallback for unrecognized error types
48
+ if (isMetaApi && isBaseSpecific) {
49
+ return `Authentication failed for base "${baseId}".
50
+
51
+ This could mean:
52
+ 1. Your token lacks the "schema.bases:read" scope
53
+ 2. Your token does not have access to this specific base
54
+
55
+ Run list_bases to see which bases your token can access.${warningsText}`;
56
+ }
57
+ if (isMetaApi) {
58
+ return `Authentication failed for Meta API.
59
+
60
+ Troubleshooting:
61
+ 1. Ensure your token has the "schema.bases:read" scope
62
+ 2. Verify token at https://airtable.com/create/tokens${warningsText}`;
63
+ }
64
+ return `Authentication failed.
65
+
66
+ Troubleshooting:
67
+ 1. Verify token scopes match the operation you're attempting
68
+ 2. Check base/table access permissions
69
+ 3. Review token at https://airtable.com/create/tokens${warningsText}`;
70
+ }
71
+ function buildValidationErrorMessage(error) {
72
+ const errorType = error.context?.upstreamErrorType;
73
+ const errorMessage = error.context?.upstreamErrorMessage;
74
+ if (errorType === 'UNKNOWN_FIELD_NAME') {
75
+ return `Airtable rejected the request: Unknown field name.
76
+
77
+ ${errorMessage ? `Details: ${errorMessage}\n\n` : ''}Troubleshooting:
78
+ 1. Use describe tool to see valid field names for this table
79
+ 2. Field names are case-sensitive
80
+ 3. Check for typos in field names`;
81
+ }
82
+ if (errorType === 'INVALID_FIELD_TYPE') {
83
+ return `Airtable rejected the request: Invalid field value type.
84
+
85
+ ${errorMessage ? `Details: ${errorMessage}\n\n` : ''}Troubleshooting:
86
+ 1. Use describe tool to see field types
87
+ 2. Ensure values match expected types (text, number, date, etc.)
88
+ 3. Check Airtable field configuration`;
89
+ }
90
+ if (errorMessage) {
91
+ return `Airtable validation error: ${errorMessage}
92
+
93
+ Troubleshooting:
94
+ 1. Check field names and values match table schema
95
+ 2. Use describe tool to verify field types
96
+ 3. Ensure required fields are provided`;
97
+ }
98
+ return `Airtable rejected the request.
99
+
100
+ Troubleshooting:
101
+ 1. Check field names exist in the table
102
+ 2. Verify values match expected field types
103
+ 3. Use describe tool to inspect table schema`;
104
+ }
105
+ function buildNotFoundErrorMessage(error) {
106
+ const baseId = error.context?.baseId;
107
+ const errorMessage = error.context?.upstreamErrorMessage;
108
+ if (baseId) {
109
+ return `Resource not found in base "${baseId}".
110
+
111
+ ${errorMessage ? `Details: ${errorMessage}\n\n` : ''}Troubleshooting:
112
+ 1. Verify the base ID is correct
113
+ 2. Check table/record IDs exist
114
+ 3. Use list_bases and describe tools to confirm identifiers`;
115
+ }
116
+ return `Requested Airtable resource was not found.
117
+
118
+ Troubleshooting:
119
+ 1. Confirm base, table, and record identifiers are correct
120
+ 2. Use list_bases to see available bases
121
+ 3. Use describe to see tables in a base`;
122
+ }
123
+ function buildRateLimitMessage(error) {
124
+ const retryAfter = error.retryAfterMs;
125
+ const retrySeconds = retryAfter ? Math.ceil(retryAfter / 1000) : undefined;
126
+ if (retrySeconds) {
127
+ return `Airtable rate limit exceeded. Retry after ${retrySeconds} seconds.
128
+
129
+ The API allows 5 requests per second per base. Consider:
130
+ 1. Reducing request frequency
131
+ 2. Batching multiple record operations
132
+ 3. Using pagination for large result sets`;
133
+ }
134
+ return `Airtable rate limit exceeded.
135
+
136
+ The API allows 5 requests per second per base. Retry after a brief delay.`;
137
+ }
138
+ function toUserMessage(error, ctx) {
139
+ const tokenWarnings = ctx.config.auth.tokenFormatWarnings || [];
140
+ switch (error.code) {
141
+ case 'RateLimited':
142
+ return buildRateLimitMessage(error);
143
+ case 'ValidationError':
144
+ return buildValidationErrorMessage(error);
145
+ case 'AuthError':
146
+ return buildAuthErrorMessage(error, tokenWarnings);
147
+ case 'ConflictError':
148
+ return `Record conflict detected.
149
+
150
+ The record was modified since it was fetched.
151
+
152
+ Troubleshooting:
153
+ 1. Fetch the latest version of the record
154
+ 2. Review the changes (diff)
155
+ 3. Retry the update with fresh data`;
156
+ case 'NotFound':
157
+ return buildNotFoundErrorMessage(error);
158
+ case 'GovernanceError':
159
+ return `Operation blocked by governance policy.
160
+
161
+ This operation is not allowed by the configured governance rules.
162
+ Check AIRTABLE_ALLOWED_BASES and AIRTABLE_ALLOWED_TABLES settings.`;
163
+ default:
164
+ return `Unexpected Airtable error.
165
+
166
+ Please retry the operation. If the problem persists, check:
167
+ 1. Airtable service status
168
+ 2. Server logs for details
169
+ 3. Request ID: ${error.context?.upstreamRequestId || 'N/A'}`;
170
+ }
171
+ }
172
+ function handleToolError(toolName, error, ctx) {
173
+ if (error instanceof errors_1.AirtableBrainError) {
174
+ ctx.logger.error(`${toolName} failed`, {
175
+ code: error.code,
176
+ status: error.status,
177
+ retryAfterMs: error.retryAfterMs,
178
+ upstreamErrorType: error.context?.upstreamErrorType,
179
+ upstreamRequestId: error.context?.upstreamRequestId
180
+ });
181
+ ctx.exceptions.record(error, `${toolName} failed`, error.message);
182
+ return {
183
+ isError: true,
184
+ content: [
185
+ {
186
+ type: 'text',
187
+ text: toUserMessage(error, ctx)
188
+ }
189
+ ]
190
+ };
191
+ }
192
+ ctx.logger.error(`${toolName} failed with unknown error`, {
193
+ error: error instanceof Error ? error.message : String(error)
194
+ });
195
+ return {
196
+ isError: true,
197
+ content: [
198
+ {
199
+ type: 'text',
200
+ text: 'Unexpected server error. Check logs for details.'
201
+ }
202
+ ]
203
+ };
204
+ }
205
+ //# sourceMappingURL=handleError.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handleError.js","sourceRoot":"","sources":["../../../../src/typescript/app/tools/handleError.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerAllTools = registerAllTools;
4
+ const listBases_1 = require("./listBases");
5
+ const describe_1 = require("./describe");
6
+ const query_1 = require("./query");
7
+ const listGovernance_1 = require("./listGovernance");
8
+ const listExceptions_1 = require("./listExceptions");
9
+ const create_1 = require("./create");
10
+ const update_1 = require("./update");
11
+ const upsert_1 = require("./upsert");
12
+ const webhooks_1 = require("./webhooks");
13
+ function registerAllTools(server, ctx) {
14
+ (0, listBases_1.registerListBasesTool)(server, ctx);
15
+ (0, describe_1.registerDescribeTool)(server, ctx);
16
+ (0, query_1.registerQueryTool)(server, ctx);
17
+ (0, listGovernance_1.registerGovernanceTool)(server, ctx);
18
+ (0, listExceptions_1.registerExceptionsTool)(server, ctx);
19
+ (0, create_1.registerCreateTool)(server, ctx);
20
+ (0, update_1.registerUpdateTool)(server, ctx);
21
+ (0, upsert_1.registerUpsertTool)(server, ctx);
22
+ (0, webhooks_1.registerWebhookTools)(server, ctx);
23
+ }
24
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/typescript/app/tools/index.ts"],"names":[],"mappings":";;AAYA,4CAUC;AApBD,2CAAoD;AACpD,yCAAkD;AAClD,mCAA4C;AAC5C,qDAA0D;AAC1D,qDAA0D;AAC1D,qCAA8C;AAC9C,qCAA8C;AAC9C,qCAA8C;AAC9C,yCAAkD;AAElD,SAAgB,gBAAgB,CAAC,MAAiB,EAAE,GAAe;IACjE,IAAA,iCAAqB,EAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACnC,IAAA,+BAAoB,EAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAClC,IAAA,yBAAiB,EAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC/B,IAAA,uCAAsB,EAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACpC,IAAA,uCAAsB,EAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACpC,IAAA,2BAAkB,EAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAChC,IAAA,2BAAkB,EAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAChC,IAAA,2BAAkB,EAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAChC,IAAA,+BAAoB,EAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AACpC,CAAC"}
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerListBasesTool = registerListBasesTool;
4
+ const zod_1 = require("zod");
5
+ const handleError_1 = require("./handleError");
6
+ const response_1 = require("./response");
7
+ // Schema for list_bases output
8
+ const listBasesOutputSchema = zod_1.z.object({
9
+ bases: zod_1.z.array(zod_1.z.object({
10
+ id: zod_1.z.string(),
11
+ name: zod_1.z.string(),
12
+ permissionLevel: zod_1.z.string().optional()
13
+ }))
14
+ });
15
+ function registerListBasesTool(server, ctx) {
16
+ server.registerTool('list_bases', {
17
+ description: 'List all accessible Airtable bases with their names, IDs, and permission levels',
18
+ inputSchema: {},
19
+ outputSchema: listBasesOutputSchema.shape
20
+ }, async (_args, _extra) => {
21
+ try {
22
+ ctx.logger.info('Listing accessible Airtable bases');
23
+ const response = await ctx.airtable.listBases();
24
+ const bases = response.bases;
25
+ if (!bases || bases.length === 0) {
26
+ const structuredContent = {
27
+ bases: []
28
+ };
29
+ return (0, response_1.createToolResponse)(structuredContent);
30
+ }
31
+ const normalizedBases = bases.map((base) => ({
32
+ id: String(base.id ?? ''),
33
+ name: String(base.name ?? ''),
34
+ permissionLevel: base.permissionLevel ? String(base.permissionLevel) : undefined
35
+ }));
36
+ const structuredContent = {
37
+ bases: normalizedBases
38
+ };
39
+ ctx.logger.info('Successfully listed bases', { count: bases.length });
40
+ return (0, response_1.createToolResponse)(structuredContent);
41
+ }
42
+ catch (error) {
43
+ return (0, handleError_1.handleToolError)('list_bases', error, ctx);
44
+ }
45
+ });
46
+ }
47
+ //# sourceMappingURL=listBases.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"listBases.js","sourceRoot":"","sources":["../../../../src/typescript/app/tools/listBases.ts"],"names":[],"mappings":";;AAmBA,sDAwCC;AAzDD,6BAAwB;AACxB,+CAAgD;AAChD,yCAAgD;AAEhD,+BAA+B;AAC/B,MAAM,qBAAqB,GAAG,OAAC,CAAC,MAAM,CAAC;IACrC,KAAK,EAAE,OAAC,CAAC,KAAK,CACZ,OAAC,CAAC,MAAM,CAAC;QACP,EAAE,EAAE,OAAC,CAAC,MAAM,EAAE;QACd,IAAI,EAAE,OAAC,CAAC,MAAM,EAAE;QAChB,eAAe,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;KACvC,CAAC,CACH;CACF,CAAC,CAAC;AAIH,SAAgB,qBAAqB,CAAC,MAAiB,EAAE,GAAe;IACtE,MAAM,CAAC,YAAY,CACjB,YAAY,EACZ;QACE,WAAW,EAAE,iFAAiF;QAC9F,WAAW,EAAE,EAAS;QACtB,YAAY,EAAE,qBAAqB,CAAC,KAAY;KACjD,EACD,KAAK,EAAE,KAAc,EAAE,MAAe,EAAE,EAAE;QACxC,IAAI,CAAC;YACH,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,mCAAmC,CAAC,CAAC;YAErD,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,SAAS,EAAE,CAAC;YAChD,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC;YAE7B,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACjC,MAAM,iBAAiB,GAAoB;oBACzC,KAAK,EAAE,EAAE;iBACV,CAAC;gBACF,OAAO,IAAA,6BAAkB,EAAC,iBAAiB,CAAC,CAAC;YAC/C,CAAC;YAED,MAAM,eAAe,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAS,EAAE,EAAE,CAAC,CAAC;gBAChD,EAAE,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC;gBACzB,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC;gBAC7B,eAAe,EAAE,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,SAAS;aACjF,CAAC,CAAC,CAAC;YAEJ,MAAM,iBAAiB,GAAoB;gBACzC,KAAK,EAAE,eAAe;aACvB,CAAC;YAEF,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,2BAA2B,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;YAEtE,OAAO,IAAA,6BAAkB,EAAC,iBAAiB,CAAC,CAAC;QAC/C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,IAAA,6BAAe,EAAC,YAAY,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;QACnD,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerExceptionsTool = registerExceptionsTool;
4
+ const types_1 = require("../types");
5
+ const response_1 = require("./response");
6
+ function registerExceptionsTool(server, ctx) {
7
+ server.registerTool('list_exceptions', {
8
+ description: 'List recent exceptions and remediation proposals.',
9
+ inputSchema: types_1.listExceptionsInputSchema.shape,
10
+ outputSchema: types_1.listExceptionsOutputSchema.shape
11
+ }, async (args) => {
12
+ const snapshot = ctx.exceptions.list(args);
13
+ return (0, response_1.createToolResponse)(snapshot);
14
+ });
15
+ }
16
+ //# sourceMappingURL=listExceptions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"listExceptions.js","sourceRoot":"","sources":["../../../../src/typescript/app/tools/listExceptions.ts"],"names":[],"mappings":";;AASA,wDAaC;AArBD,oCAIkB;AAElB,yCAAgD;AAEhD,SAAgB,sBAAsB,CAAC,MAAiB,EAAE,GAAe;IACvE,MAAM,CAAC,YAAY,CACjB,iBAAiB,EACjB;QACE,WAAW,EAAE,mDAAmD;QAChE,WAAW,EAAE,iCAAyB,CAAC,KAAY;QACnD,YAAY,EAAE,kCAA0B,CAAC,KAAY;KACtD,EACD,KAAK,EAAE,IAAyB,EAAE,EAAE;QAClC,MAAM,QAAQ,GAAG,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3C,OAAO,IAAA,6BAAkB,EAAC,QAAQ,CAAC,CAAC;IACtC,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerGovernanceTool = registerGovernanceTool;
4
+ const types_1 = require("../types");
5
+ const response_1 = require("./response");
6
+ function registerGovernanceTool(server, ctx) {
7
+ server.registerTool('list_governance', {
8
+ description: 'Return governance allow-lists and PII masking policies.',
9
+ outputSchema: types_1.governanceOutputSchema.shape
10
+ }, async () => {
11
+ const snapshot = ctx.governance.getSnapshot();
12
+ return (0, response_1.createToolResponse)(snapshot);
13
+ });
14
+ }
15
+ //# sourceMappingURL=listGovernance.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"listGovernance.js","sourceRoot":"","sources":["../../../../src/typescript/app/tools/listGovernance.ts"],"names":[],"mappings":";;AAKA,wDAYC;AAhBD,oCAAkD;AAElD,yCAAgD;AAEhD,SAAgB,sBAAsB,CAAC,MAAiB,EAAE,GAAe;IACvE,MAAM,CAAC,YAAY,CACjB,iBAAiB,EACjB;QACE,WAAW,EAAE,yDAAyD;QACtE,YAAY,EAAE,8BAAsB,CAAC,KAAY;KAClD,EACD,KAAK,IAAI,EAAE;QACT,MAAM,QAAQ,GAAG,GAAG,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC;QAC9C,OAAO,IAAA,6BAAkB,EAAC,QAAQ,CAAC,CAAC;IACtC,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,133 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerQueryTool = registerQueryTool;
4
+ const node_crypto_1 = require("node:crypto");
5
+ const types_1 = require("../types");
6
+ const handleError_1 = require("./handleError");
7
+ const response_1 = require("./response");
8
+ const sanitize_1 = require("../sanitize");
9
+ function maskValue(value) {
10
+ if (value === null || value === undefined) {
11
+ return value;
12
+ }
13
+ if (Array.isArray(value)) {
14
+ return value.map(() => '••••');
15
+ }
16
+ if (typeof value === 'object') {
17
+ return '[redacted]';
18
+ }
19
+ return '••••';
20
+ }
21
+ function hashValue(value) {
22
+ const serialized = typeof value === 'string' ? value : JSON.stringify(value ?? '');
23
+ return (0, node_crypto_1.createHash)('sha256').update(serialized).digest('hex');
24
+ }
25
+ function applyPiiPolicies(fields, policies) {
26
+ if (!policies.length) {
27
+ return fields;
28
+ }
29
+ const result = { ...fields };
30
+ for (const policy of policies) {
31
+ if (!(policy.field in result))
32
+ continue;
33
+ switch (policy.policy) {
34
+ case 'drop':
35
+ delete result[policy.field];
36
+ break;
37
+ case 'mask':
38
+ result[policy.field] = maskValue(result[policy.field]);
39
+ break;
40
+ case 'hash':
41
+ result[policy.field] = hashValue(result[policy.field]);
42
+ break;
43
+ default:
44
+ break;
45
+ }
46
+ }
47
+ return result;
48
+ }
49
+ function registerQueryTool(server, ctx) {
50
+ server.registerTool('query', {
51
+ description: 'Query Airtable records with filtering, sorting, and pagination.',
52
+ inputSchema: types_1.queryInputShape,
53
+ outputSchema: types_1.queryOutputSchema.shape
54
+ }, async (args, _extra) => {
55
+ try {
56
+ const input = types_1.queryInputSchema.parse(args);
57
+ ctx.governance.ensureOperationAllowed('query');
58
+ ctx.governance.ensureBaseAllowed(input.baseId);
59
+ ctx.governance.ensureTableAllowed(input.baseId, input.table);
60
+ const logger = ctx.logger.child({
61
+ tool: 'query',
62
+ baseId: input.baseId,
63
+ table: input.table
64
+ });
65
+ const queryParams = {};
66
+ if (input.fields) {
67
+ queryParams.fields = input.fields;
68
+ }
69
+ if (input.filterByFormula) {
70
+ // Validate formula for suspicious patterns (log warning but don't block)
71
+ const formulaValidation = (0, sanitize_1.validateFormula)(input.filterByFormula);
72
+ if (!formulaValidation.isValid) {
73
+ logger.warn('Potentially unsafe formula pattern detected', {
74
+ warning: formulaValidation.warning,
75
+ formula: input.filterByFormula.substring(0, 100) // Truncate for logging
76
+ });
77
+ }
78
+ queryParams.filterByFormula = input.filterByFormula;
79
+ }
80
+ if (input.view) {
81
+ queryParams.view = input.view;
82
+ }
83
+ if (input.pageSize) {
84
+ queryParams.pageSize = input.pageSize;
85
+ }
86
+ if (input.maxRecords) {
87
+ queryParams.maxRecords = input.maxRecords;
88
+ }
89
+ if (input.offset) {
90
+ queryParams.offset = input.offset;
91
+ }
92
+ if (typeof input.returnFieldsByFieldId === 'boolean') {
93
+ queryParams.returnFieldsByFieldId = input.returnFieldsByFieldId;
94
+ }
95
+ if (input.sorts) {
96
+ input.sorts.forEach((sort, index) => {
97
+ queryParams[`sort[${index}][field]`] = sort.field;
98
+ queryParams[`sort[${index}][direction]`] = sort.direction ?? 'asc';
99
+ });
100
+ }
101
+ const response = await ctx.airtable.queryRecords(input.baseId, input.table, queryParams);
102
+ const rawRecords = Array.isArray(response?.records)
103
+ ? response.records
104
+ : [];
105
+ const piiPolicies = ctx.governance.listPiiPolicies(input.baseId, input.table);
106
+ const sanitizedRecords = rawRecords.map((record) => {
107
+ const fields = typeof record.fields === 'object' && record.fields !== null ? record.fields : {};
108
+ return {
109
+ id: String(record.id ?? ''),
110
+ createdTime: record.createdTime ? String(record.createdTime) : undefined,
111
+ fields: applyPiiPolicies(fields, piiPolicies)
112
+ };
113
+ });
114
+ const structuredContent = {
115
+ records: sanitizedRecords,
116
+ offset: typeof response?.offset === 'string' ? response.offset : undefined,
117
+ summary: {
118
+ returned: sanitizedRecords.length,
119
+ hasMore: Boolean(response?.offset)
120
+ }
121
+ };
122
+ logger.debug('Query completed', {
123
+ returned: sanitizedRecords.length,
124
+ hasMore: structuredContent.summary?.hasMore
125
+ });
126
+ return (0, response_1.createToolResponse)(structuredContent);
127
+ }
128
+ catch (error) {
129
+ return (0, handleError_1.handleToolError)('query', error, ctx);
130
+ }
131
+ });
132
+ }
133
+ //# sourceMappingURL=query.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query.js","sourceRoot":"","sources":["../../../../src/typescript/app/tools/query.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ /**
3
+ * Utility for creating consistent MCP tool responses.
4
+ *
5
+ * The MCP protocol requires the `content` array to contain displayable data.
6
+ * While `structuredContent` is the newer typed output format, most clients
7
+ * read from `content` for backwards compatibility.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.createToolResponse = createToolResponse;
11
+ /**
12
+ * Creates a tool response with both structuredContent (for typed clients)
13
+ * and content array (for backwards compatibility with MCP clients).
14
+ */
15
+ function createToolResponse(data) {
16
+ return {
17
+ structuredContent: data,
18
+ content: [{ type: 'text', text: JSON.stringify(data, null, 2) }]
19
+ };
20
+ }
21
+ //# sourceMappingURL=response.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"response.js","sourceRoot":"","sources":["../../../../src/typescript/app/tools/response.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;AAYH,gDAKC;AATD;;;GAGG;AACH,SAAgB,kBAAkB,CAAI,IAAO;IAC3C,OAAO;QACL,iBAAiB,EAAE,IAAI;QACvB,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;KACjE,CAAC;AACJ,CAAC"}
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerUpdateTool = registerUpdateTool;
4
+ const types_1 = require("../types");
5
+ const handleError_1 = require("./handleError");
6
+ const response_1 = require("./response");
7
+ function chunk(arr, size) {
8
+ const out = [];
9
+ for (let i = 0; i < arr.length; i += size)
10
+ out.push(arr.slice(i, i + size));
11
+ return out;
12
+ }
13
+ function registerUpdateTool(server, ctx) {
14
+ server.registerTool('update', {
15
+ description: 'Update Airtable records (requires diff-before-write via dryRun first).',
16
+ inputSchema: types_1.updateInputSchema.shape,
17
+ outputSchema: types_1.updateOutputSchema.shape
18
+ }, async (raw) => {
19
+ try {
20
+ const args = types_1.updateInputSchema.parse(raw);
21
+ ctx.governance.ensureOperationAllowed('update');
22
+ ctx.governance.ensureBaseAllowed(args.baseId);
23
+ ctx.governance.ensureTableAllowed(args.baseId, args.table);
24
+ const logger = ctx.logger.child({ tool: 'update', baseId: args.baseId, table: args.table });
25
+ if (args.dryRun) {
26
+ const structuredContent = {
27
+ diff: { added: 0, updated: args.records.length, unchanged: 0, conflicts: 0 },
28
+ dryRun: true,
29
+ records: args.records.map((r) => ({ id: r.id, fields: r.fields })),
30
+ conflicts: []
31
+ };
32
+ return (0, response_1.createToolResponse)(structuredContent);
33
+ }
34
+ const chunks = chunk(args.records, 10);
35
+ const aggregated = [];
36
+ for (let i = 0; i < chunks.length; i++) {
37
+ const body = { records: chunks[i], typecast: args.typecast ?? false };
38
+ const headerKey = args.idempotencyKey ? `${args.idempotencyKey}:${i}` : undefined;
39
+ const response = await ctx.airtable.updateRecords(args.baseId, args.table, body, headerKey);
40
+ if (Array.isArray(response?.records))
41
+ aggregated.push(...response.records);
42
+ }
43
+ const structuredContent = {
44
+ diff: { added: 0, updated: aggregated.length, unchanged: 0, conflicts: 0 },
45
+ records: aggregated.map((r) => ({ id: String(r.id), fields: r.fields || {} })),
46
+ dryRun: false,
47
+ conflicts: []
48
+ };
49
+ logger.info('Update completed', { updated: aggregated.length });
50
+ return (0, response_1.createToolResponse)(structuredContent);
51
+ }
52
+ catch (error) {
53
+ return (0, handleError_1.handleToolError)('update', error, ctx);
54
+ }
55
+ });
56
+ }
57
+ //# sourceMappingURL=update.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update.js","sourceRoot":"","sources":["../../../../src/typescript/app/tools/update.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerUpsertTool = registerUpsertTool;
4
+ const types_1 = require("../types");
5
+ const handleError_1 = require("./handleError");
6
+ const response_1 = require("./response");
7
+ function chunk(arr, size) {
8
+ const out = [];
9
+ for (let i = 0; i < arr.length; i += size)
10
+ out.push(arr.slice(i, i + size));
11
+ return out;
12
+ }
13
+ function registerUpsertTool(server, ctx) {
14
+ server.registerTool('upsert', {
15
+ description: 'Upsert Airtable records using performUpsert.fieldsToMergeOn.',
16
+ inputSchema: types_1.upsertInputSchema.shape,
17
+ outputSchema: types_1.upsertOutputSchema.shape
18
+ }, async (raw) => {
19
+ try {
20
+ const args = types_1.upsertInputSchema.parse(raw);
21
+ ctx.governance.ensureOperationAllowed('upsert');
22
+ ctx.governance.ensureBaseAllowed(args.baseId);
23
+ ctx.governance.ensureTableAllowed(args.baseId, args.table);
24
+ const logger = ctx.logger.child({ tool: 'upsert', baseId: args.baseId, table: args.table });
25
+ const matchedBy = args.performUpsert.fieldsToMergeOn;
26
+ if (args.dryRun) {
27
+ const structuredContent = {
28
+ diff: { added: args.records.length, updated: 0, unchanged: 0, conflicts: 0 },
29
+ dryRun: true,
30
+ records: args.records.map((r) => ({ id: 'pending', fields: r.fields })),
31
+ conflicts: []
32
+ };
33
+ // Note: Upsert output in PRD expects 'matchedBy' array and no conflicts property; keep consistent with docs
34
+ // When using strict PRD output, we can omit conflicts and include matchedBy
35
+ structuredContent.matchedBy = matchedBy;
36
+ delete structuredContent.conflicts;
37
+ return (0, response_1.createToolResponse)(structuredContent);
38
+ }
39
+ const chunks = chunk(args.records, 10);
40
+ const aggregated = [];
41
+ for (let i = 0; i < chunks.length; i++) {
42
+ const body = {
43
+ records: chunks[i],
44
+ typecast: args.typecast ?? false,
45
+ performUpsert: { fieldsToMergeOn: matchedBy }
46
+ };
47
+ const headerKey = args.idempotencyKey ? `${args.idempotencyKey}:${i}` : undefined;
48
+ const response = await ctx.airtable.upsertRecords(args.baseId, args.table, body, headerKey);
49
+ if (Array.isArray(response?.records))
50
+ aggregated.push(...response.records);
51
+ }
52
+ const structuredContent = {
53
+ diff: { added: 0, updated: aggregated.length, unchanged: 0 },
54
+ matchedBy,
55
+ records: aggregated.map((r) => ({ id: String(r.id), fields: r.fields || {} })),
56
+ dryRun: false
57
+ };
58
+ logger.info('Upsert completed', { processed: aggregated.length, matchedBy });
59
+ return (0, response_1.createToolResponse)(structuredContent);
60
+ }
61
+ catch (error) {
62
+ return (0, handleError_1.handleToolError)('upsert', error, ctx);
63
+ }
64
+ });
65
+ }
66
+ //# sourceMappingURL=upsert.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upsert.js","sourceRoot":"","sources":["../../../../src/typescript/app/tools/upsert.ts"],"names":[],"mappings":"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"}