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
53 changes: 49 additions & 4 deletions packages/agent-sdk/builtin/skills/settings/MCP.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,25 +32,70 @@ The `.mcp.json` file contains a list of MCP server configurations.

### Fields for each server:

- `type`: (Optional) The transport type: `"stdio"`, `"sse"`, or `"http"`. If omitted, Wave infers the type from other fields (URL → `"http"`, command → `"stdio"`). Set explicitly for clarity and to avoid the default behavior.
- `command`: (For stdio) The executable to run (e.g., `npx`, `uvx`, `python`, `node`).
- `args`: (For stdio) An array of command-line arguments for the executable.
- `env`: (Optional) A record of environment variables for the server process.
- `url`: (For SSE) The endpoint URL of a remote MCP server (e.g., `https://example.com/sse`).
- `url`: (For `sse`/`http`) The endpoint URL of a remote MCP server.
- `headers`: (For `sse`/`http`) A record of HTTP headers to send with requests (e.g., `{"Authorization": "Bearer token"}`).

## Remote MCP Servers (SSE)
## Transport Types

Wave also supports connecting to remote MCP servers via SSE (Server-Sent Events).
Wave supports three MCP transport types. When `type` is not specified, Wave uses the following defaults:
- If `url` is provided → defaults to `"http"` (Streamable HTTP)
- If `command` is provided → defaults to `"stdio"`

### stdio

The server is launched as a local subprocess. Use for locally installed MCP servers.

```json
{
"mcpServers": {
"sqlite": {
"type": "stdio",
"command": "uvx",
"args": ["mcp-server-sqlite", "--db-path", "/path/to/db"]
}
}
}
```

### http (Streamable HTTP)

The recommended transport for remote servers. Uses the MCP Streamable HTTP protocol.

```json
{
"mcpServers": {
"remote-server": {
"remote-api": {
"type": "http",
"url": "https://mcp-server.example.com/mcp",
"headers": {
"Authorization": "Bearer your-token"
}
}
}
}
```

### sse (Server-Sent Events)

Legacy transport for remote servers that only support SSE. Use `"http"` for new servers unless the server requires SSE.

```json
{
"mcpServers": {
"legacy-server": {
"type": "sse",
"url": "https://mcp-server.example.com/sse"
}
}
}
```

> **Note**: When `type` is not specified, URL-based servers default to `"http"` with no SSE fallback. If you need SSE, set `type: "sse"` explicitly.

## Using MCP Tools

Once configured, Wave will automatically connect to the MCP servers when it starts. Tools provided by these servers will be available to the agent with a prefix:
Expand Down
124 changes: 0 additions & 124 deletions packages/agent-sdk/examples/constructor-mcp-deferred.ts

This file was deleted.

1 change: 1 addition & 0 deletions packages/agent-sdk/examples/tavily-mcp-example.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ async function main() {
const mcpConfig = {
mcpServers: {
tavily: {
type: "http",
url: "https://mcp.tavily.com/mcp/",
// Authenticate using the Authorization header with ${TAVILY_API_KEY} env var expansion
headers: {
Expand Down
2 changes: 1 addition & 1 deletion packages/agent-sdk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
"prepublishOnly": "pnpm run build"
},
"dependencies": {
"@modelcontextprotocol/sdk": "^1.18.2",
"@modelcontextprotocol/sdk": "^1.29.0",
"@opentelemetry/api": "^1.9.0",
"@opentelemetry/api-logs": "^0.217.0",
"@opentelemetry/exporter-logs-otlp-http": "^0.217.0",
Expand Down
107 changes: 60 additions & 47 deletions packages/agent-sdk/src/managers/mcpManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -369,61 +369,69 @@ export class McpManager {
version: "1.0.0",
},
{
capabilities: {
tools: {},
},
capabilities: {},
},
);

if (server.config.url) {
const serverType = server.config.type;

if (serverType === "http" || (!serverType && server.config.url)) {
if (!server.config.url) {
throw new Error(
`MCP server ${name} with type "http" requires a 'url'`,
);
}
const url = new URL(server.config.url);
const headers = server.config.headers;

try {
logger?.debug(
`Attempting Streamable HTTP connection for ${name} at ${url.href}`,
logger?.debug(
`Connecting to MCP server ${name} using Streamable HTTP at ${url.href}`,
);
transport = new StreamableHTTPClientTransport(url, {
requestInit: { headers },
});
client = createClient();
await client.connect(transport);
const toolsResponse = await client.listTools();
tools =
toolsResponse.tools?.map((tool) => ({
name: tool.name,
description: tool.description,
inputSchema: tool.inputSchema,
})) || [];
logger?.info(`Connected to MCP server ${name} using Streamable HTTP`);
} else if (serverType === "sse") {
if (!server.config.url) {
throw new Error(
`MCP server ${name} with type "sse" requires a 'url'`,
);
const streamableTransport = new StreamableHTTPClientTransport(url, {
requestInit: { headers },
});

const streamableClient = createClient();
await streamableClient.connect(streamableTransport);

// Try to list tools to verify connection works
const toolsResponse = await streamableClient.listTools();

transport = streamableTransport;
client = streamableClient;
tools =
toolsResponse.tools?.map((tool) => ({
name: tool.name,
description: tool.description,
inputSchema: tool.inputSchema,
})) || [];

logger?.info(`Connected to MCP server ${name} using Streamable HTTP`);
} catch (error) {
logger?.debug(
`Streamable HTTP failed for ${name}, falling back to SSE: ${error instanceof Error ? error.message : String(error)}`,
}
const url = new URL(server.config.url);
const headers = server.config.headers;
logger?.debug(
`Connecting to MCP server ${name} using SSE at ${url.href}`,
);
transport = new SSEClientTransport(url, {
requestInit: { headers },
});
client = createClient();
await client.connect(transport);
const toolsResponse = await client.listTools();
tools =
toolsResponse.tools?.map((tool) => ({
name: tool.name,
description: tool.description,
inputSchema: tool.inputSchema,
})) || [];
logger?.info(`Connected to MCP server ${name} using SSE`);
} else if (
serverType === "stdio" ||
(!serverType && server.config.command)
) {
if (!server.config.command) {
throw new Error(
`MCP server ${name} with type "stdio" requires a 'command'`,
);
transport = new SSEClientTransport(url, {
requestInit: { headers },
});
client = createClient();
await client.connect(transport);

const toolsResponse = await client.listTools();
tools =
toolsResponse.tools?.map((tool) => ({
name: tool.name,
description: tool.description,
inputSchema: tool.inputSchema,
})) || [];

logger?.info(`Connected to MCP server ${name} using SSE (fallback)`);
}
} else if (server.config.command) {
const agentEnv =
this.container.get<Record<string, string>>("MergedEnv") ||
(process.env as Record<string, string>);
Expand Down Expand Up @@ -492,6 +500,11 @@ export class McpManager {
description: tool.description,
inputSchema: tool.inputSchema,
})) || [];
} else if (serverType) {
// Unknown type value
throw new Error(
`MCP server ${name} has unknown type "${serverType}". Must be "stdio", "sse", or "http"`,
);
} else {
throw new Error(
`MCP server ${name} configuration must include either 'command' or 'url'`,
Expand Down
1 change: 1 addition & 0 deletions packages/agent-sdk/src/types/mcp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/

export interface McpServerConfig {
type?: "stdio" | "sse" | "http";
command?: string;
args?: string[];
env?: Record<string, string>;
Expand Down
Loading