Skip to main content
Glama

skill-mcp

Un servidor MCP que sirve un directorio de Agent Skills. Apúntalo a skills; las lista, entrega sus instrucciones y sus archivos empaquetados, y ejecuta solo los scripts que una skill declara.

Es un adaptador genérico, no un conjunto curado: las skills son contenido que lee, y la misma compilación sirve para aquello a lo que se apunte.

npx @chrischall/skill-mcp                       # serves the example skill bundled here
SKILLS_DIR=~/my-skills npx @chrischall/skill-mcp

El paquete npm es @chrischall/skill-mcp (skill-mcp sin scope está ocupado por otra persona en npm). Todo lo demás — el repositorio, el binario, la identidad de registro io.github.chrischall/skill-mcp — no tiene scope.

Qué es una skill

Un directorio que contiene SKILL.md: frontmatter YAML (name, description y opcionalmente el bloque mcp-host: más abajo) seguido de instrucciones, más los archivos a los que esas instrucciones hagan referencia. Bajo cada raíz se encuentran tres estructuras:

<root>/SKILL.md              # the root IS one skill
<root>/<name>/SKILL.md       # a directory of skills
<root>/skills/<name>/SKILL.md

Una skill se sirve bajo el nombre de su DIRECTORIO, nunca bajo el name de su propio frontmatter (un name de frontmatter que discrepa se notifica y por lo demás se ignora; cuando la raíz misma es la skill, el directorio raíz le da nombre). Es una regla de seguridad, no de orden: la concesión del propietario nombra una skill, así que un paquete que pudiera elegir su propio nombre podría reclamar el de su vecina y recibir el script y las variables concedidos a la vecina. Por la misma razón, dos directorios que de verdad contribuyen con un mismo nombre — solo posible entre dos raíces — son ambos rechazados y notificados, en lugar de que uno gane por orden de escaneo.

Related MCP server: MCP Skills Server

Las herramientas

herramienta

argumentos

devuelve

skill_list

—

todas las skills encontradas: nombre, descripción, cuándo usarla, número de archivos, si declara scripts ejecutables y exactamente cuáles; además de problems, para que una lista vacía nunca sea un misterio

skill_load

name

el cuerpo de SKILL.md textualmente, más un manifiesto de los archivos del paquete. Los archivos referenciados no se incrustan — para eso está skill_file

skill_file

name, path

un archivo del directorio de esa skill: texto, o base64 con su tipo de medio. Como máximo 1 MiB, con truncated: true en lugar de un corte silencioso

skill_run

name, script, args[], confirm

{exitCode, stdout, stderr, truncated, durationMs}

skill_file acepta una ruta. El diseño de referencia especifica un lote paths[] (8 rutas por llamada, 1 MiB por entrada, 4 MiB por llamada, una ruta mala falla solo en su propio slot); publicar la forma singular es un aplazamiento deliberado, no un descuido, y esos tres límites son los que un cambio posterior de procesamiento por lotes debe respetar. Lee los topes como límites del propio heap de este servidor: limitan la asignación, no solo la respuesta, porque un hijo alojado tiene un límite duro de datos de 256 MiB y un paquete puede ser más grande que eso.

