mcp-tool-search 1.1.0
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/LICENSE +21 -0
- package/README.md +215 -0
- package/dist/build-catalog.d.ts +13 -0
- package/dist/build-catalog.d.ts.map +1 -0
- package/dist/build-catalog.js +183 -0
- package/dist/build-catalog.js.map +1 -0
- package/dist/catalog.d.ts +39 -0
- package/dist/catalog.d.ts.map +1 -0
- package/dist/catalog.js +200 -0
- package/dist/catalog.js.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +246 -0
- package/dist/index.js.map +1 -0
- package/dist/pool.d.ts +31 -0
- package/dist/pool.d.ts.map +1 -0
- package/dist/pool.js +158 -0
- package/dist/pool.js.map +1 -0
- package/dist/types.d.ts +39 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.d.ts +23 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +68 -0
- package/dist/utils.js.map +1 -0
- package/package.json +55 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Kaleb Teeter
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
# MCP Tool Search
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/mcp-tool-search)
|
|
4
|
+
[](LICENSE)
|
|
5
|
+
[](https://nodejs.org/)
|
|
6
|
+
[](src/__tests__)
|
|
7
|
+
|
|
8
|
+
**Reduce MCP tool-definition context overhead by ~85–96%.**
|
|
9
|
+
|
|
10
|
+
MCP Tool Search is a proxy server that replaces dozens of MCP tool schemas in your model's context window with just 4 lightweight tools. Instead of loading every tool definition upfront, the model searches for tools on-demand and calls them through the proxy.
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
Before: 50 tool schemas loaded → ~10,000 context tokens consumed every turn
|
|
14
|
+
After: 4 proxy tools loaded → ~600 context tokens (constant)
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Problem
|
|
18
|
+
|
|
19
|
+
Every MCP server you add dumps its full tool schemas into the model's context window. With 5+ servers and 40+ tools, that's **8,000–20,000+ tokens** of schema definitions the model must process on every single turn — even when it doesn't use any of them.
|
|
20
|
+
|
|
21
|
+
## Solution
|
|
22
|
+
|
|
23
|
+
MCP Tool Search sits between your MCP client and your backend servers:
|
|
24
|
+
|
|
25
|
+
1. **Catalog Builder** pre-scans all your MCP servers and snapshots their tool definitions to a local JSON file
|
|
26
|
+
2. **Proxy Server** exposes only 4 tools — the model searches, inspects, and calls tools through the proxy
|
|
27
|
+
3. **Lazy Connections** — backend servers are spawned on first use and kept alive for 5 minutes
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
MCP Client ←→ MCP Tool Search Proxy ←→ Backend MCP Servers
|
|
31
|
+
↓ (lazily spawned)
|
|
32
|
+
catalog.json Context7, GitHub, etc.
|
|
33
|
+
(pre-built snapshot)
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## The 4 Proxy Tools
|
|
37
|
+
|
|
38
|
+
| Tool | Purpose |
|
|
39
|
+
|------|---------|
|
|
40
|
+
| `search_tools` | Fuzzy-search across all backend tools by keyword or capability |
|
|
41
|
+
| `get_tool_schema` | Retrieve the full input schema for a specific tool |
|
|
42
|
+
| `call_tool` | Execute a tool on its backend server through the proxy |
|
|
43
|
+
| `list_servers` | List all cataloged servers and their connection status |
|
|
44
|
+
|
|
45
|
+
## Quick Start
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
npx mcp-tool-search --help
|
|
49
|
+
# Or: npm install -g mcp-tool-search && mcp-build-catalog && mcp-tool-search
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Installation
|
|
53
|
+
|
|
54
|
+
### Option A: npm (recommended)
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
npm install -g mcp-tool-search
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Option B: From source
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
git clone https://github.com/kteeter0405/mcp-tool-search.git
|
|
64
|
+
cd mcp-tool-search
|
|
65
|
+
npm install
|
|
66
|
+
npm run build
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Setup
|
|
70
|
+
|
|
71
|
+
### 1. Configure backend servers
|
|
72
|
+
|
|
73
|
+
MCP Tool Search reads your MCP client's server configuration to discover backend tools. It uses the same `.mcp.json` format as Claude Code.
|
|
74
|
+
|
|
75
|
+
### 2. Build the tool catalog
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
# If installed globally:
|
|
79
|
+
mcp-build-catalog
|
|
80
|
+
|
|
81
|
+
# If from source:
|
|
82
|
+
npm run catalog
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
This connects to each configured MCP server, snapshots their tool definitions, and writes `catalog.json`. The proxy itself is automatically excluded from the catalog.
|
|
86
|
+
|
|
87
|
+
### 3. Add the proxy to your MCP client
|
|
88
|
+
|
|
89
|
+
Add to your `.mcp.json` (or equivalent config):
|
|
90
|
+
|
|
91
|
+
```json
|
|
92
|
+
{
|
|
93
|
+
"mcpServers": {
|
|
94
|
+
"mcp-tool-search": {
|
|
95
|
+
"command": "npx",
|
|
96
|
+
"args": ["-y", "mcp-tool-search"]
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Or if installed from source:
|
|
103
|
+
|
|
104
|
+
```json
|
|
105
|
+
{
|
|
106
|
+
"mcpServers": {
|
|
107
|
+
"mcp-tool-search": {
|
|
108
|
+
"command": "node",
|
|
109
|
+
"args": ["/path/to/mcp-tool-search/dist/index.js"]
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### 4. Disable direct backend servers
|
|
116
|
+
|
|
117
|
+
Remove or disable your other MCP server entries in `.mcp.json` — the proxy handles all tool calls to them now.
|
|
118
|
+
|
|
119
|
+
## Environment Variables
|
|
120
|
+
|
|
121
|
+
| Variable | Default | Purpose |
|
|
122
|
+
|----------|---------|---------|
|
|
123
|
+
| `MCP_TOOL_SEARCH_CATALOG` | `./catalog.json` | Path to the catalog file |
|
|
124
|
+
| `MCP_TOOL_SEARCH_METRICS` | *(none)* | Path to write JSON metrics (for monitoring dashboards) |
|
|
125
|
+
|
|
126
|
+
## Token Savings
|
|
127
|
+
|
|
128
|
+
The proxy's token footprint is **constant** — 4 tools regardless of how many backend servers exist.
|
|
129
|
+
|
|
130
|
+
| Backend Tools | Direct Tokens | Proxy Tokens | Savings |
|
|
131
|
+
|---|---|---|---|
|
|
132
|
+
| 10 | ~2,000 | ~600 | 70% |
|
|
133
|
+
| 25 | ~5,000 | ~600 | 88% |
|
|
134
|
+
| 50 | ~10,000 | ~600 | 94% |
|
|
135
|
+
| 100 | ~20,000 | ~600 | 97% |
|
|
136
|
+
| 200 | ~40,000 | ~600 | 99% |
|
|
137
|
+
|
|
138
|
+
See [BENCHMARKS.md](BENCHMARKS.md) for detailed methodology and measurements.
|
|
139
|
+
|
|
140
|
+
## Security
|
|
141
|
+
|
|
142
|
+
MCP Tool Search uses an **allowlist-based environment filter** when spawning backend servers. Only explicitly safe environment variables (PATH, HOME, NODE_PATH, etc.) are forwarded to child processes. API keys, tokens, and secrets from your shell environment are **never** leaked to backend servers unless explicitly configured in the catalog's per-server `env` block.
|
|
143
|
+
|
|
144
|
+
Additional security measures:
|
|
145
|
+
|
|
146
|
+
- **Connection cap**: Max 20 concurrent server connections (oldest idle connection evicted when limit reached)
|
|
147
|
+
- **Connect timeout**: 15-second timeout on server spawn
|
|
148
|
+
- **Idle cleanup**: Connections auto-close after 5 minutes of inactivity
|
|
149
|
+
- **No shell execution**: Server commands passed as arrays to `child_process.spawn()`, never through shell interpretation
|
|
150
|
+
- **TypeScript strict mode**: Full type safety with no `any` casts in core logic
|
|
151
|
+
- **Minimal dependencies**: Only 2 runtime deps (`@modelcontextprotocol/sdk`, `zod`)
|
|
152
|
+
|
|
153
|
+
> **Note:** `catalog.json` stores per-server env vars from your MCP config (including API tokens that backend servers need to function). Treat this file as sensitive — it is excluded from git (`.gitignore`) and npm publishing (`.npmignore` + `"files"` allowlist) by default. Do not share or commit it.
|
|
154
|
+
|
|
155
|
+
## Trade-offs
|
|
156
|
+
|
|
157
|
+
- **Latency**: Each tool call requires a search + schema lookup step (~2 extra LLM turns for first use of a tool)
|
|
158
|
+
- **Discovery**: The model must search for tools instead of seeing them all upfront — minor overhead for small catalogs
|
|
159
|
+
- **Connection startup**: Servers are lazily spawned, so first calls to a new server have connection overhead
|
|
160
|
+
|
|
161
|
+
### When to use the proxy
|
|
162
|
+
|
|
163
|
+
- **Use it** when you have 5+ MCP servers or 20+ total tools
|
|
164
|
+
- **Skip it** when you have 1–2 servers with few tools
|
|
165
|
+
|
|
166
|
+
## Compatibility
|
|
167
|
+
|
|
168
|
+
Tested with:
|
|
169
|
+
|
|
170
|
+
- [Claude Code](https://docs.anthropic.com/en/docs/claude-code) (primary target)
|
|
171
|
+
- [Claude Desktop](https://claude.ai/download)
|
|
172
|
+
- [Cursor](https://cursor.sh/)
|
|
173
|
+
- [Windsurf](https://codeium.com/windsurf)
|
|
174
|
+
|
|
175
|
+
Should work with any MCP client that supports the stdio transport.
|
|
176
|
+
|
|
177
|
+
## Project Structure
|
|
178
|
+
|
|
179
|
+
```
|
|
180
|
+
mcp-tool-search/
|
|
181
|
+
├── src/
|
|
182
|
+
│ ├── types.ts # Shared type definitions
|
|
183
|
+
│ ├── catalog.ts # Catalog loader + fuzzy search engine
|
|
184
|
+
│ ├── pool.ts # Lazy server connection pool with timeouts
|
|
185
|
+
│ ├── index.ts # Main proxy MCP server
|
|
186
|
+
│ └── build-catalog.ts # Catalog builder CLI
|
|
187
|
+
├── dist/ # Compiled JavaScript (after build)
|
|
188
|
+
├── catalog.json # Generated tool catalog (git-ignored)
|
|
189
|
+
├── package.json
|
|
190
|
+
├── tsconfig.json
|
|
191
|
+
└── README.md
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## Development
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
# Install dependencies
|
|
198
|
+
npm install
|
|
199
|
+
|
|
200
|
+
# Build TypeScript
|
|
201
|
+
npm run build
|
|
202
|
+
|
|
203
|
+
# Run tests
|
|
204
|
+
npm test
|
|
205
|
+
|
|
206
|
+
# Watch mode
|
|
207
|
+
npm run dev
|
|
208
|
+
|
|
209
|
+
# Rebuild catalog
|
|
210
|
+
npm run catalog
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
## License
|
|
214
|
+
|
|
215
|
+
[MIT](LICENSE) — Copyright (c) 2026 Kaleb Teeter
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* MCP Tool Search — Catalog Builder
|
|
4
|
+
*
|
|
5
|
+
* Connects to each MCP server defined in Claude Code's settings,
|
|
6
|
+
* discovers all available tools, and saves them to catalog.json.
|
|
7
|
+
*
|
|
8
|
+
* Usage: npm run catalog
|
|
9
|
+
*
|
|
10
|
+
* The catalog is a snapshot — rebuild it when you add/remove MCP servers.
|
|
11
|
+
*/
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=build-catalog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build-catalog.d.ts","sourceRoot":"","sources":["../src/build-catalog.ts"],"names":[],"mappings":";AACA;;;;;;;;;GASG"}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* MCP Tool Search — Catalog Builder
|
|
4
|
+
*
|
|
5
|
+
* Connects to each MCP server defined in Claude Code's settings,
|
|
6
|
+
* discovers all available tools, and saves them to catalog.json.
|
|
7
|
+
*
|
|
8
|
+
* Usage: npm run catalog
|
|
9
|
+
*
|
|
10
|
+
* The catalog is a snapshot — rebuild it when you add/remove MCP servers.
|
|
11
|
+
*/
|
|
12
|
+
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
13
|
+
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
14
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
15
|
+
import { resolve, dirname } from "node:path";
|
|
16
|
+
import { fileURLToPath } from "node:url";
|
|
17
|
+
import { existsSync } from "node:fs";
|
|
18
|
+
import { homedir } from "node:os";
|
|
19
|
+
import { resolveCommand, buildSafeEnv } from "./utils.js";
|
|
20
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
21
|
+
const OUTPUT_PATH = resolve(__dirname, "..", "catalog.json");
|
|
22
|
+
// Timeout for connecting to each server (ms)
|
|
23
|
+
const CONNECT_TIMEOUT = 15_000;
|
|
24
|
+
/** Find and load MCP server configs from Claude settings */
|
|
25
|
+
async function loadMcpConfigs() {
|
|
26
|
+
// Check multiple possible config locations
|
|
27
|
+
const candidates = [
|
|
28
|
+
// Claude Code project-level
|
|
29
|
+
resolve(process.cwd(), ".mcp.json"),
|
|
30
|
+
// Claude Code user-level
|
|
31
|
+
resolve(homedir(), ".claude", "settings.json"),
|
|
32
|
+
// Claude Desktop
|
|
33
|
+
resolve(homedir(), "AppData", "Roaming", "Claude", "claude_desktop_config.json"),
|
|
34
|
+
// macOS Claude Desktop
|
|
35
|
+
resolve(homedir(), "Library", "Application Support", "Claude", "claude_desktop_config.json"),
|
|
36
|
+
];
|
|
37
|
+
const allConfigs = {};
|
|
38
|
+
for (const path of candidates) {
|
|
39
|
+
if (!existsSync(path))
|
|
40
|
+
continue;
|
|
41
|
+
try {
|
|
42
|
+
const raw = JSON.parse(await readFile(path, "utf-8"));
|
|
43
|
+
// .mcp.json format: { "mcpServers": { ... } }
|
|
44
|
+
// settings.json format: { "mcpServers": { ... } }
|
|
45
|
+
// claude_desktop_config.json format: { "mcpServers": { ... } }
|
|
46
|
+
const servers = raw.mcpServers || raw.MCP_SERVERS || {};
|
|
47
|
+
for (const [name, config] of Object.entries(servers)) {
|
|
48
|
+
// Fix 1: Skip disabled servers
|
|
49
|
+
if (config.disabled === true) {
|
|
50
|
+
process.stderr.write(` Skipped: ${name} (disabled)\n`);
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
if (!allConfigs[name]) {
|
|
54
|
+
allConfigs[name] = config;
|
|
55
|
+
process.stderr.write(` Found: ${name} (from ${path})\n`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
process.stderr.write(` Warning: Could not parse ${path}: ${err}\n`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return allConfigs;
|
|
64
|
+
}
|
|
65
|
+
/** Connect to a server and discover its tools */
|
|
66
|
+
async function discoverTools(name, config) {
|
|
67
|
+
const transport = new StdioClientTransport({
|
|
68
|
+
command: resolveCommand(config.command),
|
|
69
|
+
args: config.args || [],
|
|
70
|
+
env: buildSafeEnv(config.env),
|
|
71
|
+
});
|
|
72
|
+
const client = new Client({ name: "mcp-catalog-builder", version: "2.0.0" }, { capabilities: {} });
|
|
73
|
+
try {
|
|
74
|
+
// Connect with timeout
|
|
75
|
+
await Promise.race([
|
|
76
|
+
client.connect(transport),
|
|
77
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error("Connection timeout")), CONNECT_TIMEOUT)),
|
|
78
|
+
]);
|
|
79
|
+
// List all tools
|
|
80
|
+
const response = await client.listTools();
|
|
81
|
+
const tools = (response.tools || []).map((t) => ({
|
|
82
|
+
name: t.name,
|
|
83
|
+
description: t.description || "",
|
|
84
|
+
inputSchema: t.inputSchema || {},
|
|
85
|
+
}));
|
|
86
|
+
await client.close();
|
|
87
|
+
return {
|
|
88
|
+
command: config.command,
|
|
89
|
+
args: config.args || [],
|
|
90
|
+
env: config.env,
|
|
91
|
+
tools,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
catch (err) {
|
|
95
|
+
process.stderr.write(` ✗ ${name}: ${err.message}\n`);
|
|
96
|
+
try {
|
|
97
|
+
await client.close();
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
// Ignore
|
|
101
|
+
}
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
async function main() {
|
|
106
|
+
process.stderr.write("╔══════════════════════════════════════╗\n");
|
|
107
|
+
process.stderr.write("║ MCP Tool Search — Catalog Builder ║\n");
|
|
108
|
+
process.stderr.write("╚══════════════════════════════════════╝\n\n");
|
|
109
|
+
// Step 1: Find MCP server configs
|
|
110
|
+
process.stderr.write("[1/3] Scanning for MCP server configurations...\n");
|
|
111
|
+
const configs = await loadMcpConfigs();
|
|
112
|
+
const serverNames = Object.keys(configs);
|
|
113
|
+
if (serverNames.length === 0) {
|
|
114
|
+
process.stderr.write("\nNo MCP servers found. Make sure you have:\n" +
|
|
115
|
+
" - .mcp.json in your project root, OR\n" +
|
|
116
|
+
" - ~/.claude/settings.json with mcpServers, OR\n" +
|
|
117
|
+
" - Claude Desktop config with mcpServers\n");
|
|
118
|
+
process.exit(1);
|
|
119
|
+
}
|
|
120
|
+
// Fix 3: Parse --only and --skip CLI flags to filter servers
|
|
121
|
+
const onlyArg = process.argv.find((a) => a.startsWith("--only="));
|
|
122
|
+
const skipArg = process.argv.find((a) => a.startsWith("--skip="));
|
|
123
|
+
if (onlyArg && skipArg) {
|
|
124
|
+
process.stderr.write("\nError: Cannot use --only and --skip together. Pick one.\n");
|
|
125
|
+
process.exit(1);
|
|
126
|
+
}
|
|
127
|
+
// Self-skip: never try to spawn ourselves during catalog build
|
|
128
|
+
let filteredNames = serverNames.filter((n) => n !== "mcp-tool-search");
|
|
129
|
+
if (onlyArg) {
|
|
130
|
+
const onlySet = new Set(onlyArg.replace("--only=", "").split(",").map((s) => s.trim()));
|
|
131
|
+
filteredNames = filteredNames.filter((n) => onlySet.has(n));
|
|
132
|
+
process.stderr.write(` --only filter: ${filteredNames.length}/${serverNames.length} servers selected\n`);
|
|
133
|
+
}
|
|
134
|
+
if (skipArg) {
|
|
135
|
+
const skipSet = new Set(skipArg.replace("--skip=", "").split(",").map((s) => s.trim()));
|
|
136
|
+
filteredNames = filteredNames.filter((n) => !skipSet.has(n));
|
|
137
|
+
process.stderr.write(` --skip filter: ${filteredNames.length}/${serverNames.length} servers selected\n`);
|
|
138
|
+
}
|
|
139
|
+
process.stderr.write(`\nFound ${filteredNames.length} servers.\n\n`);
|
|
140
|
+
// Step 2: Connect and discover tools
|
|
141
|
+
process.stderr.write("[2/3] Discovering tools from each server...\n");
|
|
142
|
+
const catalog = {
|
|
143
|
+
version: "2.0.0",
|
|
144
|
+
generated: new Date().toISOString(),
|
|
145
|
+
servers: {},
|
|
146
|
+
};
|
|
147
|
+
let totalTools = 0;
|
|
148
|
+
let failedServers = 0;
|
|
149
|
+
// Parallel discovery — all servers spawn simultaneously
|
|
150
|
+
const discoveryResults = await Promise.allSettled(filteredNames.map(async (name) => {
|
|
151
|
+
process.stderr.write(` → ${name}...\n`);
|
|
152
|
+
const server = await discoverTools(name, configs[name]);
|
|
153
|
+
return { name, server };
|
|
154
|
+
}));
|
|
155
|
+
for (const result of discoveryResults) {
|
|
156
|
+
if (result.status === "fulfilled" && result.value.server) {
|
|
157
|
+
catalog.servers[result.value.name] = result.value.server;
|
|
158
|
+
totalTools += result.value.server.tools.length;
|
|
159
|
+
process.stderr.write(` ✓ ${result.value.name}: ${result.value.server.tools.length} tools\n`);
|
|
160
|
+
}
|
|
161
|
+
else if (result.status === "rejected") {
|
|
162
|
+
failedServers++;
|
|
163
|
+
process.stderr.write(` ✗ ${result.reason}\n`);
|
|
164
|
+
}
|
|
165
|
+
else if (result.status === "fulfilled" && !result.value.server) {
|
|
166
|
+
failedServers++;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
// Step 3: Save catalog
|
|
170
|
+
process.stderr.write(`\n[3/3] Saving catalog to ${OUTPUT_PATH}...\n`);
|
|
171
|
+
await writeFile(OUTPUT_PATH, JSON.stringify(catalog, null, 2), "utf-8");
|
|
172
|
+
process.stderr.write("\n══════════════════════════════════════\n");
|
|
173
|
+
process.stderr.write(` Catalog built: ${Object.keys(catalog.servers).length} servers, ${totalTools} tools\n`);
|
|
174
|
+
if (failedServers > 0) {
|
|
175
|
+
process.stderr.write(` ⚠ ${failedServers} server(s) failed to connect\n`);
|
|
176
|
+
}
|
|
177
|
+
process.stderr.write("══════════════════════════════════════\n");
|
|
178
|
+
}
|
|
179
|
+
main().catch((err) => {
|
|
180
|
+
process.stderr.write(`Fatal: ${err}\n`);
|
|
181
|
+
process.exit(1);
|
|
182
|
+
});
|
|
183
|
+
//# sourceMappingURL=build-catalog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build-catalog.js","sourceRoot":"","sources":["../src/build-catalog.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Tool Search — Catalog Manager
|
|
3
|
+
*
|
|
4
|
+
* Loads the tool catalog (catalog.json) and provides fuzzy search.
|
|
5
|
+
* The catalog is pre-built by build-catalog.ts which connects to
|
|
6
|
+
* each backend MCP server and snapshots its tool definitions.
|
|
7
|
+
*/
|
|
8
|
+
import type { CatalogData, CatalogServer, SearchResult } from "./types.js";
|
|
9
|
+
export declare class Catalog {
|
|
10
|
+
private readonly path;
|
|
11
|
+
private data;
|
|
12
|
+
private searchIndex;
|
|
13
|
+
constructor(path: string);
|
|
14
|
+
/** Load catalog from disk */
|
|
15
|
+
load(): Promise<void>;
|
|
16
|
+
/** Load catalog from data directly (for testing without filesystem) */
|
|
17
|
+
loadFromData(data: CatalogData): void;
|
|
18
|
+
/** Validate catalog shape to prevent cryptic runtime crashes */
|
|
19
|
+
private validateCatalog;
|
|
20
|
+
/** Build search index from catalog data */
|
|
21
|
+
private buildIndex;
|
|
22
|
+
/** Tokenize a string for fuzzy matching — splits on spaces, underscores, and hyphens */
|
|
23
|
+
private tokenize;
|
|
24
|
+
/** Fuzzy search across all tools */
|
|
25
|
+
search(query: string, maxResults?: number): SearchResult[];
|
|
26
|
+
/** Get a specific server's config */
|
|
27
|
+
getServer(name: string): CatalogServer | undefined;
|
|
28
|
+
/** Get a specific tool's full schema */
|
|
29
|
+
getToolSchema(serverName: string, toolName: string): Record<string, unknown> | undefined;
|
|
30
|
+
/** Total number of servers in catalog */
|
|
31
|
+
get totalServers(): number;
|
|
32
|
+
/** Total number of tools across all servers */
|
|
33
|
+
get totalTools(): number;
|
|
34
|
+
/** List all server names */
|
|
35
|
+
get serverNames(): string[];
|
|
36
|
+
/** Get tool count per server */
|
|
37
|
+
serverToolCounts(): Record<string, number>;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=catalog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAsC3E,qBAAa,OAAO;IASN,OAAO,CAAC,QAAQ,CAAC,IAAI;IARjC,OAAO,CAAC,IAAI,CAA4B;IACxC,OAAO,CAAC,WAAW,CAKX;gBAEqB,IAAI,EAAE,MAAM;IAEzC,6BAA6B;IACvB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ3B,uEAAuE;IACvE,YAAY,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI;IAMrC,gEAAgE;IAChE,OAAO,CAAC,eAAe;IAwBvB,2CAA2C;IAC3C,OAAO,CAAC,UAAU;IAmBlB,wFAAwF;IACxF,OAAO,CAAC,QAAQ;IAQhB,oCAAoC;IACpC,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,GAAE,MAAW,GAAG,YAAY,EAAE;IAkE9D,qCAAqC;IACrC,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAIlD,wCAAwC;IACxC,aAAa,CACX,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,GACf,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS;IAOtC,yCAAyC;IACzC,IAAI,YAAY,IAAI,MAAM,CAEzB;IAED,+CAA+C;IAC/C,IAAI,UAAU,IAAI,MAAM,CAEvB;IAED,4BAA4B;IAC5B,IAAI,WAAW,IAAI,MAAM,EAAE,CAE1B;IAED,gCAAgC;IAChC,gBAAgB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;CAQ3C"}
|