Generated banner for String Database
Generated logo for String Database

String Database

Google DeepMindOfficialPublished by Google DeepMind

  • Skill
  • Tool integration
  • Science and research
  • Apache-2.0
  • Low risk
  • Has scripts

From the author

Query the STRING database for protein-protein interactions (PPIs), functional enrichment, and homology. Use when the user asks about interactions between specific proteins, interaction evidence, confidence scores, protein interaction partners, or pathway enrichments.
— the description by Google DeepMind

AutoGineer summary

Written by AutoGineer from the skill’s own files, not by the author

The string-database skill provides a programmatic interface to the STRING database, enabling researchers to retrieve protein-protein interaction (PPI) networks, functional annotations, and homology data. It uses a Python CLI wrapper to handle complex queries, requiring users to specify NCBI Taxon IDs for all operations. The skill emphasizes efficient data handling by requiring output to be saved to files rather than printed directly to the console, and it mandates identifier mapping to ensure optimal performance.

What it does

  • Retrieves protein-protein interaction networks with configurable confidence scores.
  • Performs functional enrichment analysis for GO, KEGG, Pfam, and other categories.
  • Calculates homology scores between proteins within or across different species.
  • Generates visual network maps in image formats.
  • Identifies top interaction partners for specific proteins.
  • Searches for proteins associated with specific functional terms or diseases.

When to use it

  • When you need to investigate the interaction network of specific proteins.
  • When analyzing functional enrichment for a set of proteins.
  • When comparing protein homology between different species.
  • When you need to identify proteins associated with a specific biological pathway or disease term.

Advantages

  • Enables programmatic access to large-scale biological interaction data.
  • Supports statistical validation of interaction networks.
  • Provides flexible output options for large datasets via file-based processing.
  • Facilitates cross-species comparative analysis through homology tools.

Usage examples

“Find the top 10 interaction partners for BRCA1 in humans.”
The agent will prompt for the NCBI Taxon ID (9606 for human), then execute the partners command to generate a TSV file containing the top 10 interaction partners.
“Are these proteins significantly enriched for any KEGG pathways? (Species: 511145)”
The agent will use the enrichment command to analyze the provided protein list against the specified species and return the enrichment results in a TSV file.

Install

  1. Download the skill as a ZIP:

    https://autogineer.com/agent-skills/google-deepmind/string-database/download
  2. Unzip it into the cross-client skills folder of your project:

    mkdir -p .agents/skills && unzip string-database.zip -d .agents/skills

Documentation by Google DeepMind

STRING Database Skill

This skill allows you to query the STRING database programmatically using a bundled Python CLI wrapper.

Prerequisites

  1. uv: Read the uv skill and follow its Setup instructions to ensure uv is installed and on PATH.

  2. User Notification: If .licenses/string_database_LICENSE.txt does not already exist in the workspace root directory then (1) prominently notify the user to check the terms at https://string-db.org/cgi/access, then (2) create the file recording the notification text and timestamp.

Core Rules

  1. MANDATORY: Ask for Species First: The STRING API requires NCBI Taxon IDs. You MUST NOT guess or assume a species. If the user does not explicitly state a species or Taxon ID, you MUST stop and ask: "Which species are you interested in? I need the NCBI Taxon ID to proceed." Even for well-known proteins like TP53, BRCA1, or MDM2 that are commonly associated with human studies, you MUST still ask — do not default to Human.

  2. Never print output to stdout: The --output <file.tsv> is required. Never read large outputs into context. Instead use jq, python or file operations (grep, head) to process large output.

  3. Map Identifiers first: If you only have common gene names (e.g., 'TP53'), map them to STRING IDs first as this guarantees much faster server responses. Use the map command for this.

  4. Notification: If this skill is used, ensure this is mentioned in the output.

Tool Execution

The CLI is at scripts/string_cli.py and should be run using uv run:

uv run scripts/string_cli.py <command> [options] --output /tmp/out.tsv

Feature Domains (Progressive Disclosure)

