# ToolAnything

> 定義一次工具，同時提供 MCP、OpenAI tool calling 與 CLI 使用介面。

## 概覽

ToolAnything 是 Python 工具層：它把 Python function、class method、HTTP API、SQL query 或 model inference 整理成同一份工具契約，再交給 MCP server、OpenAI adapter、CLI 與診斷工具使用。你不需要為每個協議各維護一份 schema，也不需要把外部來源再包成沒有實質邏輯的 wrapper function。

ToolAnything 專注在「工具如何定義、暴露、呼叫與治理」。它不是完整的 agent framework，不負責 memory、planning、workflow orchestration 或產品 UI。

## 適用範圍

適合：

- 把 Python function 或 class method 暴露成 MCP／OpenAI tool。
- 直接把 HTTP、SQL、ONNX 或 PyTorch source 註冊成 tool。
- 建立可重用的 MCP server，並用 `doctor` 或 `inspect` 驗證。
- 讓同一份工具契約支援 MCP、OpenAI tool calling 與 CLI。
- 使用內建 filesystem、web、data standard tools，並保留明確的安全邊界。

如果你只需要一次性、單一 function、MCP-only 的原型，而且不需要 CLI、診斷、shared server 或 source-based API，較小的 MCP wrapper 可能更合適。

## Prerequisites／Requirements／環境需求

- Python `>=3.10,<3.14`
- MCP Python SDK `>=2.0.0,<3`
- ToolAnything `0.0.7`（目前專案版本）

安裝正式套件：

```bash
python -m pip install toolanything
```

在本 repo 開發：

```bash
git clone <repository-url>
cd ToolAnything
python -m pip install -e ".[dev]"
```

## 五分鐘快速開始

這條路徑會建立一支 `calculator.add` 工具、啟動 Streamable HTTP server，最後實際執行 MCP discovery、`tools/list` 與 `tools/call`。

### 1. 建立 `tools.py`

```python
from toolanything import tool


@tool(name="calculator.add", description="加總兩個整數")
def add(a: int, b: int) -> int:
    return a + b
```

### 2. 啟動 MCP server

```bash
toolanything serve tools.py --streamable-http --host 127.0.0.1 --port 9092
```

MCP endpoint 是 `http://127.0.0.1:9092/mcp`。新的遠端整合建議使用這個模式。

### 3. 在另一個終端機驗證

```bash
toolanything doctor --mode http --url http://127.0.0.1:9092
```

成功時，報告中的 discovery／initialize、`tools/list` 與 `tools/call` 都會是 `PASS`。`doctor` 預設先探測 modern protocol，必要時才回退到 legacy protocol。

若要手動檢查 schema 與 tool call：

```bash
toolanything inspect
```

### 4. 改用 stdio

Claude Desktop 或其他會啟動本機子程序的 host 通常使用 stdio：

```bash
toolanything serve tools.py --stdio
```

驗證方式：

```bash
toolanything doctor --mode stdio --tools tools
```

完整入門路線見 [examples/quickstart](examples/quickstart/README.md)。

## MCP 新舊協議如何共存

預設 `sdk_v2` backend 會在同一個 stdio process 或 `/mcp` endpoint 支援兩個明確版本：

| 協議版本 | 啟動方式 | HTTP 狀態模型 | 主要差異 |
| --- | --- | --- | --- |
| `2026-07-28` modern | `server/discover` | request-scoped、無 protocol session | 不使用 `Mcp-Session-Id`、獨立 `GET /mcp` 或 `DELETE /mcp` |
| `2025-11-25` legacy | `initialize` | session-based | initialize 後取得 `Mcp-Session-Id`，後續 request 綁定該 session |

Server 會根據 request 宣告的 protocol version 分流；不是在啟動 server 時選一個版本後永久鎖定。因此一般情況維持預設即可：

```bash
toolanything serve tools.py --streamable-http
```

若要分別驗證兩個世代：

```bash
toolanything doctor --mode http --url http://127.0.0.1:9092 --protocol-mode modern
toolanything doctor --mode http --url http://127.0.0.1:9092 --protocol-mode legacy
```

