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

```
├── .claude
│   └── settings.local.json
├── .github
│   └── workflows
│       ├── claude-code-review.yml
│       └── claude.yml
├── .gitignore
├── CLAUDE.md
├── example-claude-config.json
├── package.json
├── README.md
├── src
│   └── index.ts
└── tsconfig.json
```

# Files

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

```
# Dependencies
node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Build output
build/
*.js
*.js.map
*.d.ts
*.d.ts.map

# Keep TypeScript source files
!src/**/*.ts

# IDE files
.vscode/
.idea/
*.swp
*.swo
*~
.DS_Store

# Environment files
.env
.env.local
.env.development.local
.env.test.local
.env.production.local

# Logs
logs/
*.log

# Testing
coverage/
.nyc_output/

# Temporary files
tmp/
temp/
.cache/
temp_config.json

# Package manager files
package-lock.json
yarn.lock
pnpm-lock.yaml

```

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

```markdown
# gnomAD MCP Server

A Model Context Protocol (MCP) server that provides access to the gnomAD (Genome Aggregation Database) GraphQL API. This server enables AI assistants to query genetic variant data, gene constraints, and population genetics information from gnomAD.

## Features

- 🧬 **Gene Information**: Search and retrieve detailed gene data including constraint scores
- 🔬 **Variant Analysis**: Query specific variants and their population frequencies
- 📊 **Population Genetics**: Access allele frequencies across different populations
- 🧮 **Constraint Scores**: Get pLI, LOEUF, and other constraint metrics
- 🔍 **Region Queries**: Find variants within specific genomic regions
- 🧪 **Transcript Data**: Access transcript-specific information and constraints
- 📈 **Coverage Data**: Retrieve sequencing coverage statistics
- 🔄 **Structural Variants**: Query structural variant data
- 🧲 **Mitochondrial Variants**: Access mitochondrial genome variants

## Installation

### Prerequisites

- Node.js 18 or higher
- npm or yarn

### Install from source

```bash
git clone https://github.com/yourusername/gnomad-mcp-server.git
cd gnomad-mcp-server
npm install
npm run build
```

## Configuration

### Claude Desktop

Add to your Claude Desktop configuration file:

**macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
**Windows**: `%APPDATA%\Claude\claude_desktop_config.json`

```json
{
  "mcpServers": {
    "gnomad": {
      "command": "node",
      "args": ["/path/to/gnomad-mcp-server/dist/index.js"]
    }
  }
}
```

### With MCP CLI

```bash
npx @modelcontextprotocol/cli gnomad-mcp-server
```

## Available Tools

### 1. `search`
Search for genes, variants, or regions in gnomAD.

**Parameters:**
- `query` (required): Search query (gene symbol, gene ID, variant ID, rsID)
- `reference_genome`: Reference genome (GRCh37 or GRCh38, default: GRCh38)
- `dataset`: Dataset ID (gnomad_r4, gnomad_r3, gnomad_r2_1, etc., default: gnomad_r4)

**Example:**
```json
{
  "query": "TP53",
  "reference_genome": "GRCh38"
}
```

### 2. `get_gene`
Get detailed information about a gene including constraint scores.

**Parameters:**
- `gene_id`: Ensembl gene ID (e.g., ENSG00000141510)
- `gene_symbol`: Gene symbol (e.g., TP53)
- `reference_genome`: Reference genome (default: GRCh38)

**Example:**
```json
{
  "gene_symbol": "BRCA1",
  "reference_genome": "GRCh38"
}
```

### 3. `get_variant`
Get detailed information about a specific variant.

**Parameters:**
- `variant_id` (required): Variant ID in format: chr-pos-ref-alt (e
```

--------------------------------------------------------------------------------
/CLAUDE.md:
--------------------------------------------------------------------------------

```markdown
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

This is a gnomAD MCP (Model Context Protocol) server that provides access to the Genome Aggregation Database through the MCP protocol. The server allows LLMs and other tools to query genomic variant data from gnomAD.

## Development Commands

Note: This appears to be a new repository. Common commands will be added as the project develops.

## Architecture

This MCP server will likely follow the standard MCP server pattern:
- Server implementation handling MCP protocol messages
- Resource providers for gnomAD data access
- Tool handlers for genomic queries
- Configuration for database connections and API endpoints

## Key Considerations

- Handle genomic coordinates and variant identifiers carefully
- Ensure proper error handling for invalid genomic queries
- Consider rate limiting and caching for gnomAD API calls
- Follow genomic data standards (VCF, HGVS notation, etc.)
```

