Back to List

Bio-LLM MCP Agent β€” A Practical Example of Autonomously Orchestrating Experimental Tools with the Model Context Protocol

A practical pipeline demonstrating how Claude Agent autonomously calls bioinformatics web services such as NCBI BLAST, UniProt, and PubMed using the Anthropic Model Context Protocol (MCP) standard. It covers standard tool calling, context management, error handling, and an automated loop for reproducing paper methods. A new interface for Bio R&D.

Advanced
|
40min
|
Verified (2026-07)
Progress0/15 (0%)

Bio-LLM MCP Agent β€” Implementing a Practical Workflow for Autonomous Experiment Tool Orchestration with Model Context Protocol

This section concludes the Phase 4 Pilot Track. In the previous sections (01 Clinical IE, 02 Protein Embeddings, 03 Cell Segmentation, 11 Boltz-2 Structure & Affinity), we built a hard-core implementation for each domain and pipeline. However, real-world R&D doesn't end with a single pipeline. It involves reading papers, querying sequences, searching for structures, designing experiments, reproducing results, and diagnosing failures. This section builds a practical workflow where a Claude Agent autonomously orchestrates these multiple tools using a standardized protocol (MCP).

πŸ“š Recommended Prerequisite Reading (Strongly Recommended)

This section is the concluding part of the AIΓ—Bio hardcore advanced track. We strongly recommend that you review the following DryBench sections before proceeding.

Without reviewing the prerequisite materials, it will be difficult to follow the practical code in this section, as it proceeds without re-explaining the agent loop principle, context compression/summarization strategies, and the practical patterns of tool use in Claude Code.


We Learned This in Our DryBench

In DryBench ai-native #9, we learned that an agent is defined by four components: LLM + Tools + Loop + Memory, and that each tool call is managed by a forced schema, similar to a function signature. In #10, we learned how context is compressed and offloaded during long sessions. In #14, we learned that Claude Code is a tool that implements all these principles in a practical way in the CLI.

However, in real-world bio R&D, it's highly inefficient to define each tool individually, and to re-implement authentication, retries, timeouts, and response parsing for each project. Anthropic's Model Context Protocol (MCP), announced in November 2024, is an open protocol to standardize this repetition [1]. A single MCP server exposes the same set of tools to multiple clients (Claude Desktop, Claude Code, Cursor, etc.), and the server and client consistently discover, call, and handle responses. This section applies that protocol in a practical way to the bio domain.

Defining the Hardcore Problem

Practical R&D Scenario

A researcher has identified a new candidate gene related to a specific disease. To determine if this gene is truly interesting, they need to perform at least the following tasks:

  1. Submit the gene sequence to NCBI BLAST to find homologs.
  2. Query the UniProt information for the top hit to check its function.
  3. Search PubMed for relevant papers from the last 5 years.
  4. Read the methods section of the top papers and determine if they can be reproduced.
  5. If reproducible, clone the GitHub repository, set up the environment, adapt it to their own data, and verify the results.

In the past, this process involved a person moving back and forth between the browser, terminal, and editor for each step. The goal of this section is to have a Claude Agent autonomously execute all five steps and return the results in a structured report. In this process, the person only intervenes at critical moments (e.g., "Should we try to reproduce the methods in this paper?").

Why is MCP Needed?

Even without MCP, the above workflow can be implemented using only tool use. However, using MCP offers the following advantages:

  • Reusability: Once an NCBI BLAST server is created, all MCP clients, including Claude Desktop, Claude Code, and Cursor, can use it immediately.
  • Standardized Authentication, Error, and Payload Specifications: Based on JSON-RPC 2.0. No need to reinvent it for each domain.
  • Ecosystem: You can instantly build a complex agent by combining MCP servers (e.g., file system, GitHub, Slack) created by others.
  • Separated Processes: The server communicates via stdin/stdout or SSE, isolating crashes from the client.

Target Metrics for This Section

  • Autonomously execute all five steps in a single Claude session: with no more than three human interventions.
  • NCBI BLAST, UniProt, and PubMed MCP servers: Utilize existing open-community implementations or implement a minimal custom implementation.
  • Error Recovery: Automatically retry with exponential backoff in case of rate limits, network failures, or parsing failures.
  • Reproducibility: Session logs, tool call history, and the final report are saved in JSON format for subsequent verification.

Tool Stack and Infrastructure Requirements