這裡的 `--protocol-mode` 是診斷 client 的探測選擇；在 `sdk_v2` server 上不會停用另一個世代。

如果 SDK backend 發生相容問題，可以回退到只提供 legacy profile 的 built-in backend：

```bash
toolanything serve tools.py \
  --streamable-http \
  --mcp-backend legacy_builtin \
  --protocol-mode legacy
```

如果 client 仍綁定舊式 `GET /sse` + `POST /messages/{session_id}` transport：

```bash
toolanything serve tools.py --legacy-http --host 127.0.0.1 --port 9090
```

`--legacy-http` 會自動選擇 `legacy_builtin`。協議世代、backend 與 transport 是三個不同概念，詳細對照見 [MCP transports 範例](examples/mcp_transports/README.md)。

## MCP 2026-07-28 支援狀態

ToolAnything 目前以官方 MCP Python SDK v2 負責 wire protocol：

| Gate | 結果 | 範圍 |
| --- | ---: | --- |
| M1 Full Server | 37/37 PASS | Tools、Resources、Prompts、Completion、MRTR、transport、cache |
| M2 Full Client | 32/32 PASS | Tools、metadata、OAuth/CIMD/issuer/scope、MRTR、headers、`$ref` |
| M3 Extensions | PASS | Subscriptions、Tasks、MCP Apps security boundary、EMA 10/10 |

沒有使用 expected failures。Current advisory 的 server/client JSON Schema 2020-12 preservation 另外通過 8/8 與 9/9。可重跑證據見 [MCP full-support baseline](docs/test-evidence/mcp-full-baseline.md)。

## 使用方式：工具來源怎麼選

| 來源 | 建議 API | 範例 |
| --- | --- | --- |
| Python function | `@tool(...)` | [quickstart](examples/quickstart/README.md) |
| Class method | `@tool(...)` + `@classmethod` | [class method tools](examples/class_method_tools/README.md) |
| HTTP API | `register_http_tool(...)` 或 HTTP source spec | [HTTP source](examples/non_function_tools/http_tool.py) |
| SQL query | `register_sql_tool(...)` 或 SQL source spec | [SQL source](examples/non_function_tools/sql_tool.py) |
| ONNX／PyTorch model | `register_model_tool(...)` 或 model source spec | [model sources](examples/non_function_tools/README.md) |
| 內建通用工具 | `register_standard_tools(...)` | [standard tools](examples/standard_tools/README.md) |

判斷原則：

- 穩定的 Python callable 或 class method：使用 `@tool(...)`。
- 真正來源是 HTTP、SQL 或 model：使用 source-based API。
- 要給 agent 長期重用：啟動後一定執行 `doctor` 或 `inspect`。

## Standard tools 與安全邊界

內建 standard tools 涵蓋 filesystem、web 與常見資料格式。預設註冊唯讀工具；寫入與 browser provider 必須明確 opt in。

```python
from pathlib import Path

from toolanything import ToolRegistry, register_standard_tools
from toolanything.standard_tools import StandardToolOptions, StandardToolRoot


registry = ToolRegistry()
register_standard_tools(
    registry,
    StandardToolOptions(
        roots=(StandardToolRoot("workspace", Path.cwd()),),
    ),
)
```

主要安全規則：

- filesystem tools 只能存取設定的 root。
- `standard.fs.write` 等寫入工具預設不註冊。
- 啟用寫入時必須同時設定 `include_write_tools=True` 與 writable root。
- 覆寫與 patch 路徑使用 SHA-256 guard，避免在內容已變更時靜默覆蓋。
- `standard.web.fetch` 只處理受 policy 限制的文字型 HTTP(S) 資源，不是互動式瀏覽器或 PDF reader。

完整清單與執行方式見 [standard tools 文件](docs/standard-tools.md)。

## OpenAI tool calling

同一份 registry 可以輸出 OpenAI tool schema，也可以交給 `OpenAIChatRuntime` 執行 tool loop：

