Production handover
Version 2 · Publish the reviewed production handover and verify the versioned update path.
Historical versionQDG Knowledge Base MCP production handover
Date: 4 September 2026
Outcome
The QDG Knowledge Base MCP is a central team service on Odin. Codex and Claude clients
connect to https://qdb.qdatasite.com/mcp/qdg-kb with an individual bearer token.
QWebHub terminates public HTTPS and proxies only that exact path to the service on
127.0.0.1:8972. Only the service has the MySQL writer password.
“QDG Knowledge Base” is the canonical product/data name. “KB Wiki” and “QDG Wiki”
are legacy or informal names; the backing MySQL schema remains qdgwiki.
Fixes and safeguards applied
- Confirmed the real Odin/IIS/MySQL topology with read-only inventory instead of assuming that the repository matched production.
- Corrected the unrelated
\QWebHub\Restartscheduled task so it restarts theQWebHubapplication pool rather thanAdminManagement; all reviewed websites returned HTTP 200 after the change. - Created the loopback-only
qdgkb_writer@localhostaccount with table-specific read/write permissions and no administrative/database-wide privileges. - Stored the database password and token hashes under protected ProgramData ACLs; raw bearer tokens remain only in the private inventory.
- Installed a dedicated, pinned Python 3.13.15 runtime and isolated application venv instead of trusting the shared, user-writable Python tree.
- Installed the service as the virtual account
NT SERVICE\QDG-KB-MCP; code/runtime are read/execute, database/token config is read-only, and only its own log/runtime folders are writable. - Corrected 187 Python cache ACLs that inherited rather than explicitly protected the intended Administrator/SYSTEM-only rules.
- Verified the writer password, exact MySQL grants, allowed table reads and denial of migration/system-table reads.
- Imported the existing 30-token inventory without changing token values; Odin stores hashes only.
- Verified local startup, authentication, MCP tool discovery and database access.
- Added the exact route to the overarching QWebHub site after confirming that the
internal
qdb-backendsite was not the public entry point. - Enabled Automatic (Delayed Start), restarted the service and repeated both the QWebHub and independent public HTTPS tests successfully.
Decisions not to repeat
- Do not deploy an ignored working copy for the long term. Build releases from a reviewed commit with pinned artifacts and a recorded version.
- Do not assume a working website proves the MCP route works; test missing-token, invalid-token and valid-token requests through the public hostname.
- Do not place a public route on a plausible backend site before proving the actual ingress chain. QWebHub is the public route owner in this deployment.
- Do not give the MCP shared
web_admin, root, DDL, DELETE orGRANT OPTIONaccess. - Do not put raw tokens, MySQL passwords or protected Odin inventories in source, command lines, screenshots, chat or shared documents.
- Do not use a single generic team token when per-person history and independent revocation matter. Generic enabled slots must be relabelled before issue.
- Do not make ad-hoc edits without a byte-for-byte backup, exact target checks and post-change verification. The successful scripts deliberately failed closed and restored state when their assumptions were wrong.
- Do not combine unrelated QWebHub application changes with an MCP release. The MCP route is a narrow infrastructure rule; QWebHub source remains a separate concern.
Client setup
Codex:
[mcp_servers.qdg_kb]
url = "https://qdb.qdatasite.com/mcp/qdg-kb"
bearer_token_env_var = "QDG_KB_TOKEN"
default_tools_approval_mode = "writes"
Claude project .mcp.json:
{
"mcpServers": {
"qdg_kb": {
"type": "http",
"url": "https://qdb.qdatasite.com/mcp/qdg-kb",
"headers": {
"Authorization": "Bearer ${QDG_KB_TOKEN}"
}
}
}
}
Each teammate sets their own token locally as QDG_KB_TOKEN, restarts the client,
and runs qdg_kb_status. A successful connection makes the shared documentation
available; project rules/workflows must still tell assistants when to publish or
update documentation during commits and handovers.
Operations
- Service:
Get-Service QDG-KB-MCP - Private config:
C:\ProgramData\QDG\Config\QDG-KB-MCP - Logs:
C:\ProgramData\QDG\Logs\QDG-KB-MCP - Audit evidence:
C:\ProgramData\QDG\DeploymentAudit\QDG-KB-MCP - Public check:
deployment\Test-PublicMcp.ps1 -InventoryPath <private inventory> - Token procedure: FIRST_TOKEN.md
- Current evidence and known cleanup: ROLLOUT_STATUS.md
The next release should use a versioned updater that stages a new venv, stops the service, swaps application versions, preserves ProgramData secrets, starts and runs health/auth/database checks, then automatically rolls back on failure.