tooldex 0.1.1__tar.gz
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.
- tooldex-0.1.1/.github/CODEOWNERS +1 -0
- tooldex-0.1.1/.github/PULL_REQUEST_TEMPLATE.md +30 -0
- tooldex-0.1.1/.github/workflows/docs.yml +24 -0
- tooldex-0.1.1/.github/workflows/tests.yml +29 -0
- tooldex-0.1.1/.gitignore +69 -0
- tooldex-0.1.1/CONTRIBUTING.md +127 -0
- tooldex-0.1.1/PKG-INFO +395 -0
- tooldex-0.1.1/README.dev.md +260 -0
- tooldex-0.1.1/README.md +374 -0
- tooldex-0.1.1/docs/index.md +364 -0
- tooldex-0.1.1/docs/stylesheets/extra.css +63 -0
- tooldex-0.1.1/mkdocs.yml +40 -0
- tooldex-0.1.1/package-lock.json +6 -0
- tooldex-0.1.1/pyproject.toml +38 -0
- tooldex-0.1.1/requirements.txt +27 -0
- tooldex-0.1.1/site/404.html +357 -0
- tooldex-0.1.1/site/assets/images/favicon.png +0 -0
- tooldex-0.1.1/site/assets/javascripts/bundle.79ae519e.min.js +16 -0
- tooldex-0.1.1/site/assets/javascripts/bundle.79ae519e.min.js.map +7 -0
- tooldex-0.1.1/site/assets/javascripts/lunr/min/lunr.ar.min.js +1 -0
- tooldex-0.1.1/site/assets/javascripts/lunr/min/lunr.da.min.js +18 -0
- tooldex-0.1.1/site/assets/javascripts/lunr/min/lunr.de.min.js +18 -0
- tooldex-0.1.1/site/assets/javascripts/lunr/min/lunr.du.min.js +18 -0
- tooldex-0.1.1/site/assets/javascripts/lunr/min/lunr.el.min.js +1 -0
- tooldex-0.1.1/site/assets/javascripts/lunr/min/lunr.es.min.js +18 -0
- tooldex-0.1.1/site/assets/javascripts/lunr/min/lunr.fi.min.js +18 -0
- tooldex-0.1.1/site/assets/javascripts/lunr/min/lunr.fr.min.js +18 -0
- tooldex-0.1.1/site/assets/javascripts/lunr/min/lunr.he.min.js +1 -0
- tooldex-0.1.1/site/assets/javascripts/lunr/min/lunr.hi.min.js +1 -0
- tooldex-0.1.1/site/assets/javascripts/lunr/min/lunr.hu.min.js +18 -0
- tooldex-0.1.1/site/assets/javascripts/lunr/min/lunr.hy.min.js +1 -0
- tooldex-0.1.1/site/assets/javascripts/lunr/min/lunr.it.min.js +18 -0
- tooldex-0.1.1/site/assets/javascripts/lunr/min/lunr.ja.min.js +1 -0
- tooldex-0.1.1/site/assets/javascripts/lunr/min/lunr.jp.min.js +1 -0
- tooldex-0.1.1/site/assets/javascripts/lunr/min/lunr.kn.min.js +1 -0
- tooldex-0.1.1/site/assets/javascripts/lunr/min/lunr.ko.min.js +1 -0
- tooldex-0.1.1/site/assets/javascripts/lunr/min/lunr.multi.min.js +1 -0
- tooldex-0.1.1/site/assets/javascripts/lunr/min/lunr.nl.min.js +18 -0
- tooldex-0.1.1/site/assets/javascripts/lunr/min/lunr.no.min.js +18 -0
- tooldex-0.1.1/site/assets/javascripts/lunr/min/lunr.pt.min.js +18 -0
- tooldex-0.1.1/site/assets/javascripts/lunr/min/lunr.ro.min.js +18 -0
- tooldex-0.1.1/site/assets/javascripts/lunr/min/lunr.ru.min.js +18 -0
- tooldex-0.1.1/site/assets/javascripts/lunr/min/lunr.sa.min.js +1 -0
- tooldex-0.1.1/site/assets/javascripts/lunr/min/lunr.stemmer.support.min.js +1 -0
- tooldex-0.1.1/site/assets/javascripts/lunr/min/lunr.sv.min.js +18 -0
- tooldex-0.1.1/site/assets/javascripts/lunr/min/lunr.ta.min.js +1 -0
- tooldex-0.1.1/site/assets/javascripts/lunr/min/lunr.te.min.js +1 -0
- tooldex-0.1.1/site/assets/javascripts/lunr/min/lunr.th.min.js +1 -0
- tooldex-0.1.1/site/assets/javascripts/lunr/min/lunr.tr.min.js +18 -0
- tooldex-0.1.1/site/assets/javascripts/lunr/min/lunr.vi.min.js +1 -0
- tooldex-0.1.1/site/assets/javascripts/lunr/min/lunr.zh.min.js +1 -0
- tooldex-0.1.1/site/assets/javascripts/lunr/tinyseg.js +206 -0
- tooldex-0.1.1/site/assets/javascripts/lunr/wordcut.js +6708 -0
- tooldex-0.1.1/site/assets/javascripts/workers/search.2c215733.min.js +42 -0
- tooldex-0.1.1/site/assets/javascripts/workers/search.2c215733.min.js.map +7 -0
- tooldex-0.1.1/site/assets/stylesheets/main.484c7ddc.min.css +1 -0
- tooldex-0.1.1/site/assets/stylesheets/main.484c7ddc.min.css.map +1 -0
- tooldex-0.1.1/site/assets/stylesheets/palette.ab4e12ef.min.css +1 -0
- tooldex-0.1.1/site/assets/stylesheets/palette.ab4e12ef.min.css.map +1 -0
- tooldex-0.1.1/site/index.html +1348 -0
- tooldex-0.1.1/site/search/search_index.json +164 -0
- tooldex-0.1.1/site/sitemap.xml +7 -0
- tooldex-0.1.1/site/sitemap.xml.gz +0 -0
- tooldex-0.1.1/site/stylesheets/extra.css +63 -0
- tooldex-0.1.1/tests/__init__.py +0 -0
- tooldex-0.1.1/tests/conftest.py +21 -0
- tooldex-0.1.1/tests/test_api_servers.py +126 -0
- tooldex-0.1.1/tests/test_config_detector.py +97 -0
- tooldex-0.1.1/tests/test_models.py +71 -0
- tooldex-0.1.1/tests/test_parser_singleton.py +67 -0
- tooldex-0.1.1/tests/test_parsers.py +226 -0
- tooldex-0.1.1/tests/test_paths.py +122 -0
- tooldex-0.1.1/tests/test_readers.py +104 -0
- tooldex-0.1.1/tests/test_results.py +80 -0
- tooldex-0.1.1/tests/test_to_manifest.py +98 -0
- tooldex-0.1.1/tooldex/__init__.py +6 -0
- tooldex-0.1.1/tooldex/_cli_output.py +141 -0
- tooldex-0.1.1/tooldex/api/__init__.py +0 -0
- tooldex-0.1.1/tooldex/api/app.py +74 -0
- tooldex-0.1.1/tooldex/api/deps.py +0 -0
- tooldex-0.1.1/tooldex/api/routers/__init__.py +0 -0
- tooldex-0.1.1/tooldex/api/routers/files.py +31 -0
- tooldex-0.1.1/tooldex/api/routers/health.py +82 -0
- tooldex-0.1.1/tooldex/api/routers/servers.py +127 -0
- tooldex-0.1.1/tooldex/cli.py +346 -0
- tooldex-0.1.1/tooldex/core/__init__.py +0 -0
- tooldex-0.1.1/tooldex/core/discovery/__init__.py +42 -0
- tooldex-0.1.1/tooldex/core/discovery/_docker_mcp.py +246 -0
- tooldex-0.1.1/tooldex/core/discovery/_parsers.py +220 -0
- tooldex-0.1.1/tooldex/core/discovery/_paths.py +117 -0
- tooldex-0.1.1/tooldex/core/discovery/_readers.py +182 -0
- tooldex-0.1.1/tooldex/core/discovery/_status_claude.py +68 -0
- tooldex-0.1.1/tooldex/core/discovery/_status_codex.py +57 -0
- tooldex-0.1.1/tooldex/core/discovery/_status_cursor.py +65 -0
- tooldex-0.1.1/tooldex/core/discovery/config_detector.py +249 -0
- tooldex-0.1.1/tooldex/core/discovery/mcp_client.py +412 -0
- tooldex-0.1.1/tooldex/core/discovery/results.py +143 -0
- tooldex-0.1.1/tooldex/core/discovery/to_manifest.py +50 -0
- tooldex-0.1.1/tooldex/core/discovery/tool_discovery.py +105 -0
- tooldex-0.1.1/tooldex/core/models/__init__.py +7 -0
- tooldex-0.1.1/tooldex/core/models/manifest.py +24 -0
- tooldex-0.1.1/tooldex/core/models/server.py +54 -0
- tooldex-0.1.1/tooldex/core/parsers/__init__.py +0 -0
- tooldex-0.1.1/tooldex/core/parsers/parser.py +67 -0
- tooldex-0.1.1/tooldex/settings.py +1 -0
- tooldex-0.1.1/tooldex/ui/.vite/deps_temp_b4933b73/package.json +3 -0
- tooldex-0.1.1/tooldex/ui/dist/assets/index-DzYGk_2D.js +8 -0
- tooldex-0.1.1/tooldex/ui/dist/assets/index-EQo7TfH-.css +1 -0
- tooldex-0.1.1/tooldex/ui/dist/index.html +18 -0
- tooldex-0.1.1/tooldex/ui/dist/tooldex.ico +0 -0
- tooldex-0.1.1/tooldex/ui/dist/tooldex.svg +6 -0
- tooldex-0.1.1/tooldex/ui/index.html +17 -0
- tooldex-0.1.1/tooldex/ui/package-lock.json +1565 -0
- tooldex-0.1.1/tooldex/ui/package.json +19 -0
- tooldex-0.1.1/tooldex/ui/public/tooldex.ico +0 -0
- tooldex-0.1.1/tooldex/ui/public/tooldex.svg +6 -0
- tooldex-0.1.1/tooldex/ui/src/App.jsx +137 -0
- tooldex-0.1.1/tooldex/ui/src/api.js +32 -0
- tooldex-0.1.1/tooldex/ui/src/components/Topbar.jsx +53 -0
- tooldex-0.1.1/tooldex/ui/src/components/ui.jsx +276 -0
- tooldex-0.1.1/tooldex/ui/src/constants.js +14 -0
- tooldex-0.1.1/tooldex/ui/src/hooks/useFetch.js +17 -0
- tooldex-0.1.1/tooldex/ui/src/index.css +128 -0
- tooldex-0.1.1/tooldex/ui/src/main.jsx +6 -0
- tooldex-0.1.1/tooldex/ui/src/views/Agents.jsx +168 -0
- tooldex-0.1.1/tooldex/ui/src/views/Dashboard.jsx +114 -0
- tooldex-0.1.1/tooldex/ui/src/views/Permissions.jsx +109 -0
- tooldex-0.1.1/tooldex/ui/src/views/Servers.jsx +689 -0
- tooldex-0.1.1/tooldex/ui/vite.config.js +20 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
* @RiaBanerjee24
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
## Summary
|
|
2
|
+
|
|
3
|
+
<!-- What does this PR change, and why? -->
|
|
4
|
+
|
|
5
|
+
## Related issue
|
|
6
|
+
|
|
7
|
+
<!-- Link any related issue, e.g. Closes #123 -->
|
|
8
|
+
|
|
9
|
+
## Changes
|
|
10
|
+
|
|
11
|
+
<!-- Bullet list of the key changes -->
|
|
12
|
+
|
|
13
|
+
-
|
|
14
|
+
|
|
15
|
+
## Testing
|
|
16
|
+
|
|
17
|
+
<!-- How did you verify this works? Include commands run and relevant output. -->
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Checklist
|
|
24
|
+
|
|
25
|
+
- [ ] I read [CONTRIBUTING.md](../CONTRIBUTING.md)
|
|
26
|
+
- [ ] `pytest` passes locally (required — CI will block the merge otherwise)
|
|
27
|
+
- [ ] I added/updated unit tests in `tests/` for any new or changed logic
|
|
28
|
+
- [ ] I manually verified the change (see Testing above)
|
|
29
|
+
- [ ] I updated relevant docs (`README.md`, `README.dev.md`, `docs/index.md`) if behavior changed
|
|
30
|
+
- [ ] This PR is scoped to a single concern
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
name: Deploy docs
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: write
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
deploy:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
|
|
16
|
+
- uses: actions/setup-python@v5
|
|
17
|
+
with:
|
|
18
|
+
python-version: "3.x"
|
|
19
|
+
|
|
20
|
+
- name: Install MkDocs
|
|
21
|
+
run: pip install mkdocs-material
|
|
22
|
+
|
|
23
|
+
- name: Deploy to GitHub Pages
|
|
24
|
+
run: mkdocs gh-deploy --force
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
name: Tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
branches: [main]
|
|
6
|
+
push:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
test:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
strategy:
|
|
16
|
+
matrix:
|
|
17
|
+
python-version: ["3.10", "3.11", "3.12"]
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v4
|
|
20
|
+
|
|
21
|
+
- uses: actions/setup-python@v5
|
|
22
|
+
with:
|
|
23
|
+
python-version: ${{ matrix.python-version }}
|
|
24
|
+
|
|
25
|
+
- name: Install tooldex with test dependencies
|
|
26
|
+
run: pip install -e ".[test]"
|
|
27
|
+
|
|
28
|
+
- name: Run unit tests
|
|
29
|
+
run: pytest -v
|
tooldex-0.1.1/.gitignore
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.pyo
|
|
5
|
+
*.pyd
|
|
6
|
+
.Python
|
|
7
|
+
*.egg
|
|
8
|
+
*.egg-info/
|
|
9
|
+
build/
|
|
10
|
+
.eggs/
|
|
11
|
+
pip-wheel-metadata/
|
|
12
|
+
.pypirc
|
|
13
|
+
|
|
14
|
+
# Virtual environments
|
|
15
|
+
.venv/
|
|
16
|
+
venv/
|
|
17
|
+
env/
|
|
18
|
+
ENV/
|
|
19
|
+
|
|
20
|
+
# Environment variables
|
|
21
|
+
.env
|
|
22
|
+
.env.local
|
|
23
|
+
.env.*.local
|
|
24
|
+
|
|
25
|
+
# Node
|
|
26
|
+
node_modules/
|
|
27
|
+
tooldex/ui/node_modules/
|
|
28
|
+
npm-debug.log*
|
|
29
|
+
yarn-debug.log*
|
|
30
|
+
yarn-error.log*
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
# Test / lint caches
|
|
34
|
+
.pytest_cache/
|
|
35
|
+
.coverage
|
|
36
|
+
.coverage.*
|
|
37
|
+
htmlcov/
|
|
38
|
+
.mypy_cache/
|
|
39
|
+
.ruff_cache/
|
|
40
|
+
|
|
41
|
+
# Logs
|
|
42
|
+
logs/
|
|
43
|
+
*.log
|
|
44
|
+
audit.log
|
|
45
|
+
changes.txt
|
|
46
|
+
|
|
47
|
+
# OS
|
|
48
|
+
.DS_Store
|
|
49
|
+
Thumbs.db
|
|
50
|
+
|
|
51
|
+
# IDEs
|
|
52
|
+
.vscode/
|
|
53
|
+
.idea/
|
|
54
|
+
*.swp
|
|
55
|
+
*.swo
|
|
56
|
+
|
|
57
|
+
# OPA
|
|
58
|
+
*.rego.bak
|
|
59
|
+
|
|
60
|
+
# Secrets / keys
|
|
61
|
+
*.pem
|
|
62
|
+
*.key
|
|
63
|
+
*.cert
|
|
64
|
+
*.p12
|
|
65
|
+
|
|
66
|
+
# PyPI / packaging
|
|
67
|
+
*.whl
|
|
68
|
+
*.tar.gz
|
|
69
|
+
MANIFEST
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# Contributing to Tooldex
|
|
2
|
+
|
|
3
|
+
Thanks for taking the time to contribute. This guide covers how to set up the project, the expected workflow, and what to include in a pull request.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Contents
|
|
8
|
+
|
|
9
|
+
- [Getting started](#getting-started)
|
|
10
|
+
- [Development workflow](#development-workflow)
|
|
11
|
+
- [Coding guidelines](#coding-guidelines)
|
|
12
|
+
- [Testing](#testing)
|
|
13
|
+
- [Submitting a pull request](#submitting-a-pull-request)
|
|
14
|
+
- [Reporting bugs](#reporting-bugs)
|
|
15
|
+
- [Adding a new MCP client](#adding-a-new-mcp-client)
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Getting started
|
|
20
|
+
|
|
21
|
+
1. Fork the repository and clone your fork:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
git clone https://github.com/<your-username>/Tooldex.git
|
|
25
|
+
cd Tooldex
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
2. Install in editable mode:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
pip install -e .
|
|
32
|
+
tooldex --version
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
3. Read [`README.dev.md`](README.dev.md) for an overview of the project structure and architecture before making non-trivial changes.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Development workflow
|
|
40
|
+
|
|
41
|
+
1. Create a branch off `main`:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
git checkout -b your-feature-name
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
2. Make your changes. Keep commits focused — one logical change per commit.
|
|
48
|
+
|
|
49
|
+
3. Run the unit-test suite and add tests for any new behavior (see [Testing](#testing)) before opening a PR. This is mandatory — the same suite runs in CI on every PR and must pass before a PR is considered healthy.
|
|
50
|
+
|
|
51
|
+
4. Push your branch and open a pull request against `main`.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Coding guidelines
|
|
56
|
+
|
|
57
|
+
- Match the existing style of the module you're editing rather than introducing a new convention.
|
|
58
|
+
- Keep the sync/async boundary intact: CLI and API handlers are sync; only `core/discovery/mcp_client.py` should contain async I/O. See [`README.dev.md`](README.dev.md#async-architecture).
|
|
59
|
+
- New data structures should be Pydantic v2 models, consistent with `core/models/`.
|
|
60
|
+
- Don't add dependencies unless necessary. If you do, add them to `pyproject.toml` under `dependencies`.
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Testing
|
|
65
|
+
|
|
66
|
+
Tooldex has a `pytest` unit-test suite under `tests/`, covering config parsing, path resolution, discovery merging, manifest building, the parser singleton, and the API routers. **All tests must pass before a PR can be merged** — the same suite runs in CI (see [`.github/workflows/tests.yml`](.github/workflows/tests.yml)) against Python 3.10–3.12.
|
|
67
|
+
|
|
68
|
+
Install test dependencies and run the suite:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
pip install -e ".[test]"
|
|
72
|
+
pytest
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Run a single file or a single test while iterating:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
pytest tests/test_parsers.py
|
|
79
|
+
pytest tests/test_parsers.py::TestParseMcpServers::test_parses_stdio_server -v
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
If you add or change behavior in `tooldex/core/` or `tooldex/api/`, add or update the corresponding test file in `tests/` as part of your PR — a PR that changes logic without matching test coverage will be asked to add it.
|
|
83
|
+
|
|
84
|
+
For manual, end-to-end checks against your own MCP config:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
# Verify discovery against your local MCP config
|
|
88
|
+
tooldex run --no-serve
|
|
89
|
+
|
|
90
|
+
# Inspect the raw discovery payload
|
|
91
|
+
tooldex run --json | jq .
|
|
92
|
+
|
|
93
|
+
# Confirm the API server starts and responds
|
|
94
|
+
tooldex run
|
|
95
|
+
curl http://127.0.0.1:8282/api/health/
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## Submitting a pull request
|
|
101
|
+
|
|
102
|
+
Use the [pull request template](.github/PULL_REQUEST_TEMPLATE.md) (auto-filled when you open a PR). In summary, include:
|
|
103
|
+
|
|
104
|
+
- A clear description of what changed and why.
|
|
105
|
+
- Any relevant issue numbers.
|
|
106
|
+
- The manual verification steps you ran (commands + output, where useful).
|
|
107
|
+
- Notes on any follow-up work that's intentionally out of scope.
|
|
108
|
+
|
|
109
|
+
Keep PRs scoped to a single concern — smaller PRs are easier to review and merge.
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## Reporting bugs
|
|
114
|
+
|
|
115
|
+
Open a GitHub issue with:
|
|
116
|
+
|
|
117
|
+
- Tooldex version (`tooldex --version`)
|
|
118
|
+
- Python version and OS
|
|
119
|
+
- The MCP client(s) and config involved
|
|
120
|
+
- Steps to reproduce, expected behavior, and actual behavior
|
|
121
|
+
- Relevant output from `tooldex run --json` or server logs, with secrets redacted
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## Adding a new MCP client
|
|
126
|
+
|
|
127
|
+
See [`README.dev.md` → Adding a new MCP client](README.dev.md#adding-a-new-mcp-client) for the exact steps (path resolvers, `build_plan()` registration, optional status enrichment and agent CLI fallback).
|
tooldex-0.1.1/PKG-INFO
ADDED
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: tooldex
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Unified MCP Server Observatory
|
|
5
|
+
License: MIT
|
|
6
|
+
Keywords: agents,ai,mcp,observability,permissions
|
|
7
|
+
Requires-Python: >=3.10
|
|
8
|
+
Requires-Dist: fastapi>=0.115.0
|
|
9
|
+
Requires-Dist: mcp>=1.0
|
|
10
|
+
Requires-Dist: pydantic>=2.0
|
|
11
|
+
Requires-Dist: pyyaml>=6.0
|
|
12
|
+
Requires-Dist: tomli>=2.0; python_version < '3.11'
|
|
13
|
+
Requires-Dist: typer>=0.12.0
|
|
14
|
+
Requires-Dist: uvicorn[standard]>=0.30.0
|
|
15
|
+
Requires-Dist: watchfiles>=0.21.0
|
|
16
|
+
Provides-Extra: test
|
|
17
|
+
Requires-Dist: httpx>=0.27; extra == 'test'
|
|
18
|
+
Requires-Dist: pytest-cov>=5.0; extra == 'test'
|
|
19
|
+
Requires-Dist: pytest>=8.0; extra == 'test'
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
|
|
22
|
+
# Tooldex
|
|
23
|
+
|
|
24
|
+
Tooldex autodiscovers MCP servers configured across your AI clients — Claude Code, Cursor, Codex, Docker MCP Toolkit — and surfaces them in a unified UI. No manual config. Run it from any project directory and it finds everything.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Contents
|
|
29
|
+
|
|
30
|
+
- [Requirements](#requirements)
|
|
31
|
+
- [Installation](#installation)
|
|
32
|
+
- [Quick start](#quick-start)
|
|
33
|
+
- [How discovery works](#how-discovery-works)
|
|
34
|
+
- [Config file locations](#config-file-locations)
|
|
35
|
+
- [MCP config format](#mcp-config-format)
|
|
36
|
+
- [CLI reference](#cli-reference)
|
|
37
|
+
- [JSON output](#json-output)
|
|
38
|
+
- [API endpoints](#api-endpoints)
|
|
39
|
+
- [Testing](#testing)
|
|
40
|
+
- [Contributing](#contributing)
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Requirements
|
|
45
|
+
|
|
46
|
+
- Python 3.10 or later
|
|
47
|
+
- At least one supported MCP client configured (Claude Code, Cursor, Codex, or Docker MCP Toolkit)
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Installation
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
pip install tooldex
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Verify:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
tooldex --version
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Quick start
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
cd your-project
|
|
69
|
+
tooldex run
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Tooldex scans config files, probes each discovered server for its tool surface, and opens the UI. The startup banner shows where to connect:
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
╔══════════════════════════════════════════════════╗
|
|
76
|
+
║ tooldex v0.1.1 ║
|
|
77
|
+
╠══════════════════════════════════════════════════╣
|
|
78
|
+
║ Servers 12 ║
|
|
79
|
+
║ Tools 187 ║
|
|
80
|
+
╠══════════════════════════════════════════════════╣
|
|
81
|
+
║ → http://127.0.0.1:8282 ║
|
|
82
|
+
╚══════════════════════════════════════════════════╝
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
To see the discovery summary without starting the server:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
tooldex run --no-serve
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## How discovery works
|
|
94
|
+
|
|
95
|
+
When you run `tooldex run`, the following happens in order:
|
|
96
|
+
|
|
97
|
+
1. **Config scan** — Tooldex reads every known MCP config location for the current directory (see [Config file locations](#config-file-locations)). Each found server gets a qualified ID in the form `{client}:{server_name}` so servers from different clients never collide.
|
|
98
|
+
|
|
99
|
+
2. **Live probe** — Each discovered server is contacted concurrently. Tooldex calls `tools/list` on it and records which tools it exposes, how long it took, and any errors.
|
|
100
|
+
|
|
101
|
+
3. **Deduplication** — If the same server name appears in multiple clients (e.g., `browserbase` in both Claude Code and Cursor), both are retained as separate entries under their respective clients. Duplicate server names across clients are reported in the `duplicates` field.
|
|
102
|
+
|
|
103
|
+
4. **UI** — A local web server starts and serves the unified view.
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Config file locations
|
|
108
|
+
|
|
109
|
+
Tooldex checks all of the following on every run. Files that do not exist are skipped silently.
|
|
110
|
+
|
|
111
|
+
### Claude Code
|
|
112
|
+
|
|
113
|
+
| Scope | Path |
|
|
114
|
+
|---|---|
|
|
115
|
+
| Global | `~/.claude.json` |
|
|
116
|
+
| Project | `<project>/.claude/mcp.json` |
|
|
117
|
+
| Project (flat) | `<project>/.claude.json` |
|
|
118
|
+
|
|
119
|
+
### Cursor
|
|
120
|
+
|
|
121
|
+
| Scope | Path |
|
|
122
|
+
|---|---|
|
|
123
|
+
| Global | `~/.cursor/mcp.json` |
|
|
124
|
+
| Project | `<project>/.cursor/mcp.json` |
|
|
125
|
+
|
|
126
|
+
### Codex CLI
|
|
127
|
+
|
|
128
|
+
| Scope | Path |
|
|
129
|
+
|---|---|
|
|
130
|
+
| Global | `~/.codex/config.toml` |
|
|
131
|
+
| Project | `<project>/.codex/config.toml` |
|
|
132
|
+
|
|
133
|
+
### MCP JSON (shared / team configs)
|
|
134
|
+
|
|
135
|
+
| Scope | Path |
|
|
136
|
+
|---|---|
|
|
137
|
+
| Global | `~/.mcp.json` |
|
|
138
|
+
| Project | `<project>/.mcp.json` |
|
|
139
|
+
|
|
140
|
+
### Docker MCP Toolkit
|
|
141
|
+
|
|
142
|
+
Tooldex reads all Docker MCP profiles via `docker mcp profile ls`. No additional configuration is needed.
|
|
143
|
+
|
|
144
|
+
**Project-scoped paths** are discovered by walking up the directory tree from `cwd` until the home directory. This means running `tooldex run` from a nested subdirectory will still find a `.mcp.json` at the project root.
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## MCP config format
|
|
149
|
+
|
|
150
|
+
All JSON-based clients use the same `mcpServers` structure. Tooldex understands both `stdio` (command-based) and `http`/`sse` (URL-based) transports.
|
|
151
|
+
|
|
152
|
+
### stdio server (runs a local process)
|
|
153
|
+
|
|
154
|
+
```json
|
|
155
|
+
{
|
|
156
|
+
"mcpServers": {
|
|
157
|
+
"filesystem": {
|
|
158
|
+
"command": "npx",
|
|
159
|
+
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/home/user"],
|
|
160
|
+
"env": {
|
|
161
|
+
"SOME_VAR": "value"
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
"my-db-server": {
|
|
165
|
+
"command": "node",
|
|
166
|
+
"args": ["/path/to/my-server/index.js"],
|
|
167
|
+
"env": {
|
|
168
|
+
"DB_HOST": "localhost",
|
|
169
|
+
"DB_PORT": "5432"
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### HTTP / SSE server (connects to a remote endpoint)
|
|
177
|
+
|
|
178
|
+
```json
|
|
179
|
+
{
|
|
180
|
+
"mcpServers": {
|
|
181
|
+
"browserbase": {
|
|
182
|
+
"type": "http",
|
|
183
|
+
"url": "https://mcp.browserbase.com/mcp"
|
|
184
|
+
},
|
|
185
|
+
"remote-api": {
|
|
186
|
+
"type": "sse",
|
|
187
|
+
"url": "https://api.example.com/mcp/sse"
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Codex (`~/.codex/config.toml`)
|
|
194
|
+
|
|
195
|
+
Codex uses TOML with an `[mcp_servers.<id>]` table per server:
|
|
196
|
+
|
|
197
|
+
```toml
|
|
198
|
+
[mcp_servers.filesystem]
|
|
199
|
+
command = "npx"
|
|
200
|
+
args = ["-y", "@modelcontextprotocol/server-filesystem", "."]
|
|
201
|
+
|
|
202
|
+
[mcp_servers.github]
|
|
203
|
+
type = "http"
|
|
204
|
+
url = "https://api.githubcopilot.com/mcp/"
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### What Tooldex detects from these files
|
|
208
|
+
|
|
209
|
+
For each config file found, Tooldex reports:
|
|
210
|
+
|
|
211
|
+
- **`status`** — `found` / `not_found` / `empty` / `parse_error` / `read_error`
|
|
212
|
+
- **`server_ids`** — list of server names parsed from the file
|
|
213
|
+
- **`in_file_duplicates`** — server names that appeared more than once as JSON keys (the last value is kept; all prior definitions are silently dropped by the JSON parser)
|
|
214
|
+
|
|
215
|
+
For each server probed:
|
|
216
|
+
|
|
217
|
+
- **`status`** — `found` / `timeout` / `connection_failed` / `protocol_error` / `missing_command`
|
|
218
|
+
- **`tools`** — names, descriptions, and input schemas of every tool the server exposes
|
|
219
|
+
- **`duration_ms`** — probe wall time
|
|
220
|
+
- **`error`** — human-readable failure message when status is not `found`; includes install hints for common missing runtimes (`uvx`, `npx`, `docker`, etc.)
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
## CLI reference
|
|
225
|
+
|
|
226
|
+
```
|
|
227
|
+
tooldex [OPTIONS] COMMAND [ARGS]
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### Global options
|
|
231
|
+
|
|
232
|
+
| Flag | Description |
|
|
233
|
+
|---|---|
|
|
234
|
+
| `--version`, `-V` | Print version and exit |
|
|
235
|
+
| `--help`, `-h` | Show help |
|
|
236
|
+
|
|
237
|
+
### `tooldex run`
|
|
238
|
+
|
|
239
|
+
Autodiscover MCP servers and start the UI.
|
|
240
|
+
|
|
241
|
+
```bash
|
|
242
|
+
tooldex run [OPTIONS]
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
| Flag | Default | Description |
|
|
246
|
+
|---|---|---|
|
|
247
|
+
| `--port`, `-p` | `8282` | Starting port. Increments automatically if occupied. |
|
|
248
|
+
| `--host` | `127.0.0.1` | Interface to bind the UI server to. |
|
|
249
|
+
| `--no-serve` | off | Print discovery summary and exit without starting the server. |
|
|
250
|
+
| `--json` | off | Print discovery result as JSON and exit. Implies `--no-serve`. Does not probe servers. |
|
|
251
|
+
| `--timeout` | `10.0` | Per-server probe timeout in seconds. |
|
|
252
|
+
| `--concurrency` | `8` | Maximum concurrent server probes. |
|
|
253
|
+
| `--no-probe <name>` | — | Skip probing a specific server by name. Repeatable. |
|
|
254
|
+
| `--config <path>` | — | Additional MCP config file to include. Repeatable. Custom configs are processed first and win on duplicate server IDs. |
|
|
255
|
+
|
|
256
|
+
All flags accept both `--flag` and `-flag` prefix.
|
|
257
|
+
|
|
258
|
+
#### Examples
|
|
259
|
+
|
|
260
|
+
```bash
|
|
261
|
+
# Discover and launch UI
|
|
262
|
+
tooldex run
|
|
263
|
+
|
|
264
|
+
# Custom port and host
|
|
265
|
+
tooldex run --port 9000 --host 0.0.0.0
|
|
266
|
+
|
|
267
|
+
# Just print what was found, don't start the server
|
|
268
|
+
tooldex run --no-serve
|
|
269
|
+
|
|
270
|
+
# Skip slow or broken servers during probing
|
|
271
|
+
tooldex run --no-probe node-api-docs --no-probe local-mcp
|
|
272
|
+
|
|
273
|
+
# Include an extra config file
|
|
274
|
+
tooldex run --config ~/shared/team-servers.json
|
|
275
|
+
|
|
276
|
+
# Increase timeout for slow servers
|
|
277
|
+
tooldex run --timeout 30
|
|
278
|
+
|
|
279
|
+
# Use all 16 cores for probing
|
|
280
|
+
tooldex run --concurrency 16
|
|
281
|
+
|
|
282
|
+
# Pipe the discovery result into jq
|
|
283
|
+
tooldex run --json | jq '.duplicates'
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
## JSON output
|
|
289
|
+
|
|
290
|
+
`tooldex run --json` prints a single JSON object to stdout and exits. No servers are probed; this is fast and side-effect-free for use in scripts and CI.
|
|
291
|
+
|
|
292
|
+
```json
|
|
293
|
+
{
|
|
294
|
+
"sources": [
|
|
295
|
+
{
|
|
296
|
+
"client": "claude_code_user",
|
|
297
|
+
"path": "/home/user/.claude.json",
|
|
298
|
+
"status": "found",
|
|
299
|
+
"error": null,
|
|
300
|
+
"server_ids": ["filesystem", "github"],
|
|
301
|
+
"in_file_duplicates": []
|
|
302
|
+
},
|
|
303
|
+
{
|
|
304
|
+
"client": "mcp_json_user",
|
|
305
|
+
"path": "/home/user/.mcp.json",
|
|
306
|
+
"status": "not_found",
|
|
307
|
+
"error": null,
|
|
308
|
+
"server_ids": [],
|
|
309
|
+
"in_file_duplicates": []
|
|
310
|
+
}
|
|
311
|
+
],
|
|
312
|
+
"servers": {
|
|
313
|
+
"claude_code_user:filesystem": {
|
|
314
|
+
"name": "filesystem",
|
|
315
|
+
"transport": "stdio",
|
|
316
|
+
"command": "npx",
|
|
317
|
+
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/home/user"],
|
|
318
|
+
"url": null
|
|
319
|
+
}
|
|
320
|
+
},
|
|
321
|
+
"duplicates": [
|
|
322
|
+
"\"filesystem\" in cursor_user is also configured in claude_code_user",
|
|
323
|
+
"\"firecrawl-mcp\" is a duplicate key in /home/user/.mcp.json (last value kept)"
|
|
324
|
+
]
|
|
325
|
+
}
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
**Fields:**
|
|
329
|
+
|
|
330
|
+
| Field | Description |
|
|
331
|
+
|---|---|
|
|
332
|
+
| `sources` | Every config location checked, with status and server IDs found. |
|
|
333
|
+
| `servers` | Deduplicated map of all servers, keyed by `{client}:{server_id}`. |
|
|
334
|
+
| `duplicates` | Human-readable notes about server name collisions across clients, and duplicate JSON keys within a single file. |
|
|
335
|
+
|
|
336
|
+
**Exit codes:** `0` on success, `1` on serialisation error.
|
|
337
|
+
|
|
338
|
+
---
|
|
339
|
+
|
|
340
|
+
## API endpoints
|
|
341
|
+
|
|
342
|
+
When the server is running (default `http://127.0.0.1:8282`):
|
|
343
|
+
|
|
344
|
+
All endpoints respond with or without a trailing slash.
|
|
345
|
+
|
|
346
|
+
| Method | Endpoint | Description |
|
|
347
|
+
|---|---|---|
|
|
348
|
+
| `GET` | `/api/health/` | `status`, current `timestamp`, and `uptime_seconds` since the server started |
|
|
349
|
+
| `GET` | `/api/servers/` | All MCP servers with `total_servers`, `total_tools`, `scanned_at`. Per server: `tool_count`, `source_file` |
|
|
350
|
+
| `GET` | `/api/servers/{id}/` | Single server with full tool detail |
|
|
351
|
+
| `POST` | `/api/servers/{id}/rescan/` | Re-probe a single server and update its tools in place |
|
|
352
|
+
| `GET` | `/api/files/` | All config files that were scanned: path, client, status, server IDs found, any parse errors |
|
|
353
|
+
| `POST` | `/api/rescan/` | Full rediscovery — re-reads all MCP configs and re-probes every server. Returns `{"status": "already_scanning"}` if a rescan is already in progress. |
|
|
354
|
+
|
|
355
|
+
---
|
|
356
|
+
|
|
357
|
+
## Testing
|
|
358
|
+
|
|
359
|
+
Tooldex has a `pytest` unit-test suite that runs in CI on every PR:
|
|
360
|
+
|
|
361
|
+
```bash
|
|
362
|
+
pip install -e ".[test]"
|
|
363
|
+
pytest
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md#testing) for details. For ad-hoc manual checks against your own MCP config:
|
|
367
|
+
|
|
368
|
+
```bash
|
|
369
|
+
# Verify discovery against your local config
|
|
370
|
+
tooldex run --no-serve
|
|
371
|
+
|
|
372
|
+
# Inspect the raw discovery payload
|
|
373
|
+
tooldex run --json | jq .
|
|
374
|
+
|
|
375
|
+
# Check a specific extra config file
|
|
376
|
+
tooldex run --config ./my-config.json --json
|
|
377
|
+
|
|
378
|
+
# Confirm a server is reachable with a longer timeout
|
|
379
|
+
tooldex run --timeout 30 --no-probe github
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
To run the package from source without installing:
|
|
383
|
+
|
|
384
|
+
```bash
|
|
385
|
+
git clone <repo>
|
|
386
|
+
cd Tooldex
|
|
387
|
+
pip install -e .
|
|
388
|
+
tooldex --version
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
---
|
|
392
|
+
|
|
393
|
+
## Contributing
|
|
394
|
+
|
|
395
|
+
Contributions are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md) for setup instructions, the development workflow, and pull request guidelines.
|