plm-upload-mcp 1.0.0 → 1.0.1
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/index.mjs +22 -1
- package/package.json +1 -1
package/index.mjs
CHANGED
|
@@ -43,6 +43,13 @@ const MIME = {
|
|
|
43
43
|
}
|
|
44
44
|
const mimeFor = (name) => MIME[extname(name).toLowerCase()] || 'application/octet-stream'
|
|
45
45
|
|
|
46
|
+
// Supabase Storage rejects object keys with chars outside its safe set (notably
|
|
47
|
+
// '[' ']', which the common "[SKU] Name" convention starts with) -> the store
|
|
48
|
+
// call 400s with "storage upload failed: 400". The key is internal/UUID-prefixed
|
|
49
|
+
// and never shown, so sanitize it to the safe set; the Drive display name (the
|
|
50
|
+
// separate `upload` filename) keeps the original, brackets and all.
|
|
51
|
+
const storageKeyName = (name) => name.replace(/[^\w !\-.*'()&$@=;:+,?/]/g, '_')
|
|
52
|
+
|
|
46
53
|
// --- Auth: cache one access token, re-grant when it's near expiry. -----------
|
|
47
54
|
let cached = { token: null, exp: 0 }
|
|
48
55
|
async function getToken() {
|
|
@@ -80,7 +87,8 @@ async function uploadOne({ path, sku, skuName, category, bucket }) {
|
|
|
80
87
|
const mimeType = mimeFor(filename)
|
|
81
88
|
const token = await getToken()
|
|
82
89
|
|
|
83
|
-
|
|
90
|
+
// Store under a storage-safe key; the Drive file keeps the original filename below.
|
|
91
|
+
const params = new URLSearchParams({ action: 'store', sku, filename: storageKeyName(filename), mimeType })
|
|
84
92
|
const sResp = await fetch(`${EDGE}/drive-library?${params}`, {
|
|
85
93
|
method: 'POST',
|
|
86
94
|
headers: { 'content-type': mimeType, authorization: `Bearer ${token}` },
|
|
@@ -201,5 +209,18 @@ server.registerTool(
|
|
|
201
209
|
},
|
|
202
210
|
)
|
|
203
211
|
|
|
212
|
+
// `node index.mjs --selftest` — verify the storage-key sanitizer without a server.
|
|
213
|
+
if (process.argv.includes('--selftest')) {
|
|
214
|
+
const assert = (c, m) => { if (!c) { console.error('FAIL:', m); process.exit(1) } }
|
|
215
|
+
assert(storageKeyName('[MNT-0930-X0] HANDLEBAR MOUNT LEFT_260908.STEP')
|
|
216
|
+
=== '_MNT-0930-X0_ HANDLEBAR MOUNT LEFT_260908.STEP', 'brackets -> _')
|
|
217
|
+
assert(storageKeyName('BRG-0245-X0 Bushing_260908.pdf')
|
|
218
|
+
=== 'BRG-0245-X0 Bushing_260908.pdf', 'safe name unchanged')
|
|
219
|
+
const SAFE = /^[\w !\-.*'()&$@=;:+,?/]*$/
|
|
220
|
+
assert(SAFE.test(storageKeyName('a[b]c#d%e\\f"g<h>i.STEP')), 'all unsafe chars replaced')
|
|
221
|
+
console.log('selftest ok')
|
|
222
|
+
process.exit(0)
|
|
223
|
+
}
|
|
224
|
+
|
|
204
225
|
const transport = new StdioServerTransport()
|
|
205
226
|
await server.connect(transport)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "plm-upload-mcp",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "MCP server to bulk-upload SolidWorks exports (STEP/PDF) into the LionsBot PLM by SKU.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"keywords": ["mcp", "modelcontextprotocol", "lionsbot", "plm", "solidworks"],
|