@lism-css/mcp 0.1.0 → 0.2.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.
@@ -3,13 +3,17 @@ import { loadJSON } from '../lib/load-data.js';
3
3
  import { ComponentInfoSchema } from '../lib/schemas.js';
4
4
  import { success, error, notFound, READ_ONLY_ANNOTATIONS } from '../lib/response.js';
5
5
  export function registerGetComponent(server) {
6
- server.tool('get_component', 'Get detailed information about a specific lism-css component: props, usage examples, and category. If not found, try search_docs with a broader query.', {
7
- name: z.string().describe('Component name to look up (e.g. "Box", "Flex", "Accordion").'),
8
- package: z
9
- .enum(['lism-css', '@lism-css/ui'])
10
- .optional()
11
- .describe('Filter by package. "lism-css" for core components, "@lism-css/ui" for UI components.'),
12
- }, READ_ONLY_ANNOTATIONS, ({ name, package: pkg }) => {
6
+ server.registerTool('get_component', {
7
+ description: '特定のlism-cssコンポーネントに関する詳細情報(プロパティ、使用例、カテゴリー)を取得します。該当するものが見つからない場合は、より広範なキーワードで search_docs を実行してください。',
8
+ inputSchema: {
9
+ name: z.string().describe('Component name to look up (e.g. "Box", "Flex", "Accordion").'),
10
+ package: z
11
+ .enum(['lism-css', '@lism-css/ui'])
12
+ .optional()
13
+ .describe('Filter by package. "lism-css" for core components, "@lism-css/ui" for UI components.'),
14
+ },
15
+ annotations: READ_ONLY_ANNOTATIONS,
16
+ }, ({ name, package: pkg }) => {
13
17
  try {
14
18
  const data = loadJSON('components.json', z.array(ComponentInfoSchema));
15
19
  let candidates = data;
@@ -17,10 +21,25 @@ export function registerGetComponent(server) {
17
21
  candidates = data.filter((c) => c.package === pkg);
18
22
  }
19
23
  const nameLower = name.toLowerCase();
24
+ // Step 1: 名前の完全一致
20
25
  const exact = candidates.find((c) => c.name.toLowerCase() === nameLower);
21
26
  if (exact) {
22
27
  return success({ component: exact });
23
28
  }
29
+ // Step 2: aliases マッチ(用途ベースの検索、完全一致)
30
+ const aliasMatches = candidates.filter((c) => c.aliases?.some((a) => a.toLowerCase() === nameLower));
31
+ if (aliasMatches.length === 1) {
32
+ return success({ component: aliasMatches[0], matchedBy: 'alias' });
33
+ }
34
+ if (aliasMatches.length > 1) {
35
+ const suggestions = aliasMatches.map((c) => ({
36
+ name: c.name,
37
+ package: c.package,
38
+ description: c.description,
39
+ }));
40
+ return notFound(`Component "${name}" not found by name, but ${aliasMatches.length} components matched by alias. Did you mean one of these?`, { suggestions });
41
+ }
42
+ // Step 3: 名前の部分一致
24
43
  const suggestions = candidates
25
44
  .filter((c) => c.name.toLowerCase().includes(nameLower))
26
45
  .map((c) => ({ name: c.name, package: c.package }));
@@ -38,7 +38,10 @@ function toMarkdown(data) {
38
38
  return lines.join('\n');
39
39
  }
40
40
  export function registerGetOverview(server) {
41
- server.tool('get_overview', 'Get an overview of the lism-css framework: architecture, design philosophy, packages, breakpoints, installation guide, and CSS layers. Start here to understand the framework before using other tools.', {}, READ_ONLY_ANNOTATIONS, () => {
41
+ server.registerTool('get_overview', {
42
+ description: 'Get an overview of the lism-css framework: architecture, design philosophy, packages, breakpoints, installation guide, and CSS layers. Start here to understand the framework before using other tools.',
43
+ annotations: READ_ONLY_ANNOTATIONS,
44
+ }, () => {
42
45
  try {
43
46
  const data = loadJSON('overview.json', OverviewDataSchema);
44
47
  return markdownResponse(toMarkdown(data));
@@ -2,26 +2,51 @@ import { z } from 'zod';
2
2
  import { loadJSON } from '../lib/load-data.js';
3
3
  import { PropsSystemDataSchema } from '../lib/schemas.js';
4
4
  import { success, error, notFound, READ_ONLY_ANNOTATIONS } from '../lib/response.js';
5
+ /** cssProperty フィールドからコア名を抽出(例: "--hl (CSS変数)" → "--hl") */
6
+ function normalizeCssProperty(raw) {
7
+ // "(class: is--container)" → "is--container"
8
+ const classMatch = raw.match(/\(class:\s*(.+?)\)/);
9
+ if (classMatch)
10
+ return classMatch[1].trim().toLowerCase();
11
+ // "--hl (CSS変数)" → "--hl"
12
+ return raw.replace(/\s*\(.*\)$/, '').trim().toLowerCase();
13
+ }
5
14
  export function registerGetPropsSystem(server) {
6
- server.tool('get_props_system', 'Get the lism-css Props system reference: how React props map to CSS classes and styles. Optionally filter by a specific prop name. Related: use get_component to see how props are used in specific components.', {
7
- prop: z.string().optional().describe('Specific prop name to look up (e.g. "p", "fz", "bgc"). Omit to get the full system overview.'),
8
- }, READ_ONLY_ANNOTATIONS, ({ prop }) => {
15
+ server.registerTool('get_props_system', {
16
+ description: 'Get the lism-css Props system reference: how React/Astro props map to CSS classes and styles. Supports lookup by lism prop name (e.g. "p", "fz") OR by CSS property name (e.g. "padding", "font-size"). Use this for CSS-to-lism reverse lookup. Related: use convert_css for bulk CSS conversion, get_component to see how props are used in components.',
17
+ inputSchema: {
18
+ prop: z
19
+ .string()
20
+ .optional()
21
+ .describe('Prop name or CSS property name to look up. Accepts lism prop names (e.g. "p", "fz", "bgc") and standard CSS property names (e.g. "padding", "font-size", "background-color"). Omit to get the full system overview.'),
22
+ },
23
+ annotations: READ_ONLY_ANNOTATIONS,
24
+ }, ({ prop }) => {
9
25
  try {
10
26
  const data = loadJSON('props-system.json', PropsSystemDataSchema);
11
27
  if (!prop) {
12
28
  return success(data);
13
29
  }
14
- const propLower = prop.toLowerCase();
30
+ const queryLower = prop.toLowerCase();
15
31
  const matched = [];
16
32
  for (const cat of data.categories) {
17
- const found = cat.props.filter((p) => p.prop.toLowerCase() === propLower);
33
+ const found = cat.props.filter((p) => {
34
+ // Lism prop 名で一致
35
+ if (p.prop.toLowerCase() === queryLower)
36
+ return true;
37
+ // CSS プロパティ名で一致(逆引き)
38
+ const normalizedCss = normalizeCssProperty(p.cssProperty);
39
+ if (normalizedCss === queryLower)
40
+ return true;
41
+ return false;
42
+ });
18
43
  if (found.length > 0) {
19
44
  matched.push({ ...cat, props: found });
20
45
  }
21
46
  }
22
47
  if (matched.length === 0) {
23
- const allProps = data.categories.flatMap((c) => c.props.map((p) => p.prop));
24
- return notFound(`Prop "${prop}" not found. Try search_docs to find related documentation.`, { availableProps: allProps });
48
+ const allProps = data.categories.flatMap((c) => c.props.map((p) => `${p.prop} (${p.cssProperty})`));
49
+ return notFound(`"${prop}" に一致する Prop が見つかりません。Lism prop (例: "p", "fz") または CSS プロパティ名 (例: "padding", "font-size") で検索できます。`, { availableProps: allProps });
25
50
  }
26
51
  return success({ description: data.description, categories: matched });
27
52
  }
@@ -4,9 +4,13 @@ import { TokenCategorySchema } from '../lib/schemas.js';
4
4
  import { success, error, READ_ONLY_ANNOTATIONS } from '../lib/response.js';
5
5
  const TOKEN_CATEGORIES = ['all', 'color', 'spacing', 'fontSize', 'shadow', 'radius', 'lineHeight', 'letterSpacing', 'fontFamily', 'zIndex'];
6
6
  export function registerGetTokens(server) {
7
- server.tool('get_tokens', 'Get design tokens (colors, spacing, font sizes, shadows, etc.) used in lism-css. Use get_overview first to understand the framework, then use this tool to explore specific token categories.', {
8
- category: z.enum(TOKEN_CATEGORIES).default('all').describe('Token category to retrieve. Use "all" to get all categories.'),
9
- }, READ_ONLY_ANNOTATIONS, ({ category }) => {
7
+ server.registerTool('get_tokens', {
8
+ description: 'Get design tokens (colors, spacing, font sizes, shadows, etc.) used in lism-css. Use get_overview first to understand the framework, then use this tool to explore specific token categories.',
9
+ inputSchema: {
10
+ category: z.enum(TOKEN_CATEGORIES).default('all').describe('Token category to retrieve. Use "all" to get all categories.'),
11
+ },
12
+ annotations: READ_ONLY_ANNOTATIONS,
13
+ }, ({ category }) => {
10
14
  try {
11
15
  const data = loadJSON('tokens.json', z.array(TokenCategorySchema));
12
16
  const filtered = category === 'all' ? data : data.filter((c) => c.category === category);
@@ -1,18 +1,26 @@
1
1
  import { z } from 'zod';
2
2
  import { loadJSON } from '../lib/load-data.js';
3
- import { DocsEntrySchema } from '../lib/schemas.js';
4
- import { searchDocs } from '../lib/search.js';
3
+ import { DocsEntrySchema, ComponentInfoSchema, PropsSystemDataSchema } from '../lib/schemas.js';
4
+ import { buildAliasMap, buildCssPropertyMap, searchDocs } from '../lib/search.js';
5
5
  import { success, error, READ_ONLY_ANNOTATIONS } from '../lib/response.js';
6
6
  const DOC_CATEGORIES = ['all', 'core-components', 'modules', 'props', 'ui', 'guide'];
7
7
  export function registerSearchDocs(server) {
8
- server.tool('search_docs', "Search lism-css documentation by keyword. Returns matching pages with relevance scores. Use this when other tools don't return the information you need, or to discover available components and features.", {
9
- query: z.string().describe('Search query (keywords separated by spaces).'),
10
- category: z.enum(DOC_CATEGORIES).default('all').describe('Filter by documentation category.'),
11
- limit: z.number().int().min(1).max(20).default(10).describe('Maximum number of results to return.'),
12
- }, READ_ONLY_ANNOTATIONS, ({ query, category, limit }) => {
8
+ server.registerTool('search_docs', {
9
+ description: "Search lism-css documentation by keyword. Returns matching pages with relevance scores. Supports CSS property names (e.g. 'font-size', 'padding') which are automatically expanded to corresponding lism prop names. Use this when other tools don't return the information you need, or to discover available components and features.",
10
+ inputSchema: {
11
+ query: z.string().describe('Search query (keywords separated by spaces). CSS property names like "font-size" are also accepted.'),
12
+ category: z.enum(DOC_CATEGORIES).default('all').describe('Filter by documentation category.'),
13
+ limit: z.number().int().min(1).max(20).default(10).describe('Maximum number of results to return.'),
14
+ },
15
+ annotations: READ_ONLY_ANNOTATIONS,
16
+ }, ({ query, category, limit }) => {
13
17
  try {
14
18
  const entries = loadJSON('docs-index.json', z.array(DocsEntrySchema));
15
- const results = searchDocs(entries, query, category, limit);
19
+ const components = loadJSON('components.json', z.array(ComponentInfoSchema));
20
+ const propsData = loadJSON('props-system.json', PropsSystemDataSchema);
21
+ const aliasMap = buildAliasMap(components);
22
+ const cssPropertyMap = buildCssPropertyMap(propsData.categories);
23
+ const results = searchDocs(entries, query, { category, limit, aliasMap, cssPropertyMap });
16
24
  return success({ query, results });
17
25
  }
18
26
  catch (e) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lism-css/mcp",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "MCP server for lism-css documentation and API reference.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -12,13 +12,13 @@
12
12
  "bin"
13
13
  ],
14
14
  "dependencies": {
15
- "@modelcontextprotocol/sdk": "^1.18.1",
16
- "zod": "^3.24.0"
15
+ "@modelcontextprotocol/sdk": "^1.27.1",
16
+ "zod": "^3.25.76"
17
17
  },
18
18
  "devDependencies": {
19
- "@types/node": "^22.0.0",
19
+ "@types/node": "^22.19.15",
20
20
  "typescript": "~5.8.3",
21
- "vitest": "^4.0.18"
21
+ "vitest": "^4.1.0"
22
22
  },
23
23
  "license": "MIT",
24
24
  "scripts": {