#
tokens: 4663/50000 5/5 files
lines: on (toggle) GitHub
raw markdown copy reset
# Directory Structure

```
├── .gitignore
├── package-lock.json
├── package.json
├── README.md
├── src
│   └── index.ts
└── tsconfig.json
```

# Files

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
1 | node_modules/
2 | build/
3 | *.log
4 | .env*
```

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
  1 | # Glide API MCP Server
  2 | 
  3 | A Model Context Protocol server for interacting with the Glide API (v1 & v2).
  4 | 
  5 | ## Features
  6 | 
  7 | - Support for both Glide API v1 and v2
  8 | - Secure API key handling through environment variables
  9 | - Type-safe TypeScript implementation
 10 | - Comprehensive error handling
 11 | 
 12 | ## Available Tools
 13 | 
 14 | - `set_api_version`: Configure API version and authentication
 15 | - `get_app`: Get app information
 16 | - `get_tables`: List app tables
 17 | - `get_table_rows`: Get table data
 18 | - `add_table_row`: Add new row
 19 | - `update_table_row`: Update existing row
 20 | 
 21 | ## Secure Setup
 22 | 
 23 | ### 1. Environment Variables
 24 | 
 25 | The server supports secure configuration through environment variables in the MCP settings file. Add your API credentials to the MCP settings file:
 26 | 
 27 | ```json
 28 | {
 29 |   "mcpServers": {
 30 |     "glide-api": {
 31 |       "command": "node",
 32 |       "args": ["path/to/build/index.js"],
 33 |       "env": {
 34 |         "GLIDE_API_KEY": "your-api-key-here",
 35 |         "GLIDE_API_VERSION": "v2"  // or "v1" for v1 API
 36 |       }
 37 |     }
 38 |   }
 39 | }
 40 | ```
 41 | 
 42 | This approach keeps your API key secure by:
 43 | - Storing it in a configuration file rather than in code
 44 | - Keeping it out of version control
 45 | - Making it easy to update without modifying code
 46 | 
 47 | ### 2. Runtime Configuration
 48 | 
 49 | While environment variables are the recommended way to configure the server, you can also set or override the API version and key at runtime using the `set_api_version` tool:
 50 | 
 51 | ```typescript
 52 | use_mcp_tool({
 53 |   server_name: "glide-api",
 54 |   tool_name: "set_api_version",
 55 |   arguments: {
 56 |     version: "v2",
 57 |     apiKey: "your-api-key"
 58 |   }
 59 | });
 60 | ```
 61 | 
 62 | Note: The runtime configuration will override any environment variables for the current session.
 63 | 
 64 | ### 3. Security Best Practices
 65 | 
 66 | 1. Never commit API keys to version control
 67 | 2. Use environment variables in the MCP settings file
 68 | 3. Regularly rotate your API keys
 69 | 4. Set appropriate file permissions on the settings file
 70 | 
 71 | ## Development
 72 | 
 73 | Install dependencies:
 74 | ```bash
 75 | npm install
 76 | ```
 77 | 
 78 | Build the server:
 79 | ```bash
 80 | npm run build
 81 | ```
 82 | 
 83 | For development with auto-rebuild:
 84 | ```bash
 85 | npm run watch
 86 | ```
 87 | 
 88 | ## Usage Examples
 89 | 
 90 | 1. Get app information:
 91 | ```typescript
 92 | use_mcp_tool({
 93 |   server_name: "glide-api",
 94 |   tool_name: "get_app",
 95 |   arguments: {
 96 |     appId: "your-app-id"
 97 |   }
 98 | });
 99 | ```
100 | 
101 | 2. Add a row to a table:
102 | ```typescript
103 | use_mcp_tool({
104 |   server_name: "glide-api",
105 |   tool_name: "add_table_row",
106 |   arguments: {
107 |     appId: "your-app-id",
108 |     tableId: "your-table-id",
109 |     values: {
110 |       column1: "value1",
111 |       column2: "value2"
112 |     }
113 |   }
114 | });
115 | 
```

--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "compilerOptions": {
 3 |     "target": "ES2020",
 4 |     "module": "ES2020",
 5 |     "moduleResolution": "node",
 6 |     "esModuleInterop": true,
 7 |     "strict": true,
 8 |     "outDir": "build",
 9 |     "rootDir": "src",
10 |     "declaration": true,
11 |     "skipLibCheck": true
12 |   },
13 |   "include": ["src/**/*"],
14 |   "exclude": ["node_modules", "build"]
15 | }
16 | 
```

