adachsoft / ai-tool-mcp-bundle
Symfony bundle exposing selected adachsoft/ai-tool-call tools as an MCP (Model Context Protocol) server over HTTP and stdio.
Package info
gitlab.com/a.adach/ai-tool-mcp-bundle
Type:symfony-bundle
pkg:composer/adachsoft/ai-tool-mcp-bundle
Requires
- php: ^8.3
- adachsoft/ai-tool-call: ^2.0
- psr/container: ^2.0
- psr/log: ^3.0
- symfony/config: ^7.3 || ^8.0
- symfony/console: ^7.3 || ^8.0
- symfony/dependency-injection: ^7.3 || ^8.0
- symfony/http-foundation: ^7.3 || ^8.0
- symfony/http-kernel: ^7.3 || ^8.0
- symfony/routing: ^7.3 || ^8.0
Requires (Dev)
- adachsoft/php-code-style: ^0.7.2
- friendsofphp/php-cs-fixer: ^3.95
- phpstan/phpstan: ^2.3
- phpunit/phpunit: ^13.4
- rector/rector: ^2.8
- symfony/browser-kit: ^7.3 || ^8.0
- symfony/framework-bundle: ^7.3 || ^8.0
- symfony/process: ^7.3 || ^8.0
- symfony/yaml: ^7.3 || ^8.0
- symplify/phpstan-rules: ^14.19
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
adachsoft/ai-tool-mcp-bundle is a Symfony bundle that turns any Symfony application into an
MCP (Model Context Protocol) server exposing selected
adachsoft/ai-tool-call tools.
Any ToolInterface implementation with a ToolFactoryInterface can be exposed by adding a few lines of
configuration. Tools are created by factories from the host container, so they can use the host's
repositories and services directly.
Features
- MCP methods:
initialize(with protocol version negotiation),ping,tools/list,tools/call. - Protocol versions:
2025-06-18,2025-03-26,2024-11-05. - Two transports sharing one core:
- Streamable HTTP: a single
POSTendpoint returning JSON responses. - stdio: a console command for local clients (Claude Code, Claude Desktop, IDEs).
- Streamable HTTP: a single
- Explicit allow-list: only configured tools are listed or callable.
- Tool failures (
InvalidToolCallException,ToolExecutionException) are returned as results withisError: true, so the model can read the message and correct its call. Unexpected exceptions are logged and reported without internal details. - Lazy tool creation: a factory is invoked on the first call of its tool, never during
tools/list. - No authentication logic of its own. The HTTP endpoint is protected by the host application's firewall.
Requirements
- PHP 8.3+
- Symfony 7.3+ or 8.x
adachsoft/ai-tool-call^2.0
Installation
composer require adachsoft/ai-tool-mcp-bundle
Register the bundle (Symfony Flex does it automatically):
// config/bundles.php
return [
// ...
AdachSoft\AiToolMcpBundle\AiToolMcpBundle::class => ['all' => true],
];
Configuration
# config/packages/ai_tool_mcp.yaml
ai_tool_mcp:
server:
name: task-api # reported in initialize/serverInfo
version: 1.0.0
instructions: 'Manage tasks: create, read, tree, statuses and comments.' # optional
http:
allowed_origins: [] # browser origins allowed to call the endpoint
tools:
# Key = exact tool name returned by ToolInterface::getDefinition()
task:
factory: AdachSoft\TaskTool\Tool\TaskToolFactory # service id of a ToolFactoryInterface
config: # passed to the factory as ConfigMap
max_title_length: 120
base_path: '%kernel.project_dir%' # container parameters and env vars are resolved
| Key | Description |
|---|---|
server.name, server.version | Server identity returned by initialize. |
server.instructions | Optional usage instructions for the model. |
http.allowed_origins | Requests with an Origin header not on this list get 403 (DNS rebinding protection). Requests without Origin (non-browser clients) are always accepted. |
tools.<name>.factory | Service id of an AdachSoft\AiToolCall\SPI\Factory\ToolFactoryInterface. The service must exist in the host container. |
tools.<name>.config | Map passed to ToolFactoryInterface::create() as ConfigMap. Keys must follow ConfigMap rules (lowercase, digits, _, optional . segments). |
The configuration key must equal the tool name from getDefinition(); a mismatch raises
McpToolConfigurationException. Tools whose definition has enabled: false are neither listed nor callable.
Registering the tool factory
The factory is resolved from the host container, so register it as a service if autowiring does not already cover it:
# config/services.yaml
services:
AdachSoft\TaskTool\Tool\TaskToolFactory:
arguments:
$clock: null
HTTP transport
Import the bundle routes. The endpoint path is /mcp; use a prefix to move it, e.g. under a firewall:
# config/routes/ai_tool_mcp.yaml
ai_tool_mcp:
resource: '@AiToolMcpBundle/config/routes.php'
prefix: /api # endpoint: POST /api/mcp
Behaviour:
POSTwith one JSON-RPC message:200+ JSON response, or202with an empty body for notifications.GETand other methods:405(no server-initiated SSE streams).- JSON-RPC batches are not supported (removed in MCP 2025-06-18).
Authentication is the host's responsibility. Place the route under an existing firewall, for example:
# config/packages/security.yaml
security:
firewalls:
api:
pattern: ^/api/
stateless: true
custom_authenticators: [App\Security\ApiKeyAuthenticator]
Connecting Claude Code to an HTTP server:
claude mcp add --transport http tasks https://example.com/api/mcp --header "X-API-Key: <key>"
stdio transport
php bin/console ai-tool-mcp:serve-stdio
The command reads newline-delimited JSON-RPC messages from stdin and writes exactly one line per request to stdout. Stdout carries protocol messages only. Make sure the application does not log to stdout in the environment you run the command in (log to stderr or a file instead).
Connecting Claude Code to a local project:
claude mcp add tasks -- php /path/to/project/bin/console ai-tool-mcp:serve-stdio --env=prod
Running with --env=prod and a warmed cache keeps startup fast; the process stays alive for the whole session.
Tool results
- Success:
{"content": [{"type": "text", "text": "<result as JSON>"}], "isError": false}. The tool'sToolCallResultDto::$resultmap is encoded as JSON (Unicode and slashes unescaped). - Tool error:
{"content": [{"type": "text", "text": "<exception message>"}], "isError": true}. - Unknown tool or invalid
tools/callparameters: JSON-RPC error-32602. - Unknown method: JSON-RPC error
-32601.
Development
composer test # PHPUnit (unit + HTTP and stdio integration tests on a test kernel)
composer stan # PHPStan
composer cs:fix # PHP CS Fixer
composer rector # Rector
License
MIT