Aller au contenu principal

MCPClient

La classe MCPClient permet de gérer plusieurs connexions à des serveurs MCP et leurs Tools dans une application Mastra. Elle prend en charge le cycle de vie des connexions et les espaces de noms des Tools, et donne accès aux Tools de tous les serveurs configurés.

Constructeur
Lien direct vers Constructeur

Crée une instance de la classe MCPClient.

constructor({
id?: string;
servers: Record<string, MastraMCPServerDefinition>;
timeout?: number;
}: MCPClientOptions)

MCPClientOptions
Lien direct vers MCPClientOptions


id?:

string
Identifiant unique facultatif de l’instance de configuration. Utilisez-le pour éviter les fuites de mémoire lors de la création de plusieurs instances ayant des configurations identiques.

servers:

Record<string, MastraMCPServerDefinition>
Une table de configurations de serveur, dans laquelle chaque clé est un identifiant de serveur unique et chaque valeur la configuration correspondante.

timeout?:

number
= 60000
Délai d’expiration global, en millisecondes, pour tous les serveurs, sauf remplacement dans la configuration d’un serveur.

MastraMCPServerDefinition
Lien direct vers mastramcpserverdefinition

Chaque serveur de la table servers est configuré avec le type MastraMCPServerDefinition. Le type de transport est détecté d’après les paramètres fournis :

  • Si command est fourni, le transport Stdio est utilisé.
  • Si url est fourni, le client tente d’abord d’utiliser le transport Streamable HTTP, puis se replie sur l’ancien transport SSE si la connexion initiale échoue.

command?:

string
Pour les serveurs Stdio : commande à exécuter.

args?:

string[]
Pour les serveurs Stdio : arguments à transmettre à la commande.

env?:

Record<string, string>
Pour les serveurs Stdio : variables d’environnement à définir pour la commande.

inheritDefaultEnv?:

boolean
= true
Pour les serveurs Stdio : indique si l’environnement du sous-processus part de l’environnement hérité par défaut du SDK MCP. Par défaut, il s’agit d’une liste blanche sélectionnée, et non de l’environnement complet du processus : sous POSIX, HOME, LOGNAME, PATH, SHELL, TERM et USER sont héritées ; sous Windows, APPDATA, HOMEDRIVE, HOMEPATH, LOCALAPPDATA, PATH, PROCESSOR_ARCHITECTURE, SYSTEMDRIVE, SYSTEMROOT, TEMP, USERNAME et USERPROFILE le sont. Lorsque cette option vaut false, seules les variables explicitement répertoriées dans env sont transmises au sous-processus. Notez qu’un sous-processus dépourvu de PATH peut ne pas parvenir à lancer des commandes dont le chemin n’est pas absolu.

url?:

URL
Pour les serveurs HTTP (Streamable HTTP ou SSE) : URL du serveur.

requestInit?:

RequestInit
Pour les serveurs HTTP : configuration des requêtes de l’API fetch.

eventSourceInit?:

EventSourceInit
Pour le repli SSE : configuration fetch personnalisée des connexions SSE. Requise avec des en-têtes personnalisés en SSE.

fetch?:

MastraFetchLike
Pour les serveurs HTTP : implémentation fetch personnalisée utilisée pour toutes les requêtes réseau. Elle reçoit un troisième paramètre requestContext facultatif contenant les données propres à la requête entrante (par exemple, cookies d’authentification ou jetons bearer). Lorsqu’elle est fournie, cette fonction est utilisée pour toutes les requêtes HTTP. Elle permet d’ajouter des en-têtes d’authentification dynamiques, de transmettre au serveur MCP des identifiants propres à la requête, de personnaliser le comportement de chaque requête, ou encore d’intercepter et de modifier les requêtes et réponses. Lorsque fetch est fourni, requestInit, eventSourceInit et authProvider deviennent facultatifs, car votre fonction fetch personnalisée peut prendre en charge ces aspects.

allowedHosts?:

string[]
Pour les serveurs HTTP : liste d’autorisation facultative des hôtes que le client peut contacter pour le compte de ce serveur. Chaque entrée est comparée à l’hôte de l’URL (nom d’hôte et port lorsque l’URL utilise un port non standard), par exemple "api.example.com" ou "localhost:8080". La correspondance est exacte et insensible à la casse pour le nom d’hôte ; les caractères génériques ne sont pas pris en charge et le schéma de l’URL n’est pas vérifié. Un tableau vide refuse toutes les requêtes. En l’absence de valeur, aucune restriction ne s’applique. Consultez la section Sécurité ci-dessous pour les détails d’application.

logger?:

LogHandler
Gestionnaire supplémentaire facultatif pour la journalisation.

timeout?:

number
Délai d’expiration propre au serveur, en millisecondes.

capabilities?:

ClientCapabilities
Configuration des capacités propre au serveur.

authProvider?:

OAuthClientProvider
Pour les serveurs HTTP : Provider d’authentification OAuth assurant l’actualisation automatique des jetons et la gestion du flux OAuth. Utilisez MCPOAuthClientProvider pour une implémentation prête à l’emploi.

enableServerLogs?:

boolean
= true
Indique si la journalisation doit être activée pour ce serveur.

forwardInstructions?:

boolean
= false
Indique si les instructions annoncées par ce serveur MCP doivent être ajoutées au prompt système d’un Agent lorsque celui-ci utilise les Tools du serveur. Cette option est désactivée par défaut ; ne l’activez que pour les serveurs auxquels vous faites confiance, car les instructions sont injectées dans le prompt système de l’Agent.

instructionsMaxLength?:

number
= 512
Nombre maximal de caractères d’instructions du serveur à ajouter au prompt système d’un Agent.

requireToolApproval?:

boolean | (params: RequireToolApprovalContext) => boolean | Promise<boolean>
Exige une approbation humaine avant d’exécuter les Tools de ce serveur. Avec la valeur true, tous les Tools nécessitent une approbation. Lorsqu’une fonction est fournie, elle reçoit le nom du Tool, ses arguments, le contexte de requête et les éventuelles annotations annoncées par le serveur afin de déterminer dynamiquement si une approbation est nécessaire.

Approbation des Tools
Lien direct vers Approbation des Tools

Utilisez requireToolApproval dans la définition d’un serveur pour exiger une approbation humaine avant l’exécution de tout Tool de ce serveur. Cette option s’intègre au flux d’approbation human-in-the-loop existant.

Exiger une approbation pour tous les Tools
Lien direct vers Exiger une approbation pour tous les Tools

