Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
30 changes: 18 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ Build automation workflows, integrate with external systems, manage application
### **Core Capabilities**
- **56+ Automation Tools**: Comprehensive toolkit across 10 tag categories for all network automation needs
- **Advanced Tool Selection**: Filter and control available tools using flexible tagging system
- **Multiple Transport Methods**: stdio, SSE, and HTTP transports with optional TLS encryption
- **Multiple Transport Methods**: stdio and HTTP (Streamable HTTP, recommended) transports with optional TLS encryption; legacy SSE transport is also available but deprecated
- **Dynamic Tool Discovery**: Automatically discovers and registers tools without code modifications
- **Flexible Authentication**: Supports basic auth, OAuth 2.0, JWT, and role-based access for Itential Platform
- **Comprehensive Configuration**: CLI parameters, environment variables, or configuration files
Expand Down Expand Up @@ -100,8 +100,8 @@ For development, you can run the server directly using `uv`:
# Run with stdio transport (default)
uv run itential-mcp run

# Run with SSE transport
uv run itential-mcp run --transport sse --host 0.0.0.0 --port 8000
# Run with HTTP transport (Streamable HTTP, recommended for web integration)
uv run itential-mcp run --transport http --host 0.0.0.0 --port 8000

# Run with specific configuration
uv run itential-mcp run --include-tags "system,devices" --exclude-tags "experimental"
Expand All @@ -116,9 +116,9 @@ Pull and run the latest release:
# Pull the latest image
docker pull ghcr.io/itential/itential-mcp:latest

# Run with SSE transport
# Run with HTTP transport (Streamable HTTP, recommended)
docker run -p 8000:8000 \
--env ITENTIAL_MCP_SERVER_TRANSPORT=sse \
--env ITENTIAL_MCP_SERVER_TRANSPORT=http \
--env ITENTIAL_MCP_SERVER_HOST=0.0.0.0 \
--env ITENTIAL_MCP_SERVER_PORT=8000 \
--env ITENTIAL_MCP_PLATFORM_HOST=your-platform.example.com \
Expand All @@ -128,7 +128,7 @@ docker run -p 8000:8000 \

# Or with OAuth authentication
docker run -p 8000:8000 \
--env ITENTIAL_MCP_SERVER_TRANSPORT=sse \
--env ITENTIAL_MCP_SERVER_TRANSPORT=http \
--env ITENTIAL_MCP_SERVER_HOST=0.0.0.0 \
--env ITENTIAL_MCP_SERVER_PORT=8000 \
--env ITENTIAL_MCP_PLATFORM_HOST=your-platform.example.com \
Expand All @@ -153,7 +153,7 @@ make container

# Run the locally built container
docker run -p 8000:8000 \
--env ITENTIAL_MCP_SERVER_TRANSPORT=sse \
--env ITENTIAL_MCP_SERVER_TRANSPORT=http \
--env ITENTIAL_MCP_SERVER_HOST=0.0.0.0 \
--env ITENTIAL_MCP_SERVER_PORT=8000 \
--env ITENTIAL_MCP_PLATFORM_HOST=your-platform.example.com \
Expand Down Expand Up @@ -183,8 +183,8 @@ export ITENTIAL_MCP_PLATFORM_PASSWORD="your-password"
# Basic stdio transport (default)
itential-mcp run

# Or with SSE transport for web clients
itential-mcp run --transport sse --host 0.0.0.0 --port 8000
# Or with HTTP transport (Streamable HTTP, recommended for web clients)
itential-mcp run --transport http --host 0.0.0.0 --port 8000
```

### **4. Configure Your MCP Client**
Expand All @@ -197,7 +197,13 @@ Start the MCP server with default settings _(stdio transport)_:
itential-mcp run
```

Start with SSE transport:
Start with HTTP transport (Streamable HTTP, recommended for web integration):

```bash
itential-mcp run --transport http --host 0.0.0.0 --port 8000
```

Start with SSE transport (deprecated - legacy HTTP+SSE, prefer http):

