Skip to content
Open
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
4 changes: 2 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ WEBEX_API_BASE_URL=https://webexapis.com/v1
# User Information (for reference)
WEBEX_USER_EMAIL=your-email@company.com

# Optional: Server Mode (defaults to STDIO)
# Optional: Transport mode (defaults to stdio)
# Set to 'http' for HTTP mode, 'sse' for SSE mode, or leave blank for STDIO
MCP_MODE=
TRANSPORT=

# Optional: Port for HTTP/SSE mode (defaults to 3001)
# Only used when running with --http or --sse flag
Expand Down
4 changes: 1 addition & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ COPY --chown=mcp:nodejs . .

# Set environment variables
ENV NODE_ENV=production
# Set transport mode to HTTP for Smithery deployment
ENV TRANSPORT=http

# Expose port for HTTP mode (configurable via PORT env var)
EXPOSE $PORT
Expand All @@ -37,5 +35,5 @@ USER mcp
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD node -e "console.log('Health check passed')" || exit 1

# Start the server (transport mode controlled by TRANSPORT env var)
# Start the server (transport mode controlled by env/CLI; default is STDIO)
CMD ["node", "mcpServer.js"]
25 changes: 16 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,8 @@ Tools are organized by functionality:
1. **Build and run:**
```bash
docker build -t webex-mcp-server .
docker run -i --rm --env-file .env webex-mcp-server
# STDIO transport (for Codex/Claude Desktop)
docker run -i --rm --env-file .env -e TRANSPORT=stdio webex-mcp-server
```

2. **Using docker-compose:**
Expand All @@ -132,7 +133,13 @@ Tools are organized by functionality:
| `WEBEX_API_BASE_URL` | No | Webex API base URL | `https://webexapis.com/v1` |
| `WEBEX_USER_EMAIL` | No | Your Webex email (for reference) | - |
| `PORT` | No | Port for HTTP mode | `3001` |
| `MCP_MODE` | No | Transport mode (`stdio` or `http`) | `stdio` |
| `TRANSPORT` | No | Transport mode (`stdio`, `http`, or `sse`) | `stdio` |

Transport precedence in `mcpServer.js` is:
1. CLI args (`--http`, `--sse`, `--stdio`, or bare values)
2. `TRANSPORT`

Legacy env vars `MCP_MODE` and `MODE` are deprecated and ignored.

### Getting a Webex API Token

