openclaw-mcp-router 0.2.6 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,208 +1,129 @@
1
- # openclaw-mcp-router
1
+ # OpenClaw MCP Router 🚀
2
2
 
3
- Dynamic MCP tool router for [OpenClaw](https://openclaw.ai) semantic search over large MCP tool catalogs to eliminate context bloat.
3
+ **OpenClaw MCP Router** is a dynamic tool discovery layer for [OpenClaw](https://openclaw.ai). It uses semantic vector search to eliminate **Context Bloat** by routing only the necessary Model Context Protocol (MCP) tool schemas to your agent on-demand.
4
4
 
5
- ## The problem
5
+ ## The Problem: Context Window Exhaustion
6
6
 
7
- Loading all MCP tool schemas upfront burns 55k–134k tokens before your agent processes a single message. With 58 tools across 5 MCP servers, that's ~77k tokens wasted on schemas the agent may never use.
7
+ Modern MCP catalogs are growing. Loading every tool schema upfront is expensive and inefficient:
8
8
 
9
- ## The solution
9
+ * **Token Waste:** 5 MCP servers with 50+ tools can burn **55k–134k tokens** before your agent even says "Hello."
10
+ * **Performance Hit:** Massive system prompts degrade reasoning accuracy (the "lost in the middle" phenomenon).
11
+ * **Cost:** High token usage leads to higher API costs for every turn of the conversation.
10
12
 
11
- Two tiny tools replace the full schema dump:
13
+ ## 🛠️ The Solution: Semantic Tool Routing
12
14
 
13
- - **`mcp_search(query)`** — embed the query via Ollama, search a local LanceDB index, return only matching tool definitions (~8.7k tokens, 95% reduction)
14
- - **`mcp_call(tool_name, params_json)`** — look up the owning MCP server, execute the call, return the result
15
+ Instead of a full schema dump, this plugin registers two lightweight "Meta-Tools":
15
16
 
16
- The agent asks for tools it needs instead of receiving every schema upfront.
17
+ 1. **`mcp_search(query)`**: Uses **Ollama** and **LanceDB** to perform a semantic search. It returns only the top-N most relevant tool definitions (reducing overhead by ~95%).
18
+ 2. **`mcp_call(tool_name, params)`**: Dynamically resolves the owning MCP server and executes the call.
17
19
 
18
- ## Install
20
+ > **Result:** Your agent "asks" for the tools it needs, keeping the context window clean and the reasoning sharp.
19
21
 
20
- ```sh
21
- openclaw plugins install openclaw-mcp-router
22
- ```
22
+ ---
23
23
 
24
- **Alternative: install from source**
24
+ ## 🚀 Quick Start
25
25
 
26
- ```bash
27
- git clone https://github.com/lunarmoon26/openclaw-mcp-router.git
28
- openclaw plugins install ./openclaw-mcp-router
29
- ```
26
+ ### 1. Prerequisites
30
27
 
31
- Requires [Ollama](https://ollama.ai) running locally with an embedding model:
28
+ Ensure you have **Ollama** running locally with an embedding model:
32
29
 
33
- ```sh
30
+ ```bash
34
31
  ollama pull embeddinggemma
35
- ollama serve
36
- ```
37
32
 
38
- ## Configuration
39
-
40
- Add to `~/.openclaw/openclaw.yml`:
41
-
42
- ```yaml
43
- tools:
44
- alsoAllow:
45
- - mcp_search
46
- - mcp_call
47
-
48
- plugins:
49
- openclaw-mcp-router:
50
- enabled: true
51
- config:
52
- servers:
53
- - name: filesystem
54
- transport: stdio
55
- command: npx
56
- args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
57
- - name: github
58
- transport: sse
59
- url: https://api.githubcopilot.com/mcp/
60
- embedding:
61
- provider: ollama
62
- model: embeddinggemma # or qwen3-embedding:0.6b, all-minilm
63
- url: http://localhost:11434
64
- search:
65
- topK: 5 # tools returned per search (1–20)
66
- minScore: 0.3 # minimum similarity threshold (0–1)
67
33
  ```
68
34
 
69
- ### Important: `tools.alsoAllow` is required
35
+ ### 2. Installation
70
36
 
71
- The plugin registers `mcp_search` and `mcp_call` as **optional tools** (`optional: true`). This means the gateway loads them, but they are **not exposed to agents** unless explicitly allowlisted.
72
-
73
- If the plugin is running and `openclaw openclaw-mcp-router stats` shows indexed tools, but your agent can't call `mcp_search` — this is why. Add the allowlist to your config:
74
-
75
- ```yaml
76
- # Global — all agents get access
77
- tools:
78
- alsoAllow:
79
- - mcp_search
80
- - mcp_call
81
- ```
82
-
83
- Or scope it to specific agents:
37
+ ```bash
38
+ openclaw plugins install openclaw-mcp-router
84
39
 
85
- ```yaml
86
- # Per-agent or under agents.defaults
87
- agents:
88
- defaults:
89
- tools:
90
- alsoAllow:
91
- - mcp_search
92
- - mcp_call
93
40
  ```
94
41
 
95
- Restart the gateway after changing the config.
42
+ ### 3. Setup & Indexing
96
43
 
97
- ## Configuration reference
44
+ Run the interactive wizard to configure your servers and automatically update your `alsoAllow` permissions:
98
45
 
99
- ### `servers[]`
100
-
101
- | Field | Required | Description |
102
- |-------|----------|-------------|
103
- | `name` | yes | Unique server identifier |
104
- | `transport` | yes | `stdio`, `sse`, or `http` |
105
- | `command` | stdio only | Executable to run |
106
- | `args` | stdio only | Arguments array |
107
- | `env` | no | Extra env vars merged over process.env; supports `${VAR}` expansion |
108
- | `url` | sse/http only | Server endpoint URL |
109
- | `timeout` | no | Per-server connect timeout in ms; overrides `indexer.connectTimeout` |
110
-
111
- ### `embedding`
112
-
113
- | Field | Default | Description |
114
- |-------|---------|-------------|
115
- | `provider` | `ollama` | Only Ollama is supported |
116
- | `model` | `embeddinggemma` | Embedding model name |
117
- | `url` | `http://localhost:11434` | Ollama base URL (must be localhost) |
118
-
119
- ### `vectorDb`
46
+ ```bash
47
+ openclaw openclaw-mcp-router setup
48
+ openclaw openclaw-mcp-router reindex
120
49
 
121
- | Field | Default | Description |
122
- |-------|---------|-------------|
123
- | `path` | `~/.openclaw/openclaw-mcp-router/lancedb` | LanceDB database directory |
50
+ ```
124
51
 
125
- ### `indexer`
52
+ ---
126
53
 
127
- Controls retry behavior and timeouts when connecting to MCP servers at startup. Useful for self-hosted servers (e.g. started via `uvx`) that take time to start up.
54
+ ## ⚙️ Configuration
128
55
 
129
- | Field | Default | Description |
130
- |-------|---------|-------------|
131
- | `connectTimeout` | `60000` | Per-server default connect timeout in ms |
132
- | `maxRetries` | `3` | Retry attempts per server (0 = no retry) |
133
- | `initialRetryDelay` | `2000` | Initial backoff delay in ms |
134
- | `maxRetryDelay` | `30000` | Max backoff cap in ms |
135
- | `maxChunkChars` | `500` | Max characters per chunk for long tool descriptions. `0` = disable chunking |
136
- | `overlapChars` | `100` | Overlap characters between adjacent chunks |
56
+ The plugin is highly configurable via `~/.openclaw/openclaw.json`.
137
57
 
138
- Retries use exponential backoff: delays are `initialRetryDelay * 2^(attempt-1)`, capped at `maxRetryDelay`. With defaults, a slow server gets attempts at ~0s, ~2s, ~4s, ~8s before giving up.
58
+ ### Server Management
139
59
 
140
- **Chunking:** When a tool description exceeds `maxChunkChars`, it is split into overlapping chunks at semantic boundaries (paragraphs, lines, sentences). Each chunk is stored as a separate vector, and search results are deduplicated so each tool appears once with its best matching score. Short descriptions (the common case) are unaffected.
60
+ You can manage servers via the **Interactive TUI**:
141
61
 
142
- Example for a slow-starting Python server:
62
+ ```bash
63
+ openclaw openclaw-mcp-router control
143
64
 
144
- ```yaml
145
- plugins:
146
- openclaw-mcp-router:
147
- config:
148
- mcpServers:
149
- my-python-server:
150
- command: uvx
151
- args: ["my-mcp-server"]
152
- timeout: 120000 # this server needs 2 minutes to start
153
- indexer:
154
- maxRetries: 5
155
- initialRetryDelay: 3000
156
65
  ```
157
66
 
158
- ### `search`
159
-
160
- | Field | Default | Description |
161
- |-------|---------|-------------|
162
- | `topK` | `5` | Max tools returned per search |
163
- | `minScore` | `0.3` | Minimum similarity score (0–1) |
67
+ ### Manual Schema Example
68
+
69
+ For power users, add servers directly to your `plugins.entries`:
70
+
71
+ | Key | Description | Default |
72
+ | --- | --- | --- |
73
+ | `topK` | Number of tools returned per search | `5` |
74
+ | `minScore` | Similarity threshold (0.0 - 1.0) | `0.3` |
75
+ | `maxRetries` | Connection attempts for slow servers | `3` |
76
+
77
+ ```json5
78
+ // ~/.openclaw/openclaw.json
79
+ {
80
+ "plugins": {
81
+ "entries": {
82
+ "openclaw-mcp-router": {
83
+ "enabled": true,
84
+ "config": {
85
+ "servers": [{ "name": "filesystem", "transport": "stdio", "command": "npx", "args": ["..."] }],
86
+ "embedding": { "provider": "ollama", "model": "embeddinggemma" }
87
+ }
88
+ }
89
+ }
90
+ }
91
+ }
164
92
 
165
- ## CLI commands
93
+ ```
166
94
 
167
- ```sh
168
- # Re-index all configured MCP servers
169
- openclaw openclaw-mcp-router reindex
95
+ ---
170
96
 
171
- # Show indexed tool count
172
- openclaw openclaw-mcp-router stats
173
- ```
97
+ ## 🧠 How It Works: Under the Hood
174
98
 
175
- ## How it works
99
+ 1. **Indexing:** During `reindex`, the router connects to all configured MCP servers, fetches their manifests, and generates vector embeddings for every tool description.
100
+ 2. **Storage:** These embeddings are stored in a local **LanceDB** instance for sub-millisecond retrieval.
101
+ 3. **Runtime Discovery:** * Agent detects a task (e.g., "Analyze this CSV").
102
+ * Agent calls `mcp_search("read or analyze csv files")`.
103
+ * Router returns the `filesystem` tool schema.
104
+ * Agent executes the tool via `mcp_call`.
176
105
 
177
- 1. At gateway startup, the plugin connects to each MCP server in parallel (with retry and configurable timeouts), lists its tools, embeds each description via Ollama, and stores them in a local LanceDB index.
178
- 2. When the agent needs to use an MCP capability, it calls `mcp_search("what I want to do")` to find relevant tools.
179
- 3. The agent then calls `mcp_call("tool_name", '{"param": "value"}')` to execute the chosen tool.
180
106
 
181
- Disabling the plugin (`openclaw plugins disable openclaw-mcp-router`) cancels any in-progress indexing immediately. Re-enabling starts fresh.
182
107
 
183
- ## Supported embedding models
108
+ ---
184
109
 
185
- | Model | Dims | Notes |
186
- |-------|------|-------|
187
- | `embeddinggemma` | 768 | Good balance, recommended default |
188
- | `qwen3-embedding:0.6b` | 1024 | Higher quality, larger footprint |
189
- | `all-minilm` | 384 | Fast and lightweight |
110
+ ## 📈 Performance & Benchmarks
190
111
 
191
- Any Ollama embedding model works dimensions are detected automatically for unknown models.
112
+ Based on the [Anthropic Tool Search](https://www.anthropic.com/engineering/advanced-tool-use) pattern, dynamic routing can improve tool selection accuracy significantly:
192
113
 
193
- ## Background
114
+ * **Standard Loading:** ~49% Accuracy (Large catalogs)
115
+ * **Dynamic Routing:** **~88% Accuracy** (Opus 4.5 benchmarks)
194
116
 
195
- This plugin is a basic implementation of the [Tool Search Tool](https://www.anthropic.com/engineering/advanced-tool-use) pattern from Anthropic's advanced tool use guide. The core idea: instead of injecting all tool schemas into the system prompt, provide a search tool that dynamically surfaces only relevant tools at runtime. Anthropic's benchmarks showed this improved tool selection accuracy from 49% to 74% (Opus 4) and 79.5% to 88.1% (Opus 4.5).
117
+ ---
196
118
 
197
- Our approach is intentionally simple — pure vector similarity over tool descriptions. There's plenty of room to improve:
119
+ ## 🤝 Contributing
198
120
 
199
- - **Hybrid search (BM25 + embedding).** Pure embedding search can miss exact keyword matches. Combining sparse retrieval (BM25/TF-IDF) with dense vectors would improve recall, especially for tools with distinctive names like `git_diff` or `kubectl_apply`.
200
- - **LLM-based reranking.** After the initial vector search returns candidates, a small LLM could rerank them based on the full query context — catching semantic nuances that cosine similarity misses.
201
- - **Tool use examples.** Indexing not just descriptions but example invocations (input/output pairs) would let the search match against concrete usage patterns, not just what the tool claims to do.
202
- - **Programmatic tool calling.** Anthropic's guide describes letting the agent compose tool calls inside code blocks rather than pure JSON — reducing context pollution and enabling multi-step tool pipelines.
121
+ We are looking to implement **Hybrid Search (BM25)** and **LLM-based Reranking**. If you're interested in improving LLM orchestration efficiency, we'd love your help!
203
122
 
204
- Contributions welcome if any of these interest you.
123
+ 1. Fork the repo.
124
+ 2. Create your feature branch.
125
+ 3. Submit a PR.
205
126
 
206
- ## License
127
+ ## 📄 License
207
128
 
208
- MIT
129
+ Released under the [MIT License](https://www.google.com/search?q=LICENSE).
@@ -25,7 +25,7 @@
25
25
  },
26
26
  "mcpServersFile": {
27
27
  "type": "string",
28
- "description": "Path to a .mcp.json file. Default: ~/.openclaw/.mcp.json"
28
+ "description": "Path to a .mcp.json file. Default: ~/.openclaw/openclaw-mcp-router/.mcp.json"
29
29
  },
30
30
  "servers": {
31
31
  "type": "array",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openclaw-mcp-router",
3
- "version": "0.2.6",
3
+ "version": "1.0.1",
4
4
  "private": false,
5
5
  "description": "Dynamic MCP tool router for OpenClaw — semantic search over large MCP catalogs to eliminate context bloat",
6
6
  "type": "module",
@@ -18,9 +18,12 @@
18
18
  "ollama"
19
19
  ],
20
20
  "dependencies": {
21
+ "@clack/prompts": "^1.0.1",
21
22
  "@lancedb/lancedb": "^0.26.2",
22
23
  "@modelcontextprotocol/sdk": "^1.27.1",
23
- "@sinclair/typebox": "^0.34.48"
24
+ "@sinclair/typebox": "^0.34.48",
25
+ "json5": "^2.2.3",
26
+ "open": "^11.0.0"
24
27
  },
25
28
  "peerDependencies": {
26
29
  "openclaw": "^2026.2.23"
@@ -37,6 +40,9 @@
37
40
  "openclaw": {
38
41
  "extensions": [
39
42
  "./src/index.ts"
43
+ ],
44
+ "skills": [
45
+ "./skills"
40
46
  ]
41
47
  }
42
48
  }
@@ -0,0 +1,84 @@
1
+ ---
2
+ name: mcp-router
3
+ description: Discover and route tasks to configured MCP tools using mcp_search + mcp_call. Use when a task needs external capabilities (APIs, SaaS, databases, web, files, messaging, infra) and the best tool is not already known in-session, especially before falling back to manual shell/curl/web workflows.
4
+ ---
5
+
6
+ # MCP Router
7
+
8
+ Use MCP as the first integration layer for external capabilities.
9
+
10
+ ## Core Rule
11
+
12
+ Before manual API calls, curl scripts, or ad-hoc web work, run:
13
+
14
+ - `mcp_search("<action-oriented intent>")`
15
+
16
+ If a relevant tool exists, use it with `mcp_call`.
17
+
18
+ ## Fast Workflow
19
+
20
+ 1. **Search capability**
21
+ - Use an action-oriented query: `"create github pull request"`, `"query postgres"`, `"send slack message"`.
22
+ 2. **Select tool**
23
+ - Prefer best intent match + feasible required params.
24
+ 3. **Read schema**
25
+ - Identify required fields, types, enums, nested structure.
26
+ 4. **Call tool**
27
+ - `mcp_call("exact_tool_name", "{...valid JSON...}")`
28
+ 5. **Recover on failure**
29
+ - Fix schema/type mismatch or re-search with rewritten query.
30
+
31
+ ## Query Rewrite Ladder (Deterministic)
32
+
33
+ If search quality is poor, retry in this order:
34
+
35
+ 1. **Action only**: `"read file"`
36
+ 2. **Action + system**: `"read file from s3"`, `"github create issue"`
37
+ 3. **Verb swap**: create/open, read/fetch/get, list/enumerate
38
+ 4. **Scope adjust**: broaden then narrow
39
+
40
+ Stop once you have a high-confidence tool.
41
+
42
+ ## Tool Selection Rules
43
+
44
+ When multiple tools match, rank by:
45
+
46
+ 1. Intent fit (description matches requested outcome)
47
+ 2. Required-input fit (you can provide required params now)
48
+ 3. Simplicity (fewer fragile/optional parameters)
49
+ 4. Score/order from search results (tie-breaker)
50
+
51
+ ## `mcp_call` Parameter Checklist
52
+
53
+ `params_json` must be a **JSON string**.
54
+
55
+ - Include all required fields.
56
+ - Match exact types (`42` vs `"42"`, `true` vs `"true"`).
57
+ - Respect enums and nested object shapes.
58
+ - Do not add unsupported keys unless schema allows them.
59
+
60
+ Examples:
61
+
62
+ ```text
63
+ ✅ mcp_call("filesystem::read_file", '{"path":"/tmp/a.txt"}')
64
+ ❌ mcp_call("filesystem::read_file", {"path":"/tmp/a.txt"})
65
+ ```
66
+
67
+ ```text
68
+ ✅ mcp_call("db::query", '{"sql":"select * from t where id=$1","params":[123]}')
69
+ ```
70
+
71
+ ## Error Handling
72
+
73
+ - **Missing required / invalid type**: re-read schema and correct `params_json`.
74
+ - **Unknown tool name**: re-run `mcp_search` and use exact returned name.
75
+ - **Server-side error**: report clearly; retry only with changed inputs.
76
+ - **No relevant tools**: use native fallback tools/workflow.
77
+
78
+ ## Practical Boundaries
79
+
80
+ - Reuse known tool names in the same task; avoid unnecessary re-search.
81
+ - Re-search when intent changes materially.
82
+ - Do not loop retries blindly; each retry must change query or params.
83
+
84
+ For full examples, see [references/workflows.md](references/workflows.md).
@@ -0,0 +1,184 @@
1
+ # Complete Workflow Examples
2
+
3
+ ---
4
+
5
+ ## Example 0: Check MCP before web search
6
+
7
+ **Goal:** Research a topic — but before using a built-in web search, check if a configured MCP server already handles this.
8
+
9
+ ```
10
+ mcp_search("search the web")
11
+ ```
12
+
13
+ **Tool card returned:**
14
+ ```
15
+ Tool: brave::web_search
16
+ Description: Search the web using the Brave Search API.
17
+ Input Schema:
18
+ - query (string, required): The search query
19
+ - count (number, optional): Number of results (default: 10)
20
+ ```
21
+
22
+ **Call:**
23
+ ```
24
+ mcp_call("brave::web_search", '{"query": "MCP server authentication patterns", "count": 5}')
25
+ ```
26
+
27
+ If no web-search tool appears, fall back to whichever search capability is natively available.
28
+
29
+ **The pattern applies everywhere:**
30
+ - Need to fetch a URL? → `mcp_search("fetch a webpage")` before using curl
31
+ - Need to query a DB? → `mcp_search("run a SQL query")` before writing a connection script
32
+ - Need to post to Slack? → `mcp_search("send a Slack message")` before building an API request
33
+ - Need to read a file? → `mcp_search("read a local file")` before opening a shell
34
+
35
+ The configured MCP catalog is the toolbox. Exhaust it before doing things the hard way.
36
+
37
+ These end-to-end examples show the full search → read tool card → call sequence with realistic inputs.
38
+
39
+ ---
40
+
41
+ ## Example 1: Read a local file
42
+
43
+ **Goal:** Read the contents of `/tmp/report.txt`.
44
+
45
+ ```
46
+ mcp_search("read a local file")
47
+ ```
48
+
49
+ **Tool card returned:**
50
+ ```
51
+ Tool: filesystem::read_file
52
+ Description: Read the complete contents of a file from the local filesystem.
53
+ Input Schema:
54
+ - path (string, required): Absolute path to the file
55
+ - encoding (string, optional): File encoding (default: "utf-8")
56
+ ```
57
+
58
+ **Call:**
59
+ ```
60
+ mcp_call("filesystem::read_file", '{"path": "/tmp/report.txt"}')
61
+ ```
62
+
63
+ ---
64
+
65
+ ## Example 2: Create a GitHub pull request
66
+
67
+ **Goal:** Open a PR from branch `feature/add-auth` to `main`.
68
+
69
+ ```
70
+ mcp_search("create a GitHub pull request")
71
+ ```
72
+
73
+ **Tool card returned:**
74
+ ```
75
+ Tool: github::create_pull_request
76
+ Description: Creates a new pull request in a GitHub repository.
77
+ Input Schema:
78
+ - owner (string, required): Repository owner (user or org)
79
+ - repo (string, required): Repository name
80
+ - title (string, required): PR title
81
+ - head (string, required): Branch containing the changes
82
+ - base (string, required): Branch to merge into
83
+ - body (string, optional): PR description in Markdown
84
+ ```
85
+
86
+ **Call:**
87
+ ```
88
+ mcp_call("github::create_pull_request", '{
89
+ "owner": "acme-corp",
90
+ "repo": "backend",
91
+ "title": "Add JWT authentication",
92
+ "head": "feature/add-auth",
93
+ "base": "main",
94
+ "body": "Implements JWT-based auth as described in issue #42."
95
+ }')
96
+ ```
97
+
98
+ ---
99
+
100
+ ## Example 3: Query a database
101
+
102
+ **Goal:** Count active users in a Postgres database.
103
+
104
+ ```
105
+ mcp_search("execute a SQL query against a Postgres database")
106
+ ```
107
+
108
+ **Tool card returned:**
109
+ ```
110
+ Tool: postgres::query
111
+ Description: Execute a read-only SQL query against the configured Postgres database.
112
+ Input Schema:
113
+ - sql (string, required): SQL statement to execute
114
+ - params (array, optional): Positional parameters for parameterized queries
115
+ ```
116
+
117
+ **Call:**
118
+ ```
119
+ mcp_call("postgres::query", '{"sql": "SELECT COUNT(*) FROM users WHERE active = true"}')
120
+ ```
121
+
122
+ ---
123
+
124
+ ## Example 4: Multi-step workflow (search once, call multiple times)
125
+
126
+ **Goal:** List files in a directory, then read one of them.
127
+
128
+ ```
129
+ mcp_search("list files in a directory")
130
+ ```
131
+
132
+ **Tool card returned:**
133
+ ```
134
+ Tool: filesystem::list_directory
135
+ Description: List the files and subdirectories in a given directory.
136
+ Input Schema:
137
+ - path (string, required): Absolute path to the directory
138
+ - recursive (boolean, optional): Include subdirectories (default: false)
139
+ ```
140
+
141
+ **Call 1 — list:**
142
+ ```
143
+ mcp_call("filesystem::list_directory", '{"path": "/tmp/project"}')
144
+ ```
145
+
146
+ **Result:** `["README.md", "config.json", "src/"]`
147
+
148
+ **Call 2 — read (reuse known tool name `filesystem::read_file` from Example 1):**
149
+ ```
150
+ mcp_call("filesystem::read_file", '{"path": "/tmp/project/config.json"}')
151
+ ```
152
+
153
+ No second `mcp_search` needed — once a tool name is known, reuse it directly.
154
+
155
+ ---
156
+
157
+ ## Example 5: Handling a failed search
158
+
159
+ **Goal:** Get the current weather for a city, but the first query returns nothing.
160
+
161
+ ```
162
+ mcp_search("weather")
163
+ ```
164
+
165
+ **Result:** No matches.
166
+
167
+ **Rephrase with action verb + domain:**
168
+ ```
169
+ mcp_search("get current weather conditions for a city")
170
+ ```
171
+
172
+ **Tool card returned:**
173
+ ```
174
+ Tool: weather-api::current
175
+ Description: Fetches current weather conditions for a given city or coordinates.
176
+ Input Schema:
177
+ - city (string, required): City name or "lat,lon" coordinates
178
+ - units (string, optional): "metric" or "imperial" (default: "metric")
179
+ ```
180
+
181
+ **Call:**
182
+ ```
183
+ mcp_call("weather-api::current", '{"city": "San Francisco", "units": "imperial"}')
184
+ ```