@bridge-ds/mcp 0.0.0-stage → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +130 -2
- package/dist/audit.d.ts +15 -0
- package/dist/brand.d.ts +263 -0
- package/dist/chunk-GABRGCKY.js +7921 -0
- package/dist/chunk-X455XY4E.js +1718 -0
- package/dist/components.d.ts +55 -0
- package/dist/config.d.ts +13 -0
- package/dist/context.d.ts +42 -0
- package/dist/core-adapter.d.ts +48 -0
- package/dist/drafts.d.ts +44 -0
- package/dist/explorations.d.ts +241 -0
- package/dist/history.d.ts +431 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +33 -0
- package/dist/lib.d.ts +20 -0
- package/dist/lib.js +60 -0
- package/dist/markdown.d.ts +16 -0
- package/dist/ops.d.ts +739 -0
- package/dist/requests.d.ts +89 -0
- package/dist/server.d.ts +5 -0
- package/dist/source.d.ts +39 -0
- package/dist/src-XSBCZV4W.js +1125 -0
- package/package.json +65 -4
package/README.md
CHANGED
|
@@ -1,3 +1,131 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @bridge-ds/mcp
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
An MCP server that connects your own Claude (Claude Code, Claude Desktop or any MCP client) to your own
|
|
4
|
+
design system repo. Claude can read your DTCG tokens, components and docs, run your contrast gate, and
|
|
5
|
+
propose token changes as reviewable branches and pull requests. It never writes to `main`.
|
|
6
|
+
|
|
7
|
+
Free and open source (MIT). Local, no backend, no account: it reads files on your disk, or a GitHub repo
|
|
8
|
+
with your own token.
|
|
9
|
+
|
|
10
|
+
> On npm: `npx -y @bridge-ds/mcp` runs it, nothing to build. The local path form (`node packages/mcp/dist/index.js`)
|
|
11
|
+
> is for working on the server itself.
|
|
12
|
+
|
|
13
|
+
## Run it
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
npm run mcp:build # builds packages/mcp and packages/cli
|
|
17
|
+
node packages/mcp/dist/index.js --root . # local repo (default: current directory)
|
|
18
|
+
node packages/mcp/dist/index.js --repo owner/name # GitHub repo, read-only
|
|
19
|
+
GITHUB_TOKEN=... node packages/mcp/dist/index.js --repo owner/name # GitHub repo, can open PRs
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Connect it to Claude Code:
|
|
23
|
+
|
|
24
|
+
```sh
|
|
25
|
+
claude mcp add bridge -- npx -y @bridge-ds/mcp --root /abs/path/to/your-ds
|
|
26
|
+
# or a GitHub repo (pull requests need a token):
|
|
27
|
+
claude mcp add bridge -s user -e GITHUB_TOKEN=your-github-token -- npx -y @bridge-ds/mcp --repo owner/name
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Or commit a project `.mcp.json` (this repo has one), or run `bridge init`. Claude Desktop, other clients
|
|
31
|
+
and the full guide: [docs/AI.md](../../docs/AI.md).
|
|
32
|
+
|
|
33
|
+
## Modes
|
|
34
|
+
|
|
35
|
+
| Mode | Start with | Reads | Writes |
|
|
36
|
+
| --- | --- | --- | --- |
|
|
37
|
+
| Local | `--root <dir>` (default cwd) | working tree | a commit on a new local `bridge/*` branch, via git plumbing: your checkout, index and working tree are untouched. Never pushes. |
|
|
38
|
+
| Remote, no token | `--repo owner/name` | GitHub (raw files, one API call for the tree) | nothing |
|
|
39
|
+
| Remote, token | `--repo owner/name` + `GITHUB_TOKEN` | GitHub API | new `bridge/*` branch, commit, draft PR labelled `source: mcp` and `tier: N` |
|
|
40
|
+
|
|
41
|
+
## Tools
|
|
42
|
+
|
|
43
|
+
| Tool | What it does |
|
|
44
|
+
| --- | --- |
|
|
45
|
+
| `bridge_get_config` | Source, write access, tiers, modes, the effective `bridge.config.json` |
|
|
46
|
+
| `bridge_list_tokens` | Tokens with resolved values, filtered by tier, `$type`, path prefix, mode |
|
|
47
|
+
| `bridge_get_token` | One token: value per mode with alias chain, defining files, tokens aliasing it, components using it |
|
|
48
|
+
| `bridge_search_tokens` | By words, CSS variable or value (exact and near colors) |
|
|
49
|
+
| `bridge_check_contrast` | The contrast gate in every brand x theme; with `edits`, before/after and new failures |
|
|
50
|
+
| `bridge_validate_tokens` | DTCG shapes, names, broken/circular aliases, type mismatches, light/dark parity |
|
|
51
|
+
| `bridge_list_components` | Components with family and summary |
|
|
52
|
+
| `bridge_get_component` | Props parsed from TypeScript, docs.json usage guidance, CSS variables used |
|
|
53
|
+
| `bridge_draft_docs` | docs.json pre-fill from the code (props, tokens, anatomy, contrast, changelog line, missing keys) and a prompt to write the prose; writes nothing |
|
|
54
|
+
| `bridge_get_design_language` | Sections of the design language doc |
|
|
55
|
+
| `bridge_get_guidelines` | AGENTS.md rules, risk tiers, what Bridge enforces |
|
|
56
|
+
| `bridge_propose_token_change` | Edits, validation, contrast, tier, changeset, PR body; branch (local) or PR (remote) |
|
|
57
|
+
| `bridge_list_brands` | Brands: slug, name, default, primary action color, theme override files |
|
|
58
|
+
| `bridge_plan_brand` | Dry run of a new brand: generated ramps, contrast for every theme, files, tier 3, PR body |
|
|
59
|
+
| `bridge_propose_brand` | The new brand as a local `bridge/brand-<slug>` branch or a draft PR; blocked when a pair fails |
|
|
60
|
+
| `bridge_list_reviews` | Open PRs (Bridge ones flagged) and local `bridge/*` branches |
|
|
61
|
+
| `bridge_get_review` | Diff table, contrast before/after, impact, tier check, CI status, approvals |
|
|
62
|
+
| `bridge_review_pr` | Comment, approve or request changes (token required) |
|
|
63
|
+
| `bridge_scaffold_component` | New component folder per the repo checklist |
|
|
64
|
+
| `bridge_visual_impact` | Before/after screenshots of the impacted stories and admin screens, pixel diff, manifest (local, needs Chrome; `plan` for the selection only) |
|
|
65
|
+
| `bridge_get_history` | Token history: versions, merged PRs and commits, who, when, why, tier |
|
|
66
|
+
| `bridge_get_token_history` | Every change of one token, before and after per mode |
|
|
67
|
+
| `bridge_plan_revert` | Dry run of a revert (or a one-token restore) against the current base, conflicts shown |
|
|
68
|
+
| `bridge_propose_revert` | The revert as a local bridge/* branch or a draft PR labelled revert |
|
|
69
|
+
| `bridge_audit` | Adoption in a product folder or file (local): token and component adoption, hardcoded values with the closest token, foreign components with the DS one to use, top files and fixes |
|
|
70
|
+
| `bridge_list_requests` | Component change requests (issues labeled `component-change`) with status and linked pull requests |
|
|
71
|
+
| `bridge_get_request` | One request with the component's files and a brief to implement it in a pull request that says "Closes #n" |
|
|
72
|
+
| `bridge_create_request` | File a request as an issue labeled `component-change` (token required; `dryRun` previews; `exploration` targets an exploration branch) |
|
|
73
|
+
| `bridge_start_exploration` | Start an exploration: `explore/<name>` branch and a draft pull request labeled `exploration`, previews and a snapshot package, never merged as is |
|
|
74
|
+
| `bridge_list_explorations` | Explorations with status, previews, the snapshot install command and linked requests |
|
|
75
|
+
|
|
76
|
+
Resources: `bridge://tokens/resolved`, `bridge://design-language`, `bridge://guidelines`,
|
|
77
|
+
`bridge://components/{name}`. Prompts: `review-token-pr`, `add-component`, `audit-ui-for-tokens`,
|
|
78
|
+
`migrate-file-to-ds`.
|
|
79
|
+
|
|
80
|
+
## Configuration
|
|
81
|
+
|
|
82
|
+
`bridge.config.json` at the repo root says where tokens live, how they layer per mode, and what Bridge may
|
|
83
|
+
write. It is the same file the Figma plugin and the docs site read, with one schema:
|
|
84
|
+
[`packages/core/bridge.config.schema.json`](../core/bridge.config.schema.json). Without one, Bridge detects a
|
|
85
|
+
config (token directory, tiers by folder name, light/dark and density files as modes); `bridge init` writes the
|
|
86
|
+
detected one so you can pin and edit it.
|
|
87
|
+
|
|
88
|
+
```jsonc
|
|
89
|
+
{
|
|
90
|
+
"$schema": "./packages/core/bridge.config.schema.json",
|
|
91
|
+
"repo": { "owner": "acme", "name": "design-system", "defaultBranch": "main" },
|
|
92
|
+
"tokens": {
|
|
93
|
+
"root": "packages/tokens/src",
|
|
94
|
+
"include": ["**/*.tokens.json"],
|
|
95
|
+
"tiers": { "primitive": ["primitives"], "semantic": ["semantic"], "component": ["components"] },
|
|
96
|
+
// lowest first; {mode} placeholders pick the file per mode value
|
|
97
|
+
"layers": [
|
|
98
|
+
{ "files": "primitives/*.tokens.json" },
|
|
99
|
+
{ "files": "brands/{brand}.tokens.json" },
|
|
100
|
+
{ "files": "semantic/{theme}.tokens.json" },
|
|
101
|
+
{ "files": "brands/{brand}.{theme}.tokens.json", "optional": true },
|
|
102
|
+
{ "files": "components/*.tokens.json" }
|
|
103
|
+
]
|
|
104
|
+
},
|
|
105
|
+
"modes": { "theme": { "values": ["light", "dark"], "default": "light", "parity": true } },
|
|
106
|
+
"contrast": { "path": "packages/tokens/src/contrast.checks.json" },
|
|
107
|
+
"components": { "dir": "packages/react/src/components" },
|
|
108
|
+
"changesets": { "dir": ".changeset", "package": "@acme/tokens" },
|
|
109
|
+
"governance": {
|
|
110
|
+
"protectedBranches": ["main", "master"],
|
|
111
|
+
"branchPrefix": "bridge/",
|
|
112
|
+
"labels": ["source: mcp"],
|
|
113
|
+
"owners": { "design": ["designer-login"], "tech": ["engineer-login"] }
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Develop
|
|
119
|
+
|
|
120
|
+
```sh
|
|
121
|
+
npm run mcp:test # builds both packages, runs vitest (real repo tokens, a fixture repo, fake GitHub, stdio smoke test)
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
All design-system logic comes from `@bridge-ds/core`, through `src/core-adapter.ts`: layered token sets,
|
|
125
|
+
validation, contrast, minimal-diff edits, diffs, the PR body, changesets, the GitHub client, the local git
|
|
126
|
+
writer (`@bridge-ds/core/node`) and the risk classifier the Figma plugin and the docs site use too. `npm run
|
|
127
|
+
mcp:build` bundles the server and the CLI with esbuild, compiling `@bridge-ds/core` in.
|
|
128
|
+
|
|
129
|
+
## License
|
|
130
|
+
|
|
131
|
+
MIT
|
package/dist/audit.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type TokenSet } from './core-adapter.js';
|
|
2
|
+
export interface Finding {
|
|
3
|
+
line: number;
|
|
4
|
+
text: string;
|
|
5
|
+
kind: 'color' | 'length' | 'duration' | 'z-index' | 'shadow' | 'easing' | 'font-weight';
|
|
6
|
+
property?: string;
|
|
7
|
+
suggestions: {
|
|
8
|
+
cssVar: string;
|
|
9
|
+
path: string;
|
|
10
|
+
value: string;
|
|
11
|
+
tier?: string;
|
|
12
|
+
exact: boolean;
|
|
13
|
+
}[];
|
|
14
|
+
}
|
|
15
|
+
export declare function auditSnippet(set: TokenSet, code: string, max?: number): Finding[];
|
package/dist/brand.d.ts
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
import { type BrandRadiusInput } from '@bridge-ds/core';
|
|
2
|
+
import type { BridgeContext } from './context.js';
|
|
3
|
+
export interface BrandArgs {
|
|
4
|
+
slug: string;
|
|
5
|
+
name?: string;
|
|
6
|
+
from?: string;
|
|
7
|
+
/** Hex ("#1F5F3A") or OKLCH hue in degrees. */
|
|
8
|
+
primary?: string | number;
|
|
9
|
+
neutral?: string | number;
|
|
10
|
+
accent?: string | number;
|
|
11
|
+
link?: string | number;
|
|
12
|
+
/** A preset id (soft, balanced, crisp) or px per role. */
|
|
13
|
+
radius?: string | BrandRadiusInput;
|
|
14
|
+
fonts?: {
|
|
15
|
+
heading?: string;
|
|
16
|
+
text?: string;
|
|
17
|
+
};
|
|
18
|
+
notes?: string;
|
|
19
|
+
}
|
|
20
|
+
/** Radius from a preset id, "6,12,20,20" (inset, control, container, overlay) or an object. */
|
|
21
|
+
export declare function parseRadius(r: BrandArgs['radius']): BrandRadiusInput | undefined;
|
|
22
|
+
export declare function listBrands(ctx: BridgeContext): Promise<{
|
|
23
|
+
brands: import("@bridge-ds/core").BrandSummary[];
|
|
24
|
+
hint: string;
|
|
25
|
+
}>;
|
|
26
|
+
/** Dry run: the brand file, ramps, contrast for every theme, tier and PR body. Writes nothing. */
|
|
27
|
+
export declare function planBrand(ctx: BridgeContext, a: BrandArgs): Promise<{
|
|
28
|
+
ok: boolean;
|
|
29
|
+
slug: string;
|
|
30
|
+
name: string;
|
|
31
|
+
from: string;
|
|
32
|
+
title: string;
|
|
33
|
+
tier: import("@bridge-ds/core").RiskTier;
|
|
34
|
+
bump: "minor";
|
|
35
|
+
label: string;
|
|
36
|
+
reasons: string[];
|
|
37
|
+
files: {
|
|
38
|
+
path: string;
|
|
39
|
+
action: "create" | "modify";
|
|
40
|
+
}[];
|
|
41
|
+
actionStep: number;
|
|
42
|
+
ramps: {
|
|
43
|
+
[k: string]: {
|
|
44
|
+
[k: string]: string;
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
contrast: {
|
|
48
|
+
checks: number;
|
|
49
|
+
passing: number;
|
|
50
|
+
themes: string[];
|
|
51
|
+
line: string;
|
|
52
|
+
failing: {
|
|
53
|
+
pair: string;
|
|
54
|
+
modes: string;
|
|
55
|
+
ratio: number | null;
|
|
56
|
+
min: number;
|
|
57
|
+
}[];
|
|
58
|
+
};
|
|
59
|
+
issues: import("@bridge-ds/core").BrandIssue[];
|
|
60
|
+
prBody: string;
|
|
61
|
+
status: string;
|
|
62
|
+
}>;
|
|
63
|
+
export declare function proposeBrand(ctx: BridgeContext, a: BrandArgs & {
|
|
64
|
+
dryRun?: boolean;
|
|
65
|
+
}): Promise<{
|
|
66
|
+
hint: string;
|
|
67
|
+
ok: boolean;
|
|
68
|
+
slug: string;
|
|
69
|
+
name: string;
|
|
70
|
+
from: string;
|
|
71
|
+
title: string;
|
|
72
|
+
tier: import("@bridge-ds/core").RiskTier;
|
|
73
|
+
bump: "minor";
|
|
74
|
+
label: string;
|
|
75
|
+
reasons: string[];
|
|
76
|
+
files: {
|
|
77
|
+
path: string;
|
|
78
|
+
action: "create" | "modify";
|
|
79
|
+
}[];
|
|
80
|
+
actionStep: number;
|
|
81
|
+
ramps: {
|
|
82
|
+
[k: string]: {
|
|
83
|
+
[k: string]: string;
|
|
84
|
+
};
|
|
85
|
+
};
|
|
86
|
+
contrast: {
|
|
87
|
+
checks: number;
|
|
88
|
+
passing: number;
|
|
89
|
+
themes: string[];
|
|
90
|
+
line: string;
|
|
91
|
+
failing: {
|
|
92
|
+
pair: string;
|
|
93
|
+
modes: string;
|
|
94
|
+
ratio: number | null;
|
|
95
|
+
min: number;
|
|
96
|
+
}[];
|
|
97
|
+
};
|
|
98
|
+
issues: import("@bridge-ds/core").BrandIssue[];
|
|
99
|
+
prBody: string;
|
|
100
|
+
status: string;
|
|
101
|
+
why: string;
|
|
102
|
+
} | {
|
|
103
|
+
branch: string;
|
|
104
|
+
fileContents: {
|
|
105
|
+
path: string;
|
|
106
|
+
content: string | null;
|
|
107
|
+
}[];
|
|
108
|
+
ok: boolean;
|
|
109
|
+
slug: string;
|
|
110
|
+
name: string;
|
|
111
|
+
from: string;
|
|
112
|
+
title: string;
|
|
113
|
+
tier: import("@bridge-ds/core").RiskTier;
|
|
114
|
+
bump: "minor";
|
|
115
|
+
label: string;
|
|
116
|
+
reasons: string[];
|
|
117
|
+
files: {
|
|
118
|
+
path: string;
|
|
119
|
+
action: "create" | "modify";
|
|
120
|
+
}[];
|
|
121
|
+
actionStep: number;
|
|
122
|
+
ramps: {
|
|
123
|
+
[k: string]: {
|
|
124
|
+
[k: string]: string;
|
|
125
|
+
};
|
|
126
|
+
};
|
|
127
|
+
contrast: {
|
|
128
|
+
checks: number;
|
|
129
|
+
passing: number;
|
|
130
|
+
themes: string[];
|
|
131
|
+
line: string;
|
|
132
|
+
failing: {
|
|
133
|
+
pair: string;
|
|
134
|
+
modes: string;
|
|
135
|
+
ratio: number | null;
|
|
136
|
+
min: number;
|
|
137
|
+
}[];
|
|
138
|
+
};
|
|
139
|
+
issues: import("@bridge-ds/core").BrandIssue[];
|
|
140
|
+
prBody: string;
|
|
141
|
+
status: string;
|
|
142
|
+
} | {
|
|
143
|
+
branch: string;
|
|
144
|
+
fileContents: {
|
|
145
|
+
path: string;
|
|
146
|
+
content: string | null;
|
|
147
|
+
}[];
|
|
148
|
+
ok: boolean;
|
|
149
|
+
slug: string;
|
|
150
|
+
name: string;
|
|
151
|
+
from: string;
|
|
152
|
+
title: string;
|
|
153
|
+
tier: import("@bridge-ds/core").RiskTier;
|
|
154
|
+
bump: "minor";
|
|
155
|
+
label: string;
|
|
156
|
+
reasons: string[];
|
|
157
|
+
files: {
|
|
158
|
+
path: string;
|
|
159
|
+
action: "create" | "modify";
|
|
160
|
+
}[];
|
|
161
|
+
actionStep: number;
|
|
162
|
+
ramps: {
|
|
163
|
+
[k: string]: {
|
|
164
|
+
[k: string]: string;
|
|
165
|
+
};
|
|
166
|
+
};
|
|
167
|
+
contrast: {
|
|
168
|
+
checks: number;
|
|
169
|
+
passing: number;
|
|
170
|
+
themes: string[];
|
|
171
|
+
line: string;
|
|
172
|
+
failing: {
|
|
173
|
+
pair: string;
|
|
174
|
+
modes: string;
|
|
175
|
+
ratio: number | null;
|
|
176
|
+
min: number;
|
|
177
|
+
}[];
|
|
178
|
+
};
|
|
179
|
+
issues: import("@bridge-ds/core").BrandIssue[];
|
|
180
|
+
prBody: string;
|
|
181
|
+
status: string;
|
|
182
|
+
message: string;
|
|
183
|
+
} | {
|
|
184
|
+
branch: string;
|
|
185
|
+
base: string;
|
|
186
|
+
commit: string;
|
|
187
|
+
next: string;
|
|
188
|
+
ok: boolean;
|
|
189
|
+
slug: string;
|
|
190
|
+
name: string;
|
|
191
|
+
from: string;
|
|
192
|
+
title: string;
|
|
193
|
+
tier: import("@bridge-ds/core").RiskTier;
|
|
194
|
+
bump: "minor";
|
|
195
|
+
label: string;
|
|
196
|
+
reasons: string[];
|
|
197
|
+
files: {
|
|
198
|
+
path: string;
|
|
199
|
+
action: "create" | "modify";
|
|
200
|
+
}[];
|
|
201
|
+
actionStep: number;
|
|
202
|
+
ramps: {
|
|
203
|
+
[k: string]: {
|
|
204
|
+
[k: string]: string;
|
|
205
|
+
};
|
|
206
|
+
};
|
|
207
|
+
contrast: {
|
|
208
|
+
checks: number;
|
|
209
|
+
passing: number;
|
|
210
|
+
themes: string[];
|
|
211
|
+
line: string;
|
|
212
|
+
failing: {
|
|
213
|
+
pair: string;
|
|
214
|
+
modes: string;
|
|
215
|
+
ratio: number | null;
|
|
216
|
+
min: number;
|
|
217
|
+
}[];
|
|
218
|
+
};
|
|
219
|
+
issues: import("@bridge-ds/core").BrandIssue[];
|
|
220
|
+
prBody: string;
|
|
221
|
+
status: string;
|
|
222
|
+
} | {
|
|
223
|
+
branch: string;
|
|
224
|
+
commit: string;
|
|
225
|
+
pr: number;
|
|
226
|
+
url: string;
|
|
227
|
+
labels: string[];
|
|
228
|
+
draft: boolean;
|
|
229
|
+
ok: boolean;
|
|
230
|
+
slug: string;
|
|
231
|
+
name: string;
|
|
232
|
+
from: string;
|
|
233
|
+
title: string;
|
|
234
|
+
tier: import("@bridge-ds/core").RiskTier;
|
|
235
|
+
bump: "minor";
|
|
236
|
+
label: string;
|
|
237
|
+
reasons: string[];
|
|
238
|
+
files: {
|
|
239
|
+
path: string;
|
|
240
|
+
action: "create" | "modify";
|
|
241
|
+
}[];
|
|
242
|
+
actionStep: number;
|
|
243
|
+
ramps: {
|
|
244
|
+
[k: string]: {
|
|
245
|
+
[k: string]: string;
|
|
246
|
+
};
|
|
247
|
+
};
|
|
248
|
+
contrast: {
|
|
249
|
+
checks: number;
|
|
250
|
+
passing: number;
|
|
251
|
+
themes: string[];
|
|
252
|
+
line: string;
|
|
253
|
+
failing: {
|
|
254
|
+
pair: string;
|
|
255
|
+
modes: string;
|
|
256
|
+
ratio: number | null;
|
|
257
|
+
min: number;
|
|
258
|
+
}[];
|
|
259
|
+
};
|
|
260
|
+
issues: import("@bridge-ds/core").BrandIssue[];
|
|
261
|
+
prBody: string;
|
|
262
|
+
status: string;
|
|
263
|
+
}>;
|