Skip to content

feat: add stdio bridge and npm publish workflow - #19

Merged
akurinnoy merged 2 commits into
mainfrom
feat/npm-publish-and-stdio-bridge
Jul 9, 2026
Merged

feat: add stdio bridge and npm publish workflow#19
akurinnoy merged 2 commits into
mainfrom
feat/npm-publish-and-stdio-bridge

Conversation

@akurinnoy

@akurinnoy akurinnoy commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add stdio-bridge.cjs — a stdio MCP proxy that manages oc port-forward internally, auto-starts, monitors, and restarts on failure. Enables local Claude Code sessions to connect to an in-cluster che-mcp-server without manual port-forwarding.
  • Add publish-npm.yml — GitHub Actions workflow that publishes to npm on GitHub Release (with provenance).
  • Add che-mcp-bridge bin entry so users can run via npx che-mcp-server che-mcp-bridge.
  • Update README with local connection instructions.
  • Set version to 0.0.1 for initial publish.

How it works

The bridge is a single-file Node.js script (CJS, zero dependencies) that:

  1. Reads namespace from current oc context
  2. Spawns oc port-forward svc/che-mcp-server <ephemeral-port>:8080
  3. Translates stdio JSON-RPC ↔ HTTP (Streamable HTTP with SSE responses)
  4. Auto-restarts port-forward on failure (max 5 retries)
  5. Claude Code manages the process lifecycle (stdio transport)

Usage (after npm publish)

claude mcp add --transport stdio che-mcp -- npx che-mcp-server che-mcp-bridge

Setup required for first publish

  1. Create an npm access token and add as NPM_TOKEN secret in the repo
  2. Create a GitHub Release (e.g., v0.0.1) — the workflow triggers automatically

Test plan

  • Smoke test: echo '{"jsonrpc":"2.0","method":"initialize","id":1,...}' | node stdio-bridge.cjs returns valid MCP response
  • Multi-request: initialize + tools/list both return correct responses
  • Port-forward auto-connects to cluster service
  • npm publish via GitHub Release (needs NPM_TOKEN secret)

Summary by CodeRabbit

  • New Features

    • Added a local bridge for connecting to a remote cluster from stdio-based clients.
    • Added a package publish workflow for automated npm releases.
  • Documentation

    • Expanded setup instructions for local connections to a remote cluster, including example configuration and environment variables.
  • Chores

    • Updated package metadata to include the new CLI entry and bundled files.

- Add stdio-bridge.cjs: a stdio MCP proxy that manages oc port-forward
  internally, enabling local Claude Code sessions to connect to an
  in-cluster che-mcp-server without manual port-forwarding
- Add publish-npm.yml: GitHub Actions workflow that publishes to npm
  on GitHub Release with provenance
- Add che-mcp-bridge bin entry to package.json
- Update README with local connection instructions via npx
- Set version to 0.0.1

Usage after publish:
  claude mcp add --transport stdio che-mcp -- npx che-mcp-server che-mcp-bridge

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Oleksii Kurinnyi <okurinny@redhat.com>
@akurinnoy
akurinnoy requested a review from tolusha as a code owner July 9, 2026 15:29
@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@akurinnoy, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 41 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 776679a1-797e-49aa-9a05-36275b29d8c1

📥 Commits

Reviewing files that changed from the base of the PR and between bff0abf and 92b257d.

📒 Files selected for processing (3)
  • .github/workflows/publish-npm.yml
  • README.md
  • stdio-bridge.cjs
📝 Walkthrough

Walkthrough

Adds a Node.js stdio-to-HTTP bridge script (stdio-bridge.cjs) that manages oc port-forward and relays JSON-RPC/SSE messages, registers it as a new CLI bin and packaged file, updates package version, documents its usage in README, and introduces a GitHub Actions workflow publishing the package to npm on release.

Changes

Stdio Bridge Feature

Layer / File(s) Summary
Bridge entrypoint and port-forward management
stdio-bridge.cjs
Sets up config/env defaults, detects namespace via oc, finds a free local port, and spawns/monitors oc port-forward with auto-restart on failure.
Request forwarding and stdio loop
stdio-bridge.cjs
Forwards JSON-RPC messages via HTTP POST to `/mcp`, tracks session headers, parses JSON and SSE responses, drives the stdin read/write loop, and handles shutdown signals.
CLI registration, packaging, and docs
package.json, README.md
Adds `che-mcp-bridge` bin entry, includes `stdio-bridge.cjs` in published files, bumps version to 0.0.1, and documents local-to-remote connection setup with environment variables.

