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.
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:
"""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. |
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.
Install the client dependency once:
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:
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¶
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¶
[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