Tools
The three-layer tool system: built-in, external, and MCP.
Tools
Nebflow gives agents three kinds of tools — built-in, external, and MCP — all exposed through the same uniform interface.
The Uniform Interface
From an agent's point of view, every tool is the same shape:
- name — how the agent refers to it
- input schema — the arguments it accepts
- text result — the result, always text (Markdown, JSON, or plain)
The agent never cares which layer a tool comes from. This keeps prompts simple and lets you swap implementations without touching agent definitions.
Layer 1: Built-in Tools
Implemented in Scala, always available:
| Tool | Purpose |
|------|---------|
| Read | Read a file from disk |
| Write | Write a file |
| Edit | Targeted string replacement in a file |
| Bash | Run a shell command |
| Grep / Glob | Search file contents / names |
| Mail | Message another agent or trigger a flow |
| WebSearch / WebFetch | Access information beyond training data |
| Card | Render an HTML card into the UI |
| Screenshot | Capture and verify a web page |
Layer 2: External Tools
Defined as JSON + script on disk, resolved via the $TOOL_DIR variable. They wrap arbitrary executables — Python, Node, shell — into the uniform tool interface.
Resolution order (4-level scan)
$TOOL_DIR/ # Global tools (all agents)
$TOOL_DIR/agents/<name>/ # Per-agent tools
$TOOL_DIR/teams/<team>/ # Per-team tools
$TOOL_DIR/flows/<flow>/ # Per-flow tools
More specific scopes override more general ones with the same tool name.
Structure
tools/
├── global-tools.json # Global tool definitions
├── my-tool/
│ ├── tool.json # name, description, input schema
│ └── run.sh # Executable (receives JSON args on stdin)
Layer 3: MCP Tools
Model Context Protocol servers expose tools as mcp__<server>__<tool>.
Global configuration
nebflow.json declares MCP servers globally:
{
"mcpServers": {
"github": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-github"] }
}
}
Per-agent filtering
An agent's mcpServers field is an allowlist — the agent may only call MCP tools from the listed servers:
{
"name": "release-manager",
"mcpServers": ["github"]
}
No mcpServers field means no MCP access at all. This is a deliberate default: MCP servers can be powerful and side-effectful, so they must be explicitly granted.
Agent-specific MCP
An agent directory can also ship its own MCP servers in a tools/ folder:
agents/my-agent/
├── agent.json
├── system.md
└── tools/mcp-servers.json # MCP servers scoped to this agent
Tool Safety
| Rule | Why | |------|-----| | Tools are granted per-agent | Least privilege | | MCP defaults to off | Explicit consent for powerful tools | | External tools are sandboxed scripts | No arbitrary code execution | | Bash requires explicit grant | Command injection surface | | Agent output escapes HTML | XSS prevention (Card rendering) |
Best Practices
- Grant the minimum tool set an agent needs
- Name external tools with clear verbs (
pdf-extract,deploy-site) - Document each tool's input schema — agents rely on it
- Keep MCP servers shared where possible; use per-agent only for truly local needs