diff --git a/docs/api.md b/docs/api.md
index 5cf05d4..95c9ddd 100644
--- a/docs/api.md
+++ b/docs/api.md
@@ -149,7 +149,7 @@
"id": "secretary",
"name": "Personal Secretary",
"description": "General-purpose assistant",
- "enabled_tools": ["todo", "mcp_navi-web_search", "filesystem", "..."],
+ "enabled_tools": ["todo", "mcp:navi-web:web_search", "filesystem", "..."],
"llm_backend": "ollama",
"model": ["gemma4:31b-cloud", "gemma4:26b-a4b-it-q4_K_M"],
"temperature": 0.65,
@@ -172,7 +172,7 @@
```json
[
{
- "name": "mcp_navi-web_search",
+ "name": "mcp:navi-web:web_search",
"description": "Search the web using DuckDuckGo.",
"parameters": {"type": "object", "properties": {...}, "required": [...]}
},
@@ -334,7 +334,7 @@
"tool_calls": [
{
"id": "abc123",
- "name": "mcp_navi-web_search",
+ "name": "mcp:navi-web:web_search",
"arguments": { "query": "..." }
}
]
@@ -343,7 +343,7 @@
"role": "tool",
"content": "tool result",
"tool_call_id": "abc123",
- "name": "mcp_navi-web_search"
+ "name": "mcp:navi-web:web_search"
}
]
}
@@ -657,7 +657,7 @@
```json
{
"type": "tool_started",
- "tool": "mcp_navi-web_search",
+ "tool": "mcp:navi-web:web_search",
"args": { "query": "weather in moscow" },
"is_subagent": false
}
@@ -671,7 +671,7 @@
```json
{
"type": "tool_call",
- "tool": "mcp_navi-web_search",
+ "tool": "mcp:navi-web:web_search",
"args": { "query": "weather in moscow" },
"result": "Today +12°C, cloudy.",
"success": true,
diff --git a/docs/profiles.md b/docs/profiles.md
index dae70b9..11e7edf 100644
--- a/docs/profiles.md
+++ b/docs/profiles.md
@@ -131,7 +131,7 @@
"model": ["gemma4:31b-cloud", "gemma4:26b-a4b-it-q4_K_M"],
"temperature": 0.5,
"max_iterations": 20,
- "enabled_tools": ["todo", "scratchpad", "mcp_navi-web_search", "filesystem"],
+ "enabled_tools": ["todo", "scratchpad", "mcp:navi-web:web_search", "filesystem"],
"subagent_tools": ["todo", "filesystem", "terminal"],
"planning_enabled": true,
"planning_mandatory": false,
diff --git a/docs/tools.md b/docs/tools.md
index 32fd056..bcdd147 100644
--- a/docs/tools.md
+++ b/docs/tools.md
@@ -10,10 +10,10 @@
| Tool | Name | Description |
|---|---|---|
-| `WebSearchTool` | `mcp_navi-web_search` | DuckDuckGo search |
-| `WebViewTool` | `mcp_navi-web_view` | Fetch and render a URL |
+| `WebSearchTool` | `mcp:navi-web:web_search` | DuckDuckGo search |
+| `WebViewTool` | `mcp:navi-web:web_view` | Fetch and render a URL |
| `FilesystemTool` | `filesystem` | Read/write/list local files (path restrictions via config) |
-| `HttpRequestTool` | `mcp_navi-web_request` | Generic HTTP client (GET/POST/etc.) |
+| `HttpRequestTool` | `mcp:navi-web:http_request` | Generic HTTP client (GET/POST/etc.) |
| `CodeExecTool` | `code_exec` | Execute Python in a subprocess sandbox |
| `TerminalTool` | `terminal` | Run shell commands (command allowlist via config) |
| `SshExecTool` | `ssh_exec` | SSH into remote hosts; connection pool keyed by session ID |
@@ -30,9 +30,12 @@
| `ListProfilesTool` | `list_profiles` | List all available profiles |
| `ShareFileTool` | `share_file` | Copy an existing local file into session files and return a download link |
| `ContentPublishTool` | `content_publish` | Register an existing session file for inline viewing in chat |
-| `Model3DTool` | `model_3d` | Compile an OpenSCAD script into a binary STL file |
-| `ScadLintTool` | `scad_lint` | Lightweight OpenSCAD source linting before STL compilation |
-| `Render3DTool` | `render_3d` | Render preview PNG images from an STL file (up to 3 views) |
+| `McpTool` (navi-3d) | `mcp:navi-3d:compile_scad` | Compile an OpenSCAD script into a binary STL file |
+| `McpTool` (navi-3d) | `mcp:navi-3d:lint_scad` | Lightweight OpenSCAD source linting before STL compilation |
+| `McpTool` (navi-3d) | `mcp:navi-3d:render_stl` | Render preview PNG images from an STL file (up to 3 views) |
+| `McpTool` (navi-web) | `mcp:navi-web:web_search` | Web search (SearXNG primary, DDG fallback, Brave tertiary) |
+| `McpTool` (navi-web) | `mcp:navi-web:web_view` | Open a URL in a headless browser and return clean readable text |
+| `McpTool` (navi-web) | `mcp:navi-web:http_request` | Raw HTTP request (GET/POST/PUT/PATCH/DELETE) |
| `DeleteToolTool` | `delete_tool` | Delete a user tool file |
| `TestToolTool` | `test_tool` | Run a user tool and verify its output |
| `McpStatusTool` | `mcp_status` | Check connectivity and list tools for configured MCP servers |
diff --git a/docs/visual.html b/docs/visual.html
index b3b2f24..57c3e40 100644
--- a/docs/visual.html
+++ b/docs/visual.html
@@ -872,10 +872,10 @@
| Name | Class | Description |
- web_search | WebSearchTool | DuckDuckGo web search |
- web_view | WebViewTool | Fetch and render a URL as text |
+ mcp:navi-web:web_search | McpTool | Web search (SearXNG primary, DDG fallback, Brave tertiary) |
+ mcp:navi-web:web_view | McpTool | Open a URL in a headless browser and return clean text |
filesystem | FilesystemTool | Read/write/list local files (path allowlist via config) |
- http_request | HttpRequestTool | Generic HTTP client — GET/POST/PUT/etc. |
+ mcp:navi-web:http_request | McpTool | Raw HTTP request — GET/POST/PUT/PATCH/DELETE |
code_exec | CodeExecTool | Execute Python in a subprocess sandbox |
terminal | TerminalTool | Run shell commands (command allowlist via config) |
ssh_exec | SshExecTool | SSH into remote hosts; connection pool keyed by session ID |
@@ -1091,8 +1091,8 @@
stream_start
tool_started spawn_agent is_subagent=false
turn_thinking is_subagent=true
- tool_started web_search is_subagent=true
- tool_call web_search is_subagent=true
+ tool_started mcp:navi-web:web_search is_subagent=true
+ tool_call mcp:navi-web:web_search is_subagent=true
tool_started filesystem is_subagent=true
tool_call filesystem is_subagent=true
tool_call spawn_agent is_subagent=false
diff --git a/manuals/lint_scad.md b/manuals/lint_scad.md
new file mode 100644
index 0000000..85404bf
--- /dev/null
+++ b/manuals/lint_scad.md
@@ -0,0 +1,84 @@
+# mcp:navi-3d:lint_scad
+
+## Что делает
+
+Проверяет OpenSCAD-скрипт на типичные ошибки, которые часто допускают LLM при генерации кода: незакрытые скобки, отсутствующие точки с запятой, неправильные аргументы примитивов, устаревший синтаксис и т.д.
+
+## Предпосылки
+
+1. **Файл `.scad` уже должен существовать.** Напишите его заранее через `filesystem write`.
+
+## Формат вызова
+
+```python
+mcp:navi-3d:lint_scad(
+ session_id="...",
+ source_path="bracket.scad"
+)
+```
+
+## Параметры
+
+| Параметр | Обязательно | Описание |
+|---|---|---|
+| `session_id` | Да | UUID текущей сессии Navi. Файлы разрешаются внутри `session_files//`. |
+| `source_path` | Да | Путь к существующему `.scad`-файлу (внутри сессии или абсолютный) |
+
+## Workflow
+
+### 1. Написать OpenSCAD-скрипт
+
+```
+filesystem write session_files/sess-abc/bracket.scad '
+difference() {
+ cube([40, 20, 5], center=true);
+ translate([15, 0, 0]) cylinder(h=6, d=4, center=true);
+}
+'
+```
+
+### 2. Запустить линтинг
+
+```
+mcp:navi-3d:lint_scad(
+ session_id="sess-abc",
+ source_path="bracket.scad"
+)
+```
+
+### 3. Исправить ошибки
+
+Если линт нашёл проблемы — исправьте `.scad` через `filesystem edit` и запустите линт повторно.
+
+### 4. Компилировать
+
+После чистого линта:
+
+```
+mcp:navi-3d:compile_scad(
+ session_id="sess-abc",
+ source_path="bracket.scad",
+ output_path="bracket.stl"
+)
+```
+
+## Что возвращает
+
+При успехе (ошибок нет):
+```
+Lint passed: no issues found.
+```
+
+При ошибках:
+```
+Lint errors (3):
+ line 7: missing semicolon after cylinder()
+ line 12: unexpected token '}'
+ line 15: unknown parameter 'radiu' in cylinder (did you mean 'r' or 'd'?)
+```
+
+## Важные правила
+
+1. **Всегда линт перед компиляцией** — это быстрее, чем ловить `openscad_compile_error`.
+2. **Всегда передавайте `session_id`** — без него инструмент не знает, в какой директории искать файлы.
+3. **Линт не проверяет логику** — только синтаксис и типичные LLM-ошибки. Физическую корректность проверяйте через превью.
diff --git a/manuals/model_3d.md b/manuals/model_3d.md
index 7ccfa71..3e86221 100644
--- a/manuals/model_3d.md
+++ b/manuals/model_3d.md
@@ -1,4 +1,4 @@
-# model_3d
+# mcp:navi-3d:compile_scad
## Что делает
@@ -14,9 +14,10 @@
## Формат вызова
```python
-model_3d(
- scad_path="session_files/{session_id}/handle.scad",
- output_path="session_files/{session_id}/handle.stl"
+mcp:navi-3d:compile_scad(
+ session_id="...",
+ source_path="handle.scad",
+ output_path="handle.stl"
)
```
@@ -24,7 +25,8 @@
| Параметр | Обязательно | Описание |
|---|---|---|
-| `scad_path` | Да | Путь к существующему `.scad`-файлу |
+| `session_id` | Да | UUID текущей сессии Navi. Файлы разрешаются внутри `session_files//`. |
+| `source_path` | Да | Путь к существующему `.scad`-файлу (внутри сессии или абсолютный) |
| `output_path` | Да | Путь, куда записать сгенерированный `.stl`. Родительские директории создаются автоматически. |
## Workflow
@@ -41,16 +43,26 @@
'
```
-### 2. Скомпилировать в STL
+### 2. Проверить линтингом (рекомендуется)
```
-model_3d(
- scad_path="session_files/sess-abc/bracket.scad",
- output_path="session_files/sess-abc/bracket.stl"
+mcp:navi-3d:lint_scad(
+ session_id="sess-abc",
+ source_path="bracket.scad"
)
```
-### 3. Показать пользователю
+### 3. Скомпилировать в STL
+
+```
+mcp:navi-3d:compile_scad(
+ session_id="sess-abc",
+ source_path="bracket.scad",
+ output_path="bracket.stl"
+)
+```
+
+### 4. Показать пользователю
```
content_publish(filename="bracket.stl", title="Bracket")
@@ -70,9 +82,11 @@
- `scad_not_found` — исходный файл не найден
- `openscad_compile_error` — ошибка компиляции (невалидный CSG, деление на ноль и т.д.)
- `no_output` — OpenSCAD завершился без ошибок, но файл не создался
+- `wrong_session_dir` — файл находится вне разрешённой сессии
## Важные правила
1. **Всегда binary STL** — нет параметра ASCII/binary, всегда используется `--export-format binstl`.
-2. **Скрипт должен существовать до вызова** — `model_3d` не пишет `.scad`, только компилирует.
-3. **Ошибки OpenSCAD** читаемы: строка, символ, тип ошибки — всё в stderr.
+2. **Скрипт должен существовать до вызова** — `compile_scad` не пишет `.scad`, только компилирует.
+3. **Всегда передавайте `session_id`** — без него инструмент не знает, в какой директории искать файлы.
+4. **Ошибки OpenSCAD** читаемы: строка, символ, тип ошибки — всё в stderr.
diff --git a/manuals/render_3d.md b/manuals/render_3d.md
index fea1d75..2f05ac0 100644
--- a/manuals/render_3d.md
+++ b/manuals/render_3d.md
@@ -1,4 +1,4 @@
-# render_3d
+# mcp:navi-3d:render_stl
## Что делает
@@ -8,14 +8,15 @@
## Предпосылки
-1. **STL-файл уже должен существовать.** Сгенерируйте его через `model_3d` заранее.
+1. **STL-файл уже должен существовать.** Сгенерируйте его через `mcp:navi-3d:compile_scad` заранее.
2. **OpenSCAD должен быть установлен.**
## Формат вызова
```python
-render_3d(
- source="session_files/{session_id}/bracket.stl",
+mcp:navi-3d:render_stl(
+ session_id="...",
+ source_path="bracket.stl",
views=["iso", "front", "top"]
)
```
@@ -24,7 +25,8 @@
| Параметр | Обязательно | Описание |
|---|---|---|
-| `source` | Да | Путь к существующему `.stl`-файлу |
+| `session_id` | Да | UUID текущей сессии Navi. Файлы разрешаются внутри `session_files//`. |
+| `source_path` | Да | Путь к существующему `.stl`-файлу (внутри сессии или абсолютный) |
| `views` | Нет | Список ракурсов (макс. 3). Доступные: `front`, `back`, `top`, `bottom`, `left`, `right`, `iso`. По умолчанию `["iso"]`. |
## Доступные ракурсы
@@ -44,14 +46,19 @@
### 1. Сгенерировать STL
```
-model_3d(scad_path="...", output_path="...")
+mcp:navi-3d:compile_scad(
+ session_id="sess-abc",
+ source_path="bracket.scad",
+ output_path="bracket.stl"
+)
```
### 2. Отрендерить ракурсы
```
-render_3d(
- source="session_files/sess-abc/bracket.stl",
+mcp:navi-3d:render_stl(
+ session_id="sess-abc",
+ source_path="bracket.stl",
views=["iso", "front", "top"]
)
```
@@ -63,7 +70,7 @@
- `bracket.front.png`
- `bracket.top.png`
-Обычно эти PNG нужны Нави для внутренней проверки геометрии перед публикацией STL. Откройте их через `image_view` и проверьте форму, пропорции, печатную ориентацию и очевидные проблемы печати.
+Обычно эти PNG нужны Нави для внутренней проверки геометрии перед публикацией STL. Откройте их через `image_view` и проверьте форму, пропорции и физическую корректность.
Не публикуйте PNG пользователю, если пользователь явно не попросил preview-картинки.
@@ -97,3 +104,4 @@
3. **PNG сохраняются рядом с STL** — в той же директории, с суффиксом ракурса.
4. **Всегда preview mode** — быстрый рендер, не полный CSG.
5. **Не склеивает в сетку** — каждый ракурс — отдельный файл. PNG обычно нужны для внутренней проверки; публикуйте их только по явной просьбе пользователя.
+6. **Всегда передавайте `session_id`** — без него инструмент не знает, в какой директории искать файлы.
diff --git a/manuals/spawn_agent.md b/manuals/spawn_agent.md
index a16cb4d..a444927 100644
--- a/manuals/spawn_agent.md
+++ b/manuals/spawn_agent.md
@@ -35,9 +35,9 @@
| Profile | Sub-agent tools |
|---------|----------------|
-| `secretary` | scratchpad, reflect, web_search, web_view, http_request, filesystem, code_exec, image_view, memory, share_file, weather |
-| `server_admin` | scratchpad, reflect, web_search, http_request, filesystem, code_exec, terminal, ssh_exec, image_view, share_file |
-| `developer` | scratchpad, reflect, web_search, web_view, http_request, filesystem, code_exec, terminal, image_view, reload_tools, test_tool, share_file |
+| `secretary` | scratchpad, reflect, mcp:navi-web:web_search, mcp:navi-web:web_view, mcp:navi-web:http_request, filesystem, code_exec, image_view, memory, share_file, weather |
+| `server_admin` | scratchpad, reflect, mcp:navi-web:web_search, mcp:navi-web:http_request, filesystem, code_exec, terminal, ssh_exec, image_view, share_file |
+| `developer` | scratchpad, reflect, mcp:navi-web:web_search, mcp:navi-web:web_view, mcp:navi-web:http_request, filesystem, code_exec, terminal, image_view, reload_tools, test_tool, share_file |
`spawn_agent` is always excluded — recursion is impossible.
diff --git a/mcp-servers/navi-web/app/mcp_server.py b/mcp-servers/navi-web/app/mcp_server.py
index 74aefe0..4f910bb 100644
--- a/mcp-servers/navi-web/app/mcp_server.py
+++ b/mcp-servers/navi-web/app/mcp_server.py
@@ -42,7 +42,7 @@
return Settings()
-@mcp.tool(name="search")
+@mcp.tool(name="web_search")
async def search_tool(
query: Annotated[str, Field(description="Search query.")],
max_results: Annotated[int, Field(description="Number of results (default 5).")] = 5,
@@ -52,7 +52,7 @@
return _json(result)
-@mcp.tool(name="view")
+@mcp.tool(name="web_view")
async def view_tool(
url: Annotated[str, Field(description="Full URL to open (must start with http:// or https://).")],
screenshot: Annotated[bool, Field(description="Also capture a screenshot.")] = False,
@@ -68,7 +68,7 @@
return _json(result)
-@mcp.tool(name="request")
+@mcp.tool(name="http_request")
async def request_tool(
method: Annotated[str, Field(description="HTTP method: GET, POST, PUT, PATCH, DELETE.")],
url: Annotated[str, Field(description="Full URL to request.")],
diff --git a/mcp_servers.json b/mcp_servers.json
index 17f8a1a..854d3cb 100644
--- a/mcp_servers.json
+++ b/mcp_servers.json
@@ -58,13 +58,13 @@
},
"groups": {
"search": [
- "search"
+ "web_search"
],
"browse": [
- "view"
+ "web_view"
],
"request": [
- "request"
+ "http_request"
]
},
"instructions": "Navi Web MCP server provides web search, browsing, and raw HTTP tools.\n\nUse it when the task involves:\n- searching the web for current info, docs, or real-time data;\n- opening a URL in a browser to read human-readable content;\n- making REST API calls, webhooks, or raw HTTP requests.\n\nWorkflow:\n1. search — find relevant pages or facts.\n2. view — open promising URLs to read full content.\n3. request — call APIs or services requiring headers/auth.\n\nAll three tools are stateless and work with public URLs.\nNo session_id or filesystem paths are required.\n\nABSOLUTE RULE — NEVER bypass MCP tools:\nYou MUST NOT use filesystem, terminal, code_exec, or any direct file access to read or write web content. Use only the MCP tools listed above."
diff --git a/navi/api/deps.py b/navi/api/deps.py
index 57ca137..6685ff2 100644
--- a/navi/api/deps.py
+++ b/navi/api/deps.py
@@ -108,7 +108,7 @@
"""Discover tools from all connected MCP servers and register them as external."""
# clear previous external MCP tools
for name in list(registry._external_names):
- if name.startswith("mcp_"):
+ if name.startswith("mcp:"):
registry.unregister_external(name)
tools = await manager.get_all_tools()
diff --git a/navi/api/routes/agents.py b/navi/api/routes/agents.py
index 1846e25..1de481a 100644
--- a/navi/api/routes/agents.py
+++ b/navi/api/routes/agents.py
@@ -53,14 +53,14 @@
names: list[str] = []
for server_name, groups in profile.mcp_servers.items():
if "*" in groups:
- prefix = f"mcp_{server_name}_"
+ prefix = f"mcp:{server_name}:"
for tool in tool_registry.all():
if tool.name.startswith(prefix) and tool.name not in names:
names.append(tool.name)
else:
for group_name in groups:
for tool_name in mcp_manager.resolve_group(server_name, group_name):
- full_name = f"mcp_{server_name}_{tool_name}"
+ full_name = f"mcp:{server_name}:{tool_name}"
if full_name not in names:
names.append(full_name)
return names
diff --git a/navi/core/tool_executor.py b/navi/core/tool_executor.py
index 3ecd938..33a51c9 100644
--- a/navi/core/tool_executor.py
+++ b/navi/core/tool_executor.py
@@ -24,7 +24,7 @@
bare_matches = [
(candidate_name, candidate)
for candidate_name, candidate in tool_map.items()
- if candidate_name.startswith("mcp_") and candidate_name.endswith(f"_{name}")
+ if candidate_name.startswith("mcp:") and candidate_name.endswith(f":{name}")
]
if len(bare_matches) == 1:
return bare_matches[0]
@@ -33,7 +33,7 @@
normalized_matches = [
(candidate_name, candidate)
for candidate_name, candidate in tool_map.items()
- if candidate_name.startswith("mcp_") and candidate_name.replace("-", "_") == normalized
+ if candidate_name.startswith("mcp:") and candidate_name.replace("-", "_") == normalized
]
if len(normalized_matches) == 1:
return normalized_matches[0]
diff --git a/navi/mcp/tools.py b/navi/mcp/tools.py
index b938894..72aa371 100644
--- a/navi/mcp/tools.py
+++ b/navi/mcp/tools.py
@@ -27,7 +27,7 @@
self.description = description
self.parameters = parameters
self._manager = manager
- self.name = f"mcp_{server_name}_{tool_name}"
+ self.name = f"mcp:{server_name}:{tool_name}"
async def execute(self, params: dict[str, Any]) -> ToolResult:
try:
diff --git a/navi/profiles/developer/config.json b/navi/profiles/developer/config.json
index 7347827..f4d707a 100644
--- a/navi/profiles/developer/config.json
+++ b/navi/profiles/developer/config.json
@@ -6,7 +6,7 @@
"full_description": {
"specialization": "Full-stack software development: writing code in any language, debugging, running tests, working with files and project structure, git, APIs, scripting. Works on the user's own projects, not Navi's internals.",
"when_to_use": "When the user wants to build something — a game, a script, an app, a web service, anything. For writing Navi tools specifically, use tool_developer instead.",
- "key_tools": "filesystem, code_exec, terminal, mcp_navi-web_search, mcp_navi-web_view, spawn_agent"
+ "key_tools": "filesystem, code_exec, terminal, mcp:navi-web:web_search, mcp:navi-web:web_view, spawn_agent"
},
"llm_backend": "ollama",
"model": [
@@ -66,8 +66,8 @@
"mcp_servers": {
"navi-web": [
"search",
- "view",
- "request"
+ "web_view",
+ "http_request"
]
}
}
\ No newline at end of file
diff --git a/navi/profiles/discuss/config.json b/navi/profiles/discuss/config.json
index f08bc5f..b2c1f2b 100644
--- a/navi/profiles/discuss/config.json
+++ b/navi/profiles/discuss/config.json
@@ -30,8 +30,8 @@
],
"navi-web": [
"search",
- "view",
- "request"
+ "web_view",
+ "http_request"
]
},
"subagent_tools": [],
diff --git a/navi/profiles/discuss/system_prompt.txt b/navi/profiles/discuss/system_prompt.txt
index 3f5ddfa..53f3bd9 100644
--- a/navi/profiles/discuss/system_prompt.txt
+++ b/navi/profiles/discuss/system_prompt.txt
@@ -18,7 +18,7 @@
## Tools
-Use `mcp_navi-web_search` + `mcp_navi-web_view` when a factual grounding would strengthen the discussion — not for every question, only when currency or precision matters.
+Use `mcp:navi-web:web_search` + `mcp:navi-web:web_view` when a factual grounding would strengthen the discussion — not for every question, only when currency or precision matters.
Use project `docs/` when discussing an active project. Prefer `docs/index.md` as the map, then query specific docs rather than rereading broad source trees.
diff --git a/navi/profiles/modeler_3d/config.json b/navi/profiles/modeler_3d/config.json
index 408ec4b..4ee27ea 100644
--- a/navi/profiles/modeler_3d/config.json
+++ b/navi/profiles/modeler_3d/config.json
@@ -6,7 +6,7 @@
"full_description": {
"specialization": "Physically coherent 3D geometry and STL generation. Generates STL files from OpenSCAD through dedicated 3D tools, and validates with OpenSCAD compilation plus preview render inspection.",
"when_to_use": "When the user needs a physical object modeled as 3D geometry: replacement parts, mechanical assemblies, decorative items, functional prototypes, jigs, fixtures, or custom enclosures.",
- "key_tools": "spawn_agent, filesystem, mcp_navi-3d_lint_scad, mcp_navi-3d_compile_scad, mcp_navi-3d_render_stl, image_view, content_publish"
+ "key_tools": "spawn_agent, filesystem, mcp:navi-3d:lint_scad, mcp:navi-3d:compile_scad, mcp:navi-3d:render_stl, image_view, content_publish"
},
"llm_backend": "ollama",
"model": [
@@ -59,8 +59,8 @@
],
"navi-web": [
"search",
- "view",
- "request"
+ "web_view",
+ "http_request"
]
},
"top_k": 30,
diff --git a/navi/profiles/modeler_3d/subagent_system_prompt.txt b/navi/profiles/modeler_3d/subagent_system_prompt.txt
index af8b329..3c1fd75 100644
--- a/navi/profiles/modeler_3d/subagent_system_prompt.txt
+++ b/navi/profiles/modeler_3d/subagent_system_prompt.txt
@@ -6,7 +6,7 @@
1. Read the briefing and parent session context.
2. Identify the exact missing facts requested by the parent agent.
-3. Use `mcp_navi-web_search`, `mcp_navi-web_view`, `filesystem`, and `image_view` as needed to gather evidence.
+3. Use `mcp:navi-web:web_search`, `mcp:navi-web:web_view`, `filesystem`, and `image_view` as needed to gather evidence.
4. Prefer primary sources, product pages, datasheets, manuals, dimensions in local files, or images provided by the user.
5. Return only the facts found, source paths/URLs, confidence, and unresolved gaps.
diff --git a/navi/profiles/modeler_3d/system_prompt.txt b/navi/profiles/modeler_3d/system_prompt.txt
index d9e56c2..c4e7659 100644
--- a/navi/profiles/modeler_3d/system_prompt.txt
+++ b/navi/profiles/modeler_3d/system_prompt.txt
@@ -27,9 +27,9 @@
All MCP 3D tools require the exact Navi `session_id` so files are resolved inside `session_files//`. Pass the current session ID from context.
1. **`filesystem write`** — write the OpenSCAD script (`.scad`) to the session directory.
-2. **`mcp_navi-3d_lint_scad`** — check the `.scad` source for common LLM mistakes before compiling.
-3. **`mcp_navi-3d_compile_scad`** — compile the `.scad` into a binary `.stl`.
-4. **`mcp_navi-3d_render_stl`** — generate PNG previews from several angles for your own inspection.
+2. **`mcp:navi-3d:lint_scad`** — check the `.scad` source for common LLM mistakes before compiling.
+3. **`mcp:navi-3d:compile_scad`** — compile the `.scad` into a binary `.stl`.
+4. **`mcp:navi-3d:render_stl`** — generate PNG previews from several angles for your own inspection.
5. **`image_view`** — inspect each PNG so YOU can verify geometry. PNG previews are for Navi, not for the user.
6. **`content_publish`** — publish the final STL after internal checks pass. Include `source_filename` when a real `.scad` source exists in the same session directory.
@@ -142,8 +142,8 @@
When the next step requires a tool, call the tool in the same assistant turn. Do not end a message with an announcement such as "I will now compile", "I am moving to publication", or "Next I will publish" unless you also make the required tool call in that same turn.
- If the STL is ready to publish, call `content_publish` immediately instead of saying you are going to publish it.
-- If the SCAD is ready to compile, call `mcp_navi-3d_compile_scad` immediately instead of saying you are going to compile it.
-- If the SCAD was just written or edited, call `mcp_navi-3d_lint_scad` immediately before `mcp_navi-3d_compile_scad`.
+- If the SCAD is ready to compile, call `mcp:navi-3d:compile_scad` immediately instead of saying you are going to compile it.
+- If the SCAD was just written or edited, call `mcp:navi-3d:lint_scad` immediately before `mcp:navi-3d:compile_scad`.
- If previews are ready to inspect, call `image_view` immediately instead of saying you are going to inspect them.
- Only send a text-only progress message when you are blocked, need a user decision, or are reporting a completed tool result.
@@ -154,7 +154,7 @@
- Never type, shorten, or reconstruct session IDs from memory.
- Use the exact `Session files directory` from system context or from tool output.
- Keep the `.scad`, compiled `.stl`, and preview PNGs in that same current session directory.
-- Prefer simple filenames with `mcp_navi-3d_compile_scad` when possible; the tool resolves them inside the current session directory.
+- Prefer simple filenames with `mcp:navi-3d:compile_scad` when possible; the tool resolves them inside the current session directory.
- Choose the final basename before compiling, for example `wind_turbine_blades_100mm.scad` and `wind_turbine_blades_100mm.stl`. Avoid renaming after compilation unless necessary.
- If `content_publish` returns `not_found`, read the exact directory named in its error, list that directory, then copy/move or recreate the file there before retrying. Do not keep listing or editing another `session_files/` directory.
@@ -165,12 +165,12 @@
3. **Plan physical geometry** — use `scratchpad` to store `design_plan` with scale, modules, axis convention, physical orientation, tolerances, weak points, and preview checks.
4. **Run parameter sanity check** — for functional, mechanical, or parametric fit parts, use `scratchpad` to store `parameter_sanity_check` before writing `.scad`.
5. **Write OpenSCAD yourself** — create or edit the `.scad` source with `filesystem write` or `filesystem edit`. The file must be clean, parameterized, in the session directory, and include the source comments contract.
-6. **Lint OpenSCAD** — call `scad_lint(path="...scad")` after the file exists. Fix every error before compiling. Treat warnings as reasons to inspect and revise when they affect geometry or source cleanliness.
+6. **Lint OpenSCAD** — call `mcp:navi-3d:lint_scad(session_id="...", source_path="...scad")` after the file exists. Fix every error before compiling. Treat warnings as reasons to inspect and revise when they affect geometry or source cleanliness.
7. **Research missing facts when useful** — if exact dimensions, reference images, or local documents are needed, call `spawn_agent` with a narrow research brief. Use the returned facts to update `technical_spec` or `design_plan`; do not ask the subagent to design, write, review, compile, render, or publish the model.
-8. **Compile STL** — call `model_3d(scad_path=..., output_path=...)`.
-9. **Handle compile result** — proceed only if `mcp_navi-3d_compile_scad` returns success. If it returns `openscad_compile_error`, `no_output`, `scad_not_found`, `wrong_session_dir`, or another error, fix the cause and compile again.
-10. **Render previews** — call `render_3d(source="...stl", views=["iso","front","top"])` or other relevant views.
-11. **Inspect every preview** — call `image_view` on every PNG path returned by `mcp_navi-3d_render_stl`. Do not publish PNG previews unless the user explicitly asks for preview images.
+8. **Compile STL** — call `mcp:navi-3d:compile_scad(session_id="...", source_path="...scad", output_path="...stl")`.
+9. **Handle compile result** — proceed only if `mcp:navi-3d:compile_scad` returns success. If it returns `openscad_compile_error`, `no_output`, `scad_not_found`, `wrong_session_dir`, or another error, fix the cause and compile again.
+10. **Render previews** — call `mcp:navi-3d:render_stl(session_id="...", source_path="...stl", views=["iso","front","top"])` or other relevant views.
+11. **Inspect every preview** — call `image_view` on every PNG path returned by `mcp:navi-3d:render_stl`. Do not publish PNG previews unless the user explicitly asks for preview images.
12. **Run preview checklist** — compare all inspected previews against `technical_spec` and `design_plan`. Record the checklist result in `scratchpad` section `preview_check`.
13. **Revise before publishing** — if lint, compilation output, researched facts, or preview inspection reveals a substantial issue, edit the `.scad`, lint again, recompile, re-render, and inspect again.
14. **Publish final STL** — after the model passes the geometry gate, call `content_publish(filename="...stl", content_type="stl", source_filename="...scad")`. This step is mandatory for a successful task.
@@ -206,10 +206,10 @@
- Functional, mechanical, and parametric fit parts have a `scratchpad` `parameter_sanity_check` confirming interface dimensions and formulas are internally consistent.
- The final `.stl` and `.scad` source are in the current session files directory, not another `session_files/` directory.
- The STL compiled successfully.
-- Every preview image returned by `mcp_navi-3d_render_stl` was inspected with `image_view`; inspecting only `iso` is not enough.
+- Every preview image returned by `mcp:navi-3d:render_stl` was inspected with `image_view`; inspecting only `iso` is not enough.
- `scratchpad` section `preview_check` exists and says `Revision required: no`, or records the revision that was made after a failed check.
-- OpenSCAD warnings/errors from `mcp_navi-3d_compile_scad` or `mcp_navi-3d_render_stl` were handled instead of ignored.
-- `mcp_navi-3d_lint_scad` was run on the final `.scad`, and all lint errors were fixed before compilation.
+- OpenSCAD warnings/errors from `mcp:navi-3d:compile_scad` or `mcp:navi-3d:render_stl` were handled instead of ignored.
+- `mcp:navi-3d:lint_scad` was run on the final `.scad`, and all lint errors were fixed before compilation.
- Any subagent use was limited to gathering missing factual information from web pages, local files, or images. The main agent made all modeling decisions.
- For functional fit parts, exact compatibility dimensions are either verified, provided by the user, or the artifact is explicitly labeled as a parametric template that requires user measurements.
diff --git a/navi/profiles/secretary/config.json b/navi/profiles/secretary/config.json
index 94b397b..876d6ab 100644
--- a/navi/profiles/secretary/config.json
+++ b/navi/profiles/secretary/config.json
@@ -6,7 +6,7 @@
"full_description": {
"specialization": "General-purpose personal assistant. Web research, document writing, data analysis, email correspondence, planning, calculations, and any everyday task that doesn't require direct server access or tool development.",
"when_to_use": "Default profile for most requests. If you're unsure which profile to use, this one is correct. Switch away only when the task clearly requires server/infrastructure access (server_admin) or modifying Navi's own tools (developer).",
- "key_tools": "mcp_navi-web_search, mcp_navi-web_view, filesystem, code_exec, gmail, todo, scratchpad, spawn_agent, memory"
+ "key_tools": "mcp:navi-web:web_search, mcp:navi-web:web_view, filesystem, code_exec, gmail, todo, scratchpad, spawn_agent, memory"
},
"llm_backend": "ollama",
"model": [
@@ -65,8 +65,8 @@
"mcp_servers": {
"navi-web": [
"search",
- "view",
- "request"
+ "web_view",
+ "http_request"
]
}
}
\ No newline at end of file
diff --git a/navi/profiles/secretary/system_prompt.txt b/navi/profiles/secretary/system_prompt.txt
index 4409b97..488dc14 100644
--- a/navi/profiles/secretary/system_prompt.txt
+++ b/navi/profiles/secretary/system_prompt.txt
@@ -69,11 +69,11 @@
---
## Tool priorities
-1. mcp_navi-web_search — first choice for current info, facts, documentation.
+1. mcp:navi-web:web_search — first choice for current info, facts, documentation.
2. code_exec — calculations, data processing, text parsing, format conversion.
-3. mcp_navi-web_view — view a specific page in full.
+3. mcp:navi-web:web_view — view a specific page in full.
4. filesystem — read/write local documents, notes, data files.
-5. mcp_navi-web_request — external APIs, webhooks, content not suited for search.
+5. mcp:navi-web:http_request — external APIs, webhooks, content not suited for search.
6. image_view — whenever an image path or URL is mentioned.
## Output style
diff --git a/navi/profiles/server_admin/config.json b/navi/profiles/server_admin/config.json
index 4a404cc..b164207 100644
--- a/navi/profiles/server_admin/config.json
+++ b/navi/profiles/server_admin/config.json
@@ -6,7 +6,7 @@
"full_description": {
"specialization": "Remote server operations via SSH, system diagnostics, service management, log analysis, network troubleshooting, process monitoring, and infrastructure automation.",
"when_to_use": "When the task involves SSH access to servers, running system commands, managing Linux services, analyzing logs, monitoring resources, or any hands-on infrastructure work.",
- "key_tools": "ssh_exec, terminal, filesystem, code_exec, mcp_navi-web_search, spawn_agent, memory"
+ "key_tools": "ssh_exec, terminal, filesystem, code_exec, mcp:navi-web:web_search, spawn_agent, memory"
},
"llm_backend": "ollama",
"model": [
@@ -64,8 +64,8 @@
],
"navi-web": [
"search",
- "view",
- "request"
+ "web_view",
+ "http_request"
]
},
"planning_mandatory": false,
diff --git a/navi/profiles/server_admin/system_prompt.txt b/navi/profiles/server_admin/system_prompt.txt
index 08ad591..419d8dd 100644
--- a/navi/profiles/server_admin/system_prompt.txt
+++ b/navi/profiles/server_admin/system_prompt.txt
@@ -46,7 +46,7 @@
6. **Synthesise** — after all agents report back, write your conclusions and next steps.
### Plan → execution binding
-- **TOOL** — direct local call (terminal, filesystem, mcp_navi-web_request for health checks).
+- **TOOL** — direct local call (terminal, filesystem, mcp:navi-web:http_request for health checks).
- **AGENT** — call `spawn_agent` for THIS STEP ONLY. One AGENT step = one spawn_agent call.
If your plan has steps 1, 2, 3 all marked AGENT — you make three separate spawn_agent calls.
Never bundle multiple steps into one call. Never pass your full plan to a single subagent.
@@ -80,8 +80,8 @@
1. ssh_exec — direct single-command checks on known hosts when spawning is overkill.
2. terminal — local machine operations.
3. filesystem — local config files, scripts.
-4. mcp_navi-web_request — health check endpoints, REST APIs.
-5. mcp_navi-web_search — error lookups, documentation.
+4. mcp:navi-web:http_request — health check endpoints, REST APIs.
+5. mcp:navi-web:web_search — error lookups, documentation.
## Execution environment
`terminal`, `filesystem`, and `code_exec` run on the LOCAL machine (where Navi's server is running) — NOT on any remote host.
diff --git a/navi/tools/reload_tools.py b/navi/tools/reload_tools.py
index 63792f3..a7a4edf 100644
--- a/navi/tools/reload_tools.py
+++ b/navi/tools/reload_tools.py
@@ -61,7 +61,7 @@
await self._mcp_manager.reload_all()
from navi.api.deps import register_mcp_tools
await register_mcp_tools(self._registry, self._mcp_manager)
- mcp_tools = [t.name for t in self._registry.all() if t.name.startswith("mcp_")]
+ mcp_tools = [t.name for t in self._registry.all() if t.name.startswith("mcp:")]
lines.append(f"MCP tools ({len(mcp_tools)}): {', '.join(mcp_tools) or 'none'}")
except Exception as exc:
has_errors = True
diff --git a/tests/unit/core/test_tool_executor.py b/tests/unit/core/test_tool_executor.py
index 8dcc719..aa5e180 100644
--- a/tests/unit/core/test_tool_executor.py
+++ b/tests/unit/core/test_tool_executor.py
@@ -9,7 +9,7 @@
class TestToolExecutorMcpAliases:
async def test_executes_bare_mcp_tool_alias(self):
registry = ToolRegistry()
- tool = FakeTool("mcp_gnexus-book_search_docs")
+ tool = FakeTool("mcp:gnexus-book:search_docs")
registry.register(tool, builtin=True)
executor = ToolExecutor(registry)
@@ -19,20 +19,20 @@
)
assert images == []
- assert messages[0].name == "mcp_gnexus-book_search_docs"
- assert messages[0].content == "executed mcp_gnexus-book_search_docs"
+ assert messages[0].name == "mcp:gnexus-book:search_docs"
+ assert messages[0].content == "executed mcp:gnexus-book:search_docs"
async def test_executes_mcp_tool_alias_with_underscore_server_name(self):
registry = ToolRegistry()
- tool = FakeTool("mcp_gnexus-book_search_docs")
+ tool = FakeTool("mcp:gnexus-book:search_docs")
registry.register(tool, builtin=True)
executor = ToolExecutor(registry)
messages, images = await executor._execute_tool_calls(
- [ToolCallRequest(id="1", name="mcp_gnexus_book_search_docs", arguments={"query": "git"})],
+ [ToolCallRequest(id="1", name="mcp:gnexus_book:search_docs", arguments={"query": "git"})],
[tool],
)
assert images == []
- assert messages[0].name == "mcp_gnexus-book_search_docs"
- assert messages[0].content == "executed mcp_gnexus-book_search_docs"
+ assert messages[0].name == "mcp:gnexus-book:search_docs"
+ assert messages[0].content == "executed mcp:gnexus-book:search_docs"
diff --git a/tests/unit/test_mcp.py b/tests/unit/test_mcp.py
index 86f6530..f6b7424 100644
--- a/tests/unit/test_mcp.py
+++ b/tests/unit/test_mcp.py
@@ -105,7 +105,7 @@
parameters={"type": "object", "properties": {}},
manager=mock_manager,
)
- assert tool.name == "mcp_gnexus-book_search_docs"
+ assert tool.name == "mcp:gnexus-book:search_docs"
async def test_execute_success(self):
mock_manager = AsyncMock(spec=McpManager)