19
19
The `Model Context Protocol `_ is built on top of JSON-RPC. There two types of
20
20
messages. A Notification and Request. The Notification is just a status update
21
21
that 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::
24
24
25
25
1. **Resources **: File-like data that can be read by clients (like API responses or file contents)
26
26
1. **Tools **: Functions that can be called by the LLM (with user approval)
@@ -29,4 +29,136 @@ These are::
29
29
The SDK comes with NotificationHandlers and RequestHandlers which are expected
30
30
to be wired up in your application.
31
31
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
+
32
164
.. _`Model Context Protocol` : https://modelcontextprotocol.io/
0 commit comments