guohanghui commited on
Commit
9cfe70b
·
verified ·
1 Parent(s): 130a70e

Update biopython/mcp_output/mcp_plugin/mcp_service.py

Browse files
biopython/mcp_output/mcp_plugin/mcp_service.py CHANGED
@@ -359,38 +359,37 @@ def blast_get_result(payload: dict):
359
  @mcp.tool(name="blast_search", description="Search NCBI database using BLAST to find similar sequences")
360
  def blast_search(payload: dict):
361
  """
362
- 使用 BLAST 搜索相似序列
363
  Required fields: sequence
364
- Optional fields: database (nt/nr/refseq_rna), program (blastn/blastp), hitlist_size (default 20), expect (default 1e-10)
365
-
366
- Database recommendations:
367
- - refseq_rna: Faster, curated sequences (recommended for genes)
368
- - nt: Comprehensive but VERY SLOW (can take 5-15 minutes)
369
- - nr: For protein sequences
370
  """
371
  try:
372
  sequence = str(payload.get("sequence", "")).strip()
373
  if not sequence:
374
  return {"success": False, "result": None, "error": "sequence is required"}
375
-
376
- # Clean sequence
377
  sequence = "".join(sequence.split()).upper()
378
-
379
- # 默认使用更快的 refseq_rna 据库
380
  database = payload.get("database", "refseq_rna")
381
  program = payload.get("program", "blastn")
382
  hitlist_size = int(payload.get("hitlist_size", 20))
383
  expect = float(payload.get("expect", 1e-10))
384
-
385
- # 数据库选择建议
386
  if database == "nt":
387
- print("⚠️ Warning: 'nt' database is very large and may take 5-15 minutes!")
388
- print("💡 Consider using 'refseq_rna' for faster results (curated sequences)")
389
-
390
  print(f"🔍 Submitting BLAST search: {len(sequence)} bp, database={database}, hits={hitlist_size}")
391
- print(f"⏳ Please wait... This may take 1-15 minutes depending on database size")
392
-
393
- # Submit BLAST request with timeout handling
394
  try:
395
  handle = NCBIWWW.qblast(
396
  program=program,
@@ -400,47 +399,45 @@ def blast_search(payload: dict):
400
  expect=expect,
401
  format_type="XML"
402
  )
403
-
404
- blast_record = NCBIXML.read(handle)
405
- handle.close()
406
-
407
- print(f"✅ BLAST search completed: {len(blast_record.alignments)} alignments found")
408
  except Exception as blast_error:
409
- # 如果使用 nt 失败,建议使用更快的数据库
410
- if database == "nt":
411
- return {
412
- "success": False,
413
- "result": None,
414
- "error": f"BLAST timeout or error with 'nt' database. Please try 'refseq_rna' instead. Original error: {str(blast_error)}"
415
- }
416
- else:
417
- raise blast_error
418
-
419
  hits = []
420
- for idx, alignment in enumerate(blast_record.alignments[:hitlist_size]):
421
- print(idx)
422
- print(alignment)
423
- if not alignment.hsps:
424
- continue
425
- print("✅✅✅")
426
- hsp = alignment.hsps[0]
427
- align_len = int(hsp.align_length)
428
- identities = int(hsp.identities)
429
- identity_pct = (identities / align_len * 100.0) if align_len else 0
430
-
431
- hits.append({
432
- "rank": idx + 1,
433
- "accession": str(alignment.accession),
434
- "hit_id": str(alignment.hit_id),
435
- "hit_def": str(alignment.hit_def),
436
- "length": int(alignment.length),
437
- "bit_score": float(hsp.bits),
438
- "evalue": float(hsp.expect),
439
- "identity_pct": float(round(identity_pct, 2)),
440
- "identities": int(identities),
441
- "align_length": int(align_len)
442
- })
443
- print("✅✅✅✅✅✅")
 
 
 
 
 
 
444
  result = {
445
  "query_length": int(len(sequence)),
446
  "database": str(database),
@@ -448,8 +445,9 @@ def blast_search(payload: dict):
448
  "total_hits": int(len(hits)),
449
  "hits": hits
450
  }
