使用说明
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
- Skills (Procedural Workflows)
- Use Cases
- Data Privacy and Security Considerations
- Installation
- Usage
- Claude Science Integration
- Testing
- Development
- Future Enhancements
- Architecture
- Troubleshooting
- Contributing
- License
- Resources
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 byname_contains/namespaceand capped bylimit(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 namesget_entities- Read rows from a Terra data table:entity_namefor 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 metadataget_submission_status- Get detailed status of workflow submissions (supports customizable workflow limits)get_job_metadata- Get Cromwell metadata for specific workflows with optional filteringget_workflow_logs- Get workflow logs with optional GCS content fetching and smart truncationget_workflow_outputs- Get output files and values from completed workflowsget_workflow_cost- Get cost information for workflow executionsget_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 orls-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 processingabort_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:
-
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
-
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
-
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:
- NIH NOT-OD-25-081: Expectations for the Use of Generative Artificial Intelligence (GenAI) by Recipients of NIH Funding
- NIH NOT-OD-24-157: Notice of Supplemental Information for NIH-Funded Researchers and Applicant Institutions on Generative Artificial Intelligence (GenAI) Tools
- Legal Analysis: Generative AI and Genomic Privacy - Academic analysis of privacy risks
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, andget_workflow_logs(fetch_content=True)) assumegs://buckets, andget_batch_job_statusassumes 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_statusadditionally 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
- Clone this repository:
git clone <repository-url>
cd fiss-mcp
- Install dependencies:
pip install -e .
For development (includes test dependencies):
pip install -e ".[dev]"
- 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 withnpx,node,pythonor a full program path and launching throughnpmor a.cmd,.bator.ps1file 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
gcloudonPATHat import time (firecloud/__init__.pycallswhich('gcloud')). It only checks that the file exists. A gcloud under~/Development/google-cloud-sdk/binpassed 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:
-
Interpreter outside
$HOME. Homebrew Python (brew install python@3.12if needed). -
Install tree outside
$HOME. Creates/opt/fiss-mcpowned by you, containing:repo/— a clone (or copy) of this repositoryvenv/— created from the Homebrew interpreter, withpip install -e repoadc.json— a copy of your Google Application Default Credentials (ADC), mode 600run.sh— the launcher the connector calls
-
Credentials. Copies
~/.config/gcloud/application_default_credentials.jsonto/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. -
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" -
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 200This 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:
- Select the backend.
scripts/install-claude-science.shalready puts--gcs-backend xmlin the generatedrun.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.xmlskips the probe altogether, which is why the installer sets it. - Allowlist each bucket, as described in Allowed domains.
Remaining differences when the XML backend is in use:
get_gcs_object_metadatareturnstime_created: null. The XML API reports only a last-modified time.list_gcs_objectsreturnscontent_type: nullfor each object. An XML listing does not carry content types; callget_gcs_object_metadatafor one.md5_hashin a listing is derived from the object's ETag, so it isnullfor composite and multipart-uploaded objects.get_gcs_object_metadatareports the real hashes either way.download_gcs_filemust target/tmpor 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/tmpis 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
execline inrun.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>&1A
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': thePATHline is missing from the environment box. -
ImportError: Using SOCKS proxy, but the 'socksio' package is not installed: the sandbox setsALL_PROXYto asocks5h://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 theexecline inrun.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>&1200 means the bucket is reachable;
403 … not on the allowlistnames what to add. -
Project was not passed and could not be determined from the environment: only the JSON backend needs a project. SetGOOGLE_CLOUD_PROJECTin 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:
- Add the tool function in
src/terra_mcp/server.py - Use the
@mcp.tool()decorator - Add comprehensive docstrings (visible to LLMs)
- Use
Annotatedtype hints for parameter descriptions - Implement two-tier error handling (ToolError for user-facing errors)
- Add write access check if the tool modifies Terra resources
- Add tests in
tests/test_server.pyfollowing TDD principles (useenable_writesfixture 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
- Read-only by default: Server runs in safe mode; write operations require explicit
--allow-writesflag - Explicit workspace identification: Always require namespace + name (no implicit "current workspace")
- Actionable error messages: All errors provide clear next steps for LLMs
- Smart log truncation: For error logs, return tail (last ~25K chars) where failures appear
- 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
- Verify the MCP server is configured in
claude_desktop_config.json - Check the absolute path to
server.pyis correct - Restart Claude Desktop completely
- 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.
