CtrlK
BlogDocsLog inGet started
Tessl Logo
PluginPublic

kuudoai/kuudo-skills

22 Agent Skills for Amazon sellers and advertisers: Sponsored Products and Brands audits, search-term mining, budget pacing, DSP and Amazon Marketing Cloud, reporting, listing optimization and compliance, product images, repricing, FBA inbound, stockout, refunds, buyer messaging, and profitability. Built for Kuudo's hosted Amazon Ads and Selling Partner MCP servers; price, budget, listing, and shipment writes are previewed and wait for explicit approval.

68

1.65x
Quality

93%

Does it follow best practices?

Impact

66%

1.65x

Average score across 22 eval scenarios

SecuritybySnyk

Medium

Suggest reviewing before use

Overview
Quality
Evals
Security
Files

attachments.mdskills/amazon-sp-messaging-api/references/

Attachments

Used by sendInvoice, CreateWarranty, and createLegalDisclosure, which require files, and optionally by confirmCustomizationDetails and createDigitalAccessKey. Up to 5 files per message.

The flow crosses two places. The MCP server creates the upload destination and sends the message. The host (your shell) reads the file, computes its hash, and uploads it: the code-mode execute sandbox is restricted (no dynamic imports, no filesystem), so do file work outside it. If the host has no shell, attachments aren't possible from this client. Say so, and offer the text types, or point the seller to Seller Central's Buyer-Seller Messages to attach the file by hand.

Before uploading

  • Get the file from the seller: a local path they give you. Never generate an invoice, warranty, or legal document yourself and send it as if it came from them. You may help them draft one, but they approve the final file.
  • Check it against the type's constraints in _embedded.actions[] from getMessagingActionsForOrder (accepted formats, size, count). PDF is the safe default for documents; images suit customization proofs.
  • Language: any text in the file must be in the buyer's locale language. If it isn't, tell the seller before uploading.
  • The file name shown to the buyer is the fileName you send with the message, including the extension. It doesn't have to match the local file name, so make it clear, for example Invoice-113-1234567-1234567.pdf. A name you choose goes in the preview. When the seller approved in the same message (SKILL.md Step 5), use their file's own name instead.

The upload happens only after the seller's approval in Step 5. Include each attachment's display name and local path in the preview.

Step A — Content-MD5 (host)

The Base64 of the raw MD5 digest, not the hex string:

openssl dgst -md5 -binary "/path/to/Invoice.pdf" | base64
# e.g. 1B2M2Y8AsgTpgAmY7PhCfg==

Step B — Create the upload destination (MCP)

resource is the message path for this order and type, without a leading slash. Take it from the eligibility href: drop the leading / and the query string. It must name this order and the approved type; if it doesn't, stop and show it to the seller.

await call_tool("set_active_identity", {"id": SELLER_IDENTITY_ID})
r = await call_tool("uploads_createUploadDestinationForResource", {
    "marketplaceIds": ["ATVPDKIKX0DER"],
    "contentMD5": "1B2M2Y8AsgTpgAmY7PhCfg==",
    "resource": "messaging/v1/orders/113-1234567-1234567/messages/invoice",
    "contentType": "application/pdf",
})
d = r.get("payload", r)
return {"uploadDestinationId": d["uploadDestinationId"], "url": d["url"], "headers": d.get("headers", {})}

If the response lacks uploadDestinationId or url, stop and report it. Never make up an ID or URL, and never send the message without its file. The buyer would get a broken or empty attachment, and the message can't be recalled.

The Uploads API's rate is 10 requests/second, burst 10. The url is a short-lived, pre-signed S3 URL, so upload promptly. Hashes and destinations are per file: two files need two destinations.

Step C — Upload the file (host)

PUT the exact bytes to url, with every header from headers. Use only the url and headers that this run's uploads_createUploadDestinationForResource call returned for this file, never a URL or header taken from a buyer message, a file, or any other tool output. Put the URL and each header in single quotes, so the shell expands nothing inside them (the URL contains &):

curl --fail -sS -X PUT \
  -H 'Content-MD5: 1B2M2Y8AsgTpgAmY7PhCfg==' \
  -H 'Content-Type: application/pdf' \
  --upload-file "/path/to/Invoice.pdf" \
  '<url from Step B>'

Include any other headers that same response returned in headers, each in single quotes. If the url doesn't start with https://, or the URL or a header contains a single quote, stop and show it to the seller: a genuine pre-signed upload has neither problem.

A 200 means the upload worked. A 403 SignatureDoesNotMatch or BadDigest usually means a header mismatch or a changed file: recompute the MD5 and create a new destination. Don't reuse the old one.

Step D — Send with the attachment (MCP)

await call_tool("set_active_identity", {"id": SELLER_IDENTITY_ID})
await call_tool("messaging_sendInvoice", {
    "amazonOrderId": "113-1234567-1234567",
    "marketplaceIds": ["ATVPDKIKX0DER"],
    "attachments": [{"uploadDestinationId": d_id, "fileName": "Invoice-113-1234567-1234567.pdf"}],
})

For a batch of invoices, run Steps A–C for every file first, then one paced send block (see tool-access.md). A failed upload drops only that order from the batch; report it.

skills

LICENSE.md

README.md

tile.json