Définissez requireToolApproval sur true pour exiger une approbation pour chaque Tool du serveur :

const mcp = new MCPClient({
servers: {
github: {
url: new URL('http://localhost:3000/mcp'),
requireToolApproval: true,
},
},
})

Approbation dynamique avec une fonction
Lien direct vers Approbation dynamique avec une fonction

Transmettez une fonction pour décider, à chaque appel, si une approbation est nécessaire. La fonction reçoit le nom du Tool, les arguments transmis par le modèle, tout contexte issu de la requête entrante et les annotations MCP du Tool (lorsque le serveur les annonce) :

const mcp = new MCPClient({
servers: {
github: {
url: new URL('http://localhost:3000/mcp'),
requireToolApproval: ({ toolName, args, requestContext }) => {
// Read-only tools don't need approval
if (toolName === 'list_repos') return false
// Destructive tools with force flag always need approval
if (toolName === 'delete_repo') return args.force === true
// Non-admin users need approval for everything else
return requestContext?.userRole !== 'admin'
},
},
},
})

La fonction peut également être asynchrone. Elle reçoit le requestContext de la requête entrante, que vous pouvez utiliser pour les contrôles d’authentification ou toute autre logique propre à la requête.

Utiliser les annotations de Tool d’un serveur de confiance
Lien direct vers Utiliser les annotations de Tool d’un serveur de confiance

Si vous faites confiance au serveur MCP, vous pouvez utiliser ses annotations de Tool (readOnlyHint, destructiveHint, idempotentHint, openWorldHint, title) pour orienter les décisions d’approbation :

const mcp = new MCPClient({
servers: {
github: {
url: new URL('http://localhost:3000/mcp'),
requireToolApproval: ({ annotations }) => {
// Skip approval for tools the server has marked read-only
if (annotations?.readOnlyHint) return false
// Always require approval for destructive tools
if (annotations?.destructiveHint) return true
return true
},
},
},
})

Selon la spécification MCP, les clients DOIVENT considérer les annotations de Tool comme non fiables, sauf si elles proviennent de serveurs de confiance. Ces annotations ne sont que des indications et ne constituent aucune frontière de sécurité. Un serveur malveillant ou défectueux peut prétendre qu’un Tool est en lecture seule alors que ce n’est pas le cas. N’utilisez les annotations pour assouplir les exigences d’approbation que pour les serveurs auxquels vous faites confiance.

Ces mêmes annotations sont également exposées sur les Tools renvoyés par listTools() et listToolsets(), sous tool.mcp.annotations. Vous pouvez ainsi les examiner lorsque vous associez les Tools à un Agent.

Instructions du serveur
Lien direct vers Instructions du serveur

Lorsqu’un serveur MCP annonce des instructions pendant l’initialisation, MCPClient les conserve pour ce serveur. Leur transmission au prompt système d’un Agent est facultative : définissez forwardInstructions: true sur un serveur pour que les Agents qui utilisent ses Tools (via listTools() ou listToolsets()) reçoivent automatiquement ses instructions.

Les instructions sont regroupées par nom de serveur et limitées à instructionsMaxLength caractères par serveur.

const mcp = new MCPClient({
servers: {
db: {
url: new URL('http://localhost:3000/mcp'),
forwardInstructions: true,
instructionsMaxLength: 512,
},
},
})

const agent = new Agent({
id: 'db-agent',
name: 'DB Agent',
instructions: 'Help with database changes.',
model,
tools: await mcp.listTools(),
})

Lorsque forwardInstructions est omis (comportement par défaut), les instructions restent mises en cache et peuvent être consultées avec getServerInstructions(), mais ne sont ajoutées au prompt système d’aucun Agent.

Note de sécurité : les instructions du serveur sont transmises telles quelles au prompt système de l’Agent (sous réserve uniquement de leur troncature). Un serveur MCP malveillant ou compromis peut s’en servir pour injecter des instructions que l’Agent considérera comme des directives système fiables. N’activez forwardInstructions que pour les serveurs auxquels vous faites confiance et examinez de préférence les instructions avec getServerInstructions() avant de transmettre celles de serveurs tiers.

Sécurité
Lien direct vers Sécurité

Environnement des sous-processus pour les serveurs Stdio
Lien direct vers Environnement des sous-processus pour les serveurs Stdio

Les sous-processus Stdio n’héritent pas de l’intégralité de l’environnement du processus parent. Par défaut, leur environnement part de la liste blanche sélectionnée par le SDK MCP (POSIX : HOME, LOGNAME, PATH, SHELL, TERM, USER ; Windows : APPDATA, HOMEDRIVE, HOMEPATH, LOCALAPPDATA, PATH, PROCESSOR_ARCHITECTURE, SYSTEMDRIVE, SYSTEMROOT, TEMP, USERNAME, USERPROFILE), à laquelle s’ajoutent les variables définies dans env. Les variables sensibles, comme les clés d’API, ne sont pas héritées à moins d’être transmises explicitement.

Pour une isolation plus stricte, définissez inheritDefaultEnv: false afin que seules les entrées configurées dans env atteignent le sous-processus :

const mcp = new MCPClient({
servers: {
myTool: {
command: '/usr/local/bin/my-mcp-server',
inheritDefaultEnv: false,
env: { MY_TOOL_API_KEY: process.env.MY_TOOL_API_KEY! },
},
},
})

Les variables placées dans env sont transmises telles quelles. Considérez donc comme des entrées non fiables les configurations de serveur provenant de sources non fiables, par exemple des fichiers de configuration fournis par l’utilisateur.

Restreindre les hôtes sortants avec allowedHosts
Lien direct vers restricting-outbound-hosts-with-allowedhosts

Lorsque les URL des serveurs HTTP proviennent d’une configuration non fiable, une URL contrôlée par un attaquant peut diriger le client vers des services internes (falsification de requête côté serveur). Définissez allowedHosts sur ces serveurs afin de limiter les hôtes que le client peut contacter :

const mcp = new MCPClient({
servers: {
remote: {
url: new URL(untrustedConfig.serverUrl),
allowedHosts: ['api.example.com'],
},
},
})

