Search by

konradmichalik / typo3-routing-mcp

konradmichalik

Expose annotated typo3-routing frontend routes as MCP tools via a Streamable HTTP endpoint.

Package info

github.com/konradmichalik/typo3-routing-mcp

Type:typo3-cms-extension

pkg:composer/konradmichalik/typo3-routing-mcp

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 1

Open Issues: 1

0.2.0 2026-11-05 15:03 UTC

README

Extension icon

TYPO3 extension typo3_routing_mcp

Latest Stable Version TYPO3 Supported PHP Versions CGL Coverage Tests License

This extension exposes typo3-routing frontend routes as MCP tools over a Streamable HTTP endpoint. Add the #[McpTool] PHP attribute to a routed controller method, and an AI agent can invoke your project's own domain endpoints directly, not just generic TYPO3 content operations.

Note

Generic TYPO3 MCP servers can only talk about content: pages, records, files. Your project's own domain endpoints, course search, store locator, whatever your sitepackage needs, are invisible to them. This extension closes that gap: it turns routes you've already declared via typo3-routing into MCP tools an agent can call directly.

✨ Features

  • One attribute, one tool: add #[McpTool] next to an existing #[Route], flush caches, done
  • Streamable HTTP: a single endpoint (/_mcp by default, configurable), bearer-token gated, usable on staging and production
  • Security by construction: session-scoped authenticators (FrontendUserAuthenticator/BackendUserAuthenticator) and request-token-protected routes are never exposed, no matter the attribute

🔥 Installation

Requirements

Composer

Packagist Packagist Downloads

composer require konradmichalik/typo3-routing-mcp

TER

TER version TER downloads

Download the zip file from TYPO3 extension repository (TER).

🚀 Quick start

Add #[McpTool] next to an existing #[Route]:

use KonradMichalik\Typo3Routing\Attribute\Route;
use KonradMichalik\Typo3RoutingMcp\Attribute\McpTool;

#[Route(path: '/api/courses/{id}', name: 'course_show', description: 'Fetch a single course by its numeric ID.')]
#[McpTool]
public function show(int $id): ResponseInterface { /* … */ }

#[McpTool] takes these optional arguments:

Argument Default Description
name route name Tool name shown to the client.
description route description Tool description shown to the client.
readOnly false Sets readOnlyHint. A read-only tool carries no destructiveHint or idempotentHint.
destructive derived Overrides destructiveHint, which is true for DELETE routes and false otherwise.
idempotent derived Overrides idempotentHint, which is true for GET, PUT and DELETE routes and false otherwise.

A route with a #[Returns] DTO gets an outputSchema built from it. Every successful call whose body is a JSON object returns it as structuredContent next to the text content. The schema is only set when every declared 2xx response is the same single DTO. Collections get none, because MCP revisions before 2026-07-28 only accept an object schema. Nullable DTO properties also accept null.

Important

The outputSchema is a contract: the MCP SDK validates every successful structuredContent against it and turns a mismatching response into a tool error. So the schema is only emitted when every public property of the DTO, including nested DTOs, has a precisely mappable type: int, float, bool, string, mixed, a backed enum, or another DTO that qualifies itself. The tool gets no outputSchema (but still returns structuredContent) when a property is untyped, a union or intersection type, array, iterable or object, an Extbase domain object, or a class without public properties such as DateTimeImmutable, or when the DTO or a nested one implements JsonSerializable.

Then audit what's exposed, via the TYPO3 console:

vendor/bin/typo3 routing:mcp:tools

Set a bearer token and point an MCP client at the endpoint. Any client that speaks Streamable HTTP works the same way, just configure the URL and the Authorization header:

export ROUTING_MCP_BEARER_TOKEN=<a-long-random-secret>
claude mcp add --transport http my-project \
  https://your-project.example.org/_mcp \
  --header "Authorization: Bearer <a-long-random-secret>"

Or, for clients configured via an mcp.json-style file (Cursor, VS Code Copilot, and others):

{
  "servers": {
    "my-project": {
      "type": "http",
      "url": "https://your-project.example.org/_mcp",
      "headers": {
        "Authorization": "Bearer <a-long-random-secret>"
      }
    }
  }
}

Note

Without ROUTING_MCP_BEARER_TOKEN (or the env var name configured via the extension's bearerTokenEnvName setting) set, the endpoint is entirely inactive, not merely unauthenticated.

The initialize response also carries an instructions field describing how to use the exposed tools (read-only vs. mutating, RFC 9457 error content). Most MCP clients surface this to the connecting agent automatically.

Configuration

Set these via the extension's TYPO3 Extension Configuration (Admin Tools > Settings > Extension Configuration > typo3_routing_mcp):

Setting Default Description
bearerTokenEnvName ROUTING_MCP_BEARER_TOKEN Name of the process environment variable holding the expected bearer token.
endpointPath /_mcp Request path the middleware listens on. Change this if /_mcp collides with something else in your project.

🧑‍💻 Contributing

Please have a look at CONTRIBUTING.md.

⭐ License

This project is licensed under GNU General Public License 2.0 (or later).