Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
89bc6d8
feat: add Ruby server SDK
idosal Jul 10, 2025
f5c59b1
fix build
idosal Jul 14, 2025
12c4810
production-ready Ruby
idosal Jul 14, 2025
ad8b7f8
trailing spaces
idosal Jul 14, 2025
6d460e3
feat(ruby): address code review suggestions
idosal Jul 14, 2025
2089ccb
fix installation instructions
idosal Jul 14, 2025
6b03f0a
fix ci
idosal Jul 14, 2025
786002c
use symbols for delivery
idosal Jul 14, 2025
a9d2af5
improve Ruby SDK
idosal Jul 14, 2025
bc87f54
remove branch
idosal Jul 14, 2025
8befd28
docs: add ruby sdk documentation and update links
idosal Jul 14, 2025
d7b0632
change flavor to symbol
idosal Jul 14, 2025
9bd6184
fix docs
idosal Jul 14, 2025
9b2ca48
readmes
idosal Jul 14, 2025
d0140f8
fix casing
idosal Jul 14, 2025
13b547b
fix ci typescript
idosal Jul 14, 2025
8cbfc6a
make flavor mandatory
idosal Jul 14, 2025
b8ae4c6
add tests
idosal Jul 14, 2025
11fd2bc
prettier
idosal Jul 14, 2025
7de2b07
fix tests
idosal Jul 14, 2025
f4c75aa
fix ruby mime
idosal Jul 14, 2025
4401e88
crr
idosal Jul 14, 2025
9e29a02
remove example test
idosal Jul 14, 2025
84500a7
fix ci
idosal Jul 14, 2025
71c1c2a
fix build
idosal Jul 15, 2025
a8eeab3
Merge remote-tracking branch 'origin/main' into feat/ruby
idosal Jul 15, 2025
ff5e0e2
lint
idosal Jul 15, 2025
954ede5
consolidate semver
idosal Jul 15, 2025
fc4c2b8
feat: add Ruby server SDK
idosal Jul 10, 2025
cd769bc
fix build
idosal Jul 14, 2025
30e634f
production-ready Ruby
idosal Jul 14, 2025
78fb1a2
trailing spaces
idosal Jul 14, 2025
d864cd1
feat(ruby): address code review suggestions
idosal Jul 14, 2025
d66af97
fix installation instructions
idosal Jul 14, 2025
0692f35
fix ci
idosal Jul 14, 2025
8cf24b9
use symbols for delivery
idosal Jul 14, 2025
9c3ac5a
improve Ruby SDK
idosal Jul 14, 2025
218ae75
remove branch
idosal Jul 14, 2025
5b77af0
docs: add ruby sdk documentation and update links
idosal Jul 14, 2025
e954b5e
change flavor to symbol
idosal Jul 14, 2025
5aa44cb
fix docs
idosal Jul 14, 2025
752f950
readmes
idosal Jul 14, 2025
e3ac4f3
fix casing
idosal Jul 14, 2025
409fea1
fix ci typescript
idosal Jul 14, 2025
6d79525
make flavor mandatory
idosal Jul 14, 2025
4d73a69
add tests
idosal Jul 14, 2025
70f1334
prettier
idosal Jul 14, 2025
23fba9b
fix tests
idosal Jul 14, 2025
5a92c34
fix ruby mime
idosal Jul 14, 2025
79b8685
crr
idosal Jul 14, 2025
0b11f1b
remove example test
idosal Jul 14, 2025
47113d4
fix ci
idosal Jul 14, 2025
068398d
fix build
idosal Jul 15, 2025
2c875b6
lint
idosal Jul 15, 2025
05934b5
consolidate semver
idosal Jul 15, 2025
d760384
fix release
idosal Jul 16, 2025
ec5260f
Merge branch 'feat/ruby' of https://github.com/idosal/mcp-ui into fea…
idosal Jul 16, 2025
71f0a6b
Merge remote-tracking branch 'origin/main' into feat/ruby
idosal Jul 18, 2025
8e525a4
update Ruby files
idosal Jul 18, 2025
28f3afa
fix docs
idosal Jul 18, 2025
f8ffd6a
fix lock
idosal Jul 18, 2025
5ebecc1
fix ruby release
idosal Jul 18, 2025
f302168
restore empty url check
idosal Jul 18, 2025
9bb850a
revert changelog changes
idosal Jul 18, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ dist
coverage
*.log
**/*.js
packages/client/src/remote-dom/iframe-bundle.ts
sdks/typescript/client/src/remote-dom/iframe-bundle.ts

examples
178 changes: 134 additions & 44 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,48 @@ on:
pull_request:
branches:
- main
release:
types: [published]

jobs:
build_lint_test:
filter_changed_paths:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [22.x]
outputs:
ts_client_files: ${{ steps.filter.outputs.ts_client_files }}
ts_server_files: ${{ steps.filter.outputs.ts_server_files }}
ruby_sdk_files: ${{ steps.filter.outputs.ruby_sdk_files }}
example_files: ${{ steps.filter.outputs.example_files }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- uses: actions/checkout@v4
- uses: dorny/paths-filter@v2
id: filter
with:
filters: |
ts_client_files:
- 'sdks/typescript/client/**'
ts_server_files:
- 'sdks/typescript/server/**'
ruby_sdk_files:
- 'sdks/ruby/**'
example_files:
- 'examples/**'

js_build_and_test:
needs: filter_changed_paths
if: needs.filter_changed_paths.outputs.ts_client_files == 'true' || needs.filter_changed_paths.outputs.ts_server_files == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: 10

- name: Setup Node.js ${{ matrix.node-version }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
node-version: 22.x
cache: 'pnpm'

- name: Install dependencies
Expand All @@ -36,30 +58,17 @@ jobs:
run: pnpm lint

- name: Test
run: pnpm test

- name: Build libraries (excluding docs)
run: pnpm --filter=!@mcp-ui/docs build
run: pnpm test:ts

- name: Build docs
if: matrix.node-version == '20.x' # Build docs only on one Node version to save time
run: pnpm --filter=@mcp-ui/docs build
- name: Build
run: pnpm build

publish:
needs: build_lint_test
ruby_sdk_test:
needs: filter_changed_paths
if: needs.filter_changed_paths.outputs.ruby_sdk_files == 'true'
runs-on: ubuntu-latest
# Run on pushes to the main branch. semantic-release will determine if a release is needed.
if: github.event_name == 'push' && github.ref == 'refs/heads/main' && !startsWith(github.head_commit.message, 'chore(release):') && !(contains(join(github.event.commits.*.files_changed, ','), 'examples/') || contains(join(github.event.commits.*.files_changed, ','), 'docs/'))
permissions:
contents: write # Needed to push new version tags, commit changelog/package.json updates
issues: write # Needed to create/comment on release-related issues (optional, but good practice)
id-token: write # Required for publishing to NPM with OIDC
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
# Fetch all history for all tags and branches so semantic-release can analyze commits
fetch-depth: 0
- uses: actions/checkout@v4

- name: Setup pnpm
uses: pnpm/action-setup@v2
Expand All @@ -69,29 +78,110 @@ jobs:
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22.x # Use a Node version compatible with semantic-release
node-version: 22.x
cache: 'pnpm'

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Build all packages
run: pnpm --filter="./packages/*" build
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: '3.2'
bundler: latest
bundler-cache: true
working-directory: 'sdks/ruby'

- name: List contents of client dist
run: |
echo "--- Listing packages/client/dist ---"
ls -R packages/client/dist || echo "packages/client/dist not found or empty"
echo "--- End of packages/client/dist ---"
- name: Lint
run: bundle exec rubocop
working-directory: 'sdks/ruby'

- name: List contents of server dist
run: |
echo "--- Listing packages/server/dist ---"
ls -R packages/server/dist || echo "packages/server/dist not found or empty"
echo "--- End of packages/server/dist ---"
- name: Run tests
run: pnpm test:ruby

release_ts_client:
needs: [js_build_and_test]
if: github.ref == 'refs/heads/main' && needs.filter_changed_paths.outputs.ts_client_files == 'true'
runs-on: ubuntu-latest
permissions:
contents: write
issues: write
id-token: write
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 0 }
- name: Setup pnpm
uses: pnpm/action-setup@v2
with: { version: 10 }
- name: Setup Node.js
uses: actions/setup-node@v4
with: { node-version: 22.x, cache: 'pnpm' }
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Release
working-directory: sdks/typescript/client
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
run: npx semantic-release

- name: Semantic Release
release_ts_server:
needs: [js_build_and_test]
if: github.ref == 'refs/heads/main' && needs.filter_changed_paths.outputs.ts_server_files == 'true'
runs-on: ubuntu-latest
permissions:
contents: write
issues: write
id-token: write
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 0 }
- name: Setup pnpm
uses: pnpm/action-setup@v2
with: { version: 10 }
- name: Setup Node.js
uses: actions/setup-node@v4
with: { node-version: 22.x, cache: 'pnpm' }
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Release
working-directory: sdks/typescript/server
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Provided by Actions, used by @semantic-release/github and @semantic-release/git
NPM_TOKEN: ${{ secrets.NPM_TOKEN }} # Your NPM token, used by @semantic-release/npm
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
run: npx semantic-release

release_ruby_sdk:
name: Release Ruby SDK
needs: [ruby_sdk_test]
if: github.ref == 'refs/heads/main' && needs.filter_changed_paths.outputs.ruby_sdk_files == 'true'
runs-on: ubuntu-latest
environment: release
permissions:
contents: write # to push commits and tags
id-token: write # for trusted publishing
issues: write # to comment on issues
pull-requests: write # to comment on pull requests
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 0 }
- name: Setup pnpm
uses: pnpm/action-setup@v2
with: { version: 10 }
- name: Setup Node.js
uses: actions/setup-node@v4
with: { node-version: 22.x, cache: 'pnpm' }
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: '3.2'
bundler: latest
bundler-cache: true
working-directory: sdks/ruby
- name: Release
working-directory: sdks/ruby
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: npx semantic-release
8 changes: 4 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -132,10 +132,10 @@ docs/src/.vitepress/dist
docs/src/.vitepress/cache

# Monorepo specific
/packages/**/dist
/packages/**/coverage
/apps/**/dist
/apps/**/coverage
/sdks/**/dist
/sdks/**/coverage
/examples/**/dist
/examples/**/coverage

# OS generated files #
######################
Expand Down
8 changes: 4 additions & 4 deletions .releaserc.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@
[
"@semantic-release/npm",
{
"pkgRoot": "packages/client",
"pkgRoot": "sdks/typescript/client",
"npmPublish": true
}
],
[
"@semantic-release/npm",
{
"pkgRoot": "packages/server",
"pkgRoot": "sdks/typescript/server",
"npmPublish": true
}
],
Expand All @@ -36,8 +36,8 @@
"assets": [
"CHANGELOG.md",
"package.json",
"packages/client/package.json",
"packages/server/package.json",
"sdks/typescript/client/package.json",
"sdks/typescript/server/package.json",
"pnpm-lock.yaml"
],
"message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
Expand Down
1 change: 1 addition & 0 deletions .ruby-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.2.2
64 changes: 57 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<p align="center">
<a href="https://www.npmjs.com/package/@mcp-ui/server"><img src="https://img.shields.io/npm/v/@mcp-ui/server?label=server&color=green" alt="Server Version"></a>
<a href="https://www.npmjs.com/package/@mcp-ui/client"><img src="https://img.shields.io/npm/v/@mcp-ui/client?label=client&color=blue" alt="Client Version"></a>
<a href="https://rubygems.org/gems/mcp_ui_server"><img src="https://img.shields.io/gem/v/mcp_ui_server?label=ruby-server&color=red" alt="Ruby Server SDK Version"></a>
<a href="https://gitmcp.io/idosal/mcp-ui"><img src="https://img.shields.io/endpoint?url=https://gitmcp.io/badge/idosal/mcp-ui" alt="MCP Documentation"></a>
</p>

