@chinchillaenterprises/mcp-upwork
Version:
Modular Upwork MCP server for job search and proposal management via Upwork API
110 lines (97 loc) • 3.22 kB
text/typescript
import axios, { AxiosInstance, AxiosError } from "axios";
import { McpError, ErrorCode } from "@modelcontextprotocol/sdk/types.js";
export class UpworkClient {
private static instance: UpworkClient;
private client: AxiosInstance;
private apiKey: string;
private apiSecret: string;
private accessToken: string;
constructor() {
// Get credentials from environment variables
this.apiKey = process.env.UPWORK_API_KEY || "";
this.apiSecret = process.env.UPWORK_API_SECRET || "";
this.accessToken = process.env.UPWORK_ACCESS_TOKEN || "";
if (!this.apiKey || !this.apiSecret) {
throw new Error("UPWORK_API_KEY and UPWORK_API_SECRET environment variables are required");
}
// Initialize Upwork API client
this.client = axios.create({
baseURL: "https://www.upwork.com/api",
timeout: 30000,
headers: {
"Authorization": `Bearer ${this.accessToken}`,
"Content-Type": "application/json",
"User-Agent": "ChillMCP-Upwork/1.0.0"
},
});
}
public getClient(): AxiosInstance {
return this.client;
}
public static getInstance(): UpworkClient {
if (!UpworkClient.instance) {
UpworkClient.instance = new UpworkClient();
}
return UpworkClient.instance;
}
public async get(endpoint: string, params?: any): Promise<any> {
try {
const response = await this.client.get(endpoint, { params });
return response.data;
} catch (error) {
throw this.handleError(error);
}
}
public async post(endpoint: string, data?: any): Promise<any> {
try {
const response = await this.client.post(endpoint, data);
return response.data;
} catch (error) {
throw this.handleError(error);
}
}
public handleError(error: any): McpError {
if (axios.isAxiosError(error)) {
const axiosError = error as AxiosError;
if (axiosError.response) {
const status = axiosError.response.status;
const data = axiosError.response.data as any;
switch (status) {
case 401:
return new McpError(
ErrorCode.InvalidRequest,
"Authentication failed. Please check your API credentials."
);
case 403:
return new McpError(
ErrorCode.InvalidRequest,
"Access forbidden. Please check your API permissions."
);
case 404:
return new McpError(
ErrorCode.InvalidRequest,
"Resource not found."
);
case 429:
return new McpError(
ErrorCode.InvalidRequest,
"Rate limit exceeded. Please try again later."
);
default:
return new McpError(
ErrorCode.InternalError,
`Upwork API error: ${data?.message || axiosError.message}`
);
}
}
return new McpError(
ErrorCode.InternalError,
`Network error: ${axiosError.message}`
);
}
return new McpError(
ErrorCode.InternalError,
`Unexpected error: ${error instanceof Error ? error.message : String(error)}`
);
}
}