ToolRoleLicense
mcp Python SDK (pip install mcp)Standard implementation of MCP server/clientMIT (Anthropic official)
Anthropic Claude API (anthropic)LLM + tool use orchestratorCommercial (usage-based billing)
BiopythonNCBI E-utilities wrapperBiopython License
requestsUniProt REST clientApache 2.0
Docker (Optional)MCP server containerized deploymentApache 2.0
Anthropic Skills (Optional)Domain-specific skill registrationAnthropic Service

Infrastructure Requirements:

  • Can run without a GPU (LLM is API-based, tools are web services).
  • Local CPU with 2 cores and 4GB of RAM or more.
  • Network: Access to NCBI, UniProt, and PubMed APIs (must adhere to rate limits).

Estimated Cost for Learners: Based on the Claude API pricing [2], running a single scenario from start to finish will cost approximately 5to5 to 20 (depending on the number of tool calls). No additional costs will be incurred if you comply with the individual public APIs (NCBI 3 req/s, UniProt none, PubMed basic free).

Practical Pipeline Implementation

Overall flow:

mermaid

Step 1. Minimal MCP Server Implementation β€” UniProt REST Example

The MCP server is a JSON-RPC 2.0 process that communicates via stdin/stdout. The Python SDK handles most of the boilerplate [3].

python
"""uniprot_mcp_server.py β€” Exposes the UniProt REST API as an MCP tool.
An MCP server can expose multiple tools. Here are three:
- search_protein: Search for proteins using a text query
- get_protein_details: Retrieve detailed information by accession
- get_sequence: Retrieve the FASTA sequence by accession
"""
import asyncio
import json
from typing import Any
import requests
from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp.types import Tool, TextContent
UNIPROT_BASE = "https://rest.uniprot.org"
server = Server("uniprot-mcp")
@server.list_tools()
async def list_tools() -> list[Tool]:
return [
Tool(
name="search_protein",
description="Search for proteins in UniProt using a text query. Returns the top K results.",
inputSchema={
"type": "object",
"properties": {
"query": {"type": "string", "description": "Search term (e.g., 'p53 human')"},
"limit": {"type": "integer", "default": 10},
},
"required": ["query"],
},
),
Tool(
name="get_protein_details",
description="Retrieve detailed information for a protein from UniProt using its accession.",
inputSchema={
"type": "object",
"properties": {"accession": {"type": "string"}},
"required": ["accession"],
},
),
Tool(
name="get_sequence",
description="Retrieve the FASTA sequence for a UniProt accession.",
inputSchema={
"type": "object",
"properties": {"accession": {"type": "string"}},
"required": ["accession"],
},
),
]
@server.call_tool()
async def call_tool(name: str, arguments: dict[str, Any]) -> list[TextContent]:
"""Dispatches to the appropriate function based on the tool name. In a real-world scenario, it is recommended to separate each function."""
try:
if name == "search_protein":
result = _search_protein(arguments["query"], arguments.get("limit", 10))
elif name == "get_protein_details":
result = _get_details(arguments["accession"])
elif name == "get_sequence":
result = _get_sequence(arguments["accession"])
else:
raise ValueError(f"Unknown tool: {name}")
return [TextContent(type="text", text=json.dumps(result, ensure_ascii=False, indent=2))]
except requests.RequestException as e:
return [TextContent(type="text", text=json.dumps({"error": f"UniProt API failed: {e}"}))]
except Exception as e:
return [TextContent(type="text", text=json.dumps({"error": str(e)}))]
def _search_protein(query: str, limit: int) -> dict:
resp = requests.get(
f"{UNIPROT_BASE}/uniprotkb/search",
params={
"query": query,
"format": "json",
"size": limit,
"fields": "accession,id,protein_name,organism_name,length",
},
timeout=30,
)
resp.raise_for_status()
results = resp.json().get("results", [])
return {"count": len(results), "results": results}
def _get_details(accession: str) -> dict:
resp = requests.get(
f"{UNIPROT_BASE}/uniprotkb/{accession}.json",
timeout=30,
)
resp.raise_for_status()
data = resp.json()
return {
"accession": data.get("primaryAccession"),
"protein_name": data.get("proteinDescription", {}),
"organism": data.get("organism", {}),
"length": data.get("sequence", {}).get("length"),
"function": [
c["texts"][0]["value"]
for c in data.get("comments", [])
if c.get("commentType") == "FUNCTION"
],
}
def _get_sequence(accession: str) -> dict:
resp = requests.get(f"{UNIPROT_BASE}/uniprotkb/{accession}.fasta", timeout=30)
resp.raise_for_status()
lines = resp.text.strip().split("\n")
return {
"accession": accession,
"header": lines[0],
"sequence": "".join(lines[1:]),
}
async def main():
async with stdio_server() as (read_stream, write_stream):
await server.run(read_stream, write_stream, server.create_initialization_options())
if __name__ == "__main__":
asyncio.run(main())

