Local-first MCP-native Markdown wiki for AI tools.
Project description
dtxWiki
dtxWiki는 로컬 우선 MCP-native Markdown wiki 구현체입니다. 웹 UI는 Ask, Library, Context, Agent, Activity 5개 primary surface를 제공하고, REST, MCP stdio server, HTTP MCP endpoint는 Markdown page, ContextPage, AgentPage, source, search, ChangeSet, Review, Audit 흐름을 같은 backend contract 위에서 다룹니다.
현재 범위는 SQLite 저장소, bundled React UI, CodeMirror Markdown editor, deterministic context-first Ask surface, default-off LLM provider 추상화, session/PAT 기반 인증, workspace membership RBAC, 12개 P0 MCP tool, Sprint_0/Sprint_1 legacy Pages 호환 tool, MCP stdio/HTTP onboarding, OAuth 2.1-style DCR/PKCE/JWT flow, MCP client 등록 CLI, background worker CLI까지입니다.
주요 기능
- Primary surface: Ask / Library / Context / Agent / Activity 5개 sidebar surface와 TreeRail, Breadcrumbs, StatusPill 기반 공통 navigation
- Markdown page 호환: Sprint_0/Sprint_1 Pages CRUD route와
list_pages,read_page,write_pageMCP tool을 legacy 호환 surface로 유지 - Markdown editor와 preview: CodeMirror 6 editor,
react-markdown,remark-gfm,rehype-sanitize기반 preview, canonicalcontent_hashstale conflict 감지 - Context workflow: ContextPage draft, update, publish, citation, feedback, review decision, Ask turn에서 ContextIngressProposal 생성과 accept/reject
- Agent workflow: AgentPage draft와 activation, owner/reviewer role guard, rule-based AgentInputBundle 생성, TTL/version pinning, omission reason 기록
- Tree placement: workspace tree, primary placement uniqueness, move/rename, cycle prevention,
target/expandedURL state - Source pipeline: source discovery, extraction job, inline/file storage ref,
DTXWIKI_LIBRARY_FILE_ROOTS기반 root-restrictedfile://read - Search와 Ask: Context, source, artifact, feedback, change, AgentPage 대상 keyword search와 deterministic context-first Ask. Anthropic/OpenAI LLM provider 추상화는 default off로 제공되며, LLM 기반 Ask answer 생성과 semantic/hybrid retrieval은 Epic_1 이후 범위입니다.
- Change, Review, Audit: ChangeSet, ChangeOperation, ReviewItem, FeedbackItem, MCPToolCall, AuditEvent를 write workflow에서 atomic하게 기록
- 인증과 RBAC: browser session, personal API token, workspace membership role(owner/editor/viewer), REST/MCP access gate
- MCP stdio/HTTP: P0 spec tool 12개,
list_my_workspaces, legacy Pages tool 3개를 stdio와 HTTP endpoint로 제공 - OAuth MCP onboarding: OAuth protected resource metadata, authorization server metadata, dynamic client registration, browser consent, S256 PKCE, RS256 JWT access token, rotating refresh token
- REST API:
/api/v1아래 OpenAPI artifact 기준 65개 operation, 공통 error envelope, cursor pagination, validation envelope - Worker runtime: source discovery, extraction, feedback resolution, bundle expiration job을 별도 worker CLI로 처리
- 단일 사용자 패키징: local wheel build/install,
dtxwiki bootstrap, bundled frontend serving, Claude/Cursor/Codex MCP client 등록
요구 사항
dtxWiki 는 SQLite 전용으로 동작합니다 — 별도 DB 서버가 필요 없습니다.
- solo / 평가 (단일 사용자, 로컬): Python 3.12+
- production self-host — systemd: Ubuntu 22.04+ (root), 공개 도메인 1개, 80/443 개방
- production self-host — Docker: Docker Engine + Docker Compose v2, 공개 도메인 1개, 80/443 개방
소스를 직접 빌드/수정하려는 개발자(Node.js 20+, npm, 로컬 인프라 compose 등)는 DEVELOPMENT.md를 참고하세요.
설치
설치 경로는 용도에 따라 셋입니다. 모두 SQLite를 사용합니다.
PyPI 첫 릴리스 전에는 소스 체크아웃에서
make build-wheel로 wheel(dist/dtxwiki-<version>-py3-none-any.whl)을 만들어 아래pip install dtxwiki/--wheel자리에 그 wheel 경로를 사용하세요. PyPI 게시 후에는 같은 명령에서 패키지명dtxwiki를 그대로 사용할 수 있습니다. (Docker 경로는 소스에서 빌드하므로 PyPI 게시 여부와 무관합니다.)
1) solo / 개인·평가 (단일 사용자, 인터넷 노출 없음)
SQLite DB 가 ~/.dtxwiki/data/dtxwiki.sqlite 에 자동 생성됩니다.
# PyPI 게시 후:
pipx install dtxwiki
dtxwiki
# 첫 릴리스 전(소스에서):
make build-wheel
pipx install dist/dtxwiki-*.whl
dtxwiki
dtxwiki 는 migration/seed 후 backend 를 띄우고 브라우저(http://127.0.0.1:21080/)를
엽니다. dtxWiki 는 LLM 없이도 완전히 동작하므로(LLM provider 기본 off, Ask 는
deterministic) 아래 MCP 등록은 선택사항입니다.
아래 명령은 dtxWiki 와 같은 머신에 설치된 AI 클라이언트(Claude Desktop/Claude Code/
Cursor/Codex)에 로컬 stdio MCP 서버(dtxwiki-mcp)를 등록합니다. 설치된 클라이언트가
없으면 mcp register 는 No MCP clients detected. 로 그냥 넘어갑니다.
dtxwiki claude install
dtxwiki cursor install
dtxwiki codex install
dtxwiki mcp register --all --yes
AI 클라이언트가 dtxWiki 와 다른 머신에 있다면 (예: 원격 서버의 dtxWiki + 내 노트북의 Claude Code) 위 stdio 등록은 쓰지 마세요. 대신 서버의
/mcp엔드포인트를 PAT/OAuth 로 등록합니다 — 원격 서버 배포와 팀 MCP 연결 참고:claude mcp add --transport http dtxwiki https://wiki.example.com/mcp \ --header "Authorization: Bearer dtxw_..."
2) production self-host — systemd (한 명령)
맨 Ubuntu 서버에 도메인 + 이메일 2개만으로 설치합니다. SSL 은 Caddy 가 Let's Encrypt 에서 자동 발급합니다(전제: 도메인 DNS A 레코드 → 서버 공인 IP, 80/443 개방).
curl -fsSL https://<host>/install.sh | sudo bash -s -- \
--domain wiki.example.com --email admin@example.com
# 첫 PyPI 릴리스 전에는 빌드한 wheel 을 함께 전달:
# sudo bash install.sh --domain ... --email ... --wheel /path/dtxwiki-<version>.whl
상세 절차와 Day-2 재설정(dtxwiki config set)은 아래
원격 서버 배포와 팀 MCP 연결 및
DEPLOYMENT.md 를 참고하세요.
3) production self-host — Docker Compose
레포를 clone 한 뒤 도메인 + 이메일 2개만 정하면 됩니다. init(keygen + secret +
bootstrap) → app + worker → caddy(80/443, auto-TLS) 스택이 뜨고, SQLite 는 named
volume 에 영속됩니다(JWT 키·session secret 포함, 재시작해도 토큰·세션 유지).
cd infra/prod
cp .env.docker.example .env # DTXWIKI_DOMAIN + DTXWIKI_ADMIN_EMAIL
docker compose up -d --build
이미지는 멀티스테이지 Dockerfile(프론트 빌드 → SPA 를 backend/static 에
번들 → pip install)에서 소스로 빌드됩니다. 자세한 구성은
DEPLOYMENT.md 를 참고하세요.
개발 checkout 셋업·테스트·로컬 인프라 compose 는 DEVELOPMENT.md 를 보세요.
웹 UI 사용법
http://127.0.0.1:21173/또는 packaged server의http://127.0.0.1:21080/에 접속합니다./는 Sprint_0/Sprint_1 legacy Pages landing입니다. 페이지가 있으면 첫 page reader로 이동하고, 없으면New pageaction이 표시됩니다.- Sidebar의 primary surface는 Ask, Library, Context, Agent, Activity입니다.
- Library(
/library)는 source 목록, artifact/version detail, tree selection을 보여줍니다. legacy Pages CRUD는/pages/*route에서 계속 동작합니다. - Context(
/context)는 ContextPage tree, version/change history, draft/update/publish 상태를 보여줍니다. 기존 북마크 호환을 위해 legacy alias/context-map은/context로 redirect됩니다. - Agent(
/agent)는 AgentPage category, draft, activation, AgentInputBundle preview를 다룹니다. - Ask(
/ask)는 session/turn 기반 deterministic answer를 만들고, assistant turn을 ContextIngressProposal로 저장할 수 있습니다. - Activity(
/activity)는 ChangeSet, ReviewItem, AuditEvent, MCPToolCall, job 상태를 기간 filter와 lane으로 보여줍니다. - Search, Review, Lint, Setup, Settings는 topbar action 또는 route(
/search,/review,/lint,/setup,/settings)로 접근합니다.
현재 frontend는 session cookie를 기본 인증 경로로 사용합니다. 개발 서버에서는 VITE_API_BASE_URL 기본값으로 http://127.0.0.1:21080을 사용하고, backend가 번들된 frontend를 serve하는 packaged build에서는 same-origin /api/v1로 요청합니다. CI/headless 호출은 Settings > API tokens 또는 dtxwiki users add로 계정을 만든 뒤 PAT를 발급해 Authorization: Bearer dtxw_... 형식으로 사용할 수 있습니다.
환경 변수
| 변수 | 기본값 | 용도 |
|---|---|---|
DTXWIKI_APP_ENV |
development |
Backend 실행 환경. production/prod에서는 CORS startup guard가 강화됩니다. |
DTXWIKI_DATA_DIR |
~/.dtxwiki |
기본 SQLite DB, logs, local source root의 기준 디렉터리 |
DTXWIKI_DATABASE_URL |
sqlite+pysqlite:///~/.dtxwiki/data/dtxwiki.sqlite |
Backend DB URL. dtxWiki 는 SQLite 전용으로 동작합니다. |
DTXWIKI_SESSION_SECRET |
unset | Session cookie signing secret. unset이면 local development fallback을 사용합니다. |
DTXWIKI_SESSION_TTL_SECONDS |
43200 |
Session cookie TTL |
DTXWIKI_SESSION_COOKIE_NAME |
dtxwiki_session |
Session cookie 이름 |
DTXWIKI_SESSION_COOKIE_SECURE |
derived | HTTPS/public base URL이면 secure cookie 사용 |
DTXWIKI_OAUTH_ALLOW_DCR |
true |
OAuth dynamic client registration 허용 여부 |
DTXWIKI_OAUTH_ACCESS_TOKEN_TTL_SECONDS |
3600 |
OAuth RS256 access token TTL |
DTXWIKI_OAUTH_REFRESH_TOKEN_TTL_SECONDS |
2592000 |
OAuth refresh token TTL |
DTXWIKI_OAUTH_JWT_PRIVATE_KEY_PEM |
unset | OAuth access token signing private key PEM. unset이면 process-local 개발 key를 생성합니다. |
DTXWIKI_WORKSPACE_SLUG |
default |
기본 workspace slug |
DTXWIKI_BACKEND_PORT |
21080 |
CLI/package backend bind port. --port CLI 옵션이 있으면 옵션이 우선합니다. |
DTXWIKI_CORS_ORIGINS |
derived local dev origins | Backend CORS 허용 origin. comma-separated 또는 JSON list를 지원합니다. unset이면 backend/frontend port에서 개발용 localhost origin을 파생합니다. *와 empty string은 credentials 사용 때문에 거부되며 production에서는 명시적인 non-local origin 목록을 반드시 설정해야 합니다. |
DTXWIKI_AUTO_BOOTSTRAP |
true |
CLI/package startup에서 migration과 seed를 자동 수행할지 제어 |
DTXWIKI_PUBLIC_BASE_URL |
request-derived | OAuth issuer/resource URL, secure-cookie derivation, external client metadata에 사용할 public base URL |
DTXWIKI_LIBRARY_FILE_ROOTS |
~/.dtxwiki/library |
file:// source storage ref 허용 root. 여러 root는 OS path separator로 구분합니다. |
DTXWIKI_LLM_PROVIDER |
none |
Optional LLM provider selector. 지원값은 none, anthropic, openai입니다. 현재 Ask answer 생성 경로는 deterministic default를 유지합니다. |
DTXWIKI_EMBEDDING_PROVIDER |
none |
Embedding provider selector placeholder. Embedding retrieval은 Epic_1 이후 범위입니다. |
DTXWIKI_ANTHROPIC_API_KEY |
unset | DTXWIKI_LLM_PROVIDER=anthropic 사용 시 필요한 API key |
DTXWIKI_OPENAI_API_KEY |
unset | DTXWIKI_LLM_PROVIDER=openai 사용 시 필요한 API key |
DTXWIKI_MCP_CLIENT_ID |
client별 등록값 또는 internal-agent |
MCP actor 식별자 |
DTXWIKI_MCP_LOG_LEVEL |
INFO |
MCP stdio server logging level |
VITE_API_BASE_URL |
dev server: http://127.0.0.1:21080, packaged build: same-origin |
Frontend가 호출할 backend base URL |
VITE_DTXWIKI_API_TOKEN |
unset | 선택적 PAT bearer token. 일반 browser session에서는 비워 둡니다. |
AgentInputBundle TTL은 환경변수가 아니라 workspace policy(bundle_ttl_default_seconds, bundle_ttl_max_seconds)로 관리됩니다. 현재 코드에 DTXWIKI_OBJECT_STORE_*나 DTXWIKI_JOB_QUEUE_* 환경변수는 없습니다.
REST API 사용 예시
REST API는 session cookie 또는 PAT bearer token을 요구합니다.
export DTXWIKI_API=http://127.0.0.1:21080/api/v1
export DTXWIKI_TOKEN=dtxw_...
Page 생성:
curl -sS -X POST "$DTXWIKI_API/pages" \
-H "Authorization: Bearer $DTXWIKI_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"workspace_slug": "default",
"slug": "hello-page",
"title": "Hello page",
"body_md": "# Hello page\n\nThis page was created through REST."
}'
Page 목록 조회:
curl -sS "$DTXWIKI_API/pages?workspace=default" \
-H "Authorization: Bearer $DTXWIKI_TOKEN"
Pagination:
curl -sS "$DTXWIKI_API/pages?workspace=default&limit=10&cursor=0" \
-H "Authorization: Bearer $DTXWIKI_TOKEN"
limit은 1..100입니다. cursor는 응답의 next_cursor로 받은 opaque base64 token을 그대로 전달합니다. 기존 numeric offset cursor는 Epic_0 호환 입력으로만 허용되며 0..10000 범위를 넘으면 거부됩니다.
Page 읽기:
curl -sS "$DTXWIKI_API/pages/<page_id>" \
-H "Authorization: Bearer $DTXWIKI_TOKEN"
Page 수정은 stale write 방지를 위해 base_version_id와 base_content_hash를 함께 보내야 합니다.
curl -sS -X PATCH "$DTXWIKI_API/pages/<page_id>" \
-H "Authorization: Bearer $DTXWIKI_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"title": "Updated title",
"body_md": "# Updated title\n\nNew body.",
"base_version_id": "<current_version_id>",
"base_content_hash": "<current_content_hash>"
}'
Stale update는 HTTP 409와 함께 server의 최신 version/hash 정보를 반환합니다.
Workspace 조회와 search:
curl -sS "$DTXWIKI_API/workspaces" \
-H "Authorization: Bearer $DTXWIKI_TOKEN"
curl -sS -X POST "$DTXWIKI_API/workspaces/<workspace_id>/search" \
-H "Authorization: Bearer $DTXWIKI_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"query": "context policy",
"scope": "all",
"retrieval_mode": "keyword",
"limit": 10
}'
전체 REST surface는 shared/schemas/rest/v1/openapi.json을 기준으로 확인하세요.
REST error는 공통 envelope 형태를 사용합니다. FastAPI validation error도 detail 배열 대신 아래 shape로 반환됩니다.
{
"error_code": "validation_failed",
"message": "body.slug: Field required",
"request_id": "00000000-0000-0000-0000-000000000000",
"warnings": []
}
MCP stdio server
dtxwiki-mcp와 python -m backend.mcp.stdio_server는 표준 MCP JSON-RPC 2.0 stdio transport를 사용합니다. 로컬 단일 사용자 등록은 dtxwiki claude install, dtxwiki cursor install, dtxwiki codex install, dtxwiki mcp register --all --yes 명령으로 처리합니다. 원격 HTTP MCP 등록은 아래 원격 서버 배포와 팀 MCP 연결 섹션을 참고하세요.
stdio MCP server 실행:
# 기본 ~/.dtxwiki/data/dtxwiki.sqlite 를 사용하거나, 같은 DTXWIKI_DATABASE_URL 을
# backend 와 공유하도록 설정한 뒤 실행합니다.
.venv/bin/dtxwiki-mcp
P0 spec MCP tool:
| 그룹 | Tool |
|---|---|
| Read/context | guide, search, read, list_changes |
| Context write | write_draft, update_draft, cite, submit_feedback |
| Agent | list_agent_categories, read_agent_page, write_agent_page_draft, build_agent_input_bundle |
Legacy Pages 호환 tool:
list_pages, read_page, write_page
Legacy Pages tool은 tools/list description에 [DEPRECATED in Epic_1/Sprint_1]가 표시되고, 호출 결과 envelope의 warnings에 deprecated_tool을 포함합니다. 신규 MCP client는 guide, search, read, write_draft, update_draft, list_changes 등 Context/Agent 표준 tool을 사용하세요.
2026-05 Sprint_3 fix: 호출 결과 envelope 의
warnings항목이 단순 문자열 코드에서{code, message}객체 배열로 변경되었습니다. 기존 client 가warnings[0] == "deprecated_tool"으로 비교한다면warnings[0].code == "deprecated_tool"로 마이그레이션이 필요합니다.2026-05 Sprint_3 Hotfix-2: 위 warning 객체의 JSON Schema title이
Warning에서EnvelopeWarning으로 rename되었습니다. Wire shape ({code, message})은 동일하므로warnings[i].code접근 코드는 변경 불필요합니다. 단, schema로부터 자동 생성된 client type을 사용하는 경우 재생성이 필요합니다.
write_page, update_draft 계열 write는 stale update 감지를 위해 base_version_id와 base_content_hash를 사용합니다. 권한 또는 workflow 위반은 MCP tool result 안의 dtxWiki envelope로 scope_denied, rejected_by_policy, bundle_expired, validation_failed, unsupported_retrieval_mode 같은 error code를 반환합니다.
Unknown tool name 예시:
{
"envelope": {
"result_status": "failed",
"error_code": "unknown_tool"
}
}
Worker runtime
Source discovery, extraction, feedback-resolution, bundle-expiration job 은 backend 와
별도의 worker process 가 처리합니다. production self-host 에서는 worker 가 자동 실행됩니다 —
systemd 경로는 dtxwiki-worker.service, Docker 경로는 worker 컨테이너이며, 둘 다
backend 와 같은 SQLite DB 를 공유합니다. claim 로직은 database-backed queue
(SELECT FOR UPDATE SKIP LOCKED 지원 시)와 --poll-interval-seconds, --max-jobs,
--idle-exit-after 폴링 옵션을 사용합니다.
개발 checkout 에서 worker 를 직접 실행하는 방법은 DEVELOPMENT.md 를 보세요.
원격 서버 배포와 팀 MCP 연결
팀이 공유하는 dtxWiki 인스턴스를 원격 Ubuntu 서버에 self-host 로 올리고, 각 팀원의 PC 에서 웹 UI 와 MCP client 로 접속하는 표준 절차입니다. 이 섹션은 단일 사용자 packaged 실행과 달리 외부에서 도메인으로 접근하는 다중 사용자 시나리오를 다룹니다. 본 README 의 명령은 DEPLOYMENT.md 와 infra/prod/.env.example 을 기반으로 합니다.
서버 설치·배포의 전체 절차(권장 한 명령 install.sh / Docker, 수동·디버그 Step, reverse
proxy 옵션, 백업, Day-2 재설정)는 위 설치 와 DEPLOYMENT.md 에
있습니다. 아래는 배포 토폴로지 개요와, 팀원 PC 에서 서버 /mcp 에 붙는 기초 가이드입니다.
새 서버 설치 빠른 가이드 (SQLite)
아래 절차는 새 Ubuntu 서버에 dtxWiki 를 SQLite DB 로 설치하는 최소 운영 경로입니다. 예시는 wiki.example.com 도메인을 사용하며, 실제 설치 시 본인 도메인으로 바꾸세요. Backend 는 127.0.0.1:21080 에만 bind 하고, 외부 접속은 Caddy/nginx reverse proxy 가 HTTPS 로 처리합니다.
- DNS 와 방화벽을 준비합니다.
# DNS: wiki.example.com A/AAAA 레코드가 서버 public IP 를 가리키도록 설정
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
- 전용 계정과 데이터 디렉터리를 만듭니다.
sudo useradd --system --home /opt/dtxwiki --shell /usr/sbin/nologin dtxwiki
sudo mkdir -p /opt/dtxwiki /etc/dtxwiki /var/lib/dtxwiki /var/backups/dtxwiki
sudo chown -R dtxwiki:dtxwiki /opt/dtxwiki /var/lib/dtxwiki /var/backups/dtxwiki
sudo chown root:dtxwiki /etc/dtxwiki && sudo chmod 750 /etc/dtxwiki
- Python 3.12 venv 에 dtxWiki 를 설치합니다.
sudo apt-get update
sudo apt-get install -y software-properties-common
sudo add-apt-repository -y ppa:deadsnakes/ppa # Ubuntu 22.04 에서 Python 3.12 이 필요할 때
sudo apt-get update && sudo apt-get install -y python3.12 python3.12-venv sqlite3
sudo -u dtxwiki python3.12 -m venv /opt/dtxwiki/.venv
sudo -u dtxwiki /opt/dtxwiki/.venv/bin/pip install --upgrade pip
sudo -u dtxwiki /opt/dtxwiki/.venv/bin/pip install dtxwiki
source checkout 에서 직접 wheel 을 만들어 설치하는 경우에는 마지막 줄을 다음처럼 바꿉니다.
# 개발 PC 또는 CI 에서 wheel 생성 후 서버로 복사
make test-packaged
sudo -u dtxwiki /opt/dtxwiki/.venv/bin/pip install /path/to/dtxwiki-<version>.whl
- OAuth/JWT signing key 와 환경 파일을 준비합니다.
sudo install -o dtxwiki -g dtxwiki -m 700 -d /var/lib/dtxwiki/private
sudo -u dtxwiki /opt/dtxwiki/.venv/bin/dtxwiki keygen \
--output /var/lib/dtxwiki/private/jwt.pem
sudo install -o root -g dtxwiki -m 0640 \
/var/lib/dtxwiki/private/jwt.pem /etc/dtxwiki/jwt.pem
sudo rm /var/lib/dtxwiki/private/jwt.pem
sudo cp /opt/dtxwiki/.venv/share/dtxwiki/infra/prod/.env.example /etc/dtxwiki/dtxwiki.env
sudo chown root:dtxwiki /etc/dtxwiki/dtxwiki.env
sudo chmod 640 /etc/dtxwiki/dtxwiki.env
sudo nano /etc/dtxwiki/dtxwiki.env
/etc/dtxwiki/dtxwiki.env 에서 최소한 아래 값을 확인합니다.
DTXWIKI_APP_ENV=production
DTXWIKI_APP_MODE=team
DTXWIKI_PUBLIC_BASE_URL=https://wiki.example.com
DTXWIKI_CORS_ORIGINS=https://wiki.example.com
DTXWIKI_BEHIND_PROXY=true
DTXWIKI_FORWARDED_ALLOW_IPS=127.0.0.1
DTXWIKI_SESSION_SECRET=<python -c "import secrets; print(secrets.token_urlsafe(64))" 로 생성>
DTXWIKI_OAUTH_JWT_PRIVATE_KEY_PATH=/etc/dtxwiki/jwt.pem
DTXWIKI_DATABASE_URL=sqlite+pysqlite:////var/lib/dtxwiki/dtxwiki.sqlite
DTXWIKI_AUTO_BOOTSTRAP=false
DTXWIKI_MCP_HTTP_MODE=streamable
- 최초 1회 bootstrap 을 실행합니다.
sudo -u dtxwiki bash -c 'set -a; source /etc/dtxwiki/dtxwiki.env; \
/opt/dtxwiki/.venv/bin/dtxwiki bootstrap'
- systemd service 를 등록하고 시작합니다.
sudo cp /opt/dtxwiki/.venv/share/dtxwiki/infra/prod/dtxwiki.service /etc/systemd/system/
sudo cp /opt/dtxwiki/.venv/share/dtxwiki/infra/prod/dtxwiki-worker.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now dtxwiki dtxwiki-worker
sudo systemctl status dtxwiki dtxwiki-worker
- Caddy 로 HTTPS reverse proxy 를 설정합니다.
sudo apt-get install -y caddy
sudo cp /opt/dtxwiki/.venv/share/dtxwiki/infra/prod/Caddyfile.example /etc/caddy/Caddyfile
sudo sed -i 's/wiki.example.com/<your-domain>/g' /etc/caddy/Caddyfile
sudo systemctl reload-or-restart caddy
nginx 를 선호하면 아래 상세 Step 7 의 nginx + certbot 절차를 사용하세요.
- 관리자 계정을 만들고 smoke check 를 수행합니다.
sudo -u dtxwiki bash -c 'set -a; source /etc/dtxwiki/dtxwiki.env; \
/opt/dtxwiki/.venv/bin/dtxwiki users add admin@example.com --role owner'
curl -fsS https://wiki.example.com/health/live
curl -fsS https://wiki.example.com/health/ready
curl -i https://wiki.example.com/mcp
/health/ready 가 200 이고 /mcp 가 401 + WWW-Authenticate 헤더를 반환하면 기본 노출이 정상입니다. 브라우저에서 https://wiki.example.com/ 로 접속해 admin 계정으로 로그인하세요.
SQLite 운영 시에는 DB 파일과 signing key 를 함께 백업합니다.
sudo -u dtxwiki sqlite3 /var/lib/dtxwiki/dtxwiki.sqlite \
".backup '/var/backups/dtxwiki/dtxwiki-$(date +%F).sqlite'"
sudo cp /etc/dtxwiki/dtxwiki.env /var/backups/dtxwiki/dtxwiki.env.$(date +%F)
sudo cp /etc/dtxwiki/jwt.pem /var/backups/dtxwiki/jwt.pem.$(date +%F)
sudo chmod 600 /var/backups/dtxwiki/*
아키텍처 개요
┌────────────────────────────────────────────────┐
│ Remote Ubuntu Server (wiki.example.com) │
│ │
443/TLS ────► │ Caddy / nginx (TLS termination, security │
80 (ACME) │ headers, X-Forwarded-* 주입) │
│ │ │
│ ▼ 127.0.0.1:21080 │
│ dtxwiki.service │
│ └─ uvicorn + bundled React UI + /api/v1 + │
│ /mcp (Streamable HTTP) + /oauth/* │
│ │
│ dtxwiki-worker.service │
│ └─ source/feedback/bundle jobs │
│ │
│ /var/lib/dtxwiki/dtxwiki.sqlite (DB) │
│ /etc/dtxwiki/jwt.pem (OAuth RS256 signing key) │
└────────────────────────────────────────────────┘
▲ ▲
│ HTTPS (browser) │ HTTPS (/mcp + Bearer)
┌─────────────────────┴─────────┐ ┌─────────┴─────────────────────┐
│ 팀원 A: 웹 UI (브라우저) │ │ 팀원 B: Claude Code / Codex CLI │
│ Session cookie + RBAC │ │ PAT bearer 또는 dtxWiki OAuth │
└────────────────────────────────┘ └────────────────────────────────┘
핵심 포인트:
- backend uvicorn 은 항상
127.0.0.1:21080에만 bind 합니다. 외부 노출은 반드시 reverse proxy(Caddy 또는 nginx) 가 TLS 를 종료하면서 수행합니다. uvicorn 을0.0.0.0으로 직접 외부 노출하지 마세요(DTXWIKI_BEHIND_PROXY=true가드와 production CORS 가드와 충돌함). /api/v1과/mcp는 동일 origin 으로 serve 됩니다. 따라서 frontend 는 same-origin 요청만 사용하고 CORS preflight 가 발생하지 않습니다. 외부 CORS 는 다른 도메인에서 호출하는 client(SPA, third-party)만 필요로 합니다.- bundled frontend 는 backend wheel 안에 포함되어 같은 process 가
/에서 SPA 를 serve 합니다. 별도 Vite dev server 를 production 에서 띄울 필요는 없습니다. - SQLite DB 는
/var/lib/dtxwiki/에 두고 backend·worker 가 공유합니다 (production 은 SQLite 전용).
팀원 PC 에서 MCP client 연결
원격 dtxWiki 가 동작 중이면 팀원들은 자기 PC 의 Claude Code / Codex CLI / Cursor 에서 https://wiki.example.com/mcp 를 등록해 그대로 사용할 수 있습니다. dtxWiki Python 패키지를 팀원 PC 에 설치할 필요는 없습니다(설치한 경우 helper CLI 가 추가로 동작).
인증 방식 선택
| 방식 | 사용 시나리오 | 만료/회전 |
|---|---|---|
| PAT (Personal Access Token) bearer | 모든 HTTP MCP client (Claude Code, Codex CLI, Cursor, 사내 자동화) | --expires-at 명시 시 만료, 미명시 시 무기한. dtxwiki users revoke-pat 로 즉시 폐기 |
| dtxWiki OAuth 2.1 (DCR + PKCE) | OAuth-aware client (현재 Claude Code 가 가장 깔끔). 사용자별 consent 와 refresh token rotation 자동 | Access token TTL DTXWIKI_OAUTH_ACCESS_TOKEN_TTL_SECONDS(기본 3600s), refresh token DTXWIKI_OAUTH_REFRESH_TOKEN_TTL_SECONDS(기본 30d) |
팀 운영에는 다음을 권장합니다.
- 개별 사용자별로 별도 PAT 발급 (공유 금지). PAT 한 줄에 user identity 가 매핑되므로 audit 와 폐기가 쉽습니다.
- OAuth 가 자동 동작하는 Claude Code 사용자는 OAuth 경로를 우선 시도하고, 그 외 client 는 PAT.
OAuth 동작 방식 (OAuth-aware client)
Bearer 없이 /mcp 를 호출하면 WWW-Authenticate 의 resource_metadata 가
/.well-known/oauth-protected-resource 를 가리킵니다. OAuth-aware client 는 이 metadata 로
authorization server 를 찾아 /oauth/register(DCR) → /oauth/authorize(브라우저 consent) →
/oauth/token(S256 PKCE) 순서로 RS256 JWT access token 을 얻고, refresh token 은
/oauth/token 의 refresh_token grant 로 rotate 됩니다. OAuth 를 지원하지 않는 client 는
아래 PAT 경로를 사용하세요.
PAT 발급 (서버 관리자가 remote 에서 실행)
# remote 서버에서:
sudo -u dtxwiki bash -c 'set -a; source /etc/dtxwiki/dtxwiki.env; \
/opt/dtxwiki/.venv/bin/dtxwiki users issue-pat \
--user alice@example.com \
--name alice-laptop-mcp \
--scope mcp:read,mcp:write,mcp:agent \
--expires-at 2026-12-31T23:59:59Z'
명령은 다음 형태로 토큰을 한 번만 출력합니다.
PAT issued (copy now; this is the only time it is shown):
dtxw_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
token_id: <uuid>
scopes: mcp:read,mcp:write,mcp:agent
이 값을 안전한 채널(1Password / 사내 secrets manager / 직접 전달) 로 해당 팀원에게 전달합니다. Slack DM, 평문 이메일, 공용 채팅에 붙여넣지 마세요.
대안으로 팀원이 직접 웹 UI 에 로그인한 뒤 Settings > API tokens 에서 본인 PAT 를 발급해도 됩니다.
Claude Code (macOS / Linux)
claude mcp add --transport http dtxwiki https://wiki.example.com/mcp \
--header "Authorization: Bearer dtxw_..."
# 또는 OAuth 자동 등록 (브라우저 consent 가 뜨고 token 이 자동 저장됨)
claude mcp add --transport http dtxwiki https://wiki.example.com/mcp --oauth
위 명령은 ~/.claude.json 의 mcpServers.dtxwiki 항목을 작성합니다. 등록 후 claude 를 재시작하면 dtxWiki tool (guide, search, read, write_draft, ...) 이 노출됩니다.
Claude Code (Windows)
claude mcp add --transport http dtxwiki https://wiki.example.com/mcp `
--header "Authorization: Bearer dtxw_..."
config 파일 경로는 %USERPROFILE%\.claude.json 입니다. Windows 의 cmd.exe 에서는 backtick 대신 ^ 또는 한 줄로 입력하세요.
Codex CLI
Codex CLI 는 보안상 config 파일에 bearer 를 평문으로 저장하지 않고 환경변수로 분리합니다.
# bash/zsh — ~/.bashrc 또는 ~/.zshrc 에 영구 등록
export DTXWIKI_MCP_PAT=dtxw_...
codex mcp add dtxwiki --url https://wiki.example.com/mcp \
--bearer-token-env-var DTXWIKI_MCP_PAT
# Windows PowerShell — $PROFILE 에 영구 등록 권장
$env:DTXWIKI_MCP_PAT = "dtxw_..."
codex mcp add dtxwiki --url https://wiki.example.com/mcp `
--bearer-token-env-var DTXWIKI_MCP_PAT
config 파일 경로는 macOS/Linux 가 ~/.codex/config.toml, Windows 가 %APPDATA%\codex\config.toml 입니다.
Cursor 및 기타 HTTP MCP client
수동으로 mcpServers JSON 을 추가합니다.
{
"mcpServers": {
"dtxwiki": {
"url": "https://wiki.example.com/mcp",
"transport": "http",
"headers": {
"Authorization": "Bearer dtxw_..."
}
}
}
}
헬퍼 CLI (선택: 팀원이 dtxWiki venv 를 가진 경우)
팀원이 자기 PC 에 dtxWiki Python 패키지를 설치했다면 native CLI 대신 helper 를 사용할 수 있습니다.
pipx install dtxwiki # 또는 python -m venv + pip install dtxwiki
dtxwiki mcp register-http \
--url https://wiki.example.com/mcp \
--client claude-code \
--token dtxw_...
dtxwiki mcp doctor \
--http https://wiki.example.com/mcp \
--token dtxw_...
mcp doctor 는 /mcp 401 challenge, WWW-Authenticate resource metadata, /oauth/* reachability, PAT 가 주어진 경우 tools/list round-trip 까지 검증합니다.
각 client 별 상세 설정과 OS 경로 차이(Windows %APPDATA% 등)는 doc/setup/remote-mcp-clients.md 를 참고하세요.
트러블슈팅
| 증상 | 원인 | 조치 |
|---|---|---|
systemctl start dtxwiki 가 validate_for_startup 으로 즉시 종료 |
production guard 9개 중 하나 실패 | journalctl -u dtxwiki -n 80 --no-pager 의 hint 메시지대로 /etc/dtxwiki/dtxwiki.env 수정 후 systemctl restart dtxwiki |
| 브라우저 접속 시 CORS error | DTXWIKI_CORS_ORIGINS 가 실제 접속 도메인과 불일치 |
env 파일에 정확한 origin (https://wiki.example.com) 추가, scheme 까지 일치해야 함 |
/mcp 가 HTML SPA 응답 반환 |
reverse proxy 가 /mcp 도 SPA fallback 으로 처리 중 |
Caddy/nginx example 그대로 사용. dtxWiki 자체 SPA fallback 은 /mcp 를 면제(Task 4.11) |
| OAuth 토큰이 process 재시작마다 invalidate | DTXWIKI_OAUTH_JWT_PRIVATE_KEY_PATH 미설정으로 ephemeral key 사용 |
dtxwiki keygen 으로 키 생성 후 env 에 stable path 고정 (DEPLOYMENT.md) |
/health/ready 503 oauth_jwk=ephemeral_unsafe |
같은 원인 | 위와 동일 |
/health/ready 503 app_version=unsynced |
bootstrap 미수행 또는 migration 적용 안 됨 | dtxwiki bootstrap 1회 수동 실행 |
Claude Code 가 tools/list 에서 401 |
PAT scope 누락 또는 만료 | mcp:read,mcp:write,mcp:agent 모두 포함된 새 PAT 발급 |
Codex CLI 가 DTXWIKI_MCP_PAT 를 못 찾음 |
shell rc 가 reload 안 됨 / GUI launcher 가 env 미상속 | 새 shell 에서 echo $DTXWIKI_MCP_PAT 로 확인, GUI 사용 시 OS 사용자 env 로 등록 |
| reverse proxy 가 502 | uvicorn 미기동 또는 port mismatch | systemctl status dtxwiki, curl http://127.0.0.1:21080/health/live 확인 |
| Worker unit 즉시 종료 | --idle-exit-after 0 사용 |
dtxwiki-worker.service 의 ExecStart 점검 |
전체 production 운영 절차와 health endpoint 분리(/health/live, /health/ready, deprecated /api/v1/health) 는 DEPLOYMENT.md 를 참고하세요.
개발 / 기여
소스 빌드·개발 서버·테스트(make test / make lint / Playwright E2E)·스키마 생성·
로컬 인프라 compose 등 개발 워크플로 전체는 DEVELOPMENT.md 에 있습니다.
프로젝트 구조
backend/ FastAPI, SQLAlchemy, Alembic, service/repository/MCP runtime
backend/worker/ background worker CLI and dispatcher
backend/services/ application services for page/context/agent/source/search/audit flows
backend/migrations/versions/ Sprint_0~Sprint_2 Alembic migrations
frontend/ Vite React TypeScript web UI
frontend/src/features/ ask, library/source, context, agent, activity, review, search, lint, setup screens
shared/ content hash fixtures, REST/MCP schema artifacts, version/error metadata
infra/local/ 개발용 로컬 인프라 compose (DEVELOPMENT.md 참고)
infra/prod/ production self-host: install.sh, systemd unit, Docker compose, Caddyfile
tests/ cross-stack acceptance, static, browser E2E tests
doc/plan/ local Epic_0 sprint plans, reviews, completion summaries
현재 제한 사항
Epic_0 MVP는 local-first 사용에 맞춘 구현입니다. 다음 기능은 아직 포함하지 않습니다.
- multi-workspace UI
- upstream OIDC/SSO federation, MFA, token introspection/revocation endpoint, org-wide admin UI
- LLM-driven Ask answer generation, embedding/reranking/VLM provider implementations, and provider secret storage
- background source sync loop
- real lint analysis engine beyond manual run/finding/decision state
- embedding/semantic·hybrid retrieval (현재 keyword search 만; Epic_1 이후)
- object storage integration in the packaged local path
uv tool installacceptance smoke- Windows native smoke; Windows 지원은 예정되어 있지만 현재 PoC 검증은 Linux 기준입니다.
설계 문서
구현 기준 문서는 별도 design repository에 있습니다.
- Design repository:
/home/rony/workspace_dtx/dtxwiki_design - Required design branch:
main또는 activep0/* - Software design:
/home/rony/workspace_dtx/dtxwiki_design/doc/sw-design/ - Implementation plan:
/home/rony/workspace_dtx/dtxwiki_design/doc/sw-implementation-plan/ - Prism UI reference:
/home/rony/workspace_dtx/dtxwiki_design/design/260507-prism/
이 checkout의 Epic_0 진행 문서:
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file dtxwiki-0.0.1.tar.gz.
File metadata
- Download URL: dtxwiki-0.0.1.tar.gz
- Upload date:
- Size: 3.3 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
274f8996fde2d3bf645d12757bc85630ba5ada0f8897982dfd295390b8bb18ce
|
|
| MD5 |
0bd7b2f80c2db1965aecec7931baeb00
|
|
| BLAKE2b-256 |
519f80cbd560e8a49f90643db3070bf21ae04c0300850b92876e3ec4c4cd3246
|
Provenance
The following attestation bundles were made for dtxwiki-0.0.1.tar.gz:
Publisher:
release.yml on dtxSuite/dtxWiki
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dtxwiki-0.0.1.tar.gz -
Subject digest:
274f8996fde2d3bf645d12757bc85630ba5ada0f8897982dfd295390b8bb18ce - Sigstore transparency entry: 1912590257
- Sigstore integration time:
-
Permalink:
dtxSuite/dtxWiki@983a14ee070dffa6e4964b15f52d63e57ef9f0c8 -
Branch / Tag:
refs/tags/v0.0.1 - Owner: https://github.com/dtxSuite
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@983a14ee070dffa6e4964b15f52d63e57ef9f0c8 -
Trigger Event:
push
-
Statement type:
File details
Details for the file dtxwiki-0.0.1-py3-none-any.whl.
File metadata
- Download URL: dtxwiki-0.0.1-py3-none-any.whl
- Upload date:
- Size: 3.5 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3ec5b923b5f490e88344f8baa5df8091be774395814216e9a45d6775cf8e4571
|
|
| MD5 |
dc74ae97a38ace08f46b6f9c3d0417cc
|
|
| BLAKE2b-256 |
6102cb2e32bb986d8d1c8cc175d47ad9b92c6413e3f699022fb9db00977bc6a5
|
Provenance
The following attestation bundles were made for dtxwiki-0.0.1-py3-none-any.whl:
Publisher:
release.yml on dtxSuite/dtxWiki
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dtxwiki-0.0.1-py3-none-any.whl -
Subject digest:
3ec5b923b5f490e88344f8baa5df8091be774395814216e9a45d6775cf8e4571 - Sigstore transparency entry: 1912590370
- Sigstore integration time:
-
Permalink:
dtxSuite/dtxWiki@983a14ee070dffa6e4964b15f52d63e57ef9f0c8 -
Branch / Tag:
refs/tags/v0.0.1 - Owner: https://github.com/dtxSuite
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@983a14ee070dffa6e4964b15f52d63e57ef9f0c8 -
Trigger Event:
push
-
Statement type: