@aicanvas/mcp 0.2.0 → 0.2.1
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 +3 -3
- package/dist/index.js +28 -7
- package/package.json +18 -4
package/README.md
CHANGED
|
@@ -120,11 +120,11 @@ This opens a browser UI where you can call each tool by hand.
|
|
|
120
120
|
| Env var | Default | What it does |
|
|
121
121
|
|---|---|---|
|
|
122
122
|
| `AICANVAS_REGISTRY_BASE` | `https://aicanvas.me/r` | Registry root URL. Override only for local development against a self-hosted mirror. |
|
|
123
|
-
| `AICANVAS_TOKEN` | _(none)_ | Optional per-account token. The website bakes it into the MCP config it gives you. It identifies your account so pulls
|
|
123
|
+
| `AICANVAS_TOKEN` | _(none)_ | Optional per-account token. The website bakes it into the MCP config it gives you. It identifies your AI Canvas account so source pulls are authorized and any premium content you own unlocks. Sent as a `Bearer` token on every registry request. Without it you are anonymous: metadata browsing still works, but pulling a component's source returns a short "create a free account" notice instead of the code. |
|
|
124
124
|
|
|
125
|
-
###
|
|
125
|
+
### Accounts and premium content
|
|
126
126
|
|
|
127
|
-
|
|
127
|
+
Browsing metadata (`list_categories`, `list_components`, `search_components`, `list_systems`, `get_install_command`) is free and needs no account. Pulling actual source (`get_component`, `get_system`, `get_template`) runs against a free AI Canvas account: set `AICANVAS_TOKEN` from your account and the website gives you the ready-made config. Without a token, a free-component source pull returns a short "create a free account" notice instead of the code, and premium content (full design systems and templates) returns HTTP 402 with an upgrade link at [aicanvas.me/pricing](https://aicanvas.me/pricing). Update anytime with `npx @aicanvas/mcp@latest`.
|
|
128
128
|
|
|
129
129
|
## How the registry stays fresh
|
|
130
130
|
|
package/dist/index.js
CHANGED
|
@@ -20,11 +20,12 @@ import { z } from 'zod';
|
|
|
20
20
|
const REGISTRY_BASE = process.env.AICANVAS_REGISTRY_BASE ?? 'https://aicanvas.me/r';
|
|
21
21
|
const META_URL = `${REGISTRY_BASE}/aicanvas-mcp.json`;
|
|
22
22
|
const META_TTL_MS = 5 * 60 * 1000; // 5 minutes — meta updates with deploys
|
|
23
|
-
const MCP_VERSION = '0.2.
|
|
23
|
+
const MCP_VERSION = '0.2.1';
|
|
24
24
|
const USER_AGENT = `aicanvas-mcp/${MCP_VERSION}`;
|
|
25
25
|
// Optional per-user token (the website bakes it into the copied MCP config).
|
|
26
|
-
// Identifies the account so
|
|
27
|
-
// premium content. Absent = anonymous
|
|
26
|
+
// Identifies the account so free-component source pulls are authorized and any
|
|
27
|
+
// premium content you own unlocks. Absent = anonymous: metadata browsing still
|
|
28
|
+
// works, but source pulls of free components need a free account.
|
|
28
29
|
const USER_TOKEN = process.env.AICANVAS_TOKEN ?? '';
|
|
29
30
|
function registryHeaders() {
|
|
30
31
|
return {
|
|
@@ -53,10 +54,30 @@ async function fetchComponentSource(slug) {
|
|
|
53
54
|
if (res.status === 402) {
|
|
54
55
|
const j = (await res.json().catch(() => ({})));
|
|
55
56
|
throw new Error(j.message ??
|
|
56
|
-
'This
|
|
57
|
-
'
|
|
57
|
+
'This is premium AI Canvas content. Upgrade at https://aicanvas.me/pricing, ' +
|
|
58
|
+
'then use the AI Canvas MCP config from your account (your token is included) ' +
|
|
58
59
|
'and update with: npx @aicanvas/mcp@latest');
|
|
59
60
|
}
|
|
61
|
+
// Free component pulled without an account: the registry returns a 200
|
|
62
|
+
// placeholder (not a 402), tagged with this header. Surface a warm sign-up
|
|
63
|
+
// CTA instead of handing the placeholder back as if it were real source.
|
|
64
|
+
if (res.headers.get('x-aicanvas-content-type') === 'free-account-required') {
|
|
65
|
+
const j = (await res.json().catch(() => ({})));
|
|
66
|
+
const name = typeof j.title === 'string'
|
|
67
|
+
? j.title.replace(/\s*\(free account required\)\s*$/i, '')
|
|
68
|
+
: slug;
|
|
69
|
+
throw new Error(`Almost there! "${name}" is free with an AI Canvas account (free, unlimited installs). ` +
|
|
70
|
+
`Sign up at https://aicanvas.me/account/sign-up, then use the AI Canvas MCP config from ` +
|
|
71
|
+
`your account (your token is included) and ask again.`);
|
|
72
|
+
}
|
|
73
|
+
// NOTE: premium standalones ALSO return a 200 placeholder (header
|
|
74
|
+
// 'premium-standalone'), but that header value is NOT unique to the
|
|
75
|
+
// placeholder — an entitled subscriber's REAL source carries it too (the
|
|
76
|
+
// success path stamps the contentType). Keying the MCP on it would strip a
|
|
77
|
+
// paying subscriber's real component. So premium is deliberately NOT
|
|
78
|
+
// intercepted here. Closing that footgun safely needs premiumStub to emit a
|
|
79
|
+
// distinct header (like freeAccountStub's 'free-account-required'); tracked
|
|
80
|
+
// as a separate, billing-reviewed follow-up.
|
|
60
81
|
if (!res.ok) {
|
|
61
82
|
throw new Error(`Failed to fetch source for "${slug}" from ${url}: ${res.status} ${res.statusText}`);
|
|
62
83
|
}
|
|
@@ -158,7 +179,7 @@ server.registerTool('list_categories', {
|
|
|
158
179
|
try {
|
|
159
180
|
const meta = await fetchMeta();
|
|
160
181
|
const lines = [
|
|
161
|
-
`AI Canvas
|
|
182
|
+
`AI Canvas: ${meta.componentCount} components across ${meta.categories.length} categories.`,
|
|
162
183
|
'',
|
|
163
184
|
...meta.categories.map((c) => ` ${c.label.padEnd(24)} ${String(c.count).padStart(3)} components`),
|
|
164
185
|
];
|
|
@@ -395,7 +416,7 @@ server.registerTool('get_install_command', {
|
|
|
395
416
|
'',
|
|
396
417
|
` ${component.installCommand}`,
|
|
397
418
|
'',
|
|
398
|
-
`Dependencies: ${component.dependencies.join(', ') || '(none
|
|
419
|
+
`Dependencies: ${component.dependencies.join(', ') || '(none, React only)'}`,
|
|
399
420
|
`Source: ${component.sourceUrl}`,
|
|
400
421
|
`Preview: ${component.homepageUrl}`,
|
|
401
422
|
].join('\n')),
|
package/package.json
CHANGED
|
@@ -1,15 +1,29 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aicanvas/mcp",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
|
+
"mcpName": "io.github.uinerd16/aicanvas",
|
|
4
5
|
"description": "Model Context Protocol server for AI Canvas — search, inspect, and install components from the aicanvas.me registry directly from your AI editor.",
|
|
5
6
|
"keywords": [
|
|
6
7
|
"mcp",
|
|
7
8
|
"model-context-protocol",
|
|
9
|
+
"mcp-server",
|
|
8
10
|
"aicanvas",
|
|
9
11
|
"shadcn",
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
"
|
|
12
|
+
"shadcn-registry",
|
|
13
|
+
"shadcn-ui",
|
|
14
|
+
"react-components",
|
|
15
|
+
"ui-components",
|
|
16
|
+
"component-library",
|
|
17
|
+
"framer-motion",
|
|
18
|
+
"animated-components",
|
|
19
|
+
"tailwindcss",
|
|
20
|
+
"design-system",
|
|
21
|
+
"ai-agents",
|
|
22
|
+
"ai-coding",
|
|
23
|
+
"claude",
|
|
24
|
+
"cursor",
|
|
25
|
+
"code-generation",
|
|
26
|
+
"registry"
|
|
13
27
|
],
|
|
14
28
|
"homepage": "https://aicanvas.me",
|
|
15
29
|
"repository": {
|