--------------------------------------------------------------------------------
/.claude/settings.local.json:
--------------------------------------------------------------------------------

```json
{
  "permissions": {
    "allow": [
      "WebFetch(domain:broadinstitute.github.io)",
      "WebFetch(domain:gnomad.broadinstitute.org)"
    ],
    "deny": [],
    "ask": []
  }
}
```

--------------------------------------------------------------------------------
/example-claude-config.json:
--------------------------------------------------------------------------------

```json
{
  "mcpServers": {
    "gnomad": {
      "command": "node",
      "args": ["/absolute/path/to/gnomad-mcp-server/dist/index.js"],
      "env": {}
    }
  },
  "_comment": "Replace /absolute/path/to/ with the actual path to your gnomad-mcp-server installation"
}
```

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

```json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "Node16",
    "moduleResolution": "Node16",
    "lib": ["ES2022"],
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true,
    "resolveJsonModule": true,
    "allowSyntheticDefaultImports": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist"]
}
```

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

```json
{
  "name": "gnomad-mcp-server",
  "version": "1.0.0",
  "description": "Model Context Protocol server for gnomAD (Genome Aggregation Database) GraphQL API",
  "main": "dist/index.js",
  "type": "module",
  "bin": {
    "gnomad-mcp-server": "./dist/index.js"
  },
  "scripts": {
    "build": "tsc",
    "start": "node dist/index.js",
    "dev": "tsx src/index.ts",
    "prepare": "npm run build"
  },
  "keywords": [
    "mcp",
    "gnomad",
    "genomics",
    "variants",
    "graphql",
    "bioinformatics"
  ],
  "author": "",
  "license": "MIT",
  "dependencies": {
    "@modelcontextprotocol/sdk": "^0.5.0",
    "node-fetch": "^3.3.2"
  },
  "devDependencies": {
    "@types/node": "^20.10.0",
    "tsx": "^4.7.0",
    "typescript": "^5.3.0"
  },
  "engines": {
    "node": ">=18.0.0"
  }
}
```

--------------------------------------------------------------------------------
/.github/workflows/claude.yml:
--------------------------------------------------------------------------------

```yaml
name: Claude Code

on:
  issue_comment:
    types: [created]
  pull_request_review_comment:
    types: [created]
  issues:
    types: [opened, assigned]
  pull_request_review:
    types: [submitted]

jobs:
  claude:
    if: |
      (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
      (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
      (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
      (github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
    runs-on: ubuntu-latest
    permissions:
      contents: read
      pull-requests: read
      issues: read
      id-token: write
      actions: read # Required for Claude to read CI results on PRs
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          fetch-depth: 1

      - name: Run Claude Code
        id: claude
        uses: anthropics/claude-code-action@beta
        with:
          claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}

          # This is an optional setting that allows Claude to read CI results on PRs
          additional_permissions: |
            actions: read
          
          # Optional: Specify model (defaults to Claude Sonnet 4, uncomment for Claude Opus 4.1)
          # model: "claude-opus-4-1-20250805"
          
          # Optional: Customize the trigger phrase (default: @claude)
          # trigger_phrase: "/claude"
          
          # Optional: Trigger when specific user is assigned to an issue
          # assignee_trigger: "claude-bot"
          
          # Optional: Allow Claude to run specific commands
          # allowed_tools: "Bash(npm install),Bash(npm run build),Bash(npm run test:*),Bash(npm run lint:*)"
          
          # Optional: Add custom instructions for Claude to customize its behavior for your project
          # custom_instructions: |
          #   Follow our coding standards
          #   Ensure all new code has tests
          #   Use TypeScript for new files
          
          # Optional: Custom environment variables for Claude
          # claude_env: |
          #   NODE_ENV: test


```

