Terra.Bio工作区管理工作流MCP服务

这是一个模型上下文协议(MCP)服务,通过FISS API让Claude能够发现、监控并管理Terra.Bio工作区中的工作流、数据表和GCS存储对象,适用于WDL流水线开发、回归测试与任务监控等生物信息学场景。

  • by broadinstitute
  • Python
  • 本地部署
  • 6 星标
  • 更新于
在 GitHub 查看 broadinstitute/fiss-mcp

使用说明

Terra.Bio MCP Server

A Model Context Protocol (MCP) server that enables Claude and Claude Code to interact with Terra.Bio workspaces via the FISS (Firecloud) API.

Table of Contents

Available Tools

This MCP server provides 21 tools for interacting with Terra.Bio workspaces:

Read-Only Tools (Always Available)

These tools are available in both read-only mode (default) and when write access is enabled:

Workspace & Data Discovery

  • list_workspaces - List Terra workspaces accessible to the authenticated user, filtered by name_contains / namespace and capped by limit (default 100)
  • get_workspace_metadata - Get workspace metadata and attributes for dashboard documentation (description, bucket, Google project, access level, authorization domain, timestamps)
  • get_workspace_data_tables - List data tables (entity types) in a workspace with row counts and column names
  • get_entities - Read rows from a Terra data table: entity_name for an exact single-row lookup, or a page with column selection (columns), paging (page, page_size) and text filtering (filter_terms), under a response-size guard (max_response_bytes) that refuses an oversized page instead of returning it

Workflow Monitoring & Status

  • list_submissions - List all workflow submissions in a workspace with status and metadata
  • get_submission_status - Get detailed status of workflow submissions (supports customizable workflow limits)
  • get_job_metadata - Get Cromwell metadata for specific workflows with optional filtering
  • get_workflow_logs - Get workflow logs with optional GCS content fetching and smart truncation
  • get_workflow_outputs - Get output files and values from completed workflows
  • get_workflow_cost - Get cost information for workflow executions
  • get_batch_job_status - Debug infrastructure failures (docker pull errors, preemption, OOM) via Google Batch API

Workflow Configuration (Read-Only)

  • get_method_config - Get method configuration details including WDL version and input/output mappings

GCS Bucket Access (Read-Only)

Read-only inspection of Google Cloud Storage buckets that supply Terra workflow inputs and hold workflow outputs. Uses the same Google Application Default Credentials (ADC) as the FISS API.

  • list_gcs_objects - List objects in a GCS bucket or under a prefix (supports recursive or ls-style listing)
  • get_gcs_object_metadata - Get size, content type, hashes, and timestamps for a GCS object (no content download)
  • read_gcs_object - Read a portion of a GCS object inline (100 KB default cap, configurable offset, text returned as UTF-8 or binary as base64)
  • download_gcs_file - Stream a complete GCS file to local disk (with overwrite, disk-free, and size-verification safety checks)

Write-Access Tools (Require --allow-writes Flag)

⚠️ These tools require write access to be enabled. By default, the server runs in read-only mode for safety. To use these tools, you must start the server with the --allow-writes flag (see integration sections below).

Workflow Configuration Management

  • update_method_config - Update method configuration (e.g., change WDL version to match development branch)
  • copy_method_config - Create copies of method configurations for testing or development

Workflow Execution Control

  • submit_workflow - Launch WDL workflows for single entities or batch processing
  • abort_submission - Cancel running workflow submissions

Data Management

  • upload_entities - Upsert entity data in Terra data tables: creates rows that don't exist yet, updates those that do, and supports entity references and entity-reference lists (e.g. linking a participant to its pairs)

Skills (Procedural Workflows)

This MCP server provides Skills that document common workflows and best practices. Skills are served via MCP resources for future client support.

Skill When to Use
debug-workflow-failure Debugging failed workflow submissions, identifying error patterns, troubleshooting infrastructure issues
extract-workflow-data Extracting specific data from workflow metadata without loading 100K+ tokens
submit-workflow-safely Pre-submission verification and choosing between single-entity and batch processing
navigate-subworkflows Working with nested WDL subworkflows, finding subworkflow IDs
manage-context-size Preventing context exhaustion with scattered workflows, large data tables, or verbose metadata

Skills contain step-by-step procedures, best practices, and anti-patterns.

Note: Claude Code and similar agents do not currently consume MCP-served skills automatically. The procedural knowledge is also included in the tool docstrings. Skills are provided for future MCP client support and as reference documentation.

Use Cases

  • WDL Pipeline Development: Monitor Terra workflow runs while developing and debugging WDL pipelines with Claude Code
  • Regression Testing: Run automated tests against benchmark datasets on Terra
  • Job Monitoring: Track submission status, interpret logs, and debug workflow failures

Example Usage

Once configured, you can interact with Terra.Bio through Claude:

Human: Find my malaria workspaces

