Skip to content

Commit 0a3850d

Browse files
committed
Implement repository detection feature in search-servers command
- Added support for automatic detection of npm and PyPI packages in the search-servers command. - Enhanced command description and usage examples to reflect new functionality. - Introduced configuration option `check_server_repo` to enable/disable repository detection. - Updated SearchServers function to accept a limit parameter and a guesser for repository info. - Added comprehensive documentation for the repository detection feature, including configuration and usage examples.
1 parent 9dd01ab commit 0a3850d

13 files changed

Lines changed: 1479 additions & 20 deletions

File tree

cmd/mcpproxy/main.go

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"go.uber.org/zap"
1414

1515
"mcpproxy-go/internal/config"
16+
"mcpproxy-go/internal/experiments"
1617
"mcpproxy-go/internal/logs"
1718
"mcpproxy-go/internal/registries"
1819
"mcpproxy-go/internal/server"
@@ -101,20 +102,22 @@ func main() {
101102
func createSearchServersCommand() *cobra.Command {
102103
var registryFlag, searchFlag, tagFlag string
103104
var listRegistries bool
105+
var limitFlag int
104106

105107
cmd := &cobra.Command{
106108
Use: "search-servers",
107-
Short: "Search MCP registries for available servers",
109+
Short: "Search MCP registries for available servers with repository detection",
108110
Long: `Search known MCP registries for available servers that can be added as upstreams.
109-
This tool queries embedded registries to discover MCP servers and returns results
110-
that can be directly used with the 'upstream_servers add' command.
111+
This tool queries embedded registries to discover MCP servers and includes automatic
112+
npm/PyPI package detection to enhance results with install commands.
113+
Results can be directly used with the 'upstream_servers add' command.
111114
112115
Examples:
113116
# List all known registries
114117
mcpproxy search-servers --list-registries
115118
116-
# Search for weather-related servers in the Smithery registry
117-
mcpproxy search-servers --registry smithery --search weather
119+
# Search for weather-related servers in the Smithery registry (limit 10 results)
120+
mcpproxy search-servers --registry smithery --search weather --limit 10
118121
119122
# Search for servers tagged as "finance" in the Pulse registry
120123
mcpproxy search-servers --registry pulse --tag finance`,
@@ -128,7 +131,23 @@ Examples:
128131
}
129132

130133
ctx := context.Background()
131-
servers, err := registries.SearchServers(ctx, registryFlag, tagFlag, searchFlag)
134+
135+
// Create config to check if repository guessing is enabled
136+
cfg, err := config.LoadFromFile("")
137+
if err != nil {
138+
// Use default config if loading fails
139+
cfg = config.DefaultConfig()
140+
}
141+
142+
// Create experiments guesser if repository checking is enabled
143+
var guesser *experiments.Guesser
144+
if cfg.CheckServerRepo {
145+
// For CLI, we don't have cache manager, so pass nil
146+
logger := zap.NewNop() // Use no-op logger for CLI
147+
guesser = experiments.NewGuesser(nil, logger)
148+
}
149+
150+
servers, err := registries.SearchServers(ctx, registryFlag, tagFlag, searchFlag, limitFlag, guesser)
132151
if err != nil {
133152
return fmt.Errorf("search failed: %w", err)
134153
}
@@ -147,6 +166,7 @@ Examples:
147166
cmd.Flags().StringVarP(&registryFlag, "registry", "r", "", "Registry ID or name to search (exact match)")
148167
cmd.Flags().StringVarP(&searchFlag, "search", "s", "", "Search term for server name/description")
149168
cmd.Flags().StringVarP(&tagFlag, "tag", "t", "", "Filter servers by tag/category")
169+
cmd.Flags().IntVarP(&limitFlag, "limit", "l", 10, "Maximum number of results to return (default: 10, max: 50)")
150170
cmd.Flags().BoolVar(&listRegistries, "list-registries", false, "List all known registries")
151171

152172
return cmd

docs/repository-detection.md

Lines changed: 272 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,272 @@
1+
# Repository Detection Feature
2+
3+
## Overview
4+
5+
The repository detection feature automatically identifies whether MCP servers discovered through `search_servers` are available as npm or PyPI packages. This enhances search results with accurate installation commands and package metadata.
6+
7+
## Features
8+
9+
- **Automatic Package Detection**: Queries npm registry and PyPI APIs to detect published packages
10+
- **Smart Install Commands**: Generates `npm install` or `pip install` commands when packages are found
11+
- **Intelligent Caching**: Caches API responses for 6 hours to improve performance
12+
- **Configurable**: Enable/disable via `check_server_repo` configuration parameter
13+
- **Result Limits**: Default 10 results (max 50) for optimal performance
14+
15+
## Configuration
16+
17+
### Enable/Disable Repository Detection
18+
19+
Add to your `mcp_config.json`:
20+
21+
```json
22+
{
23+
"check_server_repo": true,
24+
"listen": ":8080"
25+
}
26+
```
27+
28+
- `true` (default): Enable repository detection
29+
- `false`: Disable repository detection (faster but no install commands)
30+
31+
### Default Configuration Template
32+
33+
Repository detection is enabled by default in new configurations:
34+
35+
```json
36+
{
37+
"listen": ":8080",
38+
"data_dir": "",
39+
"enable_tray": true,
40+
"debug_search": false,
41+
"check_server_repo": true,
42+
"mcpServers": [],
43+
"logging": {
44+
"level": "info",
45+
"enable_file": true,
46+
"enable_console": true
47+
}
48+
}
49+
```
50+
51+
## Usage Examples
52+
53+
### CLI Usage
54+
55+
```bash
56+
# Basic search with repository detection
57+
mcpproxy search-servers --registry pulse --search weather
58+
59+
# Limit results for faster response
60+
mcpproxy search-servers --registry smithery --search database --limit 5
61+
62+
# Search without limit specification (uses default 10)
63+
mcpproxy search-servers --registry mcprun --search api
64+
```
65+
66+
### MCP Tool Usage
67+
68+
```json
69+
{
70+
"name": "search_servers",
71+
"arguments": {
72+
"registry": "pulse",
73+
"search": "weather",
74+
"limit": 10
75+
}
76+
}
77+
```
78+
79+
## Output Format
80+
81+
When repository detection finds packages, results include enhanced information:
82+
83+
```json
84+
[
85+
{
86+
"id": "weather-mcp",
87+
"name": "Weather MCP Server",
88+
"description": "Real-time weather data via MCP",
89+
"url": "https://weather.example.com/mcp",
90+
"installCmd": "npm install weather-mcp-server",
91+
"repository_info": {
92+
"npm": {
93+
"type": "npm",
94+
"package_name": "weather-mcp-server",
95+
"version": "1.2.3",
96+
"description": "Weather MCP server for Node.js",
97+
"install_cmd": "npm install weather-mcp-server",
98+
"url": "https://www.npmjs.com/package/weather-mcp-server",
99+
"exists": true
100+
},
101+
"pypi": {
102+
"type": "pypi",
103+
"package_name": "weather-mcp",
104+
"version": "0.5.1",
105+
"description": "Weather MCP server for Python",
106+
"install_cmd": "pip install weather-mcp",
107+
"url": "https://pypi.org/project/weather-mcp/",
108+
"exists": true
109+
}
110+
},
111+
"registry": "Example Registry"
112+
}
113+
]
114+
```
115+
116+
## API Details
117+
118+
### Package Name Extraction
119+
120+
The system intelligently extracts potential package names from:
121+
122+
- Server names
123+
- URL paths and hostnames
124+
- Common MCP naming patterns
125+
126+
**Cleaning Rules:**
127+
- Removes `mcp-`, `mcp_`, `-mcp`, `_mcp` prefixes/suffixes
128+
- Removes `-server`, `_server` suffixes
129+
- Converts to lowercase
130+
- Handles scoped npm packages (`@scope/package`)
131+
132+
### API Endpoints Used
133+
134+
**npm Registry:**
135+
- URL: `https://registry.npmjs.org/{package}`
136+
- Method: GET
137+
- Response: Package metadata with versions, description
138+
- Scoped packages: URL-encoded (`@types/node``%40types%2Fnode`)
139+
140+
**PyPI JSON API:**
141+
- URL: `https://pypi.org/pypi/{package}/json`
142+
- Method: GET
143+
- Response: Package info, releases, metadata
144+
145+
### Caching Strategy
146+
147+
- **Cache Key Format**: `npm:{package}` or `pypi:{package}`
148+
- **TTL**: 6 hours
149+
- **Storage**: Uses existing mcpproxy cache system (BBolt)
150+
- **Cache Miss**: API call → cache result → return
151+
- **Cache Hit**: Return cached result (no API call)
152+
153+
## Performance Considerations
154+
155+
### Result Limits
156+
157+
- **Default**: 10 results
158+
- **Maximum**: 50 results
159+
- **Reason**: Repository detection makes HTTP calls; limits ensure reasonable response times
160+
161+
### Parallel Processing
162+
163+
- npm and PyPI checks run concurrently
164+
- Multiple package names checked in sequence
165+
- Stops at first successful detection per server
166+
167+
### Network Timeouts
168+
169+
- HTTP requests timeout after 10 seconds
170+
- Failed requests don't block other checks
171+
- Errors logged but don't stop search
172+
173+
## Troubleshooting
174+
175+
### Slow Response Times
176+
177+
**Problem**: `search_servers` taking too long
178+
179+
**Solutions**:
180+
1. Reduce limit: `--limit 5`
181+
2. Disable repository detection: `"check_server_repo": false`
182+
3. Check network connectivity to npm/PyPI
183+
184+
### Missing Install Commands
185+
186+
**Problem**: No `installCmd` in results despite packages existing
187+
188+
**Debugging**:
189+
1. Check if `check_server_repo` is enabled
190+
2. Verify package name extraction logic
191+
3. Check cache for existing negative results
192+
4. Test package existence manually:
193+
```bash
194+
curl -s "https://registry.npmjs.org/package-name"
195+
curl -s "https://pypi.org/pypi/package-name/json"
196+
```
197+
198+
### Cache Issues
199+
200+
**Problem**: Outdated repository information
201+
202+
**Solutions**:
203+
1. Wait for cache TTL (6 hours)
204+
2. Restart mcpproxy to clear cache
205+
3. Check cache storage location: `~/.mcpproxy/cache.db`
206+
207+
### API Rate Limits
208+
209+
**Problem**: npm or PyPI returning rate limit errors
210+
211+
**Solutions**:
212+
1. Reduce search frequency
213+
2. Increase cache TTL in code
214+
3. Use smaller result limits
215+
216+
## Development
217+
218+
### Adding New Registry Types
219+
220+
To support additional package registries:
221+
222+
1. Add new `RepositoryType` in `internal/experiments/types.go`
223+
2. Implement checker function in `internal/experiments/guesser.go`
224+
3. Update `GuessRepositoryType` to call new checker
225+
4. Add tests in `internal/experiments/guesser_test.go`
226+
227+
### Testing
228+
229+
Run repository detection tests:
230+
231+
```bash
232+
# Unit tests
233+
go test ./internal/experiments/...
234+
235+
# Integration tests with registries
236+
go test ./internal/registries/... -v
237+
238+
# End-to-end tests
239+
go test ./internal/server/... -run TestSearchServers
240+
```
241+
242+
### Debugging
243+
244+
Enable debug logging to trace repository detection:
245+
246+
```bash
247+
mcpproxy --log-level=debug --tray=false
248+
```
249+
250+
Look for log entries containing:
251+
- `Found npm package`
252+
- `Found PyPI package`
253+
- `Failed to fetch`
254+
- `Repository guessing`
255+
256+
## Security Considerations
257+
258+
- Only queries public npm and PyPI APIs
259+
- No authentication credentials required
260+
- No sensitive data transmitted
261+
- API responses cached locally only
262+
- Network requests respect timeouts
263+
264+
## Future Enhancements
265+
266+
Potential improvements:
267+
268+
1. **Additional Registries**: Docker Hub, GitHub Packages, etc.
269+
2. **Version Management**: Detect latest/compatible versions
270+
3. **Security Scanning**: Check for known vulnerabilities
271+
4. **Install Verification**: Test installation commands
272+
5. **Dependency Analysis**: Show package dependencies

0 commit comments

Comments
 (0)