--------------------------------------------------------------------------------
/.github/workflows/claude-code-review.yml:
--------------------------------------------------------------------------------

```yaml
name: Claude Code Review

on:
  pull_request:
    types: [opened, synchronize]
    # Optional: Only run on specific file changes
    # paths:
    #   - "src/**/*.ts"
    #   - "src/**/*.tsx"
    #   - "src/**/*.js"
    #   - "src/**/*.jsx"

jobs:
  claude-review:
    # Optional: Filter by PR author
    # if: |
    #   github.event.pull_request.user.login == 'external-contributor' ||
    #   github.event.pull_request.user.login == 'new-developer' ||
    #   github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR'
    
    runs-on: ubuntu-latest
    permissions:
      contents: read
      pull-requests: read
      issues: read
      id-token: write
    
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          fetch-depth: 1

      - name: Run Claude Code Review
        id: claude-review
        uses: anthropics/claude-code-action@beta
        with:
          claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}

          # Optional: Specify model (defaults to Claude Sonnet 4, uncomment for Claude Opus 4.1)
          # model: "claude-opus-4-1-20250805"

          # Direct prompt for automated review (no @claude mention needed)
          direct_prompt: |
            Please review this pull request and provide feedback on:
            - Code quality and best practices
            - Potential bugs or issues
            - Performance considerations
            - Security concerns
            - Test coverage
            
            Be constructive and helpful in your feedback.

          # Optional: Use sticky comments to make Claude reuse the same comment on subsequent pushes to the same PR
          # use_sticky_comment: true
          
          # Optional: Customize review based on file types
          # direct_prompt: |
          #   Review this PR focusing on:
          #   - For TypeScript files: Type safety and proper interface usage
          #   - For API endpoints: Security, input validation, and error handling
          #   - For React components: Performance, accessibility, and best practices
          #   - For tests: Coverage, edge cases, and test quality
          
          # Optional: Different prompts for different authors
          # direct_prompt: |
          #   ${{ github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR' && 
          #   'Welcome! Please review this PR from a first-time contributor. Be encouraging and provide detailed explanations for any suggestions.' ||
          #   'Please provide a thorough code review focusing on our coding standards and best practices.' }}
          
          # Optional: Add specific tools for running tests or linting
          # allowed_tools: "Bash(npm run test),Bash(npm run lint),Bash(npm run typecheck)"
          
          # Optional: Skip review for certain conditions
          # if: |
          #   !contains(github.event.pull_request.title, '[skip-review]') &&
          #   !contains(github.event.pull_request.title, '[WIP]')


```

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

