#
tokens: 33858/50000 3/119 files (page 3/4)
lines: off (toggle) GitHub
raw markdown copy
This is page 3 of 4. Use http://codebase.md/rashidazarang/airtable-mcp?page={x} to view the full context.

# Directory Structure

```
├── .eslintrc.js
├── .github
│   ├── ISSUE_TEMPLATE
│   │   ├── bug_report.md
│   │   ├── custom.md
│   │   └── feature_request.md
│   └── pull_request_template.md
├── .gitignore
├── .nvmrc
├── .prettierrc
├── bin
│   ├── airtable-crud-cli.js
│   └── airtable-mcp.js
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── docker
│   ├── Dockerfile
│   └── Dockerfile.node
├── docs
│   ├── guides
│   │   ├── CLAUDE_INTEGRATION.md
│   │   ├── ENHANCED_FEATURES.md
│   │   ├── INSTALLATION.md
│   │   └── QUICK_START.md
│   └── releases
│       ├── RELEASE_NOTES_v1.2.2.md
│       ├── RELEASE_NOTES_v1.2.4.md
│       ├── RELEASE_NOTES_v1.4.0.md
│       ├── RELEASE_NOTES_v1.5.0.md
│       └── RELEASE_NOTES_v1.6.0.md
├── examples
│   ├── airtable-crud-example.js
│   ├── building-mcp.md
│   ├── claude_config.json
│   ├── claude_simple_config.json
│   ├── env-demo.js
│   ├── example_usage.md
│   ├── example-tasks-update.json
│   ├── example-tasks.json
│   ├── python_debug_patch.txt
│   ├── sample-transform.js
│   ├── typescript
│   │   ├── advanced-ai-prompts.ts
│   │   ├── basic-usage.ts
│   │   └── claude-desktop-config.json
│   └── windsurf_mcp_config.json
├── index.js
├── ISSUE_RESPONSES.md
├── jest.config.js
├── LICENSE
├── package-lock.json
├── package.json
├── PROJECT_STRUCTURE.md
├── README.md
├── RELEASE_SUMMARY_v3.2.x.md
├── RELEASE_v3.2.1.md
├── RELEASE_v3.2.3.md
├── RELEASE_v3.2.4.md
├── requirements.txt
├── SECURITY_NOTICE.md
├── smithery.yaml
├── src
│   ├── index.js
│   ├── javascript
│   │   ├── airtable_simple_production.js
│   │   └── airtable_simple.js
│   ├── python
│   │   ├── airtable_mcp
│   │   │   ├── __init__.py
│   │   │   └── src
│   │   │       └── server.py
│   │   ├── inspector_server.py
│   │   ├── inspector.py
│   │   ├── setup.py
│   │   ├── simple_airtable_server.py
│   │   └── test_client.py
│   └── typescript
│       ├── ai-prompts.d.ts
│       ├── airtable-mcp-server.d.ts
│       ├── airtable-mcp-server.ts
│       ├── app
│       │   ├── airtable-client.ts
│       │   ├── config.ts
│       │   ├── context.ts
│       │   ├── exceptions.ts
│       │   ├── governance.ts
│       │   ├── logger.ts
│       │   ├── rateLimiter.ts
│       │   ├── tools
│       │   │   ├── create.ts
│       │   │   ├── describe.ts
│       │   │   ├── handleError.ts
│       │   │   ├── index.ts
│       │   │   ├── listBases.ts
│       │   │   ├── listExceptions.ts
│       │   │   ├── listGovernance.ts
│       │   │   ├── query.ts
│       │   │   ├── update.ts
│       │   │   ├── upsert.ts
│       │   │   └── webhooks.ts
│       │   └── types.ts
│       ├── errors.ts
│       ├── index.d.ts
│       ├── index.ts
│       ├── prompt-templates.ts
│       ├── tools-schemas.ts
│       └── tools.d.ts
├── TESTING_REPORT.md
├── tests
│   ├── test_all_features.sh
│   ├── test_mcp_comprehensive.js
│   ├── test_v1.5.0_final.sh
│   └── test_v1.6.0_comprehensive.sh
├── tsconfig.json
└── types
    └── typescript
        ├── airtable-mcp-server.d.ts
        ├── app
        │   ├── airtable-client.d.ts
        │   ├── config.d.ts
        │   ├── context.d.ts
        │   ├── exceptions.d.ts
        │   ├── governance.d.ts
        │   ├── logger.d.ts
        │   ├── rateLimiter.d.ts
        │   ├── tools
        │   │   ├── create.d.ts
        │   │   ├── describe.d.ts
        │   │   ├── handleError.d.ts
        │   │   ├── index.d.ts
        │   │   ├── listBases.d.ts
        │   │   ├── listExceptions.d.ts
        │   │   ├── listGovernance.d.ts
        │   │   ├── query.d.ts
        │   │   ├── update.d.ts
        │   │   ├── upsert.d.ts
        │   │   └── webhooks.d.ts
        │   └── types.d.ts
        ├── errors.d.ts
        ├── index.d.ts
        ├── prompt-templates.d.ts
        ├── test-suite.d.ts
        └── tools-schemas.d.ts
```

# Files

--------------------------------------------------------------------------------
/types/typescript/app/types.d.ts:
--------------------------------------------------------------------------------