Read the following reference files based on the user's request:

  • Mapping Identifiers - Map common protein names to STRING IDs.

  • Interactions & Network - Find interacting proteins, network topologies, mediators, homology, and visual network images.

  • Enrichment & Functional Annotations - Analyze pathway enrichment (GO, KEGG, Pfam), PPI significance, or find all proteins associated with a specific term (e.g. Melanoma).

  • Values/Ranks Enrichment - Submit full experimental datasets (e.g., logFC, p-values) for rank-based enrichment analysis using the async background API.

To begin, read the reference file most appropriate to the current task to discover the correct CLI command.

Files

scripts/string_cli.py

# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""STRING Database CLI Wrapper.

Provides access to STRING API v12.0 endpoints.
"""

# /// script
# requires-python = ">=3.10"
# dependencies = [
#   "polite-http",
# ]
# ///

import argparse
import json
import os
import sys
import time
from typing import Any
import urllib.parse

from polite_http import http_client

CALLER_IDENTITY = 'google-science-skills'
URL_TEMPLATE = (
    'https://version-{api_version}-0.string-db.org/api/{format_type}/{endpoint}'
)
_CLIENT = None


class _DummyResponse:

  def __init__(self, content):
    self.content = content

  def json(self):
    return json.loads(self.content.decode('utf-8'))


def call_api(url: str, params: dict[str, Any], output_file: str):
  """Calls the STRING API and writes the response to a file.

  Args:
    url: The API URL to call.
    params: A dictionary of parameters to send with the request.
    output_file: The file path where the API response will be written.

  Returns:
    A dummy response object with a .json() method if the call is successful.
    Exits the program on API errors.
  """
  params['caller_identity'] = CALLER_IDENTITY
  data = urllib.parse.urlencode(params).encode('utf-8')
  assert _CLIENT is not None
  content = None
  try:
    content = _CLIENT.fetch_bytes(url, method='POST', data=data)
  except http_client.HttpError as e:
    print(f'API Error (HTTP {e.status_code}): {e}', file=sys.stderr)
    sys.exit(1)

  os.makedirs(os.path.dirname(os.path.abspath(output_file)), exist_ok=True)
  with open(output_file, 'wb') as f:
    f.write(content)
  print(f'Success: Output written to {output_file}')
  return _DummyResponse(content)


def main():
  parser = argparse.ArgumentParser(description='STRING Database CLI wrapper')
  parser.add_argument(
      '--api_version', default='12', help='STRING API version (default: 12)'
  )
  subparsers = parser.add_subparsers(dest='command', required=True)

  # Common parent parser for output
  parent_out = argparse.ArgumentParser(add_help=False)
  parent_out.add_argument(
      '--output', required=True, help='File to write output to'
  )

  # Common parent for identifiers and species
  parent_id = argparse.ArgumentParser(add_help=False)
  parent_id.add_argument(
      '--identifiers',
      nargs='+',
      required=True,
      help='List of protein names/IDs',
  )
  parent_id.add_argument(
      '--species', type=int, help='NCBI Taxon ID (e.g. 9606 for human)'
  )

  # map
  p_map = subparsers.add_parser(
      'map',
      parents=[parent_out, parent_id],
      help='Map identifiers to STRING IDs',
  )
  p_map.add_argument('--echo_query', type=int, choices=[0, 1], default=1)

  # network
  p_net = subparsers.add_parser(
      'network', parents=[parent_out, parent_id], help='Get interaction network'
  )
  p_net.add_argument('--required_score', type=int, help='0-1000 threshold')
  p_net.add_argument(
      '--network_type', choices=['functional', 'physical'], default='functional'
  )
  p_net.add_argument('--add_nodes', type=int, help='Number of nodes to add')

  # image
  p_img = subparsers.add_parser(
      'image', parents=[parent_out, parent_id], help='Get network image'
  )
  p_img.add_argument(
      '--format', choices=['image', 'highres_image', 'svg'], default='image'
  )
  p_img.add_argument(
      '--network_flavor',
      choices=['evidence', 'confidence', 'actions'],
      default='evidence',
  )
  p_img.add_argument('--add_color_nodes', type=int)

  # partners
  p_part = subparsers.add_parser(
      'partners',
      parents=[parent_out, parent_id],
      help='Get interaction partners',
  )
  p_part.add_argument('--limit', type=int, help='Max partners per protein')

  # homology
  subparsers.add_parser(
      'homology', parents=[parent_out, parent_id], help='Get homology scores'
  )

  # homology_best
  p_homb = subparsers.add_parser(
      'homology-best', parents=[parent_out, parent_id], help='Best homology hit'
  )
  p_homb.add_argument(
      '--species_b', help='Comma-separated target species (e.g., 10090,7227)'
  )

  # enrichment
  subparsers.add_parser(
      'enrichment',
      parents=[parent_out, parent_id],
      help='Functional enrichment',
  )

  # functional_annotation
  p_fa = subparsers.add_parser(
      'functional-annotation',
      parents=[parent_out, parent_id],
      help='Functional annotations',
  )
  p_fa.add_argument('--allow_pubmed', type=int, choices=[0, 1], default=0)

  # functional_terms (uses term_text instead of identifiers)
  p_ft = subparsers.add_parser(
      'functional-terms', parents=[parent_out], help='Search proteins by term'
  )
  p_ft.add_argument(
      '--term_text', required=True, help='e.g. Melanoma, GO:0008543'
  )
  p_ft.add_argument('--species', type=int, default=9606)

  # ppi_enrichment
  subparsers.add_parser(
      'ppi-enrichment', parents=[parent_out, parent_id], help='PPI enrichment'
  )

  # version
  subparsers.add_parser(
      'version', parents=[parent_out], help='Get STRING version'
  )

  # valuesranks API key
  subparsers.add_parser(
      'valuesranks-key',
      parents=[parent_out],
      help='Get API key for Values/Ranks',
  )

  # valuesranks submit
  p_vr_sub = subparsers.add_parser(
      'valuesranks-submit', parents=[parent_out], help='Submit Values/Ranks job'
  )
  p_vr_sub.add_argument('--api_key', required=True)
  p_vr_sub.add_argument(
      '--input_file', required=True, help='Tab-separated file of ID and value'
  )
  p_vr_sub.add_argument('--species', type=int, required=True)
  p_vr_sub.add_argument('--ge_fdr', type=float, default=0.01)

  # valuesranks status
  p_vr_stat = subparsers.add_parser(
      'valuesranks-status', parents=[parent_out], help='Check job status'
  )
  p_vr_stat.add_argument('--api_key', required=True)
  p_vr_stat.add_argument('--job_id', help='Omit to list all jobs')
  p_vr_stat.add_argument(
      '--wait',
      action='store_true',
      help='Wait for job to complete and download final TSV',
  )

  args = parser.parse_args()

  global _CLIENT
  base_url = f'https://version-{args.api_version}-0.string-db.org/'
  _CLIENT = http_client.HttpClient(base_url, qps=1)

  def _url(endpoint, *, format_type='tsv'):
    return URL_TEMPLATE.format(
        api_version=args.api_version, format_type=format_type, endpoint=endpoint
    )

  requires_species = [
      'map',
      'network',
      'image',
      'partners',
      'homology',
      'homology-best',
      'enrichment',
      'functional-annotation',
      'ppi-enrichment',
  ]
  if args.command in requires_species and (
      not hasattr(args, 'species') or args.species is None
  ):
    print(
        f"Error: Command '{args.command}' requires --species", file=sys.stderr
    )
    sys.exit(1)

  params = {}
  if hasattr(args, 'identifiers') and args.identifiers:
    params['identifiers'] = '\r'.join(args.identifiers)
  if hasattr(args, 'species') and args.species is not None:
    params['species'] = args.species

  if args.command == 'map':
    params['echo_query'] = args.echo_query
    call_api(_url('get_string_ids'), params, args.output)

  elif args.command == 'network':
    if args.required_score:
      params['required_score'] = args.required_score
    params['network_type'] = args.network_type
    if args.add_nodes:
      params['add_nodes'] = args.add_nodes
    call_api(_url('network'), params, args.output)

  elif args.command == 'image':
    params['network_flavor'] = args.network_flavor
    if args.add_color_nodes:
      params['add_color_nodes'] = args.add_color_nodes
    call_api(_url('network', format_type=args.format), params, args.output)

  elif args.command == 'partners':
    if args.limit:
      params['limit'] = args.limit
    call_api(_url('interaction_partners'), params, args.output)

  elif args.command == 'homology-best':
    if args.species_b:
      params['species_b'] = args.species_b.replace(',', '\r')
    call_api(_url('homology_best'), params, args.output)

  elif args.command == 'functional-annotation':
    params['allow_pubmed'] = args.allow_pubmed
    call_api(_url('functional_annotation'), params, args.output)

  elif args.command == 'functional-terms':
    params['term_text'] = args.term_text
    call_api(_url('functional_terms'), params, args.output)

  elif args.command == 'valuesranks-key':
    call_api(_url('get_api_key', format_type='json'), {}, args.output)

  elif args.command in ['enrichment', 'homology', 'ppi-enrichment', 'version']:
    call_api(_url(args.command.replace('-', '_')), params, args.output)

  elif args.command == 'valuesranks-submit':
    params['api_key'] = args.api_key
    params['species'] = args.species
    params['ge_fdr'] = args.ge_fdr
    try:
      with open(args.input_file, 'r') as f:
        lines = f.readlines()
      valid_lines = []
      for i, line in enumerate(lines):
        parts = line.strip().split('\t')
        if len(parts) >= 2:
          try:
            float(parts[1])
            valid_lines.append(f'{parts[0]}\t{parts[1]}')
          except ValueError:
            print(
                f"Skipping line {i+1} as it doesn't contain a valid numeric"
                f' value: {line.strip()}',
                file=sys.stderr,
            )
        elif line.strip():
          print(
              f"Skipping line {i+1} as it doesn't contain at least 2"
              f' tab-separated columns: {line.strip()}',
              file=sys.stderr,
          )
      params['identifiers'] = '\r'.join(valid_lines)
      if not params['identifiers']:
        print('Error: No valid data found in input file.', file=sys.stderr)
        sys.exit(1)
    except OSError as e:
      print(f'Error reading {args.input_file}: {e}', file=sys.stderr)
      sys.exit(1)
    url = _url('valuesranks_enrichment_submit', format_type='json')
    call_api(url, params, args.output)

  elif args.command == 'valuesranks-status':
    url = _url('valuesranks_enrichment_status', format_type='json')
    params['api_key'] = args.api_key
    if args.job_id:
      params['job_id'] = args.job_id

    if not args.wait or not args.job_id:
      call_api(url, params, args.output)
      return

    # Loop until the call completes.
    while True:
      response = call_api(url, params, args.output)
      try:
        data = response.json()
      except ValueError:
        print('Error parsing status response.', file=sys.stderr)
        sys.exit(1)

      if not isinstance(data, list) or len(data) == 0:
        print(f'Unexpected response format: {data}', file=sys.stderr)
        sys.exit(1)

      job_info = data[0]
      status = job_info.get('status')
      if status == 'success':
        if download_url := job_info.get('download_url'):
          print(
              f'Job success. Downloading from {download_url} to {args.output}'
          )
          try:
            content = _CLIENT.fetch_bytes(download_url)
          except http_client.HttpError as e:
            print(
                f'Download Error (HTTP {e.status_code}): {e}',
                file=sys.stderr,
            )
            sys.exit(1)
          with open(args.output, 'wb') as f:
            f.write(content)
          break
        else:
          print('Success but no download URL found.', file=sys.stderr)
          break
      elif status == 'running' or status == 'queued':
        print(f'Job still {status}... waiting 5 seconds.')
        time.sleep(5)
      else:
        print(f'Job failed or unknown status: {status}', file=sys.stderr)
        sys.exit(1)


if __name__ == '__main__':
  main()

Requirements and compatibility

Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta

“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.

Needs: Needs Python

Security

What our scanner noticed· Low risk

  • Scripts that your agent may run

This skill includes scripts that your agent may run. Read them before you use it.

A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.

Attribution and licence

Published by
Google DeepMind
Publisher
Google DeepMind (Official)
Source
google-deepmind/science-skills · skills/string_database · commit 4de6786
Licence
Apache License 2.0 (redistribution allowed)
  • LICENSE (added by AutoGineer from LICENSE)
  • ATTRIBUTION.md (written by AutoGineer)
Synced

AutoGineer is not affiliated with or endorsed by Google DeepMind or Google DeepMind.

Download ZIP

The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download string-database.zip