Skip to content

Multi-transport MCP chaining and hosted MCP package#17

Merged
hifi-phil merged 25 commits intodevfrom
feature/multi-transport-mcp-chaining
Mar 24, 2026
Merged

Multi-transport MCP chaining and hosted MCP package#17
hifi-phil merged 25 commits intodevfrom
feature/multi-transport-mcp-chaining

Conversation

@hifi-phil
Copy link
Copy Markdown
Contributor

Summary

  • Hosted MCP package (packages/hosted-mcp/): New package for building Cloudflare Worker-hosted MCP servers with OAuth authorization, consent screens, multi-site support, and token storage
  • Multi-transport MCP chaining: registerChainedTools helper supporting stdio and in-process transports to proxy tools from other MCP servers
  • SDK improvements: Migrated from axios to native fetch, added readOnlyHint annotation filtering, in-process MCP connections, and stdio connection support
  • Template updates: Added worker entry point, tunnel support, get-server-info tool, and hosted E2E test infrastructure
  • New skills: add-tool, add-test, and add-eval Claude Code skills for scaffolding
  • Test infrastructure: Integration and E2E tests for hosted MCP, chained MCP, and a test Umbraco instance
  • Docs cleanup: Removed docs now covered by UmbracoDocs, reorganised plans

Test plan

  • Review hosted MCP package structure and OAuth flow
  • Review multi-transport chaining implementation
  • Review fetch migration in SDK
  • Run npm run build && npm run test to verify everything builds and passes
  • Review E2E test coverage for hosted and chained scenarios

🤖 Generated with Claude Code

hifi-phil and others added 25 commits February 26, 2026 07:56
Introduces `@umbraco-cms/mcp-hosted` — building blocks for deploying
Umbraco MCP servers to Cloudflare Workers with OAuth authentication
and Streamable HTTP transport.

Key components:
- OAuth Third-Party Authorization Flow (MCP spec compliant)
  - /authorize route with per-client consent screen
  - /callback completing authorization via OAUTH_PROVIDER.completeAuthorization()
  - Full OAuthAuthRequest stored in KV for round-trip integrity
- Per-request McpServer factory (MCP SDK 1.26.0+ requirement)
- fetch-based API client replacing Axios for Workers runtime
- Worker config loader for env bindings
- UMBRACO_SERVER_URL env var for self-signed cert workaround in local dev
- OAuthAuthRequest/OAuthProviderHelpers type interfaces (avoids Wrangler virtual module dependency)

Template updates:
- Worker entry using McpAgent.serve() for Streamable HTTP
- wrangler.toml with new_sqlite_classes for agents library
- client-fetch adapter for hosted fetch client

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…t support

Enable Orval-generated API clients in Cloudflare Workers by adding
setCustomTransport() to UmbracoManagementClient, which replaces Axios
with a fetch-based transport at runtime. Add fetchCurrentUser() to
load the authenticated user's permissions for per-user tool filtering.
Switch OAuth client from confidential to public (PKCE provides
sufficient security), making client_secret optional throughout.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…iltering

SDK: Add `readOnly` field to CollectionConfiguration that filters tools
by their `annotations.readOnlyHint` or deprecated `isReadOnly` property,
replacing the previous approach of expanding readOnly into excludeSlices.
This runs as step 0 in shouldIncludeTool (before all other checks).

Hosted MCP: Add slice checkboxes to the consent screen so users can
toggle individual operation types (read, create, update, etc.). Slice
selections narrow the admin config via includeSlices intersection.
Move hosted-mcp README from docs/ to package root.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Includes token-storage KV helpers, multi-site type definitions,
fetch client token refresh, updated exports, jest config for
hosted-mcp project, and comprehensive documentation covering
architecture, auth internals, deployment, security, customization,
multi-site, troubleshooting, and future roadmap items.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… get-server-info tool

- Add /info diagnostic endpoint to hosted-mcp (gated behind ENABLE_INFO_ENDPOINT env var)
- Add 19 integration tests using Jest + unstable_dev (landing page, OAuth discovery,
  consent screen, MCP protocol, info endpoint)
- Add 5 E2E acceptance tests using Playwright against real Umbraco (OAuth flow,
  authenticated MCP calls including real API tool execution, MCP Inspector visual test)