Step 2. Second MCP Server β€” PubMed Search

python
"""pubmed_mcp_server.py β€” MCP tool for PubMed E-utilities."""
import asyncio
import json
from xml.etree import ElementTree as ET
import requests
from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp.types import Tool, TextContent
EUTILS_BASE = "https://eutils.ncbi.nlm.nih.gov/entrez/eutils"
server = Server("pubmed-mcp")
@server.list_tools()
async def list_tools() -> list[Tool]:
return [
Tool(
name="search_pubmed",
description="Search PubMed for a list of papers (PMIDs) using a search term.",
inputSchema={
"type": "object",
"properties": {
"query": {"type": "string"},
"max_results": {"type": "integer", "default": 20},
"date_range_years": {"type": "integer", "default": 5},
},
"required": ["query"],
},
),
Tool(
name="fetch_abstracts",
description="Retrieve detailed information (abstracts, authors, journals) for a list of PMIDs.",
inputSchema={
"type": "object",
"properties": {
"pmids": {"type": "array", "items": {"type": "string"}},
},
"required": ["pmids"],
},
),
]
@server.call_tool()
async def call_tool(name: str, arguments: dict) -> list[TextContent]:
try:
if name == "search_pubmed":
result = _search(arguments["query"], arguments.get("max_results", 20), arguments.get("date_range_years", 5))
elif name == "fetch_abstracts":
result = _fetch(arguments["pmids"])
else:
raise ValueError(f"Unknown tool: {name}")
return [TextContent(type="text", text=json.dumps(result, ensure_ascii=False, indent=2))]
except Exception as e:
return [TextContent(type="text", text=json.dumps({"error": str(e)}))]
def _search(query: str, max_results: int, date_range_years: int) -> dict:
esearch = requests.get(
f"{EUTILS_BASE}/esearch.fcgi",
params={
"db": "pubmed",
"term": query,
"retmax": max_results,
"reldate": date_range_years * 365,
"datetype": "pdat",
"retmode": "json",
},
timeout=30,
)
esearch.raise_for_status()
pmids = esearch.json().get("esearchresult", {}).get("idlist", [])
return {"query": query, "count": len(pmids), "pmids": pmids}
def _fetch(pmids: list[str]) -> list[dict]:
if not pmids:
return []
efetch = requests.get(
f"{EUTILS_BASE}/efetch.fcgi",
params={"db": "pubmed", "id": ",".join(pmids), "rettype": "abstract", "retmode": "xml"},
timeout=60,
)
efetch.raise_for_status()
root = ET.fromstring(efetch.content)
articles = []
for art in root.findall(".//PubmedArticle"):
pmid = art.findtext(".//PMID")
title = art.findtext(".//ArticleTitle") or ""
abstract = " ".join(t.text or "" for t in art.findall(".//AbstractText"))
authors = [
f"{a.findtext('LastName') or ''} {a.findtext('Initials') or ''}".strip()
for a in art.findall(".//Author")
]
journal = art.findtext(".//Journal/Title") or ""
year = art.findtext(".//PubDate/Year") or ""
articles.append({
"pmid": pmid,
"title": title,
"abstract": abstract,
"authors": authors[:10],
"journal": journal,
"year": year,
})
return articles
async def main():
async with stdio_server() as (read_stream, write_stream):
await server.run(read_stream, write_stream, server.create_initialization_options())
if __name__ == "__main__":
asyncio.run(main())

Step 3. NCBI BLAST MCP Server (Summary)

BLAST has a long response time, so an asynchronous polling pattern is required.

