@rashidazarang/airtable-mcp 1.5.0 → 2.1.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 (119) hide show
  1. package/.github/ISSUE_TEMPLATE/bug-report.yml +173 -0
  2. package/.github/ISSUE_TEMPLATE/feature-request.yml +209 -0
  3. package/.github/ISSUE_TEMPLATE/security-report.yml +216 -0
  4. package/.github/pull_request_template.md +245 -0
  5. package/.github/workflows/ci-cd.yml +408 -0
  6. package/.github/workflows/security-audit.yml +316 -0
  7. package/API_DOCUMENTATION.md +897 -0
  8. package/CODE_OF_CONDUCT.md +181 -0
  9. package/Dockerfile.production +127 -0
  10. package/README.md +55 -10
  11. package/RELEASE_NOTES_v1.6.0.md +248 -0
  12. package/airtable-clipper/CHANGELOG.md +198 -0
  13. package/airtable-clipper/CHROME_STORE_SUBMISSION.md +343 -0
  14. package/airtable-clipper/LAUNCH_STRATEGY.md +495 -0
  15. package/airtable-clipper/LICENSE +21 -0
  16. package/airtable-clipper/OAUTH_SETUP.md +51 -0
  17. package/airtable-clipper/PRIVACY_POLICY.md +187 -0
  18. package/airtable-clipper/README.md +575 -0
  19. package/airtable-clipper/SUBMIT_TO_CHROME_STORE.md +273 -0
  20. package/airtable-clipper/build.sh +85 -0
  21. package/airtable-clipper/docs/QUICK_START.md +99 -0
  22. package/airtable-clipper/docs/SETUP.md +291 -0
  23. package/airtable-clipper/extension/background.js +337 -0
  24. package/airtable-clipper/extension/base-setup.html +324 -0
  25. package/airtable-clipper/extension/base-setup.js +471 -0
  26. package/airtable-clipper/extension/content.js +771 -0
  27. package/airtable-clipper/extension/icons/README.md +69 -0
  28. package/airtable-clipper/extension/icons/icon-16.png +3 -0
  29. package/airtable-clipper/extension/manifest.json +73 -0
  30. package/airtable-clipper/extension/popup.html +144 -0
  31. package/airtable-clipper/extension/popup.js +475 -0
  32. package/airtable-clipper/extension/styles/content.css +229 -0
  33. package/airtable-clipper/extension/styles/popup.css +477 -0
  34. package/airtable-clipper/privacy-policy.md +63 -0
  35. package/airtable-clipper/releases/v1.0.0/background.js +337 -0
  36. package/airtable-clipper/releases/v1.0.0/base-setup.html +324 -0
  37. package/airtable-clipper/releases/v1.0.0/base-setup.js +471 -0
  38. package/airtable-clipper/releases/v1.0.0/content.js +771 -0
  39. package/airtable-clipper/releases/v1.0.0/icons/README.md +69 -0
  40. package/airtable-clipper/releases/v1.0.0/icons/icon-128.png +2 -0
  41. package/airtable-clipper/releases/v1.0.0/icons/icon-16.png +3 -0
  42. package/airtable-clipper/releases/v1.0.0/icons/icon-32.png +2 -0
  43. package/airtable-clipper/releases/v1.0.0/icons/icon-48.png +2 -0
  44. package/airtable-clipper/releases/v1.0.0/manifest.json +73 -0
  45. package/airtable-clipper/releases/v1.0.0/popup.html +144 -0
  46. package/airtable-clipper/releases/v1.0.0/popup.js +475 -0
  47. package/airtable-clipper/releases/v1.0.0/sidepanel.html +25 -0
  48. package/airtable-clipper/releases/v1.0.0/styles/content.css +229 -0
  49. package/airtable-clipper/releases/v1.0.0/styles/popup.css +477 -0
  50. package/airtable-clipper/releases/v1.0.1/background.js +337 -0
  51. package/airtable-clipper/releases/v1.0.1/base-setup.html +324 -0
  52. package/airtable-clipper/releases/v1.0.1/base-setup.js +471 -0
  53. package/airtable-clipper/releases/v1.0.1/content.js +771 -0
  54. package/airtable-clipper/releases/v1.0.1/icons/README.md +69 -0
  55. package/airtable-clipper/releases/v1.0.1/icons/icon-128.png +2 -0
  56. package/airtable-clipper/releases/v1.0.1/icons/icon-16.png +3 -0
  57. package/airtable-clipper/releases/v1.0.1/icons/icon-32.png +2 -0
  58. package/airtable-clipper/releases/v1.0.1/icons/icon-48.png +2 -0
  59. package/airtable-clipper/releases/v1.0.1/manifest.json +70 -0
  60. package/airtable-clipper/releases/v1.0.1/popup.html +157 -0
  61. package/airtable-clipper/releases/v1.0.1/popup.js +562 -0
  62. package/airtable-clipper/releases/v1.0.1/sidepanel.html +25 -0
  63. package/airtable-clipper/releases/v1.0.1/styles/content.css +229 -0
  64. package/airtable-clipper/releases/v1.0.1/styles/popup.css +647 -0
  65. package/airtable-clipper/releases/v1.0.2/background.js +337 -0
  66. package/airtable-clipper/releases/v1.0.2/base-setup.html +324 -0
  67. package/airtable-clipper/releases/v1.0.2/base-setup.js +471 -0
  68. package/airtable-clipper/releases/v1.0.2/content.js +771 -0
  69. package/airtable-clipper/releases/v1.0.2/icons/README.md +69 -0
  70. package/airtable-clipper/releases/v1.0.2/icons/icon-128.png +2 -0
  71. package/airtable-clipper/releases/v1.0.2/icons/icon-16.png +3 -0
  72. package/airtable-clipper/releases/v1.0.2/icons/icon-32.png +2 -0
  73. package/airtable-clipper/releases/v1.0.2/icons/icon-48.png +2 -0
  74. package/airtable-clipper/releases/v1.0.2/manifest.json +62 -0
  75. package/airtable-clipper/releases/v1.0.2/popup.html +157 -0
  76. package/airtable-clipper/releases/v1.0.2/popup.js +567 -0
  77. package/airtable-clipper/releases/v1.0.2/sidepanel.html +25 -0
  78. package/airtable-clipper/releases/v1.0.2/styles/content.css +229 -0
  79. package/airtable-clipper/releases/v1.0.2/styles/popup.css +647 -0
  80. package/airtable-clipper/terms-of-service.md +124 -0
  81. package/airtable-clipper/test-credentials.md +61 -0
  82. package/airtable-clipper/test-extension/background.js +337 -0
  83. package/airtable-clipper/test-extension/base-setup.html +324 -0
  84. package/airtable-clipper/test-extension/base-setup.js +471 -0
  85. package/airtable-clipper/test-extension/content.js +873 -0
  86. package/airtable-clipper/test-extension/icons/README.md +69 -0
  87. package/airtable-clipper/test-extension/icons/icon-128.png +2 -0
  88. package/airtable-clipper/test-extension/icons/icon-16.png +3 -0
  89. package/airtable-clipper/test-extension/icons/icon-32.png +2 -0
  90. package/airtable-clipper/test-extension/icons/icon-48.png +2 -0
  91. package/airtable-clipper/test-extension/manifest.json +72 -0
  92. package/airtable-clipper/test-extension/popup.html +274 -0
  93. package/airtable-clipper/test-extension/popup.js +729 -0
  94. package/airtable-clipper/test-extension/sidepanel.html +25 -0
  95. package/airtable-clipper/test-extension/styles/content.css +229 -0
  96. package/airtable-clipper/test-extension/styles/popup.css +794 -0
  97. package/airtable_mcp_v2.js +1505 -0
  98. package/airtable_mcp_v2_oauth.js +1048 -0
  99. package/airtable_mcp_v3_advanced.js +1161 -0
  100. package/airtable_simple.js +447 -1
  101. package/airtable_simple_production.js +532 -0
  102. package/docker-compose.production.yml +366 -0
  103. package/helm/airtable-mcp/Chart.yaml +122 -0
  104. package/helm/airtable-mcp/values.yaml +538 -0
  105. package/k8s/deployment.yaml +402 -0
  106. package/k8s/namespace.yaml +108 -0
  107. package/k8s/service.yaml +194 -0
  108. package/monitoring/alerts.yml +289 -0
  109. package/monitoring/prometheus.yml +224 -0
  110. package/package.json +6 -6
  111. package/test_v1.6.0_comprehensive.sh +187 -0
  112. package/.claude/settings.local.json +0 -12
  113. package/airtable-mcp-1.1.0.tgz +0 -0
  114. package/airtable_enhanced.js +0 -499
  115. package/airtable_simple_v1.2.4_backup.js +0 -277
  116. package/airtable_v1.4.0.js +0 -654
  117. package/rashidazarang-airtable-mcp-1.1.0.tgz +0 -0
  118. package/rashidazarang-airtable-mcp-1.2.0.tgz +0 -0
  119. package/rashidazarang-airtable-mcp-1.2.1.tgz +0 -0
