Skip to main content
Glama
hqn21

protocols-io-mcp-server

get_protocol_steps

Retrieve detailed steps for scientific protocols by providing the protocol ID, enabling access to structured methodology information from protocols.io.

Instructions

Retrieve the steps for a specific protocol by its protocol ID.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
protocol_idYesUnique identifier for the protocol

Implementation Reference

  • The handler function for the 'get_protocol_steps' tool. It takes a protocol_id, calls the protocols.io API to fetch steps, parses them into ProtocolStep objects, or returns an error.
    @mcp.tool()
    async def get_protocol_steps(
        protocol_id: Annotated[int, Field(description="Unique identifier for the protocol")]
    ) -> list[ProtocolStep] | ErrorMessage:
        """
        Retrieve the steps for a specific protocol by its protocol ID.
        """
        response = await helpers.access_protocols_io_resource("GET", f"/v4/protocols/{protocol_id}/steps?content_format=markdown")
        if response["status_code"] != 0:
            return ErrorMessage.from_string(response["status_text"])
        steps = [ProtocolStep.from_api_response(step) for step in response.get("payload", [])]
        return steps
  • Pydantic model for ProtocolStep, defining the output structure for protocol steps, including parsing logic from API response.
    class ProtocolStep(BaseModel):
        id: Annotated[str, Field(description="Unique identifier for the step")]
        description: Annotated[str, Field(description="Description of the step")]
        materials: Annotated[list[Material], Field(description="Materials required for this step. Empty if no materials are needed or if source data could not be parsed")] = Field(default_factory=list)
        reference_protocol_ids: Annotated[list[int], Field(description="Protocol IDs referenced by this step. Empty if no references exist or if source data could not be parsed")] = Field(default_factory=list)
    
        @staticmethod
        def parse(step: str) -> dict:
            description = []
            materials = []
            reference_protocol_ids = []
            material_flag = False
            reference_flag = False
            for line in step.splitlines():
                if material_flag is False and reference_flag is False:
                    if line == "[Materials]":
                        material_flag = True
                        reference_flag = False
                    elif line == "[Protocol References]":
                        reference_flag = True
                        material_flag = False
                    elif len(line) > 0:
                        description.append(line)
                elif material_flag:
                    if len(line) == 0 or line[0] != '-':
                        material_flag = False
                        continue
                    data = line.split()
                    materials.append(Material(
                        name=data[1],
                        quantity=float(data[2]),
                        unit=data[3]
                    ))
                elif reference_flag:
                    if len(line) == 0 or line[0] != '-':
                        reference_flag = False
                        continue
                    data = line.split("[")[1].split("]")[0]
                    reference_protocol_ids.append(int(data))
            description = "\n".join(description)
            return {
                "description": description,
                "materials": materials,
                "reference_protocol_ids": reference_protocol_ids
            }
    
        @classmethod
        def from_api_response(cls, data: dict) -> "ProtocolStep":
            parsed_step = ProtocolStep.parse(data["step"])
            return cls(
                id=data["guid"],
                description=parsed_step["description"],
                materials=parsed_step["materials"],
                reference_protocol_ids=parsed_step["reference_protocol_ids"]
            )
  • Registration of tools by importing the tools module, which executes the @mcp.tool() decorators in protocol.py to register 'get_protocol_steps' and other tools.
    importlib.import_module('protocols_io_mcp.tools')
  • Helper function used by the tool to make authenticated HTTP requests to the protocols.io API.
    async def access_protocols_io_resource(method: Literal["GET", "POST", "PUT", "DELETE"], path: str, data: dict = None) -> dict[str, Any]:
        """Access protocols.io API with specified method and path."""
        headers = {
            "Authorization": f"Bearer {PROTOCOLS_IO_CLIENT_ACCESS_TOKEN}"
        }
        async with httpx.AsyncClient(timeout=30.0) as client:
            response = await client.request(method, f"{PROTOCOLS_IO_API_URL}{path}", json=data, headers=headers)
            return response.json()

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/hqn21/protocols-io-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server