python
"""blast_mcp_server.py β€” NCBI BLAST QBlast (summary, only the core logic)."""
import time
import re
import requests
BLAST_URL = "https://blast.ncbi.nlm.nih.gov/Blast.cgi"
def submit_blast(sequence: str, program: str = "blastp", database: str = "nr") -> str:
"""Returns the QBlast RID. Polling is required afterward."""
resp = requests.post(BLAST_URL, data={
"CMD": "Put",
"PROGRAM": program,
"DATABASE": database,
"QUERY": sequence,
}, timeout=60)
resp.raise_for_status()
m = re.search(r"RID = (\S+)", resp.text)
if not m:
raise RuntimeError("QBlast RID parsing failed")
return m.group(1)
def poll_blast(rid: str, poll_interval: int = 30, max_wait: int = 600) -> str:
"""Waits for the BLAST result. Returns XML when complete."""
start = time.time()
while time.time() - start < max_wait:
resp = requests.get(BLAST_URL, params={"CMD": "Get", "RID": rid, "FORMAT_OBJECT": "SearchInfo"}, timeout=30)
if "Status=READY" in resp.text:
xml_resp = requests.get(BLAST_URL, params={"CMD": "Get", "RID": rid, "FORMAT_TYPE": "XML"}, timeout=60)
xml_resp.raise_for_status()
return xml_resp.text
elif "Status=FAILED" in resp.text:
raise RuntimeError(f"BLAST failed RID={rid}")
time.sleep(poll_interval)
raise TimeoutError(f"BLAST timeout RID={rid}")
# The MCP tool wrapper follows the same pattern as the UniProt and PubMed servers. The code is omitted for brevity.

Step 4. Claude Agent Client β€” MCP Orchestration

Claude Agent connects to multiple MCP servers simultaneously and autonomously calls tools.

python
"""bio_agent.py β€” Claude Agent + multi-MCP server orchestration."""
import asyncio
from contextlib import AsyncExitStack
import anthropic
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
class BioMCPAgent:
"""Claude Agent that orchestrates multiple MCP servers."""
def __init__(self, model: str = "claude-sonnet-4-5", max_turns: int = 20):
self.anthropic = anthropic.Anthropic()
self.model = model
self.max_turns = max_turns
self.sessions: dict[str, ClientSession] = {}
self.all_tools: list[dict] = []
self._exit_stack: AsyncExitStack | None = None
async def connect_server(self, name: str, command: str, args: list[str]) -> None:
"""Connects to an MCP server. Spawns the process and retrieves the tool list."""
params = StdioServerParameters(command=command, args=args)
stdio_transport = await self._exit_stack.enter_async_context(stdio_client(params))
session = await self._exit_stack.enter_async_context(ClientSession(*stdio_transport))
await session.initialize()
tools_result = await session.list_tools()
# Converts to Claude's tool use schema
for tool in tools_result.tools:
self.all_tools.append({
"name": f"{name}__{tool.name}", # Prevents collisions by prefixing with the server name
"description": tool.description,
"input_schema": tool.inputSchema,
})
self.sessions[f"{name}__{tool.name}"] = session
async def __aenter__(self):
self._exit_stack = AsyncExitStack()
await self._exit_stack.__aenter__()
return self
async def __aexit__(self, exc_type, exc_val, exc_tb):
await self._exit_stack.__aexit__(exc_type, exc_val, exc_tb)
async def run(self, user_query: str, system_prompt: str) -> dict:
"""Runs an autonomous loop. Claude repeats until stop_reason="end_turn"."""
messages = [{"role": "user", "content": user_query}]
tool_log = []
for turn in range(self.max_turns):
response = self.anthropic.messages.create(
model=self.model,
max_tokens=4096,
system=system_prompt,
tools=self.all_tools,
messages=messages,
)
messages.append({"role": "assistant", "content": response.content})
if response.stop_reason == "end_turn":
break
if response.stop_reason != "tool_use":
continue
# Processes the tool_use block
tool_results = []
for block in response.content:
if block.type != "tool_use":
continue
session = self.sessions.get(block.name)
if session is None:
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": f"Unknown tool: {block.name}",
"is_error": True,
})
continue
try:
# Calls the tool using the original name after removing the server name prefix
original_name = block.name.split("__", 1)[1]
result = await session.call_tool(original_name, block.input)
content_text = "\n".join(
c.text for c in result.content if hasattr(c, "text")
)
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": content_text[:10000], # Saves context
})
tool_log.append({
"tool": block.name,
"input": block.input,
"output_preview": content_text[:500],
})
except Exception as e:
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": f"Tool call failed: {e}",
"is_error": True,
})
messages.append({"role": "user", "content": tool_results})
# Extracts the final text
final_text = ""
for block in response.content:
if hasattr(block, "text"):
final_text += block.text
return {"final_answer": final_text, "tool_log": tool_log, "turns": turn + 1}
SYSTEM_PROMPT = """You are a bioinformatics research assistant.
You understand user requests and autonomously call the necessary MCP tools (uniprot__, pubmed__, blast__)
to answer based on evidence.
Principles:
1. Do not create facts. All claims must be supported by tool call results.
2. Always include the source (UniProt accession, PMID, etc.) in the answer.
3. If a tool call fails, try alternative methods, but also inform the user of the failure.
4. Minimize unnecessary tool calls (to save context and cost).
"""
async def main():
async with BioMCPAgent() as agent:
await agent.connect_server("uniprot", "python", ["uniprot_mcp_server.py"])
await agent.connect_server("pubmed", "python", ["pubmed_mcp_server.py"])
# await agent.connect_server("blast", "python", ["blast_mcp_server.py"])
result = await agent.run(
user_query="Summarize the main findings of the top 3 recent papers on human TP53, and compare them with the functional annotations of this protein in UniProt to see if there are any new insights.",
system_prompt=SYSTEM_PROMPT,
)
print("=== Final Answer ===")
print(result["final_answer"])
print(f"\n=== Turns: {result['turns']} ===")
print(f"=== Tool calls: {len(result['tool_log'])} ===")
for entry in result["tool_log"]:
print(f" - {entry['tool']}: {entry['input']}")
if __name__ == "__main__":
asyncio.run(main())

