File size: 4,834 Bytes
c088eff
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
"""Minimal reference implementation of the BioDesignBench MCP contract.

Submitters who want to evaluate their own tool implementations against
the BioDesignBench leaderboard can fork this file, plug in their own
logic for each tool, deploy it behind a public HTTPS URL, and paste
that URL into the submission form under "Advanced: Custom MCP".

The leaderboard's agent loop will POST each tool invocation to your
endpoint and treat the JSON response as the tool result. The MCP never
sees the raw task description or evaluation criteria — only the
operational arguments the agent chooses to pass (a protein sequence,
a PDB path, a set of hotspot residues, etc.).

Contract:

    POST <your-url>/
    Authorization: Bearer <optional shared token>
    Content-Type: application/json

    {
      "name": "<tool_name>",          # one of the 17 tool names
      "arguments": { ... }            # per-tool JSON object
    }

    Response: arbitrary JSON object describing the tool output.
    Errors should be reported in a top-level "error" field rather
    than via HTTP status codes.

Install:
    pip install fastapi uvicorn

Run (locally, with ngrok for a public URL):
    uvicorn example_mcp_server:app --host 0.0.0.0 --port 8000
    ngrok http 8000

Deploy (Modal example):
    modal deploy example_mcp_server.py  # see bdb-boltz as a template

Tool name list (17 total) — the full JSON Schema for each lives in
`mcp_tool_schemas.json` in this repo:

    design_binder, analyze_interface, validate_design, optimize_sequence,
    suggest_hotspots, get_design_status, predict_complex, predict_structure,
    score_stability, energy_minimize, generate_backbone, rosetta_score,
    rosetta_relax, rosetta_interface_score, rosetta_design,
    predict_structure_boltz, predict_affinity_boltz
"""

from __future__ import annotations

import os
from typing import Any

from fastapi import FastAPI, Header, HTTPException
from pydantic import BaseModel

app = FastAPI(title="BioDesignBench MCP (example stub)")

SHARED_TOKEN = os.environ.get("BDB_MCP_TOKEN", "")


class MCPRequest(BaseModel):
    name: str
    arguments: dict[str, Any] = {}


# ---------------------------------------------------------------------------
#  Tool handlers (REPLACE THESE STUBS WITH YOUR ACTUAL IMPLEMENTATIONS)
# ---------------------------------------------------------------------------


def handle_predict_structure(args: dict) -> dict:
    """Predict the structure of a single protein sequence.

    Real implementations would call AlphaFold2, ESMFold, Boltz, etc.
    """
    sequence = args.get("sequence") or ""
    if not sequence:
        return {"error": "predict_structure requires a 'sequence' argument"}
    # TODO: replace this stub with your structure predictor.
    return {
        "pdb": ">dummy\nATOM ...",
        "pLDDT": 0.0,
        "pTM": 0.0,
        "note": "stub implementation -- replace with your predictor",
    }


def handle_design_binder(args: dict) -> dict:
    """Design a protein binder against a target. Real implementations
    would call RFdiffusion followed by ProteinMPNN and AlphaFold2."""
    return {"error": "design_binder not implemented in this stub"}


def handle_score_stability(args: dict) -> dict:
    """Score single-point stability. Real implementations might call
    Rosetta, DDG_predictor, or a learned model."""
    return {"error": "score_stability not implemented in this stub"}


TOOL_HANDLERS = {
    "predict_structure": handle_predict_structure,
    "design_binder": handle_design_binder,
    "score_stability": handle_score_stability,
    # ... add handlers for the other 14 tools here
}


# ---------------------------------------------------------------------------
#  Dispatcher
# ---------------------------------------------------------------------------


@app.post("/")
def call_tool(
    req: MCPRequest,
    authorization: str | None = Header(default=None),
) -> dict:
    if SHARED_TOKEN:
        bearer = (authorization or "").removeprefix("Bearer ").strip()
        if bearer != SHARED_TOKEN:
            raise HTTPException(status_code=401, detail="Unauthorized")

    handler = TOOL_HANDLERS.get(req.name)
    if handler is None:
        return {
            "error": f"Unknown tool: {req.name}",
            "available": sorted(TOOL_HANDLERS.keys()),
        }

    try:
        return handler(req.arguments)
    except Exception as e:
        return {"error": f"{type(e).__name__}: {e}", "tool": req.name}


@app.get("/health")
def health() -> dict:
    return {
        "ok": True,
        "implemented_tools": sorted(TOOL_HANDLERS.keys()),
        "note": (
            "This is the reference stub. Replace the handle_* functions "
            "with your actual tool implementations before submitting to "
            "the BioDesignBench leaderboard."
        ),
    }