Cada skill se registra también como prompt MCP (su cuerpo es el mensaje) y cada archivo empaquetado como recurso (skill://<name>/<path>), porque un cliente que soporta esas superficies presenta una skill mejor de lo que lo hace una llamada a herramienta. Es una segunda puerta, nunca la única: cuando este servidor se ejecuta en mcp-host y un registro restringe enabledTools, prompts/list y resources/list vuelven vacías y el handshake deja de anunciar esas capacidades — así que las herramientas sostienen toda la experiencia.

El descubrimiento informa, nunca se calla

Cualquier cosa que impida que un directorio sea servido aparece en problems de skill_list, con la ruta y el motivo: falta SKILL.md, frontmatter que no se puede parsear, un nombre que dos directorios reclaman (ambos rechazados), un script declarado que no está en el paquete, un symlink que sale de la raíz o de una skill, un nombre de archivo al que las herramientas de lectura no pudieron dirigirse. Una skill mala solo se perjudica a sí misma y nunca al listado, y no hay un tercer resultado en el que algo se descarte en silencio — un directorio de skill con symlink se sirve cuando permanece dentro de la raíz (así que skills/foo -> ../shared/foo funciona) y se notifica cuando no.

La valla de ejecución

skill_run ejecuta código de terceros. Cada regla siguiente restringe qué código se ejecuta y qué se le entrega; cada una tiene su propia prueba.

  • Solo un script que la skill DECLARA. No "cualquier archivo bajo scripts/", no "cualquier cosa ejecutable". Una ruta no declarada se rechaza, diciendo que debe ser declarada y enumerando las que lo están.

  • Solo dentro del propio directorio de esa skill. La ruta se comprueba primero como cadena (segmentos simples; sin / inicial, sin . ni .., sin barra invertida, sin escape de porcentaje, sin NUL) y luego de nuevo tras la resolución: la ruta real, con los symlinks seguidos, debe seguir estando dentro del directorio real de la skill, y debe ser un archivo regular. Ambas comprobaciones, porque una comprobación de cadena por sí sola no detecta un symlink plantado dentro del paquete, y una comprobación resuelta por sí sola acepta formas que nunca deberían haberse unido. La misma disciplina rige skill_file: una lectura fuera del directorio de una skill es, en el mejor de los casos, el paquete de otra skill.

  • Un array argv, nunca una cadena de shell. spawn con shell: false, sin interpolación, sin sh -c. Los argumentos se pasan tal cual.

  • Un intérprete de un conjunto cerrado, nombrado por la declaración — nunca inferido de la extensión y nunca tomado del shebang del propio archivo, ya que un archivo que puede elegir su propio intérprete ya ha elegido su propio programa. v1 ejecuta node y nada más (ver Lo que v1 no puede ejecutar).

  • Acotado, y la llamada siempre retorna. Un timeout de tiempo real (60 s por defecto, anulable por script, con un techo duro de 300 s), 1 MiB capturado por flujo con truncated: true en lugar de un corte silencioso, y un solo skill_run a la vez. Al agotarse el timeout se señala al grupo de procesos, lo que alcanza al script y a cualquier hijo que haya permanecido en su grupo. No alcanza a un nieto que se haya separado a un grupo propio, y ese nieto también mantiene abiertos los pipes de stdio — así que la ejecución se resuelve con la salida del proceso más un drenaje corto, bajo un plazo duro, en lugar de esperar a que los pipes se cierren. Eso es lo que garantiza que la llamada a la herramienta retorne dentro de su presupuesto y libere el bloqueo de uno a la vez; no es una garantía de que un nieto deliberadamente separado esté muerto. Acotar eso es trabajo del nivel (un uid sin privilegios, prlimit NPROC y una máquina que se detiene), no de este adaptador.

  • Una lista blanca de entorno. Un script recibe PATH, HOME, LANG, TZ, TMPDIR, MCP_DATA_DIR cuando el host ha establecido una, y exactamente las variables que ese script pidió y que el propietario concedió — nunca el entorno propio de este servidor. La mitad fija refleja INSTALL_ALLOWLIST de mcp-host (packages/runner-node/src/spawn-env.ts), por la razón que da ese archivo: una constante del host que una declaración alojada no puede ampliar ni en un nombre.

  • Una salida distinta de cero es un resultado normal y notificado — el código de salida, stdout y stderr vuelven todos. Nunca es una excepción que pierda la salida.

  • skill_run está sujeto a confirmación. Sin confirm: true no inicia ningún proceso y devuelve una vista previa de dry-run de exactamente lo que se ejecutaría: el intérprete, el argv, el directorio de trabajo, el timeout y los nombres de las variables que recibiría el script.

Por qué la compuerta de confirmación es general

La convención de la flota pone una compuerta a las herramientas mutadoras. Que un script dado mute algo es algo que este servidor no puede saber: nunca lee un script, y deliberadamente no lo analiza — un veredicto generado por máquina sobre el código de otro se acepta de una manera en que no se acepta la declaración de un autor. Por tanto, los efectos desconocidos se tratan como mutadores.

El suavizado obvio — permitir que una skill marque un script como de solo lectura y omitir la compuerta para él — se rechaza porque es circular: el mismo autor escribió el script y la frase que lo describe, así que un «read-only» autodeclarado no autoriza nada. Eso deja una compuerta general. Su coste es un viaje de ida y vuelta extra en un helper de solo lectura; su beneficio es que la vista previa es el único lugar donde quien llama ve la llamada exacta antes de que ocurra nada.

Lo que la valla NO garantiza

Un script declarado sigue siendo código arbitrario. Estas reglas restringen qué código se ejecuta y con qué; ninguna hace que el código sea seguro. Un script que permitas puede leer todo el árbol de skills, gastar la CPU de la máquina y enviar lo que tenga a cualquier lugar que su red permita. Los topes de salida de skill_run son truncamiento, no confidencialidad: nada censura el stdout de un script, y nada podría.

Esto no es un sandbox. Ejecútalo contra skills que hayas leído, o ejecútalo en algún sitio que lo cerque — bajo mcp-host eso significa el nivel aislado (fly-machine): una microVM por registro, un uid sin privilegios, límites prlimit y nftables con denegación por defecto y una lista blanca de salida declarada. Este servidor es una restricción encima de esa valla, no un sustituto de una.

Lo que v1 no puede ejecutar

El conjunto de intérpretes es node, una sola entrada, y es una decisión meditada más que un descuido: la imagen de runner de mcp-host es Node + git + tar + util-linux + nftables, sin python3, curl ni jq, mientras que las skills reales son abrumadoramente Python (70 .py frente a 1 .js en anthropics/skills en 3b3fad96).

Así que una skill que declara un script Python es notificada por skill_list en unavailableScripts, con el intérprete y el conjunto de este despliegue nombrados, y skill_run la rechaza con las mismas palabras. Sus instrucciones siguen sirviendo — una skill solo de instrucciones es una skill útil, y la mayoría de las skills publicadas son exactamente eso. Un intérprete fijado es un seguimiento que llega como dependencia, nunca como un cambio de imagen.

El bloque de declaración mcp-host:

Opcional, dentro del frontmatter de SKILL.md:

---
name: weather
description: Forecasts and geocoding.
mcp-host:
  version: 1
  run:
    - script: scripts/forecast.js
      interpreter: node
      env: [WEATHER_API_KEY]     # variables this SCRIPT asks for
      timeout: 30                # seconds; clamped to 300
  env:                           # fields proposed for the SERVER's environment
    - name: WEATHER_API_KEY
      secret: true
  egress: [api.weather.example]  # hosts this skill reaches; a proposal
---

Una declaración restringe; nunca concede. El autor de los scripts también escribió el bloque que los nombra, así que nada en él es una autorización — dice qué archivos son puntos de entrada y qué quiere cada uno. Lo que hace que un script sea ejecutable, y que una variable llegue a él, es que otra persona lo acepte.

Se lee estrictamente: esquema central YAML 1.2, anclas y alias rechazados, un tope de 64 KiB, una versión MAJOR desconocida rechazada en bloque, claves desconocidas ignoradas y notificadas por nombre, y un bloque que no parsea se notifica con la posición del parser en lugar de tratarse como ausente. Un bloque roto le cuesta a una skill sus scripts, nunca sus instrucciones, y nunca el resto del listado.

Configuración

variable

significado

MCP_SKILLS_PATH

raíces de slots separadas por :, inyectadas por el runner de mcp-host. Gana sobre todo

SKILLS_DIR

lo mismo para uso local. Se lee solo cuando MCP_SKILLS_PATH no está definido

MCP_SKILL_RUN

JSON opcional [{skill, script, env?}] — la concesión del propietario. Solo restringe

(ninguno definido)

el directorio skills/ propio de este paquete

MCP_SKILL_RUN merece el énfasis. Cuando está presente, lo que puede ejecutarse es la declaración intersecada con él — una fila que nombre un script que la skill no declaró no concede nada (y se notifica), y una fila que nombre una variable que el script no pidió no concede nada. No hay ninguna forma de escribirlo que haga ejecutable algo que una skill no declaró, que es lo que hace seguro leerlo de un entorno que también lleva las variables propias de un registro.

Cuando está ausente, el valor predeterminado depende de si un host inició este proceso hijo, y la mitad alojada es de cierre ante fallos.

  • Alojado — cualquier variable que el runner de mcp-host inyecta está presente (MCP_SKILLS_PATH, MCP_HOST_METER_FILE, MCP_DATA_DIR, MCP_BLOB_BASE_URL): no se concede nada y no se ejecuta nada. Las instrucciones y los archivos de cada skill se siguen sirviendo — eso es un conector funcional y útil. La razón es que un proceso hijo contiene un único entorno con todas las credenciales que el propietario estableció, así que una skill cuyo frontmatter nombrara la variable de su vecino recibiría la credencial del vecino sin que nadie hubiera decidido entregársela. Deliberadamente no se basa únicamente en MCP_SKILLS_PATH: mcp-host aún no inyecta esa variable, así que hoy el único canal alojado es SKILLS_DIR en el env simple de un registro, y eso no debe caer en el valor predeterminado abierto. La comprobación del marcador solo puede mover el valor predeterminado en la dirección de cierre ante fallos.

  • Independiente — ningún marcador inyectado en absoluto: la declaración de la propia skill se mantiene. Nada está inyectando nada, y la persona que apuntó el servidor a un directorio es el propietario.

skill_list informa de qué caso es (grantFrom, más un grantNote en el alojado) y enumera los scripts declarados pero no concedidos de una skill, de modo que «no se ejecuta nada» nunca sea indistinguible de «no se declaró nada».

Postura de confianza

  • El código de este servidor es del operador; las skills son tuyas. Lee un conjunto fijo de directorios que se le entregan, no obtiene nada, no instala nada y no tiene ninguna herramienta que acepte una ruta fuera del directorio de la propia skill.

  • No examina nada. No hay insignia, ni lista de permitidos de editores, ni escaneo. Las instrucciones de una skill y sus scripts son exactamente tan fiables como quien los escribió.

  • Una lectura se trata con el mismo peligro que una ejecución, porque el directorio del que lee está junto a todo lo demás en la máquina.

  • No guarda nada en caché ni almacena nada. El catálogo se escanea una vez al arrancar y se mantiene en memoria; no se escribe ningún archivo en ningún sitio.

Alojamiento en mcp-host

mint.yaml en la raíz del repositorio indica cómo quiere registrarse este MCP. Cuatro cosas que deliberadamente no propone, porque solo un registro puede decidirlas:

  • El runtime — y no podría, por regla. Un manifiesto nunca puede nombrarlo (docs/MINT-MANIFEST.md §5): en qué nivel aterriza un registro lo decide quién lo solicita, no el paquete, ya que un archivo que pudiera pedir fly-shared sería el paquete de un desconocido solicitando un asiento en la propia máquina del operador. Un servidor de skills alojado pertenece al nivel aislado (fly-machine) con una política de egreso declarada, y esa es la decisión que debe tomar el registro.

  • Las propias skills. Llegan como una dependencia fijada (un github-archive que nombra un repositorio y un commit exacto) y aterrizan en un espacio de solo lectura que el runner nombra mediante MCP_SKILLS_PATH. Este paquete no puede saber cuáles lleva un registro determinado.

  • state.dataDir. El adaptador no necesita persistencia. Actívalo cuando las skills de un registro tengan scripts que necesiten un lugar donde escribir — el espacio es de solo lectura, así que MCP_DATA_DIR (con él activado) o TMPDIR (sin él) es donde va la salida de un script — y da la razón allí.

  • La lista de permitidos de egreso real. mint.yaml propone allow: [], que es lo que el propio adaptador necesita: no alcanza nada. Los hosts que necesita un registro son los que declaran sus SKILLS, mostrados en la vista previa con quién los declaró y aceptados por el propietario. En el nivel aislado, un host que no está en la lista aparece como un HTTP 403 del proxy de bucle local o como un simple timeout — los dos son indistinguibles desde dentro de un script, así que skill_run adjunta una nota que lo dice siempre que una llamada falla en una máquina que parece cercada.

Reducir enabledTools a [skill_list, skill_load, skill_file] es el interruptor no ejecutable, aplicado en la puerta de enlace en lugar de aquí — una declaración más contundente que el rechazo de skill_run por parte de este servidor, y sacrifica por completo las superficies de prompt y de recursos.

Desarrollo

npm install
npm run build      # tsc → dist/, esbuild → dist/bundle.js
npm test           # tsc typecheck + vitest

Este proyecto fue desarrollado y es mantenido por IA. Úsalo bajo tu propio criterio.

Available Tools

4 tools
skill_fileA
Read-onlyIdempotent

Read files a skill bundles. Paths are relative to that skill's own directory; text comes back as text, anything else as base64 with its media type. Ask for every file you need in ONE call — a SKILL.md usually points at several.

NameRequiredDescriptionDefault
nameYesThe skill's name, exactly as skill_list reports it.
pathsYesUp to 8 paths relative to the skill's own directory, as skill_load lists them. Reading a SKILL.md's referenced files in one call costs one round trip instead of one each.

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover read-only, idempotent, and closed-world semantics, so the bar is lower. The description adds real behavioral context beyond them: paths resolve against the skill's own directory, text is returned as text while other content comes back as base64 with a media type, and a single call replaces several round trips. It omits error behavior for missing paths, keeping it from a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, front-loaded with what the tool does, then path semantics, return format, and the batching instruction. Every sentence carries information and none is redundant.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description correctly takes on the burden of describing return values (text vs base64 plus media type) and the call-batching model. For a two-parameter read tool this is nearly complete; only failure handling for bad paths is unaddressed.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and the schema already documents both name and paths, including the relative-path semantics and the 8-item cap. The description reinforces the relative-path rule and adds the batching rationale but introduces no syntax or format detail the schema lacks, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description gives a specific verb and resource — reading files that a skill bundles — and scopes it to the skill's own directory, which cleanly separates it from skill_list and skill_run. It stops short of explicitly naming a sibling to disambiguate against, so it lands at 4 rather than 5.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It advises batching ('Ask for every file you need in ONE call') and explains why (a SKILL.md usually points at several), which implies usage after a skill load. However, it never says when to reach for skill_file versus skill_load or skill_list, so the routing guidance is only implied.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

skill_listA
Read-onlyIdempotent

List every Agent Skill this server found: name, description, when to use it, how many files it bundles, and the exact scripts (if any) that may be executed with skill_run. Also reports anything that could not be read, so an empty list is never a mystery.

NameRequiredDescriptionDefault

No parameters

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover the safety profile (readOnly, idempotent, closed-world), so the description's value-add is its disclosure of failure behavior: unreadable entries are reported so 'an empty list is never a mystery.' That is genuinely useful operational context beyond the annotations, though it doesn't mention ordering, limits, or staleness.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, both front-loaded and information-dense: the first enumerates the returned fields, the second covers the failure mode. No filler or restatement of the tool name.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema and no parameters, the description carries the full burden and discharges it by naming the exact fields returned and the error-reporting behavior. An agent knows what it gets back and how to interpret an empty response.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters, so there is nothing to document beyond the schema; baseline 4 applies. The description instead spends its budget on the return shape, which is the relevant semantic content here.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Names a specific verb and resource ('List every Agent Skill this server found') and enumerates exactly what the listing contains: name, description, when-to-use, bundled file count, and executable scripts. It also implicitly differentiates itself from skill_run by noting scripts 'may be executed with skill_run', making the read-vs-execute split with siblings clear.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Pointing at skill_run for execution implies this is the discovery step before loading or running a skill, so usage is inferable. However, it never states when to call this versus skill_load or skill_file, nor any conditions or exclusions, leaving the routing to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

skill_loadA
Read-onlyIdempotent

Load one skill's SKILL.md instructions verbatim, plus a manifest of the files it bundles. Referenced files are NOT inlined — read them by name with skill_file.

NameRequiredDescriptionDefault
nameYesThe skill's name, exactly as skill_list reports it.

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover the safety profile (readOnly, idempotent, non-open-world), so the bar is lower. The description adds real behavioral value by disclosing exactly what is returned — verbatim instructions plus a manifest — and what is deliberately withheld (referenced file contents).

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, zero filler, with the core return contract front-loaded and the skill_file handoff immediately after. Every clause carries information an agent needs.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description carries the return-value burden and does so adequately by naming the two payload components and the non-inlined rule. It stops short of describing manifest structure, but that is a minor gap for a simple loader.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the single parameter is fully described in the schema, including that the name must match skill_list output. The description adds no additional parameter semantics, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Load one skill's SKILL.md instructions') and defines the payload precisely (verbatim instructions plus a bundled-file manifest). It implicitly separates itself from skill_file by noting referenced files are not inlined.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives an explicit boundary condition: bundled files are not inlined, so the agent must use skill_file to read them by name. It does not spell out that skill_list should run first, though the parameter description ties the name to skill_list output.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

