Search and Q&A over Aalto scicomp-docs (Triton HPC and related guides).
Two ways to use this project:
| Use case | What you get | Needs LLM API key? |
|---|---|---|
| Web chat UI | Browser chat UI with tool-calling loop | Yes (Aalto gateway + VPN) |
| MCP server | Doc search tools for your own agent (Cursor, Claude, custom code) | No |
Both paths share the same Python tools in app/doc_tools.py.
- Python 3.12+ or Docker
- Docs snapshot in
docs-source/(git submodule — required for both paths) - ripgrep optional for local dev (
brew install ripgrep); included in the Docker image - LLM API key only for the web chat UI
git clone --recurse-submodules https://github.com/AaltoSciComp/scicomp-docs-assistant.git
cd scicomp-docs-assistantIf you already cloned without submodules:
git submodule update --init --recursiveAfter a healthy clone, /api/health should report docs_present: true and index_pages in the hundreds (typically 300+). If index_pages is 0, the docs submodule is missing — see Troubleshooting.
Browser-based agent that calls the same tools and cites https://scicomp.aalto.fi/.
Requires: Aalto VPN + API key from llm-gateway.k8s.aalto.fi.
cp .env.example .env
# Edit .env and set LLM_API_KEY=your-key-here
docker compose up --buildOpen http://localhost:8081 (host port 8081; container listens on 8080).
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env # set LLM_API_KEY
uvicorn app.main:app --reload --port 8080Open http://localhost:8080.
The gateway client is OpenAI-compatible. Set in .env:
LLM_API_KEY=your-provider-key
LLM_BASE_URL=https://your-provider.example.com/v1
LLM_MODEL=your-model-idThe web UI and MCP can run together on the same server — MCP does not use the LLM.
Expose doc search to any MCP client. No LLM key, no VPN.
cp .env.mcp.example .env # optional; compose works without .env for MCP-only
docker compose up --buildMCP endpoint: http://localhost:8081/mcp/ (trailing slash required)
Verify:
curl -s http://localhost:8081/api/health | python3 -m json.tool
# expect: "docs_present": true, "index_pages": 300+ (approx), "llm_configured": falsepython3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
uvicorn app.main:app --port 8080MCP endpoint: http://localhost:8080/mcp/
From the repo root, with dependencies installed:
source .venv/bin/activate # after pip install -r requirements.txt
python -m app.mcp_stdioCursor / VS Code client config (use your venv Python path):
{
"mcpServers": {
"scicomp-docs": {
"command": "/path/to/scicomp-docs-assistant/.venv/bin/python",
"args": ["-m", "app.mcp_stdio"],
"cwd": "/path/to/scicomp-docs-assistant",
"env": {
"DOCS_ROOT": "/path/to/scicomp-docs-assistant/docs-source",
"SKILLS_DIR": "/path/to/scicomp-docs-assistant/skills"
}
}
}
}| Tool | Description |
|---|---|
find_pages |
Rank pages by title, headings, and path |
get_doc_outline |
Table of contents with line numbers |
search_docs |
Ripgrep over .rst / .md sources |
list_doc_tree |
Browse the docs folder tree |
read_doc |
Read a file with optional line range |
Prompt scicomp-docs-search — recommended search workflow (same as the web agent skill).
Resource scicomp-docs://skill/search — raw skill markdown.
{
"mcpServers": {
"scicomp-docs": {
"url": "http://localhost:8081/mcp/"
}
}
}Clients that only support stdio (e.g. Claude Desktop) can proxy via mcp-remote:
{
"mcpServers": {
"scicomp-docs": {
"command": "npx",
"args": ["-y", "mcp-remote", "http://localhost:8081/mcp/"]
}
}
}Install the MCP client SDK on the machine running your script (pip install "mcp>=1.19,<2"):
import asyncio
from mcp.client.session import ClientSession
from mcp.client.streamable_http import streamablehttp_client
async def main():
async with streamablehttp_client("http://localhost:8081/mcp/") as (read, write, _):
async with ClientSession(read, write) as session:
await session.initialize()
result = await session.call_tool("find_pages", {"query": "GPU sbatch"})
print(result.content[0].text)
asyncio.run(main())Security:
/mcp/has no authentication. Bind to localhost or put a reverse proxy in front if exposing beyond your machine.
- You ask a question in the browser UI.
- The LLM receives a search skill (
skills/scicomp-docs-search.md). - The model calls tools:
find_pages→get_doc_outline/search_docs→read_doc. - It answers with citations as published URLs on https://scicomp.aalto.fi/.
git submodule update --remote docs-source
docker compose up --build # rebuild image so docs-source is refreshed| Variable | Default | Description |
|---|---|---|
LLM_API_KEY |
(empty) | Required for web chat only |
LLM_BASE_URL |
https://llm-gateway.k8s.aalto.fi/api/v1 |
OpenAI-compatible base URL |
LLM_MODEL |
RedHatAI/gemma-4-31B-it-FP8-Dynamic |
Model id |
LLM_TEMPERATURE |
0.15 |
Sampling temperature |
LLM_MAX_TOKENS |
4096 |
Max completion tokens |
AGENT_MAX_TOOL_ROUNDS |
18 |
Max tool-calling rounds per chat turn |
DOCS_ROOT |
./docs-source |
Path to scicomp-docs tree |
DOCS_SITE_BASE_URL |
https://scicomp.aalto.fi |
Published site for citations |
SKILLS_DIR |
./skills |
Agent skill markdown files |
HOST |
0.0.0.0 |
Bind address (local uvicorn) |
PORT |
8080 |
Listen port (local uvicorn) |
Env templates:
.env.example— full template (web agent + MCP).env.mcp.example— minimal MCP-only (LLM_API_KEYempty)
| Symptom | Likely cause | Fix |
|---|---|---|
index_pages: 0 or docs_present: false |
Submodule not initialized | git submodule update --init --recursive, then rebuild/restart |
| MCP client can't connect | Wrong port or missing trailing slash | Docker: http://localhost:8081/mcp/ — local: http://localhost:8080/mcp/ |
| MCP works but tools return nothing | Empty docs-source/ |
Same as above; check health endpoint |
| Chat returns 503 “LLM_API_KEY is not configured” | Key not set | Add LLM_API_KEY to .env (not needed for MCP) |
| Chat errors / timeouts from LLM | VPN off or wrong gateway | Connect to Aalto VPN; verify key at llm-gateway.k8s.aalto.fi |
docker compose fails on .env |
Old Compose version | Upgrade Docker Desktop, or cp .env.mcp.example .env |
| Slow local search | ripgrep not installed | brew install ripgrep or use Docker |
| stdio MCP: “docs not found” warning | Wrong cwd or DOCS_ROOT |
Run from repo root; set DOCS_ROOT in client config |
Docker build: can't pull python image |
Docker Hub unreachable or rate-limited | Use a mirror, e.g. public.ecr.aws/docker/library/python:3.12-slim-bookworm |
Health check:
curl -s http://localhost:8081/api/health | python3 -m json.toolHealthy MCP + docs: docs_present: true, index_pages > 0. Web chat additionally needs llm_configured: true.
app/
main.py # FastAPI + SSE chat + MCP mount
mcp_server.py # MCP tools, prompt, resource
mcp_stdio.py # stdio entry point (`python -m app.mcp_stdio`)
agent.py # Tool-calling loop
doc_tools.py # search / list / read (shared by agent + MCP)
doc_index.py # Page/heading index for find_pages
config.py # Settings from .env
llm_client.py # Gateway HTTP client
static/ # Chat UI
skills/
scicomp-docs-search.md
docs-source/ # scicomp-docs git submodule
Documentation content belongs to AaltoSciComp/scicomp-docs. This agent wrapper is provided as-is for local use.