Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,11 @@
"ext-fileinfo": "*",
"opis/json-schema": "^2.4",
"phpdocumentor/reflection-docblock": "^5.6",
"psr/clock": "^1.0",
"psr/container": "^2.0",
"psr/event-dispatcher": "^1.0",
"psr/http-factory": "^1.1",
"psr/http-message": "^2.0",
"psr/log": "^1.0 || ^2.0 || ^3.0",
"symfony/finder": "^6.4 || ^7.3",
"symfony/uid": "^6.4 || ^7.3"
Expand All @@ -34,7 +37,10 @@
"phpunit/phpunit": "^10.5",
"psr/cache": "^3.0",
"symfony/console": "^6.4 || ^7.3",
"symfony/process": "^6.4 || ^7.3"
"symfony/process": "^6.4 || ^7.3",
"nyholm/psr7": "^1.8",
"nyholm/psr7-server": "^1.1",
"laminas/laminas-httphandlerrunner": "^2.12"
},
"autoload": {
"psr-4": {
Expand All @@ -51,10 +57,11 @@
"Mcp\\Example\\DependenciesStdioExample\\": "examples/06-custom-dependencies-stdio/",
"Mcp\\Example\\ComplexSchemaHttpExample\\": "examples/07-complex-tool-schema-http/",
"Mcp\\Example\\SchemaShowcaseExample\\": "examples/08-schema-showcase-streamable/",
"Mcp\\Example\\HttpTransportExample\\": "examples/10-simple-http-transport/",
"Mcp\\Tests\\": "tests/"
}
},
"config": {
"sort-packages": true
}
}
}
13 changes: 9 additions & 4 deletions examples/01-discovery-stdio-calculator/server.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,25 @@
* file that was distributed with this source code.
*/

require_once dirname(__DIR__).'/bootstrap.php';
require_once dirname(__DIR__) . '/bootstrap.php';
chdir(__DIR__);

use Mcp\Server;
use Mcp\Server\Transport\StdioTransport;

logger()->info('Starting MCP Stdio Calculator Server...');

Server::make()
$server = Server::make()
->setServerInfo('Stdio Calculator', '1.1.0', 'Basic Calculator over STDIO transport.')
->setContainer(container())
->setLogger(logger())
->setDiscovery(__DIR__, ['.'])
->build()
->connect(new StdioTransport(logger: logger()));
->build();

$transport = new StdioTransport(logger: logger());

$server->connect($transport);

$transport->listen();

logger()->info('Server listener stopped gracefully.');
1 change: 1 addition & 0 deletions examples/10-simple-http-transport/.gitignore
Copy link
Member

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?

Copy link
Contributor Author

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)

Copy link
Member

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

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool. Got it!

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
sessions/
101 changes: 101 additions & 0 deletions examples/10-simple-http-transport/McpElements.php
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."
];
}
}
24 changes: 24 additions & 0 deletions examples/10-simple-http-transport/README.md
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
Copy link
Member

Choose a reason for hiding this comment

The 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?

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, did all of that ... will try again later

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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`
31 changes: 31 additions & 0 deletions examples/10-simple-http-transport/server.php
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);
Loading
Loading