Connect your MCP client¶
Streamable HTTP is the default, at http://127.0.0.1:8000/mcp. Generate a bearer
credential once and provide the same value to the server and authorized clients
through protected environment/configuration. For example, in a private shell:
export ETRADE_MCP_HTTP_BEARER_TOKEN="$(python3 -c 'import secrets; print(secrets.token_urlsafe(32))')"
etrade-mcp serve --transport streamable-http --environment sandbox --profile default
Every HTTP request requires Authorization: Bearer <configured token>. This is
static access control, separate from broker OAuth; the server does not provide an
OAuth authorization server or interactive MCP login. Only loopback IP literals
are accepted for binding. SDK Host/Origin checks restrict requests to the bound
address and localhost at the configured port. Non-browser clients may omit Origin;
wildcard CORS and reverse-proxy deployment are not supported. Disable client debug
logging that would record authorization headers.
A host that launches its server can use stdio instead:
# Remove inherited HTTP-only configuration before selecting stdio.
unset ETRADE_MCP_HTTP_BEARER_TOKEN ETRADE_MCP_HOST ETRADE_MCP_PORT
etrade-mcp serve --transport stdio --environment sandbox --profile default
Configure an MCP client's stdio command as etrade-mcp with arguments
serve --transport stdio --environment sandbox --profile default, forwarding
broker credentials through its protected subprocess environment. For a local
agent harness or another HTTP-capable MCP client, configure the URL above and a
bearer credential sourced from protected configuration. No secrets belong in
model prompts or command-line arguments. The server uses the same tools and
permissions for either transport. Stdio reserves stdout for protocol traffic;
diagnostics go to stderr. HTTP disables request access logging.
The official mcp>=2.3,<3 SDK supplies async tools, structured schemas, both
transports, and compatibility with earlier protocol revisions without an extra
framework. The lockfile resolves SDK 2.3.0 and client 1.1.0. Tests exercise modern
SDK mode (protocol 2026-07-28) and legacy mode (2025-11-25);
installed-artifact checks exercise both transports.
This is protocol validation, not a claim of manual validation in every MCP host.
Client examples below use environment-sourced credentials and matching HTTP/stdio scopes. See local service management for optional Linux user-service setup. No broker secrets belong in client HTTP headers or prompts.
Client examples¶
These examples configure the existing tools; they do not provide a trading strategy or a human-approval controller. Install the package and complete broker OAuth as described in the installation guide first. Use the same sandbox/production environment and profile for login and serving.
Choose HTTP or stdio for a given server entry. Start a fresh client session after
changing configuration. etrade-mcp must be on the launching user's PATH; replace
it with an absolute executable path if needed. Desktop clients may not inherit
terminal environment variables. Supply secrets through the client's protected
launch environment, never in a prompt or committed configuration.
HTTP: start the server separately¶
Provide ETRADE_CONSUMER_KEY, ETRADE_CONSUMER_SECRET, and
ETRADE_MCP_HTTP_BEARER_TOKEN through protected process configuration. Keep one
stable bearer value for the server and authorized clients; generating a different
value in each shell will fail authentication. This example exposes only local
status and market reads, with both mutation capabilities explicitly disabled:
etrade-mcp serve --transport streamable-http --environment sandbox --profile default \
--no-enable-order-execution --no-enable-alert-deletion \
--tool-allowlist server_status,market_get_quote,market_get_quotes,market_lookup_product,market_get_option_expirations,market_get_option_chain
The endpoint is http://127.0.0.1:8000/mcp. HTTP clients need its bearer token;
they do not need broker credentials. The server owns broker OAuth. No MCP OAuth
login is required or provided. Clients must reach the same machine/network
namespace's loopback endpoint; 127.0.0.1 inside a separate container or remote
host is not the host endpoint. Non-loopback binding and hosted proxy deployment
are outside this server's supported configuration.
Codex¶
Add this table to ~/.codex/config.toml. It references the token variable rather
than storing its value:
[mcp_servers.etrade]
url = "http://127.0.0.1:8000/mcp"
bearer_token_env_var = "ETRADE_MCP_HTTP_BEARER_TOKEN"
Alternatively, let Codex launch the same market-only scope through stdio:
[mcp_servers.etrade]
command = "etrade-mcp"
args = ["serve", "--transport", "stdio", "--environment", "sandbox", "--profile", "default", "--no-enable-order-execution", "--no-enable-alert-deletion", "--tool-allowlist", "server_status,market_get_quote,market_get_quotes,market_lookup_product,market_get_option_expirations,market_get_option_chain"]
env_vars = ["ETRADE_CONSUMER_KEY", "ETRADE_CONSUMER_SECRET"]
Use one table for etrade, not both. Codex documents these settings in its
official MCP configuration guide.
Claude Code¶
For a project-scoped HTTP connection, put this in .mcp.json; Claude Code expands
the token reference from its launch environment:
{
"mcpServers": {
"etrade": {
"type": "http",
"url": "http://127.0.0.1:8000/mcp",
"headers": {
"Authorization": "Bearer ${ETRADE_MCP_HTTP_BEARER_TOKEN}"
}
}
}
}
For stdio, replace that entry with:
{
"mcpServers": {
"etrade": {
"type": "stdio",
"command": "etrade-mcp",
"args": [
"serve", "--transport", "stdio", "--environment", "sandbox", "--profile", "default",
"--no-enable-order-execution", "--no-enable-alert-deletion",
"--tool-allowlist", "server_status,market_get_quote,market_get_quotes,market_lookup_product,market_get_option_expirations,market_get_option_chain"
],
"env": {
"ETRADE_CONSUMER_KEY": "${ETRADE_CONSUMER_KEY}",
"ETRADE_CONSUMER_SECRET": "${ETRADE_CONSUMER_SECRET}"
}
}
}
}
Before launching a stdio client, remove inherited HTTP-only settings:
unset ETRADE_MCP_HTTP_BEARER_TOKEN ETRADE_MCP_HOST ETRADE_MCP_PORT
Stdio rejects these settings rather than silently ignoring them. Use a separate
shell/session if another HTTP connection needs the bearer variable. In Claude
Code, /mcp shows connection status and available tools. Configuration and
variable expansion follow the official MCP guide.
Generic Python MCP client¶
In an environment containing the package dependencies, this HTTP example lists tools and invokes status only. It does not send a brokerage request:
import asyncio
import os
from contextlib import asynccontextmanager
import httpx2
from mcp import Client
from mcp.client.streamable_http import streamable_http_client
@asynccontextmanager
async def connection(http):
async with streamable_http_client("http://127.0.0.1:8000/mcp", http_client=http) as streams:
yield streams[0], streams[1]
async def main():
async with httpx2.AsyncClient(
headers={"Authorization": "Bearer " + os.environ["ETRADE_MCP_HTTP_BEARER_TOKEN"]},
trust_env=False,
) as http:
async with Client(connection(http)) as client:
print([tool.name for tool in (await client.list_tools()).tools])
result = await client.call_tool("server_status", {})
if result.is_error:
raise RuntimeError("Status failed; inspect structured error details privately.")
print(result.structured_content)
asyncio.run(main())
For equivalent stdio scope, replace the HTTP connection with:
import os
from mcp import Client
from mcp.client.stdio import StdioServerParameters
parameters = StdioServerParameters(
command="etrade-mcp",
args=[
"serve",
"--transport",
"stdio",
"--environment",
"sandbox",
"--profile",
"default",
"--no-enable-order-execution",
"--no-enable-alert-deletion",
"--tool-allowlist",
"server_status,market_get_quote,market_get_quotes,market_lookup_product,market_get_option_expirations,market_get_option_chain",
],
env={
"ETRADE_CONSUMER_KEY": os.environ["ETRADE_CONSUMER_KEY"],
"ETRADE_CONSUMER_SECRET": os.environ["ETRADE_CONSUMER_SECRET"],
},
)
# Inside an async function:
# async with Client(parameters) as client:
# result = await client.call_tool("server_status", {})
Do not assume every client's JSON configuration expands ${VARIABLE}. That
syntax above is specific to Claude Code; Codex has named environment-reference
fields, and Python reads os.environ. HTTP headers must contain the resolved
bearer value. Verify each client adapter's behavior before supplying secrets.
These configurations are checked against official client documentation and the server's protocol tests; they are not a claim that every client/version/model has been manually validated. See the README for synthetic order examples and the execution boundary.