#
tokens: 3310/50000 5/5 files
lines: off (toggle) GitHub
raw markdown copy
# Directory Structure

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

# Files

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

```
node_modules/
build/
*.log
.env*
```

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

```markdown
# Glide API MCP Server

A Model Context Protocol server for interacting with the Glide API (v1 & v2).

## Features

- Support for both Glide API v1 and v2
- Secure API key handling through environment variables
- Type-safe TypeScript implementation
- Comprehensive error handling

## Available Tools

- `set_api_version`: Configure API version and authentication
- `get_app`: Get app information
- `get_tables`: List app tables
- `get_table_rows`: Get table data
- `add_table_row`: Add new row
- `update_table_row`: Update existing row

## Secure Setup

### 1. Environment Variables

The server supports secure configuration through environment variables in the MCP settings file. Add your API credentials to the MCP settings file:

```json
{
  "mcpServers": {
    "glide-api": {
      "command": "node",
      "args": ["path/to/build/index.js"],
      "env": {
        "GLIDE_API_KEY": "your-api-key-here",
        "GLIDE_API_VERSION": "v2"  // or "v1" for v1 API
      }
    }
  }
}
```

This approach keeps your API key secure by:
- Storing it in a configuration file rather than in code
- Keeping it out of version control
- Making it easy to update without modifying code

### 2. Runtime Configuration

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:

```typescript
use_mcp_tool({
  server_name: "glide-api",
  tool_name: "set_api_version",
  arguments: {
    version: "v2",
    apiKey: "your-api-key"
  }
});
```

Note: The runtime configuration will override any environment variables for the current session.

### 3. Security Best Practices

1. Never commit API keys to version control
2. Use environment variables in the MCP settings file
3. Regularly rotate your API keys
4. Set appropriate file permissions on the settings file

## Development

Install dependencies:
```bash
npm install
```

Build the server:
```bash
npm run build
```

For development with auto-rebuild:
```bash
npm run watch
```

## Usage Examples

1. Get app information:
```typescript
use_mcp_tool({
  server_name: "glide-api",
  tool_name: "get_app",
  arguments: {
    appId: "your-app-id"
  }
});
```

2. Add a row to a table:
```typescript
use_mcp_tool({
  server_name: "glide-api",
  tool_name: "add_table_row",
  arguments: {
    appId: "your-app-id",
    tableId: "your-table-id",
    values: {
      column1: "value1",
      column2: "value2"
    }
  }
});

```

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

```json
{
  "compilerOptions": {
    "target": "ES2020",
    "module": "ES2020",
    "moduleResolution": "node",
    "esModuleInterop": true,
    "strict": true,
    "outDir": "build",
    "rootDir": "src",
    "declaration": true,
    "skipLibCheck": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "build"]
}

```

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

```json
{
  "name": "glide-api-mcp-server",
  "version": "0.1.0",
  "description": "MCP server for interacting with Glide API v1 and v2",
  "type": "module",
  "main": "build/index.js",
  "scripts": {
    "build": "tsc && chmod +x build/index.js",
    "watch": "tsc -w",
    "start": "node build/index.js"
  },
  "dependencies": {
    "@modelcontextprotocol/sdk": "^1.0.4",
    "axios": "^1.6.2"
  },
  "devDependencies": {
    "@types/node": "^20.10.0",
    "typescript": "^5.3.2"
  }
}

```

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

```typescript
#!/usr/bin/env node
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
  CallToolRequestSchema,
  ErrorCode,
  ListToolsRequestSchema,
  McpError,
} from '@modelcontextprotocol/sdk/types.js';
import axios, { AxiosInstance } from 'axios';

// Abstract base class for Glide API versions
abstract class GlideApiClient {
  protected client: AxiosInstance;
  
  constructor(apiKey: string) {
    this.client = axios.create({
      baseURL: this.getBaseUrl(),
      headers: this.getAuthHeaders(apiKey),
    });
  }
  
  abstract getBaseUrl(): string;
  abstract getAuthHeaders(apiKey: string): Record<string, string>;
  
