@@ -54,7 +54,7 @@ The schema field allows defining a Zod-based validation schema for tool input pa
5454 To use hooks with MCP tools, follow the provider-based approach:
5555
5656 Step 1: Create a hook provider:
57- ``` typescript
57+ ``` ts
5858 // src/providers/my-hook.provider.ts
5959 export class MyHookProvider implements Provider <McpHookFunction > {
6060 constructor (@inject (LOGGER .LOGGER_INJECT ) private logger : ILogger ) {}
@@ -66,7 +66,7 @@ The schema field allows defining a Zod-based validation schema for tool input pa
6666 }
6767 ```
6868 Step 2: Add binding key to McpHookBindings:
69- ``` typescript
69+ ``` ts
7070 // src/keys.ts
7171 export namespace McpHookBindings {
7272 export const MY_HOOK = BindingKey .create <McpHookFunction >(' hooks.mcp.myHook' );
@@ -77,10 +77,65 @@ The schema field allows defining a Zod-based validation schema for tool input pa
7777 this .bind (McpHookBindings .MY_HOOK ).toProvider (MyHookProvider );
7878 ```
7979 Step 4: Use in decorator:
80- ``` typescript
80+ ``` ts
8181 @mcpTool ({
8282 name: ' my-tool' ,
8383 description: ' my-description'
8484 preHookBinding : McpHookBindings .MY_HOOK ,
8585 postHookBinding: ' hooks.mcp.myOtherHook' // or string binding key
8686 })
87+ ```
88+ ## MCP Access Control
89+ By default, any authenticated user can call the ` /mcp ` endpoint.
90+ To restrict which users can access MCP functionality, this extension supports adding a custom LoopBack 4 interceptor.
91+
92+ Create an interceptor that validates the authenticated user before the request reaches the MCP controller.
93+
94+ ``` ts
95+ import {
96+ InvocationContext ,
97+ InvocationResult ,
98+ Provider ,
99+ ValueOrPromise ,
100+ inject ,
101+ interceptor ,
102+ } from ' @loopback/core' ;
103+ import {HttpErrors } from ' @loopback/rest' ;
104+ import {AuthenticationBindings , IAuthUser } from ' loopback4-authentication' ;
105+
106+ @interceptor ()
107+ export class McpAccessInterceptor implements Provider <Interceptor > {
108+ constructor (
109+ @inject (AuthenticationBindings .CURRENT_USER , {optional: true })
110+ private readonly currentUser : IAuthUser ,
111+ ) {}
112+
113+ value() {
114+ return this .intercept .bind (this );
115+ }
116+
117+ intercept(
118+ invocationCtx : InvocationContext ,
119+ next : () => ValueOrPromise <InvocationResult >,
120+ ): ValueOrPromise <InvocationResult > {
121+ if (! this .currentUser ) {
122+ throw new HttpErrors .Unauthorized (' User not authenticated' );
123+ }
124+
125+ const user = this .currentUser ;
126+
127+ // Example rule: only admins or users with `access-mcp` permission
128+ if (user .role !== ' admin' && ! user .permissions ?.includes (' access-mcp' )) {
129+ throw new HttpErrors .Forbidden (
130+ ` User ${user .username } is not allowed to access MCP ` ,
131+ );
132+ }
133+
134+ return next ();
135+ }
136+ }
137+ ```
138+ Bind it in your ` application.ts ` :
139+ ``` ts
140+ this .bind (McpBindings .ACCESS_INTERCEPTOR ).toProvider (McpAccessInterceptor );
141+ ```
0 commit comments