@@ -1,277 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- const http = require('http');
4
- const https = require('https');
5
- const fs = require('fs');
6
- const path = require('path');
7
-
8
- // Load environment variables from .env file if it exists
9
- const envPath = path.join(__dirname, '.env');
10
- if (fs.existsSync(envPath)) {
11
- require('dotenv').config({ path: envPath });
12
- }
13
-
14
- // Parse command line arguments with environment variable fallback
15
- const args = process.argv.slice(2);
16
- let tokenIndex = args.indexOf('--token');
17
- let baseIndex = args.indexOf('--base');
18
-
19
- // Use environment variables as fallback
20
- const token = tokenIndex !== -1 ? args[tokenIndex + 1] : process.env.AIRTABLE_TOKEN || process.env.AIRTABLE_API_TOKEN;
21
- const baseId = baseIndex !== -1 ? args[baseIndex + 1] : process.env.AIRTABLE_BASE_ID || process.env.AIRTABLE_BASE;
22
-
23
- if (!token || !baseId) {
24
- console.error('Error: Missing Airtable credentials');
25
- console.error('\nUsage options:');
26
- console.error(' 1. Command line: node airtable_simple.js --token YOUR_TOKEN --base YOUR_BASE_ID');
27
- console.error(' 2. Environment variables: AIRTABLE_TOKEN and AIRTABLE_BASE_ID');
28
- console.error(' 3. .env file with AIRTABLE_TOKEN and AIRTABLE_BASE_ID');
29
- process.exit(1);
30
- }
31
-
32
- // Configure logging levels
33
- const LOG_LEVELS = {
34
- ERROR: 0,
35
- WARN: 1,
36
- INFO: 2,
37
- DEBUG: 3
38
- };
39
-
40
- const currentLogLevel = process.env.LOG_LEVEL ? LOG_LEVELS[process.env.LOG_LEVEL.toUpperCase()] || LOG_LEVELS.INFO : LOG_LEVELS.INFO;
41
-
42
- function log(level, message, ...args) {
43
- const levelName = Object.keys(LOG_LEVELS).find(key => LOG_LEVELS[key] === level);
44
- const timestamp = new Date().toISOString();
45
-
46
- if (level <= currentLogLevel) {
47
- const prefix = `[${timestamp}] [${levelName}]`;
48
- if (level === LOG_LEVELS.ERROR) {
49
- console.error(prefix, message, ...args);
50
- } else if (level === LOG_LEVELS.WARN) {
51
- console.warn(prefix, message, ...args);
52
- } else {
53
- console.log(prefix, message, ...args);
54
- }
55
- }
56
- }
57
-
58
- log(LOG_LEVELS.INFO, `Starting Airtable MCP server with token ${token.slice(0, 5)}...${token.slice(-5)} and base ${baseId}`);
59
-
60
- // Create HTTP server
61
- const server = http.createServer(async (req, res) => {
62
- // Enable CORS
63
- res.setHeader('Access-Control-Allow-Origin', '*');
64
- res.setHeader('Access-Control-Allow-Methods', 'POST, OPTIONS');
65
- res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
66
-
67
- // Handle preflight request
68
- if (req.method === 'OPTIONS') {
69
- res.writeHead(200);
70
- res.end();
71
- return;
72
- }
73
-
74
- // Only handle POST requests to /mcp
75
- if (req.method !== 'POST' || !req.url.endsWith('/mcp')) {
76
- res.writeHead(404);
77
- res.end();
78
- return;
79
- }
80
-
81
- let body = '';
82
- req.on('data', chunk => {
83
- body += chunk.toString();
84
- });
85
-
86
- req.on('end', async () => {
87
- try {
88
- const request = JSON.parse(body);
89
-
90
- // Handle JSON-RPC methods
91
- if (request.method === 'resources/list') {
92
- const response = {
93
- jsonrpc: '2.0',
94
- id: request.id,
95
- result: {
96
- resources: [
97
- {
98
- id: 'airtable_tables',
99
- name: 'Airtable Tables',
100
- description: 'Tables in your Airtable base'
101
- }
102
- ]
103
- }
104
- };
105
- res.writeHead(200, { 'Content-Type': 'application/json' });
106
- res.end(JSON.stringify(response));
107
- return;
108
- }
109
-
110
- if (request.method === 'prompts/list') {
111
- const response = {
112
- jsonrpc: '2.0',
113
- id: request.id,
114
- result: {
115
- prompts: [
116
- {
117
- id: 'tables_prompt',
118
- name: 'List Tables',
119
- description: 'List all tables'
120
- }
121
- ]
122
- }
123
- };
124
- res.writeHead(200, { 'Content-Type': 'application/json' });
125
- res.end(JSON.stringify(response));
126
- return;
127
- }
128
-
129
- // Handle tool calls
130
- if (request.method === 'tools/call') {
131
- const toolName = request.params.name;
132
-
133
- if (toolName === 'list_tables') {
134
- // Call Airtable API to list tables
135
- const result = await callAirtableAPI(`meta/bases/${baseId}/tables`);
136
- const tables = result.tables || [];
137
-
138
- const tableList = tables.map((table, i) =>
139
- `${i+1}. ${table.name} (ID: ${table.id})`
140
- ).join('\n');
141
-
142
- const response = {
143
- jsonrpc: '2.0',
144
- id: request.id,
145
- result: {
146
- content: [
147
- {
148
- type: 'text',
149
- text: tables.length > 0
150
- ? `Tables in this base:\n${tableList}`
151
- : 'No tables found in this base.'
152
- }
153
- ]
154
- }
155
- };
156
-
157
- res.writeHead(200, { 'Content-Type': 'application/json' });
158
- res.end(JSON.stringify(response));
159
- return;
160
- }
161
-
162
- if (toolName === 'list_records') {
163
- const tableName = request.params.arguments.table_name;
164
- const maxRecords = request.params.arguments.max_records || 100;
165
-
166
- // Call Airtable API to list records
167
- const result = await callAirtableAPI(`${baseId}/${tableName}`, { maxRecords });
168
- const records = result.records || [];
169
-
170
- const recordList = records.map((record, i) => {
171
- const fields = Object.entries(record.fields || {})
172
- .map(([k, v]) => `${k}: ${v}`)
173
- .join(', ');
174
- return `${i+1}. ID: ${record.id} - ${fields}`;
175
- }).join('\n');
176
-
177
- const response = {
178
- jsonrpc: '2.0',
179
- id: request.id,
180
- result: {
181
- content: [
182
- {
183
- type: 'text',
184
- text: records.length > 0
185
- ? `Records:\n${recordList}`
186
- : 'No records found in this table.'
187
- }
188
- ]
189
- }
190
- };
191
-
192
- res.writeHead(200, { 'Content-Type': 'application/json' });
193
- res.end(JSON.stringify(response));
194
- return;
195
- }
196
-
197
- // Tool not found
198
- const response = {
199
- jsonrpc: '2.0',
200
- id: request.id,
201
- error: {
202
- code: -32601,
203
- message: `Tool ${toolName} not found`
204
- }
205
- };
206
- res.writeHead(200, { 'Content-Type': 'application/json' });
207
- res.end(JSON.stringify(response));
208
- return;
209
- }
210
-
211
- // Method not found
212
- const response = {
213
- jsonrpc: '2.0',
214
- id: request.id,
215
- error: {
216
- code: -32601,
217
- message: `Method ${request.method} not found`
218
- }
219
- };
220
- res.writeHead(200, { 'Content-Type': 'application/json' });
221
- res.end(JSON.stringify(response));
222
-
223
- } catch (error) {
224
- console.error('Error processing request:', error);
225
- const response = {
226
- jsonrpc: '2.0',
227
- id: request.id || null,
228
- error: {
229
- code: -32000,
230
- message: error.message || 'Unknown error'
231
- }
232
- };
233
- res.writeHead(200, { 'Content-Type': 'application/json' });
234
- res.end(JSON.stringify(response));
235
- }
236
- });
237
- });
238
-
239
- // Helper function to call Airtable API
240
- function callAirtableAPI(endpoint, params = {}) {
241
- return new Promise((resolve, reject) => {
242
- const queryParams = new URLSearchParams(params).toString();
243
- const url = `https://api.airtable.com/v0/${endpoint}${queryParams ? '?' + queryParams : ''}`;
244
-
245
- const options = {
246
- headers: {
247
- 'Authorization': `Bearer ${token}`,
248
- 'Content-Type': 'application/json'
249
- }
250
- };
251
-
252
- https.get(url, options, (response) => {
253
- let data = '';
254
-
255
- response.on('data', (chunk) => {
256
- data += chunk;
257
- });
258
-
259
- response.on('end', () => {
260
- try {
261
- resolve(JSON.parse(data));
262
- } catch (e) {
263
- reject(new Error(`Failed to parse Airtable response: ${e.message}`));
264
- }
265
- });
266
- }).on('error', (error) => {
267
- reject(new Error(`Airtable API request failed: ${error.message}`));
268
- });
269
- });
270
- }
271
-
272
- // Start the server on port 8010
273
- const PORT = 8010;
274
- server.listen(PORT, () => {
275
- console.log(`Airtable MCP server running at http://localhost:${PORT}/mcp`);
276
- console.log(`For Claude, use this URL: http://localhost:${PORT}/mcp`);
277
- });