```typescript
import { z } from 'zod';
export declare const describeInputSchema: z.ZodEffects<z.ZodObject<{
    scope: z.ZodEnum<["base", "table"]>;
    baseId: z.ZodString;
    table: z.ZodOptional<z.ZodString>;
    includeFields: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
    includeViews: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
}, "strict", z.ZodTypeAny, {
    scope: "base" | "table";
    baseId: string;
    includeFields: boolean;
    includeViews: boolean;
    table?: string | undefined;
}, {
    scope: "base" | "table";
    baseId: string;
    table?: string | undefined;
    includeFields?: boolean | undefined;
    includeViews?: boolean | undefined;
}>, {
    scope: "base" | "table";
    baseId: string;
    includeFields: boolean;
    includeViews: boolean;
    table?: string | undefined;
}, {
    scope: "base" | "table";
    baseId: string;
    table?: string | undefined;
    includeFields?: boolean | undefined;
    includeViews?: boolean | undefined;
}>;
export declare const describeInputShape: {
    scope: z.ZodEnum<["base", "table"]>;
    baseId: z.ZodString;
    table: z.ZodOptional<z.ZodString>;
    includeFields: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
    includeViews: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
};
export declare const describeOutputSchema: z.ZodObject<{
    base: z.ZodObject<{
        id: z.ZodString;
        name: z.ZodString;
    }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
        id: z.ZodString;
        name: z.ZodString;
    }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
        id: z.ZodString;
        name: z.ZodString;
    }, z.ZodTypeAny, "passthrough">>;
    tables: z.ZodOptional<z.ZodArray<z.ZodObject<{
        id: z.ZodString;
        name: z.ZodString;
        description: z.ZodOptional<z.ZodString>;
        primaryFieldId: z.ZodOptional<z.ZodString>;
        fields: z.ZodOptional<z.ZodArray<z.ZodObject<{
            id: z.ZodString;
            name: z.ZodString;
            type: z.ZodString;
            options: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
        }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
            id: z.ZodString;
            name: z.ZodString;
            type: z.ZodString;
            options: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
        }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
            id: z.ZodString;
            name: z.ZodString;
            type: z.ZodString;
            options: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
        }, z.ZodTypeAny, "passthrough">>, "many">>;
        views: z.ZodOptional<z.ZodArray<z.ZodRecord<z.ZodString, z.ZodUnknown>, "many">>;
    }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
        id: z.ZodString;
        name: z.ZodString;
        description: z.ZodOptional<z.ZodString>;
        primaryFieldId: z.ZodOptional<z.ZodString>;
        fields: z.ZodOptional<z.ZodArray<z.ZodObject<{
            id: z.ZodString;
            name: z.ZodString;
            type: z.ZodString;
            options: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
        }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
            id: z.ZodString;
            name: z.ZodString;
            type: z.ZodString;
            options: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
        }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
            id: z.ZodString;
            name: z.ZodString;
            type: z.ZodString;
            options: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
        }, z.ZodTypeAny, "passthrough">>, "many">>;
        views: z.ZodOptional<z.ZodArray<z.ZodRecord<z.ZodString, z.ZodUnknown>, "many">>;
    }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
        id: z.ZodString;
        name: z.ZodString;
        description: z.ZodOptional<z.ZodString>;
        primaryFieldId: z.ZodOptional<z.ZodString>;
        fields: z.ZodOptional<z.ZodArray<z.ZodObject<{
            id: z.ZodString;
            name: z.ZodString;
            type: z.ZodString;
            options: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
        }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
            id: z.ZodString;
            name: z.ZodString;
            type: z.ZodString;
            options: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
        }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
            id: z.ZodString;
            name: z.ZodString;
            type: z.ZodString;
            options: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
        }, z.ZodTypeAny, "passthrough">>, "many">>;
        views: z.ZodOptional<z.ZodArray<z.ZodRecord<z.ZodString, z.ZodUnknown>, "many">>;
    }, z.ZodTypeAny, "passthrough">>, "many">>;
    views: z.ZodOptional<z.ZodArray<z.ZodRecord<z.ZodString, z.ZodUnknown>, "many">>;
}, "strict", z.ZodTypeAny, {
    base: {
        id: string;
        name: string;
    } & {
        [k: string]: unknown;
    };
    views?: Record<string, unknown>[] | undefined;
    tables?: z.objectOutputType<{
        id: z.ZodString;
        name: z.ZodString;
        description: z.ZodOptional<z.ZodString>;
        primaryFieldId: z.ZodOptional<z.ZodString>;
        fields: z.ZodOptional<z.ZodArray<z.ZodObject<{
            id: z.ZodString;
            name: z.ZodString;
            type: z.ZodString;
            options: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
        }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
            id: z.ZodString;
            name: z.ZodString;
            type: z.ZodString;
            options: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
        }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
            id: z.ZodString;
            name: z.ZodString;
            type: z.ZodString;
            options: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
        }, z.ZodTypeAny, "passthrough">>, "many">>;
        views: z.ZodOptional<z.ZodArray<z.ZodRecord<z.ZodString, z.ZodUnknown>, "many">>;
    }, z.ZodTypeAny, "passthrough">[] | undefined;
}, {
    base: {
        id: string;
        name: string;
    } & {
        [k: string]: unknown;
    };
    views?: Record<string, unknown>[] | undefined;
    tables?: z.objectInputType<{
        id: z.ZodString;
        name: z.ZodString;
        description: z.ZodOptional<z.ZodString>;
        primaryFieldId: z.ZodOptional<z.ZodString>;
        fields: z.ZodOptional<z.ZodArray<z.ZodObject<{
            id: z.ZodString;
            name: z.ZodString;
            type: z.ZodString;
            options: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
        }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
            id: z.ZodString;
            name: z.ZodString;
            type: z.ZodString;
            options: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
        }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
            id: z.ZodString;
            name: z.ZodString;
            type: z.ZodString;
            options: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
        }, z.ZodTypeAny, "passthrough">>, "many">>;
        views: z.ZodOptional<z.ZodArray<z.ZodRecord<z.ZodString, z.ZodUnknown>, "many">>;
    }, z.ZodTypeAny, "passthrough">[] | undefined;
}>;
export declare const queryInputSchema: z.ZodObject<{
    baseId: z.ZodString;
    table: z.ZodString;
    fields: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
    filterByFormula: z.ZodOptional<z.ZodString>;
    view: z.ZodOptional<z.ZodString>;
    sorts: z.ZodOptional<z.ZodArray<z.ZodObject<{
        field: z.ZodString;
        direction: z.ZodDefault<z.ZodOptional<z.ZodEnum<["asc", "desc"]>>>;
    }, "strict", z.ZodTypeAny, {
        field: string;
        direction: "asc" | "desc";
    }, {
        field: string;
        direction?: "asc" | "desc" | undefined;
    }>, "many">>;
    pageSize: z.ZodOptional<z.ZodNumber>;
    maxRecords: z.ZodOptional<z.ZodNumber>;
    offset: z.ZodOptional<z.ZodString>;
    returnFieldsByFieldId: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
}, "strict", z.ZodTypeAny, {
    table: string;
    baseId: string;
    returnFieldsByFieldId: boolean;
    fields?: string[] | undefined;
    filterByFormula?: string | undefined;
    view?: string | undefined;
    sorts?: {
        field: string;
        direction: "asc" | "desc";
    }[] | undefined;
    pageSize?: number | undefined;
    maxRecords?: number | undefined;
    offset?: string | undefined;
}, {
    table: string;
    baseId: string;
    fields?: string[] | undefined;
    filterByFormula?: string | undefined;
    view?: string | undefined;
    sorts?: {
        field: string;
        direction?: "asc" | "desc" | undefined;
    }[] | undefined;
    pageSize?: number | undefined;
    maxRecords?: number | undefined;
    offset?: string | undefined;
    returnFieldsByFieldId?: boolean | undefined;
}>;
export declare const queryInputShape: {
    baseId: z.ZodString;
    table: z.ZodString;
    fields: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
    filterByFormula: z.ZodOptional<z.ZodString>;
    view: z.ZodOptional<z.ZodString>;
    sorts: z.ZodOptional<z.ZodArray<z.ZodObject<{
        field: z.ZodString;
        direction: z.ZodDefault<z.ZodOptional<z.ZodEnum<["asc", "desc"]>>>;
    }, "strict", z.ZodTypeAny, {
        field: string;
        direction: "asc" | "desc";
    }, {
        field: string;
        direction?: "asc" | "desc" | undefined;
    }>, "many">>;
    pageSize: z.ZodOptional<z.ZodNumber>;
    maxRecords: z.ZodOptional<z.ZodNumber>;
    offset: z.ZodOptional<z.ZodString>;
    returnFieldsByFieldId: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
};
export declare const queryOutputSchema: z.ZodObject<{
    records: z.ZodArray<z.ZodObject<{
        id: z.ZodString;
        createdTime: z.ZodOptional<z.ZodString>;
        fields: z.ZodRecord<z.ZodString, z.ZodUnknown>;
    }, "strict", z.ZodTypeAny, {
        id: string;
        fields: Record<string, unknown>;
        createdTime?: string | undefined;
    }, {
        id: string;
        fields: Record<string, unknown>;
        createdTime?: string | undefined;
    }>, "many">;
    offset: z.ZodOptional<z.ZodString>;
    summary: z.ZodOptional<z.ZodObject<{
        returned: z.ZodNumber;
        hasMore: z.ZodBoolean;
    }, "strict", z.ZodTypeAny, {
        returned: number;
        hasMore: boolean;
    }, {
        returned: number;
        hasMore: boolean;
    }>>;
}, "strict", z.ZodTypeAny, {
    records: {
        id: string;
        fields: Record<string, unknown>;
        createdTime?: string | undefined;
    }[];
    offset?: string | undefined;
    summary?: {
        returned: number;
        hasMore: boolean;
    } | undefined;
}, {
    records: {
        id: string;
        fields: Record<string, unknown>;
        createdTime?: string | undefined;
    }[];
    offset?: string | undefined;
    summary?: {
        returned: number;
        hasMore: boolean;
    } | undefined;
}>;
export declare const createInputSchema: z.ZodObject<{
    baseId: z.ZodString;
    table: z.ZodString;
    records: z.ZodArray<z.ZodObject<{
        fields: z.ZodRecord<z.ZodString, z.ZodUnknown>;
    }, "strict", z.ZodTypeAny, {
        fields: Record<string, unknown>;
    }, {
        fields: Record<string, unknown>;
    }>, "many">;
    typecast: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
    idempotencyKey: z.ZodOptional<z.ZodString>;
    dryRun: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
}, "strict", z.ZodTypeAny, {
    table: string;
    baseId: string;
    records: {
        fields: Record<string, unknown>;
    }[];
    typecast: boolean;
    dryRun: boolean;
    idempotencyKey?: string | undefined;
}, {
    table: string;
    baseId: string;
    records: {
        fields: Record<string, unknown>;
    }[];
    typecast?: boolean | undefined;
    idempotencyKey?: string | undefined;
    dryRun?: boolean | undefined;
}>;
export declare const createOutputSchema: z.ZodObject<{
    diff: z.ZodObject<{
        added: z.ZodNumber;
        updated: z.ZodNumber;
        unchanged: z.ZodNumber;
    }, "strict", z.ZodTypeAny, {
        added: number;
        updated: number;
        unchanged: number;
    }, {
        added: number;
        updated: number;
        unchanged: number;
    }>;
    records: z.ZodOptional<z.ZodArray<z.ZodObject<{
        id: z.ZodString;
        createdTime: z.ZodOptional<z.ZodString>;
        fields: z.ZodRecord<z.ZodString, z.ZodUnknown>;
    }, "strict", z.ZodTypeAny, {
        id: string;
        fields: Record<string, unknown>;
        createdTime?: string | undefined;
    }, {
        id: string;
        fields: Record<string, unknown>;
        createdTime?: string | undefined;
    }>, "many">>;
    dryRun: z.ZodBoolean;
    warnings: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
}, "strict", z.ZodTypeAny, {
    dryRun: boolean;
    diff: {
        added: number;
        updated: number;
        unchanged: number;
    };
    records?: {
        id: string;
        fields: Record<string, unknown>;
        createdTime?: string | undefined;
    }[] | undefined;
    warnings?: string[] | undefined;
}, {
    dryRun: boolean;
    diff: {
        added: number;
        updated: number;
        unchanged: number;
    };
    records?: {
        id: string;
        fields: Record<string, unknown>;
        createdTime?: string | undefined;
    }[] | undefined;
    warnings?: string[] | undefined;
}>;
export declare const updateOutputSchema: z.ZodObject<{
    diff: z.ZodObject<{
        added: z.ZodNumber;
        updated: z.ZodNumber;
        unchanged: z.ZodNumber;
        conflicts: z.ZodNumber;
    }, "strict", z.ZodTypeAny, {
        added: number;
        updated: number;
        unchanged: number;
        conflicts: number;
    }, {
        added: number;
        updated: number;
        unchanged: number;
        conflicts: number;
    }>;
    records: z.ZodOptional<z.ZodArray<z.ZodObject<{
        id: z.ZodString;
        createdTime: z.ZodOptional<z.ZodString>;
        fields: z.ZodRecord<z.ZodString, z.ZodUnknown>;
    }, "strict", z.ZodTypeAny, {
        id: string;
        fields: Record<string, unknown>;
        createdTime?: string | undefined;
    }, {
        id: string;
        fields: Record<string, unknown>;
        createdTime?: string | undefined;
    }>, "many">>;
    dryRun: z.ZodBoolean;
    conflicts: z.ZodOptional<z.ZodArray<z.ZodObject<{
        id: z.ZodString;
        field: z.ZodString;
        before: z.ZodOptional<z.ZodUnknown>;
        after: z.ZodOptional<z.ZodUnknown>;
        current: z.ZodUnknown;
    }, "strict", z.ZodTypeAny, {
        id: string;
        field: string;
        before?: unknown;
        after?: unknown;
        current?: unknown;
    }, {
        id: string;
        field: string;
        before?: unknown;
        after?: unknown;
        current?: unknown;
    }>, "many">>;
}, "strict", z.ZodTypeAny, {
    dryRun: boolean;
    diff: {
        added: number;
        updated: number;
        unchanged: number;
        conflicts: number;
    };
    records?: {
        id: string;
        fields: Record<string, unknown>;
        createdTime?: string | undefined;
    }[] | undefined;
    conflicts?: {
        id: string;
        field: string;
        before?: unknown;
        after?: unknown;
        current?: unknown;
    }[] | undefined;
}, {
    dryRun: boolean;
    diff: {
        added: number;
        updated: number;
        unchanged: number;
        conflicts: number;
    };
    records?: {
        id: string;
        fields: Record<string, unknown>;
        createdTime?: string | undefined;
    }[] | undefined;
    conflicts?: {
        id: string;
        field: string;
        before?: unknown;
        after?: unknown;
        current?: unknown;
    }[] | undefined;
}>;
export declare const updateInputSchema: z.ZodObject<{
    baseId: z.ZodString;
    table: z.ZodString;
    records: z.ZodArray<z.ZodObject<{
        id: z.ZodString;
        fields: z.ZodRecord<z.ZodString, z.ZodUnknown>;
    }, "strict", z.ZodTypeAny, {
        id: string;
        fields: Record<string, unknown>;
    }, {
        id: string;
        fields: Record<string, unknown>;
    }>, "many">;
    typecast: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
    idempotencyKey: z.ZodOptional<z.ZodString>;
    dryRun: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
    conflictStrategy: z.ZodDefault<z.ZodOptional<z.ZodEnum<["fail_on_conflict", "server_merge", "client_merge"]>>>;
    ifUnchangedHash: z.ZodOptional<z.ZodString>;
}, "strict", z.ZodTypeAny, {
    table: string;
    baseId: string;
    records: {
        id: string;
        fields: Record<string, unknown>;
    }[];
    typecast: boolean;
    dryRun: boolean;
    conflictStrategy: "fail_on_conflict" | "server_merge" | "client_merge";
    idempotencyKey?: string | undefined;
    ifUnchangedHash?: string | undefined;
}, {
    table: string;
    baseId: string;
    records: {
        id: string;
        fields: Record<string, unknown>;
    }[];
    typecast?: boolean | undefined;
    idempotencyKey?: string | undefined;
    dryRun?: boolean | undefined;
    conflictStrategy?: "fail_on_conflict" | "server_merge" | "client_merge" | undefined;
    ifUnchangedHash?: string | undefined;
}>;
export declare const upsertInputSchema: z.ZodObject<{
    baseId: z.ZodString;
    table: z.ZodString;
    records: z.ZodArray<z.ZodObject<{
        fields: z.ZodRecord<z.ZodString, z.ZodUnknown>;
    }, "strict", z.ZodTypeAny, {
        fields: Record<string, unknown>;
    }, {
        fields: Record<string, unknown>;
    }>, "many">;
    performUpsert: z.ZodObject<{
        fieldsToMergeOn: z.ZodArray<z.ZodString, "many">;
    }, "strict", z.ZodTypeAny, {
        fieldsToMergeOn: string[];
    }, {
        fieldsToMergeOn: string[];
    }>;
    typecast: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
    idempotencyKey: z.ZodOptional<z.ZodString>;
    dryRun: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
    conflictStrategy: z.ZodDefault<z.ZodOptional<z.ZodEnum<["fail_on_conflict", "server_merge", "client_merge"]>>>;
}, "strict", z.ZodTypeAny, {
    table: string;
    baseId: string;
    records: {
        fields: Record<string, unknown>;
    }[];
    typecast: boolean;
    dryRun: boolean;
    conflictStrategy: "fail_on_conflict" | "server_merge" | "client_merge";
    performUpsert: {
        fieldsToMergeOn: string[];
    };
    idempotencyKey?: string | undefined;
}, {
    table: string;
    baseId: string;
    records: {
        fields: Record<string, unknown>;
    }[];
    performUpsert: {
        fieldsToMergeOn: string[];
    };
    typecast?: boolean | undefined;
    idempotencyKey?: string | undefined;
    dryRun?: boolean | undefined;
    conflictStrategy?: "fail_on_conflict" | "server_merge" | "client_merge" | undefined;
}>;
export declare const upsertOutputSchema: z.ZodObject<{
    diff: z.ZodObject<{
        added: z.ZodNumber;
        updated: z.ZodNumber;
        unchanged: z.ZodNumber;
        conflicts: z.ZodNumber;
    }, "strict", z.ZodTypeAny, {
        added: number;
        updated: number;
        unchanged: number;
        conflicts: number;
    }, {
        added: number;
        updated: number;
        unchanged: number;
        conflicts: number;
    }>;
    records: z.ZodOptional<z.ZodArray<z.ZodObject<{
        id: z.ZodString;
        createdTime: z.ZodOptional<z.ZodString>;
        fields: z.ZodRecord<z.ZodString, z.ZodUnknown>;
    }, "strict", z.ZodTypeAny, {
        id: string;
        fields: Record<string, unknown>;
        createdTime?: string | undefined;
    }, {
        id: string;
        fields: Record<string, unknown>;
        createdTime?: string | undefined;
    }>, "many">>;
    dryRun: z.ZodBoolean;
    conflicts: z.ZodOptional<z.ZodArray<z.ZodObject<{
        id: z.ZodString;
        field: z.ZodString;
        before: z.ZodOptional<z.ZodUnknown>;
        after: z.ZodOptional<z.ZodUnknown>;
        current: z.ZodUnknown;
    }, "strict", z.ZodTypeAny, {
        id: string;
        field: string;
        before?: unknown;
        after?: unknown;
        current?: unknown;
    }, {
        id: string;
        field: string;
        before?: unknown;
        after?: unknown;
        current?: unknown;
    }>, "many">>;
}, "strict", z.ZodTypeAny, {
    dryRun: boolean;
    diff: {
        added: number;
        updated: number;
        unchanged: number;
        conflicts: number;
    };
    records?: {
        id: string;
        fields: Record<string, unknown>;
        createdTime?: string | undefined;
    }[] | undefined;
    conflicts?: {
        id: string;
        field: string;
        before?: unknown;
        after?: unknown;
        current?: unknown;
    }[] | undefined;
}, {
    dryRun: boolean;
    diff: {
        added: number;
        updated: number;
        unchanged: number;
        conflicts: number;
    };
    records?: {
        id: string;
        fields: Record<string, unknown>;
        createdTime?: string | undefined;
    }[] | undefined;
    conflicts?: {
        id: string;
        field: string;
        before?: unknown;
        after?: unknown;
        current?: unknown;
    }[] | undefined;
}>;
export declare const listExceptionsInputSchema: z.ZodObject<{
    since: z.ZodOptional<z.ZodString>;
    severity: z.ZodOptional<z.ZodEnum<["info", "warning", "error"]>>;
    limit: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
    cursor: z.ZodOptional<z.ZodString>;
}, "strict", z.ZodTypeAny, {
    limit: number;
    since?: string | undefined;
    severity?: "info" | "warning" | "error" | undefined;
    cursor?: string | undefined;
}, {
    since?: string | undefined;
    severity?: "info" | "warning" | "error" | undefined;
    limit?: number | undefined;
    cursor?: string | undefined;
}>;
export declare const exceptionItemSchema: z.ZodObject<{
    id: z.ZodString;
    timestamp: z.ZodString;
    severity: z.ZodEnum<["info", "warning", "error"]>;
    category: z.ZodEnum<["rate_limit", "validation", "auth", "conflict", "schema_drift", "other"]>;
    summary: z.ZodString;
    details: z.ZodOptional<z.ZodString>;
    proposedFix: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
}, "strict", z.ZodTypeAny, {
    id: string;
    summary: string;
    severity: "info" | "warning" | "error";
    timestamp: string;
    category: "validation" | "rate_limit" | "auth" | "conflict" | "schema_drift" | "other";
    details?: string | undefined;
    proposedFix?: Record<string, unknown> | undefined;
}, {
    id: string;
    summary: string;
    severity: "info" | "warning" | "error";
    timestamp: string;
    category: "validation" | "rate_limit" | "auth" | "conflict" | "schema_drift" | "other";
    details?: string | undefined;
    proposedFix?: Record<string, unknown> | undefined;
}>;
export declare const listExceptionsOutputSchema: z.ZodObject<{
    items: z.ZodArray<z.ZodObject<{
        id: z.ZodString;
        timestamp: z.ZodString;
        severity: z.ZodEnum<["info", "warning", "error"]>;
        category: z.ZodEnum<["rate_limit", "validation", "auth", "conflict", "schema_drift", "other"]>;
        summary: z.ZodString;
        details: z.ZodOptional<z.ZodString>;
        proposedFix: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
    }, "strict", z.ZodTypeAny, {
        id: string;
        summary: string;
        severity: "info" | "warning" | "error";
        timestamp: string;
        category: "validation" | "rate_limit" | "auth" | "conflict" | "schema_drift" | "other";
        details?: string | undefined;
        proposedFix?: Record<string, unknown> | undefined;
    }, {
        id: string;
        summary: string;
        severity: "info" | "warning" | "error";
        timestamp: string;
        category: "validation" | "rate_limit" | "auth" | "conflict" | "schema_drift" | "other";
        details?: string | undefined;
        proposedFix?: Record<string, unknown> | undefined;
    }>, "many">;
    cursor: z.ZodOptional<z.ZodString>;
}, "strict", z.ZodTypeAny, {
    items: {
        id: string;
        summary: string;
        severity: "info" | "warning" | "error";
        timestamp: string;
        category: "validation" | "rate_limit" | "auth" | "conflict" | "schema_drift" | "other";
        details?: string | undefined;
        proposedFix?: Record<string, unknown> | undefined;
    }[];
    cursor?: string | undefined;
}, {
    items: {
        id: string;
        summary: string;
        severity: "info" | "warning" | "error";
        timestamp: string;
        category: "validation" | "rate_limit" | "auth" | "conflict" | "schema_drift" | "other";
        details?: string | undefined;
        proposedFix?: Record<string, unknown> | undefined;
    }[];
    cursor?: string | undefined;
}>;
export declare const governanceOutputSchema: z.ZodObject<{
    allowedBases: z.ZodArray<z.ZodString, "many">;
    allowedTables: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodObject<{
        baseId: z.ZodString;
        table: z.ZodString;
    }, "strict", z.ZodTypeAny, {
        table: string;
        baseId: string;
    }, {
        table: string;
        baseId: string;
    }>, "many">>>;
    allowedOperations: z.ZodDefault<z.ZodArray<z.ZodEnum<["describe", "query", "create", "update", "upsert"]>, "many">>;
    piiFields: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodObject<{
        baseId: z.ZodString;
        table: z.ZodString;
        field: z.ZodString;
        policy: z.ZodEnum<["mask", "hash", "drop"]>;
    }, "strict", z.ZodTypeAny, {
        table: string;
        baseId: string;
        field: string;
        policy: "mask" | "hash" | "drop";
    }, {
        table: string;
        baseId: string;
        field: string;
        policy: "mask" | "hash" | "drop";
    }>, "many">>>;
    redactionPolicy: z.ZodDefault<z.ZodEnum<["mask_all_pii", "mask_on_inline", "none"]>>;
    loggingPolicy: z.ZodDefault<z.ZodEnum<["errors_only", "minimal", "verbose"]>>;
    retentionDays: z.ZodDefault<z.ZodNumber>;
}, "strict", z.ZodTypeAny, {
    allowedBases: string[];
    allowedTables: {
        table: string;
        baseId: string;
    }[];
    allowedOperations: ("describe" | "query" | "create" | "update" | "upsert")[];
    piiFields: {
        table: string;
        baseId: string;
        field: string;
        policy: "mask" | "hash" | "drop";
    }[];
    redactionPolicy: "mask_all_pii" | "mask_on_inline" | "none";
    loggingPolicy: "errors_only" | "minimal" | "verbose";
    retentionDays: number;
}, {
    allowedBases: string[];
    allowedTables?: {
        table: string;
        baseId: string;
    }[] | undefined;
    allowedOperations?: ("describe" | "query" | "create" | "update" | "upsert")[] | undefined;
    piiFields?: {
        table: string;
        baseId: string;
        field: string;
        policy: "mask" | "hash" | "drop";
    }[] | undefined;
    redactionPolicy?: "mask_all_pii" | "mask_on_inline" | "none" | undefined;
    loggingPolicy?: "errors_only" | "minimal" | "verbose" | undefined;
    retentionDays?: number | undefined;
}>;
export type DescribeInput = z.infer<typeof describeInputSchema>;
export type DescribeOutput = z.infer<typeof describeOutputSchema>;
export type QueryInput = z.infer<typeof queryInputSchema>;
export type QueryOutput = z.infer<typeof queryOutputSchema>;
export type CreateInput = z.infer<typeof createInputSchema>;
export type CreateOutput = z.infer<typeof createOutputSchema>;
export type UpdateInput = z.infer<typeof updateInputSchema>;
export type UpdateOutput = z.infer<typeof updateOutputSchema>;
export type UpsertInput = z.infer<typeof upsertInputSchema>;
export type UpsertOutput = z.infer<typeof upsertOutputSchema>;
export type ListExceptionsInput = z.infer<typeof listExceptionsInputSchema>;
export type ExceptionItem = z.infer<typeof exceptionItemSchema>;
export type ListExceptionsOutput = z.infer<typeof listExceptionsOutputSchema>;
export type GovernanceSnapshot = z.infer<typeof governanceOutputSchema>;

```

--------------------------------------------------------------------------------
/src/javascript/airtable_simple_production.js:
--------------------------------------------------------------------------------

