Objetivo del tema
Comprender cómo usar el SDK oficial de TypeScript de Qwen Code para ejecutar consultas de forma programática, incrustar el agente en aplicaciones Node.js, controlar permisos, trabajar con conversaciones multi-turno y exponer herramientas propias mediante MCP embebido.
Este tema se apoya en la documentación oficial disponible al 11 de abril de 2026, especialmente en Typescript SDK.
La documentación oficial define a @qwen-code/sdk como un SDK mínimo y experimental para acceder a Qwen Code de forma programática. Eso significa que, en lugar de usar siempre el CLI de manera interactiva, podés controlar al agente desde tu propio código.
Este cambio es muy importante conceptualmente. Hasta ahora en el curso vimos a Qwen Code como una herramienta para personas que escriben prompts en la terminal. Con el SDK, en cambio, pasa a ser también un componente integrable dentro de aplicaciones, servicios, automatizaciones o plataformas internas.
El SDK no reemplaza al CLI: se apoya en él. La idea es reutilizar la capacidad operativa de Qwen Code desde programas propios.
El SDK resulta especialmente útil cuando querés:
En otras palabras, el SDK aparece cuando la terminal sola ya no alcanza y necesitás que Qwen Code forme parte de otro sistema.
La documentación actual marca estos requisitos mínimos:
Node.js >= 20.0.0
Qwen Code >= 0.4.0 instalado y accesible en PATH
Además, la guía incluye una advertencia importante para usuarios de nvm: la autodetección del ejecutable puede fallar. En esos casos conviene especificar manualmente pathToQwenExecutable.
La instalación oficial es directa:
npm install @qwen-code/sdk
Esto agrega el paquete del SDK a tu proyecto, pero no elimina la necesidad de tener Qwen Code instalado. El SDK necesita encontrar el ejecutable del CLI para poder lanzar sesiones reales.
query()La documentación organiza casi todo el uso del SDK alrededor de una función principal:
import { query } from '@qwen-code/sdk';
query() crea una nueva sesión de consulta con Qwen Code. Puede usarse para un prompt simple o para una conversación de varias vueltas. El valor que devuelve es un objeto iterable de forma asíncrona, lo que permite ir recibiendo mensajes a medida que la sesión avanza.
La guía oficial propone un arranque como este:
import { query } from '@qwen-code/sdk';
const result = query({
prompt: '¿Qué archivos hay en el directorio actual?',
options: {
cwd: '/ruta/al/proyecto',
},
});
for await (const message of result) {
console.log(message);
}
La idea es sencilla: definís un prompt, indicás el directorio de trabajo y luego iterás sobre los mensajes que produce la sesión.
query()La documentación resume dos parámetros principales:
prompt: puede ser un string o un AsyncIterable<SDKUserMessage>options: un objeto QueryOptions con la configuración de la sesiónEsto es importante porque muestra dos modos mentales distintos:
| Opción | Función |
|---|---|
cwd |
Directorio de trabajo de la sesión. |
model |
Modelo a utilizar en esa consulta. |
pathToQwenExecutable |
Ruta explícita al ejecutable qwen. |
abortController |
Permite cancelar la sesión desde código. |
debug |
Activa logs detallados. |
maxSessionTurns |
Límite máximo de turnos conversacionales. |
coreTools |
Define qué herramientas base quedan disponibles. |
excludeTools |
Bloquea herramientas o patrones concretos. |
allowedTools |
Aprueba automáticamente herramientas que requieran confirmación. |
authType |
Tipo de autenticación, por ejemplo openai o qwen-oauth. |
agents |
Subagentes disponibles en esa sesión. |
includePartialMessages |
Emite mensajes parciales para streaming en tiempo real. |
Este conjunto de opciones deja claro que el SDK no es una simple envoltura decorativa. Expone bastante control sobre el comportamiento del agente.
El SDK entrega mensajes de distintos tipos mientras la consulta avanza. La documentación incluye type guards como:
import {
isSDKAssistantMessage,
isSDKResultMessage,
isSDKPartialAssistantMessage
} from '@qwen-code/sdk';
Esto permite distinguir entre:
Si activás includePartialMessages, podés construir interfaces tipo chat con streaming visible en tiempo real.
Uno de los puntos más interesantes del SDK es que no se limita a preguntas aisladas. También permite conversaciones multi-turno usando un AsyncIterable de mensajes de usuario.
import { query, type SDKUserMessage } from '@qwen-code/sdk';
async function* generateMessages(): AsyncIterable<SDKUserMessage> {
yield { type: 'user', message: 'Explicá la estructura del proyecto' };
yield { type: 'user', message: 'Ahora proponé una refactorización mínima' };
}
const result = query({
prompt: generateMessages(),
options: {
cwd: '/ruta/al/proyecto',
},
});
Este patrón es útil cuando querés conectar Qwen Code a una interfaz propia, a una cola de eventos o a un flujo generado dinámicamente por tu aplicación.
La instancia devuelta por query() no solo se itera. También expone métodos operativos importantes:
const q = query({ prompt: 'Hola', options: {} });
const sessionId = q.getSessionId();
const closed = q.isClosed();
await q.interrupt();
await q.setPermissionMode('yolo');
await q.setModel('qwen-max');
await q.close();
Esto permite controlar una sesión viva sin reiniciarla. Por ejemplo, podrías cambiar de modelo o de modo de permisos mientras una interfaz gráfica sigue usando la misma conversación.
El SDK incorpora los mismos grandes modos de permisos que ya vimos en el CLI, pero ahora controlados desde código:
defaultplanauto-edityoloLa documentación describe su comportamiento así:
| Modo | Comportamiento |
|---|---|
default |
Las herramientas de escritura se niegan salvo aprobación explícita o allowlist. |
plan |
Bloquea herramientas no solo de lectura y fuerza una planificación previa. |
auto-edit |
Aprueba edición de archivos, pero no el resto de herramientas sensibles. |
yolo |
Aprueba todas las herramientas automáticamente. |
La documentación del SDK insiste en un detalle fino que conviene entender bien: no todas las reglas de permiso pesan lo mismo. El orden actual es:
excludeToolspermissionMode: 'plan'permissionMode: 'yolo'allowedToolscanUseToolEsto es importante porque evita errores de diseño. Por ejemplo, no sirve aprobar una herramienta en allowedTools si antes la bloqueaste con excludeTools.
canUseToolUna de las capacidades más potentes del SDK es poder decidir desde código si una herramienta debe ejecutarse o no. La documentación muestra el callback canUseTool para ese fin.
const result = query({
prompt: 'Creá un archivo nuevo',
options: {
canUseTool: async (input) => {
if (input.toolName === 'write_file') {
return { behavior: 'allow', updatedInput: input };
}
return { behavior: 'deny', message: 'Operación no permitida' };
},
},
});
Este mecanismo es ideal cuando tu aplicación necesita reglas de aprobación propias, por ejemplo según usuario, entorno, horario, repositorio o tipo de archivo.
El SDK define timeouts por defecto para varias operaciones sensibles. La documentación actual enumera estos:
canUseTool: 1 minutomcpRequest: 1 minutocontrolRequest: 1 minutostreamClose: 1 minutoTambién se pueden personalizar:
const result = query({
prompt: 'Tu consulta',
options: {
timeout: {
canUseTool: 60000,
mcpRequest: 600000,
controlRequest: 60000,
streamClose: 15000
}
}
});
Esto resulta útil cuando un servidor MCP tarda mucho o cuando tu aplicación necesita una política de espera más estricta.
El SDK puede usar servidores MCP externos exactamente igual que el CLI. La documentación muestra un patrón como este:
const result = query({
prompt: 'Usá la herramienta personalizada de mi servidor MCP',
options: {
mcpServers: {
'my-server': {
command: 'node',
args: ['path/to/mcp-server.js'],
env: { PORT: '3000' }
}
}
}
});
Esto significa que tu aplicación puede lanzar una sesión con Qwen Code y, al mismo tiempo, conectarla a herramientas externas sin pasar por la configuración global del usuario.
tool() y createSdkMcpServer()Uno de los puntos más potentes del SDK es que permite crear herramientas MCP que viven dentro del mismo proceso de tu aplicación. Para eso existen dos piezas:
tool()createSdkMcpServer()La documentación explica que esto evita correr un servidor MCP separado cuando solo querés exponer algunas herramientas internas simples.
import { z } from 'zod';
import { query, tool, createSdkMcpServer } from '@qwen-code/sdk';
const calculatorTool = tool(
'calculate_sum',
'Suma dos números',
{ a: z.number(), b: z.number() },
async (args) => ({
content: [{ type: 'text', text: String(args.a + args.b) }],
}),
);
const server = createSdkMcpServer({
name: 'calculator',
tools: [calculatorTool],
});
const result = query({
prompt: '¿Cuánto es 42 + 17?',
options: {
permissionMode: 'yolo',
mcpServers: {
calculator: server,
},
},
});
Este patrón es excelente para prototipos, aplicaciones internas y asistentes integrados donde necesitás exponer una o dos herramientas propias sin desplegar infraestructura adicional.
La opción agents permite declarar subagentes disponibles en la sesión creada por el SDK. Esto es coherente con lo que ya vimos en el tema de subagentes: la aplicación puede decidir qué especialistas ofrecerle al agente principal en cada contexto.
Eso vuelve posible construir experiencias muy controladas, por ejemplo una aplicación de revisión de código que siempre incluya un revisor de seguridad y un generador de pruebas.
La documentación también cubre cancelación explícita con AbortController:
import { query, isAbortError } from '@qwen-code/sdk';
const abortController = new AbortController();
const result = query({
prompt: 'Tarea larga...',
options: {
abortController,
},
});
setTimeout(() => abortController.abort(), 5000);
Esto es fundamental para aplicaciones reales. Si integrás Qwen Code en una UI, un job o un backend, necesitás poder interrumpir operaciones largas cuando el usuario cancela o cuando el sistema impone un timeout mayor.
| Problema | Causa probable | Primer paso razonable |
|---|---|---|
| El SDK no encuentra el ejecutable | Qwen Code no está en PATH o falla la autodetección. | Usar pathToQwenExecutable. |
| La consulta no puede escribir archivos | El modo de permisos o la política por defecto lo bloquea. | Revisar permissionMode, allowedTools y canUseTool. |
| Una herramienta MCP tarda demasiado | El timeout por defecto resulta insuficiente. | Ajustar timeout.mcpRequest. |
Con nvm no arranca bien |
La ruta del binario no se detecta correctamente. | Declarar la ruta manualmente al ejecutable. |
| La app recibe mensajes difíciles de procesar | No se distinguen los tipos de mensaje emitidos. | Usar type guards como isSDKAssistantMessage. |
cwd de forma explícita para evitar contexto ambiguo.yolo por defecto en aplicaciones multiusuario o sensibles.El SDK de TypeScript convierte a Qwen Code en una pieza reutilizable dentro de aplicaciones Node.js. En lugar de limitarse a la terminal interactiva, el agente puede ser invocado, controlado y extendido desde código.
En este tema vimos las ideas centrales:
@qwen-code/sdk.query() es la puerta principal para consultas simples o conversaciones multi-turno.Con esta base, el siguiente paso natural es cerrar el recorrido con buenas prácticas, diagnóstico y troubleshooting, donde se consolidan muchos de los conceptos operativos vistos a lo largo del curso.