Détails d’application :

  • Avec le chemin fetch par défaut, les requêtes vers des hôtes non autorisés, y compris chaque étape d’une redirection, sont bloquées avant leur envoi. Les redirections sont suivies manuellement (jusqu’à 5 étapes) afin de valider chacune d’elles. L’en-tête Authorization n’est pas transmis lorsqu’une étape change d’origine : toute modification du schéma, de l’hôte ou du port le supprime, conformément au comportement fetch standard.
  • Lorsque vous fournissez un fetch personnalisé (ou un eventSourceInit.fetch personnalisé), l’URL initiale est toujours vérifiée avant la requête, mais les étapes de redirection sont validées a posteriori à l’aide de response.url : la requête sortante peut avoir lieu, puis la réponse est rejetée si son URL finale pointe vers un hôte non autorisé. Une Response construite manuellement avec un response.url vide contourne cette vérification a posteriori.
  • Les requêtes OAuth effectuées via authProvider (découverte des métadonnées du serveur d’autorisation, échange et actualisation des jetons) sont également validées. Si votre serveur d’autorisation s’exécute sur un hôte différent de celui du serveur MCP, ajoutez aussi cet hôte à allowedHosts.
  • Un hôte bloqué fait échouer la connexion avec une erreur explicite et la logique de reconnexion ne réessaie jamais.

allowedHosts est volontairement minimal : il compare les hôtes exactement et ne prend en charge ni caractères génériques ni contrôle du schéma. Pour une politique plus riche (contrôle du schéma ou règles de plages IP), fournissez une implémentation fetch personnalisée, appelée pour chaque requête du client.

Considérer les réponses des Tools comme des entrées non fiables
Lien direct vers Considérer les réponses des Tools comme des entrées non fiables

Les résultats de Tools renvoyés par les serveurs MCP sont intégrés au contexte de votre Agent comme entrées du modèle. Un serveur malveillant ou compromis peut utiliser la sortie d’un Tool pour injecter un prompt. Le client de transport n’assainit pas les réponses des Tools : cette politique relève de la couche Agent, où les processeurs d’entrée et de sortie de Mastra permettent d’examiner, de transformer ou de bloquer le contenu avant et après son passage dans le modèle. Lorsque vous utilisez des serveurs tiers, combinez cette protection avec requireToolApproval et les précautions relatives à forwardInstructions ci-dessus.

Méthodes
Lien direct vers Méthodes

listTools()
Lien direct vers listtools

Récupère tous les Tools de tous les serveurs configurés, en préfixant leurs noms par l’espace de noms du serveur (au format serverName_toolName) afin d’éviter les conflits. Cette valeur est destinée à être transmise à la définition d’un Agent.

new Agent({ id: 'agent', tools: await mcp.listTools() })

listToolsWithErrors()
Lien direct vers listtoolswitherrors

Récupère tous les Tools de tous les serveurs configurés, avec des noms placés dans l’espace de noms de leur serveur. Renvoie également les erreurs propres aux serveurs qui n’ont pas pu se connecter ou répertorier leurs Tools.

const { tools, errors } = await mcp.listToolsWithErrors()

new Agent({ id: 'agent', tools })
console.log(errors)

listToolsets()
Lien direct vers listtoolsets

Renvoie un objet qui associe les noms de Tools placés dans un espace de noms (au format serverName.toolName) à leurs implémentations. Cette valeur est destinée à être transmise à l’exécution à la méthode generate ou stream.

const res = await agent.stream(prompt, {
toolsets: await mcp.listToolsets(),
})

getServerInstructions()
Lien direct vers getserverinstructions

Renvoie les instructions actuellement connues pour chaque serveur MCP configuré. Les serveurs qui ne se sont pas encore connectés ou qui n’annoncent aucune instruction renvoient undefined.

getServerInstructions(): Record<string, string | undefined>

Exemple :

await mcp.listTools()

const instructionsByServer = mcp.getServerInstructions()
console.log(instructionsByServer.db)

authenticate()
Lien direct vers authenticate

Exécute le flux interactif de code d’autorisation OAuth pour un serveur configuré avec un MCPOAuthClientProvider dont l’URL de redirection pointe vers une adresse de bouclage. La méthode démarre un serveur de rappel local, transmet l’URL d’autorisation via le callback onRedirectToAuthorization du Provider, attend que le navigateur renvoie le code d’autorisation, échange celui-ci contre des jetons, puis se reconnecte. Consultez Authentification interactive dans le navigateur.

Le paramètre facultatif timeoutMs limite la durée pendant laquelle le flux attend que le navigateur renvoie le code d’autorisation avant d’échouer. Sa valeur par défaut est de 5 minutes.

async authenticate(serverName: string, options?: { timeoutMs?: number }): Promise<void>

getServerAuthState()
Lien direct vers getserverauthstate

Renvoie l’état d’autorisation OAuth d’un serveur configuré : 'needs-auth' après le rejet d’une tentative de connexion pour erreur d’autorisation, 'authorized' dès que le serveur a accepté les identifiants du Provider, ou undefined pour les serveurs sans authProvider ou qui n’ont encore tenté aucune connexion.

getServerAuthState(serverName: string): 'needs-auth' | 'authorized' | undefined

cancelAuthentication()
Lien direct vers cancelauthentication

Annule un flux authenticate() en cours pour un serveur, afin qu’une autorisation abandonnée dans le navigateur ne laisse pas le client en attente indéfiniment. La méthode interrompt le flux, y compris sa phase de préparation avant la liaison du serveur de rappel, ferme le serveur de rappel local s’il est en écoute et fait échouer l’appel authenticate() en attente. Elle renvoie true si un flux a été annulé, ou false si aucun flux n’était en cours.

La valeur de getServerAuthState() qui en résulte dépend de l’avancement du flux. Un flux annulé après un rejet 401 reste à l’état 'needs-auth' et peut être relancé immédiatement. Une annulation pendant la préparation laisse l’état inchangé (généralement undefined) si aucune connexion n’a été tentée.

async cancelAuthentication(serverName: string): Promise<boolean>

disconnect()
Lien direct vers disconnect

Se déconnecte de tous les serveurs MCP et libère les ressources.

async disconnect(): Promise<void>

toMCPServerProxies()
Lien direct vers tomcpserverproxies

Renvoie une table d’instances MCPClientServerProxy, une par serveur configuré. Chaque proxy encapsule la connexion cliente sous-jacente dans une instance MCPServerBase, ce qui permet d’enregistrer des serveurs MCP externes à Mastra dans mcpServers et de les afficher dans Studio.

async toMCPServerProxies(): Promise<Record<string, MCPClientServerProxy>>

Décomposez le résultat dans la configuration mcpServers de Mastra :

src/mastra/index.ts
import { Mastra } from '@mastra/core/mastra'
import { MCPClient } from '@mastra/mcp'

const mcpClient = new MCPClient({
servers: {
'color-mixer': {
command: 'node',
args: ['path/to/color-mixer-server.js'],
},
},
})

