feat: support 'headers' argument for SSE server connection (#23)
I have replaced the `--api-access-token` argument with the more generic `--headers` argument for SSE. This will allow for other auth mechanisms such as api keys as well. Intended usage: ```sh # API key mcp-proxy http://example.io/sse --headers x-api-key my-super-secret-api-key # Bearer token mcp-proxy http://example.io/sse --headers Authorization 'Bearer my-super-secret-bearer-token' # Multiple headers mcp-proxy http://example.io/sse --headers Authorization 'Bearer my-super-secret-bearer-token' --headers x-api-key my-super-secret-api-key ```
This commit is contained in:
30
README.md
30
README.md
@@ -51,16 +51,16 @@ This mode requires passing the URL to the MCP Server SSE endpoint as the first a
|
||||
|
||||
Arguments
|
||||
|
||||
| Name | Required | Description | Example |
|
||||
| -------------------- | -------- | --------------------------------------------------------------------- | --------------------- |
|
||||
| `command_or_url` | Yes | The MCP server SSE endpoint to connect to | http://example.io/sse |
|
||||
| `--api-access-token` | No | Will be sent as a `Bearer` access token in the `Authorization` header | YOUR_TOKEN |
|
||||
| Name | Required | Description | Example |
|
||||
| -------------------- | -------- | --------------------------------------------------------------------- | ----------------------------------------------|
|
||||
| `command_or_url` | Yes | The MCP server SSE endpoint to connect to | http://example.io/sse |
|
||||
| `--headers` | No | Headers to use for the MCP server SSE connection | Authorization 'Bearer my-secret-access-token' |
|
||||
|
||||
Environment Variables
|
||||
|
||||
| Name | Required | Description | Example |
|
||||
| ------------------ | -------- | ------------------------------------------- | ---------- |
|
||||
| `API_ACCESS_TOKEN` | No | Can be used instead of `--api-access-token` | YOUR_TOKEN |
|
||||
| Name | Required | Description | Example |
|
||||
| ------------------ | -------- | ---------------------------------------------------------------------------- | ---------- |
|
||||
| `API_ACCESS_TOKEN` | No | Can be used instead of `--headers Authorization 'Bearer <API_ACCESS_TOKEN>'` | YOUR_TOKEN |
|
||||
|
||||
### 1.2 Example usage
|
||||
|
||||
@@ -181,19 +181,19 @@ docker run -t ghcr.io/sparfenyuk/mcp-proxy:v0.3.2-alpine --help
|
||||
## Command line arguments
|
||||
|
||||
```bash
|
||||
usage: mcp-proxy [-h] [--api-access-token API_ACCESS_TOKEN] [-e KEY VALUE] [--sse-port SSE_PORT] [--sse-host SSE_HOST] [command_or_url] [args ...]
|
||||
usage: mcp-proxy [-h] [-H KEY VALUE] [-e KEY VALUE] [--sse-port SSE_PORT] [--sse-host SSE_HOST] [command_or_url] [args ...]
|
||||
|
||||
Start the MCP proxy in one of two possible modes: as a SSE or stdio client.
|
||||
Start the MCP proxy in one of two possible modes: as an SSE or stdio client.
|
||||
|
||||
positional arguments:
|
||||
command_or_url Command or URL to connect to. When a URL, will run a SSE client, otherwise will run the given command and connect as a stdio client. See corresponding options for more details.
|
||||
command_or_url Command or URL to connect to. When a URL, will run an SSE client, otherwise will run the given command and connect as a stdio client. See corresponding options for more details.
|
||||
|
||||
options:
|
||||
-h, --help show this help message and exit
|
||||
|
||||
SSE client options:
|
||||
--api-access-token API_ACCESS_TOKEN
|
||||
Access token Authorization header passed by the client to the SSE server. Can also be set as environment variable API_ACCESS_TOKEN.
|
||||
-H KEY VALUE, --headers KEY VALUE
|
||||
Headers to pass to the SSE server. Can be used multiple times.
|
||||
|
||||
stdio client options:
|
||||
args Any extra arguments to the command to spawn the server
|
||||
@@ -201,12 +201,12 @@ stdio client options:
|
||||
Environment variables used when spawning the server. Can be used multiple times.
|
||||
|
||||
SSE server options:
|
||||
--sse-port SSE_PORT Port to expose a SSE server on. Default is a random port
|
||||
--sse-host SSE_HOST Host to expose a SSE server on. Default is 127.0.0.1
|
||||
--sse-port SSE_PORT Port to expose an SSE server on. Default is a random port
|
||||
--sse-host SSE_HOST Host to expose an SSE server on. Default is 127.0.0.1
|
||||
|
||||
Examples:
|
||||
mcp-proxy http://localhost:8080/sse
|
||||
mcp-proxy --api-access-token YOUR_TOKEN http://localhost:8080/sse
|
||||
mcp-proxy --headers Authorization 'Bearer YOUR_TOKEN' http://localhost:8080/sse
|
||||
mcp-proxy --sse-port 8080 -- your-command --arg1 value1 --arg2 value2
|
||||
mcp-proxy your-command --sse-port 8080 -e KEY VALUE -e ANOTHER_KEY ANOTHER_VALUE
|
||||
```
|
||||
|
||||
@@ -22,8 +22,7 @@ logging.basicConfig(level=logging.DEBUG)
|
||||
SSE_URL: t.Final[str | None] = os.getenv(
|
||||
"SSE_URL",
|
||||
None,
|
||||
) # Left for backwards compatibility. Will be removed in future.
|
||||
API_ACCESS_TOKEN: t.Final[str | None] = os.getenv("API_ACCESS_TOKEN", None)
|
||||
)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
@@ -35,7 +34,7 @@ def main() -> None:
|
||||
epilog=(
|
||||
"Examples:\n"
|
||||
" mcp-proxy http://localhost:8080/sse\n"
|
||||
" mcp-proxy --api-access-token YOUR_TOKEN http://localhost:8080/sse\n"
|
||||
" mcp-proxy --headers Authorization 'Bearer YOUR_TOKEN' http://localhost:8080/sse\n"
|
||||
" mcp-proxy --sse-port 8080 -- your-command --arg1 value1 --arg2 value2\n"
|
||||
" mcp-proxy your-command --sse-port 8080 -e KEY VALUE -e ANOTHER_KEY ANOTHER_VALUE\n"
|
||||
),
|
||||
@@ -54,12 +53,13 @@ def main() -> None:
|
||||
|
||||
sse_client_group = parser.add_argument_group("SSE client options")
|
||||
sse_client_group.add_argument(
|
||||
"--api-access-token",
|
||||
default=API_ACCESS_TOKEN,
|
||||
help=(
|
||||
"Access token Authorization header passed by the client to the SSE "
|
||||
"server. Can also be set as environment variable API_ACCESS_TOKEN."
|
||||
),
|
||||
"-H",
|
||||
"--headers",
|
||||
nargs=2,
|
||||
action="append",
|
||||
metavar=("KEY", "VALUE"),
|
||||
help="Headers to pass to the SSE server. Can be used multiple times.",
|
||||
default=[],
|
||||
)
|
||||
|
||||
stdio_client_options = parser.add_argument_group("stdio client options")
|
||||
@@ -104,7 +104,10 @@ def main() -> None:
|
||||
):
|
||||
# Start a client connected to the SSE server, and expose as a stdio server
|
||||
logging.debug("Starting SSE client and stdio server")
|
||||
asyncio.run(run_sse_client(args.command_or_url, api_access_token=API_ACCESS_TOKEN))
|
||||
headers = dict(args.headers)
|
||||
if api_access_token := os.getenv("API_ACCESS_TOKEN", None):
|
||||
headers["Authorization"] = f"Bearer {api_access_token}"
|
||||
asyncio.run(run_sse_client(args.command_or_url, headers=headers))
|
||||
return
|
||||
|
||||
# Start a client connected to the given command, and expose as an SSE server
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
"""Create a local server that proxies requests to a remote server over SSE."""
|
||||
|
||||
from typing import Any
|
||||
|
||||
from mcp.client.session import ClientSession
|
||||
from mcp.client.sse import sse_client
|
||||
from mcp.server.stdio import stdio_server
|
||||
@@ -7,18 +9,14 @@ from mcp.server.stdio import stdio_server
|
||||
from .proxy_server import create_proxy_server
|
||||
|
||||
|
||||
async def run_sse_client(url: str, api_access_token: str | None = None) -> None:
|
||||
async def run_sse_client(url: str, headers: dict[str, Any] | None = None) -> None:
|
||||
"""Run the SSE client.
|
||||
|
||||
Args:
|
||||
url: The URL to connect to.
|
||||
api_access_token: The API access token to use for authentication.
|
||||
headers: Headers for connecting to MCP server.
|
||||
|
||||
"""
|
||||
headers = {}
|
||||
if api_access_token is not None:
|
||||
headers["Authorization"] = f"Bearer {api_access_token}"
|
||||
|
||||
async with sse_client(url=url, headers=headers) as streams, ClientSession(*streams) as session:
|
||||
app = await create_proxy_server(session)
|
||||
async with stdio_server() as (read_stream, write_stream):
|
||||
|
||||
Reference in New Issue
Block a user