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
9 changes: 1 addition & 8 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ on:
branches: [main]

env:
BUN_VERSION: "1.3.9"
BUN_VERSION: "1.3.13"

jobs:
check:
Expand All @@ -31,13 +31,6 @@ jobs:
- name: Build
run: bun build --compile src/cli/index.ts --outfile dist/mcp2cli

- name: Upload binary
uses: actions/upload-artifact@v4
with:
name: mcp2cli-binary
path: dist/mcp2cli
retention-days: 7

deploy:
needs: check
runs-on: [self-hosted, rodaddy]
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -630,8 +630,8 @@ In addition to the [base environment variables](#environment-variables), network
|----------|---------|-------------|
| `MCP2CLI_LISTEN_HOST` | (unset) | Bind address for TCP mode. Setting this enables TCP instead of Unix socket. Use `0.0.0.0` to listen on all interfaces |
| `MCP2CLI_LISTEN_PORT` | `9500` | TCP port when `MCP2CLI_LISTEN_HOST` is set |
| `MCP2CLI_AUTH_TOKEN` | (unset) | Bearer token for TCP authentication. Required for production deployments |
| `MCP2CLI_REMOTE_URL` | (unset) | URL of remote mcp2cli daemon (e.g. `http://mcp-server:9500`). Enables remote client mode |
| `MCP2CLI_AUTH_TOKEN` | (unset) | Bearer token for TCP authentication. Required for production deployments. Alias: `MCP_TOKEN` |
| `MCP2CLI_REMOTE_URL` | (unset) | URL of remote mcp2cli daemon (e.g. `https://mcp2cli.rodaddy.live`). Enables remote client mode. Alias: `MCP_HOST` |
| `MCP2CLI_CONFIG` | `~/.config/mcp2cli/services.json` | Path to service definitions (useful for server-side config in `/etc/mcp2cli/`) |
| `MCP2CLI_TOKENS_FILE` | `~/.config/mcp2cli/tokens.json` | Path to multi-user token/RBAC config |
| `MCP2CLI_CREDENTIALS_FILE` | `~/.config/mcp2cli/credentials.json` | Path to per-identity credential mappings |
Expand Down
3 changes: 2 additions & 1 deletion src/cli/commands/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
*/
import { clearCache, listCachedServices, readCacheRaw, detectDrift, resolveTtlMs, writeCache, mapToolsToCachedSchemas } from "../../cache/index.ts";
import { loadConfig } from "../../config/index.ts";
import { connectToService, connectToHttpService } from "../../connection/index.ts";
import { connectToService } from "../../connection/index.ts";
import { connectToHttpService } from "../../connection/http-transport.ts";
import { connectToWebSocketService } from "../../connection/websocket-transport.ts";
import { listAllTools } from "../../schema/introspect.ts";
import { EXIT_CODES } from "../../types/index.ts";
Expand Down
3 changes: 2 additions & 1 deletion src/cli/commands/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
* Supports --fresh flag to bypass cache for one call.
*/
import { loadConfig } from "../../config/index.ts";
import { connectToService, connectToHttpService } from "../../connection/index.ts";
import { connectToService } from "../../connection/index.ts";
import { connectToHttpService } from "../../connection/http-transport.ts";
import { connectToWebSocketService } from "../../connection/websocket-transport.ts";
import { getSchemaViaDaemon } from "../../process/index.ts";
import {
Expand Down
3 changes: 2 additions & 1 deletion src/cli/commands/service-help.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
* Routes through daemon by default. Set MCP2CLI_NO_DAEMON=1 for direct connection.
*/
import { loadConfig } from "../../config/index.ts";
import { connectToService, connectToHttpService } from "../../connection/index.ts";
import { connectToService } from "../../connection/index.ts";
import { connectToHttpService } from "../../connection/http-transport.ts";
import { connectToWebSocketService } from "../../connection/websocket-transport.ts";
import { listToolsViaDaemon } from "../../process/index.ts";
import { listToolsCached, formatToolListing } from "../../schema/index.ts";
Expand Down
3 changes: 2 additions & 1 deletion src/cli/commands/tool-call.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import {
} from "../../invocation/index.ts";
import { validationResultToCliError } from "../../validation/pipelines.ts";
import { loadConfig } from "../../config/index.ts";
import { connectToService, connectToHttpService } from "../../connection/index.ts";
import { connectToService } from "../../connection/index.ts";
import { connectToHttpService } from "../../connection/http-transport.ts";
import { connectToWebSocketService } from "../../connection/websocket-transport.ts";
import { callViaDaemon, getSchemaViaDaemon } from "../../process/index.ts";
import { getToolSchemaCached, resolveToolNameCached } from "../../schema/cached.ts";
Expand Down
1 change: 0 additions & 1 deletion src/connection/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,4 @@ export { ConnectionError } from "./errors.ts";
export { isJsonRpcLine } from "./filter.ts";
export { McpTransport } from "./transport.ts";
export { connectToService } from "./client.ts";
export { connectToHttpService } from "./http-transport.ts";
export type { ConnectionOptions, McpConnection } from "./types.ts";
2 changes: 1 addition & 1 deletion src/daemon/auth-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ export class TokenAuthProvider implements AuthProvider {
}

// Fall back to legacy single-token env var
const envToken = process.env.MCP2CLI_AUTH_TOKEN;
const envToken = process.env.MCP2CLI_AUTH_TOKEN ?? process.env.MCP_TOKEN;
if (envToken) {
log.info("using_legacy_token", { source: "MCP2CLI_AUTH_TOKEN" });
return TokenAuthProvider.fromEnvToken(envToken);
Expand Down
2 changes: 1 addition & 1 deletion src/daemon/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const AUTH_EXEMPT_PATHS = new Set(["/health", "/metrics", "/", "/api/auth/login"
* @deprecated Use TokenAuthProvider.load() for multi-user support.
*/
export function loadAuthToken(): string | undefined {
return process.env.MCP2CLI_AUTH_TOKEN || undefined;
return process.env.MCP2CLI_AUTH_TOKEN || process.env.MCP_TOKEN || undefined;
}

/**
Expand Down
4 changes: 2 additions & 2 deletions src/daemon/paths.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ export function getDaemonListenConfig(): DaemonListenConfig {
* Returns null if MCP2CLI_REMOTE_URL is not set.
*/
export function getRemoteConfig(): { url: string; token: string | undefined } | null {
const url = process.env.MCP2CLI_REMOTE_URL;
const url = process.env.MCP2CLI_REMOTE_URL ?? process.env.MCP_HOST;
if (!url) return null;
return { url, token: process.env.MCP2CLI_AUTH_TOKEN };
return { url, token: process.env.MCP2CLI_AUTH_TOKEN ?? process.env.MCP_TOKEN };
}

export function getDaemonPaths(overrides?: {
Expand Down
3 changes: 2 additions & 1 deletion src/daemon/pool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
* MEM-04: Bounded pool size (default 50, configurable via MCP2CLI_POOL_MAX).
* MEM-05: Health check before reuse -- stale connections are replaced.
*/
import { connectToService, connectToHttpService } from "../connection/index.ts";
import { connectToService } from "../connection/index.ts";
import { connectToHttpService } from "../connection/http-transport.ts";
import { connectToWebSocketService } from "../connection/websocket-transport.ts";
import { ConnectionError } from "../connection/errors.ts";
import type { McpConnection } from "../connection/types.ts";
Expand Down
4 changes: 2 additions & 2 deletions src/process/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ async function getLocalToken(): Promise<string | undefined> {

// Only use MCP2CLI_AUTH_TOKEN for local auth when no remote URL is set,
// otherwise the token belongs to the remote daemon
const envToken = process.env.MCP2CLI_AUTH_TOKEN;
if (envToken && !process.env.MCP2CLI_REMOTE_URL) {
const envToken = process.env.MCP2CLI_AUTH_TOKEN ?? process.env.MCP_TOKEN;
if (envToken && !process.env.MCP2CLI_REMOTE_URL && !process.env.MCP_HOST) {
cachedLocalToken = envToken;
return cachedLocalToken;
}
Expand Down
7 changes: 1 addition & 6 deletions tests/connection/http-transport.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,12 +146,7 @@ describe("ServicesConfig with mixed backends", () => {
});

describe("HTTP transport module imports", () => {
test("connectToHttpService is exported from connection index", async () => {
const mod = await import("../../src/connection/index.ts");
expect(typeof mod.connectToHttpService).toBe("function");
});

test("connectToHttpService function exists in http-transport module", async () => {
test("connectToHttpService is exported from http-transport module", async () => {
const mod = await import("../../src/connection/http-transport.ts");
expect(typeof mod.connectToHttpService).toBe("function");
});
Expand Down
3 changes: 3 additions & 0 deletions tests/daemon/pool.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ const mockConnectToService = mock(async () => {
// Apply the mock to the connection module
mock.module("../../src/connection/index.ts", () => ({
connectToService: mockConnectToService,
}));

mock.module("../../src/connection/http-transport.ts", () => ({
connectToHttpService: mockConnectToService,
}));

Expand Down
5 changes: 4 additions & 1 deletion tests/resilience/pool-fallback.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,13 @@ const mockConnectToHttpService = mock(async () => mockHttpConnection);
const mockConnectToService = mock(async () => mockStdioConnection);

mock.module("../../src/connection/index.ts", () => ({
connectToHttpService: mockConnectToHttpService,
connectToService: mockConnectToService,
}));

mock.module("../../src/connection/http-transport.ts", () => ({
connectToHttpService: mockConnectToHttpService,
}));

// Import pool AFTER mocking
const { ConnectionPool } = await import("../../src/daemon/pool.ts");

Expand Down
Loading