  public async makeRequest(method: 'GET' | 'POST', endpoint: string, data?: any) {
    try {
      const response = await this.client.request({
        method,
        url: endpoint,
        data,
      });
      return response.data;
    } catch (error: unknown) {
      if (axios.isAxiosError(error)) {
        throw new McpError(
          ErrorCode.InternalError,
          `Glide API error: ${error.response?.data?.message || error.message}`
        );
      }
      throw error;
    }
  }
}

// V1 API implementation
class GlideApiV1Client extends GlideApiClient {
  getBaseUrl(): string {
    return 'https://api.glideapp.io';
  }
  
  getAuthHeaders(apiKey: string): Record<string, string> {
    return {
      'X-API-Key': apiKey,
      'Content-Type': 'application/json',
    };
  }
}

// V2 API implementation
class GlideApiV2Client extends GlideApiClient {
  getBaseUrl(): string {
    return 'https://api.glideapp.com/api/v2';
  }
  
  getAuthHeaders(apiKey: string): Record<string, string> {
    return {
      'Authorization': `Bearer ${apiKey}`,
      'Content-Type': 'application/json',
    };
  }
}

class GlideApiServer {
  private server: Server;
  private apiClient: GlideApiClient | null = null;
  private readonly apiVersions = {
    v1: GlideApiV1Client,
    v2: GlideApiV2Client,
  };

  constructor() {
    // Initialize with environment variables if available
    const envApiKey = process.env.GLIDE_API_KEY;
    const envApiVersion = process.env.GLIDE_API_VERSION as 'v1' | 'v2' | undefined;

    if (envApiKey && envApiVersion && this.apiVersions[envApiVersion]) {
      console.error(`Initializing Glide API with version ${envApiVersion} from environment`);
      const ClientClass = this.apiVersions[envApiVersion];
      this.apiClient = new ClientClass(envApiKey);
    } else {
      console.error('No environment configuration found. API version and key must be set using set_api_version tool.');
    }

    this.server = new Server(
      {
        name: 'glide-api-server',
        version: '0.1.0',
      },
      {
        capabilities: {
          tools: {},
        },
      }
    );

    this.setupToolHandlers();
    
    this.server.onerror = (error: Error) => console.error('[MCP Error]', error);
    process.on('SIGINT', async () => {
      await this.server.close();
      process.exit(0);
    });
  }

