Skip to content

Implement MCP HTTP transport (v0.1.0)#1

Merged
eskp merged 5 commits into
mainfrom
feat/mcp-transport-v0.1.0
Jun 2, 2026
Merged

Implement MCP HTTP transport (v0.1.0)#1
eskp merged 5 commits into
mainfrom
feat/mcp-transport-v0.1.0

Conversation

@Bleyle823

@Bleyle823 Bleyle823 commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Implement the shared KeeperHub MCP HTTP kernel in both TypeScript (@keeperhub/mcp-client) and Python (keeperhub-mcp-client).
  • TypeScript: KeeperHubMcpClient with lazy session bootstrap, ools/call, automatic re-init on 401/404, API key resolution (KH_API_KEY / KEEPERHUB_API_KEY), and kh_ vs wfb_ key classification
  • Python: equivalent client using httpx (replaces scaffold mcp SDK dependency), plus matching key helpers
  • Add unit tests: 12 Vitest tests (TS) and 4 pytest tests (Python)
  • Bump both packages to 0.1.0 and update root/package READMEs for first publish
  • Remove unused @modelcontextprotocol/sdk dependency from TS package; use direct HTTP transport instead
  • Add prepublishOnly build hook for npm publish from packages/mcp-client

Test plan

  • pnpm --filter @keeperhub/mcp-client build succeeds
  • pnpm --filter @keeperhub/mcp-client test - 12 tests pass
  • python -m pytest python/tests/ - 4 tests pass
  • Maintainer bootstrap publish to npm (@keeperhub/mcp-client@0.1.0) - first publish must be manual before Trusted Publisher works
  • Tag
    pm-v0.1.0 to trigger release workflow after npm bootstrap
  • Tag py-v0.1.0 to trigger PyPI trusted publishing

Notes

  • Publish npm from packages/mcp-client/ only (not repo root)
  • Framework plugins (Eliza, OpenClaw, Hermes) remain in their respective ecosystems and will depend on these packages once published

Bleyle823 and others added 2 commits June 1, 2026 07:10
Port the shared KeeperHub MCP kernel from the plugins monorepo: session bootstrap, tools/call, 401/404 re-init, API key helpers, and unit tests. Bump both packages to 0.1.0 and update docs for first npm/PyPI release.

Co-authored-by: Cursor <cursoragent@cursor.com>
Run TS build/test/type-check and Python pytest on PRs and main. Add npm keywords and a root test:python script for local verification.

Co-authored-by: Cursor <cursoragent@cursor.com>
@Bleyle823

Bleyle823 commented Jun 1, 2026

Copy link
Copy Markdown
Contributor Author

For maintainers - post-merge release checklist

This PR implements v0.1.0 of both clients and is ready for review/merge. After merge:

npm (@keeperhub/mcp-client)

  1. Bootstrap publish manually once (Trusted Publisher requires an existing package):
    �ash cd packages/mcp-client npm run build npm publish
  2. On npmjs.com ? @keeperhub/mcp-client ? Settings ? Trusted Publisher ? GitHub Actions (KeeperHub/mcp-client, workflow
    elease-npm.yml)

CI

  • Added .github/workflows/ci.yml - runs TS build/test/type-check + Python pytest (3.9 & 3.12) on PRs and main

Verified locally

  • 12 Vitest tests pass
  • 4 pytest tests pass

Co-authored-by: Cursor <cursoragent@cursor.com>
@Bleyle823 Bleyle823 requested a review from eskp June 1, 2026 05:53
- Replace the abbreviated 19-line LICENSE stub with the full Apache-2.0
  text (root and packages/mcp-client) so GitHub and license scanners
  detect Apache-2.0 instead of Other, and the npm tarball ships the
  complete license.
- Cap postMcp session re-init at a single retry to prevent unbounded
  recursion / a request storm against a persistently 401/404 endpoint.
- Add regression tests for persistent 401 and persistent session-404.
- Remove the non-existent Poll-to-terminal helper claim from the root
  README.