skill_runA
Destructive

Execute a script the skill DECLARES as runnable, with an argument array. Returns the exit code and the captured output; a non-zero exit is a normal, reported outcome. Asks the user to confirm first: a confirmation prompt where the client supports one (unless MCP_CONFIRM_ELICITATION=off); otherwise the first call returns a preview of exactly what would run and a confirmToken, and only a repeat call with that token proceeds (see MCP_CONFIRM_MODE).

NameRequiredDescriptionDefault
argsNoArguments passed as an argv array. There is no shell: nothing here is interpreted.
nameYesThe skill's name, exactly as skill_list reports it.
scriptYesThe exact script path skill_list reports for this skill.
confirmTokenNoONLY for the two-step confirmation fallback (a client without MCP elicitation). The confirmToken from this same tool's phase-1 "confirmation-required" response, passed back ONLY after the user has seen that preview and explicitly approved it in chat — never on the first call, never invented, never reused. Call again with the same arguments. Ignored when the client supports elicitation.

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare destructive=true, openWorld=true, non-idempotent, but the description adds substantial value beyond them: non-zero exit is a normal reported outcome (not an error), what is returned (exit code plus captured output), and the full two-phase confirmation protocol including environment flags (MCP_CONFIRM_ELICITATION, MCP_CONFIRM_MODE) and the confirmToken handshake. This is exactly the extra context annotations cannot convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The core action and return semantics are front-loaded in the first sentence, with confirmation behavior second. It is dense with parenthetical config detail but nearly every clause carries operational weight, so little is wasted.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a mutation tool with no output schema, the description covers the return payload (exit code and captured output), the non-zero-exit interpretation, and the entire confirmation lifecycle. An agent has everything needed to invoke it correctly and safely without further documentation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and the schema already documents all four parameters, including the confirmToken fallback semantics and the no-shell argv behavior. The description only restates the argument-array concept, adding no syntax or format detail beyond the schema, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('Execute a script the skill DECLARES as runnable, with an argument array') and constrains scope to scripts the skill has marked runnable, which distinguishes it from skill_list, skill_load, and skill_file. An agent can tell what this does without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides a clear precondition (the script must be declared runnable by the skill) and describes the required confirmation flow in detail. It does not explicitly name the sibling tools or say when to prefer skill_file/skill_load instead, but the execution context is unambiguous.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 1 tool updatev1.1.0
    • Changedskill_run2 fields changed
      • removedInput schema / properties / confirm
        Removed value: -{
        -  "description": "Must be true to proceed. Without this, the tool returns a preview.",
        -  "type": "boolean"
        -}
      • addedInput schema / properties / confirmToken
        Added value: +{
        +  "description": "ONLY for the two-step confirmation fallback (a client without MCP elicitation). The confirmToken from this same tool's phase-1 \"confirmation-required\" response, passed back ONLY after the user has seen that preview and explicitly approved it in chat — never on the first call, never invented, never reused. Call again with the same arguments. Ignored when the client supports elicitation.",
        +  "type": "string"
        +}
  2. 4 tool updatesv0.3.0
    • Changedskill_file1 field changed
      • changedInput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
    • Changedskill_list1 field changed
      • changedInput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
    • Changedskill_load1 field changed
      • changedInput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
    • Changedskill_run1 field changed
      • changedInput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
  3. 4 tool updatesv0.1.0
    • First observedskill_file
    • First observedskill_list
    • First observedskill_load
    • First observedskill_run

