@nutrient-sdk/dws-mcp-server
Version:
MCP server for Nutrient DWS Processor API
117 lines (116 loc) • 4.22 kB
JavaScript
import path from 'path';
import fs from 'fs';
import axios from 'axios';
import { createSuccessResponse } from '../responses.js';
/**
* Converts a readable stream to a string
* @param responseData The readable stream to convert
* @returns A promise that resolves to the string content of the stream
*/
export async function pipeToString(responseData) {
const chunks = [];
return new Promise((resolve, reject) => {
responseData.on('data', (chunk) => chunks.push(Buffer.from(chunk)));
responseData.on('end', () => resolve(Buffer.concat(chunks).toString('utf8')));
responseData.on('error', (err) => reject(err));
});
}
/**
* Converts a readable stream to a buffer
* @param responseData The readable stream to convert
* @returns A promise that resolves to the buffer content of the stream
*/
export async function pipeToBuffer(responseData) {
const chunks = [];
return new Promise((resolve, reject) => {
responseData.on('data', (chunk) => chunks.push(Buffer.from(chunk)));
responseData.on('end', () => resolve(Buffer.concat(chunks)));
responseData.on('error', (err) => reject(err));
});
}
/**
* Validates that the API key is set in the environment
* @returns Object with error information if API key is not set
*/
export function getApiKey() {
if (!process.env.NUTRIENT_DWS_API_KEY) {
throw new Error('NUTRIENT_DWS_API_KEY not set in environment');
}
return process.env.NUTRIENT_DWS_API_KEY;
}
/**
* Handles API errors and converts them to a standard format
* @returns Object with error information
* @param e
*/
export async function handleApiError(e) {
if (axios.isAxiosError(e) && e.response?.data) {
try {
const errorString = await pipeToString(e.response.data);
try {
const errorJson = JSON.parse(errorString);
// Check if the error response matches the expected format
if (errorJson.details && (errorJson.status || errorJson.requestId || errorJson.failingPaths)) {
// This appears to be a HostedErrorResponse format
return {
content: [
{
type: 'text',
text: JSON.stringify(errorJson, null, 2),
isError: true,
},
],
isError: true,
};
}
}
catch (_) {
// ts-expect-error We can allow an empty block as we'll fall through to default error handling.
}
return {
content: [{ type: 'text', text: `Error processing API response: ${errorString}` }],
isError: true,
};
}
catch (streamError) {
return {
content: [
{
type: 'text',
text: `Error processing API response: ${streamError instanceof Error ? streamError.message : String(streamError)}`,
},
],
isError: true,
};
}
}
else {
const errorString = e instanceof Error ? e.message : String(e);
return {
content: [{ type: 'text', text: `Error: ${errorString}` }],
isError: true,
};
}
}
/**
* Handle file response
*/
export async function handleFileResponse(response, resolvedOutputPath, successMessage) {
const resultBuffer = await pipeToBuffer(response.data);
const outputDir = path.dirname(resolvedOutputPath);
try {
await fs.promises.access(outputDir);
}
catch {
await fs.promises.mkdir(outputDir, { recursive: true });
}
await fs.promises.writeFile(resolvedOutputPath, resultBuffer);
return createSuccessResponse(`${successMessage} and saved to: ${resolvedOutputPath}`);
}
/**
* Handle JSON content response
*/
export async function handleJsonContentResponse(response) {
const resultString = await pipeToString(response.data);
return createSuccessResponse(resultString);
}