Publish a tool without an HTTP route
Register a Nest provider as an MCP tool without creating a controller endpoint. The tool appears in the same search and detail catalog as your HTTP operations and runs through its own access policy and runtime validators.
Define the provider tool
The demo API's note-summary.ts contains this complete example:
import { Injectable } from "@nestjs/common";
import { defineProviderTool } from "@sezzlee/sdk-nestjs";
import { z } from "zod";
@Injectable()
export class NoteSummaryService {
summarize(text: string) {
return { characters: text.length, words: text.trim().split(/\s+/u).length };
}
}
export const noteSummaryTool = defineProviderTool({
name: "summarize_note",
description: "Count the characters and words in a note.",
provider: NoteSummaryService,
input: z.strictObject({ text: z.string().trim().min(1).max(10000) }),
output: z.strictObject({ characters: z.number().int(), words: z.number().int() }),
annotations: { readOnlyHint: true },
tags: ["notes"],
access: "public",
execute: (service, input) => service.summarize(input.text),
});The explicit public policy permits any caller admitted by your MCP transport. It does not remove
transport authentication. For a private tool, supply an access callback that checks
context.caller against your application's current permissions. It runs again on invocation and
when reading a stored result, so a discovery result cannot preserve revoked access.
Register it with the application
Add NoteSummaryService to your application's providers, and push noteSummaryTool into
options.tools in SezzleeModule.forRoot. Both changes are present in the demo API's
app.module.ts. No controller or HTTP route decorator is needed. Keep the provider and its
dependencies independent of HTTP request scope.
Use search_tools to find summarize_note, then load_tool and invoke_tool. Arguments
{ "text": "hello world" } return { "body": { "characters": 11, "words": 2 } }.
A direct HTTP request to /summarize_note returns 404 in the demo. The
agent-client --scenario provider scenario checks both the MCP result and that HTTP response.
Execution and compatibility
The provider path does not execute HTTP middleware, guards, pipes or interceptors. Put required
access rules in its policy and keep domain checks in the service. Runtime validators check inputs
and declared outputs; the shared response budgets, result storage and rate limits still apply.
Deadlines pass an abort signal to the handler, but cannot undo side effects or interrupt synchronous
JavaScript. Unexpected errors are redacted; use ProviderToolError only for an intentional public
business message.
HTTP operations retain their existing envelopes and OpenAPI export. Provider results have no
HTTP status. Provider tools are omitted from OpenAPI with a diagnostic. Custom rankers receive
provider documents without a route; custom limiter partitions can use providerTarget.
The normative contract is
provider-tools.md.