Connect a server ​
McpClient owns one MCP transport. connect() returns an immutable server snapshot with adapted tools; the client owns cleanup.
Construction performs no I/O. A successful connection negotiates the MCP protocol, lists every page of tools once, and returns a frozen registration snapshot. Reconnect and rebuild the Agent when the remote tool catalog changes.
By default the client pins protocol 2026-07-28 without fallback. Set versionNegotiation on McpClient when a 2025-era server needs mode: "auto" or mode: "legacy".
1. Connect through stdio ​
Use stdio when the application starts and owns a local MCP process:
import { McpClient } from '@anvia/mcp'
const filesystemClient = new McpClient({
name: 'docs-filesystem',
transport: {
type: 'stdio',
command: 'npx',
args: [
'@modelcontextprotocol/server-filesystem',
'/workspace/docs',
],
},
})
const filesystem = await filesystemClient.connect()Construction is lazy. connect() starts the process, connects the MCP client, lists tools, and adapts each definition.
If tool listing fails after connection, Anvia attempts to close the client before rethrowing the listing error.
Pass versionNegotiation on the same client options when the server cannot speak the pinned modern revision:
const filesystemClient = new McpClient({
name: 'docs-filesystem',
transport: {
type: 'stdio',
command: 'npx',
args: [
'@modelcontextprotocol/server-filesystem',
'/workspace/docs',
],
},
versionNegotiation: { mode: 'auto' },
})2. Inspect before registration ​
console.log(filesystem.name)
for (const tool of filesystem.tools) {
console.log(await tool.definition(''))
}The server exposes its stable name, readonly adapted tools, and server metadata. Review names, descriptions, and input schemas before exposing privileged tools.
3. Register all or selected tools ​
const agent = new Agent({
id: 'docs-operator',
model,
mcpServers: [filesystem],
})This registers every listed tool. To expose a subset, filter the snapshot's tools and register it back through mcpServers as a plain { name, tools } object:
const allowed = new Set(['search_docs', 'read_doc'])
const reviewed = filesystem.tools.filter((tool) => allowed.has(tool.name))
const agent = new Agent({
id: 'docs-operator',
model,
mcpServers: [{ name: filesystem.name, tools: reviewed }],
})MCP tools cannot be passed through Agent.tools; construction rejects them. The subset stays tied to the server's name, so agent construction still checks it against every other tool source for collisions.
4. Own cleanup ​
const client = new McpClient(connectionOptions)
const server = await client.connect()
try {
const agent = createAgent(server)
return await agent.generate({
prompt: message
})
} finally {
await client.close()
}Jobs, scripts, tests, and request-scoped connections should close in finally. Long-running applications should connect once during startup, reuse the server, and close it during shutdown.
Do not reconnect and list tools for every message unless credentials or remote visibility are intentionally request-scoped.
Next, choose a stdio, streamable HTTP, or custom transport.