export const mastra = new Mastra({
mcpServers: {
...(await mcpClient.toMCPServerProxies()),
},
})

Cette méthode permet de connecter à Studio des serveurs MCP externes qui implémentent l’extension MCP Apps ou d’autres fonctionnalités, sans les encapsuler dans un MCPServer Mastra.

Propriété resources
Lien direct vers resources-property

L’instance MCPClient possède une propriété resources qui donne accès aux opérations liées aux ressources.

const mcpClient = new MCPClient({/* ...servers configuration... */})

// Access resource methods via mcpClient.resources
const allResourcesByServer = await mcpClient.resources.list()
const templatesByServer = await mcpClient.resources.templates()
// ... and so on for other resource methods.

resources.list()
Lien direct vers resourceslist

Récupère toutes les ressources disponibles sur tous les serveurs MCP connectés, regroupées par nom de serveur.

async list(): Promise<Record<string, Resource[]>>

Exemple :

const resourcesByServer = await mcpClient.resources.list()
for (const serverName in resourcesByServer) {
console.log(`Resources from ${serverName}:`, resourcesByServer[serverName])
}

resources.templates()
Lien direct vers resourcestemplates

Récupère tous les modèles de ressource disponibles sur tous les serveurs MCP connectés, regroupés par nom de serveur.

async templates(): Promise<Record<string, ResourceTemplate[]>>

Exemple :

const templatesByServer = await mcpClient.resources.templates()
for (const serverName in templatesByServer) {
console.log(`Templates from ${serverName}:`, templatesByServer[serverName])
}

resources.read(serverName: string, uri: string)
Lien direct vers resourcesreadservername-string-uri-string

Lit le contenu d’une ressource précise sur un serveur.

async read(serverName: string, uri: string): Promise<ReadResourceResult>
  • serverName : identifiant du serveur (clé utilisée dans l’option servers du constructeur).
  • uri : URI de la ressource à lire.

Exemple :

const content = await mcpClient.resources.read('myWeatherServer', 'weather://current')
console.log('Current weather:', content.contents[0].text)

resources.subscribe(serverName: string, uri: string)
Lien direct vers resourcessubscribeservername-string-uri-string

S’abonne aux mises à jour d’une ressource précise sur un serveur.

async subscribe(serverName: string, uri: string): Promise<object>

Exemple :

await mcpClient.resources.subscribe('myWeatherServer', 'weather://current')

resources.unsubscribe(serverName: string, uri: string)
Lien direct vers resourcesunsubscribeservername-string-uri-string

Se désabonne des mises à jour d’une ressource précise sur un serveur.

async unsubscribe(serverName: string, uri: string): Promise<object>

Exemple :

await mcpClient.resources.unsubscribe('myWeatherServer', 'weather://current')

resources.onUpdated(serverName: string, handler: (params: { uri: string }) => void)
Lien direct vers resourcesonupdatedservername-string-handler-params--uri-string---void

Définit un gestionnaire de notification appelé lorsqu’une ressource suivie sur un serveur précis est mise à jour.

async onUpdated(serverName: string, handler: (params: { uri: string }) => void): Promise<void>

Exemple :

mcpClient.resources.onUpdated('myWeatherServer', params => {
console.log(`Resource updated on myWeatherServer: ${params.uri}`)
// You might want to re-fetch the resource content here
// await mcpClient.resources.read("myWeatherServer", params.uri);
})

resources.onListChanged(serverName: string, handler: () => void)
Lien direct vers resourcesonlistchangedservername-string-handler---void

Définit un gestionnaire de notification appelé lorsque la liste des ressources disponibles change sur un serveur précis.

async onListChanged(serverName: string, handler: () => void): Promise<void>

Exemple :

mcpClient.resources.onListChanged('myWeatherServer', () => {
console.log('Resource list changed on myWeatherServer.')
// You should re-fetch the list of resources
// await mcpClient.resources.list();
})

Propriété elicitation
Lien direct vers elicitation-property

L’instance MCPClient possède une propriété elicitation qui donne accès aux opérations de sollicitation. La sollicitation permet aux serveurs MCP de demander des informations structurées aux utilisateurs.

const mcpClient = new MCPClient({/* ...servers configuration... */})

// Set up elicitation handler
mcpClient.elicitation.onRequest('serverName', async request => {
// Handle elicitation request from server
console.log('Server requests:', request.message)
console.log('Schema:', request.requestedSchema)

// Return user response
return {
action: 'accept',
content: { name: 'John Doe', email: 'john@example.com' },
}
})

elicitation.onRequest(serverName: string, handler: ElicitationHandler)
Lien direct vers elicitationonrequestservername-string-handler-elicitationhandler

Configure une fonction de gestion appelée lorsqu’un serveur MCP connecté envoie une demande de sollicitation. Le gestionnaire reçoit la demande et doit renvoyer une réponse.

Fonction ElicitationHandler
Lien direct vers elicitationhandler-function

La fonction de gestion reçoit un objet de requête comprenant :

  • message : message lisible décrivant les informations nécessaires
  • requestedSchema : schéma JSON définissant la structure de la réponse attendue

Le gestionnaire doit renvoyer un ElicitResult comprenant :

  • action : l’une des valeurs 'accept', 'decline' ou 'cancel'
  • content : données de l’utilisateur (uniquement lorsque l’action vaut 'accept')

Exemple :

mcpClient.elicitation.onRequest('serverName', async request => {
console.log(`Server requests: ${request.message}`)

// Example: Simple user input collection
if (request.requestedSchema.properties.name) {
// Simulate user accepting and providing data
return {
action: 'accept',
content: {
name: 'Alice Smith',
email: 'alice@example.com',
},
}
}

// Simulate user declining the request
return { action: 'decline' }
})

Exemple interactif complet :

import { MCPClient } from '@mastra/mcp'
import { createInterface } from 'readline'

const readline = createInterface({
input: process.stdin,
output: process.stdout,
})

function askQuestion(question: string): Promise<string> {
return new Promise(resolve => {
readline.question(question, answer => resolve(answer.trim()))
})
}

const mcpClient = new MCPClient({
servers: {
interactiveServer: {
url: new URL('http://localhost:3000/mcp'),
},
},
})

