@jlcpcb/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.
package/src/index.ts ADDED
@@ -0,0 +1,117 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * jlc-mcp
5
+ * MCP server for JLC/EasyEDA component sourcing and library conversion
6
+ *
7
+ * This server uses LCSC part numbers (e.g., C2040) because LCSC is JLC PCB's
8
+ * preferred component supplier for PCB assembly (PCBA). Components sourced via
9
+ * LCSC are guaranteed to be available for JLC's assembly service.
10
+ *
11
+ * EasyEDA (owned by JLC/LCSC) provides the symbol and footprint data.
12
+ */
13
+
14
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
15
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
16
+ import {
17
+ CallToolRequestSchema,
18
+ ListToolsRequestSchema,
19
+ } from '@modelcontextprotocol/sdk/types.js';
20
+
21
+ import { tools, toolHandlers } from './tools/index.js';
22
+ import { createLogger, ensureGlobalLibraryTables } from '@jlcpcb/core';
23
+ import { startHttpServer } from './http/server.js';
24
+
25
+ const logger = createLogger('jlc-mcp');
26
+
27
+ // Create MCP server
28
+ const server = new Server(
29
+ {
30
+ name: 'jlc-mcp',
31
+ version: '0.1.0',
32
+ },
33
+ {
34
+ capabilities: {
35
+ tools: {},
36
+ },
37
+ }
38
+ );
39
+
40
+ // Handle list tools request
41
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
42
+ logger.debug('Listing tools');
43
+ return { tools };
44
+ });
45
+
46
+ // Handle tool calls
47
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
48
+ const { name, arguments: args } = request.params;
49
+
50
+ logger.debug(`Tool call: ${name}`, args);
51
+
52
+ const handler = toolHandlers[name];
53
+
54
+ if (!handler) {
55
+ return {
56
+ content: [{ type: 'text', text: `Unknown tool: ${name}` }],
57
+ isError: true,
58
+ };
59
+ }
60
+
61
+ try {
62
+ return await handler(args);
63
+ } catch (error) {
64
+ logger.error(`Tool error: ${name}`, error);
65
+ return {
66
+ content: [{
67
+ type: 'text',
68
+ text: `Error: ${error instanceof Error ? error.message : String(error)}`,
69
+ }],
70
+ isError: true,
71
+ };
72
+ }
73
+ });
74
+
75
+ // Run the server
76
+ async function main() {
77
+ // Register JLC libraries in KiCad global tables
78
+ const registration = await ensureGlobalLibraryTables();
79
+
80
+ if (!registration.success) {
81
+ logger.error('Failed to register JLC libraries in KiCad global tables', {
82
+ errors: registration.errors,
83
+ });
84
+ process.exit(1);
85
+ }
86
+
87
+ // Log registration summary
88
+ const { symLibTable, fpLibTable, libraryStubs, version } = registration;
89
+ if (symLibTable.created || symLibTable.modified || fpLibTable.created || fpLibTable.modified) {
90
+ logger.info(`JLC libraries registered in KiCad ${version}`, {
91
+ symLibTable: symLibTable.created
92
+ ? `created with ${symLibTable.entriesAdded} entries`
93
+ : symLibTable.modified
94
+ ? `added ${symLibTable.entriesAdded} entries`
95
+ : 'already configured',
96
+ fpLibTable: fpLibTable.created
97
+ ? 'created'
98
+ : fpLibTable.modified
99
+ ? 'updated'
100
+ : 'already configured',
101
+ stubsCreated: libraryStubs.symbolsCreated.length + libraryStubs.directoriesCreated.length,
102
+ });
103
+ }
104
+
105
+ // Start HTTP server for the component browser UI
106
+ const httpPort = startHttpServer();
107
+ logger.info(`Component browser available at http://localhost:${httpPort}`);
108
+
109
+ const transport = new StdioServerTransport();
110
+ await server.connect(transport);
111
+ logger.info('JLC MCP server running on stdio');
112
+ }
113
+
114
+ main().catch((error) => {
115
+ logger.error('Server error', error);
116
+ process.exit(1);
117
+ });
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Component details tools for MCP
3
+ */
4
+
5
+ import { z } from 'zod';
6
+ import type { Tool } from '@modelcontextprotocol/sdk/types.js';
7
+ import { easyedaClient } from '@jlcpcb/core';
8
+
9
+ export const getComponentTool: Tool = {
10
+ name: 'component_get',
11
+ description: 'Get detailed component information by LCSC part number (e.g., C2040). LCSC is JLC PCB\'s preferred supplier - components with LCSC IDs are available for JLC assembly. Returns symbol pins, footprint pads, manufacturer info, datasheet URL, and 3D model reference.',
12
+ inputSchema: {
13
+ type: 'object',
14
+ properties: {
15
+ lcsc_id: {
16
+ type: 'string',
17
+ description: 'LCSC part number (e.g., C2040, C14663)',
18
+ },
19
+ },
20
+ required: ['lcsc_id'],
21
+ },
22
+ };
23
+
24
+ export const GetComponentParamsSchema = z.object({
25
+ lcsc_id: z.string().regex(/^C\d+$/, 'Invalid LCSC part number'),
26
+ });
27
+
28
+ export async function handleGetComponent(args: unknown) {
29
+ const params = GetComponentParamsSchema.parse(args);
30
+
31
+ const component = await easyedaClient.getComponentData(params.lcsc_id);
32
+
33
+ if (!component) {
34
+ return {
35
+ content: [{
36
+ type: 'text' as const,
37
+ text: `Component ${params.lcsc_id} not found`,
38
+ }],
39
+ isError: true,
40
+ };
41
+ }
42
+
43
+ // Return a clean summary
44
+ const summary = {
45
+ info: component.info,
46
+ symbol: {
47
+ pin_count: component.symbol.pins.length,
48
+ pins: component.symbol.pins,
49
+ },
50
+ footprint: {
51
+ name: component.footprint.name,
52
+ type: component.footprint.type,
53
+ pad_count: component.footprint.pads.length,
54
+ pads: component.footprint.pads,
55
+ },
56
+ has_3d_model: !!component.model3d,
57
+ model_3d_uuid: component.model3d?.uuid,
58
+ };
59
+
60
+ return {
61
+ content: [{
62
+ type: 'text' as const,
63
+ text: JSON.stringify(summary, null, 2),
64
+ }],
65
+ };
66
+ }