@pure-ds/core 0.7.4 â 0.7.5
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/.cursorrules +21 -0
- package/.github/copilot-instructions.md +21 -0
- package/dist/types/src/js/pds-core/pds-start-helpers.d.ts.map +1 -1
- package/package.json +8 -2
- package/packages/pds-cli/bin/pds-bootstrap.js +1 -1
- package/packages/pds-cli/bin/pds-import.js +1 -1
- package/packages/pds-cli/bin/pds-mcp-eval.js +79 -0
- package/packages/pds-cli/bin/pds-mcp-health.js +128 -0
- package/packages/pds-cli/bin/pds-mcp-server.js +140 -0
- package/packages/pds-cli/bin/pds-setup-mcp.js +72 -0
- package/packages/pds-cli/lib/pds-mcp-core.js +497 -0
- package/packages/pds-cli/lib/pds-mcp-eval-cases.json +72 -0
- package/public/assets/js/app.js +1582 -4
- package/public/assets/js/app.js.map +7 -0
- package/public/assets/js/lit.js +1078 -3
- package/public/assets/js/lit.js.map +7 -0
- package/public/assets/js/pds-ask.js +239 -9
- package/public/assets/js/pds-ask.js.map +7 -0
- package/public/assets/js/pds-autocomplete.js +590 -7
- package/public/assets/js/pds-autocomplete.js.map +7 -0
- package/public/assets/js/pds-enhancers.js +689 -1
- package/public/assets/js/pds-enhancers.js.map +7 -0
- package/public/assets/js/pds-manager.js +15947 -3101
- package/public/assets/js/pds-manager.js.map +7 -0
- package/public/assets/js/pds-toast.js +30 -1
- package/public/assets/js/pds-toast.js.map +7 -0
- package/public/assets/js/pds.js +1442 -2
- package/public/assets/js/pds.js.map +7 -0
- package/public/assets/pds/core/pds-ask.js +239 -9
- package/public/assets/pds/core/pds-autocomplete.js +590 -7
- package/public/assets/pds/core/pds-enhancers.js +689 -1
- package/public/assets/pds/core/pds-manager.js +15947 -3101
- package/public/assets/pds/core/pds-toast.js +30 -1
- package/public/assets/pds/core.js +1442 -2
- package/public/assets/pds/external/lit.js +1078 -3
- package/readme.md +44 -2
- package/src/js/pds-core/pds-start-helpers.js +0 -20
package/.cursorrules
CHANGED
|
@@ -49,6 +49,27 @@ PDS follows the [Pure Web Manifesto](https://pureweb.dev/manifesto): "The browse
|
|
|
49
49
|
2. Otherwise use workspace root paths (pure-ds development)
|
|
50
50
|
3. Prefer reading actual files over guessing - the data is authoritative
|
|
51
51
|
|
|
52
|
+
## đ MCP-First Lookup Protocol (Preferred)
|
|
53
|
+
|
|
54
|
+
If an MCP server named `pure-ds` is available, **use MCP tools first** before generating PDS code.
|
|
55
|
+
|
|
56
|
+
### Required lookup order
|
|
57
|
+
|
|
58
|
+
1. **Tokens** â call `get_tokens`
|
|
59
|
+
2. **Primitives / utilities / selectors** â call `find_utility_class`
|
|
60
|
+
3. **Web component API** â call `get_component_api`
|
|
61
|
+
4. **Enhancer metadata + demoHtml** â call `get_enhancer_metadata`
|
|
62
|
+
5. **Design config deterministic mapping** â call `get_config_relations`
|
|
63
|
+
6. **Final snippet sanity check** â call `validate_pds_snippet`
|
|
64
|
+
|
|
65
|
+
### Non-negotiable rules
|
|
66
|
+
|
|
67
|
+
- Do not invent class names, tokens, attributes, events, or selectors.
|
|
68
|
+
- If a value is not found in MCP results, state it is unavailable and suggest nearest matches.
|
|
69
|
+
- Prefer MCP results over memory, including examples in this file.
|
|
70
|
+
- If MCP is unavailable, fall back to direct SSoT file reads using the paths above.
|
|
71
|
+
- If neither MCP nor file reads are available, provide only conservative guidance and clearly mark uncertainty.
|
|
72
|
+
|
|
52
73
|
---
|
|
53
74
|
|
|
54
75
|
## đ pds-form Best Practices
|
|
@@ -49,6 +49,27 @@ PDS follows the [Pure Web Manifesto](https://pureweb.dev/manifesto): "The browse
|
|
|
49
49
|
2. Otherwise use workspace root paths (pure-ds development)
|
|
50
50
|
3. Prefer reading actual files over guessing - the data is authoritative
|
|
51
51
|
|
|
52
|
+
## đ MCP-First Lookup Protocol (Preferred)
|
|
53
|
+
|
|
54
|
+
If an MCP server named `pure-ds` is available, **use MCP tools first** before generating PDS code.
|
|
55
|
+
|
|
56
|
+
### Required lookup order
|
|
57
|
+
|
|
58
|
+
1. **Tokens** â call `get_tokens`
|
|
59
|
+
2. **Primitives / utilities / selectors** â call `find_utility_class`
|
|
60
|
+
3. **Web component API** â call `get_component_api`
|
|
61
|
+
4. **Enhancer metadata + demoHtml** â call `get_enhancer_metadata`
|
|
62
|
+
5. **Design config deterministic mapping** â call `get_config_relations`
|
|
63
|
+
6. **Final snippet sanity check** â call `validate_pds_snippet`
|
|
64
|
+
|
|
65
|
+
### Non-negotiable rules
|
|
66
|
+
|
|
67
|
+
- Do not invent class names, tokens, attributes, events, or selectors.
|
|
68
|
+
- If a value is not found in MCP results, state it is unavailable and suggest nearest matches.
|
|
69
|
+
- Prefer MCP results over memory, including examples in this file.
|
|
70
|
+
- If MCP is unavailable, fall back to direct SSoT file reads using the paths above.
|
|
71
|
+
- If neither MCP nor file reads are available, provide only conservative guidance and clearly mark uncertainty.
|
|
72
|
+
|
|
52
73
|
---
|
|
53
74
|
|
|
54
75
|
## đ pds-form Best Practices
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pds-start-helpers.d.ts","sourceRoot":"","sources":["../../../../../src/js/pds-core/pds-start-helpers.js"],"names":[],"mappings":"AAqBA,sEAgCC;AAiBD,mDASC;AA6BD,8CAsBC;AAGD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkJC;AAGD;;;;;;;;EAmCC;AAED;;QASC;AAGD;;;;;
|
|
1
|
+
{"version":3,"file":"pds-start-helpers.d.ts","sourceRoot":"","sources":["../../../../../src/js/pds-core/pds-start-helpers.js"],"names":[],"mappings":"AAqBA,sEAgCC;AAiBD,mDASC;AA6BD,8CAsBC;AAGD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkJC;AAGD;;;;;;;;EAmCC;AAED;;QASC;AAGD;;;;;GA2JC;AAtdM,qDAGI"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pure-ds/core",
|
|
3
3
|
"shortname": "pds",
|
|
4
|
-
"version": "0.7.
|
|
4
|
+
"version": "0.7.5",
|
|
5
5
|
"description": "Why develop a Design System when you can generate one?",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -31,8 +31,12 @@
|
|
|
31
31
|
"pds-build-icons": "packages/pds-cli/bin/pds-build-icons.js",
|
|
32
32
|
"pds-import": "packages/pds-cli/bin/pds-import.js",
|
|
33
33
|
"pds-setup-copilot": "packages/pds-cli/bin/pds-setup-copilot.js",
|
|
34
|
+
"pds-setup-mcp": "packages/pds-cli/bin/pds-setup-mcp.js",
|
|
34
35
|
"pds-init-config": "packages/pds-cli/bin/pds-init-config.js",
|
|
35
|
-
"pds-bootstrap": "packages/pds-cli/bin/pds-bootstrap.js"
|
|
36
|
+
"pds-bootstrap": "packages/pds-cli/bin/pds-bootstrap.js",
|
|
37
|
+
"pds-mcp-server": "packages/pds-cli/bin/pds-mcp-server.js",
|
|
38
|
+
"pds-mcp-health": "packages/pds-cli/bin/pds-mcp-health.js",
|
|
39
|
+
"pds-mcp-eval": "packages/pds-cli/bin/pds-mcp-eval.js"
|
|
36
40
|
},
|
|
37
41
|
"exports": {
|
|
38
42
|
".": {
|
|
@@ -88,6 +92,8 @@
|
|
|
88
92
|
"pds:css-data": "node packages/pds-cli/bin/generate-css-data.js",
|
|
89
93
|
"pds:import": "node packages/pds-cli/bin/pds-import.js",
|
|
90
94
|
"pds:dx": "node packages/pds-cli/bin/pds-dx.js",
|
|
95
|
+
"pds:mcp:health": "node packages/pds-cli/bin/pds-mcp-health.js",
|
|
96
|
+
"pds:mcp:eval": "node packages/pds-cli/bin/pds-mcp-eval.js",
|
|
91
97
|
"storybook:generate": "cd packages/pds-storybook && npm run generate-stories",
|
|
92
98
|
"storybook:dev": "cd packages/pds-storybook && npm run storybook:dev",
|
|
93
99
|
"storybook:build": "cd packages/pds-storybook && npm run storybook:build"
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { readFile } from 'fs/promises';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
6
|
+
import { createPdsMcpContext, runPdsMcpTool } from '../lib/pds-mcp-core.js';
|
|
7
|
+
|
|
8
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
|
|
10
|
+
async function loadCases(filePath) {
|
|
11
|
+
const raw = await readFile(filePath, 'utf8');
|
|
12
|
+
const json = JSON.parse(raw);
|
|
13
|
+
return Array.isArray(json) ? json : [];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function hasPath(objectValue, dotPath) {
|
|
17
|
+
if (!dotPath) return true;
|
|
18
|
+
const parts = dotPath.split('.');
|
|
19
|
+
let current = objectValue;
|
|
20
|
+
for (const part of parts) {
|
|
21
|
+
if (!current || typeof current !== 'object' || !(part in current)) return false;
|
|
22
|
+
current = current[part];
|
|
23
|
+
}
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async function runCase(ctx, testCase) {
|
|
28
|
+
const result = await runPdsMcpTool(ctx, testCase.tool, testCase.args || {});
|
|
29
|
+
const checks = testCase.expect?.paths || [];
|
|
30
|
+
const failures = checks.filter((checkPath) => !hasPath(result, checkPath));
|
|
31
|
+
return {
|
|
32
|
+
id: testCase.id,
|
|
33
|
+
tool: testCase.tool,
|
|
34
|
+
pass: failures.length === 0,
|
|
35
|
+
failures,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async function main() {
|
|
40
|
+
const args = process.argv.slice(2);
|
|
41
|
+
const caseFileArgIndex = args.findIndex((arg) => arg === '--cases');
|
|
42
|
+
const caseFilePath = caseFileArgIndex > -1
|
|
43
|
+
? path.resolve(process.cwd(), args[caseFileArgIndex + 1])
|
|
44
|
+
: path.resolve(__dirname, '../lib/pds-mcp-eval-cases.json');
|
|
45
|
+
|
|
46
|
+
const ctx = createPdsMcpContext({ projectRoot: process.cwd() });
|
|
47
|
+
const cases = await loadCases(caseFilePath);
|
|
48
|
+
if (cases.length === 0) {
|
|
49
|
+
console.error('No evaluation cases found.');
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const results = [];
|
|
54
|
+
for (const testCase of cases) {
|
|
55
|
+
// eslint-disable-next-line no-await-in-loop
|
|
56
|
+
const outcome = await runCase(ctx, testCase);
|
|
57
|
+
results.push(outcome);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const passed = results.filter((r) => r.pass).length;
|
|
61
|
+
const failed = results.length - passed;
|
|
62
|
+
|
|
63
|
+
console.log(`PDS MCP Eval (${results.length} cases)`);
|
|
64
|
+
console.log(`Passed: ${passed}`);
|
|
65
|
+
console.log(`Failed: ${failed}`);
|
|
66
|
+
|
|
67
|
+
if (failed > 0) {
|
|
68
|
+
console.log('');
|
|
69
|
+
for (const result of results.filter((r) => !r.pass)) {
|
|
70
|
+
console.log(`- ${result.id} (${result.tool}) failed checks: ${result.failures.join(', ')}`);
|
|
71
|
+
}
|
|
72
|
+
process.exit(2);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
main().catch((error) => {
|
|
77
|
+
console.error('MCP eval failed:', error?.message || error);
|
|
78
|
+
process.exit(1);
|
|
79
|
+
});
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { spawn } from 'node:child_process';
|
|
4
|
+
|
|
5
|
+
const requiredTools = [
|
|
6
|
+
'get_tokens',
|
|
7
|
+
'find_utility_class',
|
|
8
|
+
'get_component_api',
|
|
9
|
+
'get_enhancer_metadata',
|
|
10
|
+
'get_config_relations',
|
|
11
|
+
'validate_pds_snippet',
|
|
12
|
+
];
|
|
13
|
+
|
|
14
|
+
function frame(message) {
|
|
15
|
+
const body = Buffer.from(JSON.stringify(message), 'utf8');
|
|
16
|
+
return Buffer.concat([
|
|
17
|
+
Buffer.from(`Content-Length: ${body.length}\r\n\r\n`, 'utf8'),
|
|
18
|
+
body,
|
|
19
|
+
]);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function parseFrames(state, chunk, onMessage) {
|
|
23
|
+
state.buffer = Buffer.concat([state.buffer, chunk]);
|
|
24
|
+
while (true) {
|
|
25
|
+
const separator = Buffer.from('\r\n\r\n', 'utf8');
|
|
26
|
+
const headerEnd = state.buffer.indexOf(separator);
|
|
27
|
+
if (headerEnd === -1) return;
|
|
28
|
+
|
|
29
|
+
const header = state.buffer.slice(0, headerEnd).toString('utf8');
|
|
30
|
+
const contentLengthMatch = header.match(/Content-Length:\s*(\d+)/i);
|
|
31
|
+
if (!contentLengthMatch) {
|
|
32
|
+
state.buffer = Buffer.alloc(0);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const contentLength = Number(contentLengthMatch[1]);
|
|
37
|
+
const bodyStart = headerEnd + separator.length;
|
|
38
|
+
const bodyEnd = bodyStart + contentLength;
|
|
39
|
+
if (state.buffer.length < bodyEnd) return;
|
|
40
|
+
|
|
41
|
+
const body = state.buffer.slice(bodyStart, bodyEnd).toString('utf8');
|
|
42
|
+
state.buffer = state.buffer.slice(bodyEnd);
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
onMessage(JSON.parse(body));
|
|
46
|
+
} catch {
|
|
47
|
+
// Ignore malformed JSON frame and continue.
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async function runHealthCheck() {
|
|
53
|
+
const child = spawn(process.execPath, ['./packages/pds-cli/bin/pds-mcp-server.js'], {
|
|
54
|
+
cwd: process.cwd(),
|
|
55
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
const state = { buffer: Buffer.alloc(0) };
|
|
59
|
+
let initialized = false;
|
|
60
|
+
|
|
61
|
+
const timer = setTimeout(() => {
|
|
62
|
+
console.error('â MCP health check timed out while waiting for server responses.');
|
|
63
|
+
child.kill();
|
|
64
|
+
process.exit(2);
|
|
65
|
+
}, 8000);
|
|
66
|
+
|
|
67
|
+
child.stderr.on('data', (data) => {
|
|
68
|
+
const text = String(data || '').trim();
|
|
69
|
+
if (text) {
|
|
70
|
+
console.error(`MCP server stderr: ${text}`);
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
child.stdout.on('data', (chunk) => {
|
|
75
|
+
parseFrames(state, chunk, (message) => {
|
|
76
|
+
if (message.id === 1 && message.result?.serverInfo?.name) {
|
|
77
|
+
initialized = true;
|
|
78
|
+
child.stdin.write(frame({ jsonrpc: '2.0', id: 2, method: 'tools/list', params: {} }));
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (message.id === 2 && Array.isArray(message.result?.tools)) {
|
|
83
|
+
const toolNames = message.result.tools.map((tool) => tool.name).filter(Boolean);
|
|
84
|
+
const missingTools = requiredTools.filter((toolName) => !toolNames.includes(toolName));
|
|
85
|
+
|
|
86
|
+
if (missingTools.length > 0) {
|
|
87
|
+
console.error('â MCP server is reachable but missing required tools:');
|
|
88
|
+
missingTools.forEach((toolName) => console.error(` - ${toolName}`));
|
|
89
|
+
clearTimeout(timer);
|
|
90
|
+
child.kill();
|
|
91
|
+
process.exit(3);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
console.log('â
PDS MCP health check passed');
|
|
95
|
+
console.log(` Server: ${message.result?.serverInfo?.name || 'pds-ssoT'}`);
|
|
96
|
+
console.log(` Tools: ${toolNames.sort().join(', ')}`);
|
|
97
|
+
clearTimeout(timer);
|
|
98
|
+
child.kill();
|
|
99
|
+
process.exit(0);
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
child.on('exit', (code) => {
|
|
105
|
+
if (!initialized) {
|
|
106
|
+
clearTimeout(timer);
|
|
107
|
+
process.exit(code || 1);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
child.stdin.write(
|
|
112
|
+
frame({
|
|
113
|
+
jsonrpc: '2.0',
|
|
114
|
+
id: 1,
|
|
115
|
+
method: 'initialize',
|
|
116
|
+
params: {
|
|
117
|
+
protocolVersion: '2024-11-05',
|
|
118
|
+
capabilities: {},
|
|
119
|
+
clientInfo: { name: 'pds-mcp-health', version: '1.0.0' },
|
|
120
|
+
},
|
|
121
|
+
})
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
runHealthCheck().catch((error) => {
|
|
126
|
+
console.error('â MCP health check failed:', error?.message || error);
|
|
127
|
+
process.exit(1);
|
|
128
|
+
});
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { createPdsMcpContext, getPdsMcpTools, runPdsMcpTool } from '../lib/pds-mcp-core.js';
|
|
4
|
+
|
|
5
|
+
const SERVER_NAME = 'pds-ssoT';
|
|
6
|
+
const SERVER_VERSION = '0.1.0';
|
|
7
|
+
const PROTOCOL_VERSION = '2024-11-05';
|
|
8
|
+
|
|
9
|
+
const ctx = createPdsMcpContext({ projectRoot: process.cwd() });
|
|
10
|
+
const tools = getPdsMcpTools();
|
|
11
|
+
|
|
12
|
+
let inputBuffer = Buffer.alloc(0);
|
|
13
|
+
|
|
14
|
+
function writeMessage(payload) {
|
|
15
|
+
const body = Buffer.from(JSON.stringify(payload), 'utf8');
|
|
16
|
+
const header = Buffer.from(`Content-Length: ${body.length}\r\n\r\n`, 'utf8');
|
|
17
|
+
process.stdout.write(Buffer.concat([header, body]));
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function sendResponse(id, result) {
|
|
21
|
+
writeMessage({ jsonrpc: '2.0', id, result });
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function sendError(id, code, message, data) {
|
|
25
|
+
writeMessage({
|
|
26
|
+
jsonrpc: '2.0',
|
|
27
|
+
id,
|
|
28
|
+
error: { code, message, data },
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async function handleMessage(message) {
|
|
33
|
+
const { id, method, params } = message || {};
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
if (method === 'initialize') {
|
|
37
|
+
return sendResponse(id, {
|
|
38
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
39
|
+
capabilities: {
|
|
40
|
+
tools: {},
|
|
41
|
+
},
|
|
42
|
+
serverInfo: {
|
|
43
|
+
name: SERVER_NAME,
|
|
44
|
+
version: SERVER_VERSION,
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (method === 'notifications/initialized' || method === 'initialized') {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (method === 'ping') {
|
|
54
|
+
return sendResponse(id, {});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (method === 'tools/list') {
|
|
58
|
+
return sendResponse(id, { tools });
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (method === 'tools/call') {
|
|
62
|
+
const toolName = params?.name;
|
|
63
|
+
const args = params?.arguments || {};
|
|
64
|
+
const data = await runPdsMcpTool(ctx, toolName, args);
|
|
65
|
+
return sendResponse(id, {
|
|
66
|
+
content: [
|
|
67
|
+
{
|
|
68
|
+
type: 'text',
|
|
69
|
+
text: JSON.stringify(data, null, 2),
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (method === 'prompts/list') {
|
|
76
|
+
return sendResponse(id, { prompts: [] });
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (method === 'resources/list') {
|
|
80
|
+
return sendResponse(id, { resources: [] });
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (typeof id !== 'undefined') {
|
|
84
|
+
return sendError(id, -32601, `Method not found: ${method}`);
|
|
85
|
+
}
|
|
86
|
+
} catch (error) {
|
|
87
|
+
if (typeof id !== 'undefined') {
|
|
88
|
+
return sendError(id, -32000, error?.message || 'Unhandled server error', {
|
|
89
|
+
stack: error?.stack || '',
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function tryReadFrame() {
|
|
96
|
+
const separator = Buffer.from('\r\n\r\n', 'utf8');
|
|
97
|
+
const headerEnd = inputBuffer.indexOf(separator);
|
|
98
|
+
if (headerEnd === -1) return false;
|
|
99
|
+
|
|
100
|
+
const header = inputBuffer.slice(0, headerEnd).toString('utf8');
|
|
101
|
+
const contentLengthMatch = header.match(/Content-Length:\s*(\d+)/i);
|
|
102
|
+
if (!contentLengthMatch) {
|
|
103
|
+
inputBuffer = Buffer.alloc(0);
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const contentLength = Number(contentLengthMatch[1]);
|
|
108
|
+
const bodyStart = headerEnd + separator.length;
|
|
109
|
+
const bodyEnd = bodyStart + contentLength;
|
|
110
|
+
if (inputBuffer.length < bodyEnd) return false;
|
|
111
|
+
|
|
112
|
+
const body = inputBuffer.slice(bodyStart, bodyEnd).toString('utf8');
|
|
113
|
+
inputBuffer = inputBuffer.slice(bodyEnd);
|
|
114
|
+
|
|
115
|
+
let message;
|
|
116
|
+
try {
|
|
117
|
+
message = JSON.parse(body);
|
|
118
|
+
} catch {
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
handleMessage(message);
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
process.stdin.on('data', (chunk) => {
|
|
127
|
+
inputBuffer = Buffer.concat([inputBuffer, chunk]);
|
|
128
|
+
while (tryReadFrame()) {
|
|
129
|
+
// Parse all complete frames currently in the input buffer.
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
process.stdin.on('error', () => {
|
|
134
|
+
process.exit(1);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
process.on('uncaughtException', (error) => {
|
|
138
|
+
const text = error?.stack || error?.message || String(error);
|
|
139
|
+
process.stderr.write(`[pds-mcp-server] uncaughtException: ${text}\n`);
|
|
140
|
+
});
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { mkdir, readFile, writeFile, access } from 'fs/promises';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
|
|
6
|
+
const projectRoot = process.cwd();
|
|
7
|
+
const serverCommand = 'node';
|
|
8
|
+
const serverArgs = ['./node_modules/@pure-ds/core/packages/pds-cli/bin/pds-mcp-server.js'];
|
|
9
|
+
|
|
10
|
+
async function readJsonIfExists(filePath) {
|
|
11
|
+
try {
|
|
12
|
+
await access(filePath);
|
|
13
|
+
const text = await readFile(filePath, 'utf8');
|
|
14
|
+
return JSON.parse(text);
|
|
15
|
+
} catch {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async function writeJson(filePath, value) {
|
|
21
|
+
await mkdir(path.dirname(filePath), { recursive: true });
|
|
22
|
+
await writeFile(filePath, `${JSON.stringify(value, null, 2)}\n`, 'utf8');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async function setupVSCodeConfig() {
|
|
26
|
+
const configPath = path.join(projectRoot, '.vscode', 'mcp.json');
|
|
27
|
+
const current = (await readJsonIfExists(configPath)) || {};
|
|
28
|
+
|
|
29
|
+
const servers = current.servers && typeof current.servers === 'object' ? current.servers : {};
|
|
30
|
+
servers['pure-ds'] = {
|
|
31
|
+
type: 'stdio',
|
|
32
|
+
command: serverCommand,
|
|
33
|
+
args: serverArgs,
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
await writeJson(configPath, { ...current, servers });
|
|
37
|
+
return configPath;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function setupCursorConfig() {
|
|
41
|
+
const configPath = path.join(projectRoot, '.cursor', 'mcp.json');
|
|
42
|
+
const current = (await readJsonIfExists(configPath)) || {};
|
|
43
|
+
|
|
44
|
+
const mcpServers = current.mcpServers && typeof current.mcpServers === 'object' ? current.mcpServers : {};
|
|
45
|
+
mcpServers['pure-ds'] = {
|
|
46
|
+
command: serverCommand,
|
|
47
|
+
args: serverArgs,
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
await writeJson(configPath, { ...current, mcpServers });
|
|
51
|
+
return configPath;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async function main() {
|
|
55
|
+
console.log('đ Setting up local PDS MCP server configuration...');
|
|
56
|
+
|
|
57
|
+
const [vscodePath, cursorPath] = await Promise.all([
|
|
58
|
+
setupVSCodeConfig(),
|
|
59
|
+
setupCursorConfig(),
|
|
60
|
+
]);
|
|
61
|
+
|
|
62
|
+
console.log('â
MCP configuration updated');
|
|
63
|
+
console.log(` âĸ VS Code: ${path.relative(projectRoot, vscodePath)}`);
|
|
64
|
+
console.log(` âĸ Cursor: ${path.relative(projectRoot, cursorPath)}`);
|
|
65
|
+
console.log('');
|
|
66
|
+
console.log('âšī¸ Restart your AI extension/IDE so it re-reads MCP server config.');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
main().catch((error) => {
|
|
70
|
+
console.error('â Failed to set up MCP:', error?.message || error);
|
|
71
|
+
process.exit(1);
|
|
72
|
+
});
|