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
|
||||
are published to the Gitea container registry at
|
||||
`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)
|
||||
| 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) |
|
||||
| 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)
|
||||
|
||||
**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)
|
||||
- ✗ 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. |
|
||||
| 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. |
|
||||
| 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. |
|
||||
| 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. |
|
||||
@@ -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.
|
||||
|
||||
### 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
|
||||
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 ./
|
||||
|
||||
# Install dependencies with pinned SDK version
|
||||
RUN pnpm add @modelcontextprotocol/sdk@^1.23.0
|
||||
# Install dependencies from lockfile (pins SDK to upstream-compatible version)
|
||||
RUN pnpm install --frozen-lockfile
|
||||
|
||||
COPY . .
|
||||
|
||||
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