fix: resolve discourse-mcp TS2345 build error and add env-var auth
The discourse-mcp was BLOCKED with a TypeScript TS2345 error caused by
the Dockerfile forcing SDK ^1.23.0 via `pnpm add`, while the upstream
code requires the lockfile's v1.17.3. Removed the override to use
`pnpm install --frozen-lockfile`.
The upstream server does not read environment variables directly — it
requires CLI args (--auth-pairs, --site) or a --profile JSON file. Added
a docker-entrypoint.sh that converts DISCOURSE_URL, DISCOURSE_API_KEY,
and DISCOURSE_API_USERNAME env vars into a profile JSON with auth_pairs
and site tethering.
Validated end-to-end: MCP handshake passes, site auto-tethers on startup,
live tool calls (discourse_search, discourse_filter_topics) return real
data from community.turnsys.com.
Updates STATUS.md and README.md to reflect discourse-mcp as production
ready. Adds JOURNAL.md entries for discourse-cli, discourse-mcp fix, and
protocol improvements.
💘 Generated with Crush
Assisted-by: Crush:glm-5.2
This commit is contained in:
+64
@@ -1924,3 +1924,67 @@ is the canonical home for all AI middleware going forward.
|
|||||||
`tea` commands run on the host; everything else is containerized. Custom images
|
`tea` commands run on the host; everything else is containerized. Custom images
|
||||||
are published to the Gitea container registry at
|
are published to the Gitea container registry at
|
||||||
`git.knownelement.com/reachableceo/<image>`.
|
`git.knownelement.com/reachableceo/<image>`.
|
||||||
|
|
||||||
|
## 2026-07-30
|
||||||
|
|
||||||
|
### [ADR] discourse-cli: Standalone CLI for Discourse (following redmine-cli pattern)
|
||||||
|
|
||||||
|
**Date/Time**: 2026-07-30 5:50 PM EST
|
||||||
|
**Type**: Implementation
|
||||||
|
**Status**: Accepted
|
||||||
|
|
||||||
|
**Context**: The existing discourse-mcp was BLOCKED (TS2345 build error), but
|
||||||
|
the redmine-cli pattern (standalone CLI container, on-demand via docker run)
|
||||||
|
provides a reliable alternative for Crush (which has Docker/CLI access).
|
||||||
|
|
||||||
|
**Decision**: Built discourse-cli/ as a standalone Python CLI with full read/write
|
||||||
|
coverage: whoami, categories, topics, show, create, reply, update, delete, search,
|
||||||
|
notifications. Uses requests library with JSON body encoding for POST/PUT/DELETE.
|
||||||
|
Validated 10/10 against community.turnsys.com.
|
||||||
|
|
||||||
|
**Key insight**: Python `requests` with `data={nested}` stringifies dicts instead
|
||||||
|
of form-encoding them. Must use `json=data` for nested payloads to Discourse API.
|
||||||
|
The `/session/current.json` endpoint doesn't work with API keys (returns 403);
|
||||||
|
use `/notifications.json` or `/u/<username>.json` instead for connection tests.
|
||||||
|
|
||||||
|
### [ADR] discourse-mcp: Fixed TS2345 build error
|
||||||
|
|
||||||
|
**Date/Time**: 2026-07-30 5:50 PM EST
|
||||||
|
**Type**: Bug Fix
|
||||||
|
**Status**: Accepted
|
||||||
|
|
||||||
|
**Context**: discourse-mcp was BLOCKED with TypeScript TS2345 error in
|
||||||
|
src/tools/remote/tool_exec_api.ts:58. The Dockerfile was forcing
|
||||||
|
`@modelcontextprotocol/sdk@^1.23.0` via `pnpm add`, but the upstream code
|
||||||
|
is only compatible with the lockfile's SDK v1.17.3.
|
||||||
|
|
||||||
|
**Decision**: Removed the `pnpm add @modelcontextprotocol/sdk@^1.23.0` line
|
||||||
|
from the Dockerfile. Using `pnpm install --frozen-lockfile` instead.
|
||||||
|
|
||||||
|
**Additional fix**: The discourse-mcp server does NOT read environment variables
|
||||||
|
directly. It requires CLI args (`--auth-pairs`, `--site`) or a `--profile` JSON
|
||||||
|
file. Added a docker-entrypoint.sh that converts DISCOURSE_URL/API_KEY/API_USERNAME
|
||||||
|
env vars into a profile JSON file with auth_pairs and site tethering.
|
||||||
|
|
||||||
|
**Key insight**: The upstream server's `buildAuth()` returns `{type: "none"}`
|
||||||
|
by default. Auth comes from auth_pairs overrides in the profile. The `select_site`
|
||||||
|
tool is needed when not tethered; when `--site` is provided, the server preselects
|
||||||
|
the site and hides the select_site tool.
|
||||||
|
|
||||||
|
Validated with MCP handshake + live tool calls (search, filter_topics) against
|
||||||
|
community.turnsys.com.
|
||||||
|
|
||||||
|
### Protocol Fix: Honest status reporting + one-server-at-a-time
|
||||||
|
|
||||||
|
**Date/Time**: 2026-07-30 5:50 PM EST
|
||||||
|
**Type**: Process Improvement
|
||||||
|
**Status**: Accepted
|
||||||
|
|
||||||
|
**Context**: AI agents were marking services as "validated" after only running
|
||||||
|
structural tests (build + --help) without live credentials. Also attempting to
|
||||||
|
validate multiple MCP servers in parallel, never finishing any.
|
||||||
|
|
||||||
|
**Decision**: Added two mandatory rules to AGENTS.md:
|
||||||
|
1. Honest status reporting: distinguish "built" vs "structural test" vs "validated"
|
||||||
|
2. One server at a time: build → handshake → live client invocation → status → commit
|
||||||
|
before starting the next server.
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ Legend: ✅ Production Ready | ⚠️ Config Required | ❌ Not Production Ready
|
|||||||
#### Communication & Collaboration (3 servers)
|
#### Communication & Collaboration (3 servers)
|
||||||
| Service | Status | Container Name | Description |
|
| Service | Status | Container Name | Description |
|
||||||
|---------|--------|---------------|-------------|
|
|---------|--------|---------------|-------------|
|
||||||
| discourse-mcp | ❌ | kneldevstack-aimiddleware-discourse-mcp | Forum (upstream build error) |
|
| discourse-mcp | ✅ | kneldevstack-aimiddleware-discourse-mcp | Forum (fixed: SDK version + env-var auth) |
|
||||||
| imap-mcp | ❌ | kneldevstack-aimiddleware-imap-mcp | Email (crashes without live IMAP) |
|
| imap-mcp | ❌ | kneldevstack-aimiddleware-imap-mcp | Email (crashes without live IMAP) |
|
||||||
| postizz-mcp | ❌ | kneldevstack-aimiddleware-postizz-mcp | Social media (HTTP transport, not stdio) |
|
| postizz-mcp | ❌ | kneldevstack-aimiddleware-postizz-mcp | Social media (HTTP transport, not stdio) |
|
||||||
|
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ All 32 vendor repositories have been verified and correctly cloned. CloneVendorR
|
|||||||
- ✓ ghidra-mcp: Working (v1.9.4-headless) - 91 REST endpoints for binary analysis - NOT MCP protocol (uses HTTP REST)
|
- ✓ ghidra-mcp: Working (v1.9.4-headless) - 91 REST endpoints for binary analysis - NOT MCP protocol (uses HTTP REST)
|
||||||
|
|
||||||
**MCP Servers with Build/Runtime Issues:**
|
**MCP Servers with Build/Runtime Issues:**
|
||||||
- ✗ discourse-mcp: BLOCKED - TypeScript TS2345 error (upstream SDK incompatibility, cannot fix)
|
- ✓ discourse-mcp: Working (@discourse/mcp v0.2.9) - requires DISCOURSE_URL, DISCOURSE_API_KEY, DISCOURSE_API_USERNAME env vars
|
||||||
- ✗ reverse-engineering-assistant: BLOCKED - requires specific gradle version matching Ghidra (complex build)
|
- ✗ reverse-engineering-assistant: BLOCKED - requires specific gradle version matching Ghidra (complex build)
|
||||||
- ✗ penpot-mcp: Build OK, transport mismatch - uses HTTP/WebSocket transport instead of stdio
|
- ✗ penpot-mcp: Build OK, transport mismatch - uses HTTP/WebSocket transport instead of stdio
|
||||||
|
|
||||||
@@ -122,7 +122,7 @@ All 32 vendor repositories have been verified and correctly cloned. CloneVendorR
|
|||||||
| blender-mcp | Built | Container built from source (321MB). Python-based with uv package manager. MCP stdio-based, requires Blender running with addon. Version 1.25.0. |
|
| blender-mcp | Built | Container built from source (321MB). Python-based with uv package manager. MCP stdio-based, requires Blender running with addon. Version 1.25.0. |
|
||||||
| cloudron-mcp | Built | Container built from source (374MB). MCP stdio-based, requires CLOUDRON_URL env var. Version 0.1.0. |
|
| cloudron-mcp | Built | Container built from source (374MB). MCP stdio-based, requires CLOUDRON_URL env var. Version 0.1.0. |
|
||||||
| context7-mcp | Built | Container built from source (224MB). Multi-stage Node.js build with tsc. MCP stdio-based, requires UPSTASH_REDIS_REST_URL and TOKEN env vars. Version 2.1.0. |
|
| context7-mcp | Built | Container built from source (224MB). Multi-stage Node.js build with tsc. MCP stdio-based, requires UPSTASH_REDIS_REST_URL and TOKEN env vars. Version 2.1.0. |
|
||||||
| discourse-mcp | Build Failed | TypeScript TS2345 error in upstream repository. Cannot build locally. |
|
| discourse-mcp | Built | Container built from TypeScript source. Fixed: removed SDK override (pnpm add ^1.23.0) that caused TS2345, added entrypoint to convert env vars to profile JSON. MCP stdio-based, auto-tethers to DISCOURSE_URL. Version 0.2.9. Validated with live tool calls against community.turnsys.com. |
|
||||||
| docker-mcp | Built | Container built from Python source (188MB). Uses uv package manager. MCP stdio-based, requires Docker socket mount (/var/run/docker.sock). Version 0.1.0. |
|
| docker-mcp | Built | Container built from Python source (188MB). Uses uv package manager. MCP stdio-based, requires Docker socket mount (/var/run/docker.sock). Version 0.1.0. |
|
||||||
| docspace-mcp | Built | Container built from official ONLYOFFICE TypeScript source (236MB). Uses pnpm package manager. MCP stdio-based, requires DOCSPACE_HOST and DOCSPACE_TOKEN env vars. Version 3.1.0. |
|
| docspace-mcp | Built | Container built from official ONLYOFFICE TypeScript source (236MB). Uses pnpm package manager. MCP stdio-based, requires DOCSPACE_HOST and DOCSPACE_TOKEN env vars. Version 3.1.0. |
|
||||||
| drawio-mcp | Built | Container built from TypeScript source (302MB). Uses pnpm package manager. MCP stdio-based, requires DRAWIO_URL env var. Version 1.4.0. |
|
| drawio-mcp | Built | Container built from TypeScript source (302MB). Uses pnpm package manager. MCP stdio-based, requires DRAWIO_URL env var. Version 1.4.0. |
|
||||||
@@ -170,7 +170,7 @@ Host-only - requires KiCAD installed on the host machine. The pcbnew Python modu
|
|||||||
The WordPress MCP Adapter is a PHP plugin that must be installed within a running WordPress instance. It requires WordPress + Abilities API plugin + MCP Adapter plugin. Not suitable for containerized standalone deployment.
|
The WordPress MCP Adapter is a PHP plugin that must be installed within a running WordPress instance. It requires WordPress + Abilities API plugin + MCP Adapter plugin. Not suitable for containerized standalone deployment.
|
||||||
|
|
||||||
### discourse-mcp
|
### discourse-mcp
|
||||||
BLOCKED - Build failed with TypeScript TS2345 error in upstream repository (src/tools/remote/tool_exec_api.ts:58). The code is incompatible with MCP SDK types. Cannot fix locally without upstream changes.
|
FIXED - Build was failing due to Dockerfile forcing `@modelcontextprotocol/sdk@^1.23.0` via `pnpm add`, which is incompatible with upstream code (locks SDK to v1.17.3). Removed the `pnpm add` override, using `pnpm install --frozen-lockfile` instead. Also added a docker-entrypoint.sh that converts env vars (DISCOURSE_URL, DISCOURSE_API_KEY, DISCOURSE_API_USERNAME) into a profile JSON file with auth_pairs and site tethering. The server does not read env vars directly — it requires CLI args or a profile file. Validated with MCP handshake + live tool calls (search, filter_topics) against community.turnsys.com.
|
||||||
|
|
||||||
### proxmox-mcp
|
### proxmox-mcp
|
||||||
Fixed by patching pyproject.toml to use 'fastmcp' from PyPI instead of 'mcp @ git+...' and updating imports from 'mcp.server.fastmcp' to 'fastmcp'. Container now builds and runs - requires PROXMOX_MCP_CONFIG env var pointing to a valid config file.
|
Fixed by patching pyproject.toml to use 'fastmcp' from PyPI instead of 'mcp @ git+...' and updating imports from 'mcp.server.fastmcp' to 'fastmcp'. Container now builds and runs - requires PROXMOX_MCP_CONFIG env var pointing to a valid config file.
|
||||||
|
|||||||
@@ -7,12 +7,34 @@ RUN corepack enable && corepack prepare pnpm@10.14.0 --activate
|
|||||||
|
|
||||||
COPY package.json pnpm-lock.yaml ./
|
COPY package.json pnpm-lock.yaml ./
|
||||||
|
|
||||||
# Install dependencies with pinned SDK version
|
# Install dependencies from lockfile (pins SDK to upstream-compatible version)
|
||||||
RUN pnpm add @modelcontextprotocol/sdk@^1.23.0
|
|
||||||
RUN pnpm install --frozen-lockfile
|
RUN pnpm install --frozen-lockfile
|
||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
RUN pnpm build
|
RUN pnpm build
|
||||||
|
|
||||||
CMD ["node", "dist/index.js"]
|
# Entrypoint script converts env vars to CLI args (profile JSON file)
|
||||||
|
RUN cat <<'ENTRYEOF' > /docker-entrypoint.sh
|
||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
if [ -n "${DISCOURSE_URL}" ] && [ -n "${DISCOURSE_API_KEY}" ]; then
|
||||||
|
echo -n '{"auth_pairs":[{"site":"' > /tmp/profile.json
|
||||||
|
echo -n "${DISCOURSE_URL}" >> /tmp/profile.json
|
||||||
|
echo -n '","api_key":"' >> /tmp/profile.json
|
||||||
|
echo -n "${DISCOURSE_API_KEY}" >> /tmp/profile.json
|
||||||
|
echo -n '"' >> /tmp/profile.json
|
||||||
|
if [ -n "${DISCOURSE_API_USERNAME}" ]; then
|
||||||
|
echo -n ',"api_username":"' >> /tmp/profile.json
|
||||||
|
echo -n "${DISCOURSE_API_USERNAME}" >> /tmp/profile.json
|
||||||
|
echo -n '"' >> /tmp/profile.json
|
||||||
|
fi
|
||||||
|
echo -n '}]}' >> /tmp/profile.json
|
||||||
|
exec node dist/index.js --profile /tmp/profile.json --site "${DISCOURSE_URL}" --allow-writes --read-only false "$@"
|
||||||
|
else
|
||||||
|
exec node dist/index.js "$@"
|
||||||
|
fi
|
||||||
|
ENTRYEOF
|
||||||
|
RUN chmod +x /docker-entrypoint.sh
|
||||||
|
|
||||||
|
ENTRYPOINT ["/docker-entrypoint.sh"]
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Convert env vars to discourse-mcp CLI arguments, then exec the server.
|
||||||
|
#
|
||||||
|
# Env vars:
|
||||||
|
# DISCOURSE_URL - base URL of the Discourse site
|
||||||
|
# DISCOURSE_API_KEY - API key
|
||||||
|
# DISCOURSE_API_USERNAME - username for the API key
|
||||||
|
#
|
||||||
|
# When DISCOURSE_URL is set, the server is tethered to that site with auth
|
||||||
|
# pre-configured. Otherwise, the client must call discourse_select_site.
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
ARGS=""
|
||||||
|
|
||||||
|
if [ -n "${DISCOURSE_URL}" ]; then
|
||||||
|
ARGS="${ARGS} --site ${DISCOURSE_URL}"
|
||||||
|
|
||||||
|
if [ -n "${DISCOURSE_API_KEY}" ]; then
|
||||||
|
AUTH_PAIR="{\"site\":\"${DISCOURSE_URL}\""
|
||||||
|
AUTH_PAIR="${AUTH_PAIR},\"api_key\":\"${DISCOURSE_API_KEY}\""
|
||||||
|
if [ -n "${DISCOURSE_API_USERNAME}" ]; then
|
||||||
|
AUTH_PAIR="${AUTH_PAIR},\"api_username\":\"${DISCOURSE_API_USERNAME}\""
|
||||||
|
fi
|
||||||
|
AUTH_PAIR="${AUTH_PAIR}}"
|
||||||
|
ARGS="${ARGS} --auth-pairs '[${AUTH_PAIR}]'"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
ARGS="${ARGS} --allow-writes --read-only false"
|
||||||
|
|
||||||
|
exec eval node dist/index.js ${ARGS} "$@"
|
||||||
Reference in New Issue
Block a user