The Registry feature lets you browse, search, and install MCP servers from one or more remote catalogs directly inside the TUI or programmatically via the registry client.
Quick Start
- Add at least one registry to your
config.yaml(see Configuring registries below). - Launch the TUI:
argus-mcp tui - Press the key binding for Registry mode (shown in the footer).
- The browser fetches the server list from your configured registries.
- Use the search box to filter by name or description.
- Select a server, review details in the right panel, and press Install.
- The server definition is written to your
config.yamlas a newbackendsentry and a hot-reload is triggered automatically.
Architecture Overview
┌──────────────────────────────────────────────────────────────────┐
│ RegistryScreen │
│ ┌─────────────────────────┐ ┌────────────────────────────────┐ │
│ │ RegistryBrowserWidget │ │ InstallPanelWidget │ │
│ │ (searchable DataTable) │ │ (detail + Install button) │ │
│ │ │ │ │ │
│ │ Name│Transport│Tools │ │ Name: my-server │ │
│ │ ────│─────────│───── │ │ Transport: stdio │ │
│ │ ... │ stdio │ 12 │ │ Command: uvx my-server │ │
│ └─────────────────────────┘ │ Tools: list_files, read_... │ │
│ │ │ │
│ │ [Install] │ │
│ └────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────┘
│ │
▼ ▼
RegistryClient ──────────── RegistryCache
(httpx) miss? (~/.cache/argus-mcp/registry/)
│
▼
Registry API (GET /v0/servers)
(user-configured URL)
Module Map
| Module | Purpose |
|---|---|
argus_mcp/registry/client.py | Async HTTP client (httpx) hitting the registry API |
argus_mcp/registry/models.py | ServerEntry, ToolDefinition, ServerPage dataclasses |
argus_mcp/registry/cache.py | File-backed JSON cache (~/.cache/argus-mcp/registry/, 300s TTL) |
argus_mcp/config/schema_registry.py | RegistryEntryConfig Pydantic model |
argus_mcp/tui/screens/registry.py | TUI screen: wires browser + install panel |
argus_mcp/tui/widgets/registry_browser.py | Searchable DataTable of servers |
argus_mcp/tui/widgets/install_panel.py | Right-side detail + install button |
argus_mcp/tui/screens/server_detail.py | Full-screen modal for detailed tool listing |
Registry API
The client expects a REST endpoint that implements the /v0/servers contract described below. Any HTTP server returning the correct JSON shapes will work.
Endpoints
| Method | Path | Query Params | Response |
|---|---|---|---|
| GET | /v0/servers | limit, cursor, q (search) | ServerPage JSON |
| GET | /v0/servers/{name} | -- | Single ServerEntry JSON |
ServerEntry JSON Shape
{
"name": "example-server",
"description": "An example MCP server",
"transport": "stdio", // "stdio" | "sse" | "streamable-http"
"command": "uvx example-server", // for stdio
"args": ["--flag"], // optional, for stdio
"url": "", // for sse / streamable-http
"version": "1.2.0",
"icon_url": "",
"categories": ["search", "coding"],
"tools": [
{
"name": "list_files",
"description": "List files in a directory",
"inputSchema": { "type": "object", "properties": { } }
}
]
}
ServerPage JSON Shape
{
"servers": [ ... ], // array of ServerEntry
"next_cursor": "abc123", // null when no more pages
"total": 42 // optional count
}
Configuring Registries
No registries are included by default. You must add the registries you want to use.
Option 1: config.yaml (recommended)
Add a registries section to your config.yaml:
registries:
- name: community
url: "https://glama.ai/api/mcp"
priority: 100
auth: none
- name: smithery
url: "https://registry.smithery.ai"
priority: 200
auth: none
- name: internal
url: "https://registry.corp.example.com/v0/servers"
priority: 50
auth: api-key
api_key_env: INTERNAL_REGISTRY_KEY # reads from environment variable
RegistryEntryConfig Fields
| Field | Type | Default | Description |
|---|---|---|---|
name | string | required | Friendly label (e.g. "community", "internal") |
url | string | required | Base URL of the registry API |
type | "auto" | "glama" | "smithery" | "generic" | "auto" | Registry backend type. "auto" detects from URL; set explicitly if auto-detect picks wrong type. |
priority | int | 100 | Lower number = checked first |
auth | "none" | "api-key" | "bearer" | "none" | Authentication type |
api_key_env | string | -- | Environment variable for API key (when auth: api-key) |
token_env | string | -- | Environment variable for bearer token (when auth: bearer) |
Option 2: TUI Settings
You can also manage registries from Settings > Registries in the TUI. These are persisted to the TUI's local settings.json file.
The TUI settings and config.yaml are merged at runtime. config.yaml registries are checked first, followed by TUI settings entries.
Resolution Order
- TUI settings (
settings.json) registries, sorted by priority config.yamlregistriessection, sorted by priority- If neither has entries, the Registry screen shows a "No registries configured" message
Known Public Registries
The following registries are known to implement (or partially implement) the /v0/servers API contract. None of these are bundled or hardcoded -- add the ones you want to use in your config.yaml.
| Registry | API URL | Catalog Size | Auth | Notes |
|---|---|---|---|---|
| Glama.ai | https://glama.ai/api/mcp | 17,800+ servers | None (public) | Curated directory, community submissions |
| Smithery.ai | https://registry.smithery.ai | 4,500+ MCPs | None (public) | CLI-first (@smithery/cli), built-in OAuth |
| mcpservers.org | -- | Community directory | -- | No REST API (browse only) |
| Composio | -- | 100+ SaaS connectors | -- | Managed MCP integrations |
| OpenTools | https://api.opentools.com | -- | -- | API gateway, OpenAI-compatible |
Note:
Not all public registries implement the exact /v0/servers contract. The RegistryClient expects ServerPage and ServerEntry JSON shapes. Verify the endpoint returns compatible responses before adding it.
Installation Flow
When you press Install on a registry server:
-
ServerEntry.to_backend_config()converts the entry to a backend config dict matching Argus's config format:Transport Generated Config stdio{"type": "stdio", "command": "...", "args": [...]}sse{"type": "sse", "url": "..."}streamable-http{"type": "streamable-http", "url": "..."} -
The config dict is written to
config.yamlunderbackends.<server-name>. -
A hot-reload is triggered via the management API, so the new backend starts connecting without a server restart.
Example
Installing a server called "mcp-github" with transport stdio adds:
backends:
# ... existing backends ...
mcp-github:
type: stdio
command: uvx mcp-github
args: []
Management API Search
Argus exposes a server-side search endpoint through the management API that proxies queries to your configured registries. This is distinct from the external registry's own API.
GET /manage/v1/registry/search
Endpoint: GET /manage/v1/registry/search
| Parameter | Type | Required | Description |
|---|---|---|---|
q | string | yes | Search query string |
limit | int | no | Max results (1–100, default 20) |
registry | string | no | Filter to a named registry only |
Behavior: Searches configured registries in priority order, stopping at the first registry that returns results.
Example:
curl "http://localhost:9000/manage/v1/registry/search?q=github&limit=5"
Response:
{
"servers": [
{
"name": "mcp-github",
"description": "GitHub MCP server",
"transport": "stdio",
"command": "uvx mcp-github",
"version": "1.0.0"
}
],
"registry": "community",
"total": 1
}
Error responses:
| Status | Code | Meaning |
|---|---|---|
| 400 | bad_request | Missing or invalid q parameter |
| 404 | not_configured | No registries configured |
| 404 | not_found | Named registry not found |
Cache
API responses are cached to ~/.cache/argus-mcp/registry/ as JSON files (one per registry URL). The cache has a 300-second TTL -- after that, the next request re-fetches from the API. On network failure, the client transparently falls back to the cache.
To clear the cache manually:
rm -rf ~/.cache/argus-mcp/registry/
Running Your Own Registry
If you want to serve a private registry:
-
Build a compatible API -- any HTTP server that returns the JSON shapes above at
GET /v0/serverswill work. The client only requires:GET /v0/servers(list/paginate)GET /v0/servers/{name}(single entry)
-
Static file approach -- for a tiny catalog, serve a static
servers.json:{ "servers": [ { "name": "my-internal-tool", "description": "Internal analysis tool", "transport": "stdio", "command": "uvx my-internal-tool", "version": "0.3.0", "tools": [] } ], "total": 1 }Host it behind nginx/caddy at
https://internal.example.com/v0/servers. -
Add it to your config:
registries: - name: internal url: "https://internal.example.com" priority: 10 auth: none