Pulse-ready topologies
This pattern covers what a topology needs to be a good Pulse tool: a clear description, the right shape for returning data, and output formatting done inside the topology.
1. Add an MCP description #
Author a description-first mcp_description so the LLM can select the tool and validate arguments:
{
"description": "Returns tomorrow's weather report for a city. Use when the user asks about the forecast.",
"exposed": true,
"input_schema": {
"type": "object",
"properties": { "city": { "type": "string", "description": "City to report on." } },
"required": ["city"]
}
}
See Getting started with Pulse for every field.
2. Return data with a response node #
If the tool should return a result (a query), end the topology with a response node. The data at that node is delivered back to the caller through the reply callback. Without a response node the topology is a fire-and-forget command. See Async and the response node.
3. Format the output inside the topology #
A query result is returned verbatim and is never sent back through the model by default, because it can carry sensitive data. If you want formatted output (a readable report, a trimmed payload), do it in a worker node before the response node.
import ACommonNode from '@orchesty/nodejs-sdk/dist/lib/Commons/ACommonNode';
import ProcessDto from '@orchesty/nodejs-sdk/dist/lib/Utils/ProcessDto';
export default class WeatherReportNode extends ACommonNode {
public getName(): string {
return 'weather-report';
}
public processAction(dto: ProcessDto): ProcessDto {
const { city, degrees } = dto.getJsonData();
return dto.setData(`Weather report\n\n${city}\nTomorrow temperature: ${degrees}`);
}
}
Only opt into model-side reformatting (llm_format: true) for tools whose output is safe to pass through the model. See confirmation and output.
4. Use the caller identity when needed #
If the process acts on behalf of a person (filing a request, looking up the caller's own records), read the protected identity header. See Caller identity.