--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "name": "glide-api-mcp-server",
 3 |   "version": "0.1.0",
 4 |   "description": "MCP server for interacting with Glide API v1 and v2",
 5 |   "type": "module",
 6 |   "main": "build/index.js",
 7 |   "scripts": {
 8 |     "build": "tsc && chmod +x build/index.js",
 9 |     "watch": "tsc -w",
10 |     "start": "node build/index.js"
11 |   },
12 |   "dependencies": {
13 |     "@modelcontextprotocol/sdk": "^1.0.4",
14 |     "axios": "^1.6.2"
15 |   },
16 |   "devDependencies": {
17 |     "@types/node": "^20.10.0",
18 |     "typescript": "^5.3.2"
19 |   }
20 | }
21 | 
```

--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------

```typescript
  1 | #!/usr/bin/env node
  2 | import { Server } from '@modelcontextprotocol/sdk/server/index.js';
  3 | import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
  4 | import {
  5 |   CallToolRequestSchema,
  6 |   ErrorCode,
  7 |   ListToolsRequestSchema,
  8 |   McpError,
  9 | } from '@modelcontextprotocol/sdk/types.js';
 10 | import axios, { AxiosInstance } from 'axios';
 11 | 
 12 | // Abstract base class for Glide API versions
 13 | abstract class GlideApiClient {
 14 |   protected client: AxiosInstance;
 15 |   
 16 |   constructor(apiKey: string) {
 17 |     this.client = axios.create({
 18 |       baseURL: this.getBaseUrl(),
 19 |       headers: this.getAuthHeaders(apiKey),
 20 |     });
 21 |   }
 22 |   
 23 |   abstract getBaseUrl(): string;
 24 |   abstract getAuthHeaders(apiKey: string): Record<string, string>;
 25 |   
 26 |   public async makeRequest(method: 'GET' | 'POST', endpoint: string, data?: any) {
 27 |     try {
 28 |       const response = await this.client.request({
 29 |         method,
 30 |         url: endpoint,
 31 |         data,
 32 |       });
 33 |       return response.data;
 34 |     } catch (error: unknown) {
 35 |       if (axios.isAxiosError(error)) {
 36 |         throw new McpError(
 37 |           ErrorCode.InternalError,
 38 |           `Glide API error: ${error.response?.data?.message || error.message}`
 39 |         );
 40 |       }
 41 |       throw error;
 42 |     }
 43 |   }
 44 | }
 45 | 
 46 | // V1 API implementation
 47 | class GlideApiV1Client extends GlideApiClient {
 48 |   getBaseUrl(): string {
 49 |     return 'https://api.glideapp.io';
 50 |   }
 51 |   
 52 |   getAuthHeaders(apiKey: string): Record<string, string> {
 53 |     return {
 54 |       'X-API-Key': apiKey,
 55 |       'Content-Type': 'application/json',
 56 |     };
 57 |   }
 58 | }
 59 | 
 60 | // V2 API implementation
 61 | class GlideApiV2Client extends GlideApiClient {
 62 |   getBaseUrl(): string {
 63 |     return 'https://api.glideapp.com/api/v2';
 64 |   }
 65 |   
 66 |   getAuthHeaders(apiKey: string): Record<string, string> {
 67 |     return {
 68 |       'Authorization': `Bearer ${apiKey}`,
 69 |       'Content-Type': 'application/json',
 70 |     };
 71 |   }
 72 | }
 73 | 
 74 | class GlideApiServer {
 75 |   private server: Server;
 76 |   private apiClient: GlideApiClient | null = null;
 77 |   private readonly apiVersions = {
 78 |     v1: GlideApiV1Client,
 79 |     v2: GlideApiV2Client,
 80 |   };
 81 | 
 82 |   constructor() {
 83 |     // Initialize with environment variables if available
 84 |     const envApiKey = process.env.GLIDE_API_KEY;
 85 |     const envApiVersion = process.env.GLIDE_API_VERSION as 'v1' | 'v2' | undefined;
 86 | 
 87 |     if (envApiKey && envApiVersion && this.apiVersions[envApiVersion]) {
 88 |       console.error(`Initializing Glide API with version ${envApiVersion} from environment`);
 89 |       const ClientClass = this.apiVersions[envApiVersion];
 90 |       this.apiClient = new ClientClass(envApiKey);
 91 |     } else {
 92 |       console.error('No environment configuration found. API version and key must be set using set_api_version tool.');
 93 |     }
 94 | 
 95 |     this.server = new Server(
 96 |       {
 97 |         name: 'glide-api-server',
 98 |         version: '0.1.0',
 99 |       },
100 |       {
101 |         capabilities: {
102 |           tools: {},
103 |         },
104 |       }
105 |     );
106 | 
107 |     this.setupToolHandlers();
108 |     
109 |     this.server.onerror = (error: Error) => console.error('[MCP Error]', error);
110 |     process.on('SIGINT', async () => {
111 |       await this.server.close();
112 |       process.exit(0);
113 |     });
114 |   }
115 | 
116 |   private setupToolHandlers() {
117 |     this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
118 |       tools: [
119 |         {
120 |           name: 'set_api_version',
121 |           description: 'Set the Glide API version and authentication to use',
122 |           inputSchema: {
123 |             type: 'object',
124 |             properties: {
125 |               version: {
126 |                 type: 'string',
127 |                 enum: ['v1', 'v2'],
128 |                 description: 'API version to use',
129 |               },
130 |               apiKey: {
131 |                 type: 'string',
132 |                 description: 'API key for authentication',
133 |               },
134 |             },
135 |             required: ['version', 'apiKey'],
136 |           },
137 |         },
138 |         {
139 |           name: 'get_app',
140 |           description: 'Get information about a Glide app',
141 |           inputSchema: {
142 |             type: 'object',
143 |             properties: {
144 |               appId: {
145 |                 type: 'string',
146 |                 description: 'ID of the Glide app',
147 |               },
148 |             },
149 |             required: ['appId'],
150 |           },
151 |         },
152 |         {
153 |           name: 'get_tables',
154 |           description: 'Get tables for a Glide app',
155 |           inputSchema: {
156 |             type: 'object',
157 |             properties: {
158 |               appId: {
159 |                 type: 'string',
160 |                 description: 'ID of the Glide app',
161 |               },
162 |             },
163 |             required: ['appId'],
164 |           },
165 |         },
166 |         {
167 |           name: 'get_table_rows',
168 |           description: 'Get rows from a table in a Glide app',
169 |           inputSchema: {
170 |             type: 'object',
171 |             properties: {
172 |               appId: {
173 |                 type: 'string',
174 |                 description: 'ID of the Glide app',
175 |               },
176 |               tableId: {
177 |                 type: 'string',
178 |                 description: 'ID of the table',
179 |               },
180 |               limit: {
181 |                 type: 'number',
182 |                 description: 'Maximum number of rows to return',
183 |                 minimum: 1,
184 |               },
185 |               offset: {
186 |                 type: 'number',
187 |                 description: 'Number of rows to skip',
188 |                 minimum: 0,
189 |               },
190 |             },
191 |             required: ['appId', 'tableId'],
192 |           },
193 |         },
194 |         {
195 |           name: 'add_table_row',
196 |           description: 'Add a new row to a table in a Glide app',
197 |           inputSchema: {
198 |             type: 'object',
199 |             properties: {
200 |               appId: {
201 |                 type: 'string',
202 |                 description: 'ID of the Glide app',
203 |               },
204 |               tableId: {
205 |                 type: 'string',
206 |                 description: 'ID of the table',
207 |               },
208 |               values: {
209 |                 type: 'object',
210 |                 description: 'Column values for the new row',
211 |                 additionalProperties: true,
212 |               },
213 |             },
214 |             required: ['appId', 'tableId', 'values'],
215 |           },
216 |         },
217 |         {
218 |           name: 'update_table_row',
219 |           description: 'Update an existing row in a table',
220 |           inputSchema: {
221 |             type: 'object',
222 |             properties: {
223 |               appId: {
224 |                 type: 'string',
225 |                 description: 'ID of the Glide app',
226 |               },
227 |               tableId: {
228 |                 type: 'string',
229 |                 description: 'ID of the table',
230 |               },
231 |               rowId: {
232 |                 type: 'string',
233 |                 description: 'ID of the row to update',
234 |               },
235 |               values: {
236 |                 type: 'object',
237 |                 description: 'New column values for the row',
238 |                 additionalProperties: true,
239 |               },
240 |             },
241 |             required: ['appId', 'tableId', 'rowId', 'values'],
242 |           },
243 |         },
244 |       ],
245 |     }));
246 | 
247 |     this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
248 |       if (request.params.name === 'set_api_version' && request.params.arguments) {
249 |         // Allow overriding environment variables with explicit settings
250 |         const args = request.params.arguments as {
251 |           version: 'v1' | 'v2';
252 |           apiKey: string;
253 |         };
254 | 
255 |         // Validate API key is not empty
256 |         if (!args.apiKey.trim()) {
257 |           throw new McpError(
258 |             ErrorCode.InvalidParams,
259 |             'API key cannot be empty'
260 |           );
261 |         }
262 | 
263 |         const ClientClass = this.apiVersions[args.version];
264 |         if (!ClientClass) {
265 |           throw new McpError(
266 |             ErrorCode.InvalidParams,
267 |             `Invalid API version: ${args.version}`
268 |           );
269 |         }
270 | 
271 |         this.apiClient = new ClientClass(args.apiKey);
272 |         
273 |         return {
274 |           content: [
275 |             {
276 |               type: 'text',
277 |               text: `Glide API version set to ${args.version}`,
278 |             },
279 |           ],
280 |         };
281 |       }
282 | 
283 |       if (!this.apiClient) {
284 |         throw new McpError(
285 |           ErrorCode.InvalidRequest,
286 |           'API version not set. Call set_api_version first.'
287 |         );
288 |       }
289 | 
290 |       switch (request.params.name) {
291 |         case 'get_app': {
292 |           const { appId } = request.params.arguments as { appId: string };
293 |           const result = await this.apiClient.makeRequest('GET', `/apps/${appId}`);
294 |           return {
295 |             content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
296 |           };
297 |         }
298 | 
299 |         case 'get_tables': {
300 |           const { appId } = request.params.arguments as { appId: string };
301 |           const result = await this.apiClient.makeRequest('GET', `/apps/${appId}/tables`);
302 |           return {
303 |             content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
304 |           };
305 |         }
306 | 
307 |         case 'get_table_rows': {
308 |           const { appId, tableId, limit, offset } = request.params.arguments as {
309 |             appId: string;
310 |             tableId: string;
311 |             limit?: number;
312 |             offset?: number;
313 |           };
314 |           const params = new URLSearchParams();
315 |           if (limit) params.append('limit', limit.toString());
316 |           if (offset) params.append('offset', offset.toString());
317 |           
318 |           const result = await this.apiClient.makeRequest(
319 |             'GET',
320 |             `/apps/${appId}/tables/${tableId}/rows${params.toString() ? '?' + params.toString() : ''}`
321 |           );
322 |           return {
323 |             content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
324 |           };
325 |         }
326 | 
327 |         case 'add_table_row': {
328 |           const { appId, tableId, values } = request.params.arguments as {
329 |             appId: string;
330 |             tableId: string;
331 |             values: Record<string, any>;
332 |           };
333 |           const result = await this.apiClient.makeRequest(
334 |             'POST',
335 |             `/apps/${appId}/tables/${tableId}/rows`,
336 |             values
337 |           );
338 |           return {
339 |             content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
340 |           };
341 |         }
342 | 
343 |         case 'update_table_row': {
344 |           const { appId, tableId, rowId, values } = request.params.arguments as {
345 |             appId: string;
346 |             tableId: string;
347 |             rowId: string;
348 |             values: Record<string, any>;
349 |           };
350 |           const result = await this.apiClient.makeRequest(
351 |             'POST',
352 |             `/apps/${appId}/tables/${tableId}/rows/${rowId}`,
353 |             values
354 |           );
355 |           return {
356 |             content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
357 |           };
358 |         }
359 | 
360 |         default:
361 |           throw new McpError(
362 |             ErrorCode.MethodNotFound,
363 |             `Unknown tool: ${request.params.name}`
364 |           );
365 |       }
366 |     });
367 |   }
368 | 
369 |   async run() {
370 |     const transport = new StdioServerTransport();
371 |     await this.server.connect(transport);
372 |     console.error('Glide API MCP server running on stdio');
373 |   }
374 | }
375 | 
376 | const server = new GlideApiServer();
377 | server.run().catch(console.error);
378 | 
```