Expand Down Expand Up @@ -162,6 +169,8 @@ Add to your Claude Desktop configuration:
"WEBEX_USER_EMAIL",
"-e",
"WEBEX_API_BASE_URL",
"-e",
"TRANSPORT=stdio",
"webex-mcp-server"
],
"env": {
Expand Down Expand Up @@ -196,7 +205,7 @@ The server supports MCP 2025-06-18 protocol with StreamableHTTP transport, inclu

For STDIO mode:
```bash
docker run -i --rm --env-file .env webex-mcp-server
docker run -i --rm --env-file .env -e TRANSPORT=stdio webex-mcp-server
```

For HTTP mode:
Expand Down Expand Up @@ -268,14 +277,12 @@ docker run -p 3001:3001 --rm --env-file .env webex-mcp-server --http

## Transport Modes

### STDIO Mode (Default)
The default transport mode for MCP clients like Claude Desktop:
### STDIO Mode
For MCP clients like Claude Desktop/Codex, use STDIO transport:

```bash
# Start in STDIO mode
node mcpServer.js
# or
npm start
```

### HTTP Mode (StreamableHTTP)
Expand All @@ -296,7 +303,7 @@ node mcpServer.js --http
- **Protocol**: MCP 2025-06-18 with StreamableHTTP transport

**Environment Variables:**
- `MCP_MODE=http` - Force HTTP mode
- `TRANSPORT=http` - Force HTTP mode
- `PORT=3001` - Custom port (default: 3001)

### Smithery Integration
Expand Down Expand Up @@ -404,4 +411,4 @@ MIT License - see LICENSE file for details

- **Issues**: Report bugs and feature requests via GitHub issues
- **Documentation**: See SETUP-COMPLETE.md for detailed setup instructions
- **Community**: Join discussions in the MCP community channels
- **Community**: Join discussions in the MCP community channels
6 changes: 3 additions & 3 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ services:
# Server Configuration
- NODE_ENV=production
- PORT=${PORT:-3001}
- MCP_MODE=${MCP_MODE:-}
- TRANSPORT=${TRANSPORT:-stdio}
ports:
# Only needed for HTTP mode - uses PORT env var with fallback to 3001
- "${PORT:-3001}:${PORT:-3001}"
Expand All @@ -19,7 +19,7 @@ services:
tty: true
restart: unless-stopped

# Example for HTTP mode using MCP_MODE
# Example for HTTP mode using TRANSPORT
webex-mcp-server-http:
build: .
container_name: webex-mcp-server-http
Expand All @@ -29,7 +29,7 @@ services:
- WEBEX_USER_EMAIL=${WEBEX_USER_EMAIL}
- NODE_ENV=production
- PORT=${PORT:-3001}
- MCP_MODE=http
- TRANSPORT=http
ports:
- "${PORT:-3001}:${PORT:-3001}"
restart: unless-stopped
Expand Down
35 changes: 35 additions & 0 deletions lib/transport-mode.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
const SUPPORTED_MODES = new Set(["stdio", "http", "sse"]);

function normalizeMode(value) {
if (typeof value !== "string") {
return null;
}

const normalized = value.trim().toLowerCase().replace(/^--/, "");
if (!normalized) {
return null;
}

return SUPPORTED_MODES.has(normalized) ? normalized : null;
}

/**
* Resolve transport mode with deterministic precedence:
* CLI > TRANSPORT > stdio(default)
*/
export function resolveTransportMode(args = [], env = process.env) {
for (const arg of args) {
const mode = normalizeMode(arg);
if (mode) {
return { mode, source: "cli" };
}
}

const transportMode = normalizeMode(env.TRANSPORT);

if (transportMode) {
return { mode: transportMode, source: "TRANSPORT" };
}

return { mode: "stdio", source: "default" };
}
20 changes: 13 additions & 7 deletions mcpServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
import { isInitializeRequest } from "@modelcontextprotocol/sdk/types.js";
import { discoverTools } from "./lib/tools.js";
import { resolveTransportMode } from "./lib/transport-mode.js";
import { randomUUID } from "crypto";
import { z } from "zod";

Expand Down Expand Up @@ -141,19 +142,24 @@ async function createMcpServer() {
}

async function run() {
// Transport mode detection following MCP 2025-06-18 patterns
// Transport mode detection with deterministic precedence
const args = process.argv.slice(2);
const modeFromEnv = (process.env.TRANSPORT || process.env.MCP_MODE || process.env.MODE)?.toLowerCase();
const isHTTP = args.includes('--http') || modeFromEnv === 'http';
const isSSE = args.includes('--sse') || modeFromEnv === 'sse';
const { mode: resolvedMode, source } = resolveTransportMode(args, process.env);

const mode = isHTTP ? 'HTTP' : 'STDIO';
console.error(`[MCP Server] Mode: ${mode}`);
if (typeof process.env.MCP_MODE === "string" || typeof process.env.MODE === "string") {
console.error("[MCP Server] Deprecated env vars detected (MCP_MODE/MODE). They are ignored. Use TRANSPORT instead.");
}

const isSSE = resolvedMode === 'sse';
const isHTTP = resolvedMode === 'http' || isSSE;

const mode = isSSE ? 'SSE (deprecated)' : (isHTTP ? 'HTTP' : 'STDIO');
console.error(`[MCP Server] Mode: ${mode} (source: ${source})`);

// Deprecation warning for SSE
if (isSSE) {
console.error('WARNING: SSE mode is deprecated in MCP 2025-06-18. Use StreamableHTTP instead.');
console.error('Use --http flag or MCP_MODE=http for HTTP mode.');
console.error('Use --http or TRANSPORT=http for HTTP mode.');
}

if (isHTTP) {
Expand Down
41 changes: 41 additions & 0 deletions tests/transport-mode.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { describe, it } from "node:test";
import assert from "node:assert";
import { resolveTransportMode } from "../lib/transport-mode.js";

describe("Transport mode resolution", () => {
it("defaults to stdio when no mode is configured", () => {
const result = resolveTransportMode([], {});
assert.strictEqual(result.mode, "stdio");
assert.strictEqual(result.source, "default");
});

it("gives CLI args highest precedence", () => {
const result = resolveTransportMode(["--http"], {
TRANSPORT: "stdio",
});

assert.strictEqual(result.mode, "http");
assert.strictEqual(result.source, "cli");
});

it("uses TRANSPORT when set", () => {
const result = resolveTransportMode([], {
TRANSPORT: "http",
});

assert.strictEqual(result.mode, "http");
assert.strictEqual(result.source, "TRANSPORT");
});

it("ignores legacy MCP_MODE and defaults to stdio when TRANSPORT is absent", () => {
const result = resolveTransportMode([], { MCP_MODE: "http" });
assert.strictEqual(result.mode, "stdio");
assert.strictEqual(result.source, "default");
});

it("normalizes values and accepts bare CLI values", () => {
const result = resolveTransportMode(["STDIO"], { TRANSPORT: "http" });
assert.strictEqual(result.mode, "stdio");
assert.strictEqual(result.source, "cli");
});
});
5 changes: 3 additions & 2 deletions tools-manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -118,13 +118,14 @@
"WEBEX_API_BASE_URL",
"WEBEX_USER_EMAIL",
"PORT",
"MCP_MODE",
"TRANSPORT",
"ENABLED_TOOLS"
]
},
"transport_modes": [
"stdio",
"http"
"http",
"sse"
],
"features": {
"tool_filtering": true,
Expand Down