Skip to main content

Developer guide

MCP Tool integration contract

The current authorization callback, risk annotation, candidate-field mapping, and launch checklist for MCP Tools.

Authorization login callback

Install the SDK:

sh
pnpm add mcp-auth-web

API environments (engineUrl is the base URL, without a path):

Full authorization callback URL: https://xxx.com/openapi/v1/mcp/authorization/callback

The SDK adds this path automatically.

Return credentials after login succeeds:

ts
import { createMcpAuthClient } from 'mcp-auth-web'

const mcpAuth = createMcpAuthClient({
  engineUrl: 'https://aim-api-test.proton-system.com',
})

mcpAuth.complete({
  Authorization: `Bearer ${token}`,
})

When login fails or the user cancels:

ts
mcpAuth.fail({ code, message })
mcpAuth.cancel()

Starting with mcp-auth-web@0.3.1, getMcpAuthErrorMessage(error) provides SDK-maintained, safe default messages in Chinese. Your UI displays them; use error codes for custom copy or translations. Catch errors from complete(), fail(), and cancel(). Do not unconditionally call fail() from a complete() catch, or expose credentials and authorization URLs from raw errors.

ts
import { getMcpAuthErrorMessage } from 'mcp-auth-web'

try {
  mcpAuth.complete({ Authorization: `Bearer ${token}` })
} catch (error) {
  message.error(getMcpAuthErrorMessage(error))
}

engineUrl is the Engine address supplied by the platform. complete directly accepts the credential Headers used by your MCP. The SDK reads exp from the Authorization Bearer JWT and generates expiresAt automatically, so callers do not pass an expiry.

The SDK automatically uses the HTTPS callback or the existing App authorization window. mcp-auth-web@0.3.0 changes the complete input shape; when upgrading, remove the headers wrapper and the manually supplied expiresAt. Omitting engineUrl continues to use the existing App authorization window.

If the method returns false, the current page has no available authorization return method:

ts
if (!mcpAuth.isAvailable()) {
  message.error('This environment does not support authorization callbacks')
}

To verify, start authorization in App and finish login. Returning to App with “Authorized” means the integration succeeded. Production login and Engine URLs require device-accessible HTTPS with a valid certificate. Never record credentials or authorization URLs in logs, analytics, or error reports.

Common Tool risk annotations

Read Tool:

ts
annotations: {
  readOnlyHint: true
}

Write Tool:

ts
annotations: {
  destructiveHint: true
}

Tool types

1. List Tool

When a Tool returns candidates that users select before the selected value is filled into another Tool parameter, add this object at the root of outputSchema:

ts
outputSchema: {
  type: "object",
  properties: {...}, // optional
  "x-prerequisiteCandidate": {
    itemsPath: "data",
    valuePath: "id",
    labelPath: "name"
  }
}

The three fields mean:

  • itemsPath: where the candidate array is located in the Tool result.
  • valuePath: which field in each candidate becomes the value filled into the target parameter.
  • labelPath: which field in each candidate is shown to the user.

For example, the Tool returns:

json
{
  "data": [
    { "id": "1", "name": "Store A" },
    { "id": "2", "name": "Store B" }
  ]
}

Then:

  • itemsPath: "data" means the candidate list is the data array in the result.
  • valuePath: "id" means the selected item's id is filled into the target Tool.
  • labelPath: "name" means the selection card displays the item's name.

Contract checklist

  • Add x-prerequisiteCandidate to list Tools.
  • Do not add x-prerequisiteCandidate to detail or write Tools.
  • Add readOnlyHint: true to read Tools.
  • Add destructiveHint: true to write Tools.
  • Return a stable structure when a list is empty, such as {"data":[]}.
  • The actual Tool result must match x-prerequisiteCandidate.