AI assistants (MCP)
Connect Claude, ChatGPT, Cursor, VS Code, a chat bot or an assistant you build to your WeShipYou account over MCP and OAuth.
WeShipYou runs a Model Context Protocol (MCP) server, so an AI assistant can use WeShipYou for a signed-in user. The assistant never sees a password: the user approves it on a WeShipYou page or in the WeShipYou app, the assistant gets its own OAuth token, and the connection can be revoked at any time.
Server addresses
| Address | For |
|---|---|
https://weshipyou.com/api/mcp/account | Customers. Your locker, shipments, shop orders, wallet and saved addresses, in every account you can switch to. |
https://weshipyou.com/api/mcp | WeShipYou team members who buy personal shopper orders for customers. Any other user is refused on its approval page. |
https://weshipyou.com/api/mcp/support | WeShipYou support team members who follow up shipments held in customs. Their step-by-step guide is in the admin area, under Support → Support assistant. Any other user is refused on its approval page. |
Everything else (where to sign in, how to register) is discovered from the address. There is no API key or client secret to paste anywhere.
What a customer assistant can do
With the account server, an assistant can answer questions like "where is my package?", "what is in my locker?" or "how much is in my wallet?", and it can prepare these for you:
- paying a shipment that is waiting for payment;
- cancelling a shipment;
- approving and paying a shop order that is waiting for your approval;
- shipping packages that are in your locker (with a saved recipient, if you name one).
Let an assistant finish actions for you
If you'd rather not open the app each time, you can let one assistant finish some actions on its own. In the app, open Settings → Connected assistants and turn on, for that assistant, any of:
- Pay shipments;
- Ship locker packages to saved recipients (a new recipient is always added in the app);
- Approve and pay shop orders;
- Cancel shipments not handed over yet (a shipment a carrier already has always goes to the app).
Turning one on asks for your Face ID, fingerprint or phone passcode. After that, the assistant still tells you in the chat what it will do and the amount, and does it only after your yes. It pays from your wallet only (balance and points, never a card). If the wallet doesn't cover it, or the price went up from what you agreed to, the request comes to the app instead. Every action it finishes sends you a receipt and is listed under Done by your assistants. You can turn each action off at any time, without any check.
Pay less for shipping
The assistant can also help you choose before you ship:
- price your locker packages to a saved recipient with every service, after the coupons that apply;
- compare shipping them together with shipping them one by one;
- tell you when a little more weight would unlock a coupon, and which ready package in your locker adds it;
- check what the destination allows in one shipment (weight and value per parcel, quantities per category, customs points where they apply);
- list the coupons you can use.
These answers change nothing in your account. Some destinations also cap what one recipient may receive in a period; that is checked when the shipment is created.
The assistant never asks for your password or card numbers, and it can't change your profile, addresses or payment methods. To see or disconnect your assistants, open Settings → Connected assistants in the app, or Account → Connected assistants on the website.
Assistants with a connectors screen
In ChatGPT, Claude (web, desktop or mobile), Gemini or Grok, add a custom connector (also called a custom app, plugin or MCP server), paste the address, and choose OAuth if asked. Leave every client ID and secret field empty. A WeShipYou page opens: check that it shows your user and press Connect.
Assistants without a browser (sign-in code)
A chat bot (for example on Telegram) or an assistant running on a server can't open a sign-in page for you. It shows you a code like BCDF-GHJK and a link instead:
- Open the link, or in the WeShipYou app go to Settings → Connected assistants → Connect with a code.
- Check the assistant's name and what it will be able to do.
- Press Approve. The assistant continues on its own.
Apps configured with a file
Desktop and command-line apps read the server from a JSON file or a command. The first time they connect they open the WeShipYou approval page in your browser. The examples use the account server; the personal shopper team uses https://weshipyou.com/api/mcp instead.
Cursor (~/.cursor/mcp.json, or .cursor/mcp.json in a project):
{
"mcpServers": {
"weshipyou": {
"url": "https://weshipyou.com/api/mcp/account"
}
}
}VS Code (.vscode/mcp.json):
{
"servers": {
"weshipyou": {
"type": "http",
"url": "https://weshipyou.com/api/mcp/account"
}
}
}Claude Code:
claude mcp add --transport http weshipyou https://weshipyou.com/api/mcp/accountClaude Desktop through its config file (claude_desktop_config.json), which needs Node.js for the mcp-remote bridge. Adding the server under Settings → Connectors instead needs nothing installed:
{
"mcpServers": {
"weshipyou": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://weshipyou.com/api/mcp/account"]
}
}
}Building your own client
Any MCP client that supports the Streamable HTTP transport and OAuth 2.1 can connect. The flow is the one the MCP specification describes:
- Call the server without a token. It answers
401with aWWW-Authenticate: Bearer resource_metadata="…"header. - Read the protected resource metadata (RFC 9728) named there, for example
https://weshipyou.com/.well-known/oauth-protected-resource/api/mcp/account. It names the authorization server,https://weshipyou.com/api. - Read the authorization server metadata (RFC 8414) at
https://weshipyou.com/.well-known/oauth-authorization-server/api: the authorize, token, registration, revocation and device authorization endpoints. - Register your client (RFC 7591, dynamic client registration) with
POST https://weshipyou.com/api/oauth/register. It is a public client: no secret,token_endpoint_auth_methodisnone. - Send the user to the authorize endpoint with PKCE (
code_challenge_method=S256, required) andresourceset to the server address (RFC 8707), for exampleresource=https://weshipyou.com/api/mcp/account. The user signs in and approves on a WeShipYou page. - Exchange the code at the token endpoint (send the same
redirect_uriandresource), then call the server withAuthorization: Bearer <access_token>.
A registration request:
{
"client_name": "My assistant",
"redirect_uris": ["http://127.0.0.1:8765/callback"]
}Redirect URIs
Registration keeps only the redirect URIs WeShipYou accepts and refuses the request when none is left:
- Loopback (
http://127.0.0.1,http://localhost,http://[::1]) for desktop and command-line apps. The port may change between sign-ins; the host and the path must stay as registered. - App schemes WeShipYou has allowed, such as
cursor://. - https callbacks of assistants WeShipYou has allowed (hosted assistants such as ChatGPT and Claude). To have a hosted assistant added, contact support with its callback URL.
Device sign-in (RFC 8628)
A client with no browser and no callback (a bot on a server) uses the device authorization grant instead of steps 5 and 6.
Register it with the device grant only; it needs no redirect URI:
{
"client_name": "My bot",
"grant_types": ["urn:ietf:params:oauth:grant-type:device_code"]
}Ask for codes with a form-encoded POST https://weshipyou.com/api/oauth/device_authorization (client_id, and resource set to the server address). The answer:
{
"device_code": "wsyd_…",
"user_code": "BCDF-GHJK",
"verification_uri": "https://weshipyou.com/agent-connect",
"verification_uri_complete": "https://weshipyou.com/agent-connect?code=BCDF-GHJK",
"expires_in": 600,
"interval": 5
}Show the user the user_code and the verification_uri_complete link, then poll the token endpoint with grant_type=urn:ietf:params:oauth:grant-type:device_code, device_code and client_id, no faster than every interval seconds:
| Error | Meaning |
|---|---|
authorization_pending | The user hasn't decided yet. Keep polling. |
slow_down | You polled too fast. Wait longer between polls. |
access_denied | The user denied it. Stop. |
expired_token | The code expired (10 minutes), or the approval was not claimed within 10 minutes. Start again. |
invalid_grant | Unknown code, or already used: a code gives one connection. |
The answer after approval is the same token pair as step 6.
Tokens
| Token | Lasts | Notes |
|---|---|---|
| Authorization code | 60 seconds | Single use, even when the exchange fails. |
| Access token | 1 hour | Opens only the server named in resource. |
| Refresh token | 30 days | Rotated on every use; a retry within 30 seconds gets the same new pair. |
Refresh with grant_type=refresh_token and keep only the newest refresh token: using an old one after those 30 seconds revokes the whole connection. When the connection is revoked, or the user no longer has access, the server answers 401 and the client must send the user through the approval page again.
Transport
The server is stateless: send every JSON-RPC message with POST to the server address and read the JSON answer. There is no session id and no event stream, so GET and DELETE answer 405. Call tools/list for the tools and their input schemas; the tools describe themselves, so do not hard-code their arguments.
On the account server, the request_* tools return a request id and send the user a notification; get_request_status tells you whether the user has opened, declined or done it, read from the shipment or order itself. Tell the user to confirm in the app; never ask them for card details.
get_automatic_actions lists the actions the user let your client finish. For those, tell the user what you will do and the amount, and after their yes call the request_* tool with confirmedInChat: true and confirmedTotal (the USD amount they agreed to). The answer then carries automatic: { ran: true, … } with what was charged, or ran: false with the reason it went to the app instead (the wallet does not cover it, a handed-over shipment, …). A price above confirmedTotal is refused; quote again and ask. sendToApp: true always sends the request to the app. Never send confirmedInChat without the user's yes to that exact action.
quote_shipping, optimize_shipment, check_destination_limits and find_coupons are read-only: they quote with the account's coupons, compare shipping together with one by one, find coupon weight gaps and check the destination's limits.