```typescript
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
  CallToolRequestSchema,
  ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import fetch, { Response } from "node-fetch";

// gnomAD GraphQL API endpoint
const GNOMAD_API_URL = "https://gnomad.broadinstitute.org/api";

// Type definitions for gnomAD responses
interface GnomadResponse {
  data?: any;
  errors?: Array<{
    message: string;
    extensions?: any;
  }>;
}

interface GeneConstraint {
  exp_lof: number;
  exp_mis: number;
  exp_syn: number;
  obs_lof: number;
  obs_mis: number;
  obs_syn: number;
  oe_lof: number;
  oe_lof_lower: number;
  oe_lof_upper: number;
  oe_mis: number;
  oe_mis_lower: number;
  oe_mis_upper: number;
  oe_syn: number;
  oe_syn_lower: number;
  oe_syn_upper: number;
  lof_z: number;
  mis_z: number;
  syn_z: number;
  pLI: number;
}

// Helper function to make GraphQL requests
async function makeGraphQLRequest(query: string, variables: Record<string, any> = {}): Promise<GnomadResponse> {
  const response: Response = await fetch(GNOMAD_API_URL, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      query,
      variables,
    }),
  });

  if (!response.ok) {
    throw new Error(`HTTP error! status: ${response.status}`);
  }

  return await response.json() as GnomadResponse;
}

// GraphQL query templates
const QUERIES = {
  searchGene: `
    query SearchGene($query: String!, $referenceGenome: ReferenceGenomeId!) {
      searchResults(query: $query, referenceGenome: $referenceGenome) {
        label
        value: url
      }
    }
  `,

  getGene: `
    query GetGene($geneId: String, $geneSymbol: String, $referenceGenome: ReferenceGenomeId!) {
      gene(gene_id: $geneId, gene_symbol: $geneSymbol, reference_genome: $referenceGenome) {
        gene_id
        symbol
        name
        canonical_transcript_id
        hgnc_id
        omim_id
        chrom
        start
        stop
        strand
        gnomad_constraint {
          exp_lof
          exp_mis
          exp_syn
          obs_lof
          obs_mis
          obs_syn
          oe_lof
          oe_lof_lower
          oe_lof_upper
          oe_mis
          oe_mis_lower
          oe_mis_upper
          oe_syn
          oe_syn_lower
          oe_syn_upper
          lof_z
          mis_z
          syn_z
          pLI
        }
        transcripts {
          transcript_id
          transcript_version
          reference_genome
        }
      }
    }
  `,

  getVariant: `
    query GetVariant($variantId: String!, $datasetId: DatasetId!) {
      variant(variantId: $variantId, dataset: $datasetId) {
        variant_id
        reference_genome
        chrom
        pos
        ref
        alt
        rsids
        caid
        colocated_variants
        multi_nucleotide_variants {
          combined_variant_id
          changes_amino_acids
          n_individuals
          other_constituent_snvs
        }
        exome {
          ac
          an
          ac_hemi
          ac_hom
          faf95 {
            popmax
            popmax_population
          }
          filters
          populations {
            id
            ac
            an
            ac_hemi
            ac_hom
          }
        }
        genome {
          ac
          an
          ac_hemi
          ac_hom
          faf95 {
            popmax
            popmax_population
          }
          filters
          populations {
            id
            ac
            an
            ac_hemi
            ac_hom
          }
        }
        transcript_consequences {
          gene_id
          gene_symbol
          transcript_id
          consequence_terms
          is_canonical
          major_consequence
          polyphen_prediction
          sift_prediction
          lof
          lof_filter
          lof_flags
        }
      }
    }
  `,

  getVariantsInGene: `
    query GetVariantsInGene($geneId: String, $geneSymbol: String, $datasetId: DatasetId!, $referenceGenome: ReferenceGenomeId!) {
      gene(gene_id: $geneId, gene_symbol: $geneSymbol, reference_genome: $referenceGenome) {
        variants(dataset: $datasetId) {
          variant_id
          pos
          rsids
          consequence
          hgvsc
          hgvsp
          lof
          exome {
            ac
            an
            af
            filters
          }
          genome {
            ac
            an
            af
            filters
          }
        }
      }
    }
  `,

  getTranscript: `
    query GetTranscript($transcriptId: String!, $referenceGenome: ReferenceGenomeId!) {
      transcript(transcript_id: $transcriptId, reference_genome: $referenceGenome) {
        transcript_id
        transcript_version
        reference_genome
        chrom
        start
        stop
        strand
        gene_id
        gene_symbol
        gene_version
        gnomad_constraint {
          exp_lof
          exp_mis
          exp_syn
          obs_lof
          obs_mis
          obs_syn
          oe_lof
          oe_lof_lower
          oe_lof_upper
          oe_mis
          oe_mis_lower
          oe_mis_upper
          oe_syn
          oe_syn_lower
          oe_syn_upper
          lof_z
          mis_z
          syn_z
          pLI
        }
      }
    }
  `,

  getRegionVariants: `
    query GetRegionVariants($chrom: String!, $start: Int!, $stop: Int!, $datasetId: DatasetId!, $referenceGenome: ReferenceGenomeId!) {
      region(chrom: $chrom, start: $start, stop: $stop, reference_genome: $referenceGenome) {
        variants(dataset: $datasetId) {
          variant_id
          pos
          rsids
          consequence
          hgvsc
          hgvsp
          lof
          exome {
            ac
            an
            af
            filters
          }
          genome {
            ac
            an
            af
            filters
          }
        }
      }
    }
  `,

  getCoverage: `
    query GetCoverage($geneId: String, $geneSymbol: String, $datasetId: DatasetId!, $referenceGenome: ReferenceGenomeId!) {
      gene(gene_id: $geneId, gene_symbol: $geneSymbol, reference_genome: $referenceGenome) {
        coverage(dataset: $datasetId) {
          exome {
            pos
            mean
            median
            over_1
            over_5
            over_10
            over_15
            over_20
            over_25
            over_30
            over_50
            over_100
          }
          genome {
            pos
            mean
            median
            over_1
            over_5
            over_10
            over_15
            over_20
            over_25
            over_30
            over_50
            over_100
          }
        }
      }
    }
  `,

  getStructuralVariants: `
    query GetStructuralVariants($chrom: String!, $start: Int!, $stop: Int!, $datasetId: DatasetId!, $referenceGenome: ReferenceGenomeId!) {
      region(chrom: $chrom, start: $start, stop: $stop, reference_genome: $referenceGenome) {
        structural_variants(dataset: $datasetId) {
          variant_id
          chrom
          pos
          end
          length
          type
          alts
          ac
          an
          af
          homozygote_count
          hemizygote_count
          filters
        }
      }
    }
  `,

  getMitochondrialVariants: `
    query GetMitochondrialVariants($datasetId: DatasetId!) {
      mitochondrial_variants(dataset: $datasetId) {
        variant_id
        pos
        ref
        alt
        rsids
        ac_het
        ac_hom
        an
        af_het
        af_hom
        max_heteroplasmy
        filters
      }
    }
  `,

  searchVariant: `
    query SearchVariant($query: String!, $datasetId: DatasetId!, $referenceGenome: ReferenceGenomeId!) {
      searchResults(query: $query, referenceGenome: $referenceGenome, dataset: $datasetId) {
        label
        value: url
      }
    }
  `
};

// Create the MCP server
const server = new Server(
  {
    name: "gnomad-mcp-server",
    version: "1.0.0",
  },
  {
    capabilities: {
      tools: {},
    },
  }
);

// Helper function to validate and parse dataset ID
function parseDatasetId(dataset: string): string {
  const validDatasets = [
    "gnomad_r2_1",
    "gnomad_r3",
    "gnomad_r4",
    "gnomad_sv_r2_1",
    "gnomad_sv_r4",
    "gnomad_cnv_r4",
    "exac",
  ];
  
  const datasetLower = dataset.toLowerCase();
  if (!validDatasets.includes(datasetLower)) {
    return "gnomad_r4"; // Default to latest version
  }
  return datasetLower;
}

// Helper function to validate reference genome
function parseReferenceGenome(genome: string): string {
  const validGenomes = ["GRCh37", "GRCh38"];
  if (!validGenomes.includes(genome)) {
    return "GRCh38"; // Default to GRCh38
  }
  return genome;
}

// Register tool handlers
server.setRequestHandler(ListToolsRequestSchema, async () => {
  return {
    tools: [
      {
        name: "search",
        description: "Search for genes, variants, or regions in gnomAD",
        inputSchema: {
          type: "object",
          properties: {
            query: {
              type: "string",
              description: "Search query (gene symbol, gene ID, variant ID, rsID, etc.)",
            },
            reference_genome: {
              type: "string",
              description: "Reference genome (GRCh37 or GRCh38)",
              default: "GRCh38",
            },
            dataset: {
              type: "string",
              description: "Dataset ID (gnomad_r4, gnomad_r3, gnomad_r2_1, etc.)",
              default: "gnomad_r4",
            },
          },
          required: ["query"],
        },
      },
      {
        name: "get_gene",
        description: "Get detailed information about a gene including constraint scores",
        inputSchema: {
          type: "object",
          properties: {
            gene_id: {
              type: "string",
              description: "Ensembl gene ID (e.g., ENSG00000141510)",
            },
            gene_symbol: {
              type: "string",
              description: "Gene symbol (e.g., TP53)",
            },
            reference_genome: {
              type: "string",
              description: "Reference genome (GRCh37 or GRCh38)",
              default: "GRCh38",
            },
          },
        },
      },
      {
        name: "get_variant",
        description: "Get detailed information about a specific variant",
        inputSchema: {
          type: "object",
          properties: {
            variant_id: {
              type: "string",
              description: "Variant ID in format: chr-pos-ref-alt (e.g., 1-55516888-G-A)",
            },
            dataset: {
              type: "string",
              description: "Dataset ID (gnomad_r4, gnomad_r3, gnomad_r2_1, etc.)",
              default: "gnomad_r4",
            },
          },
          required: ["variant_id"],
        },
      },
      {
        name: "get_variants_in_gene",
        description: "Get all variants in a specific gene",
        inputSchema: {
          type: "object",
          properties: {
            gene_id: {
              type: "string",
              description: "Ensembl gene ID",
            },
            gene_symbol: {
              type: "string",
              description: "Gene symbol",
            },
            dataset: {
              type: "string",
              description: "Dataset ID",
              default: "gnomad_r4",
            },
            reference_genome: {
              type: "string",
              description: "Reference genome",
              default: "GRCh38",
            },
          },
        },
      },
      {
        name: "get_transcript",
        description: "Get information about a specific transcript",
        inputSchema: {
          type: "object",
          properties: {
            transcript_id: {
              type: "string",
              description: "Ensembl transcript ID (e.g., ENST00000269305)",
            },
            reference_genome: {
              type: "string",
              description: "Reference genome",
              default: "GRCh38",
            },
          },
          required: ["transcript_id"],
        },
      },
      {
        name: "get_region_variants",
        description: "Get variants in a specific genomic region",
        inputSchema: {
          type: "object",
          properties: {
            chrom: {
              type: "string",
              description: "Chromosome (1-22, X, Y)",
            },
            start: {
              type: "number",
              description: "Start position",
            },
            stop: {
              type: "number",
              description: "Stop position",
            },
            dataset: {
              type: "string",
              description: "Dataset ID",
              default: "gnomad_r4",
            },
            reference_genome: {
              type: "string",
              description: "Reference genome",
              default: "GRCh38",
            },
          },
          required: ["chrom", "start", "stop"],
        },
      },
      {
        name: "get_coverage",
        description: "Get coverage information for a gene",
        inputSchema: {
          type: "object",
          properties: {
            gene_id: {
              type: "string",
              description: "Ensembl gene ID",
            },
            gene_symbol: {
              type: "string",
              description: "Gene symbol",
            },
            dataset: {
              type: "string",
              description: "Dataset ID",
              default: "gnomad_r4",
            },
            reference_genome: {
              type: "string",
              description: "Reference genome",
              default: "GRCh38",
            },
          },
        },
      },
      {
        name: "get_structural_variants",
        description: "Get structural variants in a genomic region",
        inputSchema: {
          type: "object",
          properties: {
            chrom: {
              type: "string",
              description: "Chromosome",
            },
            start: {
              type: "number",
              description: "Start position",
            },
            stop: {
              type: "number",
              description: "Stop position",
            },
            dataset: {
              type: "string",
              description: "Dataset ID (gnomad_sv_r4, gnomad_sv_r2_1)",
              default: "gnomad_sv_r4",
            },
            reference_genome: {
              type: "string",
              description: "Reference genome",
              default: "GRCh38",
            },
          },
          required: ["chrom", "start", "stop"],
        },
      },
      {
        name: "get_mitochondrial_variants",
        description: "Get mitochondrial variants",
        inputSchema: {
          type: "object",
          properties: {
            dataset: {
              type: "string",
              description: "Dataset ID",
              default: "gnomad_r3",
            },
          },
        },
      },
    ],
  };
});

server.setRequestHandler(CallToolRequestSchema, async (request) => {
  const { name, arguments: args } = request.params;
  
  // Type guard for arguments
  if (!args || typeof args !== 'object') {
    throw new Error("Invalid arguments provided");
  }

  try {
    let result: GnomadResponse;
    let formattedResult: any;

    switch (name) {
      case "search":
        result = await makeGraphQLRequest(QUERIES.searchGene, {
          query: args.query as string,
          referenceGenome: parseReferenceGenome((args.reference_genome as string) || "GRCh38"),
        });
        formattedResult = result.data?.searchResults || [];
        break;

      case "get_gene":
        if (!args.gene_id && !args.gene_symbol) {
          throw new Error("Either gene_id or gene_symbol must be provided");
        }
        result = await makeGraphQLRequest(QUERIES.getGene, {
          geneId: (args.gene_id as string) || null,
          geneSymbol: (args.gene_symbol as string) || null,
          referenceGenome: parseReferenceGenome((args.reference_genome as string) || "GRCh38"),
        });
        formattedResult = result.data?.gene || null;
        break;

      case "get_variant":
        result = await makeGraphQLRequest(QUERIES.getVariant, {
          variantId: args.variant_id as string,
          datasetId: parseDatasetId((args.dataset as string) || "gnomad_r4"),
        });
        formattedResult = result.data?.variant || null;
        break;

      case "get_variants_in_gene":
        if (!args.gene_id && !args.gene_symbol) {
          throw new Error("Either gene_id or gene_symbol must be provided");
        }
        result = await makeGraphQLRequest(QUERIES.getVariantsInGene, {
          geneId: (args.gene_id as string) || null,
          geneSymbol: (args.gene_symbol as string) || null,
          datasetId: parseDatasetId((args.dataset as string) || "gnomad_r4"),
          referenceGenome: parseReferenceGenome((args.reference_genome as string) || "GRCh38"),
        });
        formattedResult = result.data?.gene?.variants || [];
        break;

      case "get_transcript":
        result = await makeGraphQLRequest(QUERIES.getTranscript, {
          transcriptId: args.transcript_id as string,
          referenceGenome: parseReferenceGenome((args.reference_genome as string) || "GRCh38"),
        });
        formattedResult = result.data?.transcript || null;
        break;

      case "get_region_variants":
        result = await makeGraphQLRequest(QUERIES.getRegionVariants, {
          chrom: String(args.chrom),
          start: parseInt(String(args.start)),
          stop: parseInt(String(args.stop)),
          datasetId: parseDatasetId((args.dataset as string) || "gnomad_r4"),
          referenceGenome: parseReferenceGenome((args.reference_genome as string) || "GRCh38"),
        });
        formattedResult = result.data?.region?.variants || [];
        break;

      case "get_coverage":
        if (!args.gene_id && !args.gene_symbol) {
          throw new Error("Either gene_id or gene_symbol must be provided");
        }
        result = await makeGraphQLRequest(QUERIES.getCoverage, {
          geneId: (args.gene_id as string) || null,
          geneSymbol: (args.gene_symbol as string) || null,
          datasetId: parseDatasetId((args.dataset as string) || "gnomad_r4"),
          referenceGenome: parseReferenceGenome((args.reference_genome as string) || "GRCh38"),
        });
        formattedResult = result.data?.gene?.coverage || null;
        break;

      case "get_structural_variants":
        result = await makeGraphQLRequest(QUERIES.getStructuralVariants, {
          chrom: String(args.chrom),
          start: parseInt(String(args.start)),
          stop: parseInt(String(args.stop)),
          datasetId: parseDatasetId((args.dataset as string) || "gnomad_sv_r4"),
          referenceGenome: parseReferenceGenome((args.reference_genome as string) || "GRCh38"),
        });
        formattedResult = result.data?.region?.structural_variants || [];
        break;

      case "get_mitochondrial_variants":
        result = await makeGraphQLRequest(QUERIES.getMitochondrialVariants, {
          datasetId: parseDatasetId((args.dataset as string) || "gnomad_r3"),
        });
        formattedResult = result.data?.mitochondrial_variants || [];
        break;

      default:
        throw new Error(`Unknown tool: ${name}`);
    }

    // Check for GraphQL errors
    if (result.errors && result.errors.length > 0) {
      const errorMessages = result.errors.map(e => e.message).join("; ");
      throw new Error(`GraphQL errors: ${errorMessages}`);
    }

    return {
      content: [
        {
          type: "text",
          text: JSON.stringify(formattedResult, null, 2),
        },
      ],
    };
  } catch (error) {
    const errorMessage = error instanceof Error ? error.message : String(error);
    return {
      content: [
        {
          type: "text",
          text: `Error: ${errorMessage}`,
        },
      ],
    };
  }
});

// Start the server
async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
  console.error("gnomAD MCP server started");
}

main().catch((error) => {
  console.error("Fatal error:", error);
  process.exit(1);
});
```