@tabula-css/mcp
Tabula の読み取り専用 MCP サーバー: 生成された .tabula/ アーティファクト上のエージェント向けサーフェス。
インストール
npm install --save-dev @tabula-css/mcp開発時依存です — これはあなたのアプリのランタイム依存ではなく、コーディングエージェントの MCP クライアントが起動するローカルツールです。@tabula-css/cli、@tabula-css/core、@tabula-css/eslint-plugin、@tabula-css/merge、@tabula-css/registry、@tabula-css/tokens をバンドルしています。@typescript-eslint/parser は通常の依存関係として同梱されます。eslint は任意のピア依存で、validate_source ツールにのみ必要です。
概要
llms.txt/llms-full.txt がエージェントに語彙の静的な地図を与えるのに対し、MCP サーバーは同じ .tabula/ アーティファクトへのライブで構造化されたアクセスを与えます: クラス文字列が実際に何をレンダリングするかを解決すること、cn() のマージを書く前にプレビューすること、名前を思い出す代わりに意図からクラスを逆引きすること、そして提案された編集が着地する前に実際のレジストリに照らして検証すること。すべてのツールは読み取り専用です — ここでのどれもファイルを書き込みません。2 つの提案ツールは、エージェント自身の編集経路が適用するパッチを返すため、人間が diff をレビューします。
実行
npx tabula-mcp [--cwd <dir>]バイナリは tabula-mcp(bin.ts から)です。stdio(StdioServerTransport)で MCP を話します — 標準出力はプロトコルだけを運び、それ以外は何も運びません。すべての診断は標準エラーへ送られます。そうしないとプロトコルフレームとしてパースされてしまいます。--cwd は、現在のディレクトリではない別のプロジェクトルートを指定します。.tabula/ が存在しないか不正な場合、決して読んでいないプロファイルを提供するのではなく、起動を拒否します(exit 2)。
MCP 対応クライアントの設定で、直接これを指定してください。例:
{
"mcpServers": {
"tabula": { "command": "npx", "args": ["tabula-mcp"] }
}
}すべてのレスポンスは陳腐化エンベロープを伴います
{ "profileVersion": "…", "sourceHash": "…", "stale": false }陳腐化は呼び出しのたびに再計算されます — サーバーは .tabula/ とトークンのソースを再度 stat し、それらが変化していれば再読み込みするため、編集してから再ビルドするループは決して再起動を必要としません。すべてのツールは、古い読み取りを次のように拒否します:
{
"error": "STALE_REGISTRY",
"message": "The .tabula/ artifacts do not match the current inputs. …",
"command": ["tabula", "build"],
"reasons": ["…"],
"profileVersion": "…", "sourceHash": "…", "stale": true
}2 つのツールはこの拒否から除外されます(該当する場合には stale: true を報告し続けますが): doctor はその仕事全体が陳腐化を報告することであり、explain は @tabula-css/core の凍結されたカタログしか読まず、どのアーティファクトにも触れません。ソースのドリフトチェックを実行できなかった場合(解決不能なパッケージバージョン、または読み取り不能なプロジェクトソース)、エンベロープにはさらに "staleCheck": "artifacts-only" が含まれます — 陳腐化と成果物のみのチェック を参照してください。
ツール
resolve_classes
「この要素は実際にはどう見えるか?」クラス文字列に対する完全なローカルスタイリングモデルです: 基本の宣言、条件付きの帯域、アンビエントプロパティ、アトミック/未知のクラス、グループ依存関係。
| Param | Type | Required |
|---|---|---|
classes | string | string[] | yes |
axes | Record<string, string>(例: { theme: "dark" }) | no |
// → resolve_classes({ classes: "bg-surface p-md" })
{ "profileVersion": "…", "sourceHash": "…", "stale": false, /* declarations, bands, … */ }preview_merge
cn(...) を書く前に、それが実際に何を生成するかを正確に予測します: マージされた文字列に加え、破棄されたすべてのクラス、それを何が shadow したか、そしてどの CSS プロパティ上でかを返します。
| Param | Type | Required |
|---|---|---|
fragments | string[] — 順序どおり。呼び出し側の className は最後に置きます | yes |
find_class_for
意図による逆引きです — このセット内で最も価値の高いツールです。実際のテキスト(クラス名、ファミリー、宣言されたプロパティ/値、トークンの説明)のみをマッチさせ、ヒットごとに matchedOn を報告します。同義語テーブルもファジースコアもありません。ヒットしないことは、そのようなクラスが存在しないことを意味し、「任意の値を推測せよ」ということではありません。
| Param | Type | Required |
|---|---|---|
intent | string | no |
property | string、例: "padding-inline" | no |
value | string、例: "#ffffff" | no |
family | string、例: "bg" | no |
limit | number(デフォルト 25) | no |
// → find_class_for({ intent: "raised card background" })
{ "matches": [{ "class": "bg-surface-raised", "family": "bg", "matchedOn": ["intent"], "rank": 30091300002, … }], "total": 1 }get_tokens
tokens.resolved.json から直接得られる、すべてのトークン(または名前空間/部分文字列によるスライス)です — 値を選ぶ前にこれを読んでください。
| Param | Type | Required |
|---|---|---|
namespace | string、例: "color" | no |
query | string、パス + 説明に対する部分文字列マッチ | no |
get_vocabulary
ページングされた、クラスの完全な一覧です — 静かに切り詰められることは決してなく、レスポンスは total/pages/hasMore を報告します。
| Param | Type | Required |
|---|---|---|
family | string | no |
prefix | string | no |
page | number、0 始まり | no |
pageSize | number(デフォルト 100、最大 500) | no |
explain_ban
なぜあるクラスが禁止されている、あるいは未登録なのか、その置き換え案とともに — 単なる「見つかりません」で終わることは決してありません。自信のないクラス(space-x-4、dark:bg-black、pl-4)を書く前に呼び出してください。
| Param | Type | Required |
|---|---|---|
class | string、例: "space-x-4" | yes |
resolve_element
{ file, line, col } によって JSX 要素を指し示し、その解決済みクラス、同一ファイル内の祖先から継承されるテキストコンテキスト、そしてそれが参照する各 group/peer がそのファイル内にマーカーを持つかどうかを返します。同一ファイル内の解析のみ — コンポーネントの境界では、コンポーネントが何をレンダリングするかを推測するのではなく、次に開くべきファイルとともに status: "unknown" を返します。また、要素がどの軸の組み合わせの下でレンダリングされるかは実行中のドキュメントについての事実であってソースについての事実ではないため、axisValues は省略されます。
| Param | Type | Required |
|---|---|---|
file | string、プロジェクトルートからの相対パス | yes |
line | number、1 始まり | yes |
col | number、1 始まり | yes |
validate_source
ソース文字列を、あなたのレジストリに対する実際の strict ESLint 設定で lint します — check_classes が構造的に捉えられないもの(ランタイムでのクラス構築、className の順序、group/peer の構造、継承の境界、例外のスコープ)を捕捉します。これは AST を見るためです。インラインの eslint-disable コメントは無視されるため、スニペットが話術でクリーンな判定を得ることはできません。eslint と @typescript-eslint/parser がインストールされている必要があります。なければ LINTER_UNAVAILABLE とインストールコマンドを返します。
| Param | Type | Required |
|---|---|---|
code | string — lint 対象のソーステキスト | yes |
filename | string、例: "src/ui/card.tsx" — ディスクから読み取られることは決してありません。ルールと例外のスコープを選択するためのものです | yes |
propose_exception
トークンを持たない値を導入する唯一の合法な方法です。パッチを返します — 何も書き込みません。 実際のトークンバリデーターを通じて検証し、既存のトークンが約 5% 以内にある場合はそちらへ促し、パッチが発行するであろうクラス名を返します。
| Param | Type | Required |
|---|---|---|
name | string、ケバブケース | yes |
$type | string(DTCG の型) | yes |
value | string、例: "347px" | yes |
families | string[]、例: ["w"] | yes |
reason | string、40 文字以上 | yes |
owner | string、例: "@design-systems" | yes |
expires | string、YYYY-MM-DD、12 か月以内(literal の場合は 90 日以内) | yes |
allowedIn | string[](glob) | yes |
description | string | no |
ticket | string | no |
literal | boolean | no |
propose_token
新しいデザイントークンを発行します — トークンは永続的な語彙となるため、propose_exception よりもこちらを優先してください。パッチを返します — 何も書き込みません。 実際のトークンドキュメントに継ぎ足すことで検証されます。
| Param | Type | Required |
|---|---|---|
name | string、"<namespace>.<name>" | yes |
$type | string(DTCG の型) | yes |
value | string — 単一のリテラル。cases とは互いに排他的 | no |
cases | object — 軸マップ、例: { $axis: "theme", light: "#fff", dark: "#0b0b0b" }。value とは互いに排他的 | no |
description | string | no |
find_group_marker
名前付きの group/<name> マーカーがどこで宣言されているか。これにより、要素間の依存関係がツリーウォークではなくルックアップになります。「そのようなマーカーはない」ことと「このビルドがマーカーインデックスを生成しなかった」ことを区別します。
| Param | Type | Required |
|---|---|---|
name | string、例: "card" | yes |
check_classes
事前チェックです — class 属性を書く前に呼び出してください。未知のクラス(「もしかして」提案付き)、禁止されたメカニズム、同一文字列内のスロット競合を報告し、正規のマージ済み文字列を返します。
| Param | Type | Required |
|---|---|---|
classes | string[] | yes |
doctor
ヘルスチェックです: 陳腐化(理由と修正コマンド付き)、手編集されたアーティファクト、期限切れ間近の例外、そしてエスケープ予算。古い状態でも 応答します — 陳腐化を報告する仕組み自体が「古いから」という理由で拒否してしまっては、何がドリフトしたのかを決して伝えられません。
パラメータなし。
// → doctor()
{
"stale": false, "reasons": [], "checkedSource": true,
"drift": [], "expiringExceptions": [], "escapeBudget": { "used": 3, "max": 25 },
"profileVersion": "…", "sourceHash": "…", "manifestInputsHash": "…"
}explain
@tabula-css/core の凍結されたカタログからの、TAB-Exxx/TAB-Wxxx コードの原因と修正方法です。
| Param | Type | Required |
|---|---|---|
code | string、例: "TAB-E113" | yes |
関連パッケージ
@tabula-css/registry— すべてのツールが読み取るアーティファクト。@tabula-css/tokens—propose_token/propose_exceptionが検証対象とするトークンドキュメント。@tabula-css/eslint-plugin—validate_sourceが実行するstrict設定。- エージェントサーフェス —
llms.txt、フェイルビジブル保証、そして陳腐化モデルの全体像。 @tabula-css/cli—tabula doctorとtabula explain。このサーバーの CLI 版に相当します。