TDQS

A4.3/5.0

Scored across 4 tools

Disambiguation5/5

Each tool targets a distinct stage of the skill lifecycle: listing skills, loading a SKILL.md, reading bundled files, and executing declared scripts. There is no overlap—file reading and script execution are clearly separated, and descriptions reinforce the boundaries.

Naming Consistency5/5

All four tools use a uniform skill_<verb> pattern (skill_list, skill_load, skill_file, skill_run). The convention is predictable and readable throughout.

Tool Count5/5

Four tools is well-scoped for a skill-discovery and execution server. Each tool earns its place with no redundant or filler operations.

Completeness5/5

The surface covers the full lifecycle: enumerate skills, load instructions, read bundled files, and run declared scripts, with clear guidance on chaining (e.g. read files after load). No obvious gaps or dead ends for the stated purpose.

Maintenance

ActivityActive
ResponsivenessUnresponsive

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    C
    maintenance
    Converts AI Skills (following Claude Skills format) into MCP server resources, enabling LLM applications to discover, access, and utilize self-contained skill directories through the Model Context Protocol. Provides tools to list available skills, retrieve skill details and content, and read supporting files with security protections.
    3
    44 PyPI
    29
    Apache 2.0
  • A
    license
    Not graded
    quality
    C
    maintenance
    Turns any folder of Markdown agent skills into a local MCP server, exposing them as tools, prompts, and resources for MCP-compatible clients.
    MIT