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
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Changelog

## [Unreleased]

### Breaking Changes

- **MCP proxy command**: Removed the temporary `allagents mcp proxy-stdio` alias. Use `allagents mcp proxy <serverUrl>` instead.

**Migration**: Re-run `allagents mcp update` or `allagents update` after upgrading so synced client configs are regenerated with `mcp proxy`.

## [1.0.0] - 2026-03-13

### Breaking Changes
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ clients:
| `allagents skill add <name>` | Add a skill from a repo (plural `skills` alias supported) |
| `allagents skill list` | List skills and status |
| `allagents mcp add <name> <commandOrUrl>` | Add an MCP server and sync to clients |
| `allagents mcp proxy <serverUrl>` | Bridge a remote HTTP MCP server to local stdio |
| `allagents mcp list` | List workspace MCP servers |
| `allagents workspace status` | Show workspace state |
| `allagents self update` | Update AllAgents CLI |
Expand Down
22 changes: 11 additions & 11 deletions docs/.astro/content-modules.mjs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@

export default new Map([
["src/content/docs/index.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Findex.mdx&astroContentModuleFlag=true")],
["src/content/docs/getting-started/installation.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fgetting-started%2Finstallation.mdx&astroContentModuleFlag=true")],
["src/content/docs/getting-started/quick-start.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fgetting-started%2Fquick-start.mdx&astroContentModuleFlag=true")],
["src/content/docs/guides/marketplaces.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fguides%2Fmarketplaces.mdx&astroContentModuleFlag=true")],
["src/content/docs/docs.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs.mdx&astroContentModuleFlag=true")],
["src/content/docs/guides/agent-portability.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fguides%2Fagent-portability.mdx&astroContentModuleFlag=true")],
["src/content/docs/guides/workspaces.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fguides%2Fworkspaces.mdx&astroContentModuleFlag=true")],
["src/content/docs/guides/plugins.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fguides%2Fplugins.mdx&astroContentModuleFlag=true")],
["src/content/docs/reference/clients.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Freference%2Fclients.mdx&astroContentModuleFlag=true")],
["src/content/docs/reference/cli.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Freference%2Fcli.mdx&astroContentModuleFlag=true")],
["src/content/docs/reference/configuration.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Freference%2Fconfiguration.mdx&astroContentModuleFlag=true")]]);
["src/content/docs/docs/index.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Findex.mdx&astroContentModuleFlag=true")],
["src/content/docs/docs/getting-started/installation.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fgetting-started%2Finstallation.mdx&astroContentModuleFlag=true")],
["src/content/docs/docs/getting-started/quick-start.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fgetting-started%2Fquick-start.mdx&astroContentModuleFlag=true")],
["src/content/docs/docs/guides/marketplaces.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fguides%2Fmarketplaces.mdx&astroContentModuleFlag=true")],
["src/content/docs/docs/guides/mcp-proxy.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fguides%2Fmcp-proxy.mdx&astroContentModuleFlag=true")],
["src/content/docs/docs/guides/plugins.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fguides%2Fplugins.mdx&astroContentModuleFlag=true")],
["src/content/docs/docs/guides/agent-portability.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fguides%2Fagent-portability.mdx&astroContentModuleFlag=true")],
["src/content/docs/docs/guides/workspaces.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fguides%2Fworkspaces.mdx&astroContentModuleFlag=true")],
["src/content/docs/docs/reference/cli.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Freference%2Fcli.mdx&astroContentModuleFlag=true")],
["src/content/docs/docs/reference/clients.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Freference%2Fclients.mdx&astroContentModuleFlag=true")],
["src/content/docs/docs/reference/configuration.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Freference%2Fconfiguration.mdx&astroContentModuleFlag=true")]]);

2 changes: 2 additions & 0 deletions docs/src/content/docs/docs/guides/mcp-proxy.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ description: Transparently proxy HTTP MCP servers through mcp-remote for clients