// Set up interactive elicitation handler
await mcpClient.elicitation.onRequest('interactiveServer', async request => {
console.log(`\n📋 Server Request: ${request.message}`)
console.log('Required information:')

const schema = request.requestedSchema
const properties = schema.properties || {}
const required = schema.required || []
const content: Record<string, any> = {}

// Collect input for each field
for (const [fieldName, fieldSchema] of Object.entries(properties)) {
const field = fieldSchema as any
const isRequired = required.includes(fieldName)

let prompt = `${field.title || fieldName}`
if (field.description) prompt += ` (${field.description})`
if (isRequired) prompt += ' *required*'
prompt += ': '

const answer = await askQuestion(prompt)

// Handle cancellation
if (answer.toLowerCase() === 'cancel') {
return { action: 'cancel' }
}

// Validate required fields
if (answer === '' && isRequired) {
console.log(`${fieldName} is required`)
return { action: 'decline' }
}

if (answer !== '') {
content[fieldName] = answer
}
}

// Confirm submission
console.log('\n📝 You provided:')
console.log(JSON.stringify(content, null, 2))

const confirm = await askQuestion('\nSubmit this information? (yes/no/cancel): ')

if (confirm.toLowerCase() === 'yes' || confirm.toLowerCase() === 'y') {
return { action: 'accept', content }
} else if (confirm.toLowerCase() === 'cancel') {
return { action: 'cancel' }
} else {
return { action: 'decline' }
}
})

Propriété prompts
Lien direct vers prompts-property

L’instance MCPClient possède une propriété prompts qui donne accès aux opérations liées aux prompts.

const mcpClient = new MCPClient({/* ...servers configuration... */})

// Access prompt methods via mcpClient.prompts
const allPromptsByServer = await mcpClient.prompts.list()
const { prompt, messages } = await mcpClient.prompts.get({
serverName: 'myWeatherServer',
name: 'current',
})

prompts.list()
Lien direct vers promptslist

Récupère tous les prompts disponibles sur tous les serveurs MCP connectés, regroupés par nom de serveur.

async list(): Promise<Record<string, Prompt[]>>

Exemple :

const promptsByServer = await mcpClient.prompts.list()
for (const serverName in promptsByServer) {
console.log(`Prompts from ${serverName}:`, promptsByServer[serverName])
}

prompts.get({ serverName, name, args?, version? })
Lien direct vers promptsget-servername-name-args-version-

Récupère un prompt précis et ses messages depuis un serveur.

async get({
serverName,
name,
args?,
version?,
}: {
serverName: string;
name: string;
args?: Record<string, any>;
version?: string;
}): Promise<{ prompt: Prompt; messages: PromptMessage[] }>

Exemple :

const { prompt, messages } = await mcpClient.prompts.get({
serverName: 'myWeatherServer',
name: 'current',
args: { location: 'London' },
})
console.log(prompt)
console.log(messages)

prompts.onListChanged(serverName: string, handler: () => void)
Lien direct vers promptsonlistchangedservername-string-handler---void

Définit un gestionnaire de notification appelé lorsque la liste des prompts disponibles change sur un serveur précis.

async onListChanged(serverName: string, handler: () => void): Promise<void>

Exemple :

mcpClient.prompts.onListChanged('myWeatherServer', () => {
console.log('Prompt list changed on myWeatherServer.')
// You should re-fetch the list of prompts
// await mcpClient.prompts.list();
})

Propriété tools
Lien direct vers tools-property

L’instance MCPClient possède une propriété tools permettant de s’abonner aux notifications de modification de la liste des Tools. Pour récupérer les Tools, utilisez listTools() ou listToolsets().

tools.onListChanged(serverName: string, handler: () => void)
Lien direct vers toolsonlistchangedservername-string-handler---void

Définit un gestionnaire de notification appelé lorsque la liste des Tools disponibles change sur un serveur précis, par exemple lorsque le serveur ajoute ou supprime des Tools à l’exécution.

async onListChanged(serverName: string, handler: () => void): Promise<void>

Exemple :

await mcpClient.tools.onListChanged('myWeatherServer', async () => {
console.log('Tool list changed on myWeatherServer.')
// You should re-fetch the tools
// const tools = await mcpClient.listTools();
})

Propriété progress
Lien direct vers progress-property

L’instance MCPClient possède une propriété progress permettant de s’abonner aux notifications de progression émises par les serveurs MCP pendant l’exécution des Tools.

const mcpClient = new MCPClient({
servers: {
myServer: {
url: new URL('http://localhost:4111/api/mcp/myServer/mcp'),
// Enabled by default; set to false to disable
enableProgressTracking: true,
},
},
})

// Subscribe to progress updates for a specific server
await mcpClient.progress.onUpdate('myServer', params => {
console.log('📊 Progress:', params.progress, '/', params.total)
if (params.message) console.log('Message:', params.message)
if (params.progressToken) console.log('Token:', params.progressToken)
})

progress.onUpdate(serverName: string, handler)
Lien direct vers progressonupdateservername-string-handler

Enregistre une fonction de gestion qui reçoit les mises à jour de progression du serveur indiqué.

async onUpdate(
serverName: string,
handler: (params: {
progressToken: string;
progress: number;
total?: number;
message?: string;
}) => void,
): Promise<void>

Remarques :

  • Lorsque enableProgressTracking vaut true (valeur par défaut), les appels de Tool comprennent un progressToken qui permet d’associer les mises à jour à une exécution précise.
  • Si vous transmettez un runId lors de l’exécution d’un Tool, il sera utilisé comme progressToken.

Pour désactiver le suivi de progression d’un serveur :

const mcpClient = new MCPClient({
servers: {
myServer: {
url: new URL('http://localhost:4111/api/mcp/myServer/mcp'),
enableProgressTracking: false,
},
},
})

Sollicitation
Lien direct vers Sollicitation

La sollicitation est une fonctionnalité qui permet aux serveurs MCP de demander des informations structurées aux utilisateurs. Lorsqu’un serveur a besoin de données supplémentaires, il peut envoyer une demande de sollicitation que le client traite en interrogeant l’utilisateur. Un appel de Tool en est un exemple courant.

Fonctionnement de la sollicitation
Lien direct vers Fonctionnement de la sollicitation

  1. Demande du serveur : un Tool du serveur MCP appelle server.elicitation.sendRequest() avec un message et un schéma
  2. Gestionnaire du client : votre fonction de gestion de la sollicitation est appelée avec la demande
  3. Interaction utilisateur : votre gestionnaire recueille la saisie de l’utilisateur (via une interface graphique, la CLI, etc.)
  4. Réponse : votre gestionnaire renvoie la réponse de l’utilisateur (acceptation, refus ou annulation)
  5. Poursuite du Tool : le Tool du serveur reçoit la réponse et poursuit son exécution

