spartan-ng-mcp 1.0.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.
- package/README.md +259 -0
- package/package.json +54 -0
- package/server.js +43 -0
- package/tools/analysis.js +286 -0
- package/tools/blocks.js +331 -0
- package/tools/cache-tools.js +283 -0
- package/tools/cache-warmup.js +331 -0
- package/tools/cache.js +638 -0
- package/tools/components.js +319 -0
- package/tools/docs.js +123 -0
- package/tools/github.js +303 -0
- package/tools/health.js +157 -0
- package/tools/meta.js +76 -0
- package/tools/prompts.js +639 -0
- package/tools/resources.js +277 -0
- package/tools/search.js +147 -0
- package/tools/utils.js +649 -0
package/README.md
ADDED
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
# Spartan UI MCP Server
|
|
2
|
+
|
|
3
|
+
An MCP (Model Context Protocol) server that gives AI assistants full access to the [Spartan Angular UI](https://www.spartan.ng) ecosystem — components, blocks, source code, and documentation.
|
|
4
|
+
|
|
5
|
+
## What It Does
|
|
6
|
+
|
|
7
|
+
- **57 UI Components** with structured API data (Brain & Helm APIs) — selectors, inputs, outputs, models, and code examples
|
|
8
|
+
- **17 Building Blocks** — complete page-level Angular components (sidebar layouts, login/signup forms, calendar interfaces) fetched from GitHub
|
|
9
|
+
- **TypeScript Source Code** — actual component library source from the `spartan-ng/spartan` repository
|
|
10
|
+
- **Canonical Dependency Graph** — real component dependencies from the Spartan CLI
|
|
11
|
+
- **Documentation** — 13 topics including installation, theming, CLI usage, and more
|
|
12
|
+
- **Instant Search** — search across all components by name, selector, directive, or property
|
|
13
|
+
|
|
14
|
+
## Quick Start
|
|
15
|
+
|
|
16
|
+
Configure your MCP client (Claude Desktop, Cursor, VS Code, etc.):
|
|
17
|
+
|
|
18
|
+
```json
|
|
19
|
+
{
|
|
20
|
+
"mcpServers": {
|
|
21
|
+
"spartan-ui-mcp": {
|
|
22
|
+
"command": "npx",
|
|
23
|
+
"args": ["spartan-ui-mcp"]
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### With GitHub Token (recommended)
|
|
30
|
+
|
|
31
|
+
For block source code and component source fetching, a GitHub token gives you 5000 req/hr instead of 60:
|
|
32
|
+
|
|
33
|
+
```json
|
|
34
|
+
{
|
|
35
|
+
"mcpServers": {
|
|
36
|
+
"spartan-ui-mcp": {
|
|
37
|
+
"command": "npx",
|
|
38
|
+
"args": ["spartan-ui-mcp"],
|
|
39
|
+
"env": {
|
|
40
|
+
"GITHUB_TOKEN": "ghp_your_token_here"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
No special scopes needed — the token just authenticates against the public repo.
|
|
48
|
+
|
|
49
|
+
<details>
|
|
50
|
+
<summary><strong>How to get a GitHub token</strong></summary>
|
|
51
|
+
|
|
52
|
+
1. Go to [github.com/settings/tokens](https://github.com/settings/tokens?type=beta)
|
|
53
|
+
2. Click **"Generate new token"** > **"Fine-grained token"**
|
|
54
|
+
3. Give it a name (e.g., `spartan-mcp`)
|
|
55
|
+
4. Set expiration (90 days or custom)
|
|
56
|
+
5. Under **"Repository access"**, select **"Public Repositories (read-only)"**
|
|
57
|
+
6. No additional permissions needed — leave everything else as default
|
|
58
|
+
7. Click **"Generate token"** and copy the `github_pat_...` value
|
|
59
|
+
|
|
60
|
+
Classic tokens also work: create one at [github.com/settings/tokens/new](https://github.com/settings/tokens/new) with no scopes selected.
|
|
61
|
+
|
|
62
|
+
</details>
|
|
63
|
+
|
|
64
|
+
### Development Setup
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
git clone https://github.com/SOG-web/spartan-ui-mcp.git
|
|
68
|
+
cd spartan-ui-mcp
|
|
69
|
+
npm install
|
|
70
|
+
npm start # or: npm run dev (auto-reload)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Tools (17)
|
|
74
|
+
|
|
75
|
+
### Components
|
|
76
|
+
|
|
77
|
+
| Tool | Description |
|
|
78
|
+
|------|-------------|
|
|
79
|
+
| `spartan_components_list` | List all 57 components with URLs |
|
|
80
|
+
| `spartan_components_get` | Get structured API data (Brain/Helm directives, inputs, outputs, examples). Uses the Spartan Analog API for perfect data quality. |
|
|
81
|
+
| `spartan_components_source` | Fetch actual TypeScript source code from GitHub (`libs/brain/` or `libs/helm/`) |
|
|
82
|
+
| `spartan_components_dependencies` | Get the canonical dependency graph for any component |
|
|
83
|
+
|
|
84
|
+
### Blocks
|
|
85
|
+
|
|
86
|
+
| Tool | Description |
|
|
87
|
+
|------|-------------|
|
|
88
|
+
| `spartan_blocks_list` | List all building block categories and variants |
|
|
89
|
+
| `spartan_blocks_get` | Fetch complete block source code from GitHub. Returns Angular component files with template, imports, and extracted Spartan/Angular dependencies. |
|
|
90
|
+
|
|
91
|
+
### Search & Documentation
|
|
92
|
+
|
|
93
|
+
| Tool | Description |
|
|
94
|
+
|------|-------------|
|
|
95
|
+
| `spartan_search` | Instant search across components by name, selector, directive, or input/output property |
|
|
96
|
+
| `spartan_docs_get` | Fetch documentation topics (installation, theming, CLI, dark-mode, etc.) |
|
|
97
|
+
| `spartan_meta` | Get full metadata for autocomplete (all components, blocks, and tool usage) |
|
|
98
|
+
|
|
99
|
+
### Health & Cache
|
|
100
|
+
|
|
101
|
+
| Tool | Description |
|
|
102
|
+
|------|-------------|
|
|
103
|
+
| `spartan_health_check` | Check spartan.ng page availability |
|
|
104
|
+
| `spartan_health_instructions` | Get Spartan CLI health check instructions |
|
|
105
|
+
| `spartan_health_command` | Build `ng`/`nx` health check commands |
|
|
106
|
+
| `spartan_cache_status` | View cache statistics |
|
|
107
|
+
| `spartan_cache_clear` | Clear cached data |
|
|
108
|
+
| `spartan_cache_rebuild` | Rebuild cache (components, docs, and optionally blocks from GitHub) |
|
|
109
|
+
| `spartan_cache_switch_version` | Switch Spartan UI version for caching |
|
|
110
|
+
| `spartan_cache_list_versions` | List all cached versions |
|
|
111
|
+
|
|
112
|
+
## Resources
|
|
113
|
+
|
|
114
|
+
MCP resources provide read-only data via URI scheme:
|
|
115
|
+
|
|
116
|
+
- `spartan://components/list` — all components with metadata
|
|
117
|
+
- `spartan://component/{name}/api` — Brain & Helm API specifications
|
|
118
|
+
- `spartan://component/{name}/examples` — code examples
|
|
119
|
+
- `spartan://component/{name}/full` — complete documentation with install snippets
|
|
120
|
+
- `spartan://blocks/list` — all block categories and variants
|
|
121
|
+
|
|
122
|
+
## Prompts
|
|
123
|
+
|
|
124
|
+
Pre-built conversation templates:
|
|
125
|
+
|
|
126
|
+
- `spartan-get-started` — get started with a component (brain or helm)
|
|
127
|
+
- `spartan-compare-apis` — compare Brain API vs Helm API
|
|
128
|
+
- `spartan-implement-feature` — implement a feature with a component
|
|
129
|
+
- `spartan-troubleshoot` — troubleshoot component issues
|
|
130
|
+
- `spartan-list-components` — list all components by category
|
|
131
|
+
- `spartan-use-block` — use a building block in your project
|
|
132
|
+
|
|
133
|
+
## Example Usage
|
|
134
|
+
|
|
135
|
+
```jsonc
|
|
136
|
+
// Get dialog API — returns 7 Brain + 10 Helm directives with full specs
|
|
137
|
+
{ "tool": "spartan_components_get", "arguments": { "name": "dialog" } }
|
|
138
|
+
|
|
139
|
+
// Get sidebar source code from GitHub
|
|
140
|
+
{ "tool": "spartan_components_source", "arguments": { "name": "sidebar", "layer": "helm" } }
|
|
141
|
+
|
|
142
|
+
// Get a login block with shared utilities
|
|
143
|
+
{ "tool": "spartan_blocks_get", "arguments": { "category": "login", "variant": "login-simple-reactive-form", "includeShared": true } }
|
|
144
|
+
|
|
145
|
+
// Search for date-related components
|
|
146
|
+
{ "tool": "spartan_search", "arguments": { "query": "date" } }
|
|
147
|
+
|
|
148
|
+
// Get sidebar dependencies (with transitive)
|
|
149
|
+
{ "tool": "spartan_components_dependencies", "arguments": { "componentName": "sidebar", "includeTransitive": true } }
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Architecture
|
|
153
|
+
|
|
154
|
+
```mermaid
|
|
155
|
+
flowchart TB
|
|
156
|
+
subgraph Client["MCP Client (IDE / AI Assistant)"]
|
|
157
|
+
direction LR
|
|
158
|
+
C1["Tool Calls"]
|
|
159
|
+
C2["Resources"]
|
|
160
|
+
C3["Prompts"]
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
subgraph Server["spartan-ui-mcp (stdio)"]
|
|
164
|
+
direction TB
|
|
165
|
+
Router["server.js — Router"]
|
|
166
|
+
|
|
167
|
+
subgraph Tools["Tool Modules"]
|
|
168
|
+
direction LR
|
|
169
|
+
T1["components.js"]
|
|
170
|
+
T2["blocks.js"]
|
|
171
|
+
T3["search.js"]
|
|
172
|
+
T4["docs.js"]
|
|
173
|
+
T5["analysis.js"]
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
subgraph Cache["Cache Layers"]
|
|
177
|
+
direction LR
|
|
178
|
+
MC["In-Memory\n(5min / 30min / 1hr)"]
|
|
179
|
+
FC["File-Based\n(24hr TTL)\ncache/{version}/"]
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
subgraph Sources["Data Sources"]
|
|
184
|
+
direction LR
|
|
185
|
+
API["Spartan Analog API\n1 request → 57 components\n(selectors, inputs, outputs,\nexamples, install snippets)"]
|
|
186
|
+
GH["GitHub API\nspartan-ng/spartan\n(block source, TS source,\ndependency graph)"]
|
|
187
|
+
WEB["spartan.ng Website\n(documentation pages,\nHTML content)"]
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
Client --> Router
|
|
191
|
+
Router --> Tools
|
|
192
|
+
Tools --> Cache
|
|
193
|
+
Cache --> Sources
|
|
194
|
+
|
|
195
|
+
style Client fill:#1a1a2e,stroke:#e94560,color:#eee
|
|
196
|
+
style Server fill:#16213e,stroke:#0f3460,color:#eee
|
|
197
|
+
style Sources fill:#0f3460,stroke:#533483,color:#eee
|
|
198
|
+
style API fill:#1a472a,stroke:#2d6a4f,color:#eee
|
|
199
|
+
style GH fill:#1a472a,stroke:#2d6a4f,color:#eee
|
|
200
|
+
style WEB fill:#1a472a,stroke:#2d6a4f,color:#eee
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### Request Flow
|
|
204
|
+
|
|
205
|
+
```
|
|
206
|
+
┌─────────────┐ ┌──────────────┐ ┌─────────────┐ ┌──────────────────┐
|
|
207
|
+
│ AI asks: │────▶│ MCP Tool: │────▶│ Cache hit? │────▶│ Return cached │
|
|
208
|
+
│ "How do I │ │ components │ │ Yes ───────▶│ │ structured JSON │
|
|
209
|
+
│ use the │ │ _get │ │ No ────┐ │ └──────────────────┘
|
|
210
|
+
│ sidebar?" │ │ name:sidebar│ └─────────┘ │
|
|
211
|
+
└─────────────┘ └──────────────┘ │ │
|
|
212
|
+
▼ │
|
|
213
|
+
┌───────────────────┘
|
|
214
|
+
│ Fetch from source
|
|
215
|
+
├─ extract=api → Analog API (structured JSON)
|
|
216
|
+
├─ extract=code → spartan.ng (HTML scraping)
|
|
217
|
+
└─ source tool → GitHub API (TypeScript files)
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## Data Sources
|
|
221
|
+
|
|
222
|
+
The server uses a hybrid approach for maximum data quality:
|
|
223
|
+
|
|
224
|
+
| Source | Used For | Method |
|
|
225
|
+
|--------|----------|--------|
|
|
226
|
+
| Spartan Analog API | Component APIs, examples, install snippets | Single JSON endpoint for all 57 components |
|
|
227
|
+
| GitHub API (`spartan-ng/spartan`) | Block source code, component TypeScript source | Contents API with in-memory caching |
|
|
228
|
+
| spartan.ng website | Documentation pages, HTML content | HTTP fetch with file-based caching |
|
|
229
|
+
| Spartan CLI metadata | Dependency graph (canonical) | Embedded from `primitive-deps.ts` |
|
|
230
|
+
|
|
231
|
+
## Caching
|
|
232
|
+
|
|
233
|
+
Two layers:
|
|
234
|
+
|
|
235
|
+
1. **In-memory** — 5min for website content, 30min for Analog API, 1hr for GitHub API
|
|
236
|
+
2. **File-based** — 24hr TTL under `cache/{version}/` with subdirectories for components, docs, blocks, and source
|
|
237
|
+
|
|
238
|
+
## Environment Variables
|
|
239
|
+
|
|
240
|
+
| Variable | Default | Description |
|
|
241
|
+
|----------|---------|-------------|
|
|
242
|
+
| `GITHUB_TOKEN` | — | GitHub PAT for higher rate limits (5000/hr vs 60/hr) |
|
|
243
|
+
| `SPARTAN_CACHE_TTL_HOURS` | `24` | File cache TTL in hours |
|
|
244
|
+
| `SPARTAN_CACHE_TTL_MS` | `300000` | In-memory cache TTL in ms |
|
|
245
|
+
| `SPARTAN_FETCH_TIMEOUT_MS` | `15000` | HTTP request timeout in ms |
|
|
246
|
+
|
|
247
|
+
## Testing
|
|
248
|
+
|
|
249
|
+
```bash
|
|
250
|
+
node test-e2e.js # 34 end-to-end tests via MCP client protocol
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
## License
|
|
254
|
+
|
|
255
|
+
MIT
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
Built for the [Spartan Angular UI](https://www.spartan.ng) community.
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "spartan-ng-mcp",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "MCP server exposing Spartan Angular UI documentation and component tools.",
|
|
5
|
+
"main": "server.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"spartan-ui-mcp": "server.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"server.js",
|
|
12
|
+
"tools/"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"start": "node server.js",
|
|
16
|
+
"dev": "node --watch server.js",
|
|
17
|
+
"test": "echo \"No tests configured\" && exit 0",
|
|
18
|
+
"prepublish": "echo 'Ready to publish spartan-ui-mcp'",
|
|
19
|
+
"prepare": "husky || true"
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"mcp",
|
|
23
|
+
"model-context-protocol",
|
|
24
|
+
"spartan",
|
|
25
|
+
"angular",
|
|
26
|
+
"ui",
|
|
27
|
+
"spartan-ui",
|
|
28
|
+
"components",
|
|
29
|
+
"documentation"
|
|
30
|
+
],
|
|
31
|
+
"author": "Olaleka Raheem <raheemolalekausman84@gmail.com>",
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"repository": {
|
|
34
|
+
"type": "git",
|
|
35
|
+
"url": "git+https://github.com/SOG-web/spartan-ui-mcp.git"
|
|
36
|
+
},
|
|
37
|
+
"bugs": {
|
|
38
|
+
"url": "https://github.com/SOG-web/spartan-ui-mcp/issues"
|
|
39
|
+
},
|
|
40
|
+
"homepage": "https://github.com/SOG-web/spartan-ui-mcp#readme",
|
|
41
|
+
"engines": {
|
|
42
|
+
"node": ">=18.0.0"
|
|
43
|
+
},
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"@modelcontextprotocol/sdk": "^1.17.2",
|
|
46
|
+
"zod": "^3.23.8"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@commitlint/cli": "^20.5.0",
|
|
50
|
+
"@commitlint/config-conventional": "^20.5.0",
|
|
51
|
+
"@types/node": "^24.7.1",
|
|
52
|
+
"husky": "9.1.7"
|
|
53
|
+
}
|
|
54
|
+
}
|
package/server.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
//@ts-check
|
|
3
|
+
|
|
4
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
|
+
import { registerComponentTools } from "./tools/components.js";
|
|
7
|
+
import { registerDocsTools } from "./tools/docs.js";
|
|
8
|
+
import { registerHealthTools } from "./tools/health.js";
|
|
9
|
+
import { registerMetaTools } from "./tools/meta.js";
|
|
10
|
+
import { registerSearchTools } from "./tools/search.js";
|
|
11
|
+
import { registerAnalysisTools } from "./tools/analysis.js";
|
|
12
|
+
import { registerBlockTools } from "./tools/blocks.js";
|
|
13
|
+
import { registerResourceHandlers } from "./tools/resources.js";
|
|
14
|
+
import { registerPromptHandlers } from "./tools/prompts.js";
|
|
15
|
+
import { registerCacheTools } from "./tools/cache-tools.js";
|
|
16
|
+
|
|
17
|
+
const server = new McpServer({
|
|
18
|
+
name: "spartan-ui-mcp",
|
|
19
|
+
version: "2.0.0",
|
|
20
|
+
description:
|
|
21
|
+
"MCP server exposing Spartan Angular UI components, blocks, and documentation. " +
|
|
22
|
+
"Provides structured API data, source code from GitHub, and page-level building blocks.",
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
// Register tool modules
|
|
26
|
+
registerComponentTools(server);
|
|
27
|
+
registerDocsTools(server);
|
|
28
|
+
registerHealthTools(server);
|
|
29
|
+
registerMetaTools(server);
|
|
30
|
+
registerSearchTools(server);
|
|
31
|
+
registerAnalysisTools(server);
|
|
32
|
+
registerBlockTools(server);
|
|
33
|
+
registerCacheTools(server);
|
|
34
|
+
|
|
35
|
+
// Register resource handlers
|
|
36
|
+
registerResourceHandlers(server);
|
|
37
|
+
|
|
38
|
+
// Register prompt handlers
|
|
39
|
+
registerPromptHandlers(server);
|
|
40
|
+
|
|
41
|
+
const transport = new StdioServerTransport();
|
|
42
|
+
|
|
43
|
+
await server.connect(transport);
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
//@ts-check
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import {
|
|
4
|
+
KNOWN_COMPONENTS,
|
|
5
|
+
COMPONENT_DEPENDENCIES,
|
|
6
|
+
} from "./utils.js";
|
|
7
|
+
|
|
8
|
+
export function registerAnalysisTools(server) {
|
|
9
|
+
// Show component dependencies
|
|
10
|
+
server.registerTool(
|
|
11
|
+
"spartan_components_dependencies",
|
|
12
|
+
{
|
|
13
|
+
title: "Show component dependencies",
|
|
14
|
+
description:
|
|
15
|
+
"Analyze what other components, packages, or dependencies a Spartan UI component requires. " +
|
|
16
|
+
"Includes Angular CDK dependencies, peer components, and installation requirements.",
|
|
17
|
+
inputSchema: {
|
|
18
|
+
componentName: z
|
|
19
|
+
.string()
|
|
20
|
+
.min(1, "componentName is required")
|
|
21
|
+
.describe("Spartan component name (e.g., 'calendar', 'dialog')"),
|
|
22
|
+
includeTransitive: z
|
|
23
|
+
.boolean()
|
|
24
|
+
.default(false)
|
|
25
|
+
.describe(
|
|
26
|
+
"Include transitive dependencies (dependencies of dependencies)"
|
|
27
|
+
),
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
async (args) => {
|
|
31
|
+
const componentName = String(args.componentName || "")
|
|
32
|
+
.trim()
|
|
33
|
+
.toLowerCase();
|
|
34
|
+
if (!KNOWN_COMPONENTS.includes(componentName)) {
|
|
35
|
+
throw new Error(
|
|
36
|
+
`Unknown component: ${componentName}. Available: ${KNOWN_COMPONENTS.join(
|
|
37
|
+
", "
|
|
38
|
+
)}`
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const dependencies = await analyzeComponentDependencies(
|
|
43
|
+
componentName,
|
|
44
|
+
args.includeTransitive
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
content: [
|
|
49
|
+
{
|
|
50
|
+
type: "text",
|
|
51
|
+
text: JSON.stringify(
|
|
52
|
+
{
|
|
53
|
+
component: componentName,
|
|
54
|
+
dependencies,
|
|
55
|
+
},
|
|
56
|
+
null,
|
|
57
|
+
2
|
|
58
|
+
),
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
// Find related/similar components
|
|
66
|
+
// COMMENTED OUT: Not producing useful results
|
|
67
|
+
/*
|
|
68
|
+
server.registerTool(
|
|
69
|
+
"spartan_components_related",
|
|
70
|
+
{
|
|
71
|
+
title: "Find related or similar components",
|
|
72
|
+
description:
|
|
73
|
+
"Find Spartan UI components that are related to or similar to a given component. " +
|
|
74
|
+
"Analyzes functionality, use cases, and API patterns to suggest alternatives and complementary components.",
|
|
75
|
+
inputSchema: {
|
|
76
|
+
componentName: z
|
|
77
|
+
.string()
|
|
78
|
+
.min(1, "componentName is required")
|
|
79
|
+
.describe("Spartan component name to find related components for"),
|
|
80
|
+
relationshipType: z
|
|
81
|
+
.enum(["similar", "complementary", "alternative", "all"])
|
|
82
|
+
.default("all")
|
|
83
|
+
.describe(
|
|
84
|
+
"Type of relationship: 'similar' (same use case), 'complementary' (work together), 'alternative' (different approach), 'all'"
|
|
85
|
+
),
|
|
86
|
+
limit: z
|
|
87
|
+
.number()
|
|
88
|
+
.min(1)
|
|
89
|
+
.max(10)
|
|
90
|
+
.default(5)
|
|
91
|
+
.describe("Maximum number of related components to return"),
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
async (args) => {
|
|
95
|
+
const componentName = String(args.componentName || "")
|
|
96
|
+
.trim()
|
|
97
|
+
.toLowerCase();
|
|
98
|
+
if (!KNOWN_COMPONENTS.includes(componentName)) {
|
|
99
|
+
throw new Error(`Unknown component: ${componentName}`);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const related = await findRelatedComponents(
|
|
103
|
+
componentName,
|
|
104
|
+
args.relationshipType,
|
|
105
|
+
args.limit
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
return {
|
|
109
|
+
content: [
|
|
110
|
+
{
|
|
111
|
+
type: "text",
|
|
112
|
+
text: JSON.stringify(
|
|
113
|
+
{
|
|
114
|
+
component: componentName,
|
|
115
|
+
relationshipType: args.relationshipType,
|
|
116
|
+
relatedComponents: related,
|
|
117
|
+
processingInstructions:
|
|
118
|
+
"Present related components with explanations of relationships, use case comparisons, and when to choose each option.",
|
|
119
|
+
},
|
|
120
|
+
null,
|
|
121
|
+
2
|
|
122
|
+
),
|
|
123
|
+
},
|
|
124
|
+
],
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
);
|
|
128
|
+
*/
|
|
129
|
+
|
|
130
|
+
// List component variants (Brain vs Helm API)
|
|
131
|
+
// COMMENTED OUT: Not producing useful results
|
|
132
|
+
/*
|
|
133
|
+
server.registerTool(
|
|
134
|
+
"spartan_components_variants",
|
|
135
|
+
{
|
|
136
|
+
title: "List component variants (Brain vs Helm API)",
|
|
137
|
+
description:
|
|
138
|
+
"Compare Brain API (low-level, unstyled) and Helm API (high-level, styled) variants of a component. " +
|
|
139
|
+
"Shows differences in API, styling approach, and when to use each variant.",
|
|
140
|
+
inputSchema: {
|
|
141
|
+
componentName: z
|
|
142
|
+
.string()
|
|
143
|
+
.min(1, "componentName is required")
|
|
144
|
+
.describe("Spartan component name"),
|
|
145
|
+
includeComparison: z
|
|
146
|
+
.boolean()
|
|
147
|
+
.default(true)
|
|
148
|
+
.describe("Include detailed comparison between variants"),
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
async (args) => {
|
|
152
|
+
const componentName = String(args.componentName || "")
|
|
153
|
+
.trim()
|
|
154
|
+
.toLowerCase();
|
|
155
|
+
if (!KNOWN_COMPONENTS.includes(componentName)) {
|
|
156
|
+
throw new Error(`Unknown component: ${componentName}`);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const variants = await analyzeComponentVariants(
|
|
160
|
+
componentName,
|
|
161
|
+
args.includeComparison
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
return {
|
|
165
|
+
content: [
|
|
166
|
+
{
|
|
167
|
+
type: "text",
|
|
168
|
+
text: JSON.stringify(
|
|
169
|
+
{
|
|
170
|
+
component: componentName,
|
|
171
|
+
variants,
|
|
172
|
+
processingInstructions:
|
|
173
|
+
"Present variants with clear explanations of differences, use cases, and migration guidance between Brain and Helm APIs.",
|
|
174
|
+
},
|
|
175
|
+
null,
|
|
176
|
+
2
|
|
177
|
+
),
|
|
178
|
+
},
|
|
179
|
+
],
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
);
|
|
183
|
+
*/
|
|
184
|
+
|
|
185
|
+
// Accessibility check — removed: produced fake scores based on string matching,
|
|
186
|
+
// not real accessibility analysis. The data was misleading.
|
|
187
|
+
/* REMOVED in v2.0
|
|
188
|
+
server.registerTool(
|
|
189
|
+
"spartan_accessibility_check_REMOVED",
|
|
190
|
+
{
|
|
191
|
+
title: "Check component accessibility features",
|
|
192
|
+
description:
|
|
193
|
+
"Analyze accessibility features, ARIA support, keyboard navigation, and screen reader compatibility " +
|
|
194
|
+
"for a Spartan UI component. Provides accessibility best practices and implementation guidance.",
|
|
195
|
+
inputSchema: {
|
|
196
|
+
componentName: z
|
|
197
|
+
.string()
|
|
198
|
+
.min(1, "componentName is required")
|
|
199
|
+
.describe("Spartan component name"),
|
|
200
|
+
checkType: z
|
|
201
|
+
.enum(["overview", "aria", "keyboard", "screenreader", "wcag", "all"])
|
|
202
|
+
.default("all")
|
|
203
|
+
.describe(
|
|
204
|
+
"Type of accessibility check: specific area or 'all' for comprehensive analysis"
|
|
205
|
+
),
|
|
206
|
+
},
|
|
207
|
+
},
|
|
208
|
+
async (args) => {
|
|
209
|
+
const componentName = String(args.componentName || "")
|
|
210
|
+
.trim()
|
|
211
|
+
.toLowerCase();
|
|
212
|
+
if (!KNOWN_COMPONENTS.includes(componentName)) {
|
|
213
|
+
throw new Error(`Unknown component: ${componentName}`);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const accessibility = await analyzeAccessibility(
|
|
217
|
+
componentName,
|
|
218
|
+
args.checkType
|
|
219
|
+
);
|
|
220
|
+
|
|
221
|
+
return {
|
|
222
|
+
content: [
|
|
223
|
+
{
|
|
224
|
+
type: "text",
|
|
225
|
+
text: JSON.stringify(
|
|
226
|
+
{
|
|
227
|
+
component: componentName,
|
|
228
|
+
checkType: args.checkType,
|
|
229
|
+
accessibility,
|
|
230
|
+
},
|
|
231
|
+
null,
|
|
232
|
+
2
|
|
233
|
+
),
|
|
234
|
+
},
|
|
235
|
+
],
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
);
|
|
239
|
+
REMOVED in v2.0 */
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Analyze component dependencies
|
|
244
|
+
* @param {string} componentName
|
|
245
|
+
* @param {boolean} includeTransitive
|
|
246
|
+
*/
|
|
247
|
+
async function analyzeComponentDependencies(componentName, includeTransitive) {
|
|
248
|
+
// Use the canonical dependency graph from the Spartan CLI
|
|
249
|
+
const directDeps = COMPONENT_DEPENDENCIES[componentName] || [];
|
|
250
|
+
|
|
251
|
+
const dependencies = {
|
|
252
|
+
direct: directDeps.filter((d) => d !== "utils"),
|
|
253
|
+
installCommand: `npx ng g @spartan-ng/cli:ui ${componentName}`,
|
|
254
|
+
allRequired: directDeps,
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
// Add transitive dependencies if requested
|
|
258
|
+
if (includeTransitive) {
|
|
259
|
+
const transitive = new Set();
|
|
260
|
+
const visited = new Set([componentName]);
|
|
261
|
+
|
|
262
|
+
const collectDeps = (name) => {
|
|
263
|
+
const deps = COMPONENT_DEPENDENCIES[name] || [];
|
|
264
|
+
for (const dep of deps) {
|
|
265
|
+
if (!visited.has(dep)) {
|
|
266
|
+
visited.add(dep);
|
|
267
|
+
if (dep !== "utils") transitive.add(dep);
|
|
268
|
+
collectDeps(dep);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
};
|
|
272
|
+
collectDeps(componentName);
|
|
273
|
+
|
|
274
|
+
// Remove direct deps from transitive
|
|
275
|
+
for (const d of directDeps) transitive.delete(d);
|
|
276
|
+
dependencies.transitive = [...transitive];
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
return dependencies;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Remaining helper functions removed in v2.0:
|
|
283
|
+
// - findRelatedComponents, analyzeComponentVariants, analyzeAccessibility
|
|
284
|
+
// - All helper functions for the above (getSimilarComponents, etc.)
|
|
285
|
+
// These were producing fake/hardcoded data. The dependency graph now comes
|
|
286
|
+
// from COMPONENT_DEPENDENCIES (canonical source: spartan-ng/cli).
|