NPM Publish Workflow

Layer / File(s) Summary
Publish workflow definition
.github/workflows/publish-npm.yml
Adds a workflow triggered on published releases that checks out code, sets up Node 22, installs deps, builds, tests, and publishes to npm with provenance using `NPM_TOKEN`.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client as MCP Client
  participant Bridge as stdio-bridge.cjs
  participant OC as oc port-forward
  participant Service as MCP Service (K8s)

  Bridge->>OC: spawn oc port-forward (namespace, service, port)
  OC->>Service: forward local port to service port
  Bridge->>Bridge: wait for local port readiness
  Client->>Bridge: JSON-RPC message via stdin
  Bridge->>Service: POST /mcp (with session header)
  Service-->>Bridge: JSON or SSE response
  Bridge->>Client: write response to stdout
  OC--)Bridge: unexpected exit
  Bridge->>OC: restart port-forward (up to MAX_RESTARTS)
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main changes: a stdio bridge and an npm publish workflow.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/npm-publish-and-stdio-bridge

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown

Image built: quay.io/che-incubator/che-mcp-server:pr-19

@akurinnoy

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (2)
.github/workflows/publish-npm.yml (2)

14-14: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Set persist-credentials: false on checkout to prevent token persistence.

actions/checkout@v4 defaults to persisting the GITHUB_TOKEN into the local git config. While this workflow doesn't perform git pushes, disabling credential persistence is a supply-chain hardening best practice that prevents token leakage through cached artifacts or compromised dependencies.

🔒️ Proposed hardening
       - uses: actions/checkout@v4
+        with:
+          persist-credentials: false
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/publish-npm.yml at line 14, The checkout step in the
publish workflow is persisting the GITHUB_TOKEN by default, so update the
actions/checkout@v4 usage to disable credential persistence. Add
persist-credentials: false to the checkout step in the workflow so the
repository is still fetched normally but the token is not stored in local git
config.

Source: Linters/SAST tools


24-31: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Build runs twice due to prepublishOnly hook.

The explicit npm run build step at line 25 and the prepublishOnly hook (which also runs npm run build) both execute the build, doubling CI time for this step. Either remove the explicit build step (relying on the hook) or pass --ignore-scripts to npm publish and keep the explicit build. Removing the explicit step is simpler since prepublishOnly guarantees a build before publish.

♻️ Remove redundant build step
       - run: npm ci
 