```bash
itential-mcp run --transport sse --host 0.0.0.0 --port 8000
Expand All @@ -222,7 +228,7 @@ itential-mcp run --config config.conf

| Option | Description | Default |
|------------------|---------------------------------------------------|-------------------|
| `--transport` | Transport protocol (stdio, sse, http) | stdio |
| `--transport` | Transport protocol (stdio, sse, http; sse is deprecated, prefer http) | stdio |
| `--host` | Host address to listen on | 127.0.0.1 |
| `--port` | Port to listen on | 8000 |
| `--path` | The HTTP path to use | /mcp |
Expand All @@ -249,7 +255,7 @@ itential-mcp run --config config.conf
All command line options can also be set using environment variables prefixed with `ITENTIAL_MCP_SERVER_`. For example:

```bash
export ITENTIAL_MCP_SERVER_TRANSPORT=sse
export ITENTIAL_MCP_SERVER_TRANSPORT=http
export ITENTIAL_MCP_PLATFORM_HOST=platform.example.com
itential-mcp run # Will use the environment variables
```
Expand Down
8 changes: 5 additions & 3 deletions docs/mcp.conf.example
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@
[server]

# Configures the transport to use when starting the MCP server. This
# configuration option accepts one of three valid values: `sse`, `stdio`
# or `http`
# configuration option accepts one of three valid values: `sse`, `stdio`
# or `http`. `http` (Streamable HTTP) is recommended for web-based
# deployments; `sse` is deprecated (legacy HTTP+SSE) and kept only for
# backward compatibility.
#
# Default value: stdio
# Environment variable: ITENTIAL_MCP_SERVER_TRANSPORT
#
# transport = sse
# transport = http

# Sets the IP address to listen for connections on. This value must be a valid
# IP address used by MCP clients to connect to this server. This value is only
Expand Down
4 changes: 3 additions & 1 deletion src/itential_mcp/config/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,9 @@ class ServerConfig:

transport: Literal["stdio", "sse", "http"] = _create_field_with_env(
"ITENTIAL_MCP_SERVER_TRANSPORT",
"The MCP server transport to use",
"The MCP server transport to use. 'http' (Streamable HTTP) is "
"recommended; 'sse' is deprecated (legacy HTTP+SSE) and kept only "
"for backward compatibility.",
default=defaults.ITENTIAL_MCP_SERVER_TRANSPORT,
json_schema_extra={
"x-itential-mcp-cli-enabled": True,
Expand Down
10 changes: 10 additions & 0 deletions src/itential_mcp/server/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,16 @@ async def run(self):

# Continue with normal startup
if self.config.server.transport in ("sse", "http"):
if self.config.server.transport == "sse":
logging.warning(
"The 'sse' transport is deprecated and will be removed in a "
"future release. The MCP specification deprecated the "
"HTTP+SSE transport (protocol revision 2024-11-05); new "
"deployments should use the Streamable HTTP transport "
"instead. Migrate with --transport http (or "
"ITENTIAL_MCP_SERVER_TRANSPORT=http)."
)

app = self.mcp.http_app(path=self.config.server.path)

uvicorn_config = uvicorn.Config(
Expand Down
84 changes: 84 additions & 0 deletions tests/test_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -773,6 +773,90 @@ async def test_server_run_sse_transport_with_uvicorn(
mock_uvicorn_server.assert_called_once()
mock_uvicorn_instance.serve.assert_called_once()

@pytest.mark.asyncio
@patch("itential_mcp.server.server.uvicorn.Server")
@patch("itential_mcp.server.server.Server.__aenter__")
@patch("itential_mcp.server.server.Server.__aexit__")
@patch("itential_mcp.server.server.logging.warning")
async def test_server_run_sse_transport_emits_deprecation_warning(
self, mock_warning, mock_aexit, mock_aenter, mock_uvicorn_server
):
"""Test Server.run() logs a deprecation warning for the sse transport"""
mock_config = MagicMock()
mock_config.server.transport = "sse"
mock_config.server.host = "0.0.0.0"
mock_config.server.port = 8080
mock_config.server.certificate_file = None
mock_config.server.private_key_file = None
mock_config.server.path = "/mcp"
mock_config.server.test_connection_on_startup = False

server_instance = server_module.Server(mock_config)

mock_mcp = MagicMock()
mock_mcp.http_app = MagicMock(return_value="test_app")
server_instance.mcp = mock_mcp

mock_uvicorn_instance = MagicMock()
mock_uvicorn_instance.serve = AsyncMock()
mock_uvicorn_server.return_value = mock_uvicorn_instance

with patch("itential_mcp.server.server.uvicorn.Config"):
await server_instance.run()

mock_warning.assert_called_once()

@pytest.mark.asyncio
@patch("itential_mcp.server.server.uvicorn.Server")
async def test_server_run_http_transport_does_not_emit_deprecation_warning(
self, mock_uvicorn_server
):
"""Test Server.run() does not log a deprecation warning for http transport"""
mock_config = MagicMock()
mock_config.server.transport = "http"
mock_config.server.host = "localhost"
mock_config.server.port = 3000
mock_config.server.certificate_file = None
mock_config.server.private_key_file = None
mock_config.server.path = "/mcp"
mock_config.server.test_connection_on_startup = False

server_instance = server_module.Server(mock_config)

mock_mcp = MagicMock()
mock_mcp.http_app = MagicMock(return_value="test_app")
server_instance.mcp = mock_mcp

mock_uvicorn_instance = MagicMock()
mock_uvicorn_instance.serve = AsyncMock()
mock_uvicorn_server.return_value = mock_uvicorn_instance

with (
patch("itential_mcp.server.server.uvicorn.Config"),
patch("itential_mcp.server.server.logging.warning") as mock_warning,
):
await server_instance.run()

mock_warning.assert_not_called()

@pytest.mark.asyncio
async def test_server_run_stdio_transport_does_not_emit_deprecation_warning(self):
"""Test Server.run() does not log a deprecation warning for stdio transport"""
mock_config = MagicMock()
mock_config.server.transport = "stdio"
mock_config.server.test_connection_on_startup = False

server_instance = server_module.Server(mock_config)

mock_mcp = MagicMock()
mock_mcp.run_async = AsyncMock()
server_instance.mcp = mock_mcp

with patch("itential_mcp.server.server.logging.warning") as mock_warning:
await server_instance.run()

mock_warning.assert_not_called()

@pytest.mark.asyncio
@patch("itential_mcp.server.server.uvicorn.Server")
async def test_server_run_http_transport_with_uvicorn(self, mock_uvicorn_server):
Expand Down
Loading