@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.
- package/README.md +209 -334
- package/bin/airtable-mcp.js +12 -32
- package/dist/typescript/airtable-mcp-server.js +77 -0
- package/dist/typescript/airtable-mcp-server.js.map +1 -0
- package/dist/typescript/app/airtable-client.js +327 -0
- package/dist/typescript/app/airtable-client.js.map +1 -0
- package/dist/typescript/app/config.js +151 -0
- package/dist/typescript/app/config.js.map +1 -0
- package/dist/typescript/app/context.js +3 -0
- package/dist/typescript/app/context.js.map +1 -0
- package/dist/typescript/app/exceptions.js +85 -0
- package/dist/typescript/app/exceptions.js.map +1 -0
- package/dist/typescript/app/governance.js +58 -0
- package/dist/typescript/app/governance.js.map +1 -0
- package/dist/typescript/app/logger.js +47 -0
- package/dist/typescript/app/logger.js.map +1 -0
- package/dist/typescript/app/rateLimiter.js +37 -0
- package/dist/typescript/app/rateLimiter.js.map +1 -0
- package/dist/typescript/app/sanitize.js +95 -0
- package/dist/typescript/app/sanitize.js.map +1 -0
- package/dist/typescript/app/tools/create.js +55 -0
- package/dist/typescript/app/tools/create.js.map +1 -0
- package/dist/typescript/app/tools/describe.js +190 -0
- package/dist/typescript/app/tools/describe.js.map +1 -0
- package/dist/typescript/app/tools/handleError.js +205 -0
- package/dist/typescript/app/tools/handleError.js.map +1 -0
- package/dist/typescript/app/tools/index.js +24 -0
- package/dist/typescript/app/tools/index.js.map +1 -0
- package/dist/typescript/app/tools/listBases.js +47 -0
- package/dist/typescript/app/tools/listBases.js.map +1 -0
- package/dist/typescript/app/tools/listExceptions.js +16 -0
- package/dist/typescript/app/tools/listExceptions.js.map +1 -0
- package/dist/typescript/app/tools/listGovernance.js +15 -0
- package/dist/typescript/app/tools/listGovernance.js.map +1 -0
- package/dist/typescript/app/tools/query.js +133 -0
- package/dist/typescript/app/tools/query.js.map +1 -0
- package/dist/typescript/app/tools/response.js +21 -0
- package/dist/typescript/app/tools/response.js.map +1 -0
- package/dist/typescript/app/tools/update.js +57 -0
- package/dist/typescript/app/tools/update.js.map +1 -0
- package/dist/typescript/app/tools/upsert.js +66 -0
- package/dist/typescript/app/tools/upsert.js.map +1 -0
- package/dist/typescript/app/tools/webhooks.js +45 -0
- package/dist/typescript/app/tools/webhooks.js.map +1 -0
- package/dist/typescript/app/types.js +291 -0
- package/dist/typescript/app/types.js.map +1 -0
- package/dist/typescript/app/validateApiKey.js +75 -0
- package/dist/typescript/app/validateApiKey.js.map +1 -0
- package/dist/typescript/errors.js +75 -0
- package/dist/typescript/errors.js.map +1 -0
- package/dist/typescript/index.js +27 -0
- package/dist/typescript/index.js.map +1 -0
- package/package.json +49 -31
- package/tsconfig.json +10 -4
- package/types/typescript/airtable-mcp-server.d.ts +2 -0
- package/types/typescript/app/airtable-client.d.ts +50 -0
- package/types/typescript/app/config.d.ts +17 -0
- package/types/typescript/app/context.d.ts +12 -0
- package/types/typescript/app/exceptions.d.ts +12 -0
- package/types/typescript/app/governance.d.ts +18 -0
- package/types/typescript/app/logger.d.ts +13 -0
- package/types/typescript/app/rateLimiter.d.ts +13 -0
- package/types/typescript/app/sanitize.d.ts +50 -0
- package/types/typescript/app/tools/create.d.ts +3 -0
- package/types/typescript/app/tools/describe.d.ts +3 -0
- package/types/typescript/app/tools/handleError.d.ts +8 -0
- package/types/typescript/app/tools/index.d.ts +3 -0
- package/types/typescript/app/tools/listBases.d.ts +13 -0
- package/types/typescript/app/tools/listExceptions.d.ts +3 -0
- package/types/typescript/app/tools/listGovernance.d.ts +3 -0
- package/types/typescript/app/tools/query.d.ts +3 -0
- package/types/typescript/app/tools/response.d.ts +20 -0
- package/types/typescript/app/tools/update.d.ts +3 -0
- package/types/typescript/app/tools/upsert.d.ts +3 -0
- package/types/typescript/app/tools/webhooks.d.ts +3 -0
- package/types/typescript/app/types.d.ts +318 -0
- package/types/typescript/app/validateApiKey.d.ts +25 -0
- package/types/typescript/errors.d.ts +57 -0
- package/types/typescript/index.d.ts +10 -0
- package/types/typescript/prompt-templates.d.ts +5 -0
- package/types/typescript/tools-schemas.d.ts +5 -0
- package/airtable_simple.js +0 -1561
- package/airtable_simple_production.js +0 -1564
- package/dist/airtable-mcp-server.js +0 -660
- package/dist/airtable-mcp-server.js.map +0 -1
- package/dist/test-suite.js +0 -421
- package/dist/test-suite.js.map +0 -1
- package/examples/airtable-crud-example.js +0 -203
- package/examples/building-mcp.md +0 -6666
- package/examples/claude_config.json +0 -4
- package/examples/claude_simple_config.json +0 -7
- package/examples/env-demo.js +0 -172
- package/examples/example-tasks-update.json +0 -23
- package/examples/example-tasks.json +0 -26
- package/examples/example_usage.md +0 -124
- package/examples/python_debug_patch.txt +0 -27
- package/examples/sample-transform.js +0 -76
- package/examples/typescript/advanced-ai-prompts.ts +0 -447
- package/examples/typescript/basic-usage.ts +0 -174
- package/examples/typescript/claude-desktop-config.json +0 -29
- package/examples/windsurf_mcp_config.json +0 -17
- package/types/ai-prompts.d.ts +0 -321
- package/types/airtable-mcp-server.d.ts +0 -52
- package/types/index.d.ts +0 -357
- package/types/tools.d.ts +0 -514
- /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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"}
|