Step 5. Absorbing the Paper Reproduction Tool (Replacing P-02)

It was decided in section 7-1 that P-02 (the paper reproduction agent) would be absorbed into this section. The reproduction tool is provided as a separate MCP server.

python
"""paper_repro_mcp_server.py β€” Set of tools for paper reproduction (summary)."""
# Tool 1: fetch_paper_pdf β€” Fetch PDF by DOI (prioritize open access)
# Tool 2: extract_method_section β€” Extract text from the method section of the PDF
# Tool 3: find_github_repo β€” Search for a GitHub URL in the paper body and supplementary materials
# Tool 4: clone_repo β€” Git clone (in a sandbox folder)
# Tool 5: setup_env β€” Detect and attempt to install requirements.txt or conda environment
# Tool 6: run_reproduction β€” Run the standard entry point of the repository (README or setup.py)
# Each tool follows the same MCP pattern as the UniProt and PubMed servers.
# For safety, cloning and execution must be done in a separate container (Docker sandbox).

By adding this reproduction server tool to the BioMCPAgent using connect_server("paper_repro", ...), the autonomous execution loop, including paper reproduction, will be complete.

Anthropic Skills Integration (Optional Enhancement)

Anthropic Skills is a method for registering domain-specific toolkits within the Claude Sonnet family [4]. The MCP server combination described above can be packaged as a single "Bio Research" Skill and readily activated in Claude Desktop or the Claude Code CLI.

yaml
# skills/bio-research/skill.yaml
name: bio-research
version: 1.0.0
description: Bioinformatics research autonomous agent. Integrates UniProt, PubMed, BLAST, and paper reproduction.
mcp_servers:
  - name: uniprot
    command: python
    args: [/opt/mcp/uniprot_mcp_server.py]
  - name: pubmed
    command: python
    args: [/opt/mcp/pubmed_mcp_server.py]
  - name: blast
    command: python
    args: [/opt/mcp/blast_mcp_server.py]
  - name: paper_repro
    command: python
    args: [/opt/mcp/paper_repro_mcp_server.py]
system_prompt: |
  You are a bioinformatics research assistant. ...

Performance, Cost, and Known Failure Cases

Performance Reference (Based on Publicly Available Data)

ApproachScenarioTimeCostSource
Manual (Human, Browsing)5-step gene research1-3 hours0Empirical baseline
Claude Agent + Tool Use (Without MCP)Same5-10 minutes3-10 USDAnthropic tool use benchmark [5]
Claude Agent + MCP (This Article)Same3-7 minutes3-10 USDMCPmed paper evidence [6]
GPT-4o + Function CallingSame5-10 minutes5-15 USDOpenAI docs [7]

Estimated Reproduction Cost for Learners

  • Claude API: 5-20 USD per scenario (depending on the number of turns, tool repetitions, and result size).
  • MCP server infrastructure: Free for local execution. Approximately 5-10 USD per month for remote deployment on a small VPS.
  • NCBI, UniProt, PubMed: Free (subject to rate limits).

