Model Context Protocol (MCP)
@tsed/platform-mcp brings Model Context Protocol support to every Ts.ED HTTP adapter. The module exposes a configurable /mcp endpoint, lets you register tools/resources/prompts through DI-aware helpers or decorators, and reuses the same MCP primitives that power the CLI integration.
Need a standalone CLI implementation?
Use @tsed/cli-mcp (Ts.ED CLI v7) to generate a streamable or stdio MCP server that ships with the same functional API. The CLI package is ideal for headless agents, while @tsed/platform-mcp embeds MCP inside your HTTP application.
Installation
npm install @tsed/platform-mcpyarn add @tsed/platform-mcppnpm add @tsed/platform-mcpbun add @tsed/platform-mcpimport {Configuration} from "@tsed/di";
import "@tsed/platform-express";
import "@tsed/platform-mcp";
@Configuration({
mcp: {
path: "/mcp" // defaults to "/mcp"
}
})
export class Server {}Register your MCP providers in the mcp configuration so the module can expose them through the HTTP endpoint:
import {Configuration} from "@tsed/di";
import "@tsed/platform-express";
import "@tsed/platform-mcp";
import {TestPrompt} from "./prompts/TestPrompt.js";
import {TestResource} from "./resources/TestResource.js";
import {TestTool} from "./tools/TestTool.js";
@Configuration({
mcp: {
prompts: [TestPrompt],
resources: [TestResource],
tools: [TestTool]
}
})
export class Server {}All registration helpers return DI tokens. Add those tokens to a module providers array, or expose them from a feature module. Both the decorators and the function API execute handlers inside a Ts.ED DIContext, so you can reuse your existing providers and services.
Register tools
Tools expose executable actions to MCP clients. Use them for operations that take structured input and return content or structured results, such as querying a service, triggering a workflow, or composing data from your application. With decorators, the preferred approach is to declare Ts.ED models and let the framework derive both the input and the output schemas from the method signature and response metadata.
import {Injectable} from "@tsed/di";
import {Tool} from "@tsed/platform-mcp";
import {Description, Property, Returns} from "@tsed/schema";
class HelloInput {
@Property()
name: string;
}
class HelloOutput {
@Property()
message: string;
}
@Injectable()
export class HelloTool {
@Tool("hello")
@Description("Greets callers from any MCP client")
@Returns(200, HelloOutput)
async handle(input: HelloInput) {
return {
content: [
{
type: "text",
text: `Hello, ${input.name}!`
}
],
structuredContent: {
message: `Hello, ${input.name}!`
}
};
}
}import {defineTool} from "@tsed/platform-mcp";
import {s} from "@tsed/schema";
export const helloTool = defineTool({
name: "hello",
title: "Hello",
description: "Greets callers from any MCP client",
inputSchema: s
.object({
name: s.string().required()
})
.required(),
outputSchema: s
.object({
message: s.string().required()
})
.required(),
async handler({name}) {
return {
content: [
{
type: "text",
text: `Hello, ${name}!`
}
],
structuredContent: {
message: `Hello, ${name}!`
}
};
}
});Register resources
Resources expose addressable content that clients can discover and read later by URI. Use them for static or dynamic documents, generated files, configuration snapshots, or any other content that should be fetched as a resource.
import {Injectable} from "@tsed/di";
import {Resource} from "@tsed/platform-mcp";
@Injectable()
export class McpResources {
@Resource("tsed://docs/index", {
name: "docs",
title: "Internal documentation",
description: "Returns the internal MCP documentation"
})
readDocs() {
return {
contents: [
{
uri: "tsed://docs/index",
mimeType: "text/markdown",
text: "Internal doc content"
}
]
};
}
}import {defineResource} from "@tsed/platform-mcp";
export const docsResource = defineResource({
name: "docs",
title: "Internal documentation",
description: "Returns the internal MCP documentation",
uri: "tsed://docs/index",
handler() {
return {
contents: [
{
uri: "tsed://docs/index",
mimeType: "text/markdown",
text: "Internal doc content"
}
]
};
}
});Register prompts
Prompts expose reusable prompt templates that MCP clients can request on demand. Use them to generate consistent conversation starters, assistant instructions, or parameterized user messages from your Ts.ED application.
import {Injectable} from "@tsed/di";
import {Prompt} from "@tsed/platform-mcp";
@Injectable()
export class McpPrompts {
@Prompt({
name: "ask-tsed",
title: "Ask Ts.ED",
description: "Creates a prompt message for Ts.ED questions"
})
askTsed({question}: {question: string}) {
return {
messages: [
{
role: "user",
content: {
type: "text",
text: question
}
}
]
};
}
}import {definePrompt} from "@tsed/platform-mcp";
import {s} from "@tsed/schema";
export const askTsedPrompt = definePrompt({
name: "ask-tsed",
title: "Ask Ts.ED",
description: "Creates a prompt message for Ts.ED questions",
argsSchema: s
.object({
question: s.string().required()
})
.required(),
handler({question}) {
return {
messages: [
{
role: "user",
content: {
type: "text",
text: question
}
}
]
};
}
});Customising the endpoint
Set mcp.path or mcp.enabled to control how the transport is exposed:
@Configuration({
mcp: {
path: "/ai/mcp",
enabled: process.env.MCP_DISABLED !== "true"
}
})All Ts.ED adapters (Express, Fastify, Koa) forward POST <path> requests to @modelcontextprotocol/sdk's StreamableHTTPServerTransport, so any MCP-capable client (Claude Desktop, etc.) can talk with your server regardless of the underlying framework.
Testing and inspector
With @tsed/platform-mcp, your MCP server is exposed through your Ts.ED HTTP application. The usual integration test strategy is to bootstrap the server with PlatformTest, then exercise POST /mcp with supertest to verify that tools, resources, and prompts are correctly registered and reachable through the transport.
const response = await request.post("/mcp").set({
Accept: "application/json,text/event-stream",
"Content-Type": "application/json"
});If you want to inspect the server manually, start your Ts.ED application and point the MCP Inspector to the HTTP endpoint exposed by @tsed/platform-mcp:
npx @modelcontextprotocol/inspectorThen configure the inspector to use the Streamable HTTP transport with your server URL, for example:
http://localhost:8083/mcpTIP
If you also need a standalone CLI distribution that speaks MCP over stdio or standalone HTTP, use @tsed/cli-mcp. The decorators and function helpers are designed to stay close across both packages, so moving handlers between CLI and platform integrations does not require rewriting the MCP logic.