Claude: I'll search your accessible Terra workspaces.
[Claude calls list_workspaces with name_contains="malaria"]
2 of your 2,234 accessible workspaces match:
1. broad-firecloud-dsde-methods/sr-malaria (created by user@example.org on 2024-01-15)
2. my-billing/malaria-analysis (created by user@example.org on 2024-02-01)
Human: Show me the data tables in my analysis workspace

Claude: I'll retrieve the data tables from your analysis workspace.
[Claude calls get_workspace_data_tables with namespace="my-billing", name="analysis-workspace"]
The workspace has 2 data tables:
- participants: 150 rows
- samples: 450 rows
Human: Check the status of submission abc-123-def

Claude: I'll check the status of that submission.
[Claude calls get_submission_status with submission_id="abc-123-def"]
Submission abc-123-def is currently Running with 10 workflows:
- Succeeded: 7 workflows
- Running: 2 workflows
- Failed: 1 workflow
Human: Can you fetch the logs for the failed workflow and help me debug it?

Claude: I'll fetch the stderr logs for the failed workflow.
[Claude calls get_workflow_logs with workflow_id="wf-789", fetch_content=True]
The task "AlignReads" failed with this error at the end of the log:

OutOfMemoryError: Java heap space at htsjdk.samtools.BAMRecordCodec.decode()

This is a memory issue. The task needs more RAM allocated. You can increase the memory in your WDL using the runtime attribute: `memory: "32 GB"`
Human: I have a large submission running as the most recent submission in workspace my_lab/my_workspace.
Can you summarize where each workflow is in the pipeline?

Claude: I'll check the submission status and analyze the running workflows.
[Claude calls list_submissions with namespace="my_lab", name="my_workspace", limit=1]
[Claude calls get_submission_status with submission_id="abc-123-def"]
[Claude calls get_job_metadata for running workflows to identify current task]

Submission abc-123-def has 500 workflows with this breakdown:
- Succeeded: 312 workflows (complete)
- Running: 156 workflows
  - 45 in "align_reads" (earliest stage)
  - 78 in "call_variants" (middle stage)
  - 33 in "annotate_vcf" (final stage)
- Failed: 12 workflows (see next for details)
- Queued: 20 workflows (waiting to start)

The running workflows are progressing normally through the pipeline.
Human: My submission had 32 workflow failures. Can you categorize what went wrong?

Claude: I'll analyze the failed workflows to identify failure patterns.
[Claude calls get_submission_status to identify failed workflow IDs]
[Claude calls get_job_metadata (summary mode) for each failed workflow]
[Claude calls get_batch_job_status for infrastructure failures]

Failure Analysis for 32 failed workflows:

| Category | Count | Root Cause |
|----------|-------|------------|
| OOM errors | 19 | call_variants task exceeded 16GB memory limit |
| Disk exhaustion | 10 | Temporary files filled disk in align_reads |
| Docker pull failures | 2 | Rate-limited pulling image from Docker Hub |
| Input data errors | 1 | Malformed BAM file (sample_47) |

Recommendations:
1. Increase memory to 32GB for call_variants task
2. Increase disk size to 200GB for align_reads
3. Consider using a private container registry to avoid Docker Hub rate limits
4. Check sample_47 BAM file integrity before resubmitting
Human: I ran our new optimized code as submission abc-123-new and the baseline as xyz-789-old
on the same 200 samples. Can you verify the outputs match and check if runtime improved?

Claude: I'll compare both submissions for correctness and performance.
[Claude calls get_submission_status for both submissions]
[Claude calls get_job_metadata for sample of workflows from each]
[Claude calls get_workflow_outputs to compare output files]
[Claude calls get_workflow_cost for both]

**Regression Test Results: New Code vs Baseline**

Correctness (200 samples):
- Output files match: 198/200 samples (99%)
- Minor differences: 2 samples have VCF annotation order differences (functionally equivalent)
- No data quality regressions detected

Performance (call_variants step):
- Baseline avg runtime: 47 minutes
- New code avg runtime: 31 minutes
- Improvement: 34% faster

Cost:
- Baseline total: $156.40
- New code total: $118.20
- Savings: 24% reduction

Conclusion: The optimization is successful. Outputs are equivalent and the
call_variants step shows the expected ~35% runtime improvement. Safe to merge.

Human: this is great, please post your findings as a comment on the open PR on this git branch.

Data Privacy and Security Considerations

⚠️ This MCP server provides Claude with the ability to read data from your Terra workspaces. Exercise extreme caution when working with sensitive, restricted, or regulated data.

