Connect MCP and CLI
Connect an OAuth MCP client or the Rinhelp CLI and use every current operator operation.
Connect an MCP client or use the Rinhelp CLI to manage your Rinhelp workspace. Both expose the operations listed below. Your access token selects the workspace; never pass organization_id.
Connect MCP
Add https://mcp.rinhelp.com/mcp as a remote HTTP MCP server in a client that supports OAuth. Complete the browser authorization for the rinhelp.operator scope.
After connecting, call account.whoami and confirm the returned organization and role before making changes. MCP clients discover the current operation list through tools/list; the reference on this page is generated from that same shared catalog.
Legacy /sse connections are unsupported. Use the /mcp endpoint and a client with OAuth support.
Use the CLI
The current CLI is shipped in the Rinhelp repository, not published as an npm package. From a source checkout, install the workspace dependencies and run the CLI entry point:
git clone https://github.com/wilbertliu/rinhelp.git
cd rinhelp
pnpm install
pnpm --filter @rinhelp/cli exec node bin/rinhelp.mjs login
login opens browser OAuth, asks for the rinhelp.operator scope, and stores credentials locally. Stored credentials refresh when the saved credential contains refresh metadata. Use another endpoint with --mcp:
pnpm --filter @rinhelp/cli exec node bin/rinhelp.mjs login --mcp https://mcp.example.com/mcp
For the examples below, run the command with pnpm --filter @rinhelp/cli exec node bin/rinhelp.mjs from the checkout, or make that entry point available as rinhelp on your PATH.
rinhelp --json account.whoami
rinhelp ops
rinhelp sources.start_crawl --help
rinhelp --json inbox.list_items --input '{}'
Use exactly one input style per command:
--input '<json object>'for inline JSON.--input-file <path>for a file, or--input-file -for stdin.- Field flags such as
--conversation-idand--idempotency-key.
Do not mix input JSON with field flags. rinhelp logout removes saved credentials. RINHELP_ACCESS_TOKEN can supply an access token instead of saved credentials; that environment value does not carry the saved issuer/client metadata used for automatic refresh.
The CLI returns exit code 0 for success, 1 for another operator or transport failure, 2 for invalid input or usage, 3 when login is required or a credential is expired, and 4 when the operation is forbidden. With --json, successful calls print { "ok": true, "op": "...", "output": ... }; operator errors print { "ok": false, "error": { "code": "...", "message": "..." } }. Unexpected runtime failures can still write to stderr and exit 1.
Operation behavior to know first
- Crawls return
run_idimmediately. Pass it assource_idtosources.showand poll until ready or failed. widget.previewreturns one completed ephemeral answer, not a stream.email.setupreturns the exact PostShiba forwarding destination. The merchant keeps the support mailbox, configures forwarding, and keeps a mailbox copy; Rinhelp does not change MX.email.verifysends a test, thenemail.showreports whether forwarding is verified or failed.inbox.listlists conversations.inbox.list_itemsincludes conversations and pending refunds. Passcontrol=closedto select closed work.inbox.replyposts a teammate reply. The first reply claims the thread; it does not impersonate the visitor.- Refund requests do not execute refunds. Obtain a deliberate human decision before calling
inbox.approve_action; that call executes a pending Shopify refund.inbox.reject_actionrejects it without executing. Getaction_idfrom the refund item’srefund.idininbox.list_items. - Generate one
idempotency_keyper intent and reuse it on retry with the same input. The CLI does not generate keys. For a failed refund approval, reuse the same key; do not retry an unconfirmed Shopify result. team.inviteandteam.cancel_inviterequire theownerrole. The role required by every operation appears below.
Current operations
This reference contains all 23 current operations (1 account, 4 sources, 3 widget, 3 email, 7 inbox, 3 team, 2 shopify). The names are the same in MCP and the CLI. It is generated from the shared operator catalog, so this page does not document a second API.
account.whoami
Return the signed-in operator (user, organization, role).
- Role:
member - Retry:
safe
Input schema
{
"type": "object",
"additionalProperties": false,
"properties": {}
}
sources.list
List crawl/index runs for this organization.
- Role:
member - Retry:
safe
Input schema
{
"type": "object",
"additionalProperties": false,
"properties": {
"cursor": {
"type": "string"
},
"limit": {
"type": "integer",
"minimum": 1,
"maximum": 100
}
}
}
sources.start_crawl
Start a site crawl (async). Returns run_id immediately. Poll sources.show. Same idempotency_key + url + org replays the same run.
- Role:
member - Retry:
idempotency_key
Input schema
{
"type": "object",
"additionalProperties": false,
"required": ["url", "idempotency_key"],
"properties": {
"url": {
"type": "string",
"format": "uri"
},
"idempotency_key": {
"type": "string",
"minLength": 1,
"maxLength": 200
}
}
}
sources.show
Get one ingest run and its pages. Crawl is async; poll until ready or failed.
- Role:
member - Retry:
safe
Input schema
{
"type": "object",
"additionalProperties": false,
"required": ["source_id"],
"properties": {
"source_id": {
"type": "string",
"minLength": 1
}
}
}
sources.show_page
Get one crawled page and its chunks.
- Role:
member - Retry:
safe
Input schema
{
"type": "object",
"additionalProperties": false,
"required": ["page_id"],
"properties": {
"page_id": {
"type": "string",
"minLength": 1
}
}
}
widget.show
Widget config, publishable key, and install snippet for this org.
- Role:
member - Retry:
safe
Input schema
{
"type": "object",
"additionalProperties": false,
"properties": {}
}
widget.update_config
Patch widget config (greeting, title, colors, position). Omitted fields keep their current values.
- Role:
member - Retry:
idempotent
Input schema
{
"type": "object",
"additionalProperties": false,
"minProperties": 1,
"properties": {
"primary_color": {
"type": "string"
},
"position": {
"type": "string",
"enum": ["bottom-right", "bottom-left"]
},
"title": {
"type": "string"
},
"greeting": {
"type": "string"
}
}
}
widget.preview
Run one ephemeral preview question against the corpus. Returns the completed answer, not a stream.
- Role:
member - Retry:
safe
Input schema
{
"type": "object",
"additionalProperties": false,
"required": ["message"],
"properties": {
"message": {
"type": "string",
"minLength": 1,
"maxLength": 4000
}
}
}
email.show
Show the merchant support address, exact PostShiba forwarding target, and setup state. This does not change MX or send mail.
- Role:
member - Retry:
safe
Input schema
{
"type": "object",
"additionalProperties": false,
"properties": {}
}
email.setup
Create or reuse the PostShiba receive target for support_email. The merchant keeps the mailbox and forwards into the returned address; Rinhelp does not change MX.
- Role:
member - Retry:
idempotent - Hint: open-world operation.
Input schema
{
"type": "object",
"additionalProperties": false,
"required": ["support_email"],
"properties": {
"support_email": {
"type": "string",
"minLength": 1
}
}
}
email.verify
Send one forwarding test to the configured support address. This starts verification; call email.show until status is verified. Requires idempotency_key and reuse it on retry.
- Role:
member - Retry:
idempotency_key - Hint: open-world operation.
Input schema
{
"type": "object",
"additionalProperties": false,
"required": ["idempotency_key"],
"properties": {
"idempotency_key": {
"type": "string",
"minLength": 1,
"maxLength": 200
}
}
}
inbox.list
List visitor conversations in the shared inbox. Default is queued and live chats. Pass control=closed to list resolved live chats. Use inbox.list_items for mixed inbox items.
- Role:
member - Retry:
safe
Input schema
{
"type": "object",
"additionalProperties": false,
"properties": {
"cursor": {
"type": "string"
},
"limit": {
"type": "integer",
"minimum": 1,
"maximum": 100
},
"control": {
"type": "string",
"enum": ["closed"]
}
}
}
inbox.list_items
List the inbox work queue (conversations and pending refunds), the same items as the console. Default is the open queue. Pass control=closed for resolved chats and closed refunds. Use a refund_action item’s refund.id as action_id for inbox.approve_action or inbox.reject_action.
- Role:
member - Retry:
safe
Input schema
{
"type": "object",
"additionalProperties": false,
"properties": {
"cursor": {
"type": "string"
},
"limit": {
"type": "integer",
"minimum": 1,
"maximum": 100
},
"control": {
"type": "string",
"enum": ["closed"]
}
}
}
inbox.show
Get one conversation and its messages. Poll this instead of opening a live WebSocket.
- Role:
member - Retry:
safe
Input schema
{
"type": "object",
"additionalProperties": false,
"required": ["conversation_id"],
"properties": {
"conversation_id": {
"type": "string",
"minLength": 1
}
}
}
inbox.reply
Post a teammate reply (first reply claims the thread). Requires idempotency_key. Does not impersonate the visitor.
- Role:
member - Retry:
idempotency_key
Input schema
{
"type": "object",
"additionalProperties": false,
"required": ["conversation_id", "message", "idempotency_key"],
"properties": {
"conversation_id": {
"type": "string",
"minLength": 1
},
"message": {
"type": "string",
"minLength": 1,
"maxLength": 4000
},
"idempotency_key": {
"type": "string",
"minLength": 1,
"maxLength": 200
}
}
}
inbox.end_live
End live chat on a conversation.
- Role:
member - Retry:
idempotent
Input schema
{
"type": "object",
"additionalProperties": false,
"required": ["conversation_id"],
"properties": {
"conversation_id": {
"type": "string",
"minLength": 1
}
}
}
team.show
List members. Pending invitations included only for owners (same as the console).
- Role:
member - Retry:
safe
Input schema
{
"type": "object",
"additionalProperties": false,
"properties": {}
}
team.invite
Invite a member by email (owners only, role=member only). A pending invite for the same org+email is returned, not duplicated.
- Role:
owner - Retry:
idempotent
Input schema
{
"type": "object",
"additionalProperties": false,
"required": ["email"],
"properties": {
"email": {
"type": "string",
"minLength": 1
}
}
}
team.cancel_invite
Cancel a pending invitation (owners only).
- Role:
owner - Retry:
idempotent - Hint: destructive operation.
Input schema
{
"type": "object",
"additionalProperties": false,
"required": ["invitation_id"],
"properties": {
"invitation_id": {
"type": "string",
"minLength": 1
}
}
}
shopify.request_refund
Request a Shopify refund for an order (lookup only; does not execute). Requires idempotency_key. Reuse the same key to replay the same request. Amount omitted requests the full refundable balance.
- Role:
member - Retry:
idempotent
Input schema
{
"type": "object",
"additionalProperties": false,
"required": ["order_number", "email", "idempotency_key"],
"properties": {
"order_number": {
"type": "string",
"minLength": 1
},
"email": {
"type": "string",
"minLength": 1
},
"amount": {
"type": "string",
"minLength": 1
},
"reason": {
"type": "string",
"minLength": 1
},
"idempotency_key": {
"type": "string",
"minLength": 1,
"maxLength": 200
}
}
}
shopify.lookup_order
Look up a Shopify order by order number and email. Returns the widget status and tracking, or not_found / shop_unavailable. Requires idempotency_key. Reuse the same key to replay the same lookup.
- Role:
member - Retry:
idempotency_key
Input schema
{
"type": "object",
"additionalProperties": false,
"required": ["order_number", "email", "idempotency_key"],
"properties": {
"order_number": {
"type": "string",
"minLength": 1
},
"email": {
"type": "string",
"minLength": 1
},
"idempotency_key": {
"type": "string",
"minLength": 1,
"maxLength": 200
}
}
}
inbox.approve_action
Approve a pending refund action and execute the Shopify refund. List inbox.list_items first and pass the refund.id as action_id. Reuse the same idempotency_key if the refund failed. Do not retry an unconfirmed Shopify result.
- Role:
member - Retry:
idempotent - Hint: destructive operation.
Input schema
{
"type": "object",
"additionalProperties": false,
"required": ["action_id", "idempotency_key"],
"properties": {
"action_id": {
"type": "string",
"minLength": 1
},
"idempotency_key": {
"type": "string",
"minLength": 1,
"maxLength": 200
}
}
}
inbox.reject_action
Reject a pending refund action without executing a Shopify refund. Requires action_id and idempotency_key.
- Role:
member - Retry:
idempotent
Input schema
{
"type": "object",
"additionalProperties": false,
"required": ["action_id", "idempotency_key"],
"properties": {
"action_id": {
"type": "string",
"minLength": 1
},
"idempotency_key": {
"type": "string",
"minLength": 1,
"maxLength": 200
}
}
}