@ehrocks/fe-mcp-server 1.0.3
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 +32 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +128 -0
- package/package.json +40 -0
package/README.md
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Frontend MCP Server
|
|
2
|
+
|
|
3
|
+
An MCP server for searching Hero Design System components.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
- Ensure you have configured `EH_GITHUB_PKG_TOKEN` to read the internal npm package. [Read more](https://employmenthero.atlassian.net/wiki/spaces/WEBPLATFORM/pages/3314778914/PRD+Experimental+migrating+private+package+hosting+to+Github+Packages#Prerequisite)
|
|
8
|
+
- Update mcp config from Cursor, e.g. on macOS `~/.cursor/mcp.json`
|
|
9
|
+
```
|
|
10
|
+
{
|
|
11
|
+
"mcpServers": {
|
|
12
|
+
"fe-mcp-service": {
|
|
13
|
+
"command": "npx",
|
|
14
|
+
"args": [
|
|
15
|
+
"-y",
|
|
16
|
+
"--@thinkei:registry=https://npm.pkg.github.com",
|
|
17
|
+
"--//npm.pkg.github.com/:_authToken=${EH_GITHUB_PKG_TOKEN}",
|
|
18
|
+
"@thinkei/fe-mcp-server"
|
|
19
|
+
]
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Troubleshooting
|
|
26
|
+
- MCP connection gets `Client closed` error: *Ensure that Node.js is accessible globally.* Example: If you're using `asdf`, you can set the default Node.js version with:
|
|
27
|
+
```
|
|
28
|
+
asdf set -u nodejs 20.19.0
|
|
29
|
+
```
|
|
30
|
+
- Connect error or timeout: Because our MCP service is deployed to Employment Hero staging cluster, ensure you have the connection via VPN. [Read more](https://employmenthero.atlassian.net/wiki/spaces/PLAT/pages/1648525859/VPN+-+Internal+services+and+sandbox+accessibility)
|
|
31
|
+
|
|
32
|
+
For more detailed troubleshooting, please refer to the [full guide](https://employmenthero.atlassian.net/wiki/spaces/WEBPLATFORM/pages/3597567386/Hero+Design+MCP+Trouble+Shooting).
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
export interface TextContent {
|
|
3
|
+
[key: string]: unknown;
|
|
4
|
+
type: 'text';
|
|
5
|
+
text: string;
|
|
6
|
+
}
|
|
7
|
+
export interface HeroDesignComponentExample {
|
|
8
|
+
component_name: string;
|
|
9
|
+
component_description: string;
|
|
10
|
+
example_name: string;
|
|
11
|
+
example_description: string;
|
|
12
|
+
code: string;
|
|
13
|
+
purpose_description?: string;
|
|
14
|
+
technical_description?: string;
|
|
15
|
+
props_description?: string;
|
|
16
|
+
patterns_description?: string;
|
|
17
|
+
use_cases_description?: string;
|
|
18
|
+
similarity_score: number;
|
|
19
|
+
matched_embedding_type: string;
|
|
20
|
+
}
|
|
21
|
+
export declare const searchHeroDesignComponentExamples: (query: string, limit?: number, threshold?: number) => Promise<TextContent[]>;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
const HERO_DESIGN_COMPONENT_EXAMPLES_HOST = process.env.ENVIRONMENT === 'STG' ? 'https://fe-mcp-service.staging.ehrocks.com' : 'http://localhost:8000';
|
|
6
|
+
export const searchHeroDesignComponentExamples = async (query, limit = 5, threshold = 0.4) => {
|
|
7
|
+
try {
|
|
8
|
+
const response = await fetch(`${HERO_DESIGN_COMPONENT_EXAMPLES_HOST}/retrieve_hero_design`, {
|
|
9
|
+
method: 'POST',
|
|
10
|
+
headers: {
|
|
11
|
+
'Content-Type': 'application/json'
|
|
12
|
+
},
|
|
13
|
+
body: JSON.stringify({ query, limit, threshold })
|
|
14
|
+
});
|
|
15
|
+
if (!response.ok) {
|
|
16
|
+
throw new Error(`HTTP error status: ${response.status}`);
|
|
17
|
+
}
|
|
18
|
+
const examples = await response.json();
|
|
19
|
+
if (!examples.length) {
|
|
20
|
+
return [{
|
|
21
|
+
type: 'text',
|
|
22
|
+
text: "I couldn't find any relevant component examples for your query."
|
|
23
|
+
}];
|
|
24
|
+
}
|
|
25
|
+
const responseParts = [];
|
|
26
|
+
examples.forEach((example, index) => {
|
|
27
|
+
responseParts.push(`\n${index + 1}. ${example.component_name} - ${example.example_name}`, `\nSimilarity Score: ${example.similarity_score.toFixed(2)}`, `\nComponent Description: ${example.component_description}`);
|
|
28
|
+
if (example.purpose_description) {
|
|
29
|
+
responseParts.push(`\nPurpose: ${example.purpose_description}`);
|
|
30
|
+
}
|
|
31
|
+
if (example.technical_description) {
|
|
32
|
+
responseParts.push(`\nTechnical Details: ${example.technical_description}`);
|
|
33
|
+
}
|
|
34
|
+
if (example.code) {
|
|
35
|
+
responseParts.push(`\nCode Example:\n\`\`\`jsx\n${example.code}\n\`\`\``);
|
|
36
|
+
}
|
|
37
|
+
if (example.props_description) {
|
|
38
|
+
responseParts.push(`\nProps Description: ${example.props_description}`);
|
|
39
|
+
}
|
|
40
|
+
if (example.matched_embedding_type) {
|
|
41
|
+
responseParts.push(`\nMatched Embedding Type: ${example.matched_embedding_type}`);
|
|
42
|
+
}
|
|
43
|
+
responseParts.push('\n' + '='.repeat(80) + '\n');
|
|
44
|
+
});
|
|
45
|
+
return [{
|
|
46
|
+
type: 'text',
|
|
47
|
+
text: 'Here are the most relevant component examples I found:\n' + responseParts.join('\n')
|
|
48
|
+
}];
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
return [{
|
|
52
|
+
type: 'text',
|
|
53
|
+
text: `An error occurred while processing your request: ${error}`
|
|
54
|
+
}];
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
async function startServer() {
|
|
58
|
+
const server = new McpServer({
|
|
59
|
+
name: "hero-design-mcp-server",
|
|
60
|
+
version: "1.0.0"
|
|
61
|
+
});
|
|
62
|
+
server.tool("search_hero_design_component_examples", `Search for React component examples from the Hero Design System using semantic search.
|
|
63
|
+
|
|
64
|
+
This tool performs semantic search across multiple specialized collections to find the most relevant component examples based on your query. The search covers:
|
|
65
|
+
|
|
66
|
+
1. Full Component Information: Searches across complete component documentation including names, descriptions, and examples
|
|
67
|
+
2. Code Examples: Specifically searches through code implementations and syntax
|
|
68
|
+
3. Component Descriptions: Focuses on component usage descriptions and explanations
|
|
69
|
+
4. Purpose & Use Cases: Matches queries about component purposes and intended use cases
|
|
70
|
+
5. Technical Details: Searches through technical implementation details and specifications
|
|
71
|
+
6. Props & Configuration: Finds examples based on prop usage and configuration options
|
|
72
|
+
7. Design Patterns: Matches React patterns and best practices demonstrated in examples
|
|
73
|
+
8. Use Case Scenarios: Searches through real-world application scenarios
|
|
74
|
+
|
|
75
|
+
You can use this tool to:
|
|
76
|
+
- Find examples of specific components (e.g., "Button with icon")
|
|
77
|
+
- Search for implementation patterns (e.g., "how to handle form validation")
|
|
78
|
+
- Look up prop usage (e.g., "Button with custom colors")
|
|
79
|
+
- Find examples of specific features (e.g., "dropdown with search")
|
|
80
|
+
- Search for specific use cases (e.g., "loading state in forms")
|
|
81
|
+
- Find technical implementations (e.g., "async data loading pattern")
|
|
82
|
+
|
|
83
|
+
The tool will return the most relevant examples, including:
|
|
84
|
+
- Component name and description
|
|
85
|
+
- Example code with explanations
|
|
86
|
+
- Technical details and implementation notes
|
|
87
|
+
- Purpose and use case descriptions
|
|
88
|
+
- Props and configuration details
|
|
89
|
+
- Design patterns and best practices`, {
|
|
90
|
+
query: z
|
|
91
|
+
.string()
|
|
92
|
+
.describe("The search query describing what you're looking for in the component examples. Be specific about what aspects you're interested in (code, usage, props, patterns, etc.)"),
|
|
93
|
+
limit: z
|
|
94
|
+
.string()
|
|
95
|
+
.transform(val => {
|
|
96
|
+
const num = Number(val);
|
|
97
|
+
if (isNaN(num) || num <= 0)
|
|
98
|
+
return 5;
|
|
99
|
+
return num;
|
|
100
|
+
})
|
|
101
|
+
.optional()
|
|
102
|
+
.default("5")
|
|
103
|
+
.describe("Maximum number of distinct component examples to return"),
|
|
104
|
+
threshold: z
|
|
105
|
+
.string()
|
|
106
|
+
.transform(val => {
|
|
107
|
+
const num = parseFloat(val);
|
|
108
|
+
if (isNaN(num) || num <= 0)
|
|
109
|
+
return 0.4;
|
|
110
|
+
return num;
|
|
111
|
+
})
|
|
112
|
+
.optional()
|
|
113
|
+
.default("0.4")
|
|
114
|
+
.describe("Minimum similarity score (0.0 to 1.0) for returned examples. Lower values return more results but might be less relevant")
|
|
115
|
+
}, async ({ query, limit, threshold }) => {
|
|
116
|
+
const content = await searchHeroDesignComponentExamples(query, limit, threshold);
|
|
117
|
+
return { content };
|
|
118
|
+
});
|
|
119
|
+
const transport = new StdioServerTransport();
|
|
120
|
+
await server.connect(transport);
|
|
121
|
+
}
|
|
122
|
+
// If we're being executed directly (not imported), start the server
|
|
123
|
+
if (process.argv[1]) {
|
|
124
|
+
startServer().catch((error) => {
|
|
125
|
+
console.error("Failed to start server:", error);
|
|
126
|
+
process.exit(1);
|
|
127
|
+
});
|
|
128
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ehrocks/fe-mcp-server",
|
|
3
|
+
"version": "1.0.3",
|
|
4
|
+
"description": "MCP server for searching Hero Design System components",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist",
|
|
10
|
+
"README.md"
|
|
11
|
+
],
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "tsc",
|
|
14
|
+
"start": "tsx src/index.ts",
|
|
15
|
+
"prepublishOnly": "npm run build"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"mcp",
|
|
19
|
+
"hero-design",
|
|
20
|
+
"components",
|
|
21
|
+
"search"
|
|
22
|
+
],
|
|
23
|
+
"author": "",
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@modelcontextprotocol/sdk": "^1.9.0"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@types/node": "^22.14.1",
|
|
30
|
+
"tsx": "^4.7.1",
|
|
31
|
+
"typescript": "^5.4.2"
|
|
32
|
+
},
|
|
33
|
+
"bin": {
|
|
34
|
+
"start-mcp-server": "dist/index.js"
|
|
35
|
+
},
|
|
36
|
+
"repository": {
|
|
37
|
+
"type": "git",
|
|
38
|
+
"url": "git+https://github.com/thinkei/fe-mcp-service.git"
|
|
39
|
+
}
|
|
40
|
+
}
|