chore: import upstream snapshot with attribution
Validate YAML Workflows / Validate YAML Configuration Files (push) Waiting to run

This commit is contained in:
wehub-resource-sync
2026-07-13 12:37:51 +08:00
commit d0e4308def
614 changed files with 74458 additions and 0 deletions
+136
View File
@@ -0,0 +1,136 @@
# Memory Module Guide
This document explains DevAll's memory system: memory list config, built-in store implementations, how agent nodes attach memories, and troubleshooting tips. Core code lives in `entity/configs/memory.py` and `node/agent/memory/*.py`.
## 1. Architecture
1. **Memory Store** Declared under `memory[]` in YAML with `name`, `type`, and `config`. Types are registered via `register_memory_store()` and point to concrete implementations.
2. **Memory Attachment** Referenced inside agent nodes via `AgentConfig.memories`. Each `MemoryAttachmentConfig` defines read/write strategy and retrieval stages.
3. **MemoryManager** Builds store instances at runtime based on attachments and orchestrates `load()`, `retrieve()`, `update()`, `save()`.
4. **Embedding** `SimpleMemoryConfig` and `FileMemoryConfig` embed `EmbeddingConfig`, and `EmbeddingFactory` instantiates OpenAI or local vector models.
## 2. Memory Sample Config
```yaml
memory:
- name: convo_cache
type: simple
config:
memory_path: WareHouse/shared/simple.json
embedding:
provider: openai
model: text-embedding-3-small
api_key: ${API_KEY}
- name: project_docs
type: file
config:
index_path: WareHouse/index/project_docs.json
file_sources:
- path: docs/
file_types: [".md", ".mdx"]
recursive: true
embedding:
provider: openai
model: text-embedding-3-small
```
### Mem0 Memory Config
```yaml
memory:
- name: agent_memory
type: mem0
config:
api_key: ${MEM0_API_KEY}
agent_id: my-agent
```
## 3. Built-in Store Comparison
| Type | Path | Highlights | Best for |
| --- | --- | --- | --- |
| `simple` | `node/agent/memory/simple_memory.py` | Optional disk persistence (JSON) after runs; FAISS + semantic rerank; read/write capable. | Small conversation history, prototypes. |
| `file` | `node/agent/memory/file_memory.py` | Chunks files/dirs into a vector index, read-only, auto rebuilds when files change. | Knowledge bases, doc QA. |
| `blackboard` | `node/agent/memory/blackboard_memory.py` | Lightweight append-only log trimmed by time/count; no vector search. | Broadcast boards, pipeline debugging. |
| `mem0` | `node/agent/memory/mem0_memory.py` | Cloud-managed by Mem0; semantic search + graph relationships; no local embeddings or persistence needed. Requires `mem0ai` package. | Production memory, cross-session persistence, multi-agent memory sharing. |
All stores register through `register_memory_store()` so summaries show up in UI via `MemoryStoreConfig.field_specs()`.
## 4. MemoryAttachmentConfig Fields
| Field | Description |
| --- | --- |
| `name` | Target Memory Store name (must be unique inside `stores[]`). |
| `retrieve_stage` | Optional list limiting retrieval to certain `AgentExecFlowStage` values (`pre`, `plan`, `gen`, `critique`, etc.). Empty means all stages. |
| `top_k` | Number of items per retrieval (default 3). |
| `similarity_threshold` | Minimum similarity cutoff (`-1` disables filtering). |
| `read` / `write` | Whether this node can read from / write back to the store. |
Agent node example:
```yaml
nodes:
- id: answer
type: agent
config:
provider: openai
model: gpt-4o-mini
prompt_template: answer_user
memories:
- name: convo_cache
retrieve_stage: ["gen"]
top_k: 5
read: true
write: true
- name: project_docs
read: true
write: false
```
Execution order:
1. When the node enters `gen`, `MemoryManager` iterates attachments.
2. Attachments matching the stage and `read=true` call `retrieve()` on their store.
3. Retrieved items are formatted under a "===== Related Memories =====" block in the agent context.
4. After completion, attachments with `write=true` call `update()` and optionally `save()`.
## 5. Store Details
All memory stores persist a unified `MemoryItem` structure containing:
- `content_summary` trimmed text used for embedding search.
- `input_snapshot` / `output_snapshot` serialized message blocks (with base64 attachments) preserving multimodal context.
- `metadata` store-specific telemetry (role, previews, attachment IDs, etc.).
This schema lets multimodal outputs flow into Memory/Thinking modules without extra plumbing.
### 5.1 SimpleMemory
- **Path** `SimpleMemoryConfig.memory_path` (or `auto`). Defaults to in-memory.
- **Retrieval** Build a query from the prompt, trim it, embed, query FAISS `IndexFlatIP`, then apply semantic rerank (Jaccard/LCS).
- **Write** `update()` builds a `MemoryContentSnapshot` (text + blocks) for both input/output, deduplicates via hashed summary, embeds the summary, and stores the snapshots/attachments metadata.
- **Tips** Tune `max_content_length`, `top_k`, and `similarity_threshold` to avoid irrelevant context.
### 5.2 FileMemory
- **Config** Requires at least one `file_sources` entry (paths, suffix filters, recursion, encoding). `index_path` is mandatory for incremental updates.
- **Indexing** Scan files → chunk (default 500 chars, 50 overlap) → embed → persist JSON with `file_metadata`.
- **Retrieval** Uses FAISS cosine similarity. Read-only; `update()` unsupported.
- **Maintenance** `load()` checks file hashes and rebuilds if needed. Store `index_path` on persistent storage.
### 5.3 BlackboardMemory
- **Config** `memory_path` (or `auto`) plus `max_items`. Creates the file in the session directory if missing.
- **Retrieval** Returns the latest `top_k` entries ordered by time.
- **Write** `update()` appends the latest snapshot (input/output blocks, attachments, previews). No embeddings are generated, so retrieval is purely recency-based.
### 5.4 Mem0Memory
- **Config** Requires `api_key` (from [app.mem0.ai](https://app.mem0.ai)). Optional `user_id`, `agent_id`, `org_id`, `project_id` for scoping.
- **Entity scoping**: `user_id` and `agent_id` are independent dimensions — both can be included simultaneously in `add()` and `search()` calls. When both are configured, retrieval uses an OR filter (`{"OR": [{"user_id": ...}, {"agent_id": ...}]}`) to search across both scopes. Writes include both IDs when available.
- **Retrieval** Uses Mem0's server-side semantic search. Supports `top_k` and `similarity_threshold` via `MemoryAttachmentConfig`.
- **Write** `update()` sends only user input to Mem0 via the SDK (as `role: "user"` messages). Assistant output is excluded to prevent noise memories from the LLM's responses being extracted as facts.
- **Persistence** Fully cloud-managed. `load()` and `save()` are no-ops. Memories persist across runs and sessions automatically.
- **Dependencies** Requires `mem0ai` package (`pip install mem0ai`).
## 6. EmbeddingConfig Notes
- Fields: `provider`, `model`, `api_key`, `base_url`, `params`.
- `provider=openai` uses the official client; override `base_url` for compatibility layers.
- `params` can include `use_chunking`, `chunk_strategy`, `max_length`, etc.
- `provider=local` expects `params.model_path` and depends on `sentence-transformers`.
## 7. Troubleshooting & Best Practices
- **Duplicate names** The memory list enforces unique `memory[]` names. Duplicates raise `ConfigError`.
- **Missing embeddings** `SimpleMemory` without embeddings downgrades to append-only; `FileMemory` errors out. Provide an embedding config whenever semantic search is required.
- **Permissions** Ensure directories for `memory_path`/`index_path` are writable. Mount volumes when running inside containers.
- **Performance** Pre-build large `FileMemory` indexes offline, use `retrieve_stage` to limit retrieval frequency, and tune `top_k`/`similarity_threshold` to balance recall vs. token cost.
## 8. Extending Memory
1. Implement a Config + Store (subclass `MemoryBase`).
2. Register via `register_memory_store("my_store", config_cls=..., factory=..., summary="...")` in `node/agent/memory/registry.py`.
3. Add `FIELD_SPECS`, then run `python -m tools.export_design_template ...` so the frontend picks up the enum.
4. Update this guide or ship a README detailing configuration knobs and boundaries.
+108
View File
@@ -0,0 +1,108 @@
# Thinking Module Guide
The Thinking module provides reasoning enhancement capabilities for Agent nodes, enabling the model to perform additional inference before or after generating results. This document covers the Thinking module architecture, built-in modes, and configuration methods.
## 1. Architecture
1. **ThinkingConfig**: Declared in YAML under `nodes[].config.thinking`, containing `type` and `config` fields.
2. **ThinkingManagerBase**: Abstract base class defining thinking logic for two timing hooks: `_before_gen_think` and `_after_gen_think`.
3. **Registry**: New thinking modes are registered via `register_thinking_mode()`, and Schema API automatically displays available options.
## 2. Configuration Example
```yaml
nodes:
- id: Thoughtful Agent
type: agent
config:
provider: openai
name: gpt-4o
api_key: ${API_KEY}
thinking:
type: reflection
config:
reflection_prompt: |
Please carefully review your response, considering:
1. Is the logic sound?
2. Are there any factual errors?
3. Is the expression clear?
Then provide an improved response.
```
## 3. Built-in Thinking Modes
| Type | Description | Trigger Timing | Config Fields |
|------|-------------|----------------|---------------|
| `reflection` | Model reflects on and refines its output after generation | After generation (`after_gen`) | `reflection_prompt` |
### 3.1 Reflection Mode
Self-Reflection mode allows the model to reflect on and improve its initial output. The execution flow:
1. Agent node calls the model to generate initial response
2. ThinkingManager concatenates conversation history (system role, user input, model output) as reflection context
3. Calls the model again with `reflection_prompt` to generate reflection result
4. Reflection result replaces the original output as the final node output
#### Configuration
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `reflection_prompt` | string | Yes | Prompt guiding model reflection, specifying reflection dimensions and expected improvements |
#### Use Cases
- **Writing refinement**: Self-review and correct grammar, logic issues
- **Code review**: Automatic security and quality checks after code generation
- **Complex reasoning**: Verify and correct multi-step reasoning results
## 4. Execution Timing
ThinkingManager supports two execution timings:
| Timing | Property | Description |
|--------|----------|-------------|
| Before generation (`before_gen`) | `before_gen_think_enabled` | Execute thinking before model call for input preprocessing |
| After generation (`after_gen`) | `after_gen_think_enabled` | Execute thinking after model output for post-processing or refinement |
The built-in `reflection` mode only enables after-generation thinking. Extension developers can implement before-generation thinking as needed.
## 5. Interaction with Memory
The Thinking module can access Memory context:
- `ThinkingPayload.text`: Text content at current stage
- `ThinkingPayload.blocks`: Multimodal content blocks (images, attachments, etc.)
- `ThinkingPayload.metadata`: Additional metadata
Memory retrieval results are passed to thinking functions via the `memory` parameter, allowing reflection to reference historical memories.
## 6. Custom Thinking Mode Extension
1. **Create config class**: Inherit from `BaseConfig`, define required configuration fields
2. **Implement ThinkingManager**: Inherit from `ThinkingManagerBase`, implement `_before_gen_think` or `_after_gen_think`
3. **Register mode**:
```python
from runtime.node.agent.thinking.registry import register_thinking_mode
register_thinking_mode(
"my_thinking",
config_cls=MyThinkingConfig,
manager_cls=MyThinkingManager,
summary="Custom thinking mode description",
)
```
4. **Export template**: Run `python -m tools.export_design_template` to update frontend options
## 7. Best Practices
- **Control reflection rounds**: Current reflection is single-round; specify iteration requirements in `reflection_prompt` for multi-round
- **Concise prompts**: Lengthy `reflection_prompt` increases token consumption; focus on key improvement points
- **Combine with Memory**: Store important reflection results in Memory for downstream nodes
- **Monitor costs**: Reflection makes additional model calls; track token usage
## 8. Related Documentation
- [Agent Node Configuration](../nodes/agent.md)
- [Memory Module](memory.md)
- [Workflow Authoring Guide](../workflow_authoring.md)
+47
View File
@@ -0,0 +1,47 @@
# Tooling Module Overview
DevAll currently exposes two tool binding modes for agent nodes:
1. **Function Tooling** call in-repo Python functions from `functions/function_calling/`, with JSON Schema auto-generated from type hints.
2. **MCP Tooling** connect to external services that implement the Model Context Protocol, including FastMCP, Claude Desktop, or any MCP-compatible tool stack.
All tooling configs hang off `AgentConfig.tooling`:
```yaml
nodes:
- id: solve
type: agent
config:
provider: openai
model: gpt-4o-mini
prompt_template: solver
tooling:
type: function
config:
tools:
- name: describe_available_files
- name: load_file
auto_load: true
timeout: 20
```
## 1. Lifecycle
1. **Parse** `ToolingConfig` selects `FunctionToolConfig`, `McpRemoteConfig`, or `McpLocalConfig` based on `type`. Field definitions live in `entity/configs/tooling.py`.
2. **Runtime** When the LLM chooses a tool, the executor injects `_context` (attachment store, workspace paths, etc.) for Function tools or forwards the request through MCP.
3. **Completion** Tool outputs are appended to the agent message stream and, when relevant, registered as attachments (e.g., `load_file`).
## 2. Documentation Map
- [function.md](function.md) Function Tooling config, context injection, best practices.
- [function_catalog.md](function_catalog.md) Built-in function list with usage notes.
- [mcp.md](mcp.md) MCP Tooling config, auto-launch, FastMCP example, security guidance.
## 3. Quick Comparison
| Dimension | Function | MCP |
| --- | --- | --- |
| Deployment | In-process Python functions shipped with the backend. | Remote: call an HTTP MCP endpoint. Local: launch a process and talk over stdio. |
| Schemas | Derived from annotations + `ParamMeta`. | Provided by the MCP server's JSON Schema. |
| Context | `_context` provides attachments + workspace helpers automatically. | Depends on the MCP server implementation. |
| Typical use | File I/O, local scripts, internal APIs. | Third-party tool suites, browsers, database agents. |
## 4. Security Notes
- Function Tooling runs inside the backend process, so keep functions least-privileged and avoid executing arbitrary shell commands without validation.
- MCP Tooling now has explicit **remote (HTTP)** and **local (stdio)** modes. Remote only needs an existing server URL; Local launches your binary, so constrain the command/env vars and rely on `wait_for_log` + timeouts to detect readiness.
- Tools that mutate attachments or `code_workspace/` should respect the lifecycle described in the [Attachment guide](../../attachments.md) (Chinese for now) to avoid leaking artifacts.
+77
View File
@@ -0,0 +1,77 @@
# Function Tooling Configuration Guide
`FunctionToolConfig` lets agent nodes call Python functions defined in the repo. Implementation lives in `entity/configs/tooling.py`, `utils/function_catalog.py`, and `functions/function_calling/`.
## 1. Config Fields
| Field | Description |
| --- | --- |
| `tools` | List of `FunctionToolEntryConfig`. Each entry requires `name`. |
| `timeout` | Tool execution timeout (seconds). |
`FunctionToolEntryConfig` specifics:
- `name`: top-level function name in `functions/function_calling/`.
### Function picker (`module_name:function_name`) & `module_name:All`
- The dropdown displays each function as `module_name:function_name`, where `module_name` is the relative Python file under `functions/function_calling/` (without `.py`, nested folders joined by `/`). This preserves semantic grouping for large catalogs.
- Every module automatically prepends a `module_name:All` entry, and all `All` entries are sorted lexicographically ahead of concrete functions. Choosing it expands to all functions in that module during config parsing, preserving alphabetical order.
- `module_name:All` is strictly for bulk imports; overriding `description`/`parameters`/`auto_fill` alongside it raises a validation error. Customize individual functions after expansion if needed.
- Both modules and functions are sorted alphabetically, and YAML still stores the plain function names; `module_name:All` is merely an input shortcut.
## 2. Function Directory Requirements
- Path: `functions/function_calling/` (override with `MAC_FUNCTIONS_DIR`).
- Functions must live at module top level.
- Provide Python type hints; for enums/descriptions use `typing.Annotated[..., ParamMeta(...)]`.
- Parameters beginning with `_` or splats (`*args`/`**kwargs`) are hidden from the agent call.
- The docstrings first paragraph becomes the description (truncated to ~600 chars).
- `utils/function_catalog.py` builds JSON Schemas at startup for the frontend/CLI.
## 3. Context Injection
The executor passes `_context` into each function:
| Key | Value |
| --- | --- |
| `attachment_store` | `utils.attachments.AttachmentStore` for querying/registering attachments. |
| `python_workspace_root` | Session `code_workspace/` shared by Python nodes. |
| `graph_directory` | Session root directory for relative path helpers. |
| others | Environment-specific extras (session/node IDs, etc.). |
Functions can declare `_context: dict | None = None` and parse it (see `functions/function_calling/file.py`s `FileToolContext`).
## 4. Example: Read Text File
```python
from typing import Annotated
from utils.function_catalog import ParamMeta
def read_text_file(
path: Annotated[str, ParamMeta(description="workspace-relative path")],
*,
encoding: str = "utf-8",
_context: dict | None = None,
) -> str:
ctx = FileToolContext(_context)
target = ctx.resolve_under_workspace(path)
return target.read_text(encoding=encoding)
```
YAML usage:
```yaml
nodes:
- id: summarize
type: agent
config:
tooling:
type: function
config:
tools:
- name: describe_available_files
- name: read_text_file
```
## 5. Extension Flow
1. Add your function under `functions/function_calling/`.
2. Supply type hints + `ParamMeta`; set `auto_fill: false` with custom `parameters` if you need manual JSON Schema.
3. If the function needs extra packages, declare them in `pyproject.toml`/`requirements.txt`, or use the bundled `install_python_packages` sparingly.
4. Run `python -m tools.export_design_template ...` so the frontend picks up new enums.
## 6. Debugging
- If the frontend/CLI reports function `foo` not found, double-check the name and ensure it resides under `MAC_FUNCTIONS_DIR`.
- When `function_catalog` fails to load, `FunctionToolEntryConfig.field_specs()` includes the error—fix syntax or dependencies first.
- Tool timeouts bubble up to the agent; raise `timeout` or handle exceptions inside the function for friendlier responses.
+168
View File
@@ -0,0 +1,168 @@
# Built-in Function Tool Catalog
This document lists all preset tools in the `functions/function_calling/` directory for Agent nodes to use via Function Tooling.
## Quick Import
Reference tools in YAML as follows:
```yaml
tooling:
- type: function
config:
tools:
- name: file:All # Import entire module
- name: save_file # Import single function
- name: deep_research:All
```
---
## File Operations (file.py)
Tools for file and directory management within `code_workspace/`.
| Function | Description |
|----------|-------------|
| `describe_available_files` | List available files in attachment store and code_workspace |
| `list_directory` | List contents of a directory |
| `create_folder` | Create a folder (supports nested directories) |
| `delete_path` | Delete a file or directory |
| `load_file` | Load a file and register as attachment, supports multimodal (text/image/audio) |
| `save_file` | Save text content to a file |
| `read_text_file_snippet` | Read text snippet (offset + limit), suitable for large files |
| `read_file_segment` | Read file by line range, supports line number metadata |
| `apply_text_edits` | Apply multiple text edits while preserving newlines and encoding |
| `rename_path` | Rename a file or directory |
| `copy_path` | Copy a file or directory tree |
| `move_path` | Move a file or directory |
| `search_in_files` | Search for text or regex patterns in workspace files |
**Example YAML**: [ChatDev_v1.yaml](../../../../../yaml_instance/ChatDev_v1.yaml), [file_tool_use_case.yaml](../../../../../yaml_instance/file_tool_use_case.yaml)
---
## Python Environment Management (uv_related.py)
Manage Python environments and dependencies using uv.
| Function | Description |
|----------|-------------|
| `install_python_packages` | Install Python packages using `uv add` |
| `init_python_env` | Initialize Python environment (uv lock + venv) |
| `uv_run` | Execute uv run in workspace to run modules or scripts |
**Example YAML**: [ChatDev_v1.yaml](../../../../../yaml_instance/ChatDev_v1.yaml)
---
## Deep Research (deep_research.py)
Search result management and report generation tools for automated research workflows.
### Search Result Management
| Function | Description |
|----------|-------------|
| `search_save_result` | Save or update a search result (URL, title, abstract, details) |
| `search_load_all` | Load all saved search results |
| `search_load_by_url` | Load a specific search result by URL |
| `search_high_light_key` | Save highlighted keywords for a search result |
### Report Management
| Function | Description |
|----------|-------------|
| `report_read` | Read full report content |
| `report_read_chapter` | Read a specific chapter (supports multi-level paths like `Intro/Background`) |
| `report_outline` | Get report outline (header hierarchy) |
| `report_create_chapter` | Create a new chapter |
| `report_rewrite_chapter` | Rewrite chapter content |
| `report_continue_chapter` | Append content to an existing chapter |
| `report_reorder_chapters` | Reorder chapters |
| `report_del_chapter` | Delete a chapter |
| `report_export_pdf` | Export report to PDF |
**Example YAML**: [deep_research_v1.yaml](../../../../../yaml_instance/deep_research_v1.yaml)
---
## Web Tools (web.py)
Web search and webpage content retrieval.
| Function | Description |
|----------|-------------|
| `web_search` | Perform web search using Serper.dev, supports pagination and multiple languages |
| `read_webpage_content` | Read webpage content using Jina Reader, supports rate limiting |
**Environment Variables**:
- `SERPER_DEV_API_KEY`: Serper.dev API key
- `JINA_API_KEY`: Jina API key (optional, auto rate-limited to 20 RPM without key)
**Example YAML**: [deep_research_v1.yaml](../../../../../yaml_instance/deep_research_v1.yaml)
---
## Video Tools (video.py)
Manim animation rendering and video processing.
| Function | Description |
|----------|-------------|
| `render_manim` | Render Manim script, auto-detects scene class and outputs video |
| `concat_videos` | Concatenate multiple video files using FFmpeg |
**Example YAML**: [teach_video.yaml](../../../../../yaml_instance/teach_video.yaml), [teach_video.yaml](../../../../../yaml_instance/teach_video.yaml)
---
## Code Execution (code_executor.py)
| Function | Description |
|----------|-------------|
| `execute_code` | Execute Python code string, returns stdout and stderr |
> ⚠️ **Security Note**: This tool has elevated privileges and should only be used in trusted workflows.
---
## User Interaction (user.py)
| Function | Description |
|----------|-------------|
| `call_user` | Send instructions to the user and get a response, for scenarios requiring human input |
---
## Weather Query (weather.py)
Demo tools to illustrate Function Calling workflow.
| Function | Description |
|----------|-------------|
| `get_city_num` | Return city code (hardcoded example) |
| `get_weather` | Return weather info by city code (hardcoded example) |
---
## Adding Custom Tools
1. Create a Python file in `functions/function_calling/` directory
2. Define parameters using type annotations:
```python
from typing import Annotated
from utils.function_catalog import ParamMeta
def my_tool(
param1: Annotated[str, ParamMeta(description="Parameter description")],
*,
_context: dict | None = None, # Optional, auto-injected by system
) -> str:
"""Function description (shown to LLM)"""
return "result"
```
3. Restart the backend server
4. Reference in Agent node via `name: my_tool` or `name: my_module:All`
+92
View File
@@ -0,0 +1,92 @@
# MCP Tooling Guide
MCP tooling is split into two explicit modes: **Remote (HTTP)** and **Local (stdio)**. They map to `tooling.type: mcp_remote` and `tooling.type: mcp_local`. The legacy `type: mcp` schema is no longer supported.
## 1. Mode overview
| Mode | Tooling type | When to use | Key fields |
| --- | --- | --- | --- |
| Remote | `mcp_remote` | A hosted HTTP(S) MCP server (FastMCP, Claude Desktop Connector, custom gateways) | `server`, `headers`, `timeout` |
| Local | `mcp_local` | A local executable that speaks MCP over stdio (Blender MCP, CLI tools, etc.) | `command`, `args`, `cwd`, `env`, timeouts |
## 2. `McpRemoteConfig`
| Field | Description |
| --- | --- |
| `server` | Required. MCP HTTP(S) endpoint, e.g. `https://api.example.com/mcp`. |
| `headers` | Optional. Extra HTTP headers such as `Authorization`. |
| `timeout` | Optional per-request timeout (seconds). |
**YAML example**
```yaml
nodes:
- id: remote_mcp
type: agent
config:
tooling:
type: mcp_remote
config:
server: https://mcp.mycompany.com/mcp
headers:
Authorization: Bearer ${MY_MCP_TOKEN}
timeout: 15
```
DevAll connects to the URL for each list/call request and passes `headers`. If the server is unreachable, an error is raised immediately—there is no local fallback.
## 3. `McpLocalConfig` fields
`mcp_local` declares the process arguments directly under `config`:
- `command` / `args`: executable and arguments (e.g., `uvx blender-mcp`).
- `cwd`: optional working directory.
- `env` / `inherit_env`: environment overrides.
- `startup_timeout`: max seconds to wait for `wait_for_log`.
- `wait_for_log`: regex matched against stdout to mark readiness.
**YAML example**
```yaml
nodes:
- id: local_mcp
type: agent
config:
tooling:
type: mcp_local
config:
command: uvx
args:
- blender-mcp
cwd: ${REPO_ROOT}
wait_for_log: "MCP ready"
startup_timeout: 8
```
DevAll keeps the process alive and relays MCP frames over stdio.
## 4. FastMCP sample server
`mcp_example/mcp_server.py`:
```python
from fastmcp import FastMCP
import random
mcp = FastMCP("Company Simple MCP Server", debug=True)
@mcp.tool
def rand_num(a: int, b: int) -> int:
return random.randint(a, b)
if __name__ == "__main__":
mcp.run()
```
Launch:
```bash
uv run fastmcp run mcp_example/mcp_server.py --transport streamable-http --port 8010
```
- Remote mode: set `server` to `http://127.0.0.1:8010/mcp`.
- Local mode: run the script with `transport=stdio` and point `command` to that invocation.
## 5. Security & operations
- **Network exposure**: Remote mode should sit behind HTTPS + ACL/API keys. Local mode still has access to the host filesystem, so keep the script sandboxed.
- **Resource cleanup**: Local mode processes are terminated by DevAll; make sure they gracefully handle SIGTERM/SIGKILL.
- **Logs**: Emit a clear readiness line that matches `wait_for_log` to debug startup issues.
- **Auth**: Remote mode handles tokens via `headers`; Local mode can receive secrets via `env` (never commit them).
- **Multi-session**: If the MCP server is single-tenant, cap concurrency (e.g., `max_concurrency=1`) and share the same YAML config.
## 6. Debugging checklist
1. Remote: ping the HTTP endpoint via curl or `fastmcp client`. Local: run the binary manually and confirm the readiness log.
2. Start DevAll (optionally with `--reload`) and observe backend logs for tool discovery.
3. When calls fail, inspect the Web UI tool traces or the structured logs under `logs/`.