❌ Do NOT Use This Tool To:

  1. Extract Legally Restricted Genomic Data

    • Do NOT retrieve actual genome sequences, genotypes, or other individual-level genetic data
    • Do NOT ask Claude to analyze raw genomic data files (FASTQ, BAM, VCF, etc.)
    • Do NOT copy restricted research data from controlled-access databases
  2. Share Protected Health Information (PHI) with Free-Tier LLMs

    • Free and consumer LLM services (including Claude.ai free tier) may use your conversations for training
    • Do NOT share patient identifiers, clinical data, or other PHI without proper data use agreements
    • Always verify your LLM service's data retention and usage policies before working with sensitive data
  3. Violate Data Use Agreements or IRB Protocols

    • Terra workspaces often contain data with strict usage restrictions
    • Do NOT use this tool in ways that violate your institution's IRB protocols or data use agreements
    • Do NOT share controlled-access data beyond approved research teams

✅ Safe Use Cases:

  • Metadata Analysis: Query workspace organization, workflow configurations, submission statuses
  • Log Debugging: Analyze error messages and execution logs (which typically don't contain sensitive data)
  • Workflow Optimization: Review pipeline configurations, resource usage, and cost information
  • De-identified Data: Work with properly de-identified or synthetic datasets that comply with all applicable regulations
  • Secure Compute Environments: Use with restricted data when operating within a NIST-800-171 compliant compute boundary (e.g., Vertex AI within authorized Google Cloud projects with proper security controls)

Regulatory References

The NIH and other regulatory bodies have issued guidance on the use of generative AI with genomic and health data:

When in doubt, consult your institution's IRB, data governance office, or legal counsel before using this tool with potentially sensitive data.

Installation

Prerequisites

  • Python 3.10 or higher
  • Google credentials configured for Terra.Bio access (via FISS)
  • Terra.Bio account with workspace access. Any Terra account works; nothing here is specific to one institution.
  • A Google-backed Terra workspace, for part of the toolset. The GCS tools (list_gcs_objects, get_gcs_object_metadata, read_gcs_object, download_gcs_file, and get_workflow_logs(fetch_content=True)) assume gs:// buckets, and get_batch_job_status assumes Google Batch, so neither applies to a workspace backed by Azure storage. The Terra API tools (workspaces, data tables, entities, submissions, method configs, outputs, cost) do not care.
  • get_batch_job_status additionally needs the workspace's Cromwell to run on Google Batch. A workspace still on the older Pipelines API backend has no Batch job to query.

Pointing at a different Terra deployment

Every Terra call goes through FISS, which reads its API root from ~/.fissconfig (or a .fissconfig in the working directory) and defaults to https://api.firecloud.org/api/. No part of this server hardcodes that host. To use another deployment, set root_url under [DEFAULT]:

[DEFAULT]
root_url = https://api.firecloud.example.org/api/

Then substitute your own host wherever this README writes api.firecloud.org, including the Claude Science Allowed domains list.

Setup

  1. Clone this repository:
git clone <repository-url>
cd fiss-mcp
  1. Install dependencies:
pip install -e .

For development (includes test dependencies):

pip install -e ".[dev]"
  1. Verify your Google credentials are configured for FISS:
from firecloud import api as fapi
response = fapi.list_workspaces()
print(response.status_code)  # Should be 200

Usage

Running the Server (Development)

Test the server in development mode with detailed logging:

# Read-only mode (default)
fastmcp dev src/terra_mcp/server.py

# Write-enabled mode
fastmcp dev src/terra_mcp/server.py -- --allow-writes

This starts an interactive development session where you can test tools.

Running the Server (Production)

Run the server with stdio transport (for Claude Desktop integration):

# Read-only mode (default - recommended for safety)
fastmcp run src/terra_mcp/server.py

# Write-enabled mode (for active development)
fastmcp run src/terra_mcp/server.py -- --allow-writes

Or run directly:

# Read-only mode (default)
python src/terra_mcp/server.py

# Write-enabled mode
python src/terra_mcp/server.py --allow-writes

--gcs-backend {auto,json,xml}

How the server reaches Google Cloud Storage, which backs list_gcs_objects, get_gcs_object_metadata, read_gcs_object, download_gcs_file, and get_workflow_logs(fetch_content=True).

Value Behaviour
auto (default) Use google-cloud-storage (JSON API on storage.googleapis.com); if that host turns out to be unreachable, fall back to the XML API for the rest of the process.
json Always use google-cloud-storage.
xml Always use the GCS XML API on per-bucket hostnames, {bucket}.storage.googleapis.com.

auto is right everywhere except Claude Science, whose sandbox blocks storage.googleapis.com outright; see GCS inside Claude Science.

Claude Desktop Integration

To use this MCP server with Claude Desktop, add the following to your Claude Desktop configuration file:

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

Read-Only Mode (Default - Recommended for Safety)

This configuration enables all read-only tools (monitoring, querying, viewing) but blocks write operations:

{
  "mcpServers": {
    "terra": {
      "command": "python3",
      "args": ["/absolute/path/to/fiss-mcp/src/terra_mcp/server.py"]
    }
  }
}

Write-Enabled Mode (For Active Development)

To enable write operations (update_method_config, copy_method_config, submit_workflow, abort_submission, upload_entities), add the --allow-writes flag:

{
  "mcpServers": {
    "terra": {
      "command": "python3",
      "args": [
        "/absolute/path/to/fiss-mcp/src/terra_mcp/server.py",
        "--allow-writes"
      ]
    }
  }
}

Replace /absolute/path/to/fiss-mcp with the actual path to your cloned repository.

Note: If you installed dependencies in a Python virtual environment, replace python3 with the absolute path to your venv's Python interpreter (e.g., /absolute/path/to/venv/bin/python3).

Note: If you haven't authenticated with Google Cloud locally, you may need to add credentials:

{
  "mcpServers": {
    "terra": {
      "command": "python3",
      "args": [
        "/absolute/path/to/fiss-mcp/src/terra_mcp/server.py",
        "--allow-writes"
      ],
      "env": {
        "GOOGLE_APPLICATION_CREDENTIALS": "/path/to/your/credentials.json"
      }
    }
  }
}

After updating the configuration, restart Claude Desktop.

Claude Code Integration

Read-Only Mode (Default - Recommended for Safety)

To use this MCP server with Claude Code in read-only mode (monitoring, querying, viewing only), run:

claude mcp add terra --transport stdio \
  -- python3 \
  /absolute/path/to/fiss-mcp/src/terra_mcp/server.py

Write-Enabled Mode (For Active Development)

To enable write operations (update_method_config, copy_method_config, submit_workflow, abort_submission, upload_entities), add the --allow-writes flag:

claude mcp add terra --transport stdio \
  -- python3 \
  /absolute/path/to/fiss-mcp/src/terra_mcp/server.py \
  --allow-writes

Replace /absolute/path/to/fiss-mcp with the actual path to your cloned repository.

Note: If you installed dependencies in a Python virtual environment, use the absolute path to your venv's Python interpreter instead of python3:

# Read-only mode
claude mcp add terra --transport stdio \
  -- /absolute/path/to/venv/bin/python3 \
  /absolute/path/to/fiss-mcp/src/terra_mcp/server.py

# Write-enabled mode
claude mcp add terra --transport stdio \
  -- /absolute/path/to/venv/bin/python3 \
  /absolute/path/to/fiss-mcp/src/terra_mcp/server.py \
  --allow-writes

If you need to specify Google Cloud credentials:

# Read-only mode with credentials
claude mcp add terra --transport stdio \
  --env GOOGLE_APPLICATION_CREDENTIALS=/path/to/your/credentials.json \
  -- python3 \
  /absolute/path/to/fiss-mcp/src/terra_mcp/server.py

# Write-enabled mode with credentials
claude mcp add terra --transport stdio \
  --env GOOGLE_APPLICATION_CREDENTIALS=/path/to/your/credentials.json \
  -- python3 \
  /absolute/path/to/fiss-mcp/src/terra_mcp/server.py \
  --allow-writes

To verify the server is connected:

claude mcp list

To reconnect after code changes:

claude mcp reconnect terra

Claude Science Integration

Claude Science can run this server as a Local command connector (Connectors → Add connector → Local command). It works, but Claude Science launches local connectors inside a macOS sandbox that is far more restrictive than Claude Desktop or Claude Code, so the "clone it anywhere and point at your venv" setup from the sections above fails in several ways. This section documents what the sandbox does and how to install around it.

macOS only, for now. Everything in this section, including scripts/install-claude-science.sh (which refuses to run elsewhere), was written and tested against Claude Science on macOS. Claude Science also ships for Windows 11 and Linux x64, and the server has no macOS dependency, but the install layout here is built around macOS specifics: a Homebrew interpreter outside $HOME, /opt/fiss-mcp, /private/tmp, and the sandbox behaviour observed on that platform. Windows in particular has its own rules for local connectors, where the command must start with npx, node, python or a full program path and launching through npm or a .cmd, .bat or .ps1 file is unsupported. Nobody has worked out or tested the equivalent setup on either platform. This limitation is specific to the Claude Science connector. The server itself is plain Python and runs anywhere Python 3.10+ does; see Claude Desktop Integration and Claude Code Integration, which have no platform restriction.

Most of what follows is install-side configuration. The one server-side setting that matters here is --gcs-backend, because Claude Science blocks the host the normal Google Cloud Storage client uses; see GCS inside Claude Science.

What the sandbox does

Observed with Claude Science on macOS (sandbox runtime "Operon" 0.1.55, October 2026):

Restriction Symptom Workaround
Cannot execute binaries under $HOME sandbox-exec: execvp() of '~/…/venv/bin/python3' failed: Operation not permitted Use a Python installed outside your home (Homebrew: /opt/homebrew/bin/python3.12). Conda, pyenv, and venvs under ~ won't launch.
Cannot read files under $HOME can't open file '~/…/server.py': [Errno 1] Operation not permitted Keep the repo, venv, and credentials outside $HOME (this guide uses /opt/fiss-mcp).
Cannot write anywhere except /private/tmp and a per-connector workspace dir Log/cache writes fail with Operation not permitted Send logs to /tmp. Don't set TMPDIR (the sandbox sets its own).
Minimal environment KeyError: 'PATH'; credentials not found Set HOME, PATH, GOOGLE_APPLICATION_CREDENTIALS in the connector's env box.
No direct network; all traffic through a local proxy with a domain allowlist Tunnel connection failed: 403 Forbidden (host oauth2.googleapis.com not on the allowlist); every tool returns "verify your Google credentials" Add the domains in Allowed domains.
storage.googleapis.com is always blocked GCS tools fail even after allowlisting it Run with --gcs-backend xml and allowlist each bucket's own hostname; see GCS inside Claude Science.
A SOCKS proxy is in the environment ImportError: Using SOCKS proxy, but the 'socksio' package is not installed when the server starts The sandbox sets ALL_PROXY=socks5h://..., and httpx builds a transport for every proxy it finds, so socksio must be installed. It is a declared dependency as of this version; re-run the installer or pip install socksio in the venv.
Stderr must be redirected Server crashes inside mcp.run() with a truncated traceback, but runs fine from a terminal The launcher script redirects stderr to a file. (FASTMCP_SHOW_CLI_BANNER had no effect and is not needed.)

Two further details:

  • FISS requires gcloud on PATH at import time (firecloud/__init__.py calls which('gcloud')). It only checks that the file exists. A gcloud under ~/Development/google-cloud-sdk/bin passed this check despite the read restriction, so the SDK does not need relocating.
  • The server process is long-lived. Claude Science keeps it running across tool calls and conversations, so after changing run.sh, the code, or the allowlist you must restart it: pkill -f terra_mcp/server.py (the next tool call respawns it), or delete and re-add the connector.

Installation

scripts/install-claude-science.sh performs every step below with progress output and ends by printing the exact values to paste into Claude Science:

./scripts/install-claude-science.sh                 # read-only mode (recommended)
./scripts/install-claude-science.sh --allow-writes  # enable write tools
./scripts/install-claude-science.sh --source .      # install from this checkout instead of cloning
./scripts/install-claude-science.sh --help          # all options

What it does, if you'd rather do it by hand:

  1. Interpreter outside $HOME. Homebrew Python (brew install python@3.12 if needed).

  2. Install tree outside $HOME. Creates /opt/fiss-mcp owned by you, containing:

    • repo/ — a clone (or copy) of this repository
    • venv/ — created from the Homebrew interpreter, with pip install -e repo
    • adc.json — a copy of your Google Application Default Credentials (ADC), mode 600
    • run.sh — the launcher the connector calls
  3. Credentials. Copies ~/.config/gcloud/application_default_credentials.json to /opt/fiss-mcp/adc.json. This file holds a long-lived refresh token for your Google account — treat it like a password. A service-account key (--credentials path.json) is the cleaner option on shared machines.

  4. Launcher /opt/fiss-mcp/run.sh:

    #!/bin/sh
    LOGDIR=/tmp/fiss-mcp-$(id -u)
    mkdir -p -m 700 "$LOGDIR" 2>/dev/null
    LOG="$LOGDIR/stderr.log"
    ( umask 077; echo "=== $(date) ===" >> "$LOG" ) 2>/dev/null || LOG=/dev/null
    exec /opt/fiss-mcp/venv/bin/python3 /opt/fiss-mcp/repo/src/terra_mcp/server.py --gcs-backend xml "$@" 2>>"$LOG"
    
  5. Smoke test from a terminal with the connector's exact environment:

    env -i HOME=/opt/fiss-mcp \
      GOOGLE_APPLICATION_CREDENTIALS=/opt/fiss-mcp/adc.json \
      PATH=/path/to/google-cloud-sdk/bin:/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin \
      /opt/fiss-mcp/venv/bin/python3 -c \
      "from firecloud import api as fapi; print(fapi.list_workspaces().status_code)"   # expect 200
    

    This proves credentials and imports; it does not exercise the network allowlist, which only applies inside the sandbox.

Connector settings

In Claude Science: Connectors → Add connector → Local command

Field Value
Name terra
Command /opt/fiss-mcp/run.sh (append --allow-writes for write mode)
Environment variables see below
Description Terra.bio workspaces, data tables, submissions, logs

The installer's run.sh already passes --gcs-backend xml. If your launcher predates that flag, either re-run the installer or put the flag in the Command field instead: /opt/fiss-mcp/run.sh --gcs-backend xml. Passing it in both places is harmless, the last one wins.

Environment variables (one per line; substitute your gcloud directory):

HOME=/opt/fiss-mcp
GOOGLE_APPLICATION_CREDENTIALS=/opt/fiss-mcp/adc.json
PATH=/path/to/google-cloud-sdk/bin:/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin

HOME=/opt/fiss-mcp keeps anything the Google client libraries cache out of your blocked real home directory. Do not set TMPDIR.

GOOGLE_CLOUD_PROJECT=<project-id> is optional and only affects --gcs-backend json: the XML backend never sends a project, and the JSON backend falls back to a placeholder when it cannot determine one. Set it if you want GCS quota attributed to a particular project. Do not paste it with a literal placeholder value, an invalid project id is worse than none.

Allowed domains

The sandbox refuses all outbound connections except to domains on its allowlist. In Claude Science, open the connector's Allowed domains setting and paste:

oauth2.googleapis.com
api.firecloud.org
batch.googleapis.com
www.googleapis.com
Domain Needed by
oauth2.googleapis.com Token refresh — nothing works without it
api.firecloud.org Terra / FISS API: workspaces, entities, submissions, method configs, outputs, cost. Replace with your own host if root_url in ~/.fissconfig points at a different Terra deployment (see Prerequisites)
batch.googleapis.com get_batch_job_status
www.googleapis.com Some google-auth and client-library calls

Then add one entry per bucket you need to read, using the bucket's own hostname:

fc-<workspace-bucket-uuid>.storage.googleapis.com

A workspace's bucket name is the bucketName field returned by get_workspace_metadata. That single entry covers everything stored in the workspace: workflow logs, outputs, and any inputs you uploaded there. Input files that live in other buckets (reference data, another workspace) each need their own entry.

Wildcards. *.storage.googleapis.com was rejected when entered in the app's Settings > Network list, so list each bucket by name there. Claude Science's documentation does allow wildcards in the two other places a domain can come from (the config.toml key below and an organization-managed list), where a wildcard covers subdomains only and so would not re-enable the blocked storage.googleapis.com itself. Whether a wildcard is accepted for this host in those channels is untested.

You may not have to pre-populate the list. Claude Science appears to prompt for permission the first time a tool reaches a bucket, rather than simply failing, which matches its documented default that "members allow a new site themselves when Claude asks". Observed with a public bucket; not yet verified for a private bucket such as a Terra workspace bucket, where the request also has to carry working credentials. Until that is confirmed, treat the per-bucket allowlist entries above as the reliable route and the prompt as a convenience.

Adding the domains without the UI

Claude Science reads ~/.claude-science/config.toml (on Windows, %USERPROFILE%\.claude-science\config.toml) and its [sandbox.network] allowed_domains key is additive to whatever is in Settings > Network:

[sandbox.network]
allowed_domains = [
  "oauth2.googleapis.com",
  "api.firecloud.org",
  "batch.googleapis.com",
  "www.googleapis.com",
  "fc-11111111-2222-3333-4444-555555555555.storage.googleapis.com",
]

The file is read once at app startup, so restart Claude Science after editing it. Restarting the connector with pkill -f terra_mcp/server.py is not enough, since the allowlist is enforced by the app's sandbox rather than by the server.

To print the bucket lines for every workspace you can reach, run this with the connector's own interpreter:

/opt/fiss-mcp/venv/bin/python3 - <<'EOF'
from firecloud import api as fapi

for ws in fapi.list_workspaces().json():
    bucket = ws.get("workspace", {}).get("bucketName")
    if bucket:
        print(f'  "{bucket}.storage.googleapis.com",')
EOF

On Team and Enterprise plans an admin can instead set one list for every member under Organization settings > Claude Science > Manage network allowlist > Custom domains, which does document wildcard support and holds up to 600 domains. Be aware that turning that switch on replaces every member's own list, including anything config.toml added, for the whole organization. There is no API or MDM policy channel for the allowlist; deploying config.toml per member is the supported automation route.

Restart the server after changing the list (pkill -f terra_mcp/server.py).

GCS inside Claude Science

Claude Science permanently blocks storage.googleapis.com, which is the only host the google-cloud-storage library talks to (it uses the GCS JSON API). Its UI points you at the bucket's own hostname instead (my-bucket.storage.googleapis.com), and those virtual-hosted names serve the GCS XML API. So the server has a second GCS backend that speaks XML, and all five GCS-touching tools work in Claude Science once you select it: list_gcs_objects, get_gcs_object_metadata, read_gcs_object, download_gcs_file, and get_workflow_logs(fetch_content=True).

This was confirmed working inside the sandbox on 2026-10-02 against a Terra workspace bucket. Two things are required:

  1. Select the backend. scripts/install-claude-science.sh already puts --gcs-backend xml in the generated run.sh; if you wrote the launcher by hand, add it there or to the connector command. The default, --gcs-backend auto, also works, but only because the probe that detects the blocked host runs with a bounded retry: google-cloud-storage's default policy retries a proxy refusal for 120 seconds, which is longer than an MCP client will wait, so an unbounded probe would time out instead of falling back. xml skips the probe altogether, which is why the installer sets it.
  2. Allowlist each bucket, as described in Allowed domains.

Remaining differences when the XML backend is in use:

  • get_gcs_object_metadata returns time_created: null. The XML API reports only a last-modified time.
  • list_gcs_objects returns content_type: null for each object. An XML listing does not carry content types; call get_gcs_object_metadata for one.
  • md5_hash in a listing is derived from the object's ETag, so it is null for composite and multipart-uploaded objects. get_gcs_object_metadata reports the real hashes either way.
  • download_gcs_file must target /tmp or the per-connector workspace directory, since the sandbox permits writes nowhere else.
  • Requester-pays buckets are not supported by either backend. Terra workspace buckets are not requester-pays.

Troubleshooting

  • Server stderr: tail -n 60 /tmp/fiss-mcp-$(id -u)/stderr.log — each launch appends a timestamped header. The directory is created mode 0700 and the log 0600, because /tmp is shared and the log carries Terra error text.

  • Every tool fails with "verify your Google credentials" but the terminal smoke test gives 200 → almost certainly the network allowlist. Confirm by running a probe inside the sandbox: temporarily insert this before the exec line in run.sh, restart the server, and read the log:

    { echo "--- env ---"; env | sort; echo "--- probe ---"
      /opt/fiss-mcp/venv/bin/python3 -c 'import traceback
    try:
        from firecloud import api as fapi; r = fapi.list_workspaces(); print("terra:", r.status_code)
    except Exception: traceback.print_exc()'; } >> "$LOG" 2>&1
    

    A 403 Forbidden (host X not on the allowlist) names the domain to add.

  • execvp() … Operation not permitted: the command path is under $HOME. Move the interpreter.

  • can't open file … Operation not permitted: the script or a dependency is under $HOME. Move it.

  • KeyError: 'PATH': the PATH line is missing from the environment box.

  • ImportError: Using SOCKS proxy, but the 'socksio' package is not installed: the sandbox sets ALL_PROXY to a socks5h:// address, and httpx creates a transport for every proxy in the environment when it builds a client, so the package has to be present even though Terra and GCS traffic go through the plain HTTP proxy instead. /opt/fiss-mcp/venv/bin/pip install socksio, or re-run the installer, which now gets it as a declared dependency.

  • Changes don't take effect: the old process is still running. pkill -f terra_mcp/server.py.

  • A GCS tool reports Could not reach fc-….storage.googleapis.com through the sandbox proxy: that bucket's hostname is not on the allowed-domains list. Add it and restart the server. To confirm from inside the sandbox, insert this probe before the exec line in run.sh:

    /opt/fiss-mcp/venv/bin/python3 -c 'import requests, google.auth, google.auth.transport.requests
    creds, _ = google.auth.default(scopes=["https://www.googleapis.com/auth/devstorage.read_only"])
    creds.refresh(google.auth.transport.requests.Request())
    b = "fc-<uuid>"
    r = requests.get(f"https://{b}.storage.googleapis.com/?list-type=2&max-keys=3",
                     headers={"Authorization": f"Bearer {creds.token}"}, timeout=20)
    print(b, r.status_code, r.text[:300])' >> "$LOG" 2>&1
    

    200 means the bucket is reachable; 403 … not on the allowlist names what to add.

  • Project was not passed and could not be determined from the environment: only the JSON backend needs a project. Set GOOGLE_CLOUD_PROJECT in the connector environment, or use --gcs-backend xml, which never needs one.

  • Credentials expired / 401: gcloud auth application-default login, then re-copy the ADC file (re-running the install script does this).

Untested alternative

The sandbox environment shows a per-connector workspace directory, ~/.claude-science/orgs/<org-id>/workspaces/_mcp-terra/, that is writable and whose .venv/python is exempted from the dynamic-library restrictions. That suggests Claude Science intends local MCP servers to live there, with their own .venv, which would make the /opt/fiss-mcp relocation unnecessary. This has not been tested.

A note on data

Everything in the Data Privacy and Security Considerations section applies here. The sandbox restricts what the server can reach on your machine and on the network; it does nothing to restrict what Terra data flows into the model's context once a tool returns.

Testing

Run the test suite to verify the server implementation:

# Install dependencies (if not already installed)
pip install -e ".[dev]"

# Run tests
PYTHONPATH=src pytest tests/ -v

# Run with coverage
PYTHONPATH=src pytest tests/ --cov=src/terra_mcp --cov-report=term

The test suite includes 251 tests:

  • Server initialization verification
  • Tool registration checks (all 21 tools)
  • Mocked FISS API responses
  • Mocked GCS log fetching and truncation
  • Error handling scenarios (404s, 403s, 400s, 409s, API failures, GCS errors)
  • Parameter validation (max_workflows, include_keys, fetch_content, truncate, expression, entity_data, etc.)
  • Helper function tests (truncation logic, GCS URL parsing)
  • Read-only mode safety feature tests (7 tests verifying write operations are properly blocked)
  • Coverage for all tool categories: workspace discovery, monitoring, workflow management, and data management
  • GCS backend tests (tests/test_gcs.py): XML API listing/paging/delimiters, header-to-metadata mapping, range reads, error mapping, backend auto-detection, and the project fallback
  • A static check that every ctx.info() / ctx.error() call is awaited, since FastMCP 3 made them coroutines

Development

Project Structure

fiss-mcp/
├── src/terra_mcp/
│   ├── __init__.py          # Package initialization
│   ├── gcs.py               # GCS access (JSON client + XML API backend)
│   └── server.py            # MCP server implementation
├── tests/
│   ├── test_gcs.py          # GCS backend tests
│   └── test_server.py       # Test suite
├── pyproject.toml          # Project configuration
├── CLAUDE.md               # Project specification
└── README.md               # This file

Adding New Tools

To extend the server with additional Terra.Bio functionality:

  1. Add the tool function in src/terra_mcp/server.py
  2. Use the @mcp.tool() decorator
  3. Add comprehensive docstrings (visible to LLMs)
  4. Use Annotated type hints for parameter descriptions
  5. Implement two-tier error handling (ToolError for user-facing errors)
  6. Add write access check if the tool modifies Terra resources
  7. Add tests in tests/test_server.py following TDD principles (use enable_writes fixture for write tools)

Example (read-only tool):

@mcp.tool()
async def my_new_tool(
    workspace_namespace: Annotated[str, "Terra workspace namespace"],
    workspace_name: Annotated[str, "Terra workspace name"],
    ctx: Context,
) -> dict[str, Any]:
    """Tool description that LLMs will see.

    Detailed description of what this tool does.

    Args:
        workspace_namespace: Description
        workspace_name: Description

    Returns:
        Dictionary with result data
    """
    try:
        ctx.info("Starting operation")
        # Implementation
        return {"result": "data"}
    except ToolError:
        raise
    except Exception as e:
        ctx.error(f"Error: {e}")
        raise ToolError("User-friendly error message")

Example (write tool):

@mcp.tool()
async def my_write_tool(
    workspace_namespace: Annotated[str, "Terra workspace namespace"],
    workspace_name: Annotated[str, "Terra workspace name"],
    ctx: Context,
) -> dict[str, Any]:
    """Tool that modifies Terra resources.

    Args:
        workspace_namespace: Description
        workspace_name: Description

    Returns:
        Dictionary with result data
    """
    # Check write access first
    _check_write_access(ctx)

    try:
        ctx.info("Starting write operation")
        # Implementation
        return {"result": "data"}
    except ToolError:
        raise
    except Exception as e:
        ctx.error(f"Error: {e}")
        raise ToolError("User-friendly error message")

Future Enhancements

Potential areas for expansion (see CLAUDE.md for details):

  • Workflow Analysis: Automatic cost optimization suggestions, call-caching analysis
  • Enhanced Error Handling: Automatic retry logic for transient failures, rate limit backoff
  • WDL Integration: WDL parsing, validation, and linting integration
  • Batch Operations: Bulk entity operations, workspace cloning
  • Terra Notebooks: Integration with Terra notebook operations
  • Advanced Filtering: Enhanced entity queries with complex filters and pagination

Architecture

Design Principles

  1. Read-only by default: Server runs in safe mode; write operations require explicit --allow-writes flag
  2. Explicit workspace identification: Always require namespace + name (no implicit "current workspace")
  3. Actionable error messages: All errors provide clear next steps for LLMs
  4. Smart log truncation: For error logs, return tail (last ~25K chars) where failures appear
  5. Two-tier error handling: ToolError for expected failures, masked exceptions for internal errors

Key Dependencies

  • FastMCP: Python framework for building MCP servers
  • FISS (firecloud): Python client for Terra.Bio API
  • google-cloud-storage: For fetching workflow logs and bucket objects from GCS
  • requests / google-auth: Used directly by the GCS XML API backend (--gcs-backend xml)
  • socksio: Lets httpx build a client when a socks5h:// proxy is in the environment, as it is inside the Claude Science sandbox
  • Pydantic: Data validation and schema generation

Troubleshooting

"Failed to list workspaces" error

Ensure your Google credentials are properly configured:

# Check if gcloud is authenticated
gcloud auth list

# Or verify GOOGLE_APPLICATION_CREDENTIALS is set
echo $GOOGLE_APPLICATION_CREDENTIALS

Tools not appearing in Claude Desktop

  1. Verify the MCP server is configured in claude_desktop_config.json
  2. Check the absolute path to server.py is correct
  3. Restart Claude Desktop completely
  4. Check Claude Desktop logs: ~/Library/Logs/Claude/mcp*.log (macOS)

Import errors when running server

Make sure you've installed all dependencies:

pip install -e .

Contributing

Contributions are welcome! Please ensure:

  • Follow the established code patterns and architecture
  • Write tests before implementing features (TDD)
  • Maintain comprehensive error handling
  • Add clear documentation for LLM consumption
  • Run tests and linting before submitting PRs

License

See LICENSE file for details.

Resources