```python
from toolanything import OpenAIChatRuntime


runtime = OpenAIChatRuntime()
result = runtime.run(
    model="<openai-model>",
    prompt="請使用 calculator.add 計算 2 + 3。",
)
print(result["final_text"])
```

真實 API 呼叫需要 `OPENAI_API_KEY`。若只想驗證 schema 與本地執行流程，先使用 `doctor`、`inspect` 或 [basic tool chatbot](examples/basic_tool_chatbot/README.md) 的 deterministic requester。

## Prompt-cache-friendly tool bundles

工具順序或 volatile metadata 改變時，送給模型的 tools prefix 也會改變。`to_prompt_cache_bundle()` 會 canonicalize 工具清單並產生 `catalog_hash`：

```python
bundle = registry.to_prompt_cache_bundle(provider="openai", adapter="openai")
print(bundle.catalog_hash)
print(bundle.tools)
```

這個 projection 不取代 `to_openai_tools()` 或 `to_mcp_tools()`。它讓 host 可以在重連或收到 list-changed event 後，只在 catalog hash 真正改變時更新工具前綴。完整案例見 [prompt cache 範例](examples/prompt_cache/README.md)。

## 常用 CLI

### 選擇 transport

```bash
# 新的遠端 HTTP 整合
toolanything serve tools.py --streamable-http --host 127.0.0.1 --port 9092

# Desktop／本機 subprocess host
toolanything serve tools.py --stdio

# 舊式 HTTP + SSE client
toolanything serve tools.py --legacy-http --host 127.0.0.1 --port 9090
```

### 匯出成 CLI

```bash
toolanything cli export \
  --module tests.fixtures.sample_tools \
  --app-name mytools

toolanything cli run \
  --config toolanything.cli.json \
  -- math add --a 2 --b 3 --json
```

### 產生 Claude Desktop 設定

```bash
toolanything init-claude --module examples/opencv_mcp_web/server.py --port 9090
```

`install-claude` 會直接修改本機 Claude Desktop 設定；執行前先確認輸出路徑與既有設定。CLI reference 見 [wiki/CLI-Reference.md](wiki/CLI-Reference.md)。

## Examples 與文件導覽

| 目標 | 入口 |
| --- | --- |
| 第一次成功註冊並呼叫工具 | [examples/quickstart](examples/quickstart/README.md) |
| 選擇 MCP transport／理解雙協議 | [examples/mcp_transports](examples/mcp_transports/README.md) |
| 研究 legacy session lifecycle | [examples/streamable_http](examples/streamable_http/README.md) |
| 建立官方 SDK client | [examples/mcp_client](examples/mcp_client/README.md) |
| 使用 Resources、Prompts、Completion | [examples/resources_prompts](examples/resources_prompts/README.md) |
| 直接註冊 HTTP、SQL、model source | [examples/non_function_tools](examples/non_function_tools/README.md) |
| 使用內建通用工具 | [examples/standard_tools](examples/standard_tools/README.md) |
| 看完整 examples 地圖 | [examples/README.md](examples/README.md) |
| 查 MCP 完整 API | [docs/mcp-full-support-api.md](docs/mcp-full-support-api.md) |
| 升級或回退 MCP backend | [docs/mcp-2026-07-28-migration.md](docs/mcp-2026-07-28-migration.md) |
| 理解架構與擴充點 | [docs/architecture-walkthrough.md](docs/architecture-walkthrough.md) |
| 查所有文件 | [docs/docs-map.md](docs/docs-map.md) |

## 開發與驗證

完整測試：

```bash
pytest
```

文件建置：

```bash
python scripts/generate_api_docs.py
mkdocs build
```

如果修改 CLI、runtime、transport、adapter、metadata 或 examples，請執行對應測試；README 中的命令不是行為正確性的替代品。

## 已知限制

- Python 3.14 尚未列入支援範圍。
- `legacy_builtin` 是 rollback path，不會取得 MCP `2026-07-28` modern semantics。
- 對外綁定 `0.0.0.0` 前，必須自行處理 Origin、認證、權限與網路邊界。
- Model examples 可能需要額外 dependency 或本機 artifact；每個範例 README 會分開標示。

## License

MIT
