@shuji-bonji/w3c-mcp 0.1.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.
Files changed (56) hide show
  1. package/LICENSE +21 -0
  2. package/README.ja.md +246 -0
  3. package/README.md +246 -0
  4. package/dist/data/loader.d.ts +88 -0
  5. package/dist/data/loader.d.ts.map +1 -0
  6. package/dist/data/loader.js +165 -0
  7. package/dist/data/loader.js.map +1 -0
  8. package/dist/errors/index.d.ts +50 -0
  9. package/dist/errors/index.d.ts.map +1 -0
  10. package/dist/errors/index.js +116 -0
  11. package/dist/errors/index.js.map +1 -0
  12. package/dist/index.d.ts +7 -0
  13. package/dist/index.d.ts.map +1 -0
  14. package/dist/index.js +307 -0
  15. package/dist/index.js.map +1 -0
  16. package/dist/schemas/index.d.ts +97 -0
  17. package/dist/schemas/index.d.ts.map +1 -0
  18. package/dist/schemas/index.js +53 -0
  19. package/dist/schemas/index.js.map +1 -0
  20. package/dist/tools/get-css.d.ts +30 -0
  21. package/dist/tools/get-css.d.ts.map +1 -0
  22. package/dist/tools/get-css.js +99 -0
  23. package/dist/tools/get-css.js.map +1 -0
  24. package/dist/tools/get-elements.d.ts +14 -0
  25. package/dist/tools/get-elements.d.ts.map +1 -0
  26. package/dist/tools/get-elements.js +56 -0
  27. package/dist/tools/get-elements.js.map +1 -0
  28. package/dist/tools/get-pwa-specs.d.ts +10 -0
  29. package/dist/tools/get-pwa-specs.d.ts.map +1 -0
  30. package/dist/tools/get-pwa-specs.js +100 -0
  31. package/dist/tools/get-pwa-specs.js.map +1 -0
  32. package/dist/tools/get-spec.d.ts +10 -0
  33. package/dist/tools/get-spec.d.ts.map +1 -0
  34. package/dist/tools/get-spec.js +58 -0
  35. package/dist/tools/get-spec.js.map +1 -0
  36. package/dist/tools/get-webidl.d.ts +9 -0
  37. package/dist/tools/get-webidl.d.ts.map +1 -0
  38. package/dist/tools/get-webidl.js +50 -0
  39. package/dist/tools/get-webidl.js.map +1 -0
  40. package/dist/tools/list-specs.d.ts +6 -0
  41. package/dist/tools/list-specs.d.ts.map +1 -0
  42. package/dist/tools/list-specs.js +38 -0
  43. package/dist/tools/list-specs.js.map +1 -0
  44. package/dist/tools/search-specs.d.ts +16 -0
  45. package/dist/tools/search-specs.d.ts.map +1 -0
  46. package/dist/tools/search-specs.js +117 -0
  47. package/dist/tools/search-specs.js.map +1 -0
  48. package/dist/types/index.d.ts +85 -0
  49. package/dist/types/index.d.ts.map +1 -0
  50. package/dist/types/index.js +5 -0
  51. package/dist/types/index.js.map +1 -0
  52. package/dist/utils/logger.d.ts +49 -0
  53. package/dist/utils/logger.d.ts.map +1 -0
  54. package/dist/utils/logger.js +113 -0
  55. package/dist/utils/logger.js.map +1 -0
  56. package/package.json +53 -0
@@ -0,0 +1,165 @@
1
+ /**
2
+ * Data loader for web-specs and webref packages
3
+ *
4
+ * Performance improvements:
5
+ * - Lazy loading with singleton pattern
6
+ * - Promise-based caching to prevent duplicate loads
7
+ * - Parallel loading support
8
+ * - Memory-efficient data structures
9
+ */
10
+ import { createRequire } from 'module';
11
+ const require = createRequire(import.meta.url);
12
+ // ============================================
13
+ // Singleton cache with Promise-based loading
14
+ // Prevents duplicate loads when multiple requests come in simultaneously
15
+ // ============================================
16
+ let specsPromise = null;
17
+ let idlPromise = null;
18
+ let cssPromise = null;
19
+ let elementsPromise = null;
20
+ // Shortname index for O(1) lookup
21
+ let specsIndex = null;
22
+ let seriesIndex = null;
23
+ /**
24
+ * Load specs with singleton promise pattern
25
+ * Multiple simultaneous calls share the same loading promise
26
+ */
27
+ export async function loadSpecs() {
28
+ if (!specsPromise) {
29
+ specsPromise = Promise.resolve().then(() => {
30
+ const specs = require('web-specs');
31
+ // Build indices for faster lookup
32
+ buildSpecIndices(specs);
33
+ return specs;
34
+ });
35
+ }
36
+ return specsPromise;
37
+ }
38
+ /**
39
+ * Build indices for O(1) spec lookup by shortname
40
+ */
41
+ function buildSpecIndices(specs) {
42
+ specsIndex = new Map();
43
+ seriesIndex = new Map();
44
+ for (const spec of specs) {
45
+ specsIndex.set(spec.shortname, spec);
46
+ if (spec.series?.shortname) {
47
+ // Only set if not already set (prefer exact match)
48
+ if (!seriesIndex.has(spec.series.shortname)) {
49
+ seriesIndex.set(spec.series.shortname, spec);
50
+ }
51
+ }
52
+ }
53
+ }
54
+ /**
55
+ * Find a spec by shortname - O(1) with index
56
+ */
57
+ export async function findSpec(shortname) {
58
+ await loadSpecs(); // Ensure indices are built
59
+ // Try exact match first (O(1))
60
+ if (specsIndex?.has(shortname)) {
61
+ return specsIndex.get(shortname);
62
+ }
63
+ // Try series shortname (O(1))
64
+ if (seriesIndex?.has(shortname)) {
65
+ return seriesIndex.get(shortname);
66
+ }
67
+ // Fallback to partial match (O(n) - only when necessary)
68
+ const specs = await loadSpecs();
69
+ return specs.find(s => s.shortname.includes(shortname) ||
70
+ shortname.includes(s.shortname));
71
+ }
72
+ /**
73
+ * Load WebIDL with singleton promise pattern
74
+ */
75
+ export async function loadWebIDLRaw() {
76
+ if (!idlPromise) {
77
+ idlPromise = (async () => {
78
+ try {
79
+ const { readFileSync } = await import('fs');
80
+ const webrefIdl = require('@webref/idl');
81
+ const idlFiles = await webrefIdl.listAll();
82
+ const result = {};
83
+ for (const [shortname, file] of Object.entries(idlFiles)) {
84
+ try {
85
+ result[shortname] = readFileSync(file.path, 'utf8');
86
+ }
87
+ catch {
88
+ // Skip files that can't be read
89
+ }
90
+ }
91
+ return result;
92
+ }
93
+ catch (error) {
94
+ console.error('Error loading raw WebIDL:', error);
95
+ return {};
96
+ }
97
+ })();
98
+ }
99
+ return idlPromise;
100
+ }
101
+ /**
102
+ * Load CSS data with singleton promise pattern
103
+ */
104
+ export async function loadCSS() {
105
+ if (!cssPromise) {
106
+ cssPromise = (async () => {
107
+ try {
108
+ const webrefCss = require('@webref/css');
109
+ const data = await webrefCss.listAll();
110
+ return data;
111
+ }
112
+ catch (error) {
113
+ console.error('Error loading CSS data:', error);
114
+ return { properties: [], functions: [], types: [], selectors: [], atrules: [] };
115
+ }
116
+ })();
117
+ }
118
+ return cssPromise;
119
+ }
120
+ /**
121
+ * Load elements data with singleton promise pattern
122
+ */
123
+ export async function loadElements() {
124
+ if (!elementsPromise) {
125
+ elementsPromise = (async () => {
126
+ try {
127
+ const webrefElements = require('@webref/elements');
128
+ const data = await webrefElements.listAll();
129
+ return data;
130
+ }
131
+ catch (error) {
132
+ console.error('Error loading elements data:', error);
133
+ return {};
134
+ }
135
+ })();
136
+ }
137
+ return elementsPromise;
138
+ }
139
+ // ============================================
140
+ // Preload function for warming up cache
141
+ // ============================================
142
+ /**
143
+ * Preload all data in parallel
144
+ * Call this at server startup for better first-request performance
145
+ */
146
+ export async function preloadAll() {
147
+ await Promise.all([
148
+ loadSpecs(),
149
+ loadWebIDLRaw(),
150
+ loadCSS(),
151
+ loadElements()
152
+ ]);
153
+ }
154
+ // ============================================
155
+ // Cache invalidation (for testing/development)
156
+ // ============================================
157
+ export function clearCache() {
158
+ specsPromise = null;
159
+ idlPromise = null;
160
+ cssPromise = null;
161
+ elementsPromise = null;
162
+ specsIndex = null;
163
+ seriesIndex = null;
164
+ }
165
+ //# sourceMappingURL=loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/data/loader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Custom error classes for W3C MCP Server
3
+ */
4
+ import { z } from 'zod';
5
+ /**
6
+ * Base class for W3C MCP errors
7
+ */
8
+ export declare class W3CMCPError extends Error {
9
+ constructor(message: string);
10
+ }
11
+ /**
12
+ * Spec not found error with suggestions
13
+ */
14
+ export declare class SpecNotFoundError extends W3CMCPError {
15
+ suggestions?: string[];
16
+ constructor(shortname: string, suggestions?: string[]);
17
+ }
18
+ /**
19
+ * WebIDL not found error
20
+ */
21
+ export declare class WebIDLNotFoundError extends W3CMCPError {
22
+ constructor(shortname: string);
23
+ }
24
+ /**
25
+ * CSS data not found error
26
+ */
27
+ export declare class CSSNotFoundError extends W3CMCPError {
28
+ constructor(spec: string, availableSpecs?: string[]);
29
+ }
30
+ /**
31
+ * Elements data not found error
32
+ */
33
+ export declare class ElementsNotFoundError extends W3CMCPError {
34
+ constructor(spec: string, availableSpecs?: string[]);
35
+ }
36
+ /**
37
+ * Validation error wrapper
38
+ */
39
+ export declare class ValidationError extends W3CMCPError {
40
+ zodError: z.ZodError;
41
+ constructor(zodError: z.ZodError);
42
+ }
43
+ /**
44
+ * Format error response for MCP
45
+ */
46
+ export declare function formatErrorResponse(error: unknown): {
47
+ text: string;
48
+ errorType: string;
49
+ };
50
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/errors/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;GAEG;AACH,qBAAa,WAAY,SAAQ,KAAK;gBACxB,OAAO,EAAE,MAAM;CAI5B;AAED;;GAEG;AACH,qBAAa,iBAAkB,SAAQ,WAAW;IACzC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;gBAElB,SAAS,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,EAAE;CAQtD;AAED;;GAEG;AACH,qBAAa,mBAAoB,SAAQ,WAAW;gBACtC,SAAS,EAAE,MAAM;CAI9B;AAED;;GAEG;AACH,qBAAa,gBAAiB,SAAQ,WAAW;gBACnC,IAAI,EAAE,MAAM,EAAE,cAAc,CAAC,EAAE,MAAM,EAAE;CAOpD;AAED;;GAEG;AACH,qBAAa,qBAAsB,SAAQ,WAAW;gBACxC,IAAI,EAAE,MAAM,EAAE,cAAc,CAAC,EAAE,MAAM,EAAE;CAOpD;AAED;;GAEG;AACH,qBAAa,eAAgB,SAAQ,WAAW;IACvC,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAAC;gBAEhB,QAAQ,EAAE,CAAC,CAAC,QAAQ;CAMjC;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CA4CvF"}
@@ -0,0 +1,116 @@
1
+ /**
2
+ * Custom error classes for W3C MCP Server
3
+ */
4
+ /**
5
+ * Base class for W3C MCP errors
6
+ */
7
+ export class W3CMCPError extends Error {
8
+ constructor(message) {
9
+ super(message);
10
+ this.name = 'W3CMCPError';
11
+ }
12
+ }
13
+ /**
14
+ * Spec not found error with suggestions
15
+ */
16
+ export class SpecNotFoundError extends W3CMCPError {
17
+ suggestions;
18
+ constructor(shortname, suggestions) {
19
+ const message = suggestions?.length
20
+ ? `Specification "${shortname}" not found. Did you mean: ${suggestions.join(', ')}?`
21
+ : `Specification "${shortname}" not found.`;
22
+ super(message);
23
+ this.name = 'SpecNotFoundError';
24
+ this.suggestions = suggestions;
25
+ }
26
+ }
27
+ /**
28
+ * WebIDL not found error
29
+ */
30
+ export class WebIDLNotFoundError extends W3CMCPError {
31
+ constructor(shortname) {
32
+ super(`WebIDL not found for "${shortname}". This specification might not have WebIDL definitions.`);
33
+ this.name = 'WebIDLNotFoundError';
34
+ }
35
+ }
36
+ /**
37
+ * CSS data not found error
38
+ */
39
+ export class CSSNotFoundError extends W3CMCPError {
40
+ constructor(spec, availableSpecs) {
41
+ const message = availableSpecs?.length
42
+ ? `CSS data not found for "${spec}". Available CSS specs: ${availableSpecs.slice(0, 10).join(', ')}...`
43
+ : `CSS data not found for "${spec}".`;
44
+ super(message);
45
+ this.name = 'CSSNotFoundError';
46
+ }
47
+ }
48
+ /**
49
+ * Elements data not found error
50
+ */
51
+ export class ElementsNotFoundError extends W3CMCPError {
52
+ constructor(spec, availableSpecs) {
53
+ const message = availableSpecs?.length
54
+ ? `Elements data not found for "${spec}". Available specs: ${availableSpecs.join(', ')}`
55
+ : `Elements data not found for "${spec}".`;
56
+ super(message);
57
+ this.name = 'ElementsNotFoundError';
58
+ }
59
+ }
60
+ /**
61
+ * Validation error wrapper
62
+ */
63
+ export class ValidationError extends W3CMCPError {
64
+ zodError;
65
+ constructor(zodError) {
66
+ const issues = zodError.issues.map(i => `${i.path.join('.')}: ${i.message}`).join('; ');
67
+ super(`Validation error: ${issues}`);
68
+ this.name = 'ValidationError';
69
+ this.zodError = zodError;
70
+ }
71
+ }
72
+ /**
73
+ * Format error response for MCP
74
+ */
75
+ export function formatErrorResponse(error) {
76
+ if (error instanceof ValidationError) {
77
+ return {
78
+ text: JSON.stringify({
79
+ error: 'ValidationError',
80
+ message: error.message,
81
+ issues: error.zodError.issues
82
+ }, null, 2),
83
+ errorType: 'ValidationError'
84
+ };
85
+ }
86
+ if (error instanceof SpecNotFoundError) {
87
+ return {
88
+ text: JSON.stringify({
89
+ error: 'SpecNotFoundError',
90
+ message: error.message,
91
+ suggestions: error.suggestions
92
+ }, null, 2),
93
+ errorType: 'SpecNotFoundError'
94
+ };
95
+ }
96
+ if (error instanceof W3CMCPError) {
97
+ return {
98
+ text: JSON.stringify({
99
+ error: error.name,
100
+ message: error.message
101
+ }, null, 2),
102
+ errorType: error.name
103
+ };
104
+ }
105
+ if (error instanceof Error) {
106
+ return {
107
+ text: `Error: ${error.message}`,
108
+ errorType: 'Error'
109
+ };
110
+ }
111
+ return {
112
+ text: 'An unknown error occurred',
113
+ errorType: 'UnknownError'
114
+ };
115
+ }
116
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/errors/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * W3C MCP Server
4
+ * Provides access to W3C/WHATWG/IETF web specifications via MCP protocol
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;GAGG"}
package/dist/index.js ADDED
@@ -0,0 +1,307 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * W3C MCP Server
4
+ * Provides access to W3C/WHATWG/IETF web specifications via MCP protocol
5
+ */
6
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
7
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
8
+ import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
9
+ import { listSpecs } from './tools/list-specs.js';
10
+ import { getSpec, getSpecDependencies } from './tools/get-spec.js';
11
+ import { searchSpecs } from './tools/search-specs.js';
12
+ import { getWebIDL, listWebIDLSpecs } from './tools/get-webidl.js';
13
+ import { getCSSProperties, searchCSSProperty, listCSSSpecs } from './tools/get-css.js';
14
+ import { getElements, searchElement, listElementSpecs } from './tools/get-elements.js';
15
+ import { getPwaSpecs, getCorePwaSpecs } from './tools/get-pwa-specs.js';
16
+ import { preloadAll } from './data/loader.js';
17
+ // Validation schemas
18
+ import { ListSpecsSchema, GetSpecSchema, SearchSpecsSchema, GetWebIDLSchema, GetCSSPropertiesSchema, GetElementsSchema, GetPwaSpecsSchema, GetSpecDependenciesSchema, validateInput, } from './schemas/index.js';
19
+ // Error handling
20
+ import { formatErrorResponse, ValidationError } from './errors/index.js';
21
+ // Logging
22
+ import { info, logToolCall, logToolResult, PerformanceTimer } from './utils/logger.js';
23
+ const server = new Server({
24
+ name: 'w3c-mcp',
25
+ version: '0.1.0',
26
+ }, {
27
+ capabilities: {
28
+ tools: {},
29
+ },
30
+ });
31
+ // Tool definitions
32
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
33
+ tools: [
34
+ {
35
+ name: 'list_w3c_specs',
36
+ description: 'List W3C/WHATWG/IETF web specifications with optional filtering by organization, keyword, or category',
37
+ inputSchema: {
38
+ type: 'object',
39
+ properties: {
40
+ organization: {
41
+ type: 'string',
42
+ enum: ['W3C', 'WHATWG', 'IETF', 'all'],
43
+ description: 'Filter by standards organization',
44
+ },
45
+ keyword: {
46
+ type: 'string',
47
+ description: 'Filter by keyword in title or shortname',
48
+ },
49
+ category: {
50
+ type: 'string',
51
+ description: 'Filter by category (e.g., "browser")',
52
+ },
53
+ limit: {
54
+ type: 'number',
55
+ description: 'Maximum number of results (default: 50)',
56
+ },
57
+ },
58
+ },
59
+ },
60
+ {
61
+ name: 'get_w3c_spec',
62
+ description: 'Get detailed information about a specific web specification including URLs, status, repository, and test info',
63
+ inputSchema: {
64
+ type: 'object',
65
+ properties: {
66
+ shortname: {
67
+ type: 'string',
68
+ description: 'Specification shortname (e.g., "service-workers", "appmanifest", "fetch", "dom")',
69
+ },
70
+ },
71
+ required: ['shortname'],
72
+ },
73
+ },
74
+ {
75
+ name: 'search_w3c_specs',
76
+ description: 'Search web specifications by query string, searching in title, shortname, and description',
77
+ inputSchema: {
78
+ type: 'object',
79
+ properties: {
80
+ query: {
81
+ type: 'string',
82
+ description: 'Search query (e.g., "service worker", "manifest", "storage")',
83
+ },
84
+ limit: {
85
+ type: 'number',
86
+ description: 'Maximum number of results (default: 20)',
87
+ },
88
+ },
89
+ required: ['query'],
90
+ },
91
+ },
92
+ {
93
+ name: 'get_webidl',
94
+ description: 'Get WebIDL interface definitions for a specification. WebIDL defines the JavaScript APIs.',
95
+ inputSchema: {
96
+ type: 'object',
97
+ properties: {
98
+ shortname: {
99
+ type: 'string',
100
+ description: 'Specification shortname (e.g., "service-workers", "fetch", "dom")',
101
+ },
102
+ },
103
+ required: ['shortname'],
104
+ },
105
+ },
106
+ {
107
+ name: 'list_webidl_specs',
108
+ description: 'List all specifications that have WebIDL definitions available',
109
+ inputSchema: {
110
+ type: 'object',
111
+ properties: {},
112
+ },
113
+ },
114
+ {
115
+ name: 'get_css_properties',
116
+ description: 'Get CSS property definitions from a specific spec or all specs',
117
+ inputSchema: {
118
+ type: 'object',
119
+ properties: {
120
+ spec: {
121
+ type: 'string',
122
+ description: 'Specification shortname (e.g., "css-grid-1", "css-flexbox-1"). If omitted, returns all CSS properties.',
123
+ },
124
+ property: {
125
+ type: 'string',
126
+ description: 'Search for a specific CSS property by name',
127
+ },
128
+ },
129
+ },
130
+ },
131
+ {
132
+ name: 'list_css_specs',
133
+ description: 'List all CSS specifications that have property definitions available',
134
+ inputSchema: {
135
+ type: 'object',
136
+ properties: {},
137
+ },
138
+ },
139
+ {
140
+ name: 'get_html_elements',
141
+ description: 'Get HTML element definitions from a specific spec or all specs',
142
+ inputSchema: {
143
+ type: 'object',
144
+ properties: {
145
+ spec: {
146
+ type: 'string',
147
+ description: 'Specification shortname (e.g., "html", "svg"). If omitted, returns all elements.',
148
+ },
149
+ element: {
150
+ type: 'string',
151
+ description: 'Search for a specific element by name (e.g., "video", "canvas")',
152
+ },
153
+ },
154
+ },
155
+ },
156
+ {
157
+ name: 'list_element_specs',
158
+ description: 'List all specifications that have HTML element definitions available',
159
+ inputSchema: {
160
+ type: 'object',
161
+ properties: {},
162
+ },
163
+ },
164
+ {
165
+ name: 'get_pwa_specs',
166
+ description: 'Get all Progressive Web App (PWA) related specifications including Service Worker, Web App Manifest, Push API, Background Sync, etc.',
167
+ inputSchema: {
168
+ type: 'object',
169
+ properties: {
170
+ coreOnly: {
171
+ type: 'boolean',
172
+ description: 'If true, return only the core PWA specs (Service Worker, Manifest, Push, Notifications)',
173
+ },
174
+ },
175
+ },
176
+ },
177
+ {
178
+ name: 'get_spec_dependencies',
179
+ description: 'Get dependency information for a specification (which specs it depends on and which depend on it)',
180
+ inputSchema: {
181
+ type: 'object',
182
+ properties: {
183
+ shortname: {
184
+ type: 'string',
185
+ description: 'Specification shortname',
186
+ },
187
+ },
188
+ required: ['shortname'],
189
+ },
190
+ },
191
+ ],
192
+ }));
193
+ // Tool execution with validation and error handling
194
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
195
+ const { name, arguments: args } = request.params;
196
+ const timer = new PerformanceTimer(`tool:${name}`);
197
+ logToolCall(name, args);
198
+ try {
199
+ let result;
200
+ switch (name) {
201
+ case 'list_w3c_specs': {
202
+ const validation = validateInput(ListSpecsSchema, args);
203
+ if (!validation.success)
204
+ throw new ValidationError(validation.error);
205
+ result = await listSpecs(validation.data);
206
+ break;
207
+ }
208
+ case 'get_w3c_spec': {
209
+ const validation = validateInput(GetSpecSchema, args);
210
+ if (!validation.success)
211
+ throw new ValidationError(validation.error);
212
+ result = await getSpec(validation.data.shortname);
213
+ break;
214
+ }
215
+ case 'search_w3c_specs': {
216
+ const validation = validateInput(SearchSpecsSchema, args);
217
+ if (!validation.success)
218
+ throw new ValidationError(validation.error);
219
+ result = await searchSpecs(validation.data.query, validation.data.limit);
220
+ break;
221
+ }
222
+ case 'get_webidl': {
223
+ const validation = validateInput(GetWebIDLSchema, args);
224
+ if (!validation.success)
225
+ throw new ValidationError(validation.error);
226
+ const idl = await getWebIDL(validation.data.shortname);
227
+ timer.end();
228
+ logToolResult(name, idl.length);
229
+ return { content: [{ type: 'text', text: idl }] };
230
+ }
231
+ case 'list_webidl_specs': {
232
+ result = await listWebIDLSpecs();
233
+ break;
234
+ }
235
+ case 'get_css_properties': {
236
+ const validation = validateInput(GetCSSPropertiesSchema, args);
237
+ if (!validation.success)
238
+ throw new ValidationError(validation.error);
239
+ result = validation.data.property
240
+ ? await searchCSSProperty(validation.data.property)
241
+ : await getCSSProperties(validation.data.spec);
242
+ break;
243
+ }
244
+ case 'list_css_specs': {
245
+ result = await listCSSSpecs();
246
+ break;
247
+ }
248
+ case 'get_html_elements': {
249
+ const validation = validateInput(GetElementsSchema, args);
250
+ if (!validation.success)
251
+ throw new ValidationError(validation.error);
252
+ result = validation.data.element
253
+ ? await searchElement(validation.data.element)
254
+ : await getElements(validation.data.spec);
255
+ break;
256
+ }
257
+ case 'list_element_specs': {
258
+ result = await listElementSpecs();
259
+ break;
260
+ }
261
+ case 'get_pwa_specs': {
262
+ const validation = validateInput(GetPwaSpecsSchema, args);
263
+ if (!validation.success)
264
+ throw new ValidationError(validation.error);
265
+ result = validation.data.coreOnly ? await getCorePwaSpecs() : await getPwaSpecs();
266
+ break;
267
+ }
268
+ case 'get_spec_dependencies': {
269
+ const validation = validateInput(GetSpecDependenciesSchema, args);
270
+ if (!validation.success)
271
+ throw new ValidationError(validation.error);
272
+ result = await getSpecDependencies(validation.data.shortname);
273
+ break;
274
+ }
275
+ default:
276
+ throw new Error(`Unknown tool: ${name}`);
277
+ }
278
+ const text = JSON.stringify(result, null, 2);
279
+ timer.end();
280
+ logToolResult(name, text.length);
281
+ return { content: [{ type: 'text', text }] };
282
+ }
283
+ catch (error) {
284
+ timer.end();
285
+ const formatted = formatErrorResponse(error);
286
+ return {
287
+ content: [{ type: 'text', text: formatted.text }],
288
+ isError: true,
289
+ };
290
+ }
291
+ });
292
+ // Start server
293
+ async function main() {
294
+ info('W3C MCP Server: Preloading data...');
295
+ const timer = new PerformanceTimer('preload');
296
+ await preloadAll();
297
+ const loadTime = timer.end();
298
+ info(`W3C MCP Server: Data loaded in ${loadTime}ms`);
299
+ const transport = new StdioServerTransport();
300
+ await server.connect(transport);
301
+ info('W3C MCP Server running on stdio');
302
+ }
303
+ main().catch((err) => {
304
+ console.error('Failed to start server:', err);
305
+ process.exit(1);
306
+ });
307
+ //# sourceMappingURL=index.js.map