Content
# Tool List
## Goal
Batch build CodeGraph knowledge bases for multiple projects under a parent directory and provide remote MCP access through a Docker container and a single exposed port.
The final access form:
```text
http://remote-machine:8000/project-a/mcp
http://remote-machine:8000/project-b/mcp
http://remote-machine:8000/project-c/mcp
```
Inside the container, each project still starts an independent `codegraph serve --mcp --path <project>`, and then the front Node gateway forwards according to the URL prefix.
## Directory Structure
```text
docker/
.env
batch_codegraph_init.sh
codegraph.Dockerfile
docker_codegraph.md
multi_project_gateway.js
codegraph-linux-x64-v1.4.0.tar.gz
install-codegraph.sh
```
Explanation:
- `docker/codegraph.Dockerfile`: Build CodeGraph MCP remote service image.
- `docker/batch_codegraph_init.sh`: Scan the project collection directory, execute `codegraph init` for each subdirectory.
- `docker/multi_project_gateway.js`: Scan initialized projects, start internal `supergateway` for each project, and expose a unified HTTP entry.
- `docker/.env`: Save build and run variables.
- `codegraph-linux-x64-v1.4.0.tar.gz`: CodeGraph Linux x64 offline package, placed in the repository root directory as part of the Docker build context.
## Working Method
Server-side project collection directory:
```text
/srv/projects/
project-a/
project-b/
project-c/
```
Mounted inside the container:
```text
/workspace/projects/
project-a/
project-b/
project-c/
```
After batch initialization:
```text
/workspace/projects/project-a/.codegraph/codegraph.db
/workspace/projects/project-b/.codegraph/codegraph.db
/workspace/projects/project-c/.codegraph/codegraph.db
```
When the container starts, `multi_project_gateway.js` will:
1. Scan subdirectories under `CONTAINER_PROJECTS_PATH`.
2. Only serve projects with existing `.codegraph/codegraph.db`.
3. Assign an internal port for each project, e.g., `9100`, `9101`, `9102`.
4. Start internal `supergateway`.
5. Expose a unified entry on `MCP_PORT`.
Example routing:
```text
/project-a/mcp -> 127.0.0.1:9100/mcp
/project-a/healthz -> 127.0.0.1:9100/healthz
/project-b/mcp -> 127.0.0.1:9101/mcp
```
Project URL slug is generated from the directory name. Accessing the root path or `/projects` shows the actual mapping:
```bash
curl "http://remote-machine:8000/projects"
```
## Configurable Variables
Variables are centralized in `docker/.env`:
```dotenv
# Build settings
NODE_IMAGE=node:22-bookworm-slim
APT_MIRROR_BASE=http://mirrors.aliyun.com
CODEGRAPH_VERSION=v1.4.0
CODEGRAPH_ARCHIVE=codegraph-linux-x64-v1.4.0.tar.gz
SUPERGATEWAY_VERSION=3.4.3
IMAGE_NAME=codegraph-mcp
IMAGE_TAG=v1.4.0
IMAGE_TAR=codegraph-mcp-v1.4.0.tar
# Runtime settings
CONTAINER_NAME=codegraph-mcp
HOST_PORT=8000
MCP_PORT=8000
HOST_PROJECTS_PATH=/srv/projects
CONTAINER_PROJECTS_PATH=/workspace/projects
MCP_INTERNAL_PORT_START=9100
STREAMABLE_HTTP_PATH=/mcp
HEALTH_ENDPOINT=/healthz
LOG_LEVEL=info
CODEGRAPH_NO_WATCH=1
CODEGRAPH_EXCLUDE_HIDDEN=1
```
Usually, only modify:
- `HOST_PROJECTS_PATH`: Project collection directory on the offline server.
- `HOST_PORT`: Exposed port.
- `IMAGE_TAG` / `IMAGE_TAR`: Image version and export filename.
- `APT_MIRROR_BASE`: Debian apt mirror source used during image building.
Optional variables:
- `MCP_INTERNAL_PORT_START`: Internal `supergateway` starting port, only used inside the container.
- `CODEGRAPH_EXCLUDE_HIDDEN=1`: Skip hidden directories.
- `CODEGRAPH_SERVE_UNINITIALIZED=1`: Allow serving uninitialized directories. Default is not recommended.
## Building the Image in the Online Environment
Execute in the repository root directory. Linux/macOS shell:
```bash
set -a
. docker/.env
set +a
docker build \
-f docker/codegraph.Dockerfile \
--build-arg NODE_IMAGE="${NODE_IMAGE}" \
--build-arg APT_MIRROR_BASE="${APT_MIRROR_BASE}" \
--build-arg CODEGRAPH_VERSION="${CODEGRAPH_VERSION}" \
--build-arg CODEGRAPH_ARCHIVE="${CODEGRAPH_ARCHIVE}" \
--build-arg SUPERGATEWAY_VERSION="${SUPERGATEWAY_VERSION}" \
-t "${IMAGE_NAME}:${IMAGE_TAG}" \
.
```
Windows PowerShell:
```powershell
Get-Content .\docker\.env | Where-Object { $_ -and $_ -notmatch '^#' } | ForEach-Object {
$k, $v = $_ -split '=', 2
Set-Item -Path "Env:$k" -Value $v
}
docker build `
-f .\docker\codegraph.Dockerfile `
--build-arg NODE_IMAGE="$env:NODE_IMAGE" `
--build-arg APT_MIRROR_BASE="$env:APT_MIRROR_BASE" `
--build-arg CODEGRAPH_VERSION="$env:CODEGRAPH_VERSION" `
--build-arg CODEGRAPH_ARCHIVE="$env:CODEGRAPH_ARCHIVE" `
--build-arg SUPERGATEWAY_VERSION="$env:SUPERGATEWAY_VERSION" `
-t "$env:IMAGE_NAME`:$env:IMAGE_TAG" `
.
```
Export the image:
```bash
docker save "${IMAGE_NAME}:${IMAGE_TAG}" -o "${IMAGE_TAR}"
```
PowerShell:
```powershell
docker save "$env:IMAGE_NAME`:$env:IMAGE_TAG" -o "$env:IMAGE_TAR"
```
## Loading and Running in the Offline Environment
Load the image:
Before executing the following instructions, you need to change the HOST_PROJECTS_PATH variable in the .env file to the actual project path.
```bash
set -a
. docker/.env
set +a
docker load -i "${IMAGE_TAR}"
```
Run the container:
```bash
docker run -d \
--name "${CONTAINER_NAME}" \
--env-file docker/.env \
-p "${HOST_PORT}:${MCP_PORT}" \
-v "${HOST_PROJECTS_PATH}:${CONTAINER_PROJECTS_PATH}" \
--restart unless-stopped \
"${IMAGE_NAME}:${IMAGE_TAG}"
```
If the current user does not have Docker permissions, add `sudo` before `docker`.
Recommended checks before running:
```bash
printf 'HOST_PROJECTS_PATH=%s\n' "$HOST_PROJECTS_PATH"
printf 'CONTAINER_PROJECTS_PATH=%s\n' "$CONTAINER_PROJECTS_PATH"
printf 'IMAGE=%s:%s\n' "$IMAGE_NAME" "$IMAGE_TAG"
ls -ld "$HOST_PROJECTS_PATH"
```
## Initializing CodeGraph Index
After the container starts, batch initialize all primary sub-projects:
```bash
docker exec -it "${CONTAINER_NAME}" batch_codegraph_init.sh "${CONTAINER_PROJECTS_PATH}"
```
After initialization, restart the container to let the front gateway rescan initialized projects:
```bash
docker restart "${CONTAINER_NAME}"
```
Single project can also be manually initialized:
```bash
docker exec -it "${CONTAINER_NAME}" codegraph init "${CONTAINER_PROJECTS_PATH}/project-a"
```
Check status:
```bash
docker exec -it "${CONTAINER_NAME}" codegraph status "${CONTAINER_PROJECTS_PATH}/project-a"
```
Test query:
```bash
docker exec -it "${CONTAINER_NAME}" codegraph explore "某个函数名或你的问题" --path "${CONTAINER_PROJECTS_PATH}/project-a"
```
## Remote Access Verification
Check the unified gateway:
```bash
curl "http://remote-machine:${HOST_PORT}${HEALTH_ENDPOINT}"
```
View project mapping:
```bash
curl "http://remote-machine:${HOST_PORT}/projects"
```
Check a project's backend:
```bash
curl "http://remote-machine:${HOST_PORT}/project-a/healthz"
```
View logs:
```bash
docker logs -f "${CONTAINER_NAME}"
```
Logs will appear like:
```text
[CodeGraph Gateway] project-a -> 127.0.0.1:9100/mcp (/workspace/projects/project-a)
[CodeGraph Gateway] Listening on 0.0.0.0:8000
```
## opencode Configuration
opencode remote MCP example:
```jsonc
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"codegraph-project-a": {
"type": "remote",
"url": "http://remote-machine:8000/project-a/mcp",
"enabled": true
},
"codegraph-project-b": {
"type": "remote",
"url": "http://remote-machine:8000/project-b/mcp",
"enabled": true
}
}
}
```
Actual `project-a`, `project-b` are based on the `slug` returned by the front gateway `/projects`.
## openclaude Configuration
If the current OpenClaude supports HTTP MCP:
```json
{
"mcpServers": {
"codegraph-project-a": {
"type": "http",
"url": "http://remote-machine:8000/project-a/mcp"
}
},
"permissions": {
"allow": [
"mcp__codegraph-project-a__*"
]
}
}
```
If the current OpenClaude does not support `type: "http"`, use local `mcp-remote`:
```json
{
"mcpServers": {
"codegraph-project-a": {
"type": "stdio",
"command": "node",
"args": [
"D:/LX/Projects/IEI-RAG/codegraph_private/mcp-offline/node_modules/mcp-remote/dist/proxy.js",
"http://remote-machine:8000/project-a/mcp",
"--allow-http",
"--transport",
"http-only"
]
}
},
"permissions": {
"allow": [
"mcp__codegraph-project-a__*"
]
}
}
```
## Frequently Asked Questions
### `/projects` Returns an Empty Array
Indicates that no initialized projects were found when the container started. First, execute:
```bash
docker exec -it "${CONTAINER_NAME}" batch_codegraph_init.sh "${CONTAINER_PROJECTS_PATH}"
docker restart "${CONTAINER_NAME}"
```
### Project Directory Exists but is Not Served
Only projects with existing `.codegraph/codegraph.db` are served by default. Check:
```bash
docker exec -it "${CONTAINER_NAME}" ls -l "${CONTAINER_PROJECTS_PATH}/project-a/.codegraph"
```
### Client Cannot Connect
First, check:
```bash
docker ps
docker logs -f "${CONTAINER_NAME}"
curl "http://remote-machine:${HOST_PORT}${HEALTH_ENDPOINT}"
curl "http://remote-machine:${HOST_PORT}/projects"
```
Then, check if the firewall allows `HOST_PORT`.
### Docker Reports Mount Parameter Error
Usually, the `.env` file is not loaded, causing the mount parameter to be empty. Check:
```bash
printf 'HOST_PROJECTS_PATH=%s\n' "$HOST_PROJECTS_PATH"
printf 'CONTAINER_PROJECTS_PATH=%s\n' "$CONTAINER_PROJECTS_PATH"
ls -ld "$HOST_PROJECTS_PATH"
```
### Index Needs to Be Refreshed
Reindex a single project:
```bash
docker exec -it "${CONTAINER_NAME}" codegraph index "${CONTAINER_PROJECTS_PATH}/project-a"
```
Batch reindexing can be done by re-executing:
```bash
docker exec -it "${CONTAINER_NAME}" batch_codegraph_init.sh "${CONTAINER_PROJECTS_PATH}"
docker restart "${CONTAINER_NAME}"
```
### Plaintext HTTP
Intranet can directly use:
```text
http://remote-machine:8000/project-a/mcp
```
Production environment recommends adding Nginx / TLS:
```text
https://codegraph.example.com/project-a/mcp
```