Three Known Failure Cases (Collected from Community and Papers)

  1. NCBI BLAST rate limit exceeded Symptom: Calling BLAST QBlast multiple times in a short period results in a 429 error or temporary blocking. Cause: NCBI policy limits requests to 3 per second (10 req/s when an API key is registered). Mitigation: (a) Implement a minimum interval of time.sleep(1), (b) Register an NCBI API key and pass it as the api_key parameter, (c) It is recommended to run batch searches during off-peak hours (nights or weekends). Source: NCBI E-utilities documentation "usage guidelines" [8].

  2. MCP tool name collision Symptom: If multiple MCP servers expose the same tool name, the client will not know which one to call. Cause: The MCP specification only guarantees the uniqueness of tool names within a server. Mitigation: As shown in the code, prefix tool names on the client side with {server_name}__{tool_name}. Source: MCP GitHub Discussions β€” "tool name collision" [9].

  3. Claude Agent enters an infinite loop by incorrectly calling tools Symptom: In certain tasks, the Agent continuously re-calls the same tool and cannot reach a stop_reason="end_turn". Cause: (a) The condition for "when to stop" is not clearly defined in the system prompt, (b) The tool's response always returns only a partial answer, or (c) There is no maximum turn limit. Mitigation: (a) Set a hard limit on max_turns (20 in this code), (b) Explicitly state in the system prompt that the agent should "report to the user after 3 failed attempts," (c) Summarize the history of tool calls in the context to detect repetitions. Source: Anthropic Cookbook β€” agent loop patterns [10].

Expansion Ideas

  • Custom MCP server series: Fetch PDB structure files, search ChEMBL compounds, access GEO transcriptomics data, Ensembl variants, etc. Continued in Part 15.
  • Multi-agent collaboration: Separate research, visualization, and report writing agents into separate sessions and share results using MCP.
  • Remote MCP server deployment: Host MCP servers on Cloudflare Workers, AWS Lambda, or Docker Swarm to share them among multiple users.
  • Wet-lab integration: Expose APIs for laboratory equipment (e.g., liquid handler robots) as MCP tools to automate experimental planning.

Next Part

  • Part 15 bio-mcp-server-suite: Expands the servers from this article to build a series of 5-7 custom MCP servers, including PDB, ChEMBL, and GEO.
  • Part 09 llm-vendor-benchmark: Uses the same MCP tool set to compare the accuracy of tool use with Claude, GPT-4o, and Gemini.
  • Part 10 med-llm-reproduction: Automates the reproduction of the MCP-based benchmark.
  • Part 01 clinical-notes-ie-llm: Exposes the clinical IE pipeline from Part 01 as an MCP tool, allowing the agent in this article to call it autonomously.

References

  1. Anthropic. "Model Context Protocol." Official documentation: https://modelcontextprotocol.io/ / Announcement blog: https://www.anthropic.com/news/model-context-protocol
  2. Anthropic Claude API pricing: https://www.anthropic.com/pricing
  3. MCP Python SDK: https://github.com/modelcontextprotocol/python-sdk
  4. Anthropic Skills documentation: https://docs.anthropic.com/en/docs/build-with-claude/skills
  5. Anthropic Tool Use documentation: https://docs.anthropic.com/en/docs/agents-and-tools/tool-use/overview
  6. Wagner F, Bittrich S. "MCPmed: a call for Model Context Protocol-enabled bioinformatics web services for LLM-driven discovery." Briefings in Bioinformatics 2026. https://academic.oup.com/bib/article/27/1/bbag076/8495038
  7. OpenAI function calling: https://platform.openai.com/docs/guides/function-calling
  8. NCBI E-utilities usage guidelines: https://www.ncbi.nlm.nih.gov/books/NBK25497/
  9. MCP GitHub Discussions: https://github.com/modelcontextprotocol/specification/discussions
  10. Anthropic Cookbook (agent patterns): https://github.com/anthropics/anthropic-cookbook
  11. UniProt REST API: https://www.uniprot.org/help/api
  12. NCBI BLAST QBlast: https://ncbi.github.io/blast-cloud/dev/api.html
  13. Biopython E-utilities wrapper: https://biopython.org/wiki/EUtils
  14. MCP official server registry: https://github.com/modelcontextprotocol/servers
  15. Claude Code (Anthropic official): https://claude.com/product/claude-code

πŸ’¬ Questions & Comments

0 comments

You can post without signing in. Guest comments cannot be edited or deleted by their author.

0/2000

Loading...