Fix TypeScript errors and update Dockerfile for Alpine compatibility
This commit is contained in:
21
Dockerfile
21
Dockerfile
@@ -8,7 +8,8 @@ RUN apk add --no-cache \
|
|||||||
make \
|
make \
|
||||||
python3 \
|
python3 \
|
||||||
curl \
|
curl \
|
||||||
ca-certificates
|
ca-certificates \
|
||||||
|
vips-dev
|
||||||
|
|
||||||
# Configure npm for better reliability
|
# Configure npm for better reliability
|
||||||
RUN npm config set strict-ssl false
|
RUN npm config set strict-ssl false
|
||||||
@@ -16,18 +17,24 @@ RUN npm config set registry https://registry.npmjs.org/
|
|||||||
RUN npm config set fetch-retry-mintimeout 20000
|
RUN npm config set fetch-retry-mintimeout 20000
|
||||||
RUN npm config set fetch-retry-maxtimeout 120000
|
RUN npm config set fetch-retry-maxtimeout 120000
|
||||||
|
|
||||||
# Copy package files
|
# Install global packages needed for build
|
||||||
COPY package*.json ./
|
RUN npm install -g typescript shx
|
||||||
|
|
||||||
# Clean npm cache and install dependencies
|
# Copy package files and modify to prevent prepare script from running
|
||||||
|
COPY package*.json ./
|
||||||
|
RUN node -e "const pkg = require('./package.json'); delete pkg.scripts.prepare; require('fs').writeFileSync('./package.json', JSON.stringify(pkg, null, 2));"
|
||||||
|
|
||||||
|
# Install dependencies without running the prepare script, including sharp with the correct platform
|
||||||
RUN npm cache clean --force && \
|
RUN npm cache clean --force && \
|
||||||
npm install --legacy-peer-deps --no-optional
|
npm install --legacy-peer-deps --no-optional && \
|
||||||
|
npm install --platform=linuxmusl --arch=x64 sharp
|
||||||
|
|
||||||
# Copy source code
|
# Copy source code
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
# Build TypeScript code
|
# Build TypeScript code manually
|
||||||
RUN npm run build
|
RUN npx tsc && \
|
||||||
|
npx shx chmod +x dist/*.js
|
||||||
|
|
||||||
# Switch to production for runtime
|
# Switch to production for runtime
|
||||||
ENV NODE_ENV=production
|
ENV NODE_ENV=production
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import axios, { AxiosError, AxiosInstance } from 'axios';
|
import axios, { AxiosError, AxiosInstance } from 'axios';
|
||||||
import { McpError } from '@modelcontextprotocol/sdk/types.js';
|
import { McpError, ErrorCode } from '@modelcontextprotocol/sdk/types.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Client for interacting with the OpenRouter API
|
* Client for interacting with the OpenRouter API
|
||||||
@@ -90,7 +90,7 @@ export class OpenRouterAPIClient {
|
|||||||
if (axiosError.response) {
|
if (axiosError.response) {
|
||||||
const responseData = axiosError.response.data as any;
|
const responseData = axiosError.response.data as any;
|
||||||
const message = responseData?.error?.message || axiosError.message;
|
const message = responseData?.error?.message || axiosError.message;
|
||||||
throw new McpError('RequestFailed', `OpenRouter API error: ${message}`);
|
throw new McpError(ErrorCode.InternalError, `OpenRouter API error: ${message}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,17 +114,17 @@ export class OpenRouterAPIClient {
|
|||||||
const message = responseData?.error?.message || axiosError.message;
|
const message = responseData?.error?.message || axiosError.message;
|
||||||
|
|
||||||
if (status === 401 || status === 403) {
|
if (status === 401 || status === 403) {
|
||||||
throw new McpError('Unauthorized', `Authentication error: ${message}`);
|
throw new McpError(ErrorCode.InvalidRequest, `Authentication error: ${message}`);
|
||||||
} else if (status === 429) {
|
} else if (status === 429) {
|
||||||
throw new McpError('RateLimitExceeded', `Rate limit exceeded: ${message}`);
|
throw new McpError(ErrorCode.InternalError, `Rate limit exceeded: ${message}`);
|
||||||
} else {
|
} else {
|
||||||
throw new McpError('RequestFailed', `OpenRouter API error (${status}): ${message}`);
|
throw new McpError(ErrorCode.InternalError, `OpenRouter API error (${status}): ${message}`);
|
||||||
}
|
}
|
||||||
} else if (axiosError.request) {
|
} else if (axiosError.request) {
|
||||||
throw new McpError('NetworkError', `Network error: ${axiosError.message}`);
|
throw new McpError(ErrorCode.ConnectionClosed, `Network error: ${axiosError.message}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new McpError('UnknownError', `Unknown error: ${error.message || 'No error message'}`);
|
throw new McpError(ErrorCode.InternalError, `Unknown error: ${error.message || 'No error message'}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { promises as fs } from 'fs';
|
import { promises as fs } from 'fs';
|
||||||
import sharp from 'sharp';
|
import sharp from 'sharp';
|
||||||
import { McpError } from '@modelcontextprotocol/sdk/types.js';
|
import { McpError, ErrorCode } from '@modelcontextprotocol/sdk/types.js';
|
||||||
import OpenAI from 'openai';
|
import OpenAI from 'openai';
|
||||||
|
|
||||||
export interface AnalyzeImageToolRequest {
|
export interface AnalyzeImageToolRequest {
|
||||||
@@ -21,7 +21,7 @@ export async function handleAnalyzeImage(
|
|||||||
// Validate image path
|
// Validate image path
|
||||||
const imagePath = args.image_path;
|
const imagePath = args.image_path;
|
||||||
if (!path.isAbsolute(imagePath)) {
|
if (!path.isAbsolute(imagePath)) {
|
||||||
throw new McpError('InvalidParams', 'Image path must be absolute');
|
throw new McpError(ErrorCode.InvalidParams, 'Image path must be absolute');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read image file
|
// Read image file
|
||||||
@@ -85,7 +85,7 @@ export async function handleAnalyzeImage(
|
|||||||
// Call OpenRouter API
|
// Call OpenRouter API
|
||||||
const completion = await openai.chat.completions.create({
|
const completion = await openai.chat.completions.create({
|
||||||
model,
|
model,
|
||||||
messages,
|
messages: messages as any,
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { McpError } from '@modelcontextprotocol/sdk/types.js';
|
import { McpError, ErrorCode } from '@modelcontextprotocol/sdk/types.js';
|
||||||
import { ModelCache } from '../model-cache.js';
|
import { ModelCache } from '../model-cache.js';
|
||||||
|
|
||||||
export interface GetModelInfoToolRequest {
|
export interface GetModelInfoToolRequest {
|
||||||
@@ -26,7 +26,7 @@ export async function handleGetModelInfo(
|
|||||||
|
|
||||||
const model = modelCache.getModel(args.model);
|
const model = modelCache.getModel(args.model);
|
||||||
if (!model) {
|
if (!model) {
|
||||||
throw new McpError('NotFound', `Model '${args.model}' not found`);
|
throw new McpError(ErrorCode.InvalidParams, `Model '${args.model}' not found`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import fetch from 'node-fetch';
|
import fetch from 'node-fetch';
|
||||||
import sharp from 'sharp';
|
import sharp from 'sharp';
|
||||||
import { McpError } from '@modelcontextprotocol/sdk/types.js';
|
import { McpError, ErrorCode } from '@modelcontextprotocol/sdk/types.js';
|
||||||
import OpenAI from 'openai';
|
import OpenAI from 'openai';
|
||||||
|
|
||||||
export interface MultiImageAnalysisToolRequest {
|
export interface MultiImageAnalysisToolRequest {
|
||||||
@@ -90,11 +90,11 @@ export async function handleMultiImageAnalysis(
|
|||||||
try {
|
try {
|
||||||
// Validate inputs
|
// Validate inputs
|
||||||
if (!args.images || args.images.length === 0) {
|
if (!args.images || args.images.length === 0) {
|
||||||
throw new McpError('InvalidParams', 'At least one image is required');
|
throw new McpError(ErrorCode.InvalidParams, 'At least one image is required');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!args.prompt) {
|
if (!args.prompt) {
|
||||||
throw new McpError('InvalidParams', 'A prompt is required');
|
throw new McpError(ErrorCode.InvalidParams, 'A prompt is required');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare content array for the message
|
// Prepare content array for the message
|
||||||
@@ -137,7 +137,7 @@ export async function handleMultiImageAnalysis(
|
|||||||
messages: [{
|
messages: [{
|
||||||
role: 'user',
|
role: 'user',
|
||||||
content
|
content
|
||||||
}]
|
}] as any
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
Reference in New Issue
Block a user