Solar MCP について
Solar MCPは、SolarのコンポーネントレジストリをMCPツールとしてAIエージェントに公開します。実行時のコンポーネント発見、プロパティ検証、構造化された修正案に対応し、AI生成コードでUIを構築するチーム向けです。
主な機能
- 01登録コンポーネントとスキーマの一覧
- 02個別コンポーネントスキーマの取得
- 03コンポーネントプロパティの検証
- 04構造化された修正案の提示
- 05エージェントによる実行時の探索
活用シーン
- 01生成前に利用可能なUIコンポーネントを確認
- 02AI生成インターフェースのプロパティを検査
- 03無効なコンポーネント設定を修正
MCP 対応
solarbuild-mcpサーバーはmanifest、component、validateツールを公開します。MCPクライアントはSolarレジストリの確認、コンポーネントスキーマの取得、修正案付きのプロパティ検証を行えます。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
このサーバーのパッケージやリモートエンドポイントはまだ取得できていません。プロジェクトの README の手順に従ってください。
ツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細
Solar
AI 生成コード向けに構築されたランタイム UI フレームワークです。
AI エージェントが React や Vue で UI を構築するとき、推測に頼ります。プロパティ名、型、有効な値を推測します。間違えると、スタックトレースが返されます。スタックトレースは、機械可読なフィードバックではありません。
Solar は、エージェントに明確な道筋を示します。registry.manifest() を呼び出すと、登録済みのすべてのコンポーネントについて、受け取るプロパティや有効な値を含む JSON スキーマを取得できます。間違ったプロパティでコンポーネントをマウントすると、expected、received、fix フィールドを持つ構造化オブジェクト ContractError が返されます。エージェントは fix を読み取り、再試行します。人間の手を借りる必要はありません。
コア原則
- 慣習より明示的なコントラクト: プロパティは推測されるのではなく、コンポーネントの境界で型指定され、検証されます
- コンポーネントレジストリ: モデルは構成コードを生成する前に、機械可読なマニフェストを読み取ります
- 構造化エラー: 検証に失敗すると、エージェントが直接処理できる解析可能な JSON が返されます
- 宣言的な副作用: エフェクトは依存対象と作用対象を宣言します。暗黙的なサブスクリプションはありません
- 型付きコンポジション: スロットのプロパティにより、どのコンポーネントでスロットを埋められるかが定まり、ランタイム検証も行われます
- ランタイムベース: コンパイラーは不要で、そのままブラウザーでデバッグできます
- 小さな API 範囲: プリミティブが少ないほど、誤ったものを生成する可能性も減ります
仕組み
コンポーネントの定義
すべてのコンポーネントは、自身の形状を明示的に宣言します。他のコンポーネントやモデルから検出できるように、登録します。
import { createElement, defineComponent, registry } from './framework/index.js'
const Button = defineComponent({
name: 'Button',
props: {
label: { type: 'string', required: true },
onClick: { type: 'function', required: true },
variant: { type: 'string', enum: ['primary', 'secondary'], default: 'primary' },
},
render({ label, onClick, variant }) {
return createElement('button', { class: variant, onclick: onClick }, label)
}
})
registry.register(Button)
構造化エラー
誤った型を渡すと、文字列ではなく構造化エラーが返されます。エージェントは正規表現を使わずに解析し、自己修正できます。
Button({ label: 42, onClick: () => {} })
// throws ContractError:
{
"error": "ContractError",
"component": "Button",
"prop": "label",
"expected": "string",
"received": "number",
"fix": "Pass a string value for \"label\""
}
コンポーネントレジストリ
構成コードを生成する前に、モデルはカタログ全体を読み取ります。
registry.manifest()
// →
[
{
"name": "Button",
"props": {
"label": { "type": "string", "required": true },
"onClick": { "type": "function", "required": true },
"variant": { "type": "string", "enum": ["primary", "secondary"], "default": "primary" }
}
},
...
]
型付きスロット(コンポーネントの合成)
親コンポーネントは、スロットを埋められるコンポーネントの型を宣言します。それ以外のものを渡すと、ContractError がスローされます。
const Card = defineComponent({
name: 'Card',
props: {
title: { type: 'string', required: true },
action: { type: 'slot', accepts: 'Button', required: true },
},
render({ title, action }) {
return createElement('div', { class: 'card' },
createElement('h3', {}, title),
action,
)
}
})
// valid
Card({ title: 'Hello', action: Button({ label: 'Go', onClick: () => {} }) })
// throws: Card: prop "action": expected slot(Button), got vnode with no _source
Card({ title: 'Hello', action: createElement('button', {}, 'Go') })
コンパクトな h() 記法
h() は、密度の高い配列形式を解析して vnode ツリーに変換します。レジストリを認識するため、コンポーネント名は自動的に解決されます。
import { h } from './framework/index.js'
// plain DOM nodes
h(['div', { class: 'row' },
['p', {}, 'Hello'],
['button', { class: 'btn' }, 'Click'],
])
// registered component by name, dispatches to Button()
h(['Button', { label: 'Save', onClick: handleSave, variant: 'primary' }])
フックとエフェクト
状態には useState を使います。副作用には、汎用的な useEffect の代わりに、明示的な 3 つのプリミティブを使います。
useResource: キーが変更されたときに AbortController によるキャンセルを自動で行う、非同期データ取得useSubscription: ソース、イベント、ハンドラーが変更されたときに、イベントリスナーを登録・解除する機能onMount/onUnmount: レンダリングのたびではなく、一度だけ実行されるライフサイクルコールバック
const UserCard = defineComponent({
name: 'UserCard',
props: { userId: { type: 'number', required: true } },
render({ userId }) {
const [width, setWidth] = useState(window.innerWidth)
// cancels the previous fetch automatically when userId changes
const { data, loading, error } = useResource({
key: userId,
fetch: async (signal) => {
const res = await fetch(`/api/user/${userId}`, { signal })
return res.json()
},
})
// attaches once, re-attaches only if source/event/handler changes
useSubscription({ source: window, event: 'resize', handler: () => setWidth(window.innerWidth) })
onMount(() => analytics.track('UserCard mounted'))
onUnmount(() => analytics.track('UserCard unmounted'))
if (loading) return createElement('p', {}, 'Loading...')
return createElement('p', {}, `${data.name} - viewport: ${width}px`)
}
})
アーキテクチャ
framework/
├── core/
│ ├── createElement.js # vnode factory
│ ├── render.js # mount vnode tree to DOM
│ ├── diff.js # reconcile old and new vnode trees
│ ├── hooks.js # useState, useMemo, useResource, useSubscription, onMount, onUnmount
│ └── scheduler.js # batch and defer re-renders
├── contract/
│ ├── defineComponent.js # strict component definition with prop schema
│ ├── ContractError.js # structured error class with toJSON()
│ ├── validate.js # runtime prop validation
│ └── types.js # primitive type definitions + slot type
├── runtime/
│ ├── reconciler.js # component lifecycle and mount/unmount
│ └── events.js # delegated event handling
├── registry.js # component catalog and manifest
├── h.js # compact array notation parser
└── index.js # public API
コンポーネントは components/ に 1 ファイルずつ配置します。デフォルトエクスポートは defineComponent の呼び出しであり、インポート時に自動登録されます。モデルが推測せずに従えるルールです。
ライブデモ
StackBlitz で開く — ブラウザー上で 3 ステップのエージェントループを実行します。registry.manifest() でコンポーネントを検出し、不正なマウントで ContractError を捕捉して、fix フィールドを使って自己修正します。
はじめに
npm create solarbuild@latest my-app
cd my-app
npm run dev
Cursor プラグイン: cursor.directory/plugins/framework-solar — Solar のルールを Cursor に追加し、AI アシスタントが最初から API を把握できるようにします。
または、CDN を直接使えます。インストールもビルド手順も不要です。
<!DOCTYPE html>
<html>
<body>
<div id="app"></div>
<script type="module">
import {
defineComponent, mountComponent, registry,
useState, createElement
} from 'https://cdn.jsdelivr.net/npm/solarbuild/framework/index.js'
const Counter = defineComponent({
name: 'Counter',
props: {},
render() {
const [count, setCount] = useState(0)
return createElement('button', { onclick: () => setCount(n => n + 1) }, `Clicked ${count} times`)
}
})
registry.register(Counter)
mountComponent(Counter, {}, document.getElementById('app'))
</script>
</body>
</html>
デモの実行
npm run dev
http://localhost:3456/demo/ を開きます(末尾のスラッシュが必要です。静的サーバーの仕様によるものです)。
デモでは、フレームワークのすべての機能を紹介します。静的レンダリング、差分処理、フック、コントラクト検証、宣言的なエフェクト、更新のバッチ処理、レジストリマニフェスト、コンパクトな h() 記法、型付きスロットです。
MCP サーバー
solarbuild-mcp は、Solar コンポーネントレジストリを呼び出し可能なツールとして公開する MCP サーバーです。AI エージェントは静的なドキュメントを読むことなく、コンポーネントを検出し、プロパティを検証して、実行時に自ら修正できます。
npm install solarbuild-mcp
{
"mcpServers": {
"solarbuild": {
"command": "npx",
"args": ["solarbuild-mcp", "--components", "./components"]
}
}
}
ツール: manifest(レジストリ全体のスキーマ)、component(単一コンポーネントのスキーマ)、validate(修正手順付きのプロパティ検証)。
→ MCP サーバーのドキュメント · npm
ドキュメント
詳細なドキュメントはdocs.solarbuild.devをご覧ください。
これは何ではないか
- メタフレームワークではありません。SSR、ルーティング、ビルドパイプラインはありません。
- React の代替ではありません。対象範囲はより限定され、制約も異なります。
- 人間が手作業でコンポーネントを書くことに最適化されているわけではありませんが、その用途でも問題なく使えます。
主張したいのは、次世代のフレームワークは開発者向けに設計されるのではなく、開発者がコードを書くために使うモデル向けに設計されるということです。これはその初期の試みです。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。