@rashidazarang/airtable-mcp 2.1.0 โ†’ 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) hide show
  1. package/README.md +1 -1
  2. package/airtable_simple_production.js +387 -5
  3. package/examples/claude_simple_config.json +0 -9
  4. package/package.json +10 -1
  5. package/.github/ISSUE_TEMPLATE/bug-report.yml +0 -173
  6. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -38
  7. package/.github/ISSUE_TEMPLATE/custom.md +0 -10
  8. package/.github/ISSUE_TEMPLATE/feature-request.yml +0 -209
  9. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -20
  10. package/.github/ISSUE_TEMPLATE/security-report.yml +0 -216
  11. package/.github/pull_request_template.md +0 -245
  12. package/.github/workflows/ci-cd.yml +0 -408
  13. package/.github/workflows/security-audit.yml +0 -316
  14. package/API_DOCUMENTATION.md +0 -897
  15. package/CAPABILITY_REPORT.md +0 -118
  16. package/CLAUDE_INTEGRATION.md +0 -96
  17. package/CODE_OF_CONDUCT.md +0 -181
  18. package/CONTRIBUTING.md +0 -81
  19. package/DEVELOPMENT.md +0 -190
  20. package/Dockerfile +0 -39
  21. package/Dockerfile.node +0 -20
  22. package/Dockerfile.production +0 -127
  23. package/IMPROVEMENT_PROPOSAL.md +0 -371
  24. package/INSTALLATION.md +0 -183
  25. package/ISSUE_RESPONSES.md +0 -171
  26. package/MCP_REVIEW_SUMMARY.md +0 -142
  27. package/QUICK_START.md +0 -60
  28. package/RELEASE_NOTES_v1.2.0.md +0 -50
  29. package/RELEASE_NOTES_v1.2.1.md +0 -40
  30. package/RELEASE_NOTES_v1.2.2.md +0 -48
  31. package/RELEASE_NOTES_v1.2.3.md +0 -105
  32. package/RELEASE_NOTES_v1.2.4.md +0 -60
  33. package/RELEASE_NOTES_v1.4.0.md +0 -104
  34. package/RELEASE_NOTES_v1.5.0.md +0 -185
  35. package/RELEASE_NOTES_v1.6.0.md +0 -248
  36. package/SECURITY_NOTICE.md +0 -40
  37. package/airtable-clipper/CHANGELOG.md +0 -198
  38. package/airtable-clipper/CHROME_STORE_SUBMISSION.md +0 -343
  39. package/airtable-clipper/LAUNCH_STRATEGY.md +0 -495
  40. package/airtable-clipper/LICENSE +0 -21
  41. package/airtable-clipper/OAUTH_SETUP.md +0 -51
  42. package/airtable-clipper/PRIVACY_POLICY.md +0 -187
  43. package/airtable-clipper/README.md +0 -575
  44. package/airtable-clipper/SUBMIT_TO_CHROME_STORE.md +0 -273
  45. package/airtable-clipper/build.sh +0 -85
  46. package/airtable-clipper/docs/QUICK_START.md +0 -99
  47. package/airtable-clipper/docs/SETUP.md +0 -291
  48. package/airtable-clipper/extension/background.js +0 -337
  49. package/airtable-clipper/extension/base-setup.html +0 -324
  50. package/airtable-clipper/extension/base-setup.js +0 -471
  51. package/airtable-clipper/extension/content.js +0 -771
  52. package/airtable-clipper/extension/icons/README.md +0 -69
  53. package/airtable-clipper/extension/icons/icon-16.png +0 -3
  54. package/airtable-clipper/extension/manifest.json +0 -73
  55. package/airtable-clipper/extension/popup.html +0 -144
  56. package/airtable-clipper/extension/popup.js +0 -475
  57. package/airtable-clipper/extension/styles/content.css +0 -229
  58. package/airtable-clipper/extension/styles/popup.css +0 -477
  59. package/airtable-clipper/privacy-policy.md +0 -63
  60. package/airtable-clipper/releases/v1.0.0/background.js +0 -337
  61. package/airtable-clipper/releases/v1.0.0/base-setup.html +0 -324
  62. package/airtable-clipper/releases/v1.0.0/base-setup.js +0 -471
  63. package/airtable-clipper/releases/v1.0.0/content.js +0 -771
  64. package/airtable-clipper/releases/v1.0.0/icons/README.md +0 -69
  65. package/airtable-clipper/releases/v1.0.0/icons/icon-128.png +0 -2
  66. package/airtable-clipper/releases/v1.0.0/icons/icon-16.png +0 -3
  67. package/airtable-clipper/releases/v1.0.0/icons/icon-32.png +0 -2
  68. package/airtable-clipper/releases/v1.0.0/icons/icon-48.png +0 -2
  69. package/airtable-clipper/releases/v1.0.0/manifest.json +0 -73
  70. package/airtable-clipper/releases/v1.0.0/popup.html +0 -144
  71. package/airtable-clipper/releases/v1.0.0/popup.js +0 -475
  72. package/airtable-clipper/releases/v1.0.0/sidepanel.html +0 -25
  73. package/airtable-clipper/releases/v1.0.0/styles/content.css +0 -229
  74. package/airtable-clipper/releases/v1.0.0/styles/popup.css +0 -477
  75. package/airtable-clipper/releases/v1.0.1/background.js +0 -337
  76. package/airtable-clipper/releases/v1.0.1/base-setup.html +0 -324
  77. package/airtable-clipper/releases/v1.0.1/base-setup.js +0 -471
  78. package/airtable-clipper/releases/v1.0.1/content.js +0 -771
  79. package/airtable-clipper/releases/v1.0.1/icons/README.md +0 -69
  80. package/airtable-clipper/releases/v1.0.1/icons/icon-128.png +0 -2
  81. package/airtable-clipper/releases/v1.0.1/icons/icon-16.png +0 -3
  82. package/airtable-clipper/releases/v1.0.1/icons/icon-32.png +0 -2
  83. package/airtable-clipper/releases/v1.0.1/icons/icon-48.png +0 -2
  84. package/airtable-clipper/releases/v1.0.1/manifest.json +0 -70
  85. package/airtable-clipper/releases/v1.0.1/popup.html +0 -157
  86. package/airtable-clipper/releases/v1.0.1/popup.js +0 -562
  87. package/airtable-clipper/releases/v1.0.1/sidepanel.html +0 -25
  88. package/airtable-clipper/releases/v1.0.1/styles/content.css +0 -229
  89. package/airtable-clipper/releases/v1.0.1/styles/popup.css +0 -647
  90. package/airtable-clipper/releases/v1.0.2/background.js +0 -337
  91. package/airtable-clipper/releases/v1.0.2/base-setup.html +0 -324
  92. package/airtable-clipper/releases/v1.0.2/base-setup.js +0 -471
  93. package/airtable-clipper/releases/v1.0.2/content.js +0 -771
  94. package/airtable-clipper/releases/v1.0.2/icons/README.md +0 -69
  95. package/airtable-clipper/releases/v1.0.2/icons/icon-128.png +0 -2
  96. package/airtable-clipper/releases/v1.0.2/icons/icon-16.png +0 -3
  97. package/airtable-clipper/releases/v1.0.2/icons/icon-32.png +0 -2
  98. package/airtable-clipper/releases/v1.0.2/icons/icon-48.png +0 -2
  99. package/airtable-clipper/releases/v1.0.2/manifest.json +0 -62
  100. package/airtable-clipper/releases/v1.0.2/popup.html +0 -157
  101. package/airtable-clipper/releases/v1.0.2/popup.js +0 -567
  102. package/airtable-clipper/releases/v1.0.2/sidepanel.html +0 -25
  103. package/airtable-clipper/releases/v1.0.2/styles/content.css +0 -229
  104. package/airtable-clipper/releases/v1.0.2/styles/popup.css +0 -647
  105. package/airtable-clipper/terms-of-service.md +0 -124
  106. package/airtable-clipper/test-credentials.md +0 -61
  107. package/airtable-clipper/test-extension/background.js +0 -337
  108. package/airtable-clipper/test-extension/base-setup.html +0 -324
  109. package/airtable-clipper/test-extension/base-setup.js +0 -471
  110. package/airtable-clipper/test-extension/content.js +0 -873
  111. package/airtable-clipper/test-extension/icons/README.md +0 -69
  112. package/airtable-clipper/test-extension/icons/icon-128.png +0 -2
  113. package/airtable-clipper/test-extension/icons/icon-16.png +0 -3
  114. package/airtable-clipper/test-extension/icons/icon-32.png +0 -2
  115. package/airtable-clipper/test-extension/icons/icon-48.png +0 -2
  116. package/airtable-clipper/test-extension/manifest.json +0 -72
  117. package/airtable-clipper/test-extension/popup.html +0 -274
  118. package/airtable-clipper/test-extension/popup.js +0 -729
  119. package/airtable-clipper/test-extension/sidepanel.html +0 -25
  120. package/airtable-clipper/test-extension/styles/content.css +0 -229
  121. package/airtable-clipper/test-extension/styles/popup.css +0 -794
  122. package/airtable_mcp/__init__.py +0 -5
  123. package/airtable_mcp/src/server.py +0 -329
  124. package/airtable_mcp_v2.js +0 -1505
  125. package/airtable_mcp_v2_oauth.js +0 -1048
  126. package/airtable_mcp_v3_advanced.js +0 -1161
  127. package/cleanup.sh +0 -71
  128. package/docker-compose.production.yml +0 -366
  129. package/helm/airtable-mcp/Chart.yaml +0 -122
  130. package/helm/airtable-mcp/values.yaml +0 -538
  131. package/index.js +0 -179
  132. package/inspector.py +0 -148
  133. package/inspector_server.py +0 -337
  134. package/k8s/deployment.yaml +0 -402
  135. package/k8s/namespace.yaml +0 -108
  136. package/k8s/service.yaml +0 -194
  137. package/monitoring/alerts.yml +0 -289
  138. package/monitoring/prometheus.yml +0 -224
  139. package/publish-steps.txt +0 -27
  140. package/quick_test.sh +0 -30
  141. package/requirements.txt +0 -10
  142. package/setup.py +0 -29
  143. package/simple_airtable_server.py +0 -151
  144. package/smithery.yaml +0 -45
  145. package/test_all_features.sh +0 -146
  146. package/test_all_operations.sh +0 -120
  147. package/test_client.py +0 -70
  148. package/test_enhanced_features.js +0 -389
  149. package/test_mcp_comprehensive.js +0 -163
  150. package/test_mock_server.js +0 -180
  151. package/test_v1.4.0_final.sh +0 -131
  152. package/test_v1.5.0_comprehensive.sh +0 -96
  153. package/test_v1.5.0_final.sh +0 -224
  154. package/test_v1.6.0_comprehensive.sh +0 -187
  155. package/test_webhooks.sh +0 -105
