exactdocs 0.1.0__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.
- exactdocs-0.1.0/.gitignore +33 -0
- exactdocs-0.1.0/PKG-INFO +35 -0
- exactdocs-0.1.0/README.md +11 -0
- exactdocs-0.1.0/features/catalog.feature +20 -0
- exactdocs-0.1.0/features/search.feature +17 -0
- exactdocs-0.1.0/features/steps/http_steps.py +56 -0
- exactdocs-0.1.0/pyproject.toml +55 -0
- exactdocs-0.1.0/src/exactdocs/__init__.py +5 -0
- exactdocs-0.1.0/src/exactdocs/__main__.py +3 -0
- exactdocs-0.1.0/src/exactdocs/_version.py +6 -0
- exactdocs-0.1.0/src/exactdocs/_web/assets/index-B350HwjP.js +10 -0
- exactdocs-0.1.0/src/exactdocs/_web/assets/index-CG8rwfz9.css +2 -0
- exactdocs-0.1.0/src/exactdocs/_web/assets/routes-CCGZxbYl.js +1 -0
- exactdocs-0.1.0/src/exactdocs/_web/index.html +13 -0
- exactdocs-0.1.0/src/exactdocs/bootstrap/__init__.py +5 -0
- exactdocs-0.1.0/src/exactdocs/bootstrap/bridges.py +27 -0
- exactdocs-0.1.0/src/exactdocs/bootstrap/cli.py +48 -0
- exactdocs-0.1.0/src/exactdocs/bootstrap/container.py +28 -0
- exactdocs-0.1.0/src/exactdocs/bootstrap/http.py +90 -0
- exactdocs-0.1.0/src/exactdocs/bootstrap/mcp.py +21 -0
- exactdocs-0.1.0/src/exactdocs/bootstrap/settings.py +15 -0
- exactdocs-0.1.0/src/exactdocs/catalog/__init__.py +9 -0
- exactdocs-0.1.0/src/exactdocs/catalog/adapters/__init__.py +0 -0
- exactdocs-0.1.0/src/exactdocs/catalog/adapters/driven/__init__.py +0 -0
- exactdocs-0.1.0/src/exactdocs/catalog/adapters/driven/memory.py +35 -0
- exactdocs-0.1.0/src/exactdocs/catalog/adapters/driving/__init__.py +0 -0
- exactdocs-0.1.0/src/exactdocs/catalog/adapters/driving/http.py +21 -0
- exactdocs-0.1.0/src/exactdocs/catalog/adapters/driving/mcp.py +18 -0
- exactdocs-0.1.0/src/exactdocs/catalog/dtos.py +42 -0
- exactdocs-0.1.0/src/exactdocs/catalog/errors.py +16 -0
- exactdocs-0.1.0/src/exactdocs/catalog/models.py +34 -0
- exactdocs-0.1.0/src/exactdocs/catalog/module.py +27 -0
- exactdocs-0.1.0/src/exactdocs/catalog/ports/__init__.py +4 -0
- exactdocs-0.1.0/src/exactdocs/catalog/ports/driven.py +18 -0
- exactdocs-0.1.0/src/exactdocs/catalog/ports/driving.py +21 -0
- exactdocs-0.1.0/src/exactdocs/catalog/use_cases.py +33 -0
- exactdocs-0.1.0/src/exactdocs/py.typed +0 -0
- exactdocs-0.1.0/src/exactdocs/retrieval/__init__.py +8 -0
- exactdocs-0.1.0/src/exactdocs/retrieval/adapters/__init__.py +0 -0
- exactdocs-0.1.0/src/exactdocs/retrieval/adapters/driven/__init__.py +0 -0
- exactdocs-0.1.0/src/exactdocs/retrieval/adapters/driven/memory.py +26 -0
- exactdocs-0.1.0/src/exactdocs/retrieval/adapters/driving/__init__.py +0 -0
- exactdocs-0.1.0/src/exactdocs/retrieval/adapters/driving/http.py +17 -0
- exactdocs-0.1.0/src/exactdocs/retrieval/adapters/driving/mcp.py +28 -0
- exactdocs-0.1.0/src/exactdocs/retrieval/dtos.py +53 -0
- exactdocs-0.1.0/src/exactdocs/retrieval/errors.py +17 -0
- exactdocs-0.1.0/src/exactdocs/retrieval/models.py +34 -0
- exactdocs-0.1.0/src/exactdocs/retrieval/module.py +18 -0
- exactdocs-0.1.0/src/exactdocs/retrieval/ports/__init__.py +4 -0
- exactdocs-0.1.0/src/exactdocs/retrieval/ports/driven.py +26 -0
- exactdocs-0.1.0/src/exactdocs/retrieval/ports/driving.py +13 -0
- exactdocs-0.1.0/src/exactdocs/retrieval/use_cases.py +22 -0
- exactdocs-0.1.0/tests/architecture/test_architecture.py +171 -0
- exactdocs-0.1.0/tests/bootstrap/test_app.py +64 -0
- exactdocs-0.1.0/tests/catalog/test_use_cases.py +42 -0
- exactdocs-0.1.0/tests/retrieval/test_search_docs.py +54 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
.venv/
|
|
5
|
+
dist/
|
|
6
|
+
build/
|
|
7
|
+
*.egg-info/
|
|
8
|
+
.pytest_cache/
|
|
9
|
+
.ruff_cache/
|
|
10
|
+
.coverage
|
|
11
|
+
coverage.xml
|
|
12
|
+
htmlcov/
|
|
13
|
+
reports/
|
|
14
|
+
|
|
15
|
+
# Built web UI bundled into the wheel / image (see web/README.md)
|
|
16
|
+
packages/exactdocs/src/exactdocs/_web/
|
|
17
|
+
|
|
18
|
+
# Local data and secrets
|
|
19
|
+
data/
|
|
20
|
+
*.db
|
|
21
|
+
.env
|
|
22
|
+
.env.*
|
|
23
|
+
!.env.example
|
|
24
|
+
|
|
25
|
+
# Editors / OS
|
|
26
|
+
.idea/
|
|
27
|
+
.vscode/*
|
|
28
|
+
!.vscode/extensions.json
|
|
29
|
+
.DS_Store
|
|
30
|
+
Thumbs.db
|
|
31
|
+
|
|
32
|
+
# Claude Code local settings
|
|
33
|
+
.claude/settings.local.json
|
exactdocs-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: exactdocs
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Self-hosted, version-accurate documentation for AI coding agents (MCP server).
|
|
5
|
+
Project-URL: Repository, https://github.com/SirCypkowskyy/ExactDocs
|
|
6
|
+
Project-URL: Issues, https://github.com/SirCypkowskyy/ExactDocs/issues
|
|
7
|
+
Author: Cyprian Gburek
|
|
8
|
+
License-Expression: Apache-2.0
|
|
9
|
+
Keywords: ai-agents,documentation,fastmcp,mcp,rag
|
|
10
|
+
Classifier: Development Status :: 2 - Pre-Alpha
|
|
11
|
+
Classifier: Framework :: FastAPI
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
13
|
+
Classifier: Typing :: Typed
|
|
14
|
+
Requires-Python: >=3.14
|
|
15
|
+
Requires-Dist: cyclopts>=4
|
|
16
|
+
Requires-Dist: exactdocs-kernel==0.1.0
|
|
17
|
+
Requires-Dist: fastapi>=0.120
|
|
18
|
+
Requires-Dist: fastmcp>=4
|
|
19
|
+
Requires-Dist: mcp>=2
|
|
20
|
+
Requires-Dist: pydantic-settings>=2.11
|
|
21
|
+
Requires-Dist: pydantic>=2.12
|
|
22
|
+
Requires-Dist: uvicorn[standard]>=0.38
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
25
|
+
# exactdocs
|
|
26
|
+
|
|
27
|
+
Self-hosted, version-accurate documentation for AI coding agents: an MCP server that serves
|
|
28
|
+
the right docs for the right library version, verbatim and with sources.
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
uvx exactdocs serve # HTTP: web UI + MCP on http://localhost:3000
|
|
32
|
+
uvx exactdocs serve --stdio # MCP over stdio
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
See the [project README](https://github.com/SirCypkowskyy/ExactDocs) for the full documentation.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# exactdocs
|
|
2
|
+
|
|
3
|
+
Self-hosted, version-accurate documentation for AI coding agents: an MCP server that serves
|
|
4
|
+
the right docs for the right library version, verbatim and with sources.
|
|
5
|
+
|
|
6
|
+
```bash
|
|
7
|
+
uvx exactdocs serve # HTTP: web UI + MCP on http://localhost:3000
|
|
8
|
+
uvx exactdocs serve --stdio # MCP over stdio
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
See the [project README](https://github.com/SirCypkowskyy/ExactDocs) for the full documentation.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Feature: Library catalog
|
|
2
|
+
As an AI coding agent
|
|
3
|
+
I want to know which libraries and versions ExactDocs has indexed
|
|
4
|
+
So that I only ask for documentation that actually exists
|
|
5
|
+
|
|
6
|
+
Background:
|
|
7
|
+
Given ExactDocs is running with the demo catalog
|
|
8
|
+
|
|
9
|
+
Scenario: Listing indexed libraries
|
|
10
|
+
When I list the libraries over the REST API
|
|
11
|
+
Then the response status is 200
|
|
12
|
+
And the libraries are:
|
|
13
|
+
| name | versions |
|
|
14
|
+
| fastapi | 0.115 |
|
|
15
|
+
| react | 19.1 |
|
|
16
|
+
|
|
17
|
+
Scenario: Asking for a library that is not indexed
|
|
18
|
+
When I request the library "vue"
|
|
19
|
+
Then the response status is 404
|
|
20
|
+
And the error code is "not_found"
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
Feature: Version-pinned documentation search
|
|
2
|
+
As an AI coding agent
|
|
3
|
+
I want search to be pinned to the exact library version I use
|
|
4
|
+
So that I never get a plausible answer for the wrong version
|
|
5
|
+
|
|
6
|
+
Background:
|
|
7
|
+
Given ExactDocs is running with the demo catalog
|
|
8
|
+
|
|
9
|
+
Scenario: The version is a hard filter, not a ranking hint
|
|
10
|
+
When I search "react" version "18.3" for "useFormState"
|
|
11
|
+
Then the response status is 404
|
|
12
|
+
And the error code is "not_found"
|
|
13
|
+
|
|
14
|
+
Scenario: An indexed version answers, even with no matching excerpt
|
|
15
|
+
When I search "react" version "19.1" for "useActionState"
|
|
16
|
+
Then the response status is 200
|
|
17
|
+
And I get 0 excerpts
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"""Steps that drive ExactDocs through its public HTTP API, like a real client would."""
|
|
2
|
+
|
|
3
|
+
from contextlib import ExitStack
|
|
4
|
+
|
|
5
|
+
from behave import given, then, when
|
|
6
|
+
from behave.runner import Context
|
|
7
|
+
from fastapi.testclient import TestClient
|
|
8
|
+
|
|
9
|
+
from exactdocs.bootstrap.container import Container
|
|
10
|
+
from exactdocs.bootstrap.http import create_app
|
|
11
|
+
from exactdocs.bootstrap.settings import Settings
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@given("ExactDocs is running with the demo catalog")
|
|
15
|
+
def step_running(context: Context) -> None:
|
|
16
|
+
stack = ExitStack()
|
|
17
|
+
context.add_cleanup(stack.close) # runs the app's shutdown after the scenario
|
|
18
|
+
context.client = stack.enter_context(TestClient(create_app(Container.build(Settings()))))
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@when("I list the libraries over the REST API")
|
|
22
|
+
def step_list(context: Context) -> None:
|
|
23
|
+
context.response = context.client.get("/api/v1/libraries")
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@when('I request the library "{name}"')
|
|
27
|
+
def step_get(context: Context, name: str) -> None:
|
|
28
|
+
context.response = context.client.get(f"/api/v1/libraries/{name}")
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@when('I search "{library}" version "{version}" for "{query}"')
|
|
32
|
+
def step_search(context: Context, library: str, version: str, query: str) -> None:
|
|
33
|
+
params = {"library": library, "version": version, "query": query}
|
|
34
|
+
context.response = context.client.get("/api/v1/search", params=params)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@then("the response status is {status:d}")
|
|
38
|
+
def step_status(context: Context, status: int) -> None:
|
|
39
|
+
assert context.response.status_code == status, context.response.text
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@then('the error code is "{code}"')
|
|
43
|
+
def step_error(context: Context, code: str) -> None:
|
|
44
|
+
assert context.response.json()["error"] == code
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@then("the libraries are:")
|
|
48
|
+
def step_libraries(context: Context) -> None:
|
|
49
|
+
expected = [(row["name"], row["versions"].split(", ")) for row in context.table or []]
|
|
50
|
+
actual = [(lib["name"], lib["versions"]) for lib in context.response.json()["libraries"]]
|
|
51
|
+
assert actual == expected, actual
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@then("I get {count:d} excerpts")
|
|
55
|
+
def step_excerpts(context: Context, count: int) -> None:
|
|
56
|
+
assert len(context.response.json()["excerpts"]) == count
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "exactdocs"
|
|
3
|
+
dynamic = ["version", "dependencies"]
|
|
4
|
+
description = "Self-hosted, version-accurate documentation for AI coding agents (MCP server)."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "Apache-2.0"
|
|
7
|
+
requires-python = ">=3.14"
|
|
8
|
+
authors = [{ name = "Cyprian Gburek" }]
|
|
9
|
+
keywords = ["mcp", "documentation", "rag", "ai-agents", "fastmcp"]
|
|
10
|
+
classifiers = [
|
|
11
|
+
"Development Status :: 2 - Pre-Alpha",
|
|
12
|
+
"Framework :: FastAPI",
|
|
13
|
+
"Programming Language :: Python :: 3.14",
|
|
14
|
+
"Typing :: Typed",
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
[project.scripts]
|
|
18
|
+
exactdocs = "exactdocs.bootstrap.cli:main"
|
|
19
|
+
|
|
20
|
+
[project.urls]
|
|
21
|
+
Repository = "https://github.com/SirCypkowskyy/ExactDocs"
|
|
22
|
+
Issues = "https://github.com/SirCypkowskyy/ExactDocs/issues"
|
|
23
|
+
|
|
24
|
+
[build-system]
|
|
25
|
+
requires = ["hatchling>=1.27", "uv-dynamic-versioning>=0.11"]
|
|
26
|
+
build-backend = "hatchling.build"
|
|
27
|
+
|
|
28
|
+
[tool.hatch.version]
|
|
29
|
+
source = "uv-dynamic-versioning"
|
|
30
|
+
|
|
31
|
+
[tool.hatch.metadata.hooks.uv-dynamic-versioning]
|
|
32
|
+
# The kernel is released in lockstep with the app.
|
|
33
|
+
dependencies = [
|
|
34
|
+
"exactdocs-kernel=={{ version }}",
|
|
35
|
+
"cyclopts>=4",
|
|
36
|
+
"fastapi>=0.120",
|
|
37
|
+
"fastmcp>=4",
|
|
38
|
+
"mcp>=2",
|
|
39
|
+
"pydantic>=2.12",
|
|
40
|
+
"pydantic-settings>=2.11",
|
|
41
|
+
"uvicorn[standard]>=0.38",
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
[tool.uv-dynamic-versioning]
|
|
45
|
+
vcs = "git"
|
|
46
|
+
style = "pep440"
|
|
47
|
+
fallback-version = "0.0.0"
|
|
48
|
+
|
|
49
|
+
[tool.hatch.build.targets.wheel]
|
|
50
|
+
packages = ["src/exactdocs"]
|
|
51
|
+
# The web UI is built by `pnpm build` and copied here in CI/Docker; it is gitignored.
|
|
52
|
+
artifacts = ["src/exactdocs/_web/**"]
|
|
53
|
+
|
|
54
|
+
[tool.hatch.build.targets.sdist]
|
|
55
|
+
artifacts = ["src/exactdocs/_web/**"]
|