- Add get-server-info tool that calls Umbraco Management API to prove full auth chain
- Add minimal Umbraco 17 test instance (SQLite, unattended install, OAuth client registration)
- Add wrangler.integration.toml and .dev.vars.integration for test Worker config

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
These tests validate the hosted-mcp platform (OAuth flow, consent screen,
MCP protocol), not the user's project, so they don't belong in the
starter kit. Test scripts moved to root package.json; template gets a
.dev.vars.example for discoverability.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Always set prompt=login on every Umbraco authorization redirect,
removing the conditional showLoginToggle/reauth machinery. This
forces the login form on every connection, allowing users to switch
accounts between MCP sessions without manual logout.

E2E tests rewritten with consent tool selection coverage:
- Mode filtering (single mode, exclude modes)
- Slice filtering (single slice, multiple slices)
- ReadOnly toggle
- Cross-filter combinations (mode+slice, mode+readOnly, triple)
- Deny consent flow
- Tool call execution after filtering

Also fixes E2E test performance (removed unnecessary 15s/10s waits)
and suppresses wrangler 401 warnings via logLevel: "error".

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…vements

- Add scripts/tunnels.sh for Cloudflare tunnel testing with remote MCP clients
- Add umbraco/McpOAuthComposer.cs and ProgramSnippet.cs for OAuth setup
- Auto-copy McpOAuthComposer.cs and patch Program.cs during init
- Add x-forwarded-proto rewriting in createWorkerExport for tunnel support
- Add two-column grid layout for consent screen tool modes
- Collapse collection lists under mode checkboxes (show/hide on toggle)
- Add reauth/logout flow with PostLogoutRedirectUris and EndSession permission
- Add local-dev-setup.md docs, update README with new template files
- Update tests for new template files and patchProgramCs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Restore blue header with Umbraco logo on consent screen, lay out
info fields in a 2-column grid, and display operations in a 5-column
grid. Add future planning doc for chained MCP consent scenarios.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
McpClientManager now supports two transport types via a discriminated
union config. Stdio transport (default) spawns child processes as before.
In-process transport calls tool handlers directly, enabling MCP chaining
in environments without node:child_process (e.g. Cloudflare Workers).

- Extract StdioConnection from manager.ts (dynamic import)
- Add InProcessConnection with collection filtering and Zod→JSON Schema
- Add McpConnection interface abstracting both transports
- Make @modelcontextprotocol/sdk external in tsup to avoid bundling stdio
- Update mcp-chaining docs for both transports
- Add SDK docs (api-helpers, configuration, constants, testing, etc.)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New skills for incrementally adding tools, integration tests, and eval
tests to existing collections. Each skill delegates template ownership
to its respective agent rather than duplicating inline.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace $(npm root) with node_modules/ in jest paths — shell command
substitution doesn't work on Windows cmd.exe or PowerShell.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract registerChainedTools() to reduce ~60 lines of chaining boilerplate
per worker. Add agents-mcp.d.ts ambient types to hosted-mcp package.
Replace Axios with fetch-based client in SDK. Update template to delegate
to SDK's UmbracoManagementClient. Add chained MCP e2e test suite.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move inspector lifecycle, OAuth flow, tool listing, and tool execution
helpers from three duplicate inspector-setup files into a shared /testing
export. Lazy-load yargs in the SDK config module to prevent it from
crashing in Cloudflare Worker builds where import.meta.url is undefined.
Add example E2E test suite to the template.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Delete SDK and hosted-mcp docs that are now in the official Umbraco
documentation site. Move remaining planning docs into docs/plans/
grouped by package (hosted-mcp, create-mcp-server, monorepo).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Split SDK tests so stdio-based MCP client tests run sequentially
  (--runInBand) to avoid timeout under parallel Jest workers
- Document testing gotchas in CLAUDE.md: integration tests, evals,
  self-signed certs, stale workerd processes
- Auto-set npm latest tag for prerelease versions when no stable
  release exists, fixing beta.1 stuck as default

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
The template uses file: references to sibling monorepo packages which
break when the template is copied as a starter kit for new projects.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The template package.json correctly uses file: references for the
monorepo workspace. The create-mcp-server scaffold tool rewrites these
to published versions when creating new projects, but was missing the
rewrite for @umbraco-cms/mcp-hosted.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Playwright's test-results/ directory is a local artifact that shouldn't
be included when copying or scaffolding the template. Without this
exclusion, CI fails because the snapshot includes the file but clean
checkouts don't have it.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@hifi-phil hifi-phil merged commit a6ca514 into dev Mar 24, 2026
3 checks passed
@hifi-phil hifi-phil deleted the feature/multi-transport-mcp-chaining branch April 27, 2026 09:39
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