Configurer la sollicitation
Lien direct vers Configurer la sollicitation

Vous devez configurer un gestionnaire de sollicitation avant d’appeler les Tools qui utilisent cette fonctionnalité :

import { MCPClient } from '@mastra/mcp'

const mcpClient = new MCPClient({
servers: {
interactiveServer: {
url: new URL('http://localhost:3000/mcp'),
},
},
})

// Set up elicitation handler
mcpClient.elicitation.onRequest('interactiveServer', async request => {
// Handle the server's request for user input
console.log(`Server needs: ${request.message}`)

// Your logic to collect user input
const userData = await collectUserInput(request.requestedSchema)

return {
action: 'accept',
content: userData,
}
})

Types de réponse
Lien direct vers Types de réponse

Votre gestionnaire de sollicitation doit renvoyer l’un des trois types de réponse suivants :

  • Accepter : l’utilisateur a fourni des données et confirmé leur envoi

    return {
    action: 'accept',
    content: { name: 'John Doe', email: 'john@example.com' },
    }
  • Refuser : l’utilisateur a explicitement refusé de fournir les informations

    return { action: 'decline' }
  • Annuler : l’utilisateur a ignoré ou annulé la demande

    return { action: 'cancel' }

Collecte des saisies fondée sur un schéma
Lien direct vers Collecte des saisies fondée sur un schéma

Le requestedSchema définit la structure des données dont le serveur a besoin :

await mcpClient.elicitation.onRequest('interactiveServer', async request => {
const { properties, required = [] } = request.requestedSchema
const content: Record<string, any> = {}

for (const [fieldName, fieldSchema] of Object.entries(properties || {})) {
const field = fieldSchema as any
const isRequired = required.includes(fieldName)

// Collect input based on field type and requirements
const value = await promptUser({
name: fieldName,
title: field.title,
description: field.description,
type: field.type,
required: isRequired,
format: field.format,
enum: field.enum,
})

if (value !== null) {
content[fieldName] = value
}
}

return { action: 'accept', content }
})

Bonnes pratiques
Lien direct vers Bonnes pratiques

  • Toujours gérer la sollicitation : configurez votre gestionnaire avant d’appeler des Tools susceptibles d’utiliser la sollicitation
  • Valider les saisies : vérifiez que les champs obligatoires sont renseignés
  • Respecter le choix de l’utilisateur : traitez correctement les réponses de refus et d’annulation
  • Clarifier l’interface : indiquez clairement quelles informations sont demandées et pourquoi
  • Sécuriser les demandes : n’acceptez jamais automatiquement une demande d’informations sensibles

Authentification OAuth
Lien direct vers Authentification OAuth

Pour vous connecter à des serveurs MCP qui exigent une authentification OAuth conformément à la spécification d’authentification MCP, utilisez MCPOAuthClientProvider :

import { MCPClient, MCPOAuthClientProvider } from '@mastra/mcp'

// Create an OAuth provider
const oauthProvider = new MCPOAuthClientProvider({
redirectUrl: 'http://localhost:3000/oauth/callback',
clientMetadata: {
redirect_uris: ['http://localhost:3000/oauth/callback'],
client_name: 'My MCP Client',
grant_types: ['authorization_code', 'refresh_token'],
response_types: ['code'],
},
onRedirectToAuthorization: url => {
// Handle authorization redirect (open browser, redirect response, etc.)
console.log(`Please visit: ${url}`)
},
})

// Use the provider with MCPClient
const client = new MCPClient({
servers: {
protectedServer: {
url: new URL('https://mcp.example.com/mcp'),
authProvider: oauthProvider,
},
},
})

Attribuez à chaque serveur sa propre instance MCPOAuthClientProvider. Pendant l’autorisation, un Provider conserve l’état de session et les identifiants propres au serveur. Partager une même instance entre plusieurs serveurs permettrait donc à leurs flux de s’écraser mutuellement. Lorsque vous configurez plusieurs serveurs protégés, créez un Provider distinct pour chacun.

Authentification interactive dans le navigateur
Lien direct vers Authentification interactive dans le navigateur

Lorsqu’un serveur rejette une connexion parce qu’une autorisation est requise, le client enregistre l’état 'needs-auth' au lieu d’échouer immédiatement. L’appel de authenticate() termine le flux. Il démarre un serveur de rappel à usage unique sur l’URL de redirection en boucle locale du Provider et essaie les ports suivants dans l’ordre si le port est occupé. Le SDK effectue ensuite la découverte et l’enregistrement du client à l’exécution. onRedirectToAuthorization reçoit l’URL d’autorisation afin que votre application puisse l’ouvrir dans le navigateur de l’utilisateur. L’échange de jetons se termine lorsque le navigateur renvoie le code d’autorisation :

import { MCPClient, MCPOAuthClientProvider } from '@mastra/mcp'

const oauthProvider = new MCPOAuthClientProvider({
redirectUrl: 'http://127.0.0.1:5533/oauth/callback',
clientMetadata: {
redirect_uris: ['http://127.0.0.1:5533/oauth/callback'],
client_name: 'My MCP Client',
grant_types: ['authorization_code', 'refresh_token'],
response_types: ['code'],
},
onRedirectToAuthorization: url => {
// Open the user's browser at the consent page
console.log(`Please visit: ${url}`)
},
})

const mcp = new MCPClient({
servers: {
protectedServer: {
url: new URL('https://mcp.example.com/mcp'),
authProvider: oauthProvider,
},
},
})

try {
await mcp.listTools()
} catch {
if (mcp.getServerAuthState('protectedServer') === 'needs-auth') {
await mcp.authenticate('protectedServer')
}
}

Les appels simultanés de authenticate() pour un même serveur rejoignent le flux en attente. Les différents serveurs s’authentifient indépendamment. Si des jetons valides sont enregistrés, l’appel se reconnecte sans ouvrir de navigateur.

Les hôtes qui pilotent eux-mêmes le flux peuvent récupérer le code d’autorisation avec l’utilitaire exporté createOAuthCallbackServer. Celui-ci lie un serveur de bouclage à usage unique, valide le paramètre OAuth state, puis renvoie le code. Comme il crée un simple serveur HTTP, il est exclusivement destiné aux redirections locales en boucle. Les applications web qui utilisent une URL de redirection HTTPS doivent héberger leur propre point de terminaison de rappel et piloter directement le Provider au lieu d’utiliser cet utilitaire :

import { createOAuthCallbackServer, getCallbackUrlCandidates } from '@mastra/mcp'