451
-
452
  return {"success": True, "result": result, "error": None}
 
453
  except Exception as e:
454
  return {"success": False, "result": None, "error": str(e)}
455
 
 
359
  @mcp.tool(name="blast_search", description="Search NCBI database using BLAST to find similar sequences")
360
  def blast_search(payload: dict):
361
  """
362
+ 使用 BLAST 搜索相似序列(稳定版)
363
  Required fields: sequence
364
+ Optional fields:
365
+ - database (nt/nr/refseq_rna, default refseq_rna)
366
+ - program (blastn/blastp, default blastn)
367
+ - hitlist_size (default 20)
368
+ - expect (default 1e-10)
 
369
  """
370
  try:
371
  sequence = str(payload.get("sequence", "")).strip()
372
  if not sequence:
373
  return {"success": False, "result": None, "error": "sequence is required"}
374
+
375
+ # 清理序列
376
  sequence = "".join(sequence.split()).upper()
377
+
378
+ #
379
  database = payload.get("database", "refseq_rna")
380
  program = payload.get("program", "blastn")
381
  hitlist_size = int(payload.get("hitlist_size", 20))
382
  expect = float(payload.get("expect", 1e-10))
383
+
384
+ # 提示信息
385
  if database == "nt":
386
+ print("⚠️ Warning: 'nt' database is very large and may take 5-15 minutes!")
387
+ print("💡 Consider using 'refseq_rna' for faster results")
388
+
389
  print(f"🔍 Submitting BLAST search: {len(sequence)} bp, database={database}, hits={hitlist_size}")
390
+ print("⏳ Please wait...")
391
+
392
+ # 提交 BLAST
393
  try:
394
  handle = NCBIWWW.qblast(
395
  program=program,
 
399
  expect=expect,
400
  format_type="XML"
401
  )
 
 
 
 
 
402
  except Exception as blast_error:
403
+ return {
404
+ "success": False,
405
+ "result": None,
406
+ "error": f"BLAST submission failed: {str(blast_error)}"
407
+ }
408
+
409
+ # 迭代解析 XML
 
 
 
410
  hits = []
411
+ for blast_record in NCBIXML.parse(handle):
412
+ for idx, alignment in enumerate(blast_record.alignments[:hitlist_size]):
413
+ if not alignment.hsps:
414
+ continue
415
+
416
+ hsp = alignment.hsps[0]
417
+ align_len = int(hsp.align_length)
418
+ identities = int(hsp.identities)
419
+ identity_pct = round((identities / align_len) * 100, 2) if align_len else 0
420
+
421
+ hits.append({
422
+ "rank": idx + 1,
423
+ "accession": str(alignment.accession),
424
+ "hit_id": str(alignment.hit_id),
425
+ "hit_def": str(alignment.hit_def),
426
+ "length": int(alignment.length),
427
+ "bit_score": float(hsp.bits),
428
+ "evalue": float(hsp.expect),
429
+ "identity_pct": float(identity_pct),
430
+ "identities": int(identities),
431
+ "align_length": int(align_len)
432
+ })
433
+
434
+ # 输出进度,保持 SSE 活跃
435
+ print(f"Processing alignment {idx+1}/{min(hitlist_size, len(blast_record.alignments))}")
436
+
437
+ handle.close()
438
+ print(f"✅ BLAST search completed: {len(hits)} alignments found")
439
+
440
+ # 构建返回结果
441
  result = {
442
  "query_length": int(len(sequence)),
443
  "database": str(database),
 
445
  "total_hits": int(len(hits)),
446
  "hits": hits
447
  }
448
+
449
  return {"success": True, "result": result, "error": None}
450
+
451
  except Exception as e:
452
  return {"success": False, "result": None, "error": str(e)}
453