easyeda-mcp-pro 0.2.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.
Files changed (92) hide show
  1. package/README.md +304 -0
  2. package/dist/bridge/client.d.ts +16 -0
  3. package/dist/bridge/client.js +48 -0
  4. package/dist/bridge/client.js.map +1 -0
  5. package/dist/bridge/extension.d.ts +26 -0
  6. package/dist/bridge/extension.js +556 -0
  7. package/dist/bridge/extension.js.map +1 -0
  8. package/dist/bridge/manager.d.ts +37 -0
  9. package/dist/bridge/manager.js +225 -0
  10. package/dist/bridge/manager.js.map +1 -0
  11. package/dist/bridge/protocol.d.ts +68 -0
  12. package/dist/bridge/protocol.js +56 -0
  13. package/dist/bridge/protocol.js.map +1 -0
  14. package/dist/bridge/types.d.ts +52 -0
  15. package/dist/bridge/types.js +19 -0
  16. package/dist/bridge/types.js.map +1 -0
  17. package/dist/config/env.d.ts +98 -0
  18. package/dist/config/env.js +103 -0
  19. package/dist/config/env.js.map +1 -0
  20. package/dist/config/feature-flags.d.ts +16 -0
  21. package/dist/config/feature-flags.js +17 -0
  22. package/dist/config/feature-flags.js.map +1 -0
  23. package/dist/config/profiles.d.ts +10 -0
  24. package/dist/config/profiles.js +45 -0
  25. package/dist/config/profiles.js.map +1 -0
  26. package/dist/index.d.ts +2 -0
  27. package/dist/index.js +76 -0
  28. package/dist/index.js.map +1 -0
  29. package/dist/schemas/common.d.ts +123 -0
  30. package/dist/schemas/common.js +79 -0
  31. package/dist/schemas/common.js.map +1 -0
  32. package/dist/server/errors.d.ts +3 -0
  33. package/dist/server/errors.js +59 -0
  34. package/dist/server/errors.js.map +1 -0
  35. package/dist/server/factory.d.ts +17 -0
  36. package/dist/server/factory.js +60 -0
  37. package/dist/server/factory.js.map +1 -0
  38. package/dist/server/transports/http.d.ts +10 -0
  39. package/dist/server/transports/http.js +54 -0
  40. package/dist/server/transports/http.js.map +1 -0
  41. package/dist/storage/database.d.ts +19 -0
  42. package/dist/storage/database.js +136 -0
  43. package/dist/storage/database.js.map +1 -0
  44. package/dist/storage/index.d.ts +2 -0
  45. package/dist/storage/index.js +2 -0
  46. package/dist/storage/index.js.map +1 -0
  47. package/dist/storage/types.d.ts +26 -0
  48. package/dist/storage/types.js +9 -0
  49. package/dist/storage/types.js.map +1 -0
  50. package/dist/tools/L0_diagnostics.d.ts +6 -0
  51. package/dist/tools/L0_diagnostics.js +297 -0
  52. package/dist/tools/L0_diagnostics.js.map +1 -0
  53. package/dist/tools/L1_board.d.ts +6 -0
  54. package/dist/tools/L1_board.js +182 -0
  55. package/dist/tools/L1_board.js.map +1 -0
  56. package/dist/tools/L1_bom.d.ts +6 -0
  57. package/dist/tools/L1_bom.js +267 -0
  58. package/dist/tools/L1_bom.js.map +1 -0
  59. package/dist/tools/L1_drc_erc.d.ts +6 -0
  60. package/dist/tools/L1_drc_erc.js +235 -0
  61. package/dist/tools/L1_drc_erc.js.map +1 -0
  62. package/dist/tools/L1_export.d.ts +6 -0
  63. package/dist/tools/L1_export.js +214 -0
  64. package/dist/tools/L1_export.js.map +1 -0
  65. package/dist/tools/L1_schematic.d.ts +6 -0
  66. package/dist/tools/L1_schematic.js +182 -0
  67. package/dist/tools/L1_schematic.js.map +1 -0
  68. package/dist/tools/registry.d.ts +21 -0
  69. package/dist/tools/registry.js +55 -0
  70. package/dist/tools/registry.js.map +1 -0
  71. package/dist/tools/types.d.ts +53 -0
  72. package/dist/tools/types.js +2 -0
  73. package/dist/tools/types.js.map +1 -0
  74. package/dist/utils/logger.d.ts +4 -0
  75. package/dist/utils/logger.js +54 -0
  76. package/dist/utils/logger.js.map +1 -0
  77. package/dist/utils/redaction.d.ts +2 -0
  78. package/dist/utils/redaction.js +56 -0
  79. package/dist/utils/redaction.js.map +1 -0
  80. package/dist/vendors/digikey/client.d.ts +49 -0
  81. package/dist/vendors/digikey/client.js +200 -0
  82. package/dist/vendors/digikey/client.js.map +1 -0
  83. package/dist/vendors/jlcpcb/client.d.ts +79 -0
  84. package/dist/vendors/jlcpcb/client.js +156 -0
  85. package/dist/vendors/jlcpcb/client.js.map +1 -0
  86. package/dist/vendors/lcsc/client.d.ts +57 -0
  87. package/dist/vendors/lcsc/client.js +140 -0
  88. package/dist/vendors/lcsc/client.js.map +1 -0
  89. package/dist/vendors/mouser/client.d.ts +46 -0
  90. package/dist/vendors/mouser/client.js +141 -0
  91. package/dist/vendors/mouser/client.js.map +1 -0
  92. package/package.json +74 -0
