diff --git a/.changeset/legal-cloths-spend.md b/.changeset/legal-cloths-spend.md new file mode 100644 index 0000000000..50d965307a --- /dev/null +++ b/.changeset/legal-cloths-spend.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-mcp-actions-backend': patch +--- + +Clarify error handling in readme and update handleError.ts to include all backstage/errors diff --git a/plugins/mcp-actions-backend/README.md b/plugins/mcp-actions-backend/README.md index d81d0207c5..39ec169dec 100644 --- a/plugins/mcp-actions-backend/README.md +++ b/plugins/mcp-actions-backend/README.md @@ -71,6 +71,31 @@ export const myPlugin = createBackendPlugin({ }); ``` +### Error Handling + +When errors are thrown from MCP actions, the backend will handle and surface error message for any error from `@backstage/errors`. Unknown errors will be handled by `@modelcontextprotocol/sdk`'s default error handling, which may result in a generic `500 Server Error` being returned. As a result, we recommend using errors from `@backstage/errors` when applicable. + +See https://backstage.io/docs/reference/errors/ for a full list of supported errors. + +When writing MCP tools, use the appropriate error from `@backstage/errors` when applicable: + +```ts +action: async ({ input }) => { + // ... get current user and some resource + + if (!resource) { + throw new NotFoundError(`Resource ${input.id} not found`); + } + + // Check if the user has permissions to access/use the resource + if (!hasPermission(user, resource)) { + throw new NotAllowedError( + `user does not have sufficient permissions for ${resource}`, + ); + } +}; +``` + ### Authentication Configuration By default, the Backstage backend requires authentication for all requests. diff --git a/plugins/mcp-actions-backend/src/services/handleErrors.ts b/plugins/mcp-actions-backend/src/services/handleErrors.ts index 67d92664eb..5266c80e75 100644 --- a/plugins/mcp-actions-backend/src/services/handleErrors.ts +++ b/plugins/mcp-actions-backend/src/services/handleErrors.ts @@ -32,6 +32,7 @@ const knownErrors = new Set([ 'NotModifiedError', 'NotImplementedError', 'ResponseError', + 'ServiceUnavailableError', ]); // Extracts the cause error, if the provided error is `ResponseError` or