  private setupToolHandlers() {
    this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
      tools: [
        {
          name: 'set_api_version',
          description: 'Set the Glide API version and authentication to use',
          inputSchema: {
            type: 'object',
            properties: {
              version: {
                type: 'string',
                enum: ['v1', 'v2'],
                description: 'API version to use',
              },
              apiKey: {
                type: 'string',
                description: 'API key for authentication',
              },
            },
            required: ['version', 'apiKey'],
          },
        },
        {
          name: 'get_app',
          description: 'Get information about a Glide app',
          inputSchema: {
            type: 'object',
            properties: {
              appId: {
                type: 'string',
                description: 'ID of the Glide app',
              },
            },
            required: ['appId'],
          },
        },
        {
          name: 'get_tables',
          description: 'Get tables for a Glide app',
          inputSchema: {
            type: 'object',
            properties: {
              appId: {
                type: 'string',
                description: 'ID of the Glide app',
              },
            },
            required: ['appId'],
          },
        },
        {
          name: 'get_table_rows',
          description: 'Get rows from a table in a Glide app',
          inputSchema: {
            type: 'object',
            properties: {
              appId: {
                type: 'string',
                description: 'ID of the Glide app',
              },
              tableId: {
                type: 'string',
                description: 'ID of the table',
              },
              limit: {
                type: 'number',
                description: 'Maximum number of rows to return',
                minimum: 1,
              },
              offset: {
                type: 'number',
                description: 'Number of rows to skip',
                minimum: 0,
              },
            },
            required: ['appId', 'tableId'],
          },
        },
        {
          name: 'add_table_row',
          description: 'Add a new row to a table in a Glide app',
          inputSchema: {
            type: 'object',
            properties: {
              appId: {
                type: 'string',
                description: 'ID of the Glide app',
              },
              tableId: {
                type: 'string',
                description: 'ID of the table',
              },
              values: {
                type: 'object',
                description: 'Column values for the new row',
                additionalProperties: true,
              },
            },
            required: ['appId', 'tableId', 'values'],
          },
        },
        {
          name: 'update_table_row',
          description: 'Update an existing row in a table',
          inputSchema: {
            type: 'object',
            properties: {
              appId: {
                type: 'string',
                description: 'ID of the Glide app',
              },
              tableId: {
                type: 'string',
                description: 'ID of the table',
              },
              rowId: {
                type: 'string',
                description: 'ID of the row to update',
              },
              values: {
                type: 'object',
                description: 'New column values for the row',
                additionalProperties: true,
              },
            },
            required: ['appId', 'tableId', 'rowId', 'values'],
          },
        },
      ],
    }));

    this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
      if (request.params.name === 'set_api_version' && request.params.arguments) {
        // Allow overriding environment variables with explicit settings
        const args = request.params.arguments as {
          version: 'v1' | 'v2';
          apiKey: string;
        };

        // Validate API key is not empty
        if (!args.apiKey.trim()) {
          throw new McpError(
            ErrorCode.InvalidParams,
            'API key cannot be empty'
          );
        }

        const ClientClass = this.apiVersions[args.version];
        if (!ClientClass) {
          throw new McpError(
            ErrorCode.InvalidParams,
            `Invalid API version: ${args.version}`
          );
        }

        this.apiClient = new ClientClass(args.apiKey);
        
        return {
          content: [
            {
              type: 'text',
              text: `Glide API version set to ${args.version}`,
            },
          ],
        };
      }

      if (!this.apiClient) {
        throw new McpError(
          ErrorCode.InvalidRequest,
          'API version not set. Call set_api_version first.'
        );
      }

      switch (request.params.name) {
        case 'get_app': {
          const { appId } = request.params.arguments as { appId: string };
          const result = await this.apiClient.makeRequest('GET', `/apps/${appId}`);
          return {
            content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
          };
        }

        case 'get_tables': {
          const { appId } = request.params.arguments as { appId: string };
          const result = await this.apiClient.makeRequest('GET', `/apps/${appId}/tables`);
          return {
            content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
          };
        }

        case 'get_table_rows': {
          const { appId, tableId, limit, offset } = request.params.arguments as {
            appId: string;
            tableId: string;
            limit?: number;
            offset?: number;
          };
          const params = new URLSearchParams();
          if (limit) params.append('limit', limit.toString());
          if (offset) params.append('offset', offset.toString());
          
          const result = await this.apiClient.makeRequest(
            'GET',
            `/apps/${appId}/tables/${tableId}/rows${params.toString() ? '?' + params.toString() : ''}`
          );
          return {
            content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
          };
        }

        case 'add_table_row': {
          const { appId, tableId, values } = request.params.arguments as {
            appId: string;
            tableId: string;
            values: Record<string, any>;
          };
          const result = await this.apiClient.makeRequest(
            'POST',
            `/apps/${appId}/tables/${tableId}/rows`,
            values
          );
          return {
            content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
          };
        }

        case 'update_table_row': {
          const { appId, tableId, rowId, values } = request.params.arguments as {
            appId: string;
            tableId: string;
            rowId: string;
            values: Record<string, any>;
          };
          const result = await this.apiClient.makeRequest(
            'POST',
            `/apps/${appId}/tables/${tableId}/rows/${rowId}`,
            values
          );
          return {
            content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
          };
        }

        default:
          throw new McpError(
            ErrorCode.MethodNotFound,
            `Unknown tool: ${request.params.name}`
          );
      }
    });
  }

  async run() {
    const transport = new StdioServerTransport();
    await this.server.connect(transport);
    console.error('Glide API MCP server running on stdio');
  }
}

const server = new GlideApiServer();
server.run().catch(console.error);

```