```javascript
#!/usr/bin/env node

/**
 * Airtable MCP Server - Production Ready
 * Model Context Protocol server for Airtable integration
 * 
 * Features:
 * - Complete MCP 2024-11-05 protocol support
 * - OAuth2 authentication with PKCE
 * - Enterprise security features
 * - Rate limiting and input validation
 * - Production monitoring and health checks
 * 
 * Author: Rashid Azarang
 * License: MIT
 */

const http = require('http');
const https = require('https');
const fs = require('fs');
const path = require('path');
const crypto = require('crypto');
const url = require('url');
const querystring = require('querystring');

// Load environment variables
const envPath = path.join(__dirname, '.env');
if (fs.existsSync(envPath)) {
  require('dotenv').config({ path: envPath });
}

// Parse command line arguments
const args = process.argv.slice(2);
let tokenIndex = args.indexOf('--token');
let baseIndex = args.indexOf('--base');

const token = tokenIndex !== -1 ? args[tokenIndex + 1] : process.env.AIRTABLE_TOKEN || process.env.AIRTABLE_API_TOKEN;
const baseId = baseIndex !== -1 ? args[baseIndex + 1] : process.env.AIRTABLE_BASE_ID || process.env.AIRTABLE_BASE;

if (!token || !baseId) {
  console.error('Error: Missing Airtable credentials');
  console.error('\nUsage options:');
  console.error('  1. Command line: node airtable_simple_production.js --token YOUR_TOKEN --base YOUR_BASE_ID');
  console.error('  2. Environment variables: AIRTABLE_TOKEN and AIRTABLE_BASE_ID');
  console.error('  3. .env file with AIRTABLE_TOKEN and AIRTABLE_BASE_ID');
  process.exit(1);
}

// Configuration
const CONFIG = {
  PORT: process.env.PORT || 8010,
  HOST: process.env.HOST || 'localhost',
  MAX_REQUESTS_PER_MINUTE: parseInt(process.env.MAX_REQUESTS_PER_MINUTE) || 60,
  LOG_LEVEL: process.env.LOG_LEVEL || 'INFO'
};

// Logging
const LOG_LEVELS = { ERROR: 0, WARN: 1, INFO: 2, DEBUG: 3, TRACE: 4 };
let currentLogLevel = LOG_LEVELS[CONFIG.LOG_LEVEL] || LOG_LEVELS.INFO;

function log(level, message, metadata = {}) {
  if (level <= currentLogLevel) {
    const timestamp = new Date().toISOString();
    const levelName = Object.keys(LOG_LEVELS).find(key => LOG_LEVELS[key] === level);
    // Sanitize message to prevent format string attacks
    const safeMessage = String(message).replace(/%/g, '%%');
    const output = `[${timestamp}] [${levelName}] ${safeMessage}`;
    
    if (Object.keys(metadata).length > 0) {
      // Use separate arguments to avoid format string injection
      console.log('%s %s', output, JSON.stringify(metadata));
    } else {
      console.log('%s', output);
    }
  }
}

// Rate limiting
const rateLimiter = new Map();

function checkRateLimit(clientId) {
  const now = Date.now();
  const windowStart = now - 60000; // 1 minute window
  
  if (!rateLimiter.has(clientId)) {
    rateLimiter.set(clientId, []);
  }
  
  const requests = rateLimiter.get(clientId);
  const recentRequests = requests.filter(time => time > windowStart);
  
  if (recentRequests.length >= CONFIG.MAX_REQUESTS_PER_MINUTE) {
    return false;
  }
  
  recentRequests.push(now);
  rateLimiter.set(clientId, recentRequests);
  return true;
}

// Input validation and HTML escaping
function sanitizeInput(input) {
  if (typeof input === 'string') {
    return input.replace(/[<>]/g, '').trim().substring(0, 1000);
  }
  return input;
}

function escapeHtml(unsafe) {
  if (typeof unsafe !== 'string') {
    return String(unsafe);
  }
  return unsafe
    .replace(/&/g, "&amp;")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;")
    .replace(/"/g, "&quot;")
    .replace(/'/g, "&#039;")
    .replace(/\//g, "&#x2F;");
}

function validateUrl(url) {
  try {
    const parsed = new URL(url);
    // Only allow http and https protocols
    return ['http:', 'https:'].includes(parsed.protocol);
  } catch {
    return false;
  }
}

// Airtable API integration
function callAirtableAPI(endpoint, method = 'GET', body = null, queryParams = {}) {
  return new Promise((resolve, reject) => {
    const isBaseEndpoint = !endpoint.startsWith('meta/');
    const baseUrl = isBaseEndpoint ? `${baseId}/${endpoint}` : endpoint;
    
    const queryString = Object.keys(queryParams).length > 0 
      ? '?' + new URLSearchParams(queryParams).toString() 
      : '';
    
    const apiUrl = `https://api.airtable.com/v0/${baseUrl}${queryString}`;
    const urlObj = new URL(apiUrl);
    
    log(LOG_LEVELS.DEBUG, 'API Request', { method, url: apiUrl });
    
    const options = {
      hostname: urlObj.hostname,
      path: urlObj.pathname + urlObj.search,
      method: method,
      headers: {
        'Authorization': `Bearer ${token}`,
        'Content-Type': 'application/json',
        'User-Agent': 'Airtable-MCP-Server/2.1.0'
      }
    };
    
    const req = https.request(options, (response) => {
      let data = '';
      
      response.on('data', (chunk) => data += chunk);
      response.on('end', () => {
        try {
          const parsed = data ? JSON.parse(data) : {};
          
          if (response.statusCode >= 200 && response.statusCode < 300) {
            resolve(parsed);
          } else {
            const error = parsed.error || {};
            reject(new Error(`Airtable API error (${response.statusCode}): ${error.message || error.type || 'Unknown error'}`));
          }
        } catch (e) {
          reject(new Error(`Failed to parse Airtable response: ${e.message}`));
        }
      });
    });
    
    req.on('error', reject);
    
    if (body) {
      req.write(JSON.stringify(body));
    }
    
    req.end();
  });
}

// Tools schema
const TOOLS_SCHEMA = [
  {
    name: 'list_tables',
    description: 'List all tables in the Airtable base',
    inputSchema: {
      type: 'object',
      properties: {
        include_schema: { type: 'boolean', description: 'Include field schema information', default: false }
      }
    }
  },
  {
    name: 'list_records',
    description: 'List records from a specific table',
    inputSchema: {
      type: 'object',
      properties: {
        table: { type: 'string', description: 'Table name or ID' },
        maxRecords: { type: 'number', description: 'Maximum number of records to return' },
        view: { type: 'string', description: 'View name or ID' },
        filterByFormula: { type: 'string', description: 'Airtable formula to filter records' }
      },
      required: ['table']
    }
  },
  {
    name: 'get_record',
    description: 'Get a single record by ID',
    inputSchema: {
      type: 'object',
      properties: {
        table: { type: 'string', description: 'Table name or ID' },
        recordId: { type: 'string', description: 'Record ID' }
      },
      required: ['table', 'recordId']
    }
  },
  {
    name: 'create_record',
    description: 'Create a new record in a table',
    inputSchema: {
      type: 'object',
      properties: {
        table: { type: 'string', description: 'Table name or ID' },
        fields: { type: 'object', description: 'Field values for the new record' }
      },
      required: ['table', 'fields']
    }
  },
  {
    name: 'update_record',
    description: 'Update an existing record',
    inputSchema: {
      type: 'object',
      properties: {
        table: { type: 'string', description: 'Table name or ID' },
        recordId: { type: 'string', description: 'Record ID to update' },
        fields: { type: 'object', description: 'Fields to update' }
      },
      required: ['table', 'recordId', 'fields']
    }
  },
  {
    name: 'delete_record',
    description: 'Delete a record from a table',
    inputSchema: {
      type: 'object',
      properties: {
        table: { type: 'string', description: 'Table name or ID' },
        recordId: { type: 'string', description: 'Record ID to delete' }
      },
      required: ['table', 'recordId']
    }
  }
];

// Enhanced AI-powered prompts for intelligent Airtable operations
const PROMPTS_SCHEMA = [
  {
    name: 'analyze_data',
    description: 'Advanced AI data analysis with statistical insights, pattern recognition, and predictive modeling',
    arguments: [
      {
        name: 'table',
        description: 'Table name or ID to analyze',
        required: true
      },
      {
        name: 'analysis_type',
        description: 'Type of analysis (trends, statistical, patterns, predictive, anomaly_detection, correlation_matrix)',
        required: false
      },
      {
        name: 'field_focus',
        description: 'Specific fields to focus the analysis on',
        required: false
      },
      {
        name: 'time_dimension',
        description: 'Time field for temporal analysis',
        required: false
      },
      {
        name: 'confidence_level',
        description: 'Statistical confidence level (0.90, 0.95, 0.99)',
        required: false
      }
    ]
  },
  {
    name: 'create_report',
    description: 'Generate intelligent reports with AI-powered insights, visualizations, and actionable recommendations',
    arguments: [
      {
        name: 'table',
        description: 'Table name or ID for the report',
        required: true
      },
      {
        name: 'report_type',
        description: 'Type of report (executive_summary, operational_dashboard, analytical_deep_dive, performance_metrics, predictive_forecast)',
        required: false
      },
      {
        name: 'time_period',
        description: 'Time period for analysis (last_7_days, last_30_days, last_quarter, year_to_date, custom)',
        required: false
      },
      {
        name: 'stakeholder_level',
        description: 'Target audience (executive, manager, analyst, operational)',
        required: false
      },
      {
        name: 'include_recommendations',
        description: 'Include AI-generated actionable recommendations (true/false)',
        required: false
      }
    ]
  },
  {
    name: 'data_insights',
    description: 'Discover hidden patterns, correlations, and business insights using advanced AI algorithms',
    arguments: [
      {
        name: 'tables',
        description: 'Comma-separated list of table names to analyze',
        required: true
      },
      {
        name: 'insight_type',
        description: 'Type of insights (correlations, outliers, trends, predictions, segmentation, attribution, churn_analysis)',
        required: false
      },
      {
        name: 'business_context',
        description: 'Business domain context (sales, marketing, operations, finance, customer_success)',
        required: false
      },
      {
        name: 'insight_depth',
        description: 'Analysis depth (surface, moderate, deep, comprehensive)',
        required: false
      }
    ]
  },
  {
    name: 'optimize_workflow',
    description: 'AI-powered workflow optimization with automation recommendations and efficiency improvements',
    arguments: [
      {
        name: 'base_overview',
        description: 'Overview of the base structure and current workflows',
        required: false
      },
      {
        name: 'optimization_focus',
        description: 'Focus area (automation, data_quality, collaboration, performance, integration, user_experience)',
        required: false
      },
      {
        name: 'current_pain_points',
        description: 'Known issues or bottlenecks in current workflow',
        required: false
      },
      {
        name: 'team_size',
        description: 'Number of users working with this base',
        required: false
      }
    ]
  },
  {
    name: 'smart_schema_design',
    description: 'AI-assisted database schema optimization and field relationship analysis',
    arguments: [
      {
        name: 'use_case',
        description: 'Primary use case (crm, project_management, inventory, content_management, hr, finance)',
        required: true
      },
      {
        name: 'data_volume',
        description: 'Expected data volume (small, medium, large, enterprise)',
        required: false
      },
      {
        name: 'integration_needs',
        description: 'External systems to integrate with',
        required: false
      },
      {
        name: 'compliance_requirements',
        description: 'Data compliance needs (gdpr, hipaa, sox, none)',
        required: false
      }
    ]
  },
  {
    name: 'data_quality_audit',
    description: 'Comprehensive AI-powered data quality assessment with cleansing recommendations',
    arguments: [
      {
        name: 'tables',
        description: 'Tables to audit (comma-separated or "all")',
        required: true
      },
      {
        name: 'quality_dimensions',
        description: 'Quality aspects to check (completeness, accuracy, consistency, validity, uniqueness, timeliness)',
        required: false
      },
      {
        name: 'severity_threshold',
        description: 'Minimum severity level to report (low, medium, high, critical)',
        required: false
      },
      {
        name: 'auto_fix_suggestions',
        description: 'Include automated fix suggestions (true/false)',
        required: false
      }
    ]
  },
  {
    name: 'predictive_analytics',
    description: 'Advanced predictive modeling and forecasting using historical Airtable data',
    arguments: [
      {
        name: 'table',
        description: 'Table containing historical data',
        required: true
      },
      {
        name: 'target_field',
        description: 'Field to predict or forecast',
        required: true
      },
      {
        name: 'prediction_horizon',
        description: 'Forecast period (next_week, next_month, next_quarter, next_year)',
        required: false
      },
      {
        name: 'model_type',
        description: 'Prediction model (trend_analysis, seasonal_forecast, regression, classification, time_series)',
        required: false
      },
      {
        name: 'feature_fields',
        description: 'Fields to use as predictive features',
        required: false
      }
    ]
  },
  {
    name: 'natural_language_query',
    description: 'Process natural language questions about your data and provide intelligent answers',
    arguments: [
      {
        name: 'question',
        description: 'Natural language question about your data',
        required: true
      },
      {
        name: 'context_tables',
        description: 'Tables that might contain relevant data',
        required: false
      },
      {
        name: 'response_format',
        description: 'Desired response format (narrative, data_summary, visualization_suggestion, action_items)',
        required: false
      },
      {
        name: 'include_confidence',
        description: 'Include confidence scores for answers (true/false)',
        required: false
      }
    ]
  },
  {
    name: 'smart_data_transformation',
    description: 'AI-assisted data transformation, cleaning, and enrichment with intelligent suggestions',
    arguments: [
      {
        name: 'source_table',
        description: 'Source table for transformation',
        required: true
      },
      {
        name: 'transformation_goal',
        description: 'Goal (normalize, standardize, enrich, cleanse, aggregate, pivot)',
        required: true
      },
      {
        name: 'target_format',
        description: 'Desired output format or structure',
        required: false
      },
      {
        name: 'quality_rules',
        description: 'Data quality rules to apply during transformation',
        required: false
      },
      {
        name: 'preserve_history',
        description: 'Maintain audit trail of changes (true/false)',
        required: false
      }
    ]
  },
  {
    name: 'automation_recommendations',
    description: 'Generate intelligent automation suggestions based on workflow patterns and data analysis',
    arguments: [
      {
        name: 'workflow_description',
        description: 'Description of current manual processes',
        required: false
      },
      {
        name: 'automation_scope',
        description: 'Scope (single_table, multi_table, cross_base, external_integration)',
        required: false
      },
      {
        name: 'frequency_patterns',
        description: 'How often tasks are performed',
        required: false
      },
      {
        name: 'complexity_tolerance',
        description: 'Acceptable automation complexity (simple, moderate, advanced)',
        required: false
      },
      {
        name: 'integration_capabilities',
        description: 'Available integration tools (zapier, make, custom_api, native_automations)',
        required: false
      }
    ]
  }
];

// Roots configuration for filesystem access
const ROOTS_CONFIG = [
  {
    uri: 'file:///airtable-exports',
    name: 'Airtable Exports'
  },
  {
    uri: 'file:///airtable-attachments', 
    name: 'Airtable Attachments'
  }
];

// Logging configuration (currentLogLevel is already declared above)

