@aicanvas/mcp 0.2.0 → 0.2.2

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.
Files changed (3) hide show
  1. package/README.md +3 -3
  2. package/dist/index.js +28 -7
  3. 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 count against the right quota and unlock premium content. Sent as a `Bearer` token on every registry request. Absent means anonymous, which is subject to the daily free limit. |
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
- ### Daily limits and premium content
125
+ ### Accounts and premium content
126
126
 
127
- Anonymous use is capped by a daily free limit, and some content (such as full design systems) is premium. When you hit the limit or request gated content without entitlement, a source fetch returns HTTP 402 and the tool reports a clear message: upgrade at [aicanvas.me/pricing](https://aicanvas.me/pricing), set `AICANVAS_TOKEN` to use your account, and update with `npx @aicanvas/mcp@latest`. Metadata browsing (`list_categories`, `list_components`, `search_components`, `list_systems`) is not gated. The 402 only affects source fetches (`get_component`, `get_system`, `get_template`).
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.0';
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 pulls count against the right quota and unlock
27
- // premium content. Absent = anonymous (subject to the daily free limit).
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 requires AI Canvas Premium, or you have hit the daily free limit. ' +
57
- 'Upgrade at https://aicanvas.me/pricing. Set AICANVAS_TOKEN to use your account, ' +
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 ${meta.componentCount} components across ${meta.categories.length} categories.`,
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 React only)'}`,
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.0",
3
+ "version": "0.2.2",
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
- "react",
11
- "components",
12
- "framer-motion"
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": {