Some MCP servers use HTTP transport with OAuth authentication, but not every AI client supports HTTP natively. The MCP proxy feature rewrites HTTP server configs to use [`mcp-remote`](https://www.npmjs.com/package/mcp-remote) as a local stdio bridge, so all clients connect through an already-authenticated proxy.

When AllAgents generates a proxied client config, it does so through the public `allagents mcp proxy <serverUrl>` helper command.

## Quick Start

The fastest way to try MCP proxy is to scaffold the ready-made
Expand Down
16 changes: 16 additions & 0 deletions docs/src/content/docs/docs/reference/cli.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ After enabling, the skill is removed from `disabledSkills` and sync is run to re

```bash
allagents mcp add <name> <commandOrUrl> [options]
allagents mcp proxy <serverUrl> [--header KEY=VALUE...]
allagents mcp remove <name>
allagents mcp list
allagents mcp get <name>
Expand Down Expand Up @@ -229,6 +230,21 @@ allagents mcp add gh-server npx --arg=-y --arg=@modelcontextprotocol/server-gith
allagents mcp add deepwiki https://new.example.com --force
```

### mcp proxy

Expose a remote HTTP MCP server locally over stdio. This is the helper command AllAgents writes into proxied client configs when `mcpProxy` rewrites an HTTP server for clients that only support stdio transport.

| Flag | Description |
|------|-------------|
| `--header <KEY=VALUE>` | HTTP header forwarded to the upstream MCP server (repeatable) |

```bash
allagents mcp proxy https://mcp.deepwiki.com/mcp
allagents mcp proxy https://mcp.internal.corp --header Authorization=Bearer-token
```

`proxy` is the only supported public command shown in help and generated configs.

### mcp remove

Remove a server from `workspace.yaml` and unsync it from all clients. Only servers AllAgents added are removed; pre-existing user-managed servers in client MCP configs are preserved.
Expand Down
12 changes: 6 additions & 6 deletions src/cli/commands/mcp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -334,12 +334,12 @@ const mcpRemoveCmd = command({
});

// =============================================================================
// mcp proxy-stdio (internal)
// mcp proxy
// =============================================================================

const mcpProxyStdioCmd = command({
name: 'proxy-stdio',
description: 'Internal: expose a remote HTTP MCP server as local stdio',
const mcpProxyCmd = command({
name: 'proxy',
description: 'Expose a remote HTTP MCP server locally over stdio',
args: {
serverUrl: positional({ type: string, displayName: 'serverUrl' }),
header: multioption({
Expand All @@ -351,7 +351,7 @@ const mcpProxyStdioCmd = command({
handler: async ({ serverUrl, header }) => {
const headerResult = parseKeyValuePairs(header, '--header');
if ('error' in headerResult) {
exitWithError('mcp proxy-stdio', headerResult.error);
exitWithError('mcp proxy', headerResult.error);
}
await runHttpMcpStdioProxy(serverUrl, headerResult.values);
},
Expand Down Expand Up @@ -506,7 +506,7 @@ export const mcpCmd = conciseSubcommands({
description: 'Manage MCP servers for AI clients',
cmds: {
add: mcpAddCmd,
'proxy-stdio': mcpProxyStdioCmd,
proxy: mcpProxyCmd,
remove: mcpRemoveCmd,
list: mcpListCmd,
get: mcpGetCmd,
Expand Down
2 changes: 1 addition & 1 deletion src/core/mcp-proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ function toProxiedConfig(
url: string,
headers?: Record<string, string>,
): Record<string, unknown> {
const args = ['mcp', 'proxy-stdio', url];
const args = ['mcp', 'proxy', url];
if (headers) {
for (const [key, value] of Object.entries(headers)) {
args.push('--header', `${key}=${value}`);
Expand Down
4 changes: 2 additions & 2 deletions tests/e2e/mcp-add-proxy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,12 +95,12 @@ clients:
expect(claudeConfig.mcpServers.deepwiki.command).toBe('allagents');
expect(claudeConfig.mcpServers.deepwiki.args).toEqual([
'mcp',
'proxy-stdio',
'proxy',
'https://mcp.deepwiki.com/mcp',
]);

const codexConfig = readFileSync(join(workspaceDir, '.codex', 'config.toml'), 'utf-8');
expect(codexConfig).toContain('proxy-stdio');
expect(codexConfig).toContain('proxy');
expect(codexConfig).toContain('https://mcp.deepwiki.com/mcp');

const vscodeConfig = JSON.parse(readFileSync(join(workspaceDir, '.vscode', 'mcp.json'), 'utf-8'));
Expand Down
35 changes: 35 additions & 0 deletions tests/e2e/mcp-proxy-command.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { describe, expect, test } from 'bun:test';
import { join } from 'node:path';

function runCli(args: string[]) {
const cliEntry = join(import.meta.dir, '..', '..', 'src', 'cli', 'index.ts');
const proc = Bun.spawnSync(['bun', 'run', cliEntry, ...args], {
cwd: process.cwd(),
env: process.env,
stderr: 'pipe',
stdout: 'pipe',
});

return {
exitCode: proc.exitCode,
stdout: new TextDecoder().decode(proc.stdout),
stderr: new TextDecoder().decode(proc.stderr),
};
}

describe('mcp proxy command help', () => {
test('lists proxy as the canonical subcommand', () => {
const result = runCli(['mcp', '--help']);

expect(result.exitCode).toBe(0);
expect(result.stdout).toContain('- proxy - Expose a remote HTTP MCP server locally over stdio');
expect(result.stdout).not.toContain('- proxy-stdio -');
});

test('rejects proxy-stdio after the rename', () => {
const result = runCli(['mcp', 'proxy-stdio']);

expect(result.exitCode).toBe(1);
expect(result.stderr).toContain('Not a valid subcommand name');
});
});
6 changes: 3 additions & 3 deletions tests/unit/core/mcp-proxy-cli.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ describe('CLI args with proxy transform', () => {
const args = buildClaudeMcpAddArgs('deepwiki', proxiedConfig);
expect(args).toEqual([
'mcp', 'add', '--scope', 'user', 'deepwiki', '--', 'allagents',
'mcp', 'proxy-stdio', 'https://mcp.deepwiki.com/mcp',
'mcp', 'proxy', 'https://mcp.deepwiki.com/mcp',
]);
});

Expand All @@ -35,7 +35,7 @@ describe('CLI args with proxy transform', () => {
const args = buildCodexMcpAddArgs('deepwiki', proxiedConfig);
expect(args).toEqual([
'mcp', 'add', 'deepwiki', '--', 'allagents',
'mcp', 'proxy-stdio', 'https://mcp.deepwiki.com/mcp',
'mcp', 'proxy', 'https://mcp.deepwiki.com/mcp',
]);
});
});
Expand All @@ -58,7 +58,7 @@ describe('syncVscodeMcpConfig with serverOverrides', () => {
const proxiedServers = new Map<string, unknown>([
['deepwiki', {
command: 'allagents',
args: ['mcp', 'proxy-stdio', 'https://mcp.deepwiki.com/mcp'],
args: ['mcp', 'proxy', 'https://mcp.deepwiki.com/mcp'],
}],
]);

Expand Down
4 changes: 2 additions & 2 deletions tests/unit/core/mcp-proxy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ describe('applyMcpProxy', () => {
const result = applyMcpProxy(servers, 'claude', config);
expect(result.get('deepwiki')).toEqual({
command: 'allagents',
args: ['mcp', 'proxy-stdio', 'https://mcp.deepwiki.com/mcp'],
args: ['mcp', 'proxy', 'https://mcp.deepwiki.com/mcp'],
});
});

Expand Down Expand Up @@ -124,7 +124,7 @@ describe('applyMcpProxy', () => {
command: 'allagents',
args: [
'mcp',
'proxy-stdio',
'proxy',
'https://api.example.com/mcp',
'--header',
'Authorization=Bearer token',
Expand Down