-
Notifications
You must be signed in to change notification settings - Fork 81
[Server] Rework transport architecture and add StreamableHttpTransport #49
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 9 commits
7f44d22
eb28fda
fdb5e17
456480d
74e56a2
3cf1838
25bec57
1536db2
468b9ff
e276e6b
5605f07
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| sessions/ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,101 @@ | ||
| <?php | ||
|
|
||
| namespace Mcp\Example\HttpTransportExample; | ||
|
|
||
| use Mcp\Capability\Attribute\McpPrompt; | ||
| use Mcp\Capability\Attribute\McpResource; | ||
| use Mcp\Capability\Attribute\McpTool; | ||
|
|
||
| class McpElements | ||
| { | ||
| public function __construct() {} | ||
|
|
||
| /** | ||
| * Get the current server time | ||
| */ | ||
| #[McpTool(name: 'current_time')] | ||
| public function getCurrentTime(string $format = 'Y-m-d H:i:s'): string | ||
| { | ||
| try { | ||
| return date($format); | ||
| } catch (\Exception $e) { | ||
| return date('Y-m-d H:i:s'); // fallback | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Calculate simple math operations | ||
| */ | ||
| #[McpTool(name: 'calculate')] | ||
| public function calculate(float $a, float $b, string $operation): float|string | ||
| { | ||
| return match (strtolower($operation)) { | ||
| 'add', '+' => $a + $b, | ||
| 'subtract', '-' => $a - $b, | ||
| 'multiply', '*' => $a * $b, | ||
| 'divide', '/' => $b != 0 ? $a / $b : 'Error: Division by zero', | ||
| default => 'Error: Unknown operation. Use: add, subtract, multiply, divide' | ||
| }; | ||
| } | ||
|
|
||
| /** | ||
| * Server information resource | ||
| */ | ||
| #[McpResource( | ||
| uri: 'info://server/status', | ||
| name: 'server_status', | ||
| description: 'Current server status and information', | ||
| mimeType: 'application/json' | ||
| )] | ||
| public function getServerStatus(): array | ||
| { | ||
| return [ | ||
| 'status' => 'running', | ||
| 'timestamp' => time(), | ||
| 'version' => '1.0.0', | ||
| 'transport' => 'HTTP', | ||
| 'uptime' => time() - $_SERVER['REQUEST_TIME'] | ||
| ]; | ||
| } | ||
|
|
||
| /** | ||
| * Configuration resource | ||
| */ | ||
| #[McpResource( | ||
| uri: 'config://app/settings', | ||
| name: 'app_config', | ||
| description: 'Application configuration settings', | ||
| mimeType: 'application/json' | ||
| )] | ||
| public function getAppConfig(): array | ||
| { | ||
| return [ | ||
| 'debug' => $_SERVER['DEBUG'] ?? false, | ||
| 'environment' => $_SERVER['APP_ENV'] ?? 'production', | ||
| 'timezone' => date_default_timezone_get(), | ||
| 'locale' => 'en_US' | ||
| ]; | ||
| } | ||
|
|
||
| /** | ||
| * Greeting prompt | ||
| */ | ||
| #[McpPrompt( | ||
| name: 'greet', | ||
| description: 'Generate a personalized greeting message' | ||
| )] | ||
| public function greetPrompt(string $firstName = 'World', string $timeOfDay = 'day'): array | ||
| { | ||
| $greeting = match (strtolower($timeOfDay)) { | ||
| 'morning' => 'Good morning', | ||
| 'afternoon' => 'Good afternoon', | ||
| 'evening', 'night' => 'Good evening', | ||
| default => 'Hello' | ||
| }; | ||
|
|
||
| return [ | ||
| 'role' => 'user', | ||
| 'content' => "# {$greeting}, {$firstName}!\n\nWelcome to our MCP HTTP Server example. This demonstrates how to use the Model Context Protocol over HTTP transport." | ||
| ]; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| # HTTP MCP Server Example | ||
|
|
||
| This example demonstrates how to use the MCP SDK with HTTP transport using the StreamableHttpTransport. It provides a complete HTTP-based MCP server that can handle JSON-RPC requests over HTTP POST. | ||
|
|
||
| ## Usage | ||
|
|
||
| **Step 1: Start the HTTP server** | ||
|
|
||
| ```bash | ||
| cd examples/10-simple-http-transport | ||
| php -S localhost:8000 server.php | ||
| ``` | ||
|
|
||
| **Step 2: Connect with MCP Inspector** | ||
|
|
||
| ```bash | ||
| npx @modelcontextprotocol/inspector http://localhost:8000 | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. currently doesn't work for me - am i missing something? it was running for you already?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Works for me. Make sure you’ve pulled the latest commit and run composer update (I added a new dependency: psr/clock). Also, check that the inspector is set to Streamable HTTP instead of STDIO cos it sometimes defaults to STDIO.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yea, did all of that ... will try again later
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Interesting 🤔. Waiting for feedback then |
||
| ``` | ||
|
|
||
| ## Available Features | ||
|
|
||
| - **Tools**: `current_time`, `calculate` | ||
| - **Resources**: `info://server/status`, `config://app/settings` | ||
| - **Prompts**: `greet` | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| <?php | ||
|
|
||
| require_once dirname(__DIR__) . '/bootstrap.php'; | ||
| chdir(__DIR__); | ||
|
|
||
| use Mcp\Server; | ||
| use Mcp\Server\Transport\StreamableHttpTransport; | ||
| use Nyholm\Psr7\Factory\Psr17Factory; | ||
| use Nyholm\Psr7Server\ServerRequestCreator; | ||
| use Laminas\HttpHandlerRunner\Emitter\SapiEmitter; | ||
| use Mcp\Server\Session\FileSessionStore; | ||
|
|
||
| $psr17Factory = new Psr17Factory(); | ||
| $creator = new ServerRequestCreator($psr17Factory, $psr17Factory, $psr17Factory, $psr17Factory); | ||
|
|
||
| $request = $creator->fromGlobals(); | ||
|
|
||
| $server = Server::make() | ||
| ->setServerInfo('HTTP MCP Server', '1.0.0', 'MCP Server over HTTP transport') | ||
| ->setContainer(container()) | ||
| ->setSession(new FileSessionStore(__DIR__ . '/sessions')) | ||
| ->setDiscovery(__DIR__, ['.']) | ||
| ->build(); | ||
|
|
||
| $transport = new StreamableHttpTransport($request, $psr17Factory, $psr17Factory); | ||
|
|
||
| $server->connect($transport); | ||
|
|
||
| $response = $transport->listen(); | ||
|
|
||
| (new SapiEmitter())->emit($response); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do we need this here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, the example has its own composer.json and installs dependencies locally so we wouldn't want to include that (unless we agree to move the dependencies to the base)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, that's clear - sorry, should have been more explicit.
If the vendor path is really needed, let's add it in the root level one - but I'd be fine with adding the deps to root dev dependencies - we'll need them in other examples as well potentially
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool. Got it!