CWL to MCP crosswalk¶
This page describes the current converter and export plugin. The plugin generates Tool definitions; it does not execute CWL, provide an MCP server, or generate artifact receipts.
Process fields¶
| CWL source | Resulting JSON | Current mapping |
|---|---|---|
Nonempty mcp:Tool.name, otherwise process id |
name |
A mapping hint's literal name is preserved. The fallback process ID is not normalized. |
Nonempty mcp:Tool.title, otherwise label |
title |
Omitted when neither supplies a nonempty value. |
Nonempty process doc |
description |
Passed directly to the model. There is no hint description override or appended guidance. |
inputs |
inputSchema |
Result of BaseCWLtypes2OGCConverter.get_inputs_json_schema(). |
outputs |
outputSchema |
Result of BaseCWLtypes2OGCConverter.get_outputs_json_schema(). |
mcp:Tool.annotations |
annotations |
Copies all four behavioral booleans, including false. Omitted when no hint is found. |
Nonempty mcp:Tool.aliases |
_meta["<prefix>-aliases"] |
Preserves the list. |
Nonempty mcp:Tool.useWhen |
_meta["<prefix>-use_when"] |
Preserves the string without changing description. |
Nonempty mcp:Tool.doNotUseWhen |
_meta["<prefix>-do_not_use_when"] |
Preserves the string without changing description. |
The default prefix is transpiler-mate.github.io/cwl2mcp; configure it with
--meta-prefix. The converter always supplies _meta, even when it is {}.
See output configuration.
The generated MCP model requires a name of 1–128
ASCII letters, digits, underscores, dots, or hyphens. A URI-valued fallback ID can
therefore fail validation. Supply an explicit callable name in the hint.
description must be a string; lists of CWL documentation paragraphs are not
joined by the converter and can fail model validation.
Hint selection and validation¶
Only process.hints is searched. The first matching Tool is used; later matches
are not rejected. requirements is not searched for MCP hints. Class names may
be full URIs or use any process namespace prefix bound to
https://eoap.github.io/cwl-mcp-extension#.
A complete hint for the EOAP example is:
hints:
agent:Tool:
name: inspect_source
title: Inspect Source
aliases: [inspect a spatial source]
useWhen: the user needs to inspect a spatial source.
doNotUseWhen: the user needs data modification.
annotations:
readOnlyHint: true
destructiveHint: false
idempotentHint: true
openWorldHint: false
The document must bind agent to the extension namespace. See the
hint source schema and
generated hint reference for field definitions.
title is optional. aliases, useWhen, doNotUseWhen, annotations, and all
four annotation booleans are required by the current mapping loader; empty
aliases/guidance values are allowed but omitted from _meta. The schema declares
name as an identifier string; Salad can synthesize a missing identifier, so an
explicit MCP-compatible name should always be provided.
annotations.class may be omitted. If supplied, it must identify Annotations.
Tool.description is not a declared hint field and is rejected. Unknown
unqualified fields and invalid field values raise validation errors. Already
constructed Tool instances are returned unchanged rather than revalidated.
Parameter schemas and EOAP conversion¶
The project pins cwl2ogc in pyproject.toml. Its schemas
are copied directly into the Tool; this plugin does not add parameter titles,
join parameter documentation, register extra formats, or provide a custom File
receipt schema. Inspect the emitted schema for the resulting types, defaults,
required fields, and definitions.
For the current EOAP example, the input schema contains definitions equivalent to these excerpts:
{
"source": {"type": "string", "format": "uri"},
"timestamp": {"type": "string", "format": "date-time"}
}
Properties refer to them through $ref values such as #/$defs/source.
URI and DateTime records are flattened into scalar strings. The GeoJSON Point
remains an object requiring type, coordinates, and bbox. Its coordinate and
bounding-box values are arrays of numbers. The output schema uses corresponding
source_result, timestamp_result, and point_result fields.
Thus the CWL arguments fixture, which
wraps URI and timestamp values in {"value": ...}, needs adaptation before it
can satisfy the exported MCP input schema. See the
tutorial for a matching MCP argument object.
Format validation requires a format-aware JSON Schema validator.
Example metadata output¶
The EOAP example produces this metadata excerpt, alongside its input and output schemas:
{
"name": "inspect_source",
"title": "Inspect Source",
"description": "Return a source URI, timestamp and GeoJSON point without changing their records.",
"annotations": {
"readOnlyHint": true,
"destructiveHint": false,
"idempotentHint": true,
"openWorldHint": false
},
"_meta": {
"transpiler-mate.github.io/cwl2mcp-aliases": ["inspect a spatial source"],
"transpiler-mate.github.io/cwl2mcp-use_when": "the user needs to inspect a spatial source.",
"transpiler-mate.github.io/cwl2mcp-do_not_use_when": "the user needs data modification."
}
}
Export container¶
| CLI source | Export |
|---|---|
tests/examples/eoap.cwl#main |
One MCP Tool object. |
tests/examples/eoap.cwl |
A mapping such as {"main": <Tool>}. |
JSON aliases are used and fields whose value is None are omitted. Keys are
sorted, indentation is two spaces, and output ends with a newline. The plugin
creates parent directories and completes conversion before opening the output
file. It does not perform an atomic file replacement.
The runtime requires software application metadata before plugin execution;
the direct Python conversion API only needs a parsed process and a
metadata prefix. A whole-document export is a plugin container, not an MCP
tools/list response. See using definitions in MCP.