mcpField
S
Solar MCP

Solar MCP

ローカル
solarbuild.dev開発ツール214 週間前に更新

Solar MCP について

Solar MCPは、SolarのコンポーネントレジストリをMCPツールとしてAIエージェントに公開します。実行時のコンポーネント発見、プロパティ検証、構造化された修正案に対応し、AI生成コードでUIを構築するチーム向けです。

主な機能

  1. 01登録コンポーネントとスキーマの一覧
  2. 02個別コンポーネントスキーマの取得
  3. 03コンポーネントプロパティの検証
  4. 04構造化された修正案の提示
  5. 05エージェントによる実行時の探索

活用シーン

  1. 01生成前に利用可能なUIコンポーネントを確認
  2. 02AI生成インターフェースのプロパティを検査
  3. 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 の代替ではありません。対象範囲はより限定され、制約も異なります。
  • 人間が手作業でコンポーネントを書くことに最適化されているわけではありませんが、その用途でも問題なく使えます。

主張したいのは、次世代のフレームワークは開発者向けに設計されるのではなく、開発者がコードを書くために使うモデル向けに設計されるということです。これはその初期の試みです。

コメント

MCP は初めてですか?

プロトコルの概要から最初のサーバーの導入まで、よくある疑問にまとめて答えます。

AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。