Skip to content

Tools and MCP

A tool is a named function an agent can call. Science ADK resolves tools from three kinds of provider, declared in science.toml, and none of them is required — a project with only local tools is complete, offline and dependency-free.

result = await self.call_tool("power_law_fit", x=axes, y=periods)

Every call is recorded in the provenance ledger, which is why declaring a tool in workflow.json is a checkable promise rather than a comment.

Local Python functions

The zero-boilerplate case. Every public top-level function in tools/*.py becomes a callable tool:

tools/fitting.py
"""Curve fitting tools."""

from __future__ import annotations


def power_law_fit(x: list, y: list) -> dict:
    """Fit y = C * x^a by ordinary least squares in log-log space.

    Returns {"exponent", "coefficient", "r_squared", "n"}. Raises ValueError
    if the inputs differ in length or contain non-positive values, both of
    which make the log transform undefined rather than merely imprecise.
    """
    ...
Element Becomes
Function name The tool name.
Docstring The tool description a coding agent reads.
Type hints The JSON schema: parameter types, defaults, required list.
Leading underscore Excluded — private helpers stay private.
science.toml
[tools.local]
path = "./tools"
science-adk tools           # list everything the registry found
science-adk tools --json

Raise, don't return a sentinel

A tool that returns 0.0 or an all-zero vector when it fails poisons the dataset silently. A tool that raises fails the run loudly, which the gates then catch.

MCP servers

Model Context Protocol servers plug in as additional providers. Science ADK speaks JSON-RPC to them directly.

science.toml
[tools.pubchem]
command = "uvx mcp-pubchem"

The command is launched as a subprocess and driven over stdin/stdout.

science.toml
[tools.remote_compute]
url = "https://mcp.example.org/api"
token_env = "COMPUTE_API_TOKEN"

token_env names an environment variable, never the secret itself. If the variable is unset the registry fails fast:

ToolError: Tool provider 'remote_compute' needs COMPUTE_API_TOKEN
environment variable, which is not set.

Install the client dependency once:

pip install "./science-adk/python[mcp]"

Names and resolution

Every tool has a qualified name, provider.tool. Agents may call either form:

await self.call_tool("power_law_fit")        # bare, if unambiguous
await self.call_tool("local.power_law_fit")  # qualified, always unambiguous

Use the qualified name when two providers expose the same tool name — which is also the case where a bare name is a bug waiting to happen.

If a provider is unreachable, the registry warns and continues rather than failing the whole project:

warning: tool provider 'pubchem' unavailable: ...

The run then fails at the point of use, in a node whose declared tools did not get called — which the tool_use_verified gate reports.

Declaring tools on a node

{ "id": "analyze", "kind": "algorithm", "tools": ["power_law_fit"] }

The declaration is advisory for the agent and binding for the gate: a node listing tools that completes without one successful tool call fails tool_use_verified and scores the run 0.00. Declare what you will call, and call what you declare.

The complete config

science.toml
[project]
name = "molecular-dynamics"

# Local Python functions in tools/*.py
[tools.local]
path = "./tools"

# Stdio-based MCP server
[tools.pubchem]
command = "uvx mcp-pubchem"

# Remote HTTP MCP server
[tools.remote_compute]
url = "https://mcp.example.org/api"
token_env = "COMPUTE_API_TOKEN"

[run]
node_timeout_s = 900
max_optimize_iterations = 5

Reference