@eskp

eskp commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Pre-publish review + fixes (pushed as 31335f4)

Reviewed the package end-to-end for the first npm publish. The TS package builds clean, npm pack ships the right 9 files, publishConfig.access: public is set, and tests pass. Three publish-blocking items were found and fixed on this branch:

  1. LICENSE was a 19-line stub, not Apache-2.0. Replaced both the root and packages/mcp-client/LICENSE with the full Apache-2.0 text (Copyright 2026 KeeperHub). GitHub now detects Apache-2.0 instead of "Other", and the npm tarball ships the complete license (806 B -> 11.3 kB).
  2. postMcp re-init had no retry cap -> a persistently 401/404 endpoint caused unbounded recursion / a request storm. Capped at a single re-init retry, then it throws. Added regression tests for persistent 401 and persistent session-404 (test count 12 -> 14, all green).
  3. Root README advertised a "Poll-to-terminal helper" that exists in neither client. Removed.

Deferred to a Python 0.1.1 follow-up (not in this PR)

keeperhub-mcp-client 0.1.0 is already live on PyPI and byte-identical to this branch, so PyPI will reject re-publishing 0.1.0. To avoid diverging the repo from the published 0.1.0, these Python parity items are intentionally left for a separate 0.1.1 PR:

  • add a py.typed marker (package is fully typed but ships as untyped per PEP 561)
  • bundle LICENSE into the sdist/wheel (license-files in pyproject.toml)
  • apply the same re-init retry cap (the recursion bug exists in client.py too)

Publish runbook

  • npm (first publish is manual): npm trusted publishing can't bootstrap a package that doesn't exist yet, so a maintainer runs cd packages/mcp-client && npm publish once (scoped-public access comes from publishConfig). Then add the Trusted Publisher on npmjs.com (org KeeperHub, repo mcp-client, workflow release-npm.yml, no environment). After that, pushing an npm-v* tag publishes future versions via OIDC.
  • PyPI: the release-pypi.yml header says "add a pending publisher", but the project already exists, so configure a regular Trusted Publisher on the existing project + create the pypi GitHub Environment. Add skip-existing: true (or never re-tag a published version) since the workflow has no duplicate-version guard.
  • Contributor flow: merging a version-bump PR does not auto-publish; a maintainer still pushes the npm-v* / py-v* tag (or runs the workflow_dispatch). A short CONTRIBUTING/RELEASING note documenting this would help.

…lic API

- Add import/require-specific "types" to the exports map so node16/nodenext
  CommonJS consumers resolve dist/index.d.cts instead of the ESM
  dist/index.d.ts (was TS1479 'cannot be imported with require').
- Remove __resetClientForTests from the package entrypoint; it stays an
  internal seam imported directly from ./client by the test suite.
@eskp

eskp commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Follow-up polish (pushed as 682bb5a)

Second-pass review (verified against a packed-tgz consumer) found two cheap items worth fixing before the first public release; both done:

  1. exports map now has per-condition types. The single top-level types meant node16/nodenext CommonJS consumers resolved the ESM dist/index.d.ts for a require and hit TS1479. Now import -> index.d.ts and require -> index.d.cts. Verified: a nodenext + commonjs consumer importing from the packed tarball type-checks clean (previously errored).
  2. Removed __resetClientForTests from the package entrypoint. It was leaking into the public API and dist/index.d.ts; it stays an internal seam imported directly from ./client by the test suite.

Build + type-check clean, 14/14 tests pass, public export surface no longer exposes the test hook. CI green on 682bb5a.

Remaining non-blocking items (getClient option-staleness on cached key, default console logger noise, inlined sourcemaps) are documented for a future pass and do not block 0.1.0.

@eskp eskp merged commit 5f82b45 into main Jun 2, 2026
3 checks passed
@eskp eskp deleted the feat/mcp-transport-v0.1.0 branch June 2, 2026 21:21
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.

2 participants