Skip to content

Commit 436c0a0

Browse files
committed
Add an overview documentation of the SDK
1 parent 504cdce commit 436c0a0

File tree

2 files changed

+135
-3
lines changed

2 files changed

+135
-3
lines changed

src/mcp-sdk/composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
],
1616
"require": {
1717
"php": "^8.2",
18-
"psr/log": "^3.0",
18+
"psr/log": "^1.0 || ^2.0 || ^3.0",
1919
"symfony/uid": "^6.4 || ^7.0"
2020
},
2121
"require-dev": {

src/mcp-sdk/doc/index.rst

Lines changed: 134 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ Usage
1919
The `Model Context Protocol`_ is built on top of JSON-RPC. There two types of
2020
messages. A Notification and Request. The Notification is just a status update
2121
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::
2424

2525
1. **Resources**: File-like data that can be read by clients (like API responses or file contents)
2626
1. **Tools**: Functions that can be called by the LLM (with user approval)
@@ -29,4 +29,136 @@ These are::
2929
The SDK comes with NotificationHandlers and RequestHandlers which are expected
3030
to 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

Comments
 (0)