// getCallbackUrlCandidates() lists every URL the helper may bind, so register
// all of them as redirect_uris during client registration to cover port fallback.
const redirectUris = getCallbackUrlCandidates('http://127.0.0.1:5533/oauth/callback').map(url =>
url.toString(),
)

const server = await createOAuthCallbackServer({
redirectUrl: 'http://127.0.0.1:5533/oauth/callback',
state: expectedState,
})

// server.url reflects the port actually bound — use it as the redirect_uri.
try {
const { code } = await server.waitForCode()
// Exchange the code here.
} finally {
await server.close()
}

Provider de jeton rapide
Lien direct vers Provider de jeton rapide

Pour effectuer des tests ou lorsque vous disposez déjà d’un jeton d’accès valide :

import { MCPClient, createSimpleTokenProvider } from '@mastra/mcp'

const provider = createSimpleTokenProvider('your-access-token', {
redirectUrl: 'http://localhost:3000/callback',
clientMetadata: {
redirect_uris: ['http://localhost:3000/callback'],
client_name: 'Test Client',
},
})

const client = new MCPClient({
servers: {
testServer: {
url: new URL('https://mcp.example.com/mcp'),
authProvider: provider,
},
},
})

Stockage personnalisé des jetons
Lien direct vers Stockage personnalisé des jetons

Pour conserver les jetons entre les sessions, implémentez l’interface OAuthStorage :

import { MCPOAuthClientProvider, OAuthStorage } from '@mastra/mcp'

class DatabaseOAuthStorage implements OAuthStorage {
constructor(
private db: Database,
private userId: string,
) {}

async set(key: string, value: string): Promise<void> {
await this.db.query(
'INSERT INTO oauth_tokens (user_id, key, value) VALUES (?, ?, ?) ON CONFLICT DO UPDATE SET value = ?',
[this.userId, key, value, value],
)
}

async get(key: string): Promise<string | undefined> {
const result = await this.db.query(
'SELECT value FROM oauth_tokens WHERE user_id = ? AND key = ?',
[this.userId, key],
)
return result?.[0]?.value
}

async delete(key: string): Promise<void> {
await this.db.query('DELETE FROM oauth_tokens WHERE user_id = ? AND key = ?', [
this.userId,
key,
])
}
}

const provider = new MCPOAuthClientProvider({
redirectUrl: 'http://localhost:3000/callback',
clientMetadata: {/* ... */},
storage: new DatabaseOAuthStorage(db, 'user-123'),
})

Exemples
Lien direct vers Exemples

Configuration statique des Tools
Lien direct vers Configuration statique des Tools

Pour les Tools qui utilisent une seule connexion au serveur MCP dans toute votre application, appelez listTools() et transmettez les Tools à votre Agent :

import { MCPClient } from '@mastra/mcp'
import { Agent } from '@mastra/core/agent'

const mcp = new MCPClient({
servers: {
stockPrice: {
command: 'npx',
args: ['tsx', 'stock-price.ts'],
env: {
API_KEY: 'your-api-key',
},
log: logMessage => {
console.log(`[${logMessage.level}] ${logMessage.message}`)
},
},
weather: {
url: new URL('http://localhost:8080/sse'),
},
},
timeout: 30000, // Global 30s timeout
})

// Create an agent with access to all tools
const agent = new Agent({
id: 'multi-tool-agent',
name: 'Multi-tool Agent',
instructions: 'You have access to multiple tool servers.',
model: 'openai/gpt-5.6-sol',
tools: await mcp.listTools(),
})

// Example of using resource methods
async function checkWeatherResource() {
try {
const weatherResources = await mcp.resources.list()
if (weatherResources.weather && weatherResources.weather.length > 0) {
const currentWeatherURI = weatherResources.weather[0].uri
const weatherData = await mcp.resources.read('weather', currentWeatherURI)
console.log('Weather data:', weatherData.contents[0].text)
}
} catch (error) {
console.error('Error fetching weather resource:', error)
}
}
checkWeatherResource()

// Example of using prompt methods
async function checkWeatherPrompt() {
try {
const weatherPrompts = await mcp.prompts.list()
if (weatherPrompts.weather && weatherPrompts.weather.length > 0) {
const currentWeatherPrompt = weatherPrompts.weather.find(p => p.name === 'current')
if (currentWeatherPrompt) {
console.log('Weather prompt:', currentWeatherPrompt)
} else {
console.log('Current weather prompt not found')
}
}
} catch (error) {
console.error('Error fetching weather prompt:', error)
}
}
checkWeatherPrompt()

Toolsets dynamiques
Lien direct vers Toolsets dynamiques

Lorsque chaque utilisateur nécessite une nouvelle connexion MCP, utilisez listToolsets() et ajoutez les Tools lors de l’appel de stream ou generate :

import { Agent } from '@mastra/core/agent'
import { MCPClient } from '@mastra/mcp'

// Create the agent first, without any tools
const agent = new Agent({
id: 'multi-tool-agent',
name: 'Multi-tool Agent',
instructions: 'You help users check stocks and weather.',
model: 'openai/gpt-5.6-sol',
})

// Later, configure MCP with user-specific settings
const mcp = new MCPClient({
servers: {
stockPrice: {
command: 'npx',
args: ['tsx', 'stock-price.ts'],
env: {
API_KEY: 'user-123-api-key',
},
timeout: 20000, // Server-specific timeout
},
weather: {
url: new URL('http://localhost:8080/sse'),
requestInit: {
headers: {
Authorization: `Bearer user-123-token`,
},
},
},
},
})

// Pass all toolsets to stream() or generate()
const response = await agent.stream('How is AAPL doing and what is the weather?', {
toolsets: await mcp.listToolsets(),
})

Gestion des instances
Lien direct vers Gestion des instances

La classe MCPClient intègre un mécanisme de prévention des fuites de mémoire pour gérer plusieurs instances :

  1. Créer plusieurs instances avec des configurations identiques sans id provoque une erreur afin d’éviter les fuites de mémoire
  2. Si plusieurs instances avec des configurations identiques sont nécessaires, fournissez un id unique à chacune
  3. Appelez await configuration.disconnect() avant de recréer une instance avec la même configuration
  4. Si une seule instance suffit, placez la configuration dans une portée supérieure afin d’éviter de la recréer

Par exemple, si vous tentez de créer plusieurs instances avec la même configuration sans id :

// First instance - OK
const mcp1 = new MCPClient({
servers: {/* ... */},
})

// Second instance with same config - Will throw an error
const mcp2 = new MCPClient({
servers: {/* ... */},
})

