ai_sdk_mcp
Model Context Protocol (MCP) client for AI SDK Dart. Connects to MCP servers over Streamable HTTP (protocol 2025-06-18) or stdio and exposes their tools as a typed ToolSet.
Installation
dependencies:
ai_sdk_dart: ^2.0.0
ai_sdk_mcp: ^2.0.0
Usage
Streamable HTTP transport (remote server)
StreamableHttpClientTransport speaks the MCP Streamable HTTP transport
(protocol 2025-06-18) against a single MCP endpoint such as
https://example.com/mcp. It:
- sends every JSON-RPC request as an HTTP
POST - accepts either
application/jsonortext/event-streamresponses - sends
notifications/initializedafter protocol negotiation succeeds - starts the optional
GETSSE listener after initialization to surface server-pushed notifications - reuses
Mcp-Session-IdandMCP-Protocol-Versionon laterPOST/GET/DELETErequests when the server negotiates a session - reconnects the optional
GETlistener withLast-Event-IDafter an unexpected disconnect - sends a best-effort
notifications/cancellednotification when a request times out
import 'package:ai_sdk_dart/ai_sdk_dart.dart';
import 'package:ai_sdk_mcp/ai_sdk_mcp.dart';
import 'package:ai_sdk_openai/ai_sdk_openai.dart';
final transport = StreamableHttpClientTransport(
url: Uri.parse('https://mcp.example.com/mcp'),
headers: {
'Authorization': 'Bearer <short-lived-token>',
'X-Tenant-Id': 'acme',
},
requestTimeout: const Duration(seconds: 20),
);
final client = MCPClient(transport: transport);
await client.initialize();
// Discover tools and use them in a generateText call
final tools = await client.tools();
final result = await generateText(
model: openai('gpt-4.1-mini'),
prompt: 'Search for "Dart programming"',
tools: tools,
maxSteps: 3,
);
print(result.text);
await client.close();
headers are copied onto the transport's POST, optional GET, and DELETE
requests. This is the place to put required credential or routing headers.
Do not ship long-lived secrets inside browser or mobile client builds. Prefer
short-lived tokens minted by your backend or a trusted proxy.
Transport behavior notes
initialize()negotiates MCP protocol version2025-06-18. Older HTTP+SSE (2024-11-05) servers are not supported by this transport.- If the server returns
Mcp-Session-Idduring initialize, the transport includes it on later requests and sendsDELETEonclose()to end the session. A server may rejectDELETEwith405 Method Not Allowed; that is treated as an allowed shutdown path. - Server-pushed notifications are available on
transport.notifications, andnotifications/resources/updatedare wired intoMCPClientresource-subscription listeners automatically.
Stdio transport (local process)
Desktop/CLI only.
StdioMCPTransportspawns an OS process and is not available on Flutter web — referencing it still compiles for web (via a stub), but constructing and using it on web throwsUnsupportedError.
final transport = StdioMCPTransport(
command: 'npx',
args: ['-y', '@modelcontextprotocol/server-filesystem', '/tmp'],
);
final client = MCPClient(transport: transport);
await client.initialize();
final tools = await client.tools();
// Use tools with any generateText / streamText call...
await client.close();
Injecting your own http.Client
import 'package:http/http.dart' as http;
final sharedClient = http.Client();
final transport = StreamableHttpClientTransport(
url: Uri.parse('https://mcp.example.com/mcp'),
client: sharedClient,
);
final client = MCPClient(transport: transport);
await client.initialize();
await client.close();
// The injected client is still yours to manage.
sharedClient.close();
Direct tool invocation
final result = await client.callTool('readFile', {'path': '/tmp/hello.txt'});
print(result); // file contents as string
Error handling
try {
await client.callTool('dangerousOp', {});
} on MCPException catch (e) {
print('MCP server error: ${e.message}');
}
License
MIT
Libraries
- ai_sdk_mcp
- MCP (Model Context Protocol) client for the AI SDK.