feat : MCP server infrastructure setup
Install symfony/mcp-bundle, add STDIO + HTTP transport config, API token auth on User entity with custom authenticator and firewall, generate-api-token console command, Nginx /_mcp location, fixture token. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -14,7 +14,7 @@
|
||||
"doctrine/orm": "^3.6",
|
||||
"lexik/jwt-authentication-bundle": "^3.2",
|
||||
"nelmio/cors-bundle": "^2.6",
|
||||
"phpdocumentor/reflection-docblock": "^6.0",
|
||||
"phpdocumentor/reflection-docblock": "^5.6|^6.0",
|
||||
"phpstan/phpdoc-parser": "^2.3",
|
||||
"symfony/asset": "8.0.*",
|
||||
"symfony/console": "8.0.*",
|
||||
@@ -23,6 +23,7 @@
|
||||
"symfony/flex": "^2",
|
||||
"symfony/framework-bundle": "8.0.*",
|
||||
"symfony/http-client": "8.0.*",
|
||||
"symfony/mcp-bundle": "^0.6.0",
|
||||
"symfony/property-access": "8.0.*",
|
||||
"symfony/property-info": "8.0.*",
|
||||
"symfony/runtime": "8.0.*",
|
||||
|
||||
786
composer.lock
generated
786
composer.lock
generated
@@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "4790d8c80c0fb208e5af11fb205c0202",
|
||||
"content-hash": "75456bd21a6cc5bf33989f885a1ab515",
|
||||
"packages": [
|
||||
{
|
||||
"name": "api-platform/doctrine-common",
|
||||
@@ -2549,6 +2549,82 @@
|
||||
],
|
||||
"time": "2025-12-20T17:47:00+00:00"
|
||||
},
|
||||
{
|
||||
"name": "mcp/sdk",
|
||||
"version": "v0.4.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/modelcontextprotocol/php-sdk.git",
|
||||
"reference": "1f5f7e16a3af23dd43ec0a5c972d7aa8e8429024"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/modelcontextprotocol/php-sdk/zipball/1f5f7e16a3af23dd43ec0a5c972d7aa8e8429024",
|
||||
"reference": "1f5f7e16a3af23dd43ec0a5c972d7aa8e8429024",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-fileinfo": "*",
|
||||
"opis/json-schema": "^2.4",
|
||||
"php": "^8.1",
|
||||
"php-http/discovery": "^1.20",
|
||||
"phpdocumentor/reflection-docblock": "^5.6",
|
||||
"psr/clock": "^1.0",
|
||||
"psr/container": "^1.0 || ^2.0",
|
||||
"psr/event-dispatcher": "^1.0",
|
||||
"psr/http-factory": "^1.1",
|
||||
"psr/http-message": "^1.1 || ^2.0",
|
||||
"psr/http-server-handler": "^1.0",
|
||||
"psr/http-server-middleware": "^1.0",
|
||||
"psr/log": "^1.0 || ^2.0 || ^3.0",
|
||||
"symfony/finder": "^5.4 || ^6.4 || ^7.3 || ^8.0",
|
||||
"symfony/uid": "^5.4 || ^6.4 || ^7.3 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"laminas/laminas-httphandlerrunner": "^2.12",
|
||||
"nyholm/psr7": "^1.8",
|
||||
"nyholm/psr7-server": "^1.1",
|
||||
"phar-io/composer-distributor": "^1.0.2",
|
||||
"php-cs-fixer/shim": "^3.91",
|
||||
"phpdocumentor/shim": "^3",
|
||||
"phpstan/phpstan": "^2.1",
|
||||
"phpunit/phpunit": "^10.5",
|
||||
"psr/simple-cache": "^2.0 || ^3.0",
|
||||
"symfony/cache": "^5.4 || ^6.4 || ^7.3 || ^8.0",
|
||||
"symfony/console": "^5.4 || ^6.4 || ^7.3 || ^8.0",
|
||||
"symfony/process": "^5.4 || ^6.4 || ^7.3 || ^8.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Mcp\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"Apache-2.0"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Christopher Hertel",
|
||||
"email": "mail@christopher-hertel.de"
|
||||
},
|
||||
{
|
||||
"name": "Kyrian Obikwelu",
|
||||
"email": "koshnawaza@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Tobias Nyholm",
|
||||
"email": "tobias.nyholm@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Model Context Protocol SDK for Client and Server applications in PHP",
|
||||
"support": {
|
||||
"issues": "https://github.com/modelcontextprotocol/php-sdk/issues",
|
||||
"source": "https://github.com/modelcontextprotocol/php-sdk/tree/v0.4.0"
|
||||
},
|
||||
"time": "2026-02-23T21:42:54+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nelmio/cors-bundle",
|
||||
"version": "2.6.1",
|
||||
@@ -2614,6 +2690,275 @@
|
||||
},
|
||||
"time": "2026-01-12T15:59:08+00:00"
|
||||
},
|
||||
{
|
||||
"name": "opis/json-schema",
|
||||
"version": "2.6.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/opis/json-schema.git",
|
||||
"reference": "8458763e0dd0b6baa310e04f1829fc73da4e8c8a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/opis/json-schema/zipball/8458763e0dd0b6baa310e04f1829fc73da4e8c8a",
|
||||
"reference": "8458763e0dd0b6baa310e04f1829fc73da4e8c8a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-json": "*",
|
||||
"opis/string": "^2.1",
|
||||
"opis/uri": "^1.0",
|
||||
"php": "^7.4 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"ext-bcmath": "*",
|
||||
"ext-intl": "*",
|
||||
"phpunit/phpunit": "^9.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Opis\\JsonSchema\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"Apache-2.0"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Sorin Sarca",
|
||||
"email": "sarca_sorin@hotmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Marius Sarca",
|
||||
"email": "marius.sarca@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Json Schema Validator for PHP",
|
||||
"homepage": "https://opis.io/json-schema",
|
||||
"keywords": [
|
||||
"json",
|
||||
"json-schema",
|
||||
"schema",
|
||||
"validation",
|
||||
"validator"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/opis/json-schema/issues",
|
||||
"source": "https://github.com/opis/json-schema/tree/2.6.0"
|
||||
},
|
||||
"time": "2025-10-17T12:46:48+00:00"
|
||||
},
|
||||
{
|
||||
"name": "opis/string",
|
||||
"version": "2.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/opis/string.git",
|
||||
"reference": "3e4d2aaff518ac518530b89bb26ed40f4503635e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/opis/string/zipball/3e4d2aaff518ac518530b89bb26ed40f4503635e",
|
||||
"reference": "3e4d2aaff518ac518530b89bb26ed40f4503635e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-iconv": "*",
|
||||
"ext-json": "*",
|
||||
"php": "^7.4 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^9.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Opis\\String\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"Apache-2.0"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Marius Sarca",
|
||||
"email": "marius.sarca@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Sorin Sarca",
|
||||
"email": "sarca_sorin@hotmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Multibyte strings as objects",
|
||||
"homepage": "https://opis.io/string",
|
||||
"keywords": [
|
||||
"multi-byte",
|
||||
"opis",
|
||||
"string",
|
||||
"string manipulation",
|
||||
"utf-8"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/opis/string/issues",
|
||||
"source": "https://github.com/opis/string/tree/2.1.0"
|
||||
},
|
||||
"time": "2025-10-17T12:38:41+00:00"
|
||||
},
|
||||
{
|
||||
"name": "opis/uri",
|
||||
"version": "1.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/opis/uri.git",
|
||||
"reference": "0f3ca49ab1a5e4a6681c286e0b2cc081b93a7d5a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/opis/uri/zipball/0f3ca49ab1a5e4a6681c286e0b2cc081b93a7d5a",
|
||||
"reference": "0f3ca49ab1a5e4a6681c286e0b2cc081b93a7d5a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"opis/string": "^2.0",
|
||||
"php": "^7.4 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^9"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Opis\\Uri\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"Apache-2.0"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Marius Sarca",
|
||||
"email": "marius.sarca@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Sorin Sarca",
|
||||
"email": "sarca_sorin@hotmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Build, parse and validate URIs and URI-templates",
|
||||
"homepage": "https://opis.io",
|
||||
"keywords": [
|
||||
"URI Template",
|
||||
"parse url",
|
||||
"punycode",
|
||||
"uri",
|
||||
"uri components",
|
||||
"url",
|
||||
"validate uri"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/opis/uri/issues",
|
||||
"source": "https://github.com/opis/uri/tree/1.1.0"
|
||||
},
|
||||
"time": "2021-05-22T15:57:08+00:00"
|
||||
},
|
||||
{
|
||||
"name": "php-http/discovery",
|
||||
"version": "1.20.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-http/discovery.git",
|
||||
"reference": "82fe4c73ef3363caed49ff8dd1539ba06044910d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-http/discovery/zipball/82fe4c73ef3363caed49ff8dd1539ba06044910d",
|
||||
"reference": "82fe4c73ef3363caed49ff8dd1539ba06044910d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"composer-plugin-api": "^1.0|^2.0",
|
||||
"php": "^7.1 || ^8.0"
|
||||
},
|
||||
"conflict": {
|
||||
"nyholm/psr7": "<1.0",
|
||||
"zendframework/zend-diactoros": "*"
|
||||
},
|
||||
"provide": {
|
||||
"php-http/async-client-implementation": "*",
|
||||
"php-http/client-implementation": "*",
|
||||
"psr/http-client-implementation": "*",
|
||||
"psr/http-factory-implementation": "*",
|
||||
"psr/http-message-implementation": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"composer/composer": "^1.0.2|^2.0",
|
||||
"graham-campbell/phpspec-skip-example-extension": "^5.0",
|
||||
"php-http/httplug": "^1.0 || ^2.0",
|
||||
"php-http/message-factory": "^1.0",
|
||||
"phpspec/phpspec": "^5.1 || ^6.1 || ^7.3",
|
||||
"sebastian/comparator": "^3.0.5 || ^4.0.8",
|
||||
"symfony/phpunit-bridge": "^6.4.4 || ^7.0.1"
|
||||
},
|
||||
"type": "composer-plugin",
|
||||
"extra": {
|
||||
"class": "Http\\Discovery\\Composer\\Plugin",
|
||||
"plugin-optional": true
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Http\\Discovery\\": "src/"
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"src/Composer/Plugin.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Márk Sági-Kazár",
|
||||
"email": "mark.sagikazar@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Finds and installs PSR-7, PSR-17, PSR-18 and HTTPlug implementations",
|
||||
"homepage": "http://php-http.org",
|
||||
"keywords": [
|
||||
"adapter",
|
||||
"client",
|
||||
"discovery",
|
||||
"factory",
|
||||
"http",
|
||||
"message",
|
||||
"psr17",
|
||||
"psr7"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/php-http/discovery/issues",
|
||||
"source": "https://github.com/php-http/discovery/tree/1.20.0"
|
||||
},
|
||||
"time": "2024-10-02T11:20:13+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpdocumentor/reflection-common",
|
||||
"version": "2.2.0",
|
||||
@@ -2669,16 +3014,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpdocumentor/reflection-docblock",
|
||||
"version": "6.0.2",
|
||||
"version": "5.6.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
|
||||
"reference": "897b5986ece6b4f9d8413fea345c7d49c757d6bf"
|
||||
"reference": "5cee1d3dfc2d2aa6599834520911d246f656bcb8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/897b5986ece6b4f9d8413fea345c7d49c757d6bf",
|
||||
"reference": "897b5986ece6b4f9d8413fea345c7d49c757d6bf",
|
||||
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/5cee1d3dfc2d2aa6599834520911d246f656bcb8",
|
||||
"reference": "5cee1d3dfc2d2aa6599834520911d246f656bcb8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2686,8 +3031,8 @@
|
||||
"ext-filter": "*",
|
||||
"php": "^7.4 || ^8.0",
|
||||
"phpdocumentor/reflection-common": "^2.2",
|
||||
"phpdocumentor/type-resolver": "^2.0",
|
||||
"phpstan/phpdoc-parser": "^2.0",
|
||||
"phpdocumentor/type-resolver": "^1.7",
|
||||
"phpstan/phpdoc-parser": "^1.7|^2.0",
|
||||
"webmozart/assert": "^1.9.1 || ^2"
|
||||
},
|
||||
"require-dev": {
|
||||
@@ -2697,8 +3042,7 @@
|
||||
"phpstan/phpstan-mockery": "^1.1",
|
||||
"phpstan/phpstan-webmozart-assert": "^1.2",
|
||||
"phpunit/phpunit": "^9.5",
|
||||
"psalm/phar": "^5.26",
|
||||
"shipmonk/dead-code-detector": "^0.5.1"
|
||||
"psalm/phar": "^5.26"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
@@ -2728,44 +3072,44 @@
|
||||
"description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
|
||||
"support": {
|
||||
"issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues",
|
||||
"source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/6.0.2"
|
||||
"source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.6.6"
|
||||
},
|
||||
"time": "2026-03-01T18:43:49+00:00"
|
||||
"time": "2025-12-22T21:13:58+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpdocumentor/type-resolver",
|
||||
"version": "2.0.0",
|
||||
"version": "1.12.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpDocumentor/TypeResolver.git",
|
||||
"reference": "327a05bbee54120d4786a0dc67aad30226ad4cf9"
|
||||
"reference": "92a98ada2b93d9b201a613cb5a33584dde25f195"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/327a05bbee54120d4786a0dc67aad30226ad4cf9",
|
||||
"reference": "327a05bbee54120d4786a0dc67aad30226ad4cf9",
|
||||
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/92a98ada2b93d9b201a613cb5a33584dde25f195",
|
||||
"reference": "92a98ada2b93d9b201a613cb5a33584dde25f195",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"doctrine/deprecations": "^1.0",
|
||||
"php": "^7.4 || ^8.0",
|
||||
"php": "^7.3 || ^8.0",
|
||||
"phpdocumentor/reflection-common": "^2.0",
|
||||
"phpstan/phpdoc-parser": "^2.0"
|
||||
"phpstan/phpdoc-parser": "^1.18|^2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"ext-tokenizer": "*",
|
||||
"phpbench/phpbench": "^1.2",
|
||||
"phpstan/extension-installer": "^1.4",
|
||||
"phpstan/phpstan": "^2.1",
|
||||
"phpstan/phpstan-phpunit": "^2.0",
|
||||
"phpstan/extension-installer": "^1.1",
|
||||
"phpstan/phpstan": "^1.8",
|
||||
"phpstan/phpstan-phpunit": "^1.1",
|
||||
"phpunit/phpunit": "^9.5",
|
||||
"psalm/phar": "^4"
|
||||
"rector/rector": "^0.13.9",
|
||||
"vimeo/psalm": "^4.25"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-1.x": "1.x-dev",
|
||||
"dev-2.x": "2.x-dev"
|
||||
"dev-1.x": "1.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -2786,9 +3130,9 @@
|
||||
"description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
|
||||
"support": {
|
||||
"issues": "https://github.com/phpDocumentor/TypeResolver/issues",
|
||||
"source": "https://github.com/phpDocumentor/TypeResolver/tree/2.0.0"
|
||||
"source": "https://github.com/phpDocumentor/TypeResolver/tree/1.12.0"
|
||||
},
|
||||
"time": "2026-01-06T21:53:42+00:00"
|
||||
"time": "2025-11-21T15:09:14+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpdoc-parser",
|
||||
@@ -3037,6 +3381,227 @@
|
||||
},
|
||||
"time": "2019-01-08T18:20:26+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/http-factory",
|
||||
"version": "1.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-fig/http-factory.git",
|
||||
"reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a",
|
||||
"reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.1",
|
||||
"psr/http-message": "^1.0 || ^2.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Psr\\Http\\Message\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "PHP-FIG",
|
||||
"homepage": "https://www.php-fig.org/"
|
||||
}
|
||||
],
|
||||
"description": "PSR-17: Common interfaces for PSR-7 HTTP message factories",
|
||||
"keywords": [
|
||||
"factory",
|
||||
"http",
|
||||
"message",
|
||||
"psr",
|
||||
"psr-17",
|
||||
"psr-7",
|
||||
"request",
|
||||
"response"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/php-fig/http-factory"
|
||||
},
|
||||
"time": "2024-04-15T12:06:14+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/http-message",
|
||||
"version": "2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-fig/http-message.git",
|
||||
"reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71",
|
||||
"reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.2 || ^8.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Psr\\Http\\Message\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "PHP-FIG",
|
||||
"homepage": "https://www.php-fig.org/"
|
||||
}
|
||||
],
|
||||
"description": "Common interface for HTTP messages",
|
||||
"homepage": "https://github.com/php-fig/http-message",
|
||||
"keywords": [
|
||||
"http",
|
||||
"http-message",
|
||||
"psr",
|
||||
"psr-7",
|
||||
"request",
|
||||
"response"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/php-fig/http-message/tree/2.0"
|
||||
},
|
||||
"time": "2023-04-04T09:54:51+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/http-server-handler",
|
||||
"version": "1.0.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-fig/http-server-handler.git",
|
||||
"reference": "84c4fb66179be4caaf8e97bd239203245302e7d4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-fig/http-server-handler/zipball/84c4fb66179be4caaf8e97bd239203245302e7d4",
|
||||
"reference": "84c4fb66179be4caaf8e97bd239203245302e7d4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.0",
|
||||
"psr/http-message": "^1.0 || ^2.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Psr\\Http\\Server\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "PHP-FIG",
|
||||
"homepage": "https://www.php-fig.org/"
|
||||
}
|
||||
],
|
||||
"description": "Common interface for HTTP server-side request handler",
|
||||
"keywords": [
|
||||
"handler",
|
||||
"http",
|
||||
"http-interop",
|
||||
"psr",
|
||||
"psr-15",
|
||||
"psr-7",
|
||||
"request",
|
||||
"response",
|
||||
"server"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/php-fig/http-server-handler/tree/1.0.2"
|
||||
},
|
||||
"time": "2023-04-10T20:06:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/http-server-middleware",
|
||||
"version": "1.0.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-fig/http-server-middleware.git",
|
||||
"reference": "c1481f747daaa6a0782775cd6a8c26a1bf4a3829"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-fig/http-server-middleware/zipball/c1481f747daaa6a0782775cd6a8c26a1bf4a3829",
|
||||
"reference": "c1481f747daaa6a0782775cd6a8c26a1bf4a3829",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.0",
|
||||
"psr/http-message": "^1.0 || ^2.0",
|
||||
"psr/http-server-handler": "^1.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Psr\\Http\\Server\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "PHP-FIG",
|
||||
"homepage": "https://www.php-fig.org/"
|
||||
}
|
||||
],
|
||||
"description": "Common interface for HTTP server-side middleware",
|
||||
"keywords": [
|
||||
"http",
|
||||
"http-interop",
|
||||
"middleware",
|
||||
"psr",
|
||||
"psr-15",
|
||||
"psr-7",
|
||||
"request",
|
||||
"response"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/php-fig/http-server-middleware/issues",
|
||||
"source": "https://github.com/php-fig/http-server-middleware/tree/1.0.2"
|
||||
},
|
||||
"time": "2023-04-11T06:14:47+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/link",
|
||||
"version": "2.0.1",
|
||||
@@ -4976,6 +5541,90 @@
|
||||
],
|
||||
"time": "2026-03-06T16:58:46+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/mcp-bundle",
|
||||
"version": "v0.6.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/mcp-bundle.git",
|
||||
"reference": "739ad154256402f5a0c4dbbc4c5b0f8797e6f8fc"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/mcp-bundle/zipball/739ad154256402f5a0c4dbbc4c5b0f8797e6f8fc",
|
||||
"reference": "739ad154256402f5a0c4dbbc4c5b0f8797e6f8fc",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"mcp/sdk": "^0.4",
|
||||
"php-http/discovery": "^1.20",
|
||||
"symfony/config": "^7.3|^8.0",
|
||||
"symfony/console": "^7.3|^8.0",
|
||||
"symfony/dependency-injection": "^7.3|^8.0",
|
||||
"symfony/framework-bundle": "^7.3|^8.0",
|
||||
"symfony/http-foundation": "^7.3|^8.0",
|
||||
"symfony/http-kernel": "^7.3|^8.0",
|
||||
"symfony/psr-http-message-bridge": "^7.3|^8.0",
|
||||
"symfony/routing": "^7.3|^8.0",
|
||||
"symfony/service-contracts": "^2.5|^3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "^2.1",
|
||||
"phpstan/phpstan-phpunit": "^2.0",
|
||||
"phpstan/phpstan-strict-rules": "^2.0",
|
||||
"phpunit/phpunit": "^11.5.53",
|
||||
"symfony/monolog-bundle": "^3.10 || ^4.0"
|
||||
},
|
||||
"type": "symfony-bundle",
|
||||
"extra": {
|
||||
"thanks": {
|
||||
"url": "https://github.com/symfony/ai",
|
||||
"name": "symfony/ai"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\AI\\McpBundle\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Christopher Hertel",
|
||||
"email": "mail@christopher-hertel.de"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony integration bundle for Model Context Protocol (via official mcp/sdk)",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/mcp-bundle/tree/v0.6.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/nicolas-grekas",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2026-03-04T16:39:24+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/password-hasher",
|
||||
"version": "v8.0.6",
|
||||
@@ -5631,6 +6280,93 @@
|
||||
],
|
||||
"time": "2026-03-04T15:54:04+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/psr-http-message-bridge",
|
||||
"version": "v8.0.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/psr-http-message-bridge.git",
|
||||
"reference": "d6edf266746dd0b8e81e754a79da77b08dc00531"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/psr-http-message-bridge/zipball/d6edf266746dd0b8e81e754a79da77b08dc00531",
|
||||
"reference": "d6edf266746dd0b8e81e754a79da77b08dc00531",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.4",
|
||||
"psr/http-message": "^1.0|^2.0",
|
||||
"symfony/http-foundation": "^7.4|^8.0"
|
||||
},
|
||||
"conflict": {
|
||||
"php-http/discovery": "<1.15"
|
||||
},
|
||||
"require-dev": {
|
||||
"nyholm/psr7": "^1.1",
|
||||
"php-http/discovery": "^1.15",
|
||||
"psr/log": "^1.1.4|^2|^3",
|
||||
"symfony/browser-kit": "^7.4|^8.0",
|
||||
"symfony/config": "^7.4|^8.0",
|
||||
"symfony/event-dispatcher": "^7.4|^8.0",
|
||||
"symfony/framework-bundle": "^7.4|^8.0",
|
||||
"symfony/http-kernel": "^7.4|^8.0",
|
||||
"symfony/runtime": "^7.4|^8.0"
|
||||
},
|
||||
"type": "symfony-bridge",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Bridge\\PsrHttpMessage\\": ""
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "PSR HTTP message bridge",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"http",
|
||||
"http-message",
|
||||
"psr-17",
|
||||
"psr-7"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/psr-http-message-bridge/tree/v8.0.4"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/nicolas-grekas",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2026-01-03T23:40:55+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/routing",
|
||||
"version": "v8.0.6",
|
||||
|
||||
23
config/packages/mcp.yaml
Normal file
23
config/packages/mcp.yaml
Normal file
@@ -0,0 +1,23 @@
|
||||
mcp:
|
||||
app: 'lesstime'
|
||||
version: '1.0.0'
|
||||
description: 'Lesstime project management — projects, tasks, time tracking'
|
||||
instructions: |
|
||||
This server provides access to the Lesstime project management system.
|
||||
You can list/create/update/delete projects, tasks, and time entries.
|
||||
Tasks belong to projects and have statuses, priorities, efforts, tags, and groups.
|
||||
Statuses, priorities, efforts, and tags are GLOBAL (shared across all projects).
|
||||
Groups are PER-PROJECT (each group belongs to one project).
|
||||
Time entries track work duration and can be linked to projects and tasks.
|
||||
Use list-statuses, list-priorities, list-efforts, list-tags, list-groups to discover
|
||||
available metadata before creating or updating tasks.
|
||||
Use list-users and list-clients to discover valid user and client IDs.
|
||||
client_transports:
|
||||
stdio: true
|
||||
http: true
|
||||
http:
|
||||
path: /_mcp
|
||||
session:
|
||||
store: file
|
||||
directory: '%kernel.cache_dir%/mcp-sessions'
|
||||
ttl: 3600
|
||||
@@ -28,6 +28,12 @@ security:
|
||||
password_path: password
|
||||
success_handler: lexik_jwt_authentication.handler.authentication_success
|
||||
failure_handler: lexik_jwt_authentication.handler.authentication_failure
|
||||
mcp:
|
||||
pattern: ^/_mcp
|
||||
stateless: true
|
||||
provider: app_user_provider
|
||||
custom_authenticators:
|
||||
- App\Security\ApiTokenAuthenticator
|
||||
api:
|
||||
pattern: ^/api
|
||||
stateless: true
|
||||
@@ -53,6 +59,7 @@ security:
|
||||
- { path: ^/api/docs, roles: PUBLIC_ACCESS }
|
||||
# Version de l'application en public
|
||||
- { path: ^/api/version, roles: PUBLIC_ACCESS, methods: [ GET ] }
|
||||
- { path: ^/_mcp, roles: IS_AUTHENTICATED_FULLY }
|
||||
- { path: ^/api, roles: IS_AUTHENTICATED_FULLY }
|
||||
|
||||
when@test:
|
||||
|
||||
3
config/routes/mcp.yaml
Normal file
3
config/routes/mcp.yaml
Normal file
@@ -0,0 +1,3 @@
|
||||
mcp:
|
||||
resource: .
|
||||
type: mcp
|
||||
@@ -7,6 +7,11 @@ server {
|
||||
|
||||
client_max_body_size 55m;
|
||||
|
||||
location ^~ /_mcp {
|
||||
root /var/www/html/public;
|
||||
try_files $uri /index.php?$query_string;
|
||||
}
|
||||
|
||||
location ^~ /api/ {
|
||||
root /var/www/html/public;
|
||||
try_files $uri /index.php?$query_string;
|
||||
|
||||
33
migrations/Version20260315183313.php
Normal file
33
migrations/Version20260315183313.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20260315183313 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
// this up() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('ALTER TABLE "user" ADD api_token VARCHAR(64) DEFAULT NULL');
|
||||
$this->addSql('CREATE UNIQUE INDEX UNIQ_8D93D6497BA2F5EB ON "user" (api_token)');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('DROP INDEX UNIQ_8D93D6497BA2F5EB');
|
||||
$this->addSql('ALTER TABLE "user" DROP api_token');
|
||||
}
|
||||
}
|
||||
58
src/Command/GenerateApiTokenCommand.php
Normal file
58
src/Command/GenerateApiTokenCommand.php
Normal file
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Command;
|
||||
|
||||
use App\Repository\UserRepository;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
use function sprintf;
|
||||
|
||||
#[AsCommand(
|
||||
name: 'app:generate-api-token',
|
||||
description: 'Generate or regenerate an API token for a user (used for MCP HTTP authentication)',
|
||||
)]
|
||||
class GenerateApiTokenCommand extends Command
|
||||
{
|
||||
public function __construct(
|
||||
private readonly UserRepository $userRepository,
|
||||
private readonly EntityManagerInterface $entityManager,
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this->addArgument('username', InputArgument::REQUIRED, 'The username to generate a token for');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$username = $input->getArgument('username');
|
||||
|
||||
$user = $this->userRepository->findOneBy(['username' => $username]);
|
||||
|
||||
if (null === $user) {
|
||||
$io->error(sprintf('User "%s" not found.', $username));
|
||||
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
$token = bin2hex(random_bytes(32));
|
||||
$user->setApiToken($token);
|
||||
$this->entityManager->flush();
|
||||
|
||||
$io->success(sprintf('API token generated for user "%s":', $username));
|
||||
$io->writeln($token);
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,7 @@ class AppFixtures extends Fixture
|
||||
$admin->setUsername('admin');
|
||||
$admin->setRoles(['ROLE_ADMIN']);
|
||||
$admin->setPassword($this->passwordHasher->hashPassword($admin, 'admin'));
|
||||
$admin->setApiToken('dev-mcp-token-for-testing-only-do-not-use-in-production');
|
||||
$manager->persist($admin);
|
||||
|
||||
// Clients
|
||||
|
||||
@@ -67,6 +67,9 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
|
||||
#[ORM\Column(type: Types::DATETIME_IMMUTABLE)]
|
||||
private ?DateTimeImmutable $createdAt = null;
|
||||
|
||||
#[ORM\Column(length: 64, unique: true, nullable: true)]
|
||||
private ?string $apiToken = null;
|
||||
|
||||
#[ORM\ManyToOne(targetEntity: Client::class)]
|
||||
#[ORM\JoinColumn(nullable: true, onDelete: 'SET NULL')]
|
||||
#[Groups(['me:read', 'user:list', 'user:write'])]
|
||||
@@ -184,5 +187,17 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getApiToken(): ?string
|
||||
{
|
||||
return $this->apiToken;
|
||||
}
|
||||
|
||||
public function setApiToken(?string $apiToken): static
|
||||
{
|
||||
$this->apiToken = $apiToken;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function eraseCredentials(): void {}
|
||||
}
|
||||
|
||||
66
src/Security/ApiTokenAuthenticator.php
Normal file
66
src/Security/ApiTokenAuthenticator.php
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Security;
|
||||
|
||||
use App\Entity\User;
|
||||
use App\Repository\UserRepository;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||
use Symfony\Component\Security\Core\Exception\AuthenticationException;
|
||||
use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException;
|
||||
use Symfony\Component\Security\Http\Authenticator\AbstractAuthenticator;
|
||||
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
|
||||
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
|
||||
use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;
|
||||
|
||||
class ApiTokenAuthenticator extends AbstractAuthenticator
|
||||
{
|
||||
public function __construct(
|
||||
private readonly UserRepository $userRepository,
|
||||
) {}
|
||||
|
||||
public function supports(Request $request): ?bool
|
||||
{
|
||||
return $request->headers->has('Authorization')
|
||||
&& str_starts_with((string) $request->headers->get('Authorization'), 'Bearer ');
|
||||
}
|
||||
|
||||
public function authenticate(Request $request): Passport
|
||||
{
|
||||
$authHeader = (string) $request->headers->get('Authorization');
|
||||
$token = substr($authHeader, 7);
|
||||
|
||||
if ('' === $token) {
|
||||
throw new CustomUserMessageAuthenticationException('API token missing.');
|
||||
}
|
||||
|
||||
return new SelfValidatingPassport(
|
||||
new UserBadge($token, function (string $token): ?User {
|
||||
$user = $this->userRepository->findOneBy(['apiToken' => $token]);
|
||||
|
||||
if (null === $user) {
|
||||
throw new CustomUserMessageAuthenticationException('Invalid API token.');
|
||||
}
|
||||
|
||||
return $user;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response
|
||||
{
|
||||
return new JsonResponse(
|
||||
['error' => $exception->getMessageKey()],
|
||||
Response::HTTP_UNAUTHORIZED
|
||||
);
|
||||
}
|
||||
}
|
||||
15
symfony.lock
15
symfony.lock
@@ -97,6 +97,18 @@
|
||||
"config/packages/nelmio_cors.yaml"
|
||||
]
|
||||
},
|
||||
"php-http/discovery": {
|
||||
"version": "1.20",
|
||||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes",
|
||||
"branch": "main",
|
||||
"version": "1.18",
|
||||
"ref": "f45b5dd173a27873ab19f5e3180b2f661c21de02"
|
||||
},
|
||||
"files": [
|
||||
"config/packages/http_discovery.yaml"
|
||||
]
|
||||
},
|
||||
"phpunit/phpunit": {
|
||||
"version": "13.0",
|
||||
"recipe": {
|
||||
@@ -157,6 +169,9 @@
|
||||
".editorconfig"
|
||||
]
|
||||
},
|
||||
"symfony/mcp-bundle": {
|
||||
"version": "v0.6.0"
|
||||
},
|
||||
"symfony/property-info": {
|
||||
"version": "8.0",
|
||||
"recipe": {
|
||||
|
||||
Reference in New Issue
Block a user