// To fix, either:
// 1. Add unique IDs
const mcp3 = new MCPClient({
id: 'instance-1',
servers: {/* ... */},
})

// 2. Or disconnect before recreating
await mcp1.disconnect()
const mcp4 = new MCPClient({
servers: {/* ... */},
})

Cycle de vie des serveurs
Lien direct vers Cycle de vie des serveurs

MCPClient gère proprement les connexions aux serveurs :

  1. Gestion automatique des connexions à plusieurs serveurs
  2. Arrêt propre des serveurs pour éviter les messages d’erreur pendant le développement
  3. Libération correcte des ressources lors de la déconnexion

Utiliser un fetch personnalisé pour l’authentification définie à l’exécution
Lien direct vers Utiliser un fetch personnalisé pour l’authentification définie à l’exécution

Pour les serveurs HTTP, vous pouvez fournir une fonction fetch personnalisée afin de gérer une authentification définie à l’exécution ou d’intercepter les requêtes. Elle peut aussi prendre en charge d’autres comportements personnalisés. Cette approche est particulièrement utile lorsque vous devez actualiser les jetons à chaque requête ou transmettre au serveur MCP les identifiants utilisateur issus de la requête entrante.

La fonction fetch personnalisée reçoit un troisième paramètre facultatif requestContext, qui donne accès aux données propres à la requête (par exemple, cookies d’authentification ou jetons bearer) définies par un middleware ou transmises lors de l’exécution d’un Agent ou d’un Tool. Le requestContext vaut null pendant l’établissement initial de la connexion.

Lorsque fetch est fourni, requestInit, eventSourceInit et authProvider deviennent facultatifs, car votre fonction fetch personnalisée peut prendre en charge ces aspects.

const mcpClient = new MCPClient({
servers: {
apiServer: {
url: new URL('https://api.example.com/mcp'),
fetch: async (url, init, requestContext) => {
const headers = new Headers(init?.headers)
// Forward auth cookie from the incoming request
const cookie = requestContext?.get('cookie')
if (cookie) {
headers.set('cookie', cookie)
}
return fetch(url, { ...init, headers })
},
},
},
})

// Use with an agent — requestContext is automatically forwarded
const agent = new Agent({
id: 'my-agent',
name: 'My Agent',
instructions: 'You are a helpful assistant.',
model: openai('gpt-5.4'),
tools: await mcpClient.listTools(),
})

await agent.generate('Hello!', {
requestContext: myRequestContext, // forwarded to the custom fetch
})

Gérer les échecs d’authentification dans un fetch personnalisé
Lien direct vers Gérer les échecs d’authentification dans un fetch personnalisé

Un fetch personnalisé ne doit pas utiliser throw lorsque l’authentification est indisponible. Le transport Streamable HTTP du SDK MCP ouvre en arrière-plan un flux « écouteur autonome » GET /mcp de longue durée pour recevoir les notifications envoyées par le serveur. Les erreurs de ce flux font l’objet de nouvelles tentatives avec temporisation exponentielle ; un fetch qui lève une exception ou un flux fermé proprement peut entraîner une boucle de reconnexion indéfinie, à raison d’environ une tentative par seconde.

Renvoyez plutôt une Response synthétique. La spécification MCP Streamable HTTP définit 405 Method Not Allowed comme le signal renvoyé par un serveur qui ne propose pas le flux GET SSE. Le SDK le traite comme un état final qui arrête proprement l’écouteur. Utilisez ce mécanisme pour désactiver l’écouteur lorsque votre serveur n’envoie pas de notifications.

Le modèle suivant attend un jeton d’authentification pour les requêtes POST, l’ajoute aux en-têtes sortants et court-circuite l’écouteur GET avec une réponse 405 synthétique :

async function waitForToken(timeoutMs = 5000): Promise<string | null> {
// Replace with your token lookup. Return null if no token is available.
return getAuthToken({ timeoutMs })
}

const mcpClient = new MCPClient({
servers: {
apiServer: {
url: new URL('https://api.example.com/mcp'),
fetch: async (url, init) => {
const method = (init?.method || 'GET').toUpperCase()

// The SDK opens a background GET stream for server-pushed notifications.
// If your server does not use it, short-circuit with 405 to stop reconnect attempts.
if (method === 'GET') {
return new Response(null, { status: 405, statusText: 'Method Not Allowed' })
}

// POST: wait for the token, then forward the request with an Authorization header.
const token = await waitForToken()
if (!token) {
// Forward the request without a token and let the server reject it.
// The SDK surfaces non-2xx POST responses as errors to the caller of
// tools/list, tools/call, etc., which is the desired behavior here.
return fetch(url, init)
}

const headers = new Headers(init?.headers)
headers.set('authorization', `Bearer ${token}`)
return fetch(url, { ...init, headers })
},
},
},
})

Ne renvoyez 405 pour l’écouteur GET que si votre serveur n’envoie pas de notifications au client. Si votre serveur utilise le flux GET autonome, ajoutez également le jeton d’authentification aux requêtes GET et laissez-les aboutir.

Utiliser des en-têtes de requête SSE
Lien direct vers Utiliser des en-têtes de requête SSE

Lorsque vous utilisez l’ancien transport MCP SSE, vous devez configurer à la fois requestInit et eventSourceInit en raison d’un bug du SDK MCP. Vous pouvez aussi employer une fonction fetch personnalisée, qui sera automatiquement utilisée pour les requêtes POST comme pour les connexions SSE :

// Option 1: Using requestInit and eventSourceInit (required for SSE)
const sseClient = new MCPClient({
servers: {
exampleServer: {
url: new URL('https://your-mcp-server.com/sse'),
// Note: requestInit alone isn't enough for SSE
requestInit: {
headers: {
Authorization: 'Bearer your-token',
},
},
// This is also required for SSE connections with custom headers
eventSourceInit: {
fetch(input: Request | URL | string, init?: RequestInit) {
const headers = new Headers(init?.headers || {})
headers.set('Authorization', 'Bearer your-token')
return fetch(input, {
...init,
headers,
})
},
},
},
},
})

// Option 2: Using custom fetch (simpler, works for both Streamable HTTP and SSE)
const sseClientWithFetch = new MCPClient({
servers: {
exampleServer: {
url: new URL('https://your-mcp-server.com/sse'),
fetch: async (url, init) => {
const headers = new Headers(init?.headers || {})
headers.set('Authorization', 'Bearer your-token')
return fetch(url, {
...init,
headers,
})
},
},
},
})