@@ -1,180 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * Mock Airtable API Server for Testing
5
- * Simulates Airtable API responses for testing the MCP
6
- */
7
-
8
- const http = require('http');
9
- const https = require('https');
10
-
11
- // Mock data store
12
- let mockTables = {
13
- 'tblTest123': {
14
- id: 'tblTest123',
15
- name: 'Tasks',
16
- fields: [
17
- { id: 'fld1', name: 'Name', type: 'singleLineText' },
18
- { id: 'fld2', name: 'Status', type: 'singleSelect' },
19
- { id: 'fld3', name: 'Notes', type: 'multilineText' }
20
- ]
21
- },
22
- 'tblTest456': {
23
- id: 'tblTest456',
24
- name: 'Projects',
25
- fields: [
26
- { id: 'fld4', name: 'Title', type: 'singleLineText' },
27
- { id: 'fld5', name: 'Description', type: 'multilineText' }
28
- ]
29
- }
30
- };
31
-
32
- let mockRecords = {
33
- 'tblTest123': [
34
- {
35
- id: 'recABC123',
36
- fields: { Name: 'Test Task 1', Status: 'Todo', Notes: 'First test task' },
37
- createdTime: '2025-08-14T10:00:00.000Z'
38
- },
39
- {
40
- id: 'recDEF456',
41
- fields: { Name: 'Test Task 2', Status: 'In Progress', Notes: 'Second test task' },
42
- createdTime: '2025-08-14T11:00:00.000Z'
43
- }
44
- ],
45
- 'tblTest456': []
46
- };
47
-
48
- let recordIdCounter = 1000;
49
-
50
- // Create mock server
51
- const server = http.createServer((req, res) => {
52
- console.log(`Mock API: ${req.method} ${req.url}`);
53
-
54
- // Parse URL
55
- const url = req.url;
56
-
57
- // Enable CORS
58
- res.setHeader('Access-Control-Allow-Origin', '*');
59
- res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PATCH, DELETE, OPTIONS');
60
- res.setHeader('Access-Control-Allow-Headers', 'Authorization, Content-Type');
61
-
62
- // Check authorization
63
- if (!req.headers.authorization || !req.headers.authorization.includes('Bearer')) {
64
- res.writeHead(401, { 'Content-Type': 'application/json' });
65
- res.end(JSON.stringify({ error: { type: 'UNAUTHORIZED', message: 'Missing authorization' } }));
66
- return;
67
- }
68
-
69
- // Handle preflight
70
- if (req.method === 'OPTIONS') {
71
- res.writeHead(200);
72
- res.end();
73
- return;
74
- }
75
-
76
- // Route handlers
77
- if (url.includes('/v0/meta/bases/') && url.includes('/tables')) {
78
- // List tables
79
- res.writeHead(200, { 'Content-Type': 'application/json' });
80
- res.end(JSON.stringify({ tables: Object.values(mockTables) }));
81
-
82
- } else if (req.method === 'GET' && url.match(/\/v0\/test_base\/(tbl\w+)$/)) {
83
- // List records
84
- const tableId = url.match(/\/(tbl\w+)$/)[1];
85
- const records = mockRecords[tableId] || [];
86
-
87
- res.writeHead(200, { 'Content-Type': 'application/json' });
88
- res.end(JSON.stringify({ records }));
89
-
90
- } else if (req.method === 'GET' && url.match(/\/v0\/test_base\/(tbl\w+)\/(rec\w+)$/)) {
91
- // Get single record
92
- const matches = url.match(/\/(tbl\w+)\/(rec\w+)$/);
93
- const tableId = matches[1];
94
- const recordId = matches[2];
95
-
96
- const records = mockRecords[tableId] || [];
97
- const record = records.find(r => r.id === recordId);
98
-
99
- if (record) {
100
- res.writeHead(200, { 'Content-Type': 'application/json' });
101
- res.end(JSON.stringify(record));
102
- } else {
103
- res.writeHead(404, { 'Content-Type': 'application/json' });
104
- res.end(JSON.stringify({ error: { type: 'NOT_FOUND', message: 'Record not found' } }));
105
- }
106
-
107
- } else if (req.method === 'POST' && url.match(/\/v0\/test_base\/(tbl\w+)$/)) {
108
- // Create record
109
- const tableId = url.match(/\/(tbl\w+)$/)[1];
110
-
111
- let body = '';
112
- req.on('data', chunk => body += chunk);
113
- req.on('end', () => {
114
- const data = JSON.parse(body);
115
- const newRecord = {
116
- id: `recNEW${recordIdCounter++}`,
117
- fields: data.fields,
118
- createdTime: new Date().toISOString()
119
- };
120
-
121
- if (!mockRecords[tableId]) mockRecords[tableId] = [];
122
- mockRecords[tableId].push(newRecord);
123
-
124
- res.writeHead(200, { 'Content-Type': 'application/json' });
125
- res.end(JSON.stringify(newRecord));
126
- });
127
-
128
- } else if (req.method === 'PATCH' && url.match(/\/v0\/test_base\/(tbl\w+)\/(rec\w+)$/)) {
129
- // Update record
130
- const matches = url.match(/\/(tbl\w+)\/(rec\w+)$/);
131
- const tableId = matches[1];
132
- const recordId = matches[2];
133
-
134
- let body = '';
135
- req.on('data', chunk => body += chunk);
136
- req.on('end', () => {
137
- const data = JSON.parse(body);
138
- const records = mockRecords[tableId] || [];
139
- const record = records.find(r => r.id === recordId);
140
-
141
- if (record) {
142
- Object.assign(record.fields, data.fields);
143
- res.writeHead(200, { 'Content-Type': 'application/json' });
144
- res.end(JSON.stringify(record));
145
- } else {
146
- res.writeHead(404, { 'Content-Type': 'application/json' });
147
- res.end(JSON.stringify({ error: { type: 'NOT_FOUND', message: 'Record not found' } }));
148
- }
149
- });
150
-
151
- } else if (req.method === 'DELETE' && url.match(/\/v0\/test_base\/(tbl\w+)\/(rec\w+)$/)) {
152
- // Delete record
153
- const matches = url.match(/\/(tbl\w+)\/(rec\w+)$/);
154
- const tableId = matches[1];
155
- const recordId = matches[2];
156
-
157
- const records = mockRecords[tableId] || [];
158
- const index = records.findIndex(r => r.id === recordId);
159
-
160
- if (index !== -1) {
161
- records.splice(index, 1);
162
- res.writeHead(200, { 'Content-Type': 'application/json' });
163
- res.end(JSON.stringify({ id: recordId, deleted: true }));
164
- } else {
165
- res.writeHead(404, { 'Content-Type': 'application/json' });
166
- res.end(JSON.stringify({ error: { type: 'NOT_FOUND', message: 'Record not found' } }));
167
- }
168
-
169
- } else {
170
- res.writeHead(404, { 'Content-Type': 'application/json' });
171
- res.end(JSON.stringify({ error: { type: 'NOT_FOUND', message: 'Endpoint not found' } }));
172
- }
173
- });
174
-
175
- // Start mock server on port 8888
176
- server.listen(8888, () => {
177
- console.log('๐ŸŽญ Mock Airtable API server running on http://localhost:8888');
178
- console.log('๐Ÿ“‹ Mock tables: Tasks (tblTest123), Projects (tblTest456)');
179
- console.log('๐Ÿ“ Mock records: 2 in Tasks, 0 in Projects');
180
- });
@@ -1,131 +0,0 @@
1
- #!/bin/bash
2
-
3
- echo "๐Ÿš€ FINAL TEST SUITE FOR AIRTABLE MCP v1.4.0"
4
- echo "==========================================="
5
- echo ""
6
-
7
- PASSED=0
8
- FAILED=0
9
-
10
- # Helper function to test a tool
11
- test_tool() {
12
- local tool_name=$1
13
- local args=$2
14
- local expected=$3
15
-
16
- result=$(curl -s -X POST http://localhost:8010/mcp \
17
- -H "Content-Type: application/json" \
18
- -d "{\"jsonrpc\": \"2.0\", \"id\": 1, \"method\": \"tools/call\", \"params\": {\"name\": \"$tool_name\", \"arguments\": $args}}")
19
-
20
- if echo "$result" | grep -q "$expected"; then
21
- echo "โœ… $tool_name: PASSED"
22
- ((PASSED++))
23
- return 0
24
- else
25
- echo "โŒ $tool_name: FAILED"
26
- echo " Response: $(echo "$result" | python3 -c "import sys, json; r=json.load(sys.stdin); print(r.get('result', {}).get('content', [{}])[0].get('text', 'ERROR')[:100])")"
27
- ((FAILED++))
28
- return 1
29
- fi
30
- }
31
-
32
- echo "๐Ÿ“‹ Testing 12 Tools"
33
- echo "==================="
34
- echo ""
35
-
36
- # 1. List tools
37
- echo -n "1. Tools available: "
38
- tools_count=$(curl -s -X POST http://localhost:8010/mcp \
39
- -H "Content-Type: application/json" \
40
- -d '{"jsonrpc": "2.0", "id": 1, "method": "tools/list"}' \
41
- | python3 -c "import sys, json; print(len(json.load(sys.stdin)['result']['tools']))")
42
- echo "$tools_count tools"
43
-
44
- # 2. List tables
45
- test_tool "list_tables" "{}" "table"
46
-
47
- # 3. Create record
48
- RECORD_JSON=$(curl -s -X POST http://localhost:8010/mcp \
49
- -H "Content-Type: application/json" \
50
- -d '{"jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": {"name": "create_record", "arguments": {"table": "tblH7TnJxYpNqhQYK", "fields": {"Name": "Test v1.4.0", "Status": "Testing"}}}}')
51
-
52
- if echo "$RECORD_JSON" | grep -q "Successfully created"; then
53
- echo "โœ… create_record: PASSED"
54
- ((PASSED++))
55
- RECORD_ID=$(echo "$RECORD_JSON" | grep -o 'rec[a-zA-Z0-9]\+' | head -1)
56
- else
57
- echo "โŒ create_record: FAILED"
58
- ((FAILED++))
59
- RECORD_ID=""
60
- fi
61
-
62
- # 4. Get record
63
- if [ ! -z "$RECORD_ID" ]; then
64
- test_tool "get_record" "{\"table\": \"tblH7TnJxYpNqhQYK\", \"recordId\": \"$RECORD_ID\"}" "Record $RECORD_ID"
65
- fi
66
-
67
- # 5. Update record
68
- if [ ! -z "$RECORD_ID" ]; then
69
- test_tool "update_record" "{\"table\": \"tblH7TnJxYpNqhQYK\", \"recordId\": \"$RECORD_ID\", \"fields\": {\"Status\": \"Updated\"}}" "Successfully updated"
70
- fi
71
-
72
- # 6. List records
73
- test_tool "list_records" "{\"table\": \"tblH7TnJxYpNqhQYK\", \"maxRecords\": 2}" "record"
74
-
75
- # 7. Search records
76
- test_tool "search_records" "{\"table\": \"tblH7TnJxYpNqhQYK\", \"maxRecords\": 2}" "record"
77
-
78
- # 8. List webhooks
79
- test_tool "list_webhooks" "{}" "webhook"
80
-
81
- # 9. Create webhook
82
- WEBHOOK_JSON=$(curl -s -X POST http://localhost:8010/mcp \
83
- -H "Content-Type: application/json" \
84
- -d '{"jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": {"name": "create_webhook", "arguments": {"notificationUrl": "https://webhook.site/unique-test-id"}}}')
85
-
86
- if echo "$WEBHOOK_JSON" | grep -q "Successfully created"; then
87
- echo "โœ… create_webhook: PASSED"
88
- ((PASSED++))
89
- WEBHOOK_ID=$(echo "$WEBHOOK_JSON" | grep -o 'ach[a-zA-Z0-9]\+' | head -1)
90
- else
91
- echo "โŒ create_webhook: FAILED"
92
- ((FAILED++))
93
- WEBHOOK_ID=""
94
- fi
95
-
96
- # 10. Get webhook payloads
97
- if [ ! -z "$WEBHOOK_ID" ]; then
98
- test_tool "get_webhook_payloads" "{\"webhookId\": \"$WEBHOOK_ID\"}" "payload"
99
- fi
100
-
101
- # 11. Refresh webhook
102
- if [ ! -z "$WEBHOOK_ID" ]; then
103
- test_tool "refresh_webhook" "{\"webhookId\": \"$WEBHOOK_ID\"}" "refreshed"
104
- fi
105
-
106
- # 12. Delete webhook
107
- if [ ! -z "$WEBHOOK_ID" ]; then
108
- test_tool "delete_webhook" "{\"webhookId\": \"$WEBHOOK_ID\"}" "deleted"
109
- fi
110
-
111
- # 13. Delete record (cleanup)
112
- if [ ! -z "$RECORD_ID" ]; then
113
- test_tool "delete_record" "{\"table\": \"tblH7TnJxYpNqhQYK\", \"recordId\": \"$RECORD_ID\"}" "Successfully deleted"
114
- fi
115
-
116
- echo ""
117
- echo "๐Ÿ“Š TEST RESULTS"
118
- echo "=============="
119
- echo "โœ… Passed: $PASSED"
120
- echo "โŒ Failed: $FAILED"
121
- echo "๐Ÿ“ˆ Success Rate: $(( PASSED * 100 / (PASSED + FAILED) ))%"
122
-
123
- if [ $FAILED -eq 0 ]; then
124
- echo ""
125
- echo "๐ŸŽ‰ ALL TESTS PASSED! Ready for production!"
126
- exit 0
127
- else
128
- echo ""
129
- echo "โš ๏ธ Some tests failed. Please review before publishing."
130
- exit 1
131
- fi
@@ -1,96 +0,0 @@
1
- #!/bin/bash
2
-
3
- # Comprehensive Test Suite for Airtable MCP Server v1.5.0
4
- # Tests all 23 tools including new schema management features
5
-
6
- set -e
7
- SERVER_URL="http://localhost:8010/mcp"
8
- PASSED=0
9
- FAILED=0
10
-
11
- echo "๐Ÿš€ Airtable MCP Server v1.5.0 Comprehensive Test Suite"
12
- echo "======================================================"
13
-
14
- # Function to make MCP calls
15
- call_tool() {
16
- local tool_name="$1"
17
- local params="$2"
18
- curl -s -X POST "$SERVER_URL" \
19
- -H "Content-Type: application/json" \
20
- -d "{\"jsonrpc\": \"2.0\", \"id\": 1, \"method\": \"tools/call\", \"params\": {\"name\": \"$tool_name\", \"arguments\": $params}}"
21
- }
22
-
23
- # Test function with result reporting
24
- test_tool() {
25
- local tool_name="$1"
26
- local params="$2"
27
- local description="$3"
28
-
29
- echo -n "Testing $tool_name ($description)... "
30
-
31
- if result=$(call_tool "$tool_name" "$params" 2>&1); then
32
- if echo "$result" | jq -e '.result.content[0].text' > /dev/null 2>&1; then
33
- echo "โœ… PASS"
34
- ((PASSED++))
35
- else
36
- echo "โŒ FAIL (No content)"
37
- echo "Response: $result"
38
- ((FAILED++))
39
- fi
40
- else
41
- echo "โŒ FAIL (Request failed)"
42
- echo "Error: $result"
43
- ((FAILED++))
44
- fi
45
- }
46
-
47
- echo ""
48
- echo "๐Ÿ“Š Testing Original Data Operations (7 tools)..."
49
- echo "------------------------------------------------"
50
-
51
- test_tool "list_tables" "{}" "List all tables"
52
- test_tool "list_records" "{\"table\": \"Test Table CRUD\", \"maxRecords\": 3}" "List records from test table"
53
- test_tool "get_record" "{\"table\": \"Test Table CRUD\", \"recordId\": \"recXXX\"}" "Get specific record (may fail if record doesn't exist)"
54
- test_tool "search_records" "{\"table\": \"Test Table CRUD\", \"searchTerm\": \"test\"}" "Search records"
55
-
56
- echo ""
57
- echo "๐Ÿ”ง Testing New Schema Management Tools (6 tools)..."
58
- echo "---------------------------------------------------"
59
-
60
- test_tool "list_bases" "{}" "List accessible bases"
61
- test_tool "get_base_schema" "{}" "Get complete base schema"
62
- test_tool "describe_table" "{\"table\": \"Test Table CRUD\"}" "Describe table with detailed field info"
63
- test_tool "list_field_types" "{}" "List available field types reference"
64
- test_tool "get_table_views" "{\"table\": \"Test Table CRUD\"}" "Get table views"
65
-
66
- echo ""
67
- echo "๐ŸŽ›๏ธ Testing Webhook Management Tools (5 tools)..."
68
- echo "-------------------------------------------------"
69
-
70
- test_tool "list_webhooks" "{}" "List webhooks"
71
-
72
- echo ""
73
- echo "๐Ÿ“ˆ Testing Results Summary"
74
- echo "=========================="
75
- echo "โœ… Passed: $PASSED"
76
- echo "โŒ Failed: $FAILED"
77
- echo "Total Tests: $((PASSED + FAILED))"
78
-
79
- if [ $FAILED -eq 0 ]; then
80
- echo ""
81
- echo "๐ŸŽ‰ ALL TESTS PASSED! v1.5.0 is ready for production!"
82
- echo ""
83
- echo "๐Ÿ”ฅ NEW FEATURES IN v1.5.0:"
84
- echo "โ€ข 23 total tools (up from 12 in v1.4.0)"
85
- echo "โ€ข Complete base discovery with list_bases"
86
- echo "โ€ข Advanced schema management"
87
- echo "โ€ข Table and field creation/modification"
88
- echo "โ€ข Comprehensive field type reference"
89
- echo "โ€ข Enhanced table inspection"
90
- echo ""
91
- exit 0
92
- else
93
- echo ""
94
- echo "โš ๏ธ Some tests failed. Please review the errors above."
95
- exit 1
96
- fi
@@ -1,224 +0,0 @@
1
- #!/bin/bash
2
-
3
- # COMPREHENSIVE FINAL TEST SUITE - Airtable MCP Server v1.5.0
4
- # Tests ALL 23 tools with no assumptions
5
-
6
- set -e
7
- SERVER_URL="http://localhost:8010/mcp"
8
- PASSED=0
9
- FAILED=0
10
- TEST_RECORD_ID=""
11
- TEST_WEBHOOK_ID=""
12
- CREATED_FIELD_ID=""
13
-
14
- echo "๐Ÿงช FINAL COMPREHENSIVE TEST SUITE - v1.5.0"
15
- echo "==========================================="
16
- echo "Testing ALL 23 tools with real API calls"
17
- echo ""
18
-
19
- # Function to make MCP calls
20
- call_tool() {
21
- local tool_name="$1"
22
- local params="$2"
23
- curl -s -X POST "$SERVER_URL" \
24
- -H "Content-Type: application/json" \
25
- -d "{\"jsonrpc\": \"2.0\", \"id\": 1, \"method\": \"tools/call\", \"params\": {\"name\": \"$tool_name\", \"arguments\": $params}}"
26
- }
27
-
28
- # Enhanced test function with better error reporting
29
- test_tool() {
30
- local tool_name="$1"
31
- local params="$2"
32
- local description="$3"
33
- local expect_fail="$4"
34
-
35
- echo -n "๐Ÿ”ง $tool_name: $description... "
36
-
37
- if result=$(call_tool "$tool_name" "$params" 2>&1); then
38
- if echo "$result" | jq -e '.result.content[0].text' > /dev/null 2>&1; then
39
- response_text=$(echo "$result" | jq -r '.result.content[0].text')
40
- if [[ "$expect_fail" == "true" ]]; then
41
- if echo "$response_text" | grep -q "error\|Error\|not found\|requires"; then
42
- echo "โœ… PASS (Expected failure)"
43
- ((PASSED++))
44
- else
45
- echo "โŒ FAIL (Should have failed)"
46
- echo " Response: ${response_text:0:100}..."
47
- ((FAILED++))
48
- fi
49
- else
50
- echo "โœ… PASS"
51
- ((PASSED++))
52
- # Store important IDs for later tests
53
- if [[ "$tool_name" == "create_record" ]]; then
54
- TEST_RECORD_ID=$(echo "$result" | jq -r '.result.content[0].text' | grep -o 'rec[a-zA-Z0-9]\{10,20\}' | head -1)
55
- echo " ๐Ÿ“ Stored record ID: $TEST_RECORD_ID"
56
- elif [[ "$tool_name" == "create_webhook" ]]; then
57
- TEST_WEBHOOK_ID=$(echo "$result" | jq -r '.result.content[0].text' | grep -o 'ach[a-zA-Z0-9]\{10,20\}' | head -1)
58
- echo " ๐Ÿช Stored webhook ID: $TEST_WEBHOOK_ID"
59
- elif [[ "$tool_name" == "create_field" ]]; then
60
- CREATED_FIELD_ID=$(echo "$result" | jq -r '.result.content[0].text' | grep -o 'fld[a-zA-Z0-9]\{10,20\}' | head -1)
61
- echo " ๐Ÿ—๏ธ Stored field ID: $CREATED_FIELD_ID"
62
- fi
63
- fi
64
- else
65
- if echo "$result" | jq -e '.error' > /dev/null 2>&1; then
66
- error_msg=$(echo "$result" | jq -r '.error.message')
67
- if [[ "$expect_fail" == "true" ]]; then
68
- echo "โœ… PASS (Expected error: $error_msg)"
69
- ((PASSED++))
70
- else
71
- echo "โŒ FAIL (API Error: $error_msg)"
72
- ((FAILED++))
73
- fi
74
- else
75
- echo "โŒ FAIL (Invalid response)"
76
- echo " Response: $result"
77
- ((FAILED++))
78
- fi
79
- fi
80
- else
81
- echo "โŒ FAIL (Request failed)"
82
- echo " Error: $result"
83
- ((FAILED++))
84
- fi
85
- }
86
-
87
- echo "๐Ÿ“Š PHASE 1: Core Data Operations (7 tools)"
88
- echo "==========================================="
89
-
90
- test_tool "list_tables" "{}" "List all tables in base"
91
- test_tool "list_records" "{\"table\": \"Test Table CRUD\", \"maxRecords\": 3}" "List records with limit"
92
- test_tool "create_record" "{\"table\": \"Test Table CRUD\", \"fields\": {\"Name\": \"v1.5.0 Test Record\", \"Description\": \"Created during final testing\", \"Status\": \"Testing\"}}" "Create test record"
93
-
94
- # Use the created record ID for get_record test
95
- if [[ -n "$TEST_RECORD_ID" ]]; then
96
- test_tool "get_record" "{\"table\": \"Test Table CRUD\", \"recordId\": \"$TEST_RECORD_ID\"}" "Get the created record"
97
- test_tool "update_record" "{\"table\": \"Test Table CRUD\", \"recordId\": \"$TEST_RECORD_ID\", \"fields\": {\"Status\": \"Updated\"}}" "Update the created record"
98
- else
99
- echo "โš ๏ธ Skipping get_record and update_record tests (no record ID)"
100
- ((FAILED += 2))
101
- fi
102
-
103
- test_tool "search_records" "{\"table\": \"Test Table CRUD\", \"searchTerm\": \"v1.5.0\"}" "Search for our test record"
104
-
105
- echo ""
106
- echo "๐Ÿ”— PHASE 2: Webhook Management (5 tools)"
107
- echo "========================================"
108
-
109
- test_tool "list_webhooks" "{}" "List existing webhooks"
110
- test_tool "create_webhook" "{\"notificationUrl\": \"https://webhook.site/test-v1.5.0\", \"specification\": {\"options\": {\"filters\": {\"dataTypes\": [\"tableData\"]}}}}" "Create test webhook"
111
-
112
- if [[ -n "$TEST_WEBHOOK_ID" ]]; then
113
- test_tool "get_webhook_payloads" "{\"webhookId\": \"$TEST_WEBHOOK_ID\"}" "Get webhook payloads"
114
- test_tool "refresh_webhook" "{\"webhookId\": \"$TEST_WEBHOOK_ID\"}" "Refresh webhook"
115
- test_tool "delete_webhook" "{\"webhookId\": \"$TEST_WEBHOOK_ID\"}" "Delete test webhook"
116
- else
117
- echo "โš ๏ธ Skipping webhook payload/refresh/delete tests (no webhook ID)"
118
- ((FAILED += 3))
119
- fi
120
-
121
- echo ""
122
- echo "๐Ÿ—๏ธ PHASE 3: NEW Schema Discovery (6 tools)"
123
- echo "==========================================="
124
-
125
- test_tool "list_bases" "{}" "Discover all accessible bases"
126
- test_tool "get_base_schema" "{}" "Get complete base schema"
127
- test_tool "describe_table" "{\"table\": \"Test Table CRUD\"}" "Describe table with field details"
128
- test_tool "list_field_types" "{}" "List all available field types"
129
- test_tool "get_table_views" "{\"table\": \"Test Table CRUD\"}" "Get table views"
130
-
131
- # Test pagination for list_bases
132
- test_tool "list_bases" "{\"offset\": \"invalid_offset\"}" "Test list_bases with invalid offset"
133
-
134
- echo ""
135
- echo "๐Ÿ”ง PHASE 4: NEW Field Management (4 tools)"
136
- echo "=========================================="
137
-
138
- test_tool "create_field" "{\"table\": \"Test Table CRUD\", \"name\": \"v1.5.0 Test Field\", \"type\": \"singleLineText\", \"description\": \"Field created during v1.5.0 testing\"}" "Create new field"
139
-
140
- if [[ -n "$CREATED_FIELD_ID" ]]; then
141
- test_tool "update_field" "{\"table\": \"Test Table CRUD\", \"fieldId\": \"$CREATED_FIELD_ID\", \"name\": \"v1.5.0 Updated Field\", \"description\": \"Updated during testing\"}" "Update the created field"
142
- test_tool "delete_field" "{\"table\": \"Test Table CRUD\", \"fieldId\": \"$CREATED_FIELD_ID\", \"confirm\": true}" "Delete the test field"
143
- else
144
- echo "โš ๏ธ Skipping field update/delete tests (no field ID)"
145
- ((FAILED += 2))
146
- fi
147
-
148
- # Test safety checks
149
- test_tool "delete_field" "{\"table\": \"Test Table CRUD\", \"fieldId\": \"fldDummyID\", \"confirm\": false}" "Test field deletion without confirmation" "true"
150
-
151
- echo ""
152
- echo "๐Ÿข PHASE 5: NEW Table Management (3 tools)"
153
- echo "========================================="
154
-
155
- test_tool "create_table" "{\"name\": \"v1.5.0 Test Table\", \"description\": \"Table created during v1.5.0 testing\", \"fields\": [{\"name\": \"Name\", \"type\": \"singleLineText\"}, {\"name\": \"Notes\", \"type\": \"multilineText\"}]}" "Create new table"
156
- test_tool "update_table" "{\"table\": \"v1.5.0 Test Table\", \"name\": \"v1.5.0 Updated Table\", \"description\": \"Updated description\"}" "Update table metadata"
157
-
158
- # Test safety checks
159
- test_tool "delete_table" "{\"table\": \"v1.5.0 Updated Table\", \"confirm\": false}" "Test table deletion without confirmation" "true"
160
- test_tool "delete_table" "{\"table\": \"v1.5.0 Updated Table\", \"confirm\": true}" "Delete the test table"
161
-
162
- echo ""
163
- echo "โš ๏ธ PHASE 6: Error Handling & Edge Cases"
164
- echo "======================================="
165
-
166
- test_tool "get_record" "{\"table\": \"NonExistentTable\", \"recordId\": \"recFakeID123\"}" "Test with non-existent table" "true"
167
- test_tool "describe_table" "{\"table\": \"NonExistentTable\"}" "Test describe non-existent table" "true"
168
- test_tool "create_field" "{\"table\": \"NonExistentTable\", \"name\": \"Test\", \"type\": \"singleLineText\"}" "Test create field in non-existent table" "true"
169
- test_tool "update_table" "{\"table\": \"NonExistentTable\", \"name\": \"New Name\"}" "Test update non-existent table" "true"
170
-
171
- echo ""
172
- echo "๐Ÿ”’ PHASE 7: Security Verification"
173
- echo "================================"
174
-
175
- # Check that logs don't contain sensitive data
176
- echo -n "๐Ÿ”’ Security check: Log file doesn't contain tokens... "
177
- if grep -q "pat" /tmp/v1.5.0_test.log; then
178
- echo "โŒ FAIL (Token found in logs)"
179
- ((FAILED++))
180
- else
181
- echo "โœ… PASS"
182
- ((PASSED++))
183
- fi
184
-
185
- # Clean up test record if it exists
186
- if [[ -n "$TEST_RECORD_ID" ]]; then
187
- echo -n "๐Ÿงน Cleanup: Deleting test record... "
188
- cleanup_result=$(test_tool "delete_record" "{\"table\": \"Test Table CRUD\", \"recordId\": \"$TEST_RECORD_ID\"}" "Delete test record" 2>&1)
189
- if echo "$cleanup_result" | grep -q "โœ… PASS"; then
190
- echo "โœ… CLEANED"
191
- else
192
- echo "โš ๏ธ CLEANUP FAILED"
193
- fi
194
- fi
195
-
196
- echo ""
197
- echo "๐Ÿ“ˆ FINAL TEST RESULTS"
198
- echo "===================="
199
- echo "โœ… Passed: $PASSED"
200
- echo "โŒ Failed: $FAILED"
201
- echo "๐Ÿ“Š Total Tests: $((PASSED + FAILED))"
202
- echo "๐Ÿ“Š Success Rate: $(echo "scale=1; $PASSED * 100 / ($PASSED + $FAILED)" | bc -l)%"
203
-
204
- if [ $FAILED -eq 0 ]; then
205
- echo ""
206
- echo "๐ŸŽ‰ ๐ŸŽ‰ ๐ŸŽ‰ ALL TESTS PASSED! ๐ŸŽ‰ ๐ŸŽ‰ ๐ŸŽ‰"
207
- echo ""
208
- echo "โœ… v1.5.0 is READY FOR PRODUCTION!"
209
- echo ""
210
- echo "๐Ÿš€ ACHIEVEMENTS:"
211
- echo "โ€ข 23 tools working perfectly"
212
- echo "โ€ข Complete schema management"
213
- echo "โ€ข Robust error handling"
214
- echo "โ€ข Security verified"
215
- echo "โ€ข All edge cases handled"
216
- echo ""
217
- echo "๐Ÿ“ฆ Ready for GitHub and NPM release!"
218
- exit 0
219
- else
220
- echo ""
221
- echo "โŒ SOME TESTS FAILED"
222
- echo "Please review failures above before release."
223
- exit 1
224
- fi