Skip to content

Commit a587dcb

Browse files
authored
Create CONTRIBUTING.md
1 parent 5b7edae commit a587dcb

File tree

1 file changed

+269
-0
lines changed

1 file changed

+269
-0
lines changed

CONTRIBUTING.md

Lines changed: 269 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,269 @@
1+
# Symfony MCP Server Development Guidelines
2+
3+
This document provides essential information for developers working on the Symfony MCP Server project.
4+
5+
## Build/Configuration Instructions
6+
7+
### Prerequisites
8+
- PHP 8.2 or higher
9+
- Symfony 6.4 or higher
10+
- Composer
11+
12+
### Installation
13+
14+
1. Clone the repository:
15+
```bash
16+
git clone https://github.com/klapaudius/symfony-mcp-server.git
17+
```
18+
19+
2. Create a new Symfony project (if you don't have one already):
20+
```bash
21+
composer create-project symfony/skeleton my-symfony-project
22+
cd my-symfony-project
23+
```
24+
25+
3. Add the cloned repository as a local repository in your Symfony project's composer.json:
26+
```json
27+
{
28+
"repositories": [
29+
{
30+
"type": "path",
31+
"url": "../symfony-mcp-server"
32+
}
33+
]
34+
}
35+
```
36+
Note: Adjust the path "../symfony-mcp-server" to match the relative path from your Symfony project to the cloned repository.
37+
38+
4. Require the package from the local repository:
39+
```bash
40+
composer require klapaudius/symfony-mcp-server:@dev
41+
```
42+
43+
5. Create the configuration file `config/packages/klp_mcp_server.yaml` with the following content:
44+
```yaml
45+
klp_mcp_server:
46+
enabled: true
47+
server:
48+
name: 'My MCP Server'
49+
version: '1.0.0'
50+
default_path: 'mcp'
51+
ping:
52+
enabled: true
53+
interval: 30
54+
server_providers: ['streamable_http', 'sse'] # Available options: 'sse', 'streamable_http'
55+
sse_adapter: 'cache'
56+
adapters:
57+
redis:
58+
prefix: 'mcp_sse_'
59+
host: 'localhost' # Change as needed
60+
ttl: 100
61+
tools:
62+
- KLP\KlpMcpServer\Services\ToolService\Examples\HelloWorldTool
63+
- KLP\KlpMcpServer\Services\ToolService\Examples\StreamingDataTool
64+
- KLP\KlpMcpServer\Services\ToolService\Examples\VersionCheckTool
65+
```
66+
67+
6. Add routes in your `config/routes.yaml`:
68+
```yaml
69+
klp_mcp_server:
70+
resource: '@KlpMcpServerBundle/Resources/config/routes.php'
71+
type: php
72+
```
73+
74+
### Important Configuration Notes
75+
76+
- **Web Server**: This package cannot be used with `symfony server:start` as it requires processing multiple connections concurrently. Use Nginx + PHP-FPM, Apache + PHP-FPM, or a custom Docker setup instead.
77+
- **Redis Configuration**: Ensure your Redis server is properly configured and accessible at the host specified in the configuration.
78+
- **Security**: It's strongly recommended to implement OAuth2 Authentication for production use.
79+
- **Protocol Support**: This bundle supports two protocols:
80+
- **SSE (Server-Sent Events)**: The legacy protocol for real-time communication.
81+
- **StreamableHTTP**: The actual protocol that works over standard HTTP connection or Streaming if needed.
82+
83+
### Docker Setup
84+
85+
The project includes a Docker setup that can be used for development. The Docker setup includes:
86+
- Nginx web server
87+
- PHP-FPM with Redis extension
88+
- Redis server
89+
90+
To set up and use the Docker containers:
91+
92+
1. Navigate to the docker directory:
93+
```bash
94+
cd docker
95+
```
96+
97+
2. Configure the environment variables by creating a `.env.local` file:
98+
```bash
99+
# Example configuration
100+
COMPOSE_PROJECT_NAME=mcp
101+
102+
NGINX_IP=172.20.0.2
103+
NGINX_EXPOSED_PORT=8080
104+
105+
PHP_IP=172.20.0.3
106+
107+
REDIS_IP=172.20.0.4
108+
109+
NETWORK_SUBNET=172.20.0.0/24
110+
```
111+
Note: Adjust the IP addresses and port as needed for your environment.
112+
113+
3. Build and start the Docker containers:
114+
```bash
115+
docker-compose up -d
116+
```
117+
118+
4. Access the application in your browser at `http://localhost:8080` (or the port you specified in NGINX_EXPOSED_PORT).
119+
120+
5. To stop the containers:
121+
```bash
122+
docker-compose down
123+
```
124+
125+
6. Update your Symfony configuration to use the Redis server in the Docker container:
126+
```yaml
127+
# config/packages/klp_mcp_server.yaml
128+
klp_mcp_server:
129+
# ...
130+
adapters:
131+
redis:
132+
prefix: 'mcp_sse_'
133+
host: 'redis' # Use the service name from docker-compose.yml
134+
ttl: 100
135+
```
136+
137+
## Testing Information
138+
139+
### Running Tests
140+
141+
The project uses PHPUnit for testing. To run all tests:
142+
143+
```bash
144+
vendor/bin/phpunit
145+
```
146+
147+
To run a specific test file:
148+
149+
```bash
150+
vendor/bin/phpunit tests/path/to/TestFile.php
151+
```
152+
153+
To generate code coverage reports:
154+
155+
```bash
156+
vendor/bin/phpunit --coverage-html build/coverage
157+
```
158+
159+
### Adding New Tests
160+
161+
1. **Test Location**: Place tests in the `tests/` directory, mirroring the structure of the `src/` directory.
162+
2. **Naming Convention**: Name test classes with the suffix `Test` (e.g., `DataUtilTest.php`).
163+
3. **Test Size**: Use PHPUnit attributes to indicate test size:
164+
```php
165+
#[Small] // For unit tests
166+
#[Medium] // For integration tests
167+
#[Large] // For system tests
168+
```
169+
4. **Mocking**: Use PHPUnit's mocking capabilities for dependencies:
170+
```php
171+
$mockTransport = $this->createMock(SseTransportInterface::class);
172+
```
173+
174+
### Example Test
175+
176+
Here's a simple test for the `DataUtil` class:
177+
178+
```php
179+
<?php
180+
181+
namespace KLP\KlpMcpServer\Tests\Utils;
182+
183+
use KLP\KlpMcpServer\Data\Requests\NotificationData;
184+
use KLP\KlpMcpServer\Data\Requests\RequestData;
185+
use KLP\KlpMcpServer\Utils\DataUtil;
186+
use PHPUnit\Framework\Attributes\Small;
187+
use PHPUnit\Framework\TestCase;
188+
189+
#[Small]
190+
class DataUtilTest extends TestCase
191+
{
192+
public function test_make_request_data_creates_request_data_when_message_has_method_and_id(): void
193+
{
194+
$clientId = 'test_client';
195+
$message = [
196+
'jsonrpc' => '2.0',
197+
'method' => 'test.method',
198+
'id' => 1,
199+
'params' => ['param1' => 'value1']
200+
];
201+
202+
$result = DataUtil::makeRequestData($clientId, $message);
203+
204+
$this->assertInstanceOf(RequestData::class, $result);
205+
$this->assertEquals('test.method', $result->method);
206+
$this->assertEquals('2.0', $result->jsonRpc);
207+
$this->assertEquals(1, $result->id);
208+
$this->assertEquals(['param1' => 'value1'], $result->params);
209+
}
210+
}
211+
```
212+
213+
## Additional Development Information
214+
215+
### Code Style
216+
217+
- The project follows PSR-12 coding standards.
218+
- Use type hints for method parameters and return types.
219+
- Document classes and methods with PHPDoc comments.
220+
221+
### Creating MCP Tools
222+
223+
1. Use the provided command to generate a new tool:
224+
```bash
225+
php bin/console make:mcp-tool MyCustomTool
226+
```
227+
228+
2. Implement the `StreamableToolInterface` in your custom tool class:
229+
```php
230+
use KLP\KlpMcpServer\Services\ToolService\StreamableToolInterface;
231+
232+
class MyCustomTool implements StreamableToolInterface
233+
{
234+
// Implementation
235+
}
236+
```
237+
238+
3. Register your tool in `config/packages/klp_mcp_server.yaml`.
239+
240+
### Testing MCP Tools
241+
242+
Use the provided command to test your MCP tools:
243+
244+
```bash
245+
# Test a specific tool interactively
246+
php bin/console mcp:test-tool MyCustomTool
247+
248+
# List all available tools
249+
php bin/console mcp:test-tool --list
250+
251+
# Test with specific JSON input
252+
php bin/console mcp:test-tool MyCustomTool --input='{"param":"value"}'
253+
```
254+
255+
### Debugging
256+
257+
- Enable Symfony's debug mode for detailed error messages.
258+
- Use the MCP Inspector for visualizing and testing your MCP tools:
259+
```bash
260+
npx @modelcontextprotocol/inspector node build/index.js
261+
```
262+
263+
### Architecture Notes
264+
265+
- The package implements a publish/subscribe (pub/sub) messaging pattern through its adapter system.
266+
- The default Redis adapter maintains message queues for each client, identified by unique client IDs.
267+
- The bundle supports two transport protocols:
268+
- **SSE (Server-Sent Events)**: Long-lived connections that subscribe to messages for their respective clients and deliver them in real-time.
269+
- **StreamableHTTP**: An HTTP-based protocol that can handle both streaming and non-streaming responses.

0 commit comments

Comments
 (0)