Expand Down Expand Up @@ -34,10 +35,11 @@

## 💡 What's `mcp-ui`?

`mcp-ui` is a TypeScript SDK comprising two packages:
`mcp-ui` is a collection of SDKs comprising:

* **`@mcp-ui/server`**: Utilities to generate UI resources (`UIResource`) on your MCP server.
* **`@mcp-ui/client`**: UI components (e.g., `<UIResourceRenderer />`) to render the UI resources and handle their events.
* **`@mcp-ui/server` (TypeScript)**: Utilities to generate UI resources (`UIResource`) on your MCP server.
* **`@mcp-ui/client` (TypeScript)**: UI components (e.g., `<UIResourceRenderer />`) to render the UI resources and handle their events.
* **`mcp_ui_server` (Ruby)**: Utilities to generate UI resources on your MCP server in a Ruby environment.

Together, they let you define reusable UI snippets on the server side, seamlessly and securely render them in the client, and react to their actions in the MCP host environment.

Expand Down Expand Up @@ -93,7 +95,7 @@ It accepts the following props:

#### HTML (`text/html` and `text/uri-list`)

Rendered using the `<HTMLResourceRenderer />` component, which displays content inside an `<iframe>`. This is suitable for self-contained HTML or embedding external apps.
Rendered using the internal `<HTMLResourceRenderer />` component, which displays content inside an `<iframe>`. This is suitable for self-contained HTML or embedding external apps.