@@ -0,0 +1,156 @@
1
+ import { request } from 'undici';
2
+ import { EasyEdaMcpError } from '../../schemas/common.js';
3
+ import { getLogger } from '../../utils/logger.js';
4
+ async function readBody(stream) {
5
+ const chunks = [];
6
+ for await (const chunk of stream) {
7
+ chunks.push(typeof chunk === 'string' ? Buffer.from(chunk) : chunk);
8
+ }
9
+ return Buffer.concat(chunks).toString('utf-8');
10
+ }
11
+ const MAX_RETRIES = 3;
12
+ const BASE_DELAY_MS = 1000;
13
+ export class JlcpcbClient {
14
+ config;
15
+ logger;
16
+ baseUrl;
17
+ constructor(config) {
18
+ this.config = config;
19
+ this.logger = getLogger();
20
+ this.baseUrl = config.JLCPCB_API_BASE_URL.replace(/\/+$/, '');
21
+ if (config.JLCPCB_MODE !== 'approved_api') {
22
+ throw new EasyEdaMcpError({
23
+ code: 'FEATURE_DISABLED',
24
+ message: 'JLCPCB API is not enabled. Set JLCPCB_MODE=approved_api to enable.',
25
+ suggestion: 'Set JLCPCB_MODE=approved_api and provide JLCPCB_CLIENT_ID and JLCPCB_CLIENT_SECRET.',
26
+ retryable: false,
27
+ });
28
+ }
29
+ if (!config.JLCPCB_CLIENT_ID || !config.JLCPCB_CLIENT_SECRET) {
30
+ throw new EasyEdaMcpError({
31
+ code: 'CREDENTIALS_MISSING',
32
+ message: 'JLCPCB credentials are missing.',
33
+ suggestion: 'Set JLCPCB_CLIENT_ID and JLCPCB_CLIENT_SECRET environment variables.',
34
+ retryable: false,
35
+ });
36
+ }
37
+ }
38
+ authHeaders() {
39
+ return {
40
+ 'x-client-id': this.config.JLCPCB_CLIENT_ID,
41
+ 'x-client-secret': this.config.JLCPCB_CLIENT_SECRET,
42
+ 'content-type': 'application/json',
43
+ };
44
+ }
45
+ async requestWithRetry(path, options) {
46
+ const method = options.method ?? 'POST';
47
+ const url = `${this.baseUrl}${path}`;
48
+ let lastError;
49
+ for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
50
+ try {
51
+ this.logger.debug({ url, method, attempt }, 'jlcpcb api call');
52
+ const { statusCode, body } = await request(url, {
53
+ method,
54
+ headers: this.authHeaders(),
55
+ body: options.body !== undefined ? JSON.stringify(options.body) : undefined,
56
+ });
57
+ const responseText = await readBody(body);
58
+ if (statusCode === 429) {
59
+ const retryAfter = 2000;
60
+ this.logger.warn({ url, retryAfter, attempt }, 'jlcpcb rate limited');
61
+ if (attempt < MAX_RETRIES) {
62
+ await new Promise((resolve) => setTimeout(resolve, retryAfter));
63
+ }
64
+ continue;
65
+ }
66
+ if (statusCode >= 500) {
67
+ this.logger.warn({ url, statusCode, attempt }, 'jlcpcb server error');
68
+ if (attempt < MAX_RETRIES) {
69
+ const delay = BASE_DELAY_MS * Math.pow(2, attempt - 1);
70
+ await new Promise((resolve) => setTimeout(resolve, delay));
71
+ }
72
+ continue;
73
+ }
74
+ if (statusCode < 200 || statusCode >= 300) {
75
+ let parsed = null;
76
+ try {
77
+ parsed = JSON.parse(responseText);
78
+ }
79
+ catch {
80
+ // ignore parse failure
81
+ }
82
+ throw new EasyEdaMcpError({
83
+ code: 'VENDOR_API_UNAVAILABLE',
84
+ message: parsed?.message ?? parsed?.error ?? `JLCPCB API returned status ${statusCode}`,
85
+ suggestion: 'Check JLCPCB credentials and request parameters.',
86
+ retryable: statusCode >= 500,
87
+ details: { statusCode, response: responseText.slice(0, 500) },
88
+ });
89
+ }
90
+ return JSON.parse(responseText);
91
+ }
92
+ catch (err) {
93
+ lastError = err;
94
+ if (err instanceof EasyEdaMcpError && !err.retryable) {
95
+ throw err;
96
+ }
97
+ if (attempt < MAX_RETRIES) {
98
+ const delay = BASE_DELAY_MS * Math.pow(2, attempt - 1);
99
+ this.logger.debug({ url, attempt, delay }, 'jlcpcb retry');
100
+ await new Promise((resolve) => setTimeout(resolve, delay));
101
+ }
102
+ }
103
+ }
104
+ throw lastError instanceof EasyEdaMcpError
105
+ ? lastError
106
+ : new EasyEdaMcpError({
107
+ code: 'VENDOR_API_UNAVAILABLE',
108
+ message: 'JLCPCB API request failed after retries.',
109
+ suggestion: 'Check network connectivity and JLCPCB API status.',
110
+ retryable: true,
111
+ details: { error: String(lastError) },
112
+ });
113
+ }
114
+ /**
115
+ * Request a quotation for a PCB order from JLCPCB.
116
+ * @param request - The PCB order specification
117
+ * @returns Quote result with total cost and breakdown
118
+ */
119
+ async getQuote(request) {
120
+ return this.requestWithRetry('/api/order/getQuote', {
121
+ method: 'POST',
122
+ body: request,
123
+ });
124
+ }
125
+ /**
126
+ * Place a PCB order with JLCPCB.
127
+ * @param request - The PCB order specification
128
+ * @returns Order result containing the order ID
129
+ */
130
+ async placeOrder(request) {
131
+ return this.requestWithRetry('/api/order/addOrder', {
132
+ method: 'POST',
133
+ body: request,
134
+ });
135
+ }
136
+ /**
137
+ * Get the current status of an existing JLCPCB order.
138
+ * @param orderId - The JLCPCB order ID
139
+ * @returns Order status and details
140
+ */
141
+ async getOrderStatus(orderId) {
142
+ return this.requestWithRetry(`/api/order/getOrderDetail?orderId=${encodeURIComponent(orderId)}`, { method: 'GET' });
143
+ }
144
+ /**
145
+ * Check JLCPCB capabilities for a given board specification.
146
+ * @param boardSpec - Board specification to check
147
+ * @returns Array of capability results
148
+ */
149
+ async checkCapabilities(boardSpec) {
150
+ return this.requestWithRetry('/api/capabilities/check', {
151
+ method: 'POST',
152
+ body: boardSpec,
153
+ });
154
+ }
155
+ }
156
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../../src/vendors/jlcpcb/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,57 @@
1
+ import { type EnvConfig } from '../../config/env.js';
2
+ export interface LcscPart {
3
+ lcsc: string;
4
+ manufacturer: string;
5
+ description: string;
6
+ datasheet: string;
7
+ stock: number;
8
+ price: string;
9
+ category: string;
10
+ package: string;
11
+ inStock: boolean;
12
+ }
13
+ export interface LcscSearchResponse {
14
+ parts: LcscPart[];
15
+ total: number;
16
+ }
17
+ export interface LcscCategoryPart {
18
+ lcsc: string;
19
+ manufacturer: string;
20
+ description: string;
21
+ price: string;
22
+ stock: number;
23
+ package: string;
24
+ datasheet: string;
25
+ }
26
+ export declare class LcscClient {
27
+ private config;
28
+ private logger;
29
+ private jlcsearchBase;
30
+ private lcscApiKey;
31
+ constructor(config: EnvConfig);
32
+ private jlcsearchRequest;
33
+ private lcscOfficialRequest;
34
+ /**
35
+ * Search LCSC parts by keyword query.
36
+ * Uses the jlcsearch API as primary backend, falls back to LCSC official API if available.
37
+ * @param query - The search keyword
38
+ * @param options - Optional search configuration (limit, page)
39
+ * @returns Search results with parts list and total count
40
+ */
41
+ searchParts(query: string, options?: {
42
+ limit?: number;
43
+ page?: number;
44
+ }): Promise<LcscSearchResponse>;
45
+ /**
46
+ * Get detailed information for a specific LCSC part by its LCSC code.
47
+ * @param lcscCode - The LCSC part number (e.g., "C12345")
48
+ * @returns The part detail or null if not found
49
+ */
50
+ getPartDetail(lcscCode: string): Promise<LcscPart | null>;
51
+ /**
52
+ * Get parts by category from LCSC.
53
+ * @param category - The category name or ID
54
+ * @returns Array of parts in the category
55
+ */
56
+ getPartsByCategory(category: string): Promise<LcscPart[]>;
57
+ }
@@ -0,0 +1,140 @@
1
+ import { request } from 'undici';
2
+ import { EasyEdaMcpError } from '../../schemas/common.js';
3
+ import { getLogger } from '../../utils/logger.js';
4
+ async function readBody(stream) {
5
+ const chunks = [];
6
+ for await (const chunk of stream) {
7
+ chunks.push(typeof chunk === 'string' ? Buffer.from(chunk) : chunk);
8
+ }
9
+ return Buffer.concat(chunks).toString('utf-8');
10
+ }
11
+ export class LcscClient {
12
+ config;
13
+ logger;
14
+ jlcsearchBase;
15
+ lcscApiKey;
16
+ constructor(config) {
17
+ this.config = config;
18
+ this.logger = getLogger();
19
+ this.jlcsearchBase = config.JLCSEARCH_BASE_URL.replace(/\/+$/, '');
20
+ this.lcscApiKey = config.LCSC_API_KEY;
21
+ }
22
+ async jlcsearchRequest(path, options) {
23
+ const method = options.method ?? 'GET';
24
+ const queryString = options.query ? '?' + new URLSearchParams(options.query).toString() : '';
25
+ const url = `${this.jlcsearchBase}${path}${queryString}`;
26
+ this.logger.debug({ url, method }, 'lcsc jlcsearch api call');
27
+ const { statusCode, body } = await request(url, {
28
+ method,
29
+ headers: { accept: 'application/json' },
30
+ });
31
+ const responseText = await readBody(body);
32
+ if (statusCode < 200 || statusCode >= 300) {
33
+ throw new EasyEdaMcpError({
34
+ code: 'VENDOR_API_UNAVAILABLE',
35
+ message: `LCSC jlcsearch API returned status ${statusCode}`,
36
+ suggestion: 'Check JLCSEARCH_BASE_URL and network connectivity.',
37
+ retryable: statusCode >= 500,
38
+ details: { statusCode, response: responseText.slice(0, 500) },
39
+ });
40
+ }
41
+ return JSON.parse(responseText);
42
+ }
43
+ async lcscOfficialRequest(path, options) {
44
+ const method = options.method ?? 'GET';
45
+ const url = `https://www.lcsc.com/api${path}`;
46
+ this.logger.debug({ url, method }, 'lcsc official api call');
47
+ const headers = {
48
+ accept: 'application/json',
49
+ };
50
+ if (this.lcscApiKey) {
51
+ headers['x-api-key'] = this.lcscApiKey;
52
+ }
53
+ if (options.body) {
54
+ headers['content-type'] = 'application/json';
55
+ }
56
+ const { statusCode, body } = await request(url, {
57
+ method,
58
+ headers,
59
+ body: options.body !== undefined ? JSON.stringify(options.body) : undefined,
60
+ });
61
+ const responseText = await readBody(body);
62
+ if (statusCode < 200 || statusCode >= 300) {
63
+ throw new EasyEdaMcpError({
64
+ code: 'VENDOR_API_UNAVAILABLE',
65
+ message: `LCSC official API returned status ${statusCode}`,
66
+ suggestion: 'Check LCSC_API_KEY and network connectivity.',
67
+ retryable: statusCode >= 500,
68
+ details: { statusCode, response: responseText.slice(0, 500) },
69
+ });
70
+ }
71
+ return JSON.parse(responseText);
72
+ }
73
+ /**
74
+ * Search LCSC parts by keyword query.
75
+ * Uses the jlcsearch API as primary backend, falls back to LCSC official API if available.
76
+ * @param query - The search keyword
77
+ * @param options - Optional search configuration (limit, page)
78
+ * @returns Search results with parts list and total count
79
+ */
80
+ async searchParts(query, options) {
81
+ const limit = options?.limit ?? 20;
82
+ const page = options?.page ?? 1;
83
+ try {
84
+ const data = await this.jlcsearchRequest('/api/search', {
85
+ query: { keyword: query, limit: String(limit), page: String(page) },
86
+ });
87
+ const parts = data.results ?? data.parts ?? [];
88
+ const total = data.count ?? data.total ?? parts.length;
89
+ return { parts, total };
90
+ }
91
+ catch (err) {
92
+ if (this.lcscApiKey) {
93
+ this.logger.debug('jlcsearch failed, falling back to lcsc official api');
94
+ return this.lcscOfficialRequest('/search', {
95
+ method: 'POST',
96
+ body: { keyword: query, limit, page },
97
+ });
98
+ }
99
+ throw err;
100
+ }
101
+ }
102
+ /**
103
+ * Get detailed information for a specific LCSC part by its LCSC code.
104
+ * @param lcscCode - The LCSC part number (e.g., "C12345")
105
+ * @returns The part detail or null if not found
106
+ */
107
+ async getPartDetail(lcscCode) {
108
+ try {
109
+ const data = await this.jlcsearchRequest(`/api/part/${encodeURIComponent(lcscCode)}`, {});
110
+ const part = 'part' in data ? data.part : data;
111
+ return part ?? null;
112
+ }
113
+ catch (err) {
114
+ if (this.lcscApiKey) {
115
+ this.logger.debug('jlcsearch failed, falling back to lcsc official api');
116
+ return this.lcscOfficialRequest(`/part/${encodeURIComponent(lcscCode)}`, {});
117
+ }
118
+ throw err;
119
+ }
120
+ }
121
+ /**
122
+ * Get parts by category from LCSC.
123
+ * @param category - The category name or ID
124
+ * @returns Array of parts in the category
125
+ */
126
+ async getPartsByCategory(category) {
127
+ try {
128
+ const data = await this.jlcsearchRequest(`/api/categories/${encodeURIComponent(category)}/parts`, {});
129
+ return data.parts ?? data.results ?? [];
130
+ }
131
+ catch (err) {
132
+ if (this.lcscApiKey) {
133
+ this.logger.debug('jlcsearch failed, falling back to lcsc official api');
134
+ return this.lcscOfficialRequest(`/categories/${encodeURIComponent(category)}/parts`, {});
135
+ }
136
+ throw err;
137
+ }
138
+ }
139
+ }
140
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../../src/vendors/lcsc/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ import { type EnvConfig } from '../../config/env.js';
2
+ export interface MouserPriceBreak {
3
+ quantity: number;
4
+ price: number;
5
+ }
6
+ export interface MouserPart {
7
+ mouserNumber: string;
8
+ manufacturer: string;
9
+ description: string;
10
+ datasheetUrl: string;
11
+ priceBreaks: MouserPriceBreak[];
12
+ availability: number;
13
+ leadTime: string;
14
+ rohs: boolean;
15
+ }
16
+ export interface MouserSearchResponse {
17
+ parts: MouserPart[];
18
+ total: number;
19
+ }
20
+ export declare class MouserClient {
21
+ private config;
22
+ private logger;
23
+ private baseUrl;
24
+ private apiKey;
25
+ constructor(config: EnvConfig);
26
+ private apiPost;
27
+ private parseMouserPart;
28
+ /**
29
+ * Search Mouser parts by keyword.
30
+ * @param query - The search keyword
31
+ * @returns Array of matching parts
32
+ */
33
+ searchByKeyword(query: string): Promise<MouserPart[]>;
34
+ /**
35
+ * Search Mouser parts by exact manufacturer part number.
36
+ * @param partNumber - The manufacturer part number
37
+ * @returns Array of matching parts
38
+ */
39
+ searchByPartNumber(partNumber: string): Promise<MouserPart[]>;
40
+ /**
41
+ * Get price and availability for a specific Mouser part number.
42
+ * @param mouserNumber - The Mouser system part number
43
+ * @returns Part details with pricing and stock
44
+ */
45
+ getPriceAndAvailability(mouserNumber: string): Promise<MouserPart>;
46
+ }
@@ -0,0 +1,141 @@
1
+ import { request } from 'undici';
2
+ import { EasyEdaMcpError } from '../../schemas/common.js';
3
+ import { getLogger } from '../../utils/logger.js';
4
+ async function readBody(stream) {
5
+ const chunks = [];
6
+ for await (const chunk of stream) {
7
+ chunks.push(typeof chunk === 'string' ? Buffer.from(chunk) : chunk);
8
+ }
9
+ return Buffer.concat(chunks).toString('utf-8');
10
+ }
11
+ export class MouserClient {
12
+ config;
13
+ logger;
14
+ baseUrl;
15
+ apiKey;
16
+ constructor(config) {
17
+ this.config = config;
18
+ this.logger = getLogger();
19
+ this.baseUrl = config.MOUSER_API_BASE_URL.replace(/\/+$/, '');
20
+ this.apiKey = config.MOUSER_API_KEY;
21
+ if (!config.MOUSER_ENABLED) {
22
+ throw new EasyEdaMcpError({
23
+ code: 'FEATURE_DISABLED',
24
+ message: 'Mouser API is not enabled. Set MOUSER_ENABLED=true to enable.',
25
+ suggestion: 'Set MOUSER_ENABLED=true and provide MOUSER_API_KEY in your environment.',
26
+ retryable: false,
27
+ });
28
+ }
29
+ if (!this.apiKey) {
30
+ throw new EasyEdaMcpError({
31
+ code: 'CREDENTIALS_MISSING',
32
+ message: 'Mouser API key is missing.',
33
+ suggestion: 'Set MOUSER_API_KEY environment variable.',
34
+ retryable: false,
35
+ });
36
+ }
37
+ }
38
+ async apiPost(endpoint, body) {
39
+ const url = `${this.baseUrl}${endpoint}?apiKey=${encodeURIComponent(this.apiKey)}`;
40
+ this.logger.debug({ url, endpoint }, 'mouser api call');
41
+ const { statusCode, body: responseBody } = await request(url, {
42
+ method: 'POST',
43
+ headers: { 'content-type': 'application/json' },
44
+ body: JSON.stringify(body),
45
+ });
46
+ const responseText = await readBody(responseBody);
47
+ if (statusCode === 429) {
48
+ throw new EasyEdaMcpError({
49
+ code: 'RATE_LIMITED',
50
+ message: 'Mouser API rate limit exceeded.',
51
+ suggestion: 'Retry after a short delay or reduce request frequency.',
52
+ retryable: true,
53
+ });
54
+ }
55
+ if (statusCode < 200 || statusCode >= 300) {
56
+ let parsed = null;
57
+ try {
58
+ parsed = JSON.parse(responseText);
59
+ }
60
+ catch {
61
+ // ignore
62
+ }
63
+ throw new EasyEdaMcpError({
64
+ code: 'VENDOR_API_UNAVAILABLE',
65
+ message: parsed?.ErrorMessage ?? `Mouser API returned status ${statusCode}`,
66
+ suggestion: 'Check MOUSER_API_KEY and request parameters.',
67
+ retryable: statusCode >= 500,
68
+ details: { statusCode, response: responseText.slice(0, 500) },
69
+ });
70
+ }
71
+ return JSON.parse(responseText);
72
+ }
73
+ parseMouserPart(raw) {
74
+ const priceBreaks = [];
75
+ const rawBreaks = raw['PriceBreaks'];
76
+ if (rawBreaks) {
77
+ for (const pb of rawBreaks) {
78
+ priceBreaks.push({
79
+ quantity: Number(pb['Quantity'] ?? 0),
80
+ price: Number(pb['Price'] ?? 0),
81
+ });
82
+ }
83
+ }
84
+ return {
85
+ mouserNumber: String(raw['MouserPartNumber'] ?? raw['MouserNumber'] ?? ''),
86
+ manufacturer: String(raw['Manufacturer'] ?? ''),
87
+ description: String(raw['Description'] ?? ''),
88
+ datasheetUrl: String(raw['DataSheetUrl'] ?? raw['DatasheetUrl'] ?? ''),
89
+ priceBreaks,
90
+ availability: Number(raw['AvailabilityInStock'] ?? raw['Availability'] ?? 0),
91
+ leadTime: String(raw['LeadTime'] ?? ''),
92
+ rohs: Boolean(raw['RoHS'] ?? raw['Rohs'] ?? false),
93
+ };
94
+ }
95
+ /**
96
+ * Search Mouser parts by keyword.
97
+ * @param query - The search keyword
98
+ * @returns Array of matching parts
99
+ */
100
+ async searchByKeyword(query) {
101
+ const response = await this.apiPost('/api/v1/search/keyword', {
102
+ SearchByKeywordRequest: { keyword: query },
103
+ });
104
+ const parts = response.SearchResults?.Parts ?? [];
105
+ return parts.map((p) => this.parseMouserPart(p));
106
+ }
107
+ /**
108
+ * Search Mouser parts by exact manufacturer part number.
109
+ * @param partNumber - The manufacturer part number
110
+ * @returns Array of matching parts
111
+ */
112
+ async searchByPartNumber(partNumber) {
113
+ const response = await this.apiPost('/api/v1/search/partnumber', {
114
+ SearchByPartNumberRequest: { partNumber },
115
+ });
116
+ const parts = response.SearchResults?.Parts ?? [];
117
+ return parts.map((p) => this.parseMouserPart(p));
118
+ }
119
+ /**
120
+ * Get price and availability for a specific Mouser part number.
121
+ * @param mouserNumber - The Mouser system part number
122
+ * @returns Part details with pricing and stock
123
+ */
124
+ async getPriceAndAvailability(mouserNumber) {
125
+ const response = await this.apiPost('/api/v1/search/partnumber', {
126
+ SearchByPartNumberRequest: { partNumber: mouserNumber },
127
+ });
128
+ const raw = response.SearchResults?.Parts?.[0];
129
+ if (!raw) {
130
+ throw new EasyEdaMcpError({
131
+ code: 'VENDOR_API_UNAVAILABLE',
132
+ message: `Mouser part ${mouserNumber} not found.`,
133
+ suggestion: 'Verify the Mouser part number is correct.',
134
+ retryable: false,
135
+ details: { mouserNumber },
136
+ });
137
+ }
138
+ return this.parseMouserPart(raw);
139
+ }
140
+ }
141
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../../src/vendors/mouser/client.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,74 @@
1
+ {
2
+ "name": "easyeda-mcp-pro",
3
+ "version": "0.2.0",
4
+ "mcpName": "io.github.oaslananka/easyeda-mcp-pro",
5
+ "description": "Production-grade MCP server for EasyEDA Pro: safe PCB design inspection, BOM sourcing, manufacturing export, and AI-assisted hardware review.",
6
+ "keywords": [
7
+ "mcp",
8
+ "model-context-protocol",
9
+ "easyeda",
10
+ "easyeda-pro",
11
+ "pcb",
12
+ "eda",
13
+ "jlcpcb",
14
+ "lcsc",
15
+ "hardware",
16
+ "schematic",
17
+ "bom"
18
+ ],
19
+ "author": "oaslananka",
20
+ "license": "MIT",
21
+ "type": "module",
22
+ "main": "dist/index.js",
23
+ "bin": {
24
+ "easyeda-mcp-pro": "dist/index.js"
25
+ },
26
+ "files": [
27
+ "dist",
28
+ "README.md",
29
+ "LICENSE"
30
+ ],
31
+ "engines": {
32
+ "node": ">=24 <27",
33
+ "pnpm": ">=11"
34
+ },
35
+ "dependencies": {
36
+ "@modelcontextprotocol/sdk": "^1.29.0",
37
+ "better-sqlite3": "^12.10.0",
38
+ "dotenv": "^17.4.2",
39
+ "pino": "^10.3.1",
40
+ "undici": "^8.3.0",
41
+ "ws": "^8.21.0",
42
+ "zod": "^4.4.3"
43
+ },
44
+ "devDependencies": {
45
+ "@eslint/js": "^10.0.1",
46
+ "@jlceda/pro-api-types": "^0.2.54",
47
+ "@types/better-sqlite3": "^7.6.13",
48
+ "@types/express": "^5.0.6",
49
+ "@types/node": "^24.12.4",
50
+ "@types/ws": "^8.5.14",
51
+ "eslint": "^10.4.1",
52
+ "prettier": "^3.8.3",
53
+ "tsx": "^4.22.4",
54
+ "typescript": "^6.0.3",
55
+ "typescript-eslint": "^8.60.1",
56
+ "vitest": "^4.1.8"
57
+ },
58
+ "scripts": {
59
+ "dev": "tsx watch src/index.ts",
60
+ "build": "tsc -p tsconfig.build.json",
61
+ "start": "node dist/index.js",
62
+ "typecheck": "tsc --noEmit",
63
+ "lint": "eslint .",
64
+ "format": "prettier --write .",
65
+ "format:check": "prettier --check .",
66
+ "test": "vitest run",
67
+ "test:watch": "vitest",
68
+ "test:coverage": "vitest run --coverage",
69
+ "inspector": "pnpm build && npx @modelcontextprotocol/inspector node dist/index.js",
70
+ "generate:methods": "tsx scripts/generate-method-registry.ts",
71
+ "generate:tools-doc": "tsx scripts/generate-tools-doc.ts",
72
+ "verify:tool-coverage": "tsx scripts/verify-tool-coverage.ts"
73
+ }
74
+ }