// HTTP server
const server = http.createServer(async (req, res) => {
  // Security headers
  res.setHeader('X-Content-Type-Options', 'nosniff');
  res.setHeader('X-Frame-Options', 'DENY');
  res.setHeader('X-XSS-Protection', '1; mode=block');
  res.setHeader('Access-Control-Allow-Origin', process.env.ALLOWED_ORIGINS || '*');
  res.setHeader('Access-Control-Allow-Methods', 'POST, GET, OPTIONS');
  res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
  
  // Handle preflight request
  if (req.method === 'OPTIONS') {
    res.writeHead(200);
    res.end();
    return;
  }
  
  const parsedUrl = url.parse(req.url, true);
  const pathname = parsedUrl.pathname;
  
  // Health check endpoint
  if (pathname === '/health' && req.method === 'GET') {
    res.writeHead(200, { 'Content-Type': 'application/json' });
    res.end(JSON.stringify({
      status: 'healthy',
      version: '3.0.0',
      timestamp: new Date().toISOString(),
      uptime: process.uptime()
    }));
    return;
  }
  
  // OAuth2 authorization endpoint
  if (pathname === '/oauth/authorize' && req.method === 'GET') {
    const params = parsedUrl.query;
    const clientId = params.client_id;
    const redirectUri = params.redirect_uri;
    const state = params.state;
    const codeChallenge = params.code_challenge;
    const codeChallengeMethod = params.code_challenge_method;
    
    // Validate inputs to prevent XSS
    if (!clientId || !redirectUri) {
      res.writeHead(400, { 'Content-Type': 'application/json' });
      res.end(JSON.stringify({ error: 'invalid_request', error_description: 'Missing required parameters' }));
      return;
    }
    
    // Validate redirect URI
    if (!validateUrl(redirectUri)) {
      res.writeHead(400, { 'Content-Type': 'application/json' });
      res.end(JSON.stringify({ error: 'invalid_request', error_description: 'Invalid redirect URI' }));
      return;
    }
    
    // Create safe copies of all variables for JavaScript use
    const safeRedirectUri = redirectUri.slice(0, 2000); // Limit length
    const safeState = (state || '').slice(0, 200); // Limit length
    const safeClientId = clientId.slice(0, 200); // Limit length
    
    // Sanitize for HTML display only
    const displayClientId = escapeHtml(safeClientId);
    const displayRedirectUri = escapeHtml(safeRedirectUri);
    
    // Generate authorization code
    const authCode = crypto.randomBytes(32).toString('hex');
    
    // In a real implementation, store the auth code with expiration
    // and associate it with the client and PKCE challenge
    
    res.writeHead(200, { 
      'Content-Type': 'text/html; charset=utf-8',
      'Content-Security-Policy': "default-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline'; connect-src 'none'; object-src 'none'; base-uri 'none'; form-action 'none';",
      'X-Content-Type-Options': 'nosniff',
      'X-Frame-Options': 'DENY',
      'X-XSS-Protection': '1; mode=block',
      'Referrer-Policy': 'no-referrer',
      'Cache-Control': 'no-store, no-cache, must-revalidate, private'
    });
    
    // Safely encode data for embedding in HTML attributes and JavaScript
    // This prevents XSS by encoding any potentially dangerous characters
    const safeJsonConfig = JSON.stringify({
      redirectUri: safeRedirectUri,
      code: authCode,
      state: safeState,
      clientId: displayClientId,
      displayRedirectUri: displayRedirectUri
    }).replace(/</g, '\\u003c').replace(/>/g, '\\u003e').replace(/&/g, '\\u0026').replace(/'/g, '\\u0027').replace(/"/g, '\\u0022');
    
    // Build HTML with all dynamic content properly escaped
    // Using template literals but with pre-escaped content only
    const htmlContent = `<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>OAuth2 Authorization</title>
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline';">
</head>
<body>
  <h2>Airtable MCP Server - OAuth2 Authorization</h2>
  <p>Client ID: <span id="client-id"></span></p>
  <p>Redirect URI: <span id="redirect-uri"></span></p>
  <div style="margin: 20px 0;">
    <button onclick="authorize()" style="background: #18BFFF; color: white; padding: 10px 20px; border: none; border-radius: 5px; cursor: pointer;">
      Authorize Application
    </button>
    <button onclick="deny()" style="background: #ff4444; color: white; padding: 10px 20px; border: none; border-radius: 5px; cursor: pointer; margin-left: 10px;">
      Deny Access
    </button>
  </div>
  <script>
    // Parse safely encoded JSON config
    (function() {
      // Config is safely encoded to prevent XSS
      var config = ${safeJsonConfig};
      
      // Safely set text content (not innerHTML) to prevent XSS
      document.addEventListener('DOMContentLoaded', function() {
        document.getElementById('client-id').textContent = config.clientId;
        document.getElementById('redirect-uri').textContent = config.displayRedirectUri;
      });
      
      window.authorize = function() {
        try {
          var url = new URL(config.redirectUri);
          if (url.protocol !== 'http:' && url.protocol !== 'https:') {
            throw new Error('Invalid protocol');
          }
          var finalUrl = config.redirectUri + '?code=' + encodeURIComponent(config.code) + '&state=' + encodeURIComponent(config.state);
          window.location.href = finalUrl;
        } catch (e) {
          console.error('Authorization failed:', e);
          alert('Invalid redirect URL');
        }
      };
      
      window.deny = function() {
        try {
          var url = new URL(config.redirectUri);
          if (url.protocol !== 'http:' && url.protocol !== 'https:') {
            throw new Error('Invalid protocol');
          }
          var finalUrl = config.redirectUri + '?error=access_denied&state=' + encodeURIComponent(config.state);
          window.location.href = finalUrl;
        } catch (e) {
          console.error('Denial failed:', e);
          alert('Invalid redirect URL');
        }
      };
    })();
  </script>
</body>
</html>`;

    // Write response with explicit UTF-8 encoding
    res.end(htmlContent, 'utf8');
    return;
  }
  
  // OAuth2 token endpoint
  if (pathname === '/oauth/token' && req.method === 'POST') {
    let body = '';
    req.on('data', chunk => {
      body += chunk.toString();
      // Prevent DoS by limiting body size
      if (body.length > 10000) {
        res.writeHead(413, { 'Content-Type': 'application/json' });
        res.end(JSON.stringify({ error: 'payload_too_large', error_description: 'Request body too large' }));
        return;
      }
    });
    
    req.on('end', () => {
      try {
        const params = querystring.parse(body);
        const grantType = sanitizeInput(params.grant_type);
        const code = sanitizeInput(params.code);
        const codeVerifier = sanitizeInput(params.code_verifier);
        const clientId = sanitizeInput(params.client_id);
        
        // Validate required parameters
        if (!grantType || !code || !clientId) {
          res.writeHead(400, { 'Content-Type': 'application/json' });
          res.end(JSON.stringify({
            error: 'invalid_request',
            error_description: 'Missing required parameters'
          }));
          return;
        }
        
        // In a real implementation, verify the authorization code and PKCE
        if (grantType === 'authorization_code' && code) {
          // Generate access token
          const accessToken = crypto.randomBytes(32).toString('hex');
          const refreshToken = crypto.randomBytes(32).toString('hex');
          
          res.writeHead(200, { 
            'Content-Type': 'application/json',
            'Cache-Control': 'no-store',
            'Pragma': 'no-cache'
          });
          res.end(JSON.stringify({
            access_token: accessToken,
            token_type: 'Bearer',
            expires_in: 3600,
            refresh_token: refreshToken,
            scope: 'data.records:read data.records:write schema.bases:read'
          }));
        } else {
          res.writeHead(400, { 'Content-Type': 'application/json' });
          res.end(JSON.stringify({
            error: 'invalid_grant',
            error_description: 'Invalid grant type or authorization code'
          }));
        }
      } catch (error) {
        log(LOG_LEVELS.WARN, 'OAuth token request parsing failed', { error: error.message });
        res.writeHead(400, { 'Content-Type': 'application/json' });
        res.end(JSON.stringify({
          error: 'invalid_request',
          error_description: 'Malformed request body'
        }));
      }
    });
    return;
  }
  
  // MCP endpoint
  if (pathname === '/mcp' && req.method === 'POST') {
    // Rate limiting
    const clientId = req.headers['x-client-id'] || req.connection.remoteAddress;
    if (!checkRateLimit(clientId)) {
      res.writeHead(429, { 'Content-Type': 'application/json' });
      res.end(JSON.stringify({
        jsonrpc: '2.0',
        error: {
          code: -32000,
          message: 'Rate limit exceeded. Maximum 60 requests per minute.'
        }
      }));
      return;
    }
    
    let body = '';
    req.on('data', chunk => body += chunk.toString());
    
    req.on('end', async () => {
      try {
        const request = JSON.parse(body);
        
        // Sanitize inputs
        if (request.params) {
          Object.keys(request.params).forEach(key => {
            request.params[key] = sanitizeInput(request.params[key]);
          });
        }
        
        log(LOG_LEVELS.DEBUG, 'MCP request received', { 
          method: request.method, 
          id: request.id 
        });
        
        let response;
        
        switch (request.method) {
          case 'initialize':
            response = {
              jsonrpc: '2.0',
              id: request.id,
              result: {
                protocolVersion: '2024-11-05',
                capabilities: {
                  tools: { listChanged: true },
                  resources: { subscribe: true, listChanged: true },
                  prompts: { listChanged: true },
                  sampling: {},
                  roots: { listChanged: true },
                  logging: {}
                },
                serverInfo: {
                  name: 'Airtable MCP Server - AI Agent Enhanced',
                  version: '3.0.0',
                  description: 'Advanced AI-powered MCP server with 10 intelligent prompt templates, predictive analytics, and enterprise automation capabilities'
                }
              }
            };
            log(LOG_LEVELS.INFO, 'Client initialized', { clientId: request.id });
            break;
            
          case 'tools/list':
            response = {
              jsonrpc: '2.0',
              id: request.id,
              result: {
                tools: TOOLS_SCHEMA
              }
            };
            break;
            
          case 'tools/call':
            response = await handleToolCall(request);
            break;
            
          case 'prompts/list':
            response = {
              jsonrpc: '2.0',
              id: request.id,
              result: {
                prompts: PROMPTS_SCHEMA
              }
            };
            break;
            
          case 'prompts/get':
            response = await handlePromptGet(request);
            break;
            
          case 'roots/list':
            response = {
              jsonrpc: '2.0',
              id: request.id,
              result: {
                roots: ROOTS_CONFIG
              }
            };
            break;
            
          case 'logging/setLevel':
            const level = request.params?.level;
            if (level && LOG_LEVELS[level.toUpperCase()] !== undefined) {
              currentLogLevel = LOG_LEVELS[level.toUpperCase()];
              log(LOG_LEVELS.INFO, 'Log level updated', { newLevel: level });
            }
            response = {
              jsonrpc: '2.0',
              id: request.id,
              result: {}
            };
            break;
            
          case 'sampling/createMessage':
            response = await handleSampling(request);
            break;
            
          default:
            log(LOG_LEVELS.WARN, 'Unknown method', { method: request.method });
            throw new Error(`Method "${request.method}" not found`);
        }
        
        res.writeHead(200, { 'Content-Type': 'application/json' });
        res.end(JSON.stringify(response));
        
      } catch (error) {
        log(LOG_LEVELS.ERROR, 'Request processing failed', { error: error.message });
        
        const errorResponse = {
          jsonrpc: '2.0',
          id: request?.id || null,
          error: {
            code: -32000,
            message: error.message || 'Internal server error'
          }
        };
        
        res.writeHead(200, { 'Content-Type': 'application/json' });
        res.end(JSON.stringify(errorResponse));
      }
    });
    return;
  }
  
  // Default 404
  res.writeHead(404, { 'Content-Type': 'application/json' });
  res.end(JSON.stringify({ error: 'Not Found' }));
});

// Tool handlers
async function handleToolCall(request) {
  const toolName = request.params.name;
  const toolParams = request.params.arguments || {};
  
  try {
    let result;
    let responseText;
    
    switch (toolName) {
      case 'list_tables':
        const includeSchema = toolParams.include_schema || false;
        result = await callAirtableAPI(`meta/bases/${baseId}/tables`);
        const tables = result.tables || [];
        
        responseText = tables.length > 0 
          ? `Found ${tables.length} table(s): ` + 
            tables.map((table, i) => 
              `${table.name} (ID: ${table.id}, Fields: ${table.fields?.length || 0})`
            ).join(', ')
          : 'No tables found in this base.';
        break;
        
      case 'list_records':
        const { table, maxRecords, view, filterByFormula } = toolParams;
        
        const queryParams = {};
        if (maxRecords) queryParams.maxRecords = maxRecords;
        if (view) queryParams.view = view;
        if (filterByFormula) queryParams.filterByFormula = filterByFormula;
        
        result = await callAirtableAPI(table, 'GET', null, queryParams);
        const records = result.records || [];
        
        responseText = records.length > 0
          ? `Found ${records.length} record(s) in table "${table}"`
          : `No records found in table "${table}".`;
        break;
        
      case 'get_record':
        const { table: getTable, recordId } = toolParams;
        result = await callAirtableAPI(`${getTable}/${recordId}`);
        responseText = `Retrieved record ${recordId} from table "${getTable}"`;
        break;
        
      case 'create_record':
        const { table: createTable, fields } = toolParams;
        const body = { fields: fields };
        result = await callAirtableAPI(createTable, 'POST', body);
        responseText = `Successfully created record in table "${createTable}" with ID: ${result.id}`;
        break;
        
      case 'update_record':
        const { table: updateTable, recordId: updateRecordId, fields: updateFields } = toolParams;
        const updateBody = { fields: updateFields };
        result = await callAirtableAPI(`${updateTable}/${updateRecordId}`, 'PATCH', updateBody);
        responseText = `Successfully updated record ${updateRecordId} in table "${updateTable}"`;
        break;
        
      case 'delete_record':
        const { table: deleteTable, recordId: deleteRecordId } = toolParams;
        result = await callAirtableAPI(`${deleteTable}/${deleteRecordId}`, 'DELETE');
        responseText = `Successfully deleted record ${deleteRecordId} from table "${deleteTable}"`;
        break;
        
      default:
        throw new Error(`Unknown tool: ${toolName}`);
    }
    
    return {
      jsonrpc: '2.0',
      id: request.id,
      result: {
        content: [
          {
            type: 'text',
            text: responseText
          }
        ]
      }
    };
    
  } catch (error) {
    log(LOG_LEVELS.ERROR, `Tool ${toolName} failed`, { error: error.message });
    
    return {
      jsonrpc: '2.0',
      id: request.id,
      result: {
        content: [
          {
            type: 'text',
            text: `Error executing ${toolName}: ${error.message}`
          }
        ]
      }
    };
  }
}

// Enhanced AI-powered prompt handlers
async function handlePromptGet(request) {
  const promptName = request.params.name;
  const promptArgs = request.params.arguments || {};
  
  try {
    const prompt = PROMPTS_SCHEMA.find(p => p.name === promptName);
    if (!prompt) {
      throw new Error(`Prompt "${promptName}" not found`);
    }
    
    let messages = [];
    
    switch (promptName) {
      case 'analyze_data':
        const { table, analysis_type = 'statistical', field_focus, time_dimension, confidence_level = '0.95' } = promptArgs;
        messages = [
          {
            role: 'user',
            content: {
              type: 'text',
              text: `🤖 ADVANCED DATA ANALYSIS REQUEST

**Table**: ${table}
**Analysis Type**: ${analysis_type}
**Confidence Level**: ${confidence_level}
${field_focus ? `**Focus Fields**: ${field_focus}` : ''}
${time_dimension ? `**Time Dimension**: ${time_dimension}` : ''}

**Instructions**:
1. First, examine the table schema and structure using list_tables with include_schema=true
2. Retrieve representative sample data using list_records with appropriate filters
3. Perform ${analysis_type} analysis with statistical rigor
4. Generate insights with confidence intervals and significance testing
5. Provide actionable recommendations based on findings

**Expected Deliverables**:
- Statistical summary with key metrics
- Pattern identification and trend analysis
- Anomaly detection if applicable
- Predictive insights where relevant
- Visualization recommendations
- Business impact assessment

Please use the available Airtable tools to gather data and provide comprehensive ${analysis_type} analysis.`
            }
          }
        ];
        break;
        
      case 'create_report':
        const { table: reportTable, report_type = 'executive_summary', time_period = 'last_30_days', stakeholder_level = 'manager', include_recommendations = 'true' } = promptArgs;
        messages = [
          {
            role: 'user',
            content: {
              type: 'text',
              text: `📊 INTELLIGENT REPORT GENERATION

**Target Table**: ${reportTable}
**Report Type**: ${report_type}
**Time Period**: ${time_period}
**Stakeholder Level**: ${stakeholder_level}
**Include Recommendations**: ${include_recommendations}

**Report Generation Process**:
1. Analyze table structure and data types
2. Extract relevant data for specified time period
3. Calculate key performance indicators
4. Identify trends and patterns
5. Generate visualizations suggestions
6. Create ${stakeholder_level}-appropriate narrative

**Report Sections**:
- Executive Summary (key findings)
- Data Overview and Quality Assessment
- Trend Analysis and Patterns
- Performance Metrics and KPIs
- Risk Assessment and Opportunities
${include_recommendations === 'true' ? '- AI-Generated Recommendations' : ''}
- Next Steps and Action Items

Please gather the necessary data and create a comprehensive ${report_type} tailored for ${stakeholder_level} level stakeholders.`
            }
          }
        ];
        break;
        
      case 'data_insights':
        const { tables, insight_type = 'correlations', business_context = 'general', insight_depth = 'moderate' } = promptArgs;
        messages = [
          {
            role: 'user',
            content: {
              type: 'text',
              text: `🔍 ADVANCED DATA INSIGHTS DISCOVERY

**Target Tables**: ${tables}
**Insight Type**: ${insight_type}
**Business Context**: ${business_context}
**Analysis Depth**: ${insight_depth}

**Discovery Framework**:
1. Multi-table schema analysis and relationship mapping
2. Cross-table data correlation analysis
3. Pattern recognition using ${business_context} domain knowledge
4. Statistical significance testing
5. Business impact quantification

**Insight Categories**:
- ${insight_type} analysis with statistical validation
- Hidden patterns and unexpected relationships
- Segmentation opportunities
- Predictive indicators
- Data quality insights
- Business optimization opportunities

**${business_context.toUpperCase()} CONTEXT ANALYSIS**:
${business_context === 'sales' ? '- Revenue drivers and conversion patterns\n- Customer lifetime value indicators\n- Sales cycle optimization opportunities' : ''}
${business_context === 'marketing' ? '- Campaign effectiveness and attribution\n- Customer segmentation insights\n- Channel performance analysis' : ''}
${business_context === 'operations' ? '- Process efficiency metrics\n- Resource utilization patterns\n- Bottleneck identification' : ''}

Please conduct ${insight_depth} analysis across the specified tables and provide actionable business insights.`
            }
          }
        ];
        break;
        
      case 'optimize_workflow':
        const { base_overview, optimization_focus = 'automation', current_pain_points, team_size } = promptArgs;
        messages = [
          {
            role: 'user',
            content: {
              type: 'text',
              text: `⚡ AI-POWERED WORKFLOW OPTIMIZATION

**Optimization Focus**: ${optimization_focus}
**Team Size**: ${team_size || 'Not specified'}
${base_overview ? `**Base Overview**: ${base_overview}` : ''}
${current_pain_points ? `**Current Pain Points**: ${current_pain_points}` : ''}

**Optimization Analysis**:
1. Workflow pattern analysis and bottleneck identification
2. Automation opportunity assessment
3. User experience and efficiency evaluation
4. Integration and scaling considerations
5. ROI analysis for proposed improvements

**${optimization_focus.toUpperCase()} OPTIMIZATION**:
${optimization_focus === 'automation' ? '- Identify repetitive manual tasks\n- Suggest automation workflows\n- Estimate time savings and ROI' : ''}
${optimization_focus === 'data_quality' ? '- Data validation and cleansing rules\n- Consistency and accuracy improvements\n- Quality monitoring systems' : ''}
${optimization_focus === 'collaboration' ? '- Team workflow improvements\n- Permission and access optimization\n- Communication enhancement strategies' : ''}

**Deliverables**:
- Workflow efficiency assessment
- Prioritized improvement recommendations
- Implementation roadmap with timelines
- Cost-benefit analysis
- Change management considerations

Please analyze the current setup and provide comprehensive ${optimization_focus} optimization recommendations.`
            }
          }
        ];
        break;

      case 'smart_schema_design':
        const { use_case, data_volume = 'medium', integration_needs, compliance_requirements = 'none' } = promptArgs;
        messages = [
          {
            role: 'user',
            content: {
              type: 'text',
              text: `🏗️ AI-ASSISTED SCHEMA OPTIMIZATION

**Use Case**: ${use_case}
**Data Volume**: ${data_volume}
**Compliance**: ${compliance_requirements}
${integration_needs ? `**Integrations**: ${integration_needs}` : ''}

**Schema Design Analysis**:
1. Current schema evaluation for ${use_case} best practices
2. Field type and relationship optimization
3. Performance and scalability assessment
4. Compliance requirement implementation
5. Integration compatibility review

**${use_case.toUpperCase()} OPTIMIZATION**:
${use_case === 'crm' ? '- Customer lifecycle tracking\n- Sales pipeline optimization\n- Contact relationship mapping' : ''}
${use_case === 'project_management' ? '- Task dependency modeling\n- Resource allocation tracking\n- Timeline and milestone management' : ''}
${use_case === 'inventory' ? '- Stock level monitoring\n- Supplier relationship tracking\n- Cost and pricing optimization' : ''}

**Recommendations**:
- Optimal field types and relationships
- Indexing and performance suggestions
- Data validation and integrity rules
- Automation and workflow triggers
- Scaling and maintenance considerations

Please analyze the current schema and provide ${use_case}-optimized recommendations.`
            }
          }
        ];
        break;

      case 'data_quality_audit':
        const { tables: auditTables, quality_dimensions = 'completeness,accuracy,consistency', severity_threshold = 'medium', auto_fix_suggestions = 'true' } = promptArgs;
        messages = [
          {
            role: 'user',
            content: {
              type: 'text',
              text: `🔍 COMPREHENSIVE DATA QUALITY AUDIT

**Tables to Audit**: ${auditTables}
**Quality Dimensions**: ${quality_dimensions}
**Severity Threshold**: ${severity_threshold}
**Auto-Fix Suggestions**: ${auto_fix_suggestions}

**Audit Framework**:
1. Data completeness analysis (missing values, empty fields)
2. Accuracy assessment (format validation, range checks)
3. Consistency evaluation (cross-field validation, duplicates)
4. Validity verification (data type compliance, constraints)
5. Uniqueness analysis (duplicate detection, key integrity)
6. Timeliness review (data freshness, update patterns)

**Quality Assessment Process**:
- Statistical analysis of data distribution
- Pattern recognition for anomalies
- Cross-table consistency validation
- Historical trend analysis
- Business rule compliance checking

**Deliverables**:
- Quality score by dimension and table
- Detailed issue identification and classification
- Impact assessment and prioritization
${auto_fix_suggestions === 'true' ? '- Automated fix suggestions and scripts' : ''}
- Data governance recommendations
- Monitoring and maintenance strategies

Please conduct a thorough data quality audit focusing on ${quality_dimensions} dimensions.`
            }
          }
        ];
        break;

      case 'predictive_analytics':
        const { table: predTable, target_field, prediction_horizon = 'next_month', model_type = 'trend_analysis', feature_fields } = promptArgs;
        messages = [
          {
            role: 'user',
            content: {
              type: 'text',
              text: `🔮 ADVANCED PREDICTIVE ANALYTICS

**Source Table**: ${predTable}
**Target Field**: ${target_field}
**Prediction Horizon**: ${prediction_horizon}
**Model Type**: ${model_type}
${feature_fields ? `**Feature Fields**: ${feature_fields}` : ''}

**Predictive Modeling Process**:
1. Historical data analysis and trend identification
2. Feature engineering and variable selection
3. Model development using ${model_type} approach
4. Validation and accuracy assessment
5. Forecast generation for ${prediction_horizon}
6. Confidence intervals and uncertainty quantification

**${model_type.toUpperCase()} ANALYSIS**:
${model_type === 'time_series' ? '- Seasonal pattern detection\n- Trend decomposition\n- Cyclical behavior analysis' : ''}
${model_type === 'regression' ? '- Variable relationship modeling\n- Predictive factor identification\n- Statistical significance testing' : ''}
${model_type === 'classification' ? '- Category prediction modeling\n- Feature importance analysis\n- Classification accuracy metrics' : ''}

**Outputs**:
- Historical pattern analysis
- Predictive model performance metrics
- Forecast values with confidence intervals
- Key influencing factors identification
- Model limitations and assumptions
- Actionable insights and recommendations

Please develop a ${model_type} model to predict ${target_field} over ${prediction_horizon}.`
            }
          }
        ];
        break;

      case 'natural_language_query':
        const { question, context_tables, response_format = 'narrative', include_confidence = 'true' } = promptArgs;
        messages = [
          {
            role: 'user',
            content: {
              type: 'text',
              text: `🗣️ NATURAL LANGUAGE DATA QUERY

**Question**: "${question}"
${context_tables ? `**Context Tables**: ${context_tables}` : ''}
**Response Format**: ${response_format}
**Include Confidence**: ${include_confidence}

**Query Processing Framework**:
1. Question analysis and intent recognition
2. Relevant table and field identification
3. Data retrieval strategy formulation
4. Analysis execution and result compilation
5. Natural language response generation

**Analysis Approach**:
- Semantic understanding of the question
- Automatic table and field mapping
- Intelligent data filtering and aggregation
- Statistical analysis where appropriate
- Context-aware interpretation

**Response Requirements**:
${response_format === 'narrative' ? '- Conversational, easy-to-understand explanation\n- Supporting data and evidence\n- Contextual insights and implications' : ''}
${response_format === 'data_summary' ? '- Structured data summary\n- Key metrics and statistics\n- Trend identification' : ''}
${response_format === 'visualization_suggestion' ? '- Chart and graph recommendations\n- Data visualization best practices\n- Tool-specific guidance' : ''}
${include_confidence === 'true' ? '\n- Confidence scores for answers\n- Data quality indicators\n- Uncertainty acknowledgment' : ''}

Please analyze the available data and provide a comprehensive answer to: "${question}"`
            }
          }
        ];
        break;

      case 'smart_data_transformation':
        const { source_table, transformation_goal, target_format, quality_rules, preserve_history = 'true' } = promptArgs;
        messages = [
          {
            role: 'user',
            content: {
              type: 'text',
              text: `🔄 INTELLIGENT DATA TRANSFORMATION

**Source Table**: ${source_table}
**Transformation Goal**: ${transformation_goal}
${target_format ? `**Target Format**: ${target_format}` : ''}
${quality_rules ? `**Quality Rules**: ${quality_rules}` : ''}
**Preserve History**: ${preserve_history}

**Transformation Framework**:
1. Source data analysis and quality assessment
2. Transformation strategy development
3. Data mapping and conversion rules
4. Quality validation and error handling
5. Output optimization and validation

**${transformation_goal.toUpperCase()} PROCESS**:
${transformation_goal === 'normalize' ? '- Database normalization principles\n- Redundancy elimination\n- Relationship optimization' : ''}
${transformation_goal === 'standardize' ? '- Format standardization\n- Value normalization\n- Consistency enforcement' : ''}
${transformation_goal === 'enrich' ? '- Data augmentation strategies\n- External data integration\n- Value-added field creation' : ''}
${transformation_goal === 'cleanse' ? '- Data validation and correction\n- Duplicate removal\n- Missing value handling' : ''}

**Deliverables**:
- Transformation execution plan
- Data mapping specifications
- Quality validation results
- Performance optimization recommendations
${preserve_history === 'true' ? '- Change audit trail and versioning' : ''}
- Post-transformation validation

Please analyze the source data and execute ${transformation_goal} transformation with intelligent optimization.`
            }
          }
        ];
        break;

      case 'automation_recommendations':
        const { workflow_description, automation_scope = 'single_table', frequency_patterns, complexity_tolerance = 'moderate', integration_capabilities } = promptArgs;
        messages = [
          {
            role: 'user',
            content: {
              type: 'text',
              text: `🤖 INTELLIGENT AUTOMATION RECOMMENDATIONS

**Automation Scope**: ${automation_scope}
**Complexity Tolerance**: ${complexity_tolerance}
${workflow_description ? `**Current Workflow**: ${workflow_description}` : ''}
${frequency_patterns ? `**Frequency Patterns**: ${frequency_patterns}` : ''}
${integration_capabilities ? `**Integration Tools**: ${integration_capabilities}` : ''}

**Automation Analysis Framework**:
1. Workflow pattern analysis and task identification
2. Automation opportunity assessment and prioritization
3. Technical feasibility and complexity evaluation
4. ROI calculation and benefit quantification
5. Implementation roadmap development

**${automation_scope.toUpperCase()} AUTOMATION**:
${automation_scope === 'single_table' ? '- Field auto-population rules\n- Data validation automation\n- Notification triggers' : ''}
${automation_scope === 'multi_table' ? '- Cross-table data synchronization\n- Workflow orchestration\n- Complex business logic automation' : ''}
${automation_scope === 'external_integration' ? '- API integration strategies\n- Data pipeline automation\n- Third-party tool connectivity' : ''}

**Recommendations**:
- High-impact automation opportunities
- Implementation complexity assessment
- Cost-benefit analysis with ROI projections
- Technical requirements and dependencies
- Risk assessment and mitigation strategies
- Success metrics and monitoring approach

Please analyze the workflow patterns and provide ${complexity_tolerance}-level automation recommendations for ${automation_scope} scope.`
            }
          }
        ];
        break;
        
      default:
        throw new Error(`Unsupported prompt: ${promptName}`);
    }
    
    return {
      jsonrpc: '2.0',
      id: request.id,
      result: {
        description: prompt.description,
        messages: messages
      }
    };
    
  } catch (error) {
    log(LOG_LEVELS.ERROR, `Prompt ${promptName} failed`, { error: error.message });
    
    return {
      jsonrpc: '2.0',
      id: request.id,
      error: {
        code: -32000,
        message: `Error getting prompt ${promptName}: ${error.message}`
      }
    };
  }
}

// Sampling handler
async function handleSampling(request) {
  const { messages, modelPreferences } = request.params;
  
  try {
    // Note: In a real implementation, this would integrate with an LLM API
    // For now, we'll return a structured response indicating sampling capability
    
    log(LOG_LEVELS.INFO, 'Sampling request received', { 
      messageCount: messages?.length,
      model: modelPreferences?.model 
    });
    
    return {
      jsonrpc: '2.0',
      id: request.id,
      result: {
        model: modelPreferences?.model || 'claude-3-sonnet',
        role: 'assistant',
        content: {
          type: 'text',
          text: 'Sampling capability is available. This MCP server can request AI assistance for complex data analysis and insights generation. In a full implementation, this would connect to your preferred LLM for intelligent Airtable operations.'
        },
        stopReason: 'end_turn'
      }
    };
    
  } catch (error) {
    log(LOG_LEVELS.ERROR, 'Sampling failed', { error: error.message });
    
    return {
      jsonrpc: '2.0',
      id: request.id,
      error: {
        code: -32000,
        message: `Sampling error: ${error.message}`
      }
    };
  }
}

// Server startup
const PORT = CONFIG.PORT;
const HOST = CONFIG.HOST;

server.listen(PORT, HOST, () => {
  log(LOG_LEVELS.INFO, `Airtable MCP Server started`, {
    host: HOST,
    port: PORT,
    version: '2.1.0'
  });
  
  console.log(`
╔═══════════════════════════════════════════════════════════════╗
║                 Airtable MCP Server v2.1                     ║
║            Model Context Protocol Implementation              ║
╠═══════════════════════════════════════════════════════════════╣
║  🌐 MCP Endpoint: http://${HOST}:${PORT}/mcp                  ║
║  📊 Health Check: http://${HOST}:${PORT}/health               ║
║  🔒 Security: Rate limiting, input validation                ║
║  📋 Tools: ${TOOLS_SCHEMA.length} available operations                    ║
╠═══════════════════════════════════════════════════════════════╣
║  🔗 Connected to Airtable Base: ${baseId.slice(0, 8)}...        ║
║  🚀 Ready for MCP client connections                         ║
╚═══════════════════════════════════════════════════════════════╝
  `);
});

// Graceful shutdown
function gracefulShutdown(signal) {
  log(LOG_LEVELS.INFO, 'Graceful shutdown initiated', { signal });
  
  server.close(() => {
    log(LOG_LEVELS.INFO, 'Server stopped');
    process.exit(0);
  });
  
  setTimeout(() => {
    log(LOG_LEVELS.ERROR, 'Force shutdown - server did not close in time');
    process.exit(1);
  }, 10000);
}

process.on('SIGTERM', () => gracefulShutdown('SIGTERM'));
process.on('SIGINT', () => gracefulShutdown('SIGINT'));

process.on('uncaughtException', (error) => {
  log(LOG_LEVELS.ERROR, 'Uncaught exception', { error: error.message });
  gracefulShutdown('uncaughtException');
});

process.on('unhandledRejection', (reason) => {
  log(LOG_LEVELS.ERROR, 'Unhandled promise rejection', { reason: reason?.toString() });
  gracefulShutdown('unhandledRejection');
});
```

--------------------------------------------------------------------------------
/src/javascript/airtable_simple.js:
--------------------------------------------------------------------------------

```javascript
#!/usr/bin/env node

const http = require('http');
const https = require('https');
const fs = require('fs');
const path = require('path');

// Load environment variables from .env file if it exists
const envPath = path.join(__dirname, '.env');
if (fs.existsSync(envPath)) {
  require('dotenv').config({ path: envPath });
}

// Parse command line arguments with environment variable fallback
const args = process.argv.slice(2);
let tokenIndex = args.indexOf('--token');
let baseIndex = args.indexOf('--base');

// Use environment variables as fallback
const token = tokenIndex !== -1 ? args[tokenIndex + 1] : process.env.AIRTABLE_TOKEN || process.env.AIRTABLE_API_TOKEN;
const baseId = baseIndex !== -1 ? args[baseIndex + 1] : process.env.AIRTABLE_BASE_ID || process.env.AIRTABLE_BASE;

if (!token || !baseId) {
  console.error('Error: Missing Airtable credentials');
  console.error('\nUsage options:');
  console.error('  1. Command line: node airtable_enhanced.js --token YOUR_TOKEN --base YOUR_BASE_ID');
  console.error('  2. Environment variables: AIRTABLE_TOKEN and AIRTABLE_BASE_ID');
  console.error('  3. .env file with AIRTABLE_TOKEN and AIRTABLE_BASE_ID');
  process.exit(1);
}

// Configure logging levels
const LOG_LEVELS = {
  ERROR: 0,
  WARN: 1,
  INFO: 2,
  DEBUG: 3
};

const currentLogLevel = process.env.LOG_LEVEL ? LOG_LEVELS[process.env.LOG_LEVEL.toUpperCase()] || LOG_LEVELS.INFO : LOG_LEVELS.INFO;

function log(level, message, ...args) {
  const levelName = Object.keys(LOG_LEVELS).find(key => LOG_LEVELS[key] === level);
  const timestamp = new Date().toISOString();
  
  if (level <= currentLogLevel) {
    const prefix = `[${timestamp}] [${levelName}]`;
    if (level === LOG_LEVELS.ERROR) {
      console.error(prefix, message, ...args);
    } else if (level === LOG_LEVELS.WARN) {
      console.warn(prefix, message, ...args);
    } else {
      console.log(prefix, message, ...args);
    }
  }
}

log(LOG_LEVELS.INFO, `Starting Enhanced Airtable MCP server v1.6.0`);
log(LOG_LEVELS.INFO, `Authentication configured`);
log(LOG_LEVELS.INFO, `Base connection established`);

// Enhanced Airtable API function with full HTTP method support
function callAirtableAPI(endpoint, method = 'GET', body = null, queryParams = {}) {
  return new Promise((resolve, reject) => {
    const isBaseEndpoint = !endpoint.startsWith('meta/') && !endpoint.startsWith('bases/');
    const baseUrl = isBaseEndpoint ? `${baseId}/${endpoint}` : endpoint;
    
    // Build query string
    const queryString = Object.keys(queryParams).length > 0 
      ? '?' + new URLSearchParams(queryParams).toString() 
      : '';
    
    const url = `https://api.airtable.com/v0/${baseUrl}${queryString}`;
    const urlObj = new URL(url);
    
    log(LOG_LEVELS.DEBUG, `API Request: ${method} ${url}`);
    if (body) {
      log(LOG_LEVELS.DEBUG, `Request body:`, JSON.stringify(body, null, 2));
    }
    
    const options = {
      hostname: urlObj.hostname,
      path: urlObj.pathname + urlObj.search,
      method: method,
      headers: {
        'Authorization': `Bearer ${token}`,
        'Content-Type': 'application/json'
      }
    };
    
    const req = https.request(options, (response) => {
      let data = '';
      
      response.on('data', (chunk) => {
        data += chunk;
      });
      
      response.on('end', () => {
        log(LOG_LEVELS.DEBUG, `Response status: ${response.statusCode}`);
        log(LOG_LEVELS.DEBUG, `Response data:`, data);
        
        try {
          const parsed = data ? JSON.parse(data) : {};
          
          if (response.statusCode >= 200 && response.statusCode < 300) {
            resolve(parsed);
          } else {
            const error = parsed.error || {};
            reject(new Error(`Airtable API error (${response.statusCode}): ${error.message || error.type || 'Unknown error'}`));
          }
        } catch (e) {
          reject(new Error(`Failed to parse Airtable response: ${e.message}`));
        }
      });
    });
    
    req.on('error', (error) => {
      reject(new Error(`Airtable API request failed: ${error.message}`));
    });
    
    if (body) {
      req.write(JSON.stringify(body));
    }
    
    req.end();
  });
}

// Create HTTP server
const server = http.createServer(async (req, res) => {
  // Enable CORS
  res.setHeader('Access-Control-Allow-Origin', '*');
  res.setHeader('Access-Control-Allow-Methods', 'POST, OPTIONS');
  res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
  
  // Handle preflight request
  if (req.method === 'OPTIONS') {
    res.writeHead(200);
    res.end();
    return;
  }
  
  // Only handle POST requests to /mcp
  if (req.method !== 'POST' || !req.url.endsWith('/mcp')) {
    res.writeHead(404);
    res.end();
    return;
  }
  
  let body = '';
  req.on('data', chunk => {
    body += chunk.toString();
  });
  
  req.on('end', async () => {
    try {
      const request = JSON.parse(body);
      log(LOG_LEVELS.DEBUG, 'Received request:', JSON.stringify(request, null, 2));
      
      // Handle JSON-RPC methods
      if (request.method === 'tools/list') {
        const response = {
          jsonrpc: '2.0',
          id: request.id,
          result: {
            tools: [
              {
                name: 'list_tables',
                description: 'List all tables in the Airtable base',
                inputSchema: {
                  type: 'object',
                  properties: {}
                }
              },
              {
                name: 'list_records',
                description: 'List records from a specific table',
                inputSchema: {
                  type: 'object',
                  properties: {
                    table: { type: 'string', description: 'Table name or ID' },
                    maxRecords: { type: 'number', description: 'Maximum number of records to return' },
                    view: { type: 'string', description: 'View name or ID' }
                  },
                  required: ['table']
                }
              },
              {
                name: 'get_record',
                description: 'Get a single record by ID',
                inputSchema: {
                  type: 'object',
                  properties: {
                    table: { type: 'string', description: 'Table name or ID' },
                    recordId: { type: 'string', description: 'Record ID' }
                  },
                  required: ['table', 'recordId']
                }
              },
              {
                name: 'create_record',
                description: 'Create a new record in a table',
                inputSchema: {
                  type: 'object',
                  properties: {
                    table: { type: 'string', description: 'Table name or ID' },
                    fields: { type: 'object', description: 'Field values for the new record' }
                  },
                  required: ['table', 'fields']
                }
              },
              {
                name: 'update_record',
                description: 'Update an existing record',
                inputSchema: {
                  type: 'object',
                  properties: {
                    table: { type: 'string', description: 'Table name or ID' },
                    recordId: { type: 'string', description: 'Record ID to update' },
                    fields: { type: 'object', description: 'Fields to update' }
                  },
                  required: ['table', 'recordId', 'fields']
                }
              },
              {
                name: 'delete_record',
                description: 'Delete a record from a table',
                inputSchema: {
                  type: 'object',
                  properties: {
                    table: { type: 'string', description: 'Table name or ID' },
                    recordId: { type: 'string', description: 'Record ID to delete' }
                  },
                  required: ['table', 'recordId']
                }
              },
              {
                name: 'search_records',
                description: 'Search records with filtering and sorting',
                inputSchema: {
                  type: 'object',
                  properties: {
                    table: { type: 'string', description: 'Table name or ID' },
                    filterByFormula: { type: 'string', description: 'Airtable formula to filter records' },
                    sort: { type: 'array', description: 'Sort configuration' },
                    maxRecords: { type: 'number', description: 'Maximum records to return' },
                    fields: { type: 'array', description: 'Fields to return' }
                  },
                  required: ['table']
                }
              },
              {
                name: 'list_webhooks',
                description: 'List all webhooks for the base',
                inputSchema: {
                  type: 'object',
                  properties: {}
                }
              },
              {
                name: 'create_webhook',
                description: 'Create a new webhook for a table',
                inputSchema: {
                  type: 'object',
                  properties: {
                    notificationUrl: { type: 'string', description: 'URL to receive webhook notifications' },
                    specification: {
                      type: 'object',
                      description: 'Webhook specification',
                      properties: {
                        options: {
                          type: 'object',
                          properties: {
                            filters: {
                              type: 'object',
                              properties: {
                                dataTypes: { type: 'array', items: { type: 'string' } },
                                recordChangeScope: { type: 'string' }
                              }
                            }
                          }
                        }
                      }
                    }
                  },
                  required: ['notificationUrl']
                }
              },
              {
                name: 'delete_webhook',
                description: 'Delete a webhook',
                inputSchema: {
                  type: 'object',
                  properties: {
                    webhookId: { type: 'string', description: 'Webhook ID to delete' }
                  },
                  required: ['webhookId']
                }
              },
              {
                name: 'get_webhook_payloads',
                description: 'Get webhook payload history',
                inputSchema: {
                  type: 'object',
                  properties: {
                    webhookId: { type: 'string', description: 'Webhook ID' },
                    cursor: { type: 'number', description: 'Cursor for pagination' }
                  },
                  required: ['webhookId']
                }
              },
              {
                name: 'refresh_webhook',
                description: 'Refresh a webhook to extend its expiration',
                inputSchema: {
                  type: 'object',
                  properties: {
                    webhookId: { type: 'string', description: 'Webhook ID to refresh' }
                  },
                  required: ['webhookId']
                }
              },
              {
                name: 'list_bases',
                description: 'List all accessible Airtable bases',
                inputSchema: {
                  type: 'object',
                  properties: {
                    offset: { type: 'string', description: 'Pagination offset for listing more bases' }
                  }
                }
              },
              {
                name: 'get_base_schema',
                description: 'Get complete schema information for a base',
                inputSchema: {
                  type: 'object',
                  properties: {
                    baseId: { type: 'string', description: 'Base ID to get schema for (optional, defaults to current base)' }
                  }
                }
              },
              {
                name: 'describe_table',
                description: 'Get detailed information about a specific table including all fields',
                inputSchema: {
                  type: 'object',
                  properties: {
                    table: { type: 'string', description: 'Table name or ID' }
                  },
                  required: ['table']
                }
              },
              {
                name: 'create_table',
                description: 'Create a new table in the base',
                inputSchema: {
                  type: 'object',
                  properties: {
                    name: { type: 'string', description: 'Name for the new table' },
                    description: { type: 'string', description: 'Optional description for the table' },
                    fields: { 
                      type: 'array', 
                      description: 'Array of field definitions',
                      items: {
                        type: 'object',
                        properties: {
                          name: { type: 'string', description: 'Field name' },
                          type: { type: 'string', description: 'Field type (singleLineText, number, etc.)' },
                          description: { type: 'string', description: 'Field description' },
                          options: { type: 'object', description: 'Field-specific options' }
                        },
                        required: ['name', 'type']
                      }
                    }
                  },
                  required: ['name', 'fields']
                }
              },
              {
                name: 'update_table',
                description: 'Update table name or description',
                inputSchema: {
                  type: 'object',
                  properties: {
                    table: { type: 'string', description: 'Table name or ID' },
                    name: { type: 'string', description: 'New table name' },
                    description: { type: 'string', description: 'New table description' }
                  },
                  required: ['table']
                }
              },
              {
                name: 'delete_table',
                description: 'Delete a table (WARNING: This will permanently delete all data)',
                inputSchema: {
                  type: 'object',
                  properties: {
                    table: { type: 'string', description: 'Table name or ID to delete' },
                    confirm: { type: 'boolean', description: 'Must be true to confirm deletion' }
                  },
                  required: ['table', 'confirm']
                }
              },
              {
                name: 'create_field',
                description: 'Add a new field to an existing table',
                inputSchema: {
                  type: 'object',
                  properties: {
                    table: { type: 'string', description: 'Table name or ID' },
                    name: { type: 'string', description: 'Field name' },
                    type: { type: 'string', description: 'Field type (singleLineText, number, multipleSelectionList, etc.)' },
                    description: { type: 'string', description: 'Field description' },
                    options: { type: 'object', description: 'Field-specific options (e.g., choices for select fields)' }
                  },
                  required: ['table', 'name', 'type']
                }
              },
              {
                name: 'update_field',
                description: 'Update field properties',
                inputSchema: {
                  type: 'object',
                  properties: {
                    table: { type: 'string', description: 'Table name or ID' },
                    fieldId: { type: 'string', description: 'Field ID to update' },
                    name: { type: 'string', description: 'New field name' },
                    description: { type: 'string', description: 'New field description' },
                    options: { type: 'object', description: 'Updated field options' }
                  },
                  required: ['table', 'fieldId']
                }
              },
              {
                name: 'delete_field',
                description: 'Delete a field from a table (WARNING: This will permanently delete all data in this field)',
                inputSchema: {
                  type: 'object',
                  properties: {
                    table: { type: 'string', description: 'Table name or ID' },
                    fieldId: { type: 'string', description: 'Field ID to delete' },
                    confirm: { type: 'boolean', description: 'Must be true to confirm deletion' }
                  },
                  required: ['table', 'fieldId', 'confirm']
                }
              },
              {
                name: 'list_field_types',
                description: 'Get a reference of all available Airtable field types and their schemas',
                inputSchema: {
                  type: 'object',
                  properties: {}
                }
              },
              {
                name: 'get_table_views',
                description: 'List all views for a specific table',
                inputSchema: {
                  type: 'object',
                  properties: {
                    table: { type: 'string', description: 'Table name or ID' }
                  },
                  required: ['table']
                }
              },
              {
                name: 'upload_attachment',
                description: 'Upload/attach a file from URL to a record',
                inputSchema: {
                  type: 'object',
                  properties: {
                    table: { type: 'string', description: 'Table name or ID' },
                    recordId: { type: 'string', description: 'Record ID to attach file to' },
                    fieldName: { type: 'string', description: 'Name of the attachment field' },
                    url: { type: 'string', description: 'Public URL of the file to attach' },
                    filename: { type: 'string', description: 'Optional filename for the attachment' }
                  },
                  required: ['table', 'recordId', 'fieldName', 'url']
                }
              },
              {
                name: 'batch_create_records',
                description: 'Create multiple records at once (up to 10)',
                inputSchema: {
                  type: 'object',
                  properties: {
                    table: { type: 'string', description: 'Table name or ID' },
                    records: {
                      type: 'array',
                      description: 'Array of record objects to create (max 10)',
                      items: {
                        type: 'object',
                        properties: {
                          fields: { type: 'object', description: 'Record fields' }
                        },
                        required: ['fields']
                      },
                      maxItems: 10
                    }
                  },
                  required: ['table', 'records']
                }
              },
              {
                name: 'batch_update_records',
                description: 'Update multiple records at once (up to 10)',
                inputSchema: {
                  type: 'object',
                  properties: {
                    table: { type: 'string', description: 'Table name or ID' },
                    records: {
                      type: 'array',
                      description: 'Array of record objects to update (max 10)',
                      items: {
                        type: 'object',
                        properties: {
                          id: { type: 'string', description: 'Record ID' },
                          fields: { type: 'object', description: 'Fields to update' }
                        },
                        required: ['id', 'fields']
                      },
                      maxItems: 10
                    }
                  },
                  required: ['table', 'records']
                }
              },
              {
                name: 'batch_delete_records',
                description: 'Delete multiple records at once (up to 10)',
                inputSchema: {
                  type: 'object',
                  properties: {
                    table: { type: 'string', description: 'Table name or ID' },
                    recordIds: {
                      type: 'array',
                      description: 'Array of record IDs to delete (max 10)',
                      items: { type: 'string' },
                      maxItems: 10
                    }
                  },
                  required: ['table', 'recordIds']
                }
              },
              {
                name: 'batch_upsert_records',
                description: 'Update existing records or create new ones based on key fields',
                inputSchema: {
                  type: 'object',
                  properties: {
                    table: { type: 'string', description: 'Table name or ID' },
                    records: {
                      type: 'array',
                      description: 'Array of record objects (max 10)',
                      items: {
                        type: 'object',
                        properties: {
                          fields: { type: 'object', description: 'Record fields' }
                        },
                        required: ['fields']
                      },
                      maxItems: 10
                    },
                    keyFields: {
                      type: 'array',
                      description: 'Fields to use for matching existing records',
                      items: { type: 'string' }
                    }
                  },
                  required: ['table', 'records', 'keyFields']
                }
              },
              {
                name: 'create_view',
                description: 'Create a new view for a table',
                inputSchema: {
                  type: 'object',
                  properties: {
                    table: { type: 'string', description: 'Table name or ID' },
                    name: { type: 'string', description: 'Name for the new view' },
                    type: { type: 'string', description: 'View type (grid, form, calendar, etc.)', enum: ['grid', 'form', 'calendar', 'gallery', 'kanban', 'timeline', 'gantt'] },
                    visibleFieldIds: { type: 'array', description: 'Array of field IDs to show in view', items: { type: 'string' } },
                    fieldOrder: { type: 'array', description: 'Order of fields in view', items: { type: 'string' } }
                  },
                  required: ['table', 'name', 'type']
                }
              },
              {
                name: 'get_view_metadata',
                description: 'Get detailed metadata for a specific view',
                inputSchema: {
                  type: 'object',
                  properties: {
                    table: { type: 'string', description: 'Table name or ID' },
                    viewId: { type: 'string', description: 'View ID' }
                  },
                  required: ['table', 'viewId']
                }
              },
              {
                name: 'create_base',
                description: 'Create a new Airtable base',
                inputSchema: {
                  type: 'object',
                  properties: {
                    name: { type: 'string', description: 'Name for the new base' },
                    workspaceId: { type: 'string', description: 'Workspace ID to create the base in' },
                    tables: {
                      type: 'array',
                      description: 'Initial tables to create in the base',
                      items: {
                        type: 'object',
                        properties: {
                          name: { type: 'string', description: 'Table name' },
                          description: { type: 'string', description: 'Table description' },
                          fields: {
                            type: 'array',
                            description: 'Table fields',
                            items: {
                              type: 'object',
                              properties: {
                                name: { type: 'string', description: 'Field name' },
                                type: { type: 'string', description: 'Field type' }
                              },
                              required: ['name', 'type']
                            }
                          }
                        },
                        required: ['name', 'fields']
                      }
                    }
                  },
                  required: ['name', 'tables']
                }
              },
              {
                name: 'list_collaborators',
                description: 'List collaborators and their permissions for the current base',
                inputSchema: {
                  type: 'object',
                  properties: {
                    baseId: { type: 'string', description: 'Base ID (optional, defaults to current base)' }
                  }
                }
              },
              {
                name: 'list_shares',
                description: 'List shared views and their configurations',
                inputSchema: {
                  type: 'object',
                  properties: {
                    baseId: { type: 'string', description: 'Base ID (optional, defaults to current base)' }
                  }
                }
              }
            ]
          }
        };
        res.writeHead(200, { 'Content-Type': 'application/json' });
        res.end(JSON.stringify(response));
        return;
      }
      
      if (request.method === 'resources/list') {
        const response = {
          jsonrpc: '2.0',
          id: request.id,
          result: {
            resources: [
              {
                id: 'airtable_tables',
                name: 'Airtable Tables',
                description: 'Tables in your Airtable base'
              }
            ]
          }
        };
        res.writeHead(200, { 'Content-Type': 'application/json' });
        res.end(JSON.stringify(response));
        return;
      }
      
      if (request.method === 'prompts/list') {
        const response = {
          jsonrpc: '2.0',
          id: request.id,
          result: {
            prompts: [
              {
                id: 'tables_prompt',
                name: 'List Tables',
                description: 'List all tables'
              }
            ]
          }
        };
        res.writeHead(200, { 'Content-Type': 'application/json' });
        res.end(JSON.stringify(response));
        return;
      }
      
      // Handle tool calls
      if (request.method === 'tools/call') {
        const toolName = request.params.name;
        const toolParams = request.params.arguments || {};
        
        let result;
        let responseText;
        
        try {
          // LIST TABLES
          if (toolName === 'list_tables') {
            result = await callAirtableAPI(`meta/bases/${baseId}/tables`);
            const tables = result.tables || [];
            
            responseText = tables.length > 0 
              ? `Found ${tables.length} table(s):\n` + tables.map((table, i) => 
                  `${i+1}. ${table.name} (ID: ${table.id}, Fields: ${table.fields?.length || 0})`
                ).join('\n')
              : 'No tables found in this base.';
          }
          
          // LIST RECORDS
          else if (toolName === 'list_records') {
            const { table, maxRecords, view } = toolParams;
            
            const queryParams = {};
            if (maxRecords) queryParams.maxRecords = maxRecords;
            if (view) queryParams.view = view;
            
            result = await callAirtableAPI(`${table}`, 'GET', null, queryParams);
            const records = result.records || [];
            
            responseText = records.length > 0
              ? `Found ${records.length} record(s) in table "${table}":\n` + 
                records.map((record, i) => 
                  `${i+1}. ID: ${record.id}\n   Fields: ${JSON.stringify(record.fields, null, 2)}`
                ).join('\n\n')
              : `No records found in table "${table}".`;
          }
          
          // GET SINGLE RECORD
          else if (toolName === 'get_record') {
            const { table, recordId } = toolParams;
            
            result = await callAirtableAPI(`${table}/${recordId}`);
            
            responseText = `Record ${recordId} from table "${table}":\n` + 
              JSON.stringify(result.fields, null, 2) +
              `\n\nCreated: ${result.createdTime}`;
          }
          
          // CREATE RECORD
          else if (toolName === 'create_record') {
            const { table, fields } = toolParams;
            
            const body = {
              fields: fields
            };
            
            result = await callAirtableAPI(table, 'POST', body);
            
            responseText = `Successfully created record in table "${table}":\n` +
              `Record ID: ${result.id}\n` +
              `Fields: ${JSON.stringify(result.fields, null, 2)}\n` +
              `Created at: ${result.createdTime}`;
          }
          
          // UPDATE RECORD
          else if (toolName === 'update_record') {
            const { table, recordId, fields } = toolParams;
            
            const body = {
              fields: fields
            };
            
            result = await callAirtableAPI(`${table}/${recordId}`, 'PATCH', body);
            
            responseText = `Successfully updated record ${recordId} in table "${table}":\n` +
              `Updated fields: ${JSON.stringify(result.fields, null, 2)}`;
          }
          
          // DELETE RECORD
          else if (toolName === 'delete_record') {
            const { table, recordId } = toolParams;
            
            result = await callAirtableAPI(`${table}/${recordId}`, 'DELETE');
            
            responseText = `Successfully deleted record ${recordId} from table "${table}".\n` +
              `Deleted record ID: ${result.id}\n` +
              `Deleted: ${result.deleted}`;
          }
          
          // SEARCH RECORDS
          else if (toolName === 'search_records') {
            const { table, filterByFormula, sort, maxRecords, fields } = toolParams;
            
            const queryParams = {};
            if (filterByFormula) queryParams.filterByFormula = filterByFormula;
            if (maxRecords) queryParams.maxRecords = maxRecords;
            if (fields && fields.length > 0) queryParams.fields = fields;
            if (sort && sort.length > 0) {
              sort.forEach((s, i) => {
                queryParams[`sort[${i}][field]`] = s.field;
                queryParams[`sort[${i}][direction]`] = s.direction || 'asc';
              });
            }
            
            result = await callAirtableAPI(table, 'GET', null, queryParams);
            const records = result.records || [];
            
            responseText = records.length > 0
              ? `Found ${records.length} matching record(s) in table "${table}":\n` + 
                records.map((record, i) => 
                  `${i+1}. ID: ${record.id}\n   Fields: ${JSON.stringify(record.fields, null, 2)}`
                ).join('\n\n')
              : `No records found matching the search criteria in table "${table}".`;
          }
          
          // LIST WEBHOOKS
          else if (toolName === 'list_webhooks') {
            result = await callAirtableAPI(`bases/${baseId}/webhooks`, 'GET');
            const webhooks = result.webhooks || [];
            
            responseText = webhooks.length > 0
              ? `Found ${webhooks.length} webhook(s):\n` + 
                webhooks.map((webhook, i) => 
                  `${i+1}. ID: ${webhook.id}\n` +
                  `   URL: ${webhook.notificationUrl}\n` +
                  `   Active: ${webhook.isHookEnabled}\n` +
                  `   Created: ${webhook.createdTime}\n` +
                  `   Expires: ${webhook.expirationTime}`
                ).join('\n\n')
              : 'No webhooks configured for this base.';
          }
          
          // CREATE WEBHOOK
          else if (toolName === 'create_webhook') {
            const { notificationUrl, specification } = toolParams;
            
            const body = {
              notificationUrl: notificationUrl,
              specification: specification || {
                options: {
                  filters: {
                    dataTypes: ['tableData']
                  }
                }
              }
            };
            
            result = await callAirtableAPI(`bases/${baseId}/webhooks`, 'POST', body);
            
            responseText = `Successfully created webhook:\n` +
              `Webhook ID: ${result.id}\n` +
              `URL: ${result.notificationUrl}\n` +
              `MAC Secret: ${result.macSecretBase64}\n` +
              `Expiration: ${result.expirationTime}\n` +
              `Cursor: ${result.cursorForNextPayload}\n\n` +
              `⚠️ IMPORTANT: Save the MAC secret - it won't be shown again!`;
          }
          
          // DELETE WEBHOOK
          else if (toolName === 'delete_webhook') {
            const { webhookId } = toolParams;
            
            await callAirtableAPI(`bases/${baseId}/webhooks/${webhookId}`, 'DELETE');
            
            responseText = `Successfully deleted webhook ${webhookId}`;
          }
          
          // GET WEBHOOK PAYLOADS
          else if (toolName === 'get_webhook_payloads') {
            const { webhookId, cursor } = toolParams;
            
            const queryParams = {};
            if (cursor) queryParams.cursor = cursor;
            
            result = await callAirtableAPI(`bases/${baseId}/webhooks/${webhookId}/payloads`, 'GET', null, queryParams);
            
            const payloads = result.payloads || [];
            responseText = payloads.length > 0
              ? `Found ${payloads.length} webhook payload(s):\n` + 
                payloads.map((payload, i) => 
                  `${i+1}. Timestamp: ${payload.timestamp}\n` +
                  `   Base/Table: ${payload.baseTransactionNumber}\n` +
                  `   Change Types: ${JSON.stringify(payload.changePayload?.changedTablesById || {})}`
                ).join('\n\n') +
                (result.cursor ? `\n\nNext cursor: ${result.cursor}` : '')
              : 'No payloads found for this webhook.';
          }
          
          // REFRESH WEBHOOK
          else if (toolName === 'refresh_webhook') {
            const { webhookId } = toolParams;
            
            result = await callAirtableAPI(`bases/${baseId}/webhooks/${webhookId}/refresh`, 'POST');
            
            responseText = `Successfully refreshed webhook ${webhookId}:\n` +
              `New expiration: ${result.expirationTime}`;
          }
          
          // Schema Management Tools
          else if (toolName === 'list_bases') {
            const { offset } = toolParams;
            const queryParams = offset ? { offset } : {};
            
            result = await callAirtableAPI('meta/bases', 'GET', null, queryParams);
            
            if (result.bases && result.bases.length > 0) {
              responseText = `Found ${result.bases.length} accessible base(s):\n`;
              result.bases.forEach((base, index) => {
                responseText += `${index + 1}. ${base.name} (ID: ${base.id})\n`;
                if (base.permissionLevel) {
                  responseText += `   Permission: ${base.permissionLevel}\n`;
                }
              });
              if (result.offset) {
                responseText += `\nNext page offset: ${result.offset}`;
              }
            } else {
              responseText = 'No accessible bases found.';
            }
          }
          
          else if (toolName === 'get_base_schema') {
            const { baseId: targetBaseId } = toolParams;
            const targetId = targetBaseId || baseId;
            
            result = await callAirtableAPI(`meta/bases/${targetId}/tables`, 'GET');
            
            if (result.tables && result.tables.length > 0) {
              responseText = `Base schema for ${targetId}:\n\n`;
              result.tables.forEach((table, index) => {
                responseText += `${index + 1}. Table: ${table.name} (ID: ${table.id})\n`;
                if (table.description) {
                  responseText += `   Description: ${table.description}\n`;
                }
                responseText += `   Fields (${table.fields.length}):\n`;
                table.fields.forEach((field, fieldIndex) => {
                  responseText += `   ${fieldIndex + 1}. ${field.name} (${field.type})\n`;
                  if (field.description) {
                    responseText += `      Description: ${field.description}\n`;
                  }
                });
                if (table.views && table.views.length > 0) {
                  responseText += `   Views (${table.views.length}): ${table.views.map(v => v.name).join(', ')}\n`;
                }
                responseText += '\n';
              });
            } else {
              responseText = 'No tables found in this base.';
            }
          }
          
          else if (toolName === 'describe_table') {
            const { table } = toolParams;
            
            // Get table schema first
            const schemaResult = await callAirtableAPI(`meta/bases/${baseId}/tables`, 'GET');
            const tableInfo = schemaResult.tables.find(t => 
              t.name.toLowerCase() === table.toLowerCase() || t.id === table
            );
            
            if (!tableInfo) {
              responseText = `Table "${table}" not found.`;
            } else {
              responseText = `Table Details: ${tableInfo.name}\n`;
              responseText += `ID: ${tableInfo.id}\n`;
              if (tableInfo.description) {
                responseText += `Description: ${tableInfo.description}\n`;
              }
              responseText += `\nFields (${tableInfo.fields.length}):\n`;
              
              tableInfo.fields.forEach((field, index) => {
                responseText += `${index + 1}. ${field.name}\n`;
                responseText += `   Type: ${field.type}\n`;
                responseText += `   ID: ${field.id}\n`;
                if (field.description) {
                  responseText += `   Description: ${field.description}\n`;
                }
                if (field.options) {
                  responseText += `   Options: ${JSON.stringify(field.options, null, 2)}\n`;
                }
                responseText += '\n';
              });
              
              if (tableInfo.views && tableInfo.views.length > 0) {
                responseText += `Views (${tableInfo.views.length}):\n`;
                tableInfo.views.forEach((view, index) => {
                  responseText += `${index + 1}. ${view.name} (${view.type})\n`;
                });
              }
            }
          }
          
          else if (toolName === 'create_table') {
            const { name, description, fields } = toolParams;
            
            const body = {
              name,
              fields: fields.map(field => ({
                name: field.name,
                type: field.type,
                description: field.description,
                options: field.options
              }))
            };
            
            if (description) {
              body.description = description;
            }
            
            result = await callAirtableAPI(`meta/bases/${baseId}/tables`, 'POST', body);
            
            responseText = `Successfully created table "${name}" (ID: ${result.id})\n`;
            responseText += `Fields created: ${result.fields.length}\n`;
            result.fields.forEach((field, index) => {
              responseText += `${index + 1}. ${field.name} (${field.type})\n`;
            });
          }
          
          else if (toolName === 'update_table') {
            const { table, name, description } = toolParams;
            
            // Get table ID first
            const schemaResult = await callAirtableAPI(`meta/bases/${baseId}/tables`, 'GET');
            const tableInfo = schemaResult.tables.find(t => 
              t.name.toLowerCase() === table.toLowerCase() || t.id === table
            );
            
            if (!tableInfo) {
              responseText = `Table "${table}" not found.`;
            } else {
              const body = {};
              if (name) body.name = name;
              if (description !== undefined) body.description = description;
              
              if (Object.keys(body).length === 0) {
                responseText = 'No updates specified. Provide name or description to update.';
              } else {
                result = await callAirtableAPI(`meta/bases/${baseId}/tables/${tableInfo.id}`, 'PATCH', body);
                responseText = `Successfully updated table "${tableInfo.name}":\n`;
                if (name) responseText += `New name: ${result.name}\n`;
                if (description !== undefined) responseText += `New description: ${result.description || '(none)'}\n`;
              }
            }
          }
          
          else if (toolName === 'delete_table') {
            const { table, confirm } = toolParams;
            
            if (!confirm) {
              responseText = 'Table deletion requires confirm=true to proceed. This action cannot be undone!';
            } else {
              // Get table ID first
              const schemaResult = await callAirtableAPI(`meta/bases/${baseId}/tables`, 'GET');
              const tableInfo = schemaResult.tables.find(t => 
                t.name.toLowerCase() === table.toLowerCase() || t.id === table
              );
              
              if (!tableInfo) {
                responseText = `Table "${table}" not found.`;
              } else {
                result = await callAirtableAPI(`meta/bases/${baseId}/tables/${tableInfo.id}`, 'DELETE');
                responseText = `Successfully deleted table "${tableInfo.name}" (ID: ${tableInfo.id})\n`;
                responseText += 'All data in this table has been permanently removed.';
              }
            }
          }
          
          // Field Management Tools
          else if (toolName === 'create_field') {
            const { table, name, type, description, options } = toolParams;
            
            // Get table ID first
            const schemaResult = await callAirtableAPI(`meta/bases/${baseId}/tables`, 'GET');
            const tableInfo = schemaResult.tables.find(t => 
              t.name.toLowerCase() === table.toLowerCase() || t.id === table
            );
            
            if (!tableInfo) {
              responseText = `Table "${table}" not found.`;
            } else {
              const body = {
                name,
                type
              };
              
              if (description) body.description = description;
              if (options) body.options = options;
              
              result = await callAirtableAPI(`meta/bases/${baseId}/tables/${tableInfo.id}/fields`, 'POST', body);
              
              responseText = `Successfully created field "${name}" in table "${tableInfo.name}"\n`;
              responseText += `Field ID: ${result.id}\n`;
              responseText += `Type: ${result.type}\n`;
              if (result.description) {
                responseText += `Description: ${result.description}\n`;
              }
            }
          }
          
          else if (toolName === 'update_field') {
            const { table, fieldId, name, description, options } = toolParams;
            
            // Get table ID first
            const schemaResult = await callAirtableAPI(`meta/bases/${baseId}/tables`, 'GET');
            const tableInfo = schemaResult.tables.find(t => 
              t.name.toLowerCase() === table.toLowerCase() || t.id === table
            );
            
            if (!tableInfo) {
              responseText = `Table "${table}" not found.`;
            } else {
              const body = {};
              if (name) body.name = name;
              if (description !== undefined) body.description = description;
              if (options) body.options = options;
              
              if (Object.keys(body).length === 0) {
                responseText = 'No updates specified. Provide name, description, or options to update.';
              } else {
                result = await callAirtableAPI(`meta/bases/${baseId}/tables/${tableInfo.id}/fields/${fieldId}`, 'PATCH', body);
                responseText = `Successfully updated field in table "${tableInfo.name}":\n`;
                responseText += `Field: ${result.name} (${result.type})\n`;
                responseText += `ID: ${result.id}\n`;
                if (result.description) {
                  responseText += `Description: ${result.description}\n`;
                }
              }
            }
          }
          
          else if (toolName === 'delete_field') {
            const { table, fieldId, confirm } = toolParams;
            
            if (!confirm) {
              responseText = 'Field deletion requires confirm=true to proceed. This action cannot be undone!';
            } else {
              // Get table ID first
              const schemaResult = await callAirtableAPI(`meta/bases/${baseId}/tables`, 'GET');
              const tableInfo = schemaResult.tables.find(t => 
                t.name.toLowerCase() === table.toLowerCase() || t.id === table
              );
              
              if (!tableInfo) {
                responseText = `Table "${table}" not found.`;
              } else {
                result = await callAirtableAPI(`meta/bases/${baseId}/tables/${tableInfo.id}/fields/${fieldId}`, 'DELETE');
                responseText = `Successfully deleted field from table "${tableInfo.name}"\n`;
                responseText += 'All data in this field has been permanently removed.';
              }
            }
          }
          
          else if (toolName === 'list_field_types') {
            responseText = `Available Airtable Field Types:\n\n`;
            responseText += `Basic Fields:\n`;
            responseText += `• singleLineText - Single line text input\n`;
            responseText += `• multilineText - Multi-line text input\n`;
            responseText += `• richText - Rich text with formatting\n`;
            responseText += `• number - Number field with optional formatting\n`;
            responseText += `• percent - Percentage field\n`;
            responseText += `• currency - Currency field\n`;
            responseText += `• singleSelect - Single choice from predefined options\n`;
            responseText += `• multipleSelectionList - Multiple choices from predefined options\n`;
            responseText += `• date - Date field\n`;
            responseText += `• dateTime - Date and time field\n`;
            responseText += `• phoneNumber - Phone number field\n`;
            responseText += `• email - Email address field\n`;
            responseText += `• url - URL field\n`;
            responseText += `• checkbox - Checkbox (true/false)\n`;
            responseText += `• rating - Star rating field\n`;
            responseText += `• duration - Duration/time field\n\n`;
            responseText += `Advanced Fields:\n`;
            responseText += `• multipleAttachment - File attachments\n`;
            responseText += `• linkedRecord - Link to records in another table\n`;
            responseText += `• lookup - Lookup values from linked records\n`;
            responseText += `• rollup - Calculate values from linked records\n`;
            responseText += `• count - Count of linked records\n`;
            responseText += `• formula - Calculated field with formulas\n`;
            responseText += `• createdTime - Auto-timestamp when record created\n`;
            responseText += `• createdBy - Auto-user who created record\n`;
            responseText += `• lastModifiedTime - Auto-timestamp when record modified\n`;
            responseText += `• lastModifiedBy - Auto-user who last modified record\n`;
            responseText += `• autoNumber - Auto-incrementing number\n`;
            responseText += `• barcode - Barcode/QR code field\n`;
            responseText += `• button - Action button field\n`;
          }
          
          else if (toolName === 'get_table_views') {
            const { table } = toolParams;
            
            // Get table schema
            const schemaResult = await callAirtableAPI(`meta/bases/${baseId}/tables`, 'GET');
            const tableInfo = schemaResult.tables.find(t => 
              t.name.toLowerCase() === table.toLowerCase() || t.id === table
            );
            
            if (!tableInfo) {
              responseText = `Table "${table}" not found.`;
            } else {
              if (tableInfo.views && tableInfo.views.length > 0) {
                responseText = `Views for table "${tableInfo.name}" (${tableInfo.views.length}):\n\n`;
                tableInfo.views.forEach((view, index) => {
                  responseText += `${index + 1}. ${view.name}\n`;
                  responseText += `   Type: ${view.type}\n`;
                  responseText += `   ID: ${view.id}\n`;
                  if (view.visibleFieldIds && view.visibleFieldIds.length > 0) {
                    responseText += `   Visible fields: ${view.visibleFieldIds.length}\n`;
                  }
                  responseText += '\n';
                });
              } else {
                responseText = `No views found for table "${tableInfo.name}".`;
              }
            }
          }
          
          // NEW v1.6.0 TOOLS - Attachment and Batch Operations
          else if (toolName === 'upload_attachment') {
            const { table, recordId, fieldName, url, filename } = toolParams;
            
            const attachment = { url };
            if (filename) attachment.filename = filename;
            
            const updateBody = {
              fields: {
                [fieldName]: [attachment]
              }
            };
            
            result = await callAirtableAPI(`${table}/${recordId}`, 'PATCH', updateBody);
            
            responseText = `Successfully attached file to record ${recordId}:\n`;
            responseText += `Field: ${fieldName}\n`;
            responseText += `URL: ${url}\n`;
            if (filename) responseText += `Filename: ${filename}\n`;
          }
          
          else if (toolName === 'batch_create_records') {
            const { table, records } = toolParams;
            
            if (records.length > 10) {
              responseText = 'Error: Cannot create more than 10 records at once. Please split into smaller batches.';
            } else {
              const body = { records };
              result = await callAirtableAPI(table, 'POST', body);
              
              responseText = `Successfully created ${result.records.length} records:\n`;
              result.records.forEach((record, index) => {
                responseText += `${index + 1}. ID: ${record.id}\n`;
                const fields = Object.keys(record.fields);
                if (fields.length > 0) {
                  responseText += `   Fields: ${fields.join(', ')}\n`;
                }
              });
            }
          }
          
          else if (toolName === 'batch_update_records') {
            const { table, records } = toolParams;
            
            if (records.length > 10) {
              responseText = 'Error: Cannot update more than 10 records at once. Please split into smaller batches.';
            } else {
              const body = { records };
              result = await callAirtableAPI(table, 'PATCH', body);
              
              responseText = `Successfully updated ${result.records.length} records:\n`;
              result.records.forEach((record, index) => {
                responseText += `${index + 1}. ID: ${record.id}\n`;
                const fields = Object.keys(record.fields);
                if (fields.length > 0) {
                  responseText += `   Updated fields: ${fields.join(', ')}\n`;
                }
              });
            }
          }
          
          else if (toolName === 'batch_delete_records') {
            const { table, recordIds } = toolParams;
            
            if (recordIds.length > 10) {
              responseText = 'Error: Cannot delete more than 10 records at once. Please split into smaller batches.';
            } else {
              const queryParams = { records: recordIds };
              result = await callAirtableAPI(table, 'DELETE', null, queryParams);
              
              responseText = `Successfully deleted ${result.records.length} records:\n`;
              result.records.forEach((record, index) => {
                responseText += `${index + 1}. Deleted ID: ${record.id}\n`;
              });
            }
          }
          
          else if (toolName === 'batch_upsert_records') {
            const { table, records, keyFields } = toolParams;
            
            if (records.length > 10) {
              responseText = 'Error: Cannot upsert more than 10 records at once. Please split into smaller batches.';
            } else {
              // For simplicity, we'll implement this as a batch create with merge fields
              // Note: Real upsert requires checking existing records first
              const body = {
                records,
                performUpsert: {
                  fieldsToMergeOn: keyFields
                }
              };
              
              result = await callAirtableAPI(table, 'PATCH', body);
              
              responseText = `Successfully upserted ${result.records.length} records:\n`;
              result.records.forEach((record, index) => {
                responseText += `${index + 1}. ID: ${record.id}\n`;
                const fields = Object.keys(record.fields);
                if (fields.length > 0) {
                  responseText += `   Fields: ${fields.join(', ')}\n`;
                }
              });
            }
          }
          
          // NEW v1.6.0 TOOLS - Advanced View Management
          else if (toolName === 'create_view') {
            const { table, name, type, visibleFieldIds, fieldOrder } = toolParams;
            
            // Get table ID first
            const schemaResult = await callAirtableAPI(`meta/bases/${baseId}/tables`, 'GET');
            const tableInfo = schemaResult.tables.find(t => 
              t.name.toLowerCase() === table.toLowerCase() || t.id === table
            );
            
            if (!tableInfo) {
              responseText = `Table "${table}" not found.`;
            } else {
              const body = {
                name,
                type
              };
              
              if (visibleFieldIds) body.visibleFieldIds = visibleFieldIds;
              if (fieldOrder) body.fieldOrder = fieldOrder;
              
              result = await callAirtableAPI(`meta/bases/${baseId}/tables/${tableInfo.id}/views`, 'POST', body);
              
              responseText = `Successfully created view "${name}" in table "${tableInfo.name}":\n`;
              responseText += `View ID: ${result.id}\n`;
              responseText += `Type: ${result.type}\n`;
              if (result.visibleFieldIds && result.visibleFieldIds.length > 0) {
                responseText += `Visible fields: ${result.visibleFieldIds.length}\n`;
              }
            }
          }
          
          else if (toolName === 'get_view_metadata') {
            const { table, viewId } = toolParams;
            
            // Get table ID first
            const schemaResult = await callAirtableAPI(`meta/bases/${baseId}/tables`, 'GET');
            const tableInfo = schemaResult.tables.find(t => 
              t.name.toLowerCase() === table.toLowerCase() || t.id === table
            );
            
            if (!tableInfo) {
              responseText = `Table "${table}" not found.`;
            } else {
              result = await callAirtableAPI(`meta/bases/${baseId}/tables/${tableInfo.id}/views/${viewId}`, 'GET');
              
              responseText = `View Metadata: ${result.name}\n`;
              responseText += `ID: ${result.id}\n`;
              responseText += `Type: ${result.type}\n`;
              
              if (result.visibleFieldIds && result.visibleFieldIds.length > 0) {
                responseText += `\nVisible Fields (${result.visibleFieldIds.length}):\n`;
                result.visibleFieldIds.forEach((fieldId, index) => {
                  responseText += `${index + 1}. ${fieldId}\n`;
                });
              }
              
              if (result.filterByFormula) {
                responseText += `\nFilter Formula: ${result.filterByFormula}\n`;
              }
              
              if (result.sorts && result.sorts.length > 0) {
                responseText += `\nSort Configuration:\n`;
                result.sorts.forEach((sort, index) => {
                  responseText += `${index + 1}. Field: ${sort.field}, Direction: ${sort.direction}\n`;
                });
              }
            }
          }
          
          // NEW v1.6.0 TOOLS - Base Management
          else if (toolName === 'create_base') {
            const { name, workspaceId, tables } = toolParams;
            
            const body = {
              name,
              tables: tables.map(table => ({
                name: table.name,
                description: table.description,
                fields: table.fields
              }))
            };
            
            if (workspaceId) {
              body.workspaceId = workspaceId;
            }
            
            result = await callAirtableAPI('meta/bases', 'POST', body);
            
            responseText = `Successfully created base "${name}":\n`;
            responseText += `Base ID: ${result.id}\n`;
            if (result.tables && result.tables.length > 0) {
              responseText += `\nTables created (${result.tables.length}):\n`;
              result.tables.forEach((table, index) => {
                responseText += `${index + 1}. ${table.name} (ID: ${table.id})\n`;
                if (table.fields && table.fields.length > 0) {
                  responseText += `   Fields: ${table.fields.length}\n`;
                }
              });
            }
          }
          
          else if (toolName === 'list_collaborators') {
            const { baseId: targetBaseId } = toolParams;
            const targetId = targetBaseId || baseId;
            
            result = await callAirtableAPI(`meta/bases/${targetId}/collaborators`, 'GET');
            
            if (result.collaborators && result.collaborators.length > 0) {
              responseText = `Base collaborators (${result.collaborators.length}):\n\n`;
              result.collaborators.forEach((collaborator, index) => {
                responseText += `${index + 1}. ${collaborator.email || collaborator.name || 'Unknown'}\n`;
                responseText += `   Permission: ${collaborator.permissionLevel || 'Unknown'}\n`;
                responseText += `   Type: ${collaborator.type || 'User'}\n`;
                if (collaborator.userId) {
                  responseText += `   User ID: ${collaborator.userId}\n`;
                }
                responseText += '\n';
              });
            } else {
              responseText = 'No collaborators found for this base.';
            }
          }
          
          else if (toolName === 'list_shares') {
            const { baseId: targetBaseId } = toolParams;
            const targetId = targetBaseId || baseId;
            
            result = await callAirtableAPI(`meta/bases/${targetId}/shares`, 'GET');
            
            if (result.shares && result.shares.length > 0) {
              responseText = `Shared views (${result.shares.length}):\n\n`;
              result.shares.forEach((share, index) => {
                responseText += `${index + 1}. ${share.name || 'Unnamed Share'}\n`;
                responseText += `   Share ID: ${share.id}\n`;
                responseText += `   URL: ${share.url}\n`;
                responseText += `   Type: ${share.type || 'View'}\n`;
                if (share.viewId) {
                  responseText += `   View ID: ${share.viewId}\n`;
                }
                if (share.tableId) {
                  responseText += `   Table ID: ${share.tableId}\n`;
                }
                responseText += `   Effective: ${share.effective ? 'Yes' : 'No'}\n`;
                responseText += '\n';
              });
            } else {
              responseText = 'No shared views found for this base.';
            }
          }
          
          else {
            throw new Error(`Unknown tool: ${toolName}`);
          }
          
          const response = {
            jsonrpc: '2.0',
            id: request.id,
            result: {
              content: [
                {
                  type: 'text',
                  text: responseText
                }
              ]
            }
          };
          res.writeHead(200, { 'Content-Type': 'application/json' });
          res.end(JSON.stringify(response));
          
        } catch (error) {
          log(LOG_LEVELS.ERROR, `Tool ${toolName} error:`, error.message);
          
          const response = {
            jsonrpc: '2.0',
            id: request.id,
            result: {
              content: [
                {
                  type: 'text',
                  text: `Error executing ${toolName}: ${error.message}`
                }
              ]
            }
          };
          res.writeHead(200, { 'Content-Type': 'application/json' });
          res.end(JSON.stringify(response));
        }
        
        return;
      }
      
      // Method not found
      const response = {
        jsonrpc: '2.0',
        id: request.id,
        error: {
          code: -32601,
          message: `Method ${request.method} not found`
        }
      };
      res.writeHead(200, { 'Content-Type': 'application/json' });
      res.end(JSON.stringify(response));
      
    } catch (error) {
      log(LOG_LEVELS.ERROR, 'Error processing request:', error);
      const response = {
        jsonrpc: '2.0',
        id: request.id || null,
        error: {
          code: -32000,
          message: error.message || 'Unknown error'
        }
      };
      res.writeHead(200, { 'Content-Type': 'application/json' });
      res.end(JSON.stringify(response));
    }
  });
});

// Start server
const PORT = process.env.PORT || 8010;
server.listen(PORT, () => {
  log(LOG_LEVELS.INFO, `Enhanced Airtable MCP server v1.4.0 running at http://localhost:${PORT}/mcp`);
  console.log(`For Claude, use this URL: http://localhost:${PORT}/mcp`);
});

// Graceful shutdown
process.on('SIGINT', () => {
  log(LOG_LEVELS.INFO, 'Shutting down server...');
  server.close(() => {
    log(LOG_LEVELS.INFO, 'Server stopped');
    process.exit(0);
  });
});
```
Page 3/4FirstPrevNextLast