* **`mimeType`**:
* `text/html`: Renders inline HTML content.
Expand All @@ -111,6 +113,8 @@ UI snippets must be able to interact with the agent. In `mcp-ui`, this is done b

## 🏗️ Installation

### TypeScript

```bash
# using npm
npm install @mcp-ui/server @mcp-ui/client
Expand All @@ -122,11 +126,19 @@ pnpm add @mcp-ui/server @mcp-ui/client
yarn add @mcp-ui/server @mcp-ui/client
```

### Ruby

```bash
gem install mcp_ui_server
```

## 🎬 Quickstart

You can use [GitMCP](https://gitmcp.io/idosal/mcp-ui) to give your IDE access to `mcp-ui`'s latest documentation!

1. **Server-side**: Build your resource blocks
### TypeScript

1. **Server-side**: Build your UI resources

```ts
import { createUIResource } from '@mcp-ui/server';
Expand Down Expand Up @@ -193,7 +205,45 @@ You can use [GitMCP](https://gitmcp.io/idosal/mcp-ui) to give your IDE access to
}
```

3. **Enjoy** interactive MCP UI — no extra configuration required.
### Ruby

**Server-side**: Build your UI resources

```ruby
require 'mcp_ui_server'

# Inline HTML
html_resource = McpUiServer.create_ui_resource(
uri: 'ui://greeting/1',
content: { type: :raw_html, htmlString: '<p>Hello, from Ruby!</p>' },
encoding: :text
)

# External URL
external_url_resource = McpUiServer.create_ui_resource(
uri: 'ui://greeting/2',
content: { type: :external_url, iframeUrl: 'https://example.com' },
encoding: :text
)

# remote-dom
remote_dom_resource = McpUiServer.create_ui_resource(
uri: 'ui://remote-component/action-button',
content: {
type: :remote_dom,
script: "
const button = document.createElement('ui-button');
button.setAttribute('label', 'Click me from Ruby!');
button.addEventListener('press', () => {
window.parent.postMessage({ type: 'tool', payload: { toolName: 'uiInteraction', params: { action: 'button-click', from: 'ruby-remote-dom' } } }, '*');
});
root.appendChild(button);
",
framework: :react,
},
encoding: :text
)
```

## 🌍 Examples

Expand Down Expand Up @@ -222,7 +272,7 @@ Host and user security is one of `mcp-ui`'s primary concerns. In all content typ
- [X] Support Web Components
- [X] Support Remote-DOM
- [ ] Add component libraries (in progress)
- [ ] Add SDKs for additional programming languages (in progress)
- [ ] Add SDKs for additional programming languages (in progress; Ruby available)
- [ ] Support additional frontend frameworks
- [ ] Add declarative UI content type
- [ ] Support generative UI?
Expand Down
Loading