docchat-server 0.0.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.
- docchat_server-0.0.1/.github/workflows/release.yml +50 -0
- docchat_server-0.0.1/.gitignore +32 -0
- docchat_server-0.0.1/.python-version +1 -0
- docchat_server-0.0.1/LICENSE +21 -0
- docchat_server-0.0.1/PKG-INFO +140 -0
- docchat_server-0.0.1/README.md +113 -0
- docchat_server-0.0.1/pyproject.toml +64 -0
- docchat_server-0.0.1/src/docchat_server/__init__.py +12 -0
- docchat_server-0.0.1/src/docchat_server/cli.py +111 -0
- docchat_server-0.0.1/src/docchat_server/indexer.py +261 -0
- docchat_server-0.0.1/src/docchat_server/library_config.py +124 -0
- docchat_server-0.0.1/src/docchat_server/py.typed +0 -0
- docchat_server-0.0.1/src/docchat_server/retrieval.py +171 -0
- docchat_server-0.0.1/src/docchat_server/server.py +149 -0
- docchat_server-0.0.1/tests/__init__.py +0 -0
- docchat_server-0.0.1/tests/test_smoke.py +123 -0
- docchat_server-0.0.1/uv.lock +2093 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
# Triggered by pushing a semver tag. Example:
|
|
4
|
+
# git tag v0.0.1
|
|
5
|
+
# git push --tags
|
|
6
|
+
#
|
|
7
|
+
# Pre-req: PyPI trusted publisher is registered for this repo
|
|
8
|
+
# (https://pypi.org/manage/account/publishing/). For the very first
|
|
9
|
+
# release, register a "pending publisher" before pushing the tag so
|
|
10
|
+
# PyPI knows to accept the OIDC token before the project exists.
|
|
11
|
+
|
|
12
|
+
on:
|
|
13
|
+
push:
|
|
14
|
+
tags:
|
|
15
|
+
- "v*.*.*"
|
|
16
|
+
|
|
17
|
+
permissions:
|
|
18
|
+
contents: read
|
|
19
|
+
id-token: write # required for PyPI trusted publishing (OIDC)
|
|
20
|
+
|
|
21
|
+
jobs:
|
|
22
|
+
release:
|
|
23
|
+
name: Build and publish to PyPI
|
|
24
|
+
runs-on: ubuntu-latest
|
|
25
|
+
environment:
|
|
26
|
+
name: pypi
|
|
27
|
+
url: https://pypi.org/project/docchat-server/
|
|
28
|
+
steps:
|
|
29
|
+
- name: Check out the repository
|
|
30
|
+
uses: actions/checkout@v4
|
|
31
|
+
|
|
32
|
+
- name: Install uv
|
|
33
|
+
uses: astral-sh/setup-uv@v3
|
|
34
|
+
with:
|
|
35
|
+
version: latest
|
|
36
|
+
|
|
37
|
+
- name: Set up Python
|
|
38
|
+
run: uv python install 3.11
|
|
39
|
+
|
|
40
|
+
- name: Sync project (so smoke tests can import the package)
|
|
41
|
+
run: uv sync --frozen --no-dev
|
|
42
|
+
|
|
43
|
+
- name: Build wheel + sdist
|
|
44
|
+
run: uv build
|
|
45
|
+
|
|
46
|
+
- name: Verify the build artifacts exist
|
|
47
|
+
run: ls -la dist/
|
|
48
|
+
|
|
49
|
+
- name: Publish to PyPI via trusted publishing
|
|
50
|
+
run: uv publish --trusted-publishing always
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.egg-info/
|
|
6
|
+
.pytest_cache/
|
|
7
|
+
.mypy_cache/
|
|
8
|
+
.ruff_cache/
|
|
9
|
+
.coverage
|
|
10
|
+
htmlcov/
|
|
11
|
+
dist/
|
|
12
|
+
build/
|
|
13
|
+
*.whl
|
|
14
|
+
*.tar.gz
|
|
15
|
+
.venv/
|
|
16
|
+
venv/
|
|
17
|
+
|
|
18
|
+
# Editor / OS
|
|
19
|
+
.vscode/settings.json
|
|
20
|
+
.idea/
|
|
21
|
+
*.swp
|
|
22
|
+
*.swo
|
|
23
|
+
.DS_Store
|
|
24
|
+
Thumbs.db
|
|
25
|
+
|
|
26
|
+
# Secrets
|
|
27
|
+
.env
|
|
28
|
+
.env.*
|
|
29
|
+
!.env.example
|
|
30
|
+
|
|
31
|
+
# Runtime data (per-user managed Qdrant + caches)
|
|
32
|
+
.docchat-mcp-cache/
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.11
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ashwin Ugale
|
|
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.
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: docchat-server
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Version-pinned documentation retrieval as a Model Context Protocol server. Gives Claude Code / Cursor / any MCP-aware AI grounded answers from the docs of the exact library version your lockfile pins.
|
|
5
|
+
Project-URL: Homepage, https://github.com/AshwinUgale/docchat-mcp
|
|
6
|
+
Project-URL: Repository, https://github.com/AshwinUgale/docchat-mcp
|
|
7
|
+
Project-URL: Issues, https://github.com/AshwinUgale/docchat-mcp/issues
|
|
8
|
+
Author-email: Ashwin Ugale <ugaleashwin@gmail.com>
|
|
9
|
+
License: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: claude,cursor,docs,llm,mcp,model-context-protocol,rag,version-pinned
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
19
|
+
Classifier: Topic :: Software Development :: Documentation
|
|
20
|
+
Requires-Python: >=3.11
|
|
21
|
+
Requires-Dist: fastmcp>=0.4
|
|
22
|
+
Requires-Dist: httpx>=0.27
|
|
23
|
+
Requires-Dist: openai>=1.40
|
|
24
|
+
Requires-Dist: python-dotenv>=1.0
|
|
25
|
+
Requires-Dist: qdrant-client>=1.12
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
|
|
28
|
+
# docchat-server
|
|
29
|
+
|
|
30
|
+
> Version-pinned documentation retrieval as a Model Context Protocol server. Gives Claude Code / Cursor / any MCP-aware AI grounded answers from the docs of the exact library version your lockfile pins.
|
|
31
|
+
|
|
32
|
+
[](#)
|
|
33
|
+
[](./LICENSE)
|
|
34
|
+
[](./pyproject.toml)
|
|
35
|
+
|
|
36
|
+
**Status:** v0.0 — initial scaffold. v0.1 ships PyPI + Smithery registration once the FastMCP server is locally verified.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## What it is
|
|
41
|
+
|
|
42
|
+
Claude Code, Cursor, and other AI coding assistants answer library questions from training data. If your project pins `react@18.2.0` and the latest is `19.1.0`, you get React 19 APIs in your React 18 file — the model has no way to know which version actually matters.
|
|
43
|
+
|
|
44
|
+
`docchat-server` is an MCP server that fixes that. Index a library at the version you pin once. Register the server with your MCP host. Now every query to your coding assistant can be grounded in the docs for the *exact pinned version*, with hard refusal when the docs don't cover the question.
|
|
45
|
+
|
|
46
|
+
It's the [DocChat VS Code extension](https://github.com/AshwinUgale/docchat) stripped of its agent + chat UI, exposed as an MCP tool surface instead. The retrieval logic, version-aware routing, and per-library cosine score floors are identical (and identically eval-tuned).
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Install
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
pip install docchat-server # or: uvx --from docchat-server docchat-server
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Requires Python 3.11+ and an `OPENAI_API_KEY` env var (used for query + index-time embeddings). The Qdrant vector store runs *embedded* — no Docker, no separate server.
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Use (3 steps)
|
|
61
|
+
|
|
62
|
+
### 1. Index the libraries you care about
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
export OPENAI_API_KEY=sk-...
|
|
66
|
+
|
|
67
|
+
docchat-server index react 18.2.0
|
|
68
|
+
docchat-server index fastapi 0.100.0
|
|
69
|
+
docchat-server index vue 3.4.0
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Each index takes ~30–60 seconds and a few cents of embedding cost. Stored at `~/.docchat-server/qdrant/`.
|
|
73
|
+
|
|
74
|
+
### 2. Verify
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
docchat-server list
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
Indexed collections:
|
|
82
|
+
- react_18_2_0 (47 chunks)
|
|
83
|
+
- fastapi_0_100_0 (38 chunks)
|
|
84
|
+
- vue_3_4_0 (62 chunks)
|
|
85
|
+
|
|
86
|
+
Supported libraries: fastapi, react, vue
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### 3. Register with your MCP host
|
|
90
|
+
|
|
91
|
+
Claude Desktop / Claude Code: add to your MCP config (`~/.config/claude/mcp-config.json` on Mac/Linux, `%APPDATA%\Claude\mcp-config.json` on Windows):
|
|
92
|
+
|
|
93
|
+
```json
|
|
94
|
+
{
|
|
95
|
+
"mcpServers": {
|
|
96
|
+
"docchat": {
|
|
97
|
+
"command": "docchat-server",
|
|
98
|
+
"args": ["serve"],
|
|
99
|
+
"env": {
|
|
100
|
+
"OPENAI_API_KEY": "sk-..."
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Restart your MCP host. The `docchat` server should appear with two tools: `search_docs` and `list_indexed`.
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## The tools
|
|
112
|
+
|
|
113
|
+
### `search_docs(library, version, query, api_name?, top_k?)`
|
|
114
|
+
|
|
115
|
+
Retrieves top-K chunks from the indexed docs of the exact pinned version. Returns the chunks with citations, or `"No relevant chunks found"` if nothing clears the per-library cosine floor (a hard signal to the model that it should refuse rather than guess).
|
|
116
|
+
|
|
117
|
+
### `list_indexed()`
|
|
118
|
+
|
|
119
|
+
Returns the collections currently populated locally. Useful as a session-start probe — your assistant can call this once to know what's available before answering anything.
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## Sibling project
|
|
124
|
+
|
|
125
|
+
The same retrieval engine ships as a [VS Code extension on the Marketplace](https://marketplace.visualstudio.com/items?itemName=AshwinUgale.docchat). Source: https://github.com/AshwinUgale/docchat. If you want a chat panel instead of MCP-tool integration, install that.
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## Roadmap
|
|
130
|
+
|
|
131
|
+
- **v0.1** — PyPI publish, Smithery listing, README screenshots from real Claude Code session
|
|
132
|
+
- **v0.2** — `detect_pinned_libraries(workspace_path)` tool (parse package.json / pyproject.toml / requirements.txt and report pinned versions to the assistant)
|
|
133
|
+
- **v0.3** — `--repo` / `--paths` flags for arbitrary library indexing (extend beyond the built-in react / fastapi / vue)
|
|
134
|
+
- **v0.4** — local embeddings via sentence-transformers (drop the OpenAI dependency for the embed step)
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## License
|
|
139
|
+
|
|
140
|
+
MIT. See [LICENSE](./LICENSE).
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# docchat-server
|
|
2
|
+
|
|
3
|
+
> Version-pinned documentation retrieval as a Model Context Protocol server. Gives Claude Code / Cursor / any MCP-aware AI grounded answers from the docs of the exact library version your lockfile pins.
|
|
4
|
+
|
|
5
|
+
[](#)
|
|
6
|
+
[](./LICENSE)
|
|
7
|
+
[](./pyproject.toml)
|
|
8
|
+
|
|
9
|
+
**Status:** v0.0 — initial scaffold. v0.1 ships PyPI + Smithery registration once the FastMCP server is locally verified.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## What it is
|
|
14
|
+
|
|
15
|
+
Claude Code, Cursor, and other AI coding assistants answer library questions from training data. If your project pins `react@18.2.0` and the latest is `19.1.0`, you get React 19 APIs in your React 18 file — the model has no way to know which version actually matters.
|
|
16
|
+
|
|
17
|
+
`docchat-server` is an MCP server that fixes that. Index a library at the version you pin once. Register the server with your MCP host. Now every query to your coding assistant can be grounded in the docs for the *exact pinned version*, with hard refusal when the docs don't cover the question.
|
|
18
|
+
|
|
19
|
+
It's the [DocChat VS Code extension](https://github.com/AshwinUgale/docchat) stripped of its agent + chat UI, exposed as an MCP tool surface instead. The retrieval logic, version-aware routing, and per-library cosine score floors are identical (and identically eval-tuned).
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Install
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
pip install docchat-server # or: uvx --from docchat-server docchat-server
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Requires Python 3.11+ and an `OPENAI_API_KEY` env var (used for query + index-time embeddings). The Qdrant vector store runs *embedded* — no Docker, no separate server.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Use (3 steps)
|
|
34
|
+
|
|
35
|
+
### 1. Index the libraries you care about
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
export OPENAI_API_KEY=sk-...
|
|
39
|
+
|
|
40
|
+
docchat-server index react 18.2.0
|
|
41
|
+
docchat-server index fastapi 0.100.0
|
|
42
|
+
docchat-server index vue 3.4.0
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Each index takes ~30–60 seconds and a few cents of embedding cost. Stored at `~/.docchat-server/qdrant/`.
|
|
46
|
+
|
|
47
|
+
### 2. Verify
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
docchat-server list
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
Indexed collections:
|
|
55
|
+
- react_18_2_0 (47 chunks)
|
|
56
|
+
- fastapi_0_100_0 (38 chunks)
|
|
57
|
+
- vue_3_4_0 (62 chunks)
|
|
58
|
+
|
|
59
|
+
Supported libraries: fastapi, react, vue
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### 3. Register with your MCP host
|
|
63
|
+
|
|
64
|
+
Claude Desktop / Claude Code: add to your MCP config (`~/.config/claude/mcp-config.json` on Mac/Linux, `%APPDATA%\Claude\mcp-config.json` on Windows):
|
|
65
|
+
|
|
66
|
+
```json
|
|
67
|
+
{
|
|
68
|
+
"mcpServers": {
|
|
69
|
+
"docchat": {
|
|
70
|
+
"command": "docchat-server",
|
|
71
|
+
"args": ["serve"],
|
|
72
|
+
"env": {
|
|
73
|
+
"OPENAI_API_KEY": "sk-..."
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Restart your MCP host. The `docchat` server should appear with two tools: `search_docs` and `list_indexed`.
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## The tools
|
|
85
|
+
|
|
86
|
+
### `search_docs(library, version, query, api_name?, top_k?)`
|
|
87
|
+
|
|
88
|
+
Retrieves top-K chunks from the indexed docs of the exact pinned version. Returns the chunks with citations, or `"No relevant chunks found"` if nothing clears the per-library cosine floor (a hard signal to the model that it should refuse rather than guess).
|
|
89
|
+
|
|
90
|
+
### `list_indexed()`
|
|
91
|
+
|
|
92
|
+
Returns the collections currently populated locally. Useful as a session-start probe — your assistant can call this once to know what's available before answering anything.
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## Sibling project
|
|
97
|
+
|
|
98
|
+
The same retrieval engine ships as a [VS Code extension on the Marketplace](https://marketplace.visualstudio.com/items?itemName=AshwinUgale.docchat). Source: https://github.com/AshwinUgale/docchat. If you want a chat panel instead of MCP-tool integration, install that.
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Roadmap
|
|
103
|
+
|
|
104
|
+
- **v0.1** — PyPI publish, Smithery listing, README screenshots from real Claude Code session
|
|
105
|
+
- **v0.2** — `detect_pinned_libraries(workspace_path)` tool (parse package.json / pyproject.toml / requirements.txt and report pinned versions to the assistant)
|
|
106
|
+
- **v0.3** — `--repo` / `--paths` flags for arbitrary library indexing (extend beyond the built-in react / fastapi / vue)
|
|
107
|
+
- **v0.4** — local embeddings via sentence-transformers (drop the OpenAI dependency for the embed step)
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## License
|
|
112
|
+
|
|
113
|
+
MIT. See [LICENSE](./LICENSE).
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "docchat-server"
|
|
3
|
+
version = "0.0.1"
|
|
4
|
+
description = "Version-pinned documentation retrieval as a Model Context Protocol server. Gives Claude Code / Cursor / any MCP-aware AI grounded answers from the docs of the exact library version your lockfile pins."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.11"
|
|
7
|
+
license = { text = "MIT" }
|
|
8
|
+
authors = [{ name = "Ashwin Ugale", email = "ugaleashwin@gmail.com" }]
|
|
9
|
+
keywords = ["mcp", "model-context-protocol", "llm", "rag", "docs", "version-pinned", "claude", "cursor"]
|
|
10
|
+
classifiers = [
|
|
11
|
+
"Development Status :: 3 - Alpha",
|
|
12
|
+
"Intended Audience :: Developers",
|
|
13
|
+
"License :: OSI Approved :: MIT License",
|
|
14
|
+
"Programming Language :: Python :: 3",
|
|
15
|
+
"Programming Language :: Python :: 3.11",
|
|
16
|
+
"Programming Language :: Python :: 3.12",
|
|
17
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
18
|
+
"Topic :: Software Development :: Documentation",
|
|
19
|
+
]
|
|
20
|
+
dependencies = [
|
|
21
|
+
"fastmcp>=0.4",
|
|
22
|
+
"qdrant-client>=1.12",
|
|
23
|
+
"openai>=1.40",
|
|
24
|
+
"httpx>=0.27",
|
|
25
|
+
"python-dotenv>=1.0",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
[project.urls]
|
|
29
|
+
Homepage = "https://github.com/AshwinUgale/docchat-mcp"
|
|
30
|
+
Repository = "https://github.com/AshwinUgale/docchat-mcp"
|
|
31
|
+
Issues = "https://github.com/AshwinUgale/docchat-mcp/issues"
|
|
32
|
+
|
|
33
|
+
[project.scripts]
|
|
34
|
+
docchat-server = "docchat_server.cli:main"
|
|
35
|
+
|
|
36
|
+
[build-system]
|
|
37
|
+
requires = ["hatchling"]
|
|
38
|
+
build-backend = "hatchling.build"
|
|
39
|
+
|
|
40
|
+
[tool.hatch.build.targets.wheel]
|
|
41
|
+
packages = ["src/docchat_server"]
|
|
42
|
+
|
|
43
|
+
[dependency-groups]
|
|
44
|
+
dev = [
|
|
45
|
+
"pytest>=8.0",
|
|
46
|
+
"pytest-asyncio>=0.23",
|
|
47
|
+
"ruff>=0.6",
|
|
48
|
+
"mypy>=1.10",
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
[tool.ruff]
|
|
52
|
+
target-version = "py311"
|
|
53
|
+
line-length = 100
|
|
54
|
+
|
|
55
|
+
[tool.ruff.lint]
|
|
56
|
+
select = ["E", "F", "I", "B", "UP", "SIM", "RUF"]
|
|
57
|
+
|
|
58
|
+
[tool.mypy]
|
|
59
|
+
python_version = "3.11"
|
|
60
|
+
strict = true
|
|
61
|
+
|
|
62
|
+
[tool.pytest.ini_options]
|
|
63
|
+
asyncio_mode = "auto"
|
|
64
|
+
testpaths = ["tests"]
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""docchat-server - version-pinned documentation retrieval as an MCP server.
|
|
2
|
+
|
|
3
|
+
Stripped-down sibling of docchat (https://github.com/AshwinUgale/docchat).
|
|
4
|
+
Exposes ``search_docs`` and ``list_indexed`` MCP tools that Claude Code,
|
|
5
|
+
Cursor, Cline, or any other MCP-aware client can call to ground library
|
|
6
|
+
questions in the exact pinned-version docs instead of training data.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
__version__ = "0.0.1"
|
|
12
|
+
__all__ = ["__version__"]
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"""docchat-server CLI.
|
|
2
|
+
|
|
3
|
+
Subcommands:
|
|
4
|
+
- ``docchat-server serve`` - run the MCP server on stdio.
|
|
5
|
+
- ``docchat-server index <library> <ver>`` - populate the local Qdrant.
|
|
6
|
+
- ``docchat-server list`` - show indexed collections.
|
|
7
|
+
|
|
8
|
+
The ``serve`` subcommand is what an MCP host (Claude Code, Cursor, Cline)
|
|
9
|
+
spawns. The ``index`` and ``list`` subcommands are for the user, run
|
|
10
|
+
manually to set up before pointing an MCP host at the server.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import argparse
|
|
16
|
+
import os
|
|
17
|
+
import sys
|
|
18
|
+
|
|
19
|
+
from dotenv import load_dotenv
|
|
20
|
+
|
|
21
|
+
from docchat_server import __version__
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _cmd_serve(_args: argparse.Namespace) -> int:
|
|
25
|
+
# Import inside the handler so `docchat-server index` doesn't pull in
|
|
26
|
+
# FastMCP (which checks OPENAI_API_KEY at import time in server.py).
|
|
27
|
+
from docchat_server.server import main as serve_main
|
|
28
|
+
|
|
29
|
+
serve_main()
|
|
30
|
+
return 0
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _cmd_index(args: argparse.Namespace) -> int:
|
|
34
|
+
load_dotenv()
|
|
35
|
+
if not os.environ.get("OPENAI_API_KEY"):
|
|
36
|
+
print(
|
|
37
|
+
"ERROR: OPENAI_API_KEY is not set. docchat-server uses OpenAI's "
|
|
38
|
+
"embeddings API. Set it in your shell or a .env file.",
|
|
39
|
+
file=sys.stderr,
|
|
40
|
+
)
|
|
41
|
+
return 2
|
|
42
|
+
|
|
43
|
+
from openai import OpenAI
|
|
44
|
+
|
|
45
|
+
from docchat_server.indexer import DocIndexer, open_qdrant
|
|
46
|
+
|
|
47
|
+
qdrant = open_qdrant()
|
|
48
|
+
indexer = DocIndexer(qdrant=qdrant, openai=OpenAI())
|
|
49
|
+
|
|
50
|
+
def _progress(msg: str) -> None:
|
|
51
|
+
print(f"[indexer] {msg}", file=sys.stderr, flush=True)
|
|
52
|
+
|
|
53
|
+
try:
|
|
54
|
+
total = indexer.index(args.library, args.version, progress=_progress)
|
|
55
|
+
except ValueError as exc:
|
|
56
|
+
print(f"ERROR: {exc}", file=sys.stderr)
|
|
57
|
+
return 2
|
|
58
|
+
except RuntimeError as exc:
|
|
59
|
+
print(f"ERROR: {exc}", file=sys.stderr)
|
|
60
|
+
return 1
|
|
61
|
+
print(f"indexed {total} chunks into {args.library}@{args.version}")
|
|
62
|
+
return 0
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _cmd_list(_args: argparse.Namespace) -> int:
|
|
66
|
+
from docchat_server.indexer import open_qdrant
|
|
67
|
+
from docchat_server.library_config import LIBRARY_CONFIG
|
|
68
|
+
|
|
69
|
+
qdrant = open_qdrant()
|
|
70
|
+
collections = qdrant.get_collections().collections
|
|
71
|
+
print("Indexed collections:")
|
|
72
|
+
if not collections:
|
|
73
|
+
print(" (none yet - run `docchat-server index <library> <version>`)")
|
|
74
|
+
for c in collections:
|
|
75
|
+
try:
|
|
76
|
+
count = qdrant.count(collection_name=c.name).count
|
|
77
|
+
except Exception:
|
|
78
|
+
count = "?"
|
|
79
|
+
print(f" - {c.name} ({count} chunks)")
|
|
80
|
+
print()
|
|
81
|
+
print(f"Supported libraries: {', '.join(sorted(LIBRARY_CONFIG.keys()))}")
|
|
82
|
+
return 0
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def main(argv: list[str] | None = None) -> int:
|
|
86
|
+
parser = argparse.ArgumentParser(
|
|
87
|
+
prog="docchat-server",
|
|
88
|
+
description="Version-pinned doc retrieval as an MCP server.",
|
|
89
|
+
)
|
|
90
|
+
parser.add_argument("--version", action="version", version=f"docchat-server {__version__}")
|
|
91
|
+
sub = parser.add_subparsers(dest="cmd", required=True)
|
|
92
|
+
|
|
93
|
+
p_serve = sub.add_parser("serve", help="run the MCP server on stdio")
|
|
94
|
+
p_serve.set_defaults(func=_cmd_serve)
|
|
95
|
+
|
|
96
|
+
p_index = sub.add_parser(
|
|
97
|
+
"index", help="fetch + embed + upsert docs for one (library, version)"
|
|
98
|
+
)
|
|
99
|
+
p_index.add_argument("library", help="e.g. react, fastapi, vue")
|
|
100
|
+
p_index.add_argument("version", help="e.g. 18.2.0, 0.100.0, 3.4.0")
|
|
101
|
+
p_index.set_defaults(func=_cmd_index)
|
|
102
|
+
|
|
103
|
+
p_list = sub.add_parser("list", help="show indexed collections")
|
|
104
|
+
p_list.set_defaults(func=_cmd_list)
|
|
105
|
+
|
|
106
|
+
args = parser.parse_args(argv)
|
|
107
|
+
return int(args.func(args))
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
if __name__ == "__main__":
|
|
111
|
+
sys.exit(main())
|