1919The `Model Context Protocol `_ is built on top of JSON-RPC. There two types of
2020messages. A Notification and Request. The Notification is just a status update
2121that something has happened. There is never a response to a Notification. A Request
22- is a message that expects a response. There are 3 concepts that you may request.
23- These are::
22+ is a message that expects a response. There are 3 concepts/capabilities that you
23+ may use. These are::
2424
25251. **Resources **: File-like data that can be read by clients (like API responses or file contents)
26261. **Tools **: Functions that can be called by the LLM (with user approval)
@@ -29,4 +29,136 @@ These are::
2929The SDK comes with NotificationHandlers and RequestHandlers which are expected
3030to be wired up in your application.
3131
32+ JsonRpcHandler
33+ ..............
34+
35+ The ``Symfony\AI\McpSdk\Server\JsonRpcHandler `` is the heart of the SDK. It is here
36+ you inject the NotificationHandlers and RequestHandlers. It is recommended to use
37+ the built-in handlers in ``Symfony\AI\McpSdk\Server\NotificationHandlers\* `` and
38+ ``Symfony\AI\McpSdk\Server\RequestHandlers\* ``.
39+
40+ The ``Symfony\AI\McpSdk\Server\JsonRpcHandler `` is started and kept running by
41+ the ``Symfony\AI\McpSdk\Server ``
42+
43+ Transports
44+ ..........
45+
46+ The SDK supports multiple transports for sending and receiving messages. The
47+ ``Symfony\AI\McpSdk\Server `` is using the transport to fetch a message, then
48+ give it to the ``Symfony\AI\McpSdk\Server\JsonRpcHandler `` and finally send the
49+ response/error back to the transport. The SDK comes with a few transports::
50+
51+ 1. **Symfony Console Transport **: Good for testing and for CLI applications
52+ 1. **Stream Transport **: It uses Server Side Events (SSE) and HTTP streaming
53+
54+ Capabilities
55+ ............
56+
57+ Any client would like to discover the capabilities of the server. Exactly what
58+ the server supports is defined in the ``Symfony\AI\McpSdk\Server\RequestHandler\InitializeHandler ``.
59+ When the client connects, it sees the capabilities and will ask the server to list
60+ the tools/resource/prompts etc. When you want to add a new capability, example a
61+ **Tool ** that can tell the current time, you need to provide some metadata to the
62+ ``Symfony\AI\McpSdk\Server\RequestHandler\ToolListHandler ``.
63+
64+ .. code-block: php
65+
66+ namespace App;
67+
68+ use Symfony\AI\McpSdk\Capability\Tool\MetadataInterface;
69+
70+ class CurrentTimeToolMetadata implements MetadataInterface
71+ {
72+ public function getName(): string
73+ {
74+ return 'Current time';
75+ }
76+
77+ public function getDescription(): string
78+ {
79+ return 'Returns the current time in UTC';
80+ }
81+
82+ public function getInputSchema(): array
83+ {
84+ return [
85+ 'type' => 'object',
86+ 'properties' => [
87+ 'format' => [
88+ 'type' => 'string',
89+ 'description' => 'The format of the time, e.g. "Y-m-d H:i:s"',
90+ 'default' => 'Y-m-d H:i:s',
91+ ],
92+ ],
93+ 'required' => [],
94+ ];
95+ }
96+ }
97+
98+ We would also need a class to actually execute the tool.
99+
100+ .. code-block: php
101+
102+ namespace App;
103+
104+ use Symfony\AI\McpSdk\Capability\Tool\ToolExecutorInterface;
105+ use Symfony\AI\McpSdk\Capability\Tool\IdentifierInterface;
106+ use Symfony\AI\McpSdk\Capability\Tool\ToolCall;
107+ use Symfony\AI\McpSdk\Capability\Tool\ToolCallResult;
108+
109+ class CurrentTimeToolExecutor implements ToolExecutorInterface, IdentifierInterface
110+ {
111+ public function getName(): string
112+ {
113+ return 'Current time';
114+ }
115+
116+ public function call(ToolCall $input): ToolCallResult
117+ {
118+ $format = $input->arguments['format'] ?? 'Y-m-d H:i:s';
119+
120+ return new ToolCallResult(
121+ (new \DateTime('now', new \DateTimeZone('UTC')))->format($format)
122+ );
123+ }
124+ }
125+
126+ If you have multiple tools, you can put them in a ToolChain.
127+
128+ .. code-block: php
129+
130+ $tools = new ToolChain([
131+ new CurrentTimeToolMetadata(),
132+ new CurrentTimeToolExecutor(),
133+ ]);
134+
135+ $jsonRpcHandler = new Symfony\AI\McpSdk\Server\JsonRpcHandler(
136+ new Symfony\AI\McpSdk\Message\Factory(),
137+ [
138+ new ToolCallHandler($tools),
139+ new ToolListHandler($tools),
140+ // Other RequestHandlers ...
141+ ],
142+ [
143+ // Other NotificationHandlers ...
144+ ],
145+ new NullLogger()
146+ );
147+
148+ With this metadata and executor, the client can now call the tool.
149+
150+ Extending the SDK
151+ -----------------
152+
153+ If you want to extend the SDK, you can create your own RequestHandlers and NotificationHandlers.
154+ The provided one are very good defaults for most applications but they are not
155+ a requirement.
156+
157+ If you do decide to use them, you get the benefit of having a well-defined interfaces
158+ and value objects to work with. They will assure that you follow the `Model Context Protocol `_.
159+ specification.
160+
161+ You also have the Transport abstraction that allows you to create your own transport
162+ if non of the standard ones fit your needs.
163+
32164.. _`Model Context Protocol` : https://modelcontextprotocol.io/
0 commit comments