-      - name: Build
-        run: npm run build
-
       - name: Run tests
         run: npm test
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/publish-npm.yml around lines 24 - 31, The publish workflow
is building the package twice because the explicit Build step and the package’s
prepublishOnly hook both run npm run build. Update the publish job in
publish-npm.yml by removing the standalone build step and letting npm publish
invoke prepublishOnly, or alternatively keep the build step and add
--ignore-scripts to the npm publish command; the simpler fix is to remove the
redundant Build step and leave Run tests and Publish intact.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@README.md`:
- Around line 26-33: The README’s npx example is invoking the package entrypoint
instead of the che-mcp-bridge bin, so update the “Via npx” command to use npx
with -p che-mcp-server and then call che-mcp-bridge directly. Keep the
global-install example unchanged, and make sure the surrounding setup text in
README clearly distinguishes the npx path from the globally installed bin path.

In `@stdio-bridge.cjs`:
- Around line 31-37: The fallback namespace in detectNamespace is hardcoded to a
personal value, which will be published publicly; remove that default and
replace it with a safe generic fallback or explicit failure path when oc is
unavailable or misconfigured. Update detectNamespace so it either returns the
detected project namespace from execFileSync('oc', ['project', '-q'], ...) or
handles the error without leaking a user-specific namespace, keeping the
behavior in stdio-bridge.cjs generic for all consumers.
- Around line 169-193: The queue drain logic in drain() and rl.on('close') never
exits after stdin has closed and the pending queue is fully processed. Track the
stdin-closed state in the bridge, and when drain() reaches an empty queue after
close, call cleanup() (or equivalent shutdown logic) instead of only setting
processing = false. Make sure the close handler and processLine()/drain() paths
both use the same completion check so the process exits once all queued items
are handled.
- Around line 106-153: The forwardRequest HTTP call in stdio-bridge.cjs can hang
forever because it has no timeout, causing queued stdin lines to stall. Add a
30s timeout to the http.request in forwardRequest, and make sure the timeout
path aborts/destroys the request and rejects or otherwise resolves the promise
cleanly so the bridge can continue processing. Use the existing req/res handling
around req.on('error'), res.on('data'), and res.on('end') to locate the change.
- Around line 179-186: The stdin bridge in processLine should not let JSON.parse
failures escape, because malformed input currently drops the request without any
JSON-RPC response. Update processLine in stdio-bridge.cjs to catch parse errors
around JSON.parse(line) and emit a proper error response for that input before
returning, while keeping the existing forwardRequest and process.stdout.write
flow for valid messages.
- Around line 116-137: The SSE handling in the response parsing path resolves on
the first data event and destroys the stream, so it can drop later events from
the same request. Update the event processing in stdio-bridge.cjs to keep
consuming the full SSE stream, collect each data: payload, and only resolve with
the final JSON-RPC response rather than the first notification. Make the change
in the text/event-stream branch around the res.on('data') logic and the
resolved/res.destroy flow so the parser does not terminate early.

---

Nitpick comments:
In @.github/workflows/publish-npm.yml:
- Line 14: The checkout step in the publish workflow is persisting the
GITHUB_TOKEN by default, so update the actions/checkout@v4 usage to disable
credential persistence. Add persist-credentials: false to the checkout step in
the workflow so the repository is still fetched normally but the token is not
stored in local git config.
- Around line 24-31: The publish workflow is building the package twice because
the explicit Build step and the package’s prepublishOnly hook both run npm run
build. Update the publish job in publish-npm.yml by removing the standalone
build step and letting npm publish invoke prepublishOnly, or alternatively keep
the build step and add --ignore-scripts to the npm publish command; the simpler
fix is to remove the redundant Build step and leave Run tests and Publish
intact.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7d3d94f7-d998-49c9-81c2-b163f1971766

📥 Commits

Reviewing files that changed from the base of the PR and between a123abd and bff0abf.

📒 Files selected for processing (4)
  • .github/workflows/publish-npm.yml
  • README.md
  • package.json
  • stdio-bridge.cjs

Comment thread README.md
Comment thread stdio-bridge.cjs
Comment thread stdio-bridge.cjs
Comment thread stdio-bridge.cjs
Comment thread stdio-bridge.cjs
Comment thread stdio-bridge.cjs
- Remove hardcoded personal namespace fallback; exit with clear
  error message when oc context is unavailable
- Add 30s timeout on HTTP forwarding requests
- Fix SSE parser to collect all events and resolve with the last
  response instead of the first (handles notifications before final)
- Fix process hang after stdin close with pending queue items
- Add JSON.parse error handling for malformed stdin input
- Fix npx command in README: use -p flag to specify package
- Add persist-credentials: false to checkout step (hardening)
- Remove redundant build step (prepublishOnly handles it)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Oleksii Kurinnyi <okurinny@redhat.com>
@akurinnoy

Copy link
Copy Markdown
Contributor Author

All 6 actionable findings and 2 nitpicks addressed in 92b257d:

Inline findings (6):

  • ✅ npx command fixed (npx -p che-mcp-server che-mcp-bridge)
  • ✅ Hardcoded namespace removed (exits with error if oc unavailable)
  • ✅ HTTP request timeout added (30s)
  • ✅ SSE parser collects all events, resolves with last response
  • ✅ stdin close + queue drain exits cleanly
  • ✅ JSON.parse wrapped in try/catch

Nitpicks (2):

  • persist-credentials: false added to checkout
  • ✅ Redundant build step removed (prepublishOnly handles it)

@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown

Image built: quay.io/che-incubator/che-mcp-server:pr-19

@akurinnoy
akurinnoy merged commit 5ee4daf into main Jul 9, 2026
3 checks passed
@akurinnoy
akurinnoy deleted the feat/npm-publish-and-stdio-bridge branch July 9, 2026 16:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant