@omnitend/dashboard-for-laravel 0.4.7

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 (149) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +397 -0
  3. package/dist/components/base/DAccordion.vue.d.ts +12 -0
  4. package/dist/components/base/DAccordionItem.vue.d.ts +12 -0
  5. package/dist/components/base/DAlert.vue.d.ts +12 -0
  6. package/dist/components/base/DAvatar.vue.d.ts +12 -0
  7. package/dist/components/base/DBadge.vue.d.ts +12 -0
  8. package/dist/components/base/DBreadcrumb.vue.d.ts +12 -0
  9. package/dist/components/base/DButton.vue.d.ts +29 -0
  10. package/dist/components/base/DButtonGroup.vue.d.ts +12 -0
  11. package/dist/components/base/DButtonToolbar.vue.d.ts +12 -0
  12. package/dist/components/base/DCard.vue.d.ts +12 -0
  13. package/dist/components/base/DCarousel.vue.d.ts +12 -0
  14. package/dist/components/base/DCarouselSlide.vue.d.ts +12 -0
  15. package/dist/components/base/DCol.vue.d.ts +12 -0
  16. package/dist/components/base/DCollapse.vue.d.ts +12 -0
  17. package/dist/components/base/DContainer.vue.d.ts +12 -0
  18. package/dist/components/base/DDropdown.vue.d.ts +12 -0
  19. package/dist/components/base/DDropdownDivider.vue.d.ts +2 -0
  20. package/dist/components/base/DDropdownItem.vue.d.ts +12 -0
  21. package/dist/components/base/DForm.vue.d.ts +12 -0
  22. package/dist/components/base/DFormCheckbox.vue.d.ts +12 -0
  23. package/dist/components/base/DFormGroup.vue.d.ts +12 -0
  24. package/dist/components/base/DFormInput.vue.d.ts +2 -0
  25. package/dist/components/base/DFormInvalidFeedback.vue.d.ts +12 -0
  26. package/dist/components/base/DFormRadio.vue.d.ts +12 -0
  27. package/dist/components/base/DFormSelect.vue.d.ts +12 -0
  28. package/dist/components/base/DFormSpinbutton.vue.d.ts +12 -0
  29. package/dist/components/base/DFormTags.vue.d.ts +12 -0
  30. package/dist/components/base/DFormText.vue.d.ts +12 -0
  31. package/dist/components/base/DFormTextarea.vue.d.ts +2 -0
  32. package/dist/components/base/DImage.vue.d.ts +12 -0
  33. package/dist/components/base/DInputGroup.vue.d.ts +12 -0
  34. package/dist/components/base/DLink.vue.d.ts +12 -0
  35. package/dist/components/base/DListGroup.vue.d.ts +12 -0
  36. package/dist/components/base/DListGroupItem.vue.d.ts +12 -0
  37. package/dist/components/base/DModal.vue.d.ts +12 -0
  38. package/dist/components/base/DNav.vue.d.ts +12 -0
  39. package/dist/components/base/DNavItem.vue.d.ts +12 -0
  40. package/dist/components/base/DNavbar.vue.d.ts +12 -0
  41. package/dist/components/base/DNavbarBrand.vue.d.ts +12 -0
  42. package/dist/components/base/DNavbarNav.vue.d.ts +12 -0
  43. package/dist/components/base/DNavbarToggle.vue.d.ts +12 -0
  44. package/dist/components/base/DOffcanvas.vue.d.ts +12 -0
  45. package/dist/components/base/DOverlay.vue.d.ts +12 -0
  46. package/dist/components/base/DPagination.vue.d.ts +2 -0
  47. package/dist/components/base/DPlaceholder.vue.d.ts +12 -0
  48. package/dist/components/base/DPopover.vue.d.ts +12 -0
  49. package/dist/components/base/DProgress.vue.d.ts +12 -0
  50. package/dist/components/base/DRow.vue.d.ts +12 -0
  51. package/dist/components/base/DSpinner.vue.d.ts +2 -0
  52. package/dist/components/base/DTab.vue.d.ts +12 -0
  53. package/dist/components/base/DTable.vue.d.ts +26 -0
  54. package/dist/components/base/DTabs.vue.d.ts +12 -0
  55. package/dist/components/base/DToast.vue.d.ts +12 -0
  56. package/dist/components/base/DToaster.vue.d.ts +12 -0
  57. package/dist/components/base/DTooltip.vue.d.ts +12 -0
  58. package/dist/components/extended/DXBasicForm.vue.d.ts +39 -0
  59. package/dist/components/extended/DXDashboard.vue.d.ts +52 -0
  60. package/dist/components/extended/DXDashboardNavbar.vue.d.ts +53 -0
  61. package/dist/components/extended/DXDashboardSidebar.vue.d.ts +37 -0
  62. package/dist/components/extended/DXForm.vue.d.ts +31 -0
  63. package/dist/components/extended/DXTable.vue.d.ts +190 -0
  64. package/dist/composables/defineForm.d.ts +35 -0
  65. package/dist/composables/useForm.d.ts +46 -0
  66. package/dist/composables/useToast.d.ts +1 -0
  67. package/dist/dashboard-for-laravel.js +17748 -0
  68. package/dist/dashboard-for-laravel.js.map +1 -0
  69. package/dist/dashboard-for-laravel.umd.cjs +11 -0
  70. package/dist/dashboard-for-laravel.umd.cjs.map +1 -0
  71. package/dist/index.d.ts +73 -0
  72. package/dist/style.css +5 -0
  73. package/dist/types/index.d.ts +37 -0
  74. package/dist/types/navigation.d.ts +17 -0
  75. package/dist/utils/api.d.ts +30 -0
  76. package/docs/public/api-reference.json +1932 -0
  77. package/docs/public/docs-map.md +85 -0
  78. package/docs/public/llms.txt +110 -0
  79. package/package.json +116 -0
  80. package/resources/css/theme.scss +219 -0
  81. package/resources/js/components/base/DAccordion.vue +21 -0
  82. package/resources/js/components/base/DAccordionItem.vue +14 -0
  83. package/resources/js/components/base/DAlert.vue +14 -0
  84. package/resources/js/components/base/DAvatar.vue +21 -0
  85. package/resources/js/components/base/DBadge.vue +14 -0
  86. package/resources/js/components/base/DBreadcrumb.vue +21 -0
  87. package/resources/js/components/base/DButton.vue +58 -0
  88. package/resources/js/components/base/DButtonGroup.vue +21 -0
  89. package/resources/js/components/base/DButtonToolbar.vue +21 -0
  90. package/resources/js/components/base/DCard.vue +35 -0
  91. package/resources/js/components/base/DCarousel.vue +21 -0
  92. package/resources/js/components/base/DCarouselSlide.vue +14 -0
  93. package/resources/js/components/base/DCol.vue +14 -0
  94. package/resources/js/components/base/DCollapse.vue +34 -0
  95. package/resources/js/components/base/DContainer.vue +14 -0
  96. package/resources/js/components/base/DDropdown.vue +16 -0
  97. package/resources/js/components/base/DDropdownDivider.vue +7 -0
  98. package/resources/js/components/base/DDropdownItem.vue +14 -0
  99. package/resources/js/components/base/DForm.vue +21 -0
  100. package/resources/js/components/base/DFormCheckbox.vue +14 -0
  101. package/resources/js/components/base/DFormGroup.vue +11 -0
  102. package/resources/js/components/base/DFormInput.vue +7 -0
  103. package/resources/js/components/base/DFormInvalidFeedback.vue +16 -0
  104. package/resources/js/components/base/DFormRadio.vue +21 -0
  105. package/resources/js/components/base/DFormSelect.vue +14 -0
  106. package/resources/js/components/base/DFormSpinbutton.vue +21 -0
  107. package/resources/js/components/base/DFormTags.vue +21 -0
  108. package/resources/js/components/base/DFormText.vue +16 -0
  109. package/resources/js/components/base/DFormTextarea.vue +7 -0
  110. package/resources/js/components/base/DImage.vue +21 -0
  111. package/resources/js/components/base/DInputGroup.vue +21 -0
  112. package/resources/js/components/base/DLink.vue +21 -0
  113. package/resources/js/components/base/DListGroup.vue +21 -0
  114. package/resources/js/components/base/DListGroupItem.vue +14 -0
  115. package/resources/js/components/base/DModal.vue +11 -0
  116. package/resources/js/components/base/DNav.vue +14 -0
  117. package/resources/js/components/base/DNavItem.vue +14 -0
  118. package/resources/js/components/base/DNavbar.vue +21 -0
  119. package/resources/js/components/base/DNavbarBrand.vue +14 -0
  120. package/resources/js/components/base/DNavbarNav.vue +14 -0
  121. package/resources/js/components/base/DNavbarToggle.vue +14 -0
  122. package/resources/js/components/base/DOffcanvas.vue +11 -0
  123. package/resources/js/components/base/DOverlay.vue +21 -0
  124. package/resources/js/components/base/DPagination.vue +7 -0
  125. package/resources/js/components/base/DPlaceholder.vue +21 -0
  126. package/resources/js/components/base/DPopover.vue +21 -0
  127. package/resources/js/components/base/DProgress.vue +21 -0
  128. package/resources/js/components/base/DRow.vue +14 -0
  129. package/resources/js/components/base/DSpinner.vue +7 -0
  130. package/resources/js/components/base/DTab.vue +14 -0
  131. package/resources/js/components/base/DTable.vue +62 -0
  132. package/resources/js/components/base/DTabs.vue +21 -0
  133. package/resources/js/components/base/DToast.vue +16 -0
  134. package/resources/js/components/base/DToaster.vue +16 -0
  135. package/resources/js/components/base/DTooltip.vue +21 -0
  136. package/resources/js/components/extended/DXBasicForm.vue +177 -0
  137. package/resources/js/components/extended/DXDashboard.vue +208 -0
  138. package/resources/js/components/extended/DXDashboardNavbar.vue +112 -0
  139. package/resources/js/components/extended/DXDashboardSidebar.vue +233 -0
  140. package/resources/js/components/extended/DXForm.vue +44 -0
  141. package/resources/js/components/extended/DXTable.vue +1345 -0
  142. package/resources/js/composables/defineForm.ts +78 -0
  143. package/resources/js/composables/useForm.ts +272 -0
  144. package/resources/js/composables/useToast.ts +1 -0
  145. package/resources/js/index.ts +118 -0
  146. package/resources/js/types/index.ts +61 -0
  147. package/resources/js/types/navigation.ts +19 -0
  148. package/resources/js/utils/api.ts +182 -0
  149. package/scripts/mcp-server.mjs +359 -0
@@ -0,0 +1,182 @@
1
+ export interface ApiError {
2
+ message: string;
3
+ errors: Record<string, string[]>;
4
+ status: number;
5
+ }
6
+
7
+ export interface ApiResponse<T = unknown> {
8
+ data: T;
9
+ response: Response;
10
+ }
11
+
12
+ interface RequestOptions extends Omit<RequestInit, "body"> {
13
+ headers?: Record<string, string>;
14
+ body?: BodyInit | null; // allow FormData/Blob/etc.
15
+ }
16
+
17
+ class ApiClient {
18
+ private baseURL = "";
19
+ private defaultHeaders: Record<string, string> = {
20
+ Accept: "application/json",
21
+ "Content-Type": "application/json", // removed automatically for FormData
22
+ "X-Requested-With": "XMLHttpRequest",
23
+ };
24
+
25
+ setBaseURL(url: string) {
26
+ this.baseURL = url.replace(/\/+$/, "");
27
+ }
28
+ setDefaultHeader(key: string, value: string) {
29
+ this.defaultHeaders[key] = value;
30
+ }
31
+
32
+ private getCsrfToken(): string {
33
+ if (typeof document === 'undefined') {
34
+ return "";
35
+ }
36
+ const el = document.querySelector('meta[name="csrf-token"]');
37
+ return el?.getAttribute("content") ?? "";
38
+ }
39
+
40
+ private toQuery(params: Record<string, unknown> = {}): string {
41
+ const search = new URLSearchParams();
42
+ const append = (k: string, v: unknown) => {
43
+ if (v === undefined || v === null) return;
44
+ if (Array.isArray(v)) v.forEach((x) => append(`${k}[]`, x));
45
+ else if (typeof v === "object") {
46
+ for (const [ck, cv] of Object.entries(
47
+ v as Record<string, unknown>,
48
+ )) {
49
+ append(`${k}[${ck}]`, cv);
50
+ }
51
+ } else {
52
+ search.append(k, String(v));
53
+ }
54
+ };
55
+ for (const [k, v] of Object.entries(params)) append(k, v);
56
+ const qs = search.toString();
57
+ return qs ? `?${qs}` : "";
58
+ }
59
+
60
+ private handleError(response: Response, data: any): never {
61
+ const error: ApiError = {
62
+ message: data?.message ?? "An error occurred",
63
+ errors: (data?.errors as Record<string, string[]>) ?? {},
64
+ status: response.status,
65
+ };
66
+ switch (response.status) {
67
+ case 422:
68
+ error.message = data?.message ?? "Validation failed";
69
+ break;
70
+ case 401:
71
+ error.message = "Unauthenticated. Please log in.";
72
+ break;
73
+ case 403:
74
+ error.message = "Forbidden. You do not have permission.";
75
+ break;
76
+ case 404:
77
+ error.message = "Resource not found.";
78
+ break;
79
+ case 419:
80
+ error.message = "Page expired. Please refresh and try again.";
81
+ break;
82
+ case 500:
83
+ error.message = "Server error. Please try again later.";
84
+ break;
85
+ }
86
+ throw error;
87
+ }
88
+
89
+ async request<T = unknown>(
90
+ url: string,
91
+ options: RequestOptions = {},
92
+ ): Promise<ApiResponse<T>> {
93
+ const isFormData =
94
+ typeof FormData !== "undefined" && options.body instanceof FormData;
95
+
96
+ const headers: Record<string, string> = {
97
+ ...this.defaultHeaders,
98
+ ...(isFormData
99
+ ? {}
100
+ : { "Content-Type": this.defaultHeaders["Content-Type"] }),
101
+ "X-CSRF-TOKEN": this.getCsrfToken(),
102
+ ...options.headers,
103
+ };
104
+
105
+ // Let fetch set the multipart boundary if FormData
106
+ if (isFormData) delete headers["Content-Type"];
107
+
108
+ const config: RequestOptions = {
109
+ credentials: "same-origin",
110
+ ...options,
111
+ headers,
112
+ };
113
+
114
+ const resp = await fetch(this.baseURL + url, config);
115
+
116
+ // Fast-path for 204/205
117
+ if (resp.status === 204 || resp.status === 205) {
118
+ if (!resp.ok) {
119
+ this.handleError(resp, null);
120
+ }
121
+
122
+ return { data: undefined as unknown as T, response: resp };
123
+ }
124
+
125
+ const ctype = resp.headers.get("Content-Type") || "";
126
+ const isJson = /\bjson\b/i.test(ctype);
127
+ const parsed = isJson
128
+ ? await resp.json().catch(() => ({}))
129
+ : await resp.text();
130
+
131
+ if (!resp.ok) {
132
+ this.handleError(resp, parsed);
133
+ }
134
+
135
+ return { data: parsed as T, response: resp };
136
+ }
137
+
138
+ async get<T = unknown>(
139
+ url: string,
140
+ params: Record<string, unknown> = {},
141
+ options: Omit<RequestOptions, "method"> = {},
142
+ ) {
143
+ const full = `${url}${this.toQuery(params)}`;
144
+ return this.request<T>(full, { ...options, method: "GET" });
145
+ }
146
+
147
+ async post<T = unknown>(
148
+ url: string,
149
+ data: any = {},
150
+ options: Omit<RequestOptions, "method" | "body"> = {},
151
+ ) {
152
+ const body = data instanceof FormData ? data : JSON.stringify(data);
153
+ return this.request<T>(url, { ...options, method: "POST", body });
154
+ }
155
+
156
+ async put<T = unknown>(
157
+ url: string,
158
+ data: any = {},
159
+ options: Omit<RequestOptions, "method" | "body"> = {},
160
+ ) {
161
+ const body = data instanceof FormData ? data : JSON.stringify(data);
162
+ return this.request<T>(url, { ...options, method: "PUT", body });
163
+ }
164
+
165
+ async patch<T = unknown>(
166
+ url: string,
167
+ data: any = {},
168
+ options: Omit<RequestOptions, "method" | "body"> = {},
169
+ ) {
170
+ const body = data instanceof FormData ? data : JSON.stringify(data);
171
+ return this.request<T>(url, { ...options, method: "PATCH", body });
172
+ }
173
+
174
+ async delete<T = unknown>(
175
+ url: string,
176
+ options: Omit<RequestOptions, "method"> = {},
177
+ ) {
178
+ return this.request<T>(url, { ...options, method: "DELETE" });
179
+ }
180
+ }
181
+
182
+ export const api = new ApiClient();
@@ -0,0 +1,359 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * MCP Server for Dashboard for Laravel Documentation
5
+ *
6
+ * Provides AI agents with structured access to documentation via MCP tools.
7
+ * Works with Claude Desktop, Claude Code, and any MCP-compatible client.
8
+ */
9
+
10
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
11
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
12
+ import {
13
+ CallToolRequestSchema,
14
+ ListToolsRequestSchema,
15
+ } from '@modelcontextprotocol/sdk/types.js';
16
+ import { readFileSync, readdirSync, existsSync } from 'fs';
17
+ import { join, dirname } from 'path';
18
+ import { fileURLToPath } from 'url';
19
+
20
+ const __dirname = dirname(fileURLToPath(import.meta.url));
21
+ const rootDir = join(__dirname, '..');
22
+
23
+ // Load generated documentation files
24
+ function loadApiReference() {
25
+ const path = join(rootDir, 'docs/public/api-reference.json');
26
+ if (!existsSync(path)) {
27
+ throw new Error('API reference not found. Run: npm run docs:generate:ai');
28
+ }
29
+ return JSON.parse(readFileSync(path, 'utf8'));
30
+ }
31
+
32
+ function loadDocsMap() {
33
+ const path = join(rootDir, 'docs/public/docs-map.md');
34
+ if (!existsSync(path)) {
35
+ throw new Error('Docs map not found. Run: npm run docs:generate:ai');
36
+ }
37
+ return readFileSync(path, 'utf8');
38
+ }
39
+
40
+ function loadLlmsTxt() {
41
+ const path = join(rootDir, 'docs/public/llms.txt');
42
+ if (!existsSync(path)) {
43
+ throw new Error('llms.txt not found. Run: npm run docs:generate:ai');
44
+ }
45
+ return readFileSync(path, 'utf8');
46
+ }
47
+
48
+ // Read guide/documentation files
49
+ function readGuide(slug) {
50
+ const guidePath = join(rootDir, `docs/src/pages/guide/${slug}.md`);
51
+ if (!existsSync(guidePath)) {
52
+ return null;
53
+ }
54
+ return readFileSync(guidePath, 'utf8');
55
+ }
56
+
57
+ // Create MCP server
58
+ const server = new Server(
59
+ {
60
+ name: 'dashboard-for-laravel-docs',
61
+ version: '0.3.1',
62
+ },
63
+ {
64
+ capabilities: {
65
+ tools: {},
66
+ },
67
+ }
68
+ );
69
+
70
+ // List available tools
71
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
72
+ return {
73
+ tools: [
74
+ {
75
+ name: 'list_components',
76
+ description: 'List all components, optionally filtered by category (base/extended) or tag',
77
+ inputSchema: {
78
+ type: 'object',
79
+ properties: {
80
+ category: {
81
+ type: 'string',
82
+ enum: ['base', 'extended'],
83
+ description: 'Filter by component category',
84
+ },
85
+ tag: {
86
+ type: 'string',
87
+ description: 'Filter by tag (e.g., forms, tables, navigation)',
88
+ },
89
+ },
90
+ },
91
+ },
92
+ {
93
+ name: 'get_component',
94
+ description: 'Get detailed API information for a specific component (props, events, slots)',
95
+ inputSchema: {
96
+ type: 'object',
97
+ properties: {
98
+ name: {
99
+ type: 'string',
100
+ description: 'Component name (e.g., DButton, DXTable)',
101
+ },
102
+ },
103
+ required: ['name'],
104
+ },
105
+ },
106
+ {
107
+ name: 'search_components',
108
+ description: 'Search components by name or description',
109
+ inputSchema: {
110
+ type: 'object',
111
+ properties: {
112
+ query: {
113
+ type: 'string',
114
+ description: 'Search query',
115
+ },
116
+ },
117
+ required: ['query'],
118
+ },
119
+ },
120
+ {
121
+ name: 'get_guide',
122
+ description: 'Get a documentation guide (installation, forms, theming, typescript, getting-started)',
123
+ inputSchema: {
124
+ type: 'object',
125
+ properties: {
126
+ slug: {
127
+ type: 'string',
128
+ enum: ['installation', 'forms', 'theming', 'typescript', 'getting-started'],
129
+ description: 'Guide slug',
130
+ },
131
+ },
132
+ required: ['slug'],
133
+ },
134
+ },
135
+ {
136
+ name: 'get_overview',
137
+ description: 'Get complete documentation overview (llms.txt content)',
138
+ inputSchema: {
139
+ type: 'object',
140
+ properties: {},
141
+ },
142
+ },
143
+ {
144
+ name: 'get_docs_map',
145
+ description: 'Get hierarchical map of all available documentation',
146
+ inputSchema: {
147
+ type: 'object',
148
+ properties: {},
149
+ },
150
+ },
151
+ ],
152
+ };
153
+ });
154
+
155
+ // Handle tool calls
156
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
157
+ const { name, arguments: args } = request.params;
158
+
159
+ try {
160
+ switch (name) {
161
+ case 'list_components': {
162
+ const apiRef = loadApiReference();
163
+ let components = [
164
+ ...apiRef.components.base.map(c => ({ ...c, category: 'base' })),
165
+ ...apiRef.components.extended.map(c => ({ ...c, category: 'extended' })),
166
+ ];
167
+
168
+ // Filter by category
169
+ if (args.category) {
170
+ components = components.filter(c => c.category === args.category);
171
+ }
172
+
173
+ // Filter by tag (from frontmatter)
174
+ if (args.tag) {
175
+ const tag = args.tag.toLowerCase();
176
+ components = components.filter(c => {
177
+ const mdxPath = join(rootDir, `docs/src/pages/components/${c.category}/${c.name}.mdx`);
178
+ if (!existsSync(mdxPath)) return false;
179
+ const content = readFileSync(mdxPath, 'utf8');
180
+ const tagsMatch = content.match(/^tags:\s*(.+)$/m);
181
+ if (!tagsMatch) return false;
182
+ return tagsMatch[1].toLowerCase().includes(tag);
183
+ });
184
+ }
185
+
186
+ return {
187
+ content: [
188
+ {
189
+ type: 'text',
190
+ text: JSON.stringify(
191
+ {
192
+ total: components.length,
193
+ components: components.map(c => ({
194
+ name: c.name,
195
+ category: c.category,
196
+ description: c.description,
197
+ propsCount: c.props.length,
198
+ eventsCount: c.events.length,
199
+ slotsCount: c.slots.length,
200
+ })),
201
+ },
202
+ null,
203
+ 2
204
+ ),
205
+ },
206
+ ],
207
+ };
208
+ }
209
+
210
+ case 'get_component': {
211
+ const apiRef = loadApiReference();
212
+ const allComponents = [
213
+ ...apiRef.components.base,
214
+ ...apiRef.components.extended,
215
+ ];
216
+ const component = allComponents.find(c => c.name === args.name);
217
+
218
+ if (!component) {
219
+ return {
220
+ content: [
221
+ {
222
+ type: 'text',
223
+ text: `Component "${args.name}" not found. Available components: ${allComponents.map(c => c.name).join(', ')}`,
224
+ },
225
+ ],
226
+ isError: true,
227
+ };
228
+ }
229
+
230
+ return {
231
+ content: [
232
+ {
233
+ type: 'text',
234
+ text: JSON.stringify(component, null, 2),
235
+ },
236
+ ],
237
+ };
238
+ }
239
+
240
+ case 'search_components': {
241
+ const apiRef = loadApiReference();
242
+ const allComponents = [
243
+ ...apiRef.components.base,
244
+ ...apiRef.components.extended,
245
+ ];
246
+ const query = args.query.toLowerCase();
247
+
248
+ const matches = allComponents.filter(c =>
249
+ c.name.toLowerCase().includes(query) ||
250
+ c.description.toLowerCase().includes(query) ||
251
+ c.filePath.toLowerCase().includes(query)
252
+ );
253
+
254
+ return {
255
+ content: [
256
+ {
257
+ type: 'text',
258
+ text: JSON.stringify(
259
+ {
260
+ query: args.query,
261
+ matches: matches.length,
262
+ components: matches.map(c => ({
263
+ name: c.name,
264
+ category: c.category,
265
+ description: c.description,
266
+ filePath: c.filePath,
267
+ })),
268
+ },
269
+ null,
270
+ 2
271
+ ),
272
+ },
273
+ ],
274
+ };
275
+ }
276
+
277
+ case 'get_guide': {
278
+ const content = readGuide(args.slug);
279
+ if (!content) {
280
+ return {
281
+ content: [
282
+ {
283
+ type: 'text',
284
+ text: `Guide "${args.slug}" not found.`,
285
+ },
286
+ ],
287
+ isError: true,
288
+ };
289
+ }
290
+
291
+ return {
292
+ content: [
293
+ {
294
+ type: 'text',
295
+ text: content,
296
+ },
297
+ ],
298
+ };
299
+ }
300
+
301
+ case 'get_overview': {
302
+ const llmsTxt = loadLlmsTxt();
303
+ return {
304
+ content: [
305
+ {
306
+ type: 'text',
307
+ text: llmsTxt,
308
+ },
309
+ ],
310
+ };
311
+ }
312
+
313
+ case 'get_docs_map': {
314
+ const docsMap = loadDocsMap();
315
+ return {
316
+ content: [
317
+ {
318
+ type: 'text',
319
+ text: docsMap,
320
+ },
321
+ ],
322
+ };
323
+ }
324
+
325
+ default:
326
+ return {
327
+ content: [
328
+ {
329
+ type: 'text',
330
+ text: `Unknown tool: ${name}`,
331
+ },
332
+ ],
333
+ isError: true,
334
+ };
335
+ }
336
+ } catch (error) {
337
+ return {
338
+ content: [
339
+ {
340
+ type: 'text',
341
+ text: `Error: ${error.message}`,
342
+ },
343
+ ],
344
+ isError: true,
345
+ };
346
+ }
347
+ });
348
+
349
+ // Start server
350
+ async function main() {
351
+ const transport = new StdioServerTransport();
352
+ await server.connect(transport);
353
+ console.error('Dashboard for Laravel MCP Server running on stdio');
354
+ }
355
+
356
+ main().catch((error) => {
357
+ console.error('Server error:', error);
358
+ process.exit(1);
359
+ });