Publish @classroomio/mcp package

This commit is contained in:
Rotimi Best
2026-03-13 18:01:46 +01:00
parent 6e6f825e89
commit 77a1188573
9 changed files with 531 additions and 0 deletions
+99
View File
@@ -0,0 +1,99 @@
import type {
TCourseImportDraftCreate,
TCourseImportDraftPublish,
TCourseImportDraftUpdate
} from '@cio/utils/validation/course-import';
import type { McpServerConfig } from './config.js';
type ApiSuccess<T> = {
success: true;
data: T;
};
type ApiFailure = {
success?: false;
error?: string;
message?: string;
code?: string;
field?: string;
};
export class ClassroomIoApiError extends Error {
constructor(
message: string,
public status: number,
public code?: string,
public field?: string
) {
super(message);
this.name = 'ClassroomIoApiError';
}
}
export class ClassroomIoApiClient {
constructor(private readonly config: McpServerConfig) {}
async createCourseDraft(payload: TCourseImportDraftCreate) {
return this.request('/organization/course-import/drafts', {
method: 'POST',
body: payload
});
}
async getCourseDraft(draftId: string) {
return this.request(`/organization/course-import/drafts/${draftId}`, {
method: 'GET'
});
}
async updateCourseDraft(draftId: string, payload: TCourseImportDraftUpdate) {
return this.request(`/organization/course-import/drafts/${draftId}`, {
method: 'PUT',
body: payload
});
}
async publishCourseDraft(draftId: string, payload: TCourseImportDraftPublish) {
return this.request(`/organization/course-import/drafts/${draftId}/publish`, {
method: 'POST',
body: payload
});
}
private async request<TResponse>(
path: string,
options: {
method: 'GET' | 'POST' | 'PUT';
body?: unknown;
}
): Promise<TResponse> {
const response = await fetch(new URL(path, this.config.CLASSROOMIO_API_URL), {
method: options.method,
headers: {
Authorization: `Bearer ${this.config.CLASSROOMIO_API_KEY}`,
'content-type': 'application/json',
'user-agent': this.config.CLASSROOMIO_USER_AGENT
},
body: options.body ? JSON.stringify(options.body) : undefined
});
const json = (await response.json().catch(() => null)) as ApiSuccess<TResponse> | ApiFailure | null;
if (!response.ok) {
const errorPayload = json as ApiFailure | null;
throw new ClassroomIoApiError(
errorPayload?.error ?? errorPayload?.message ?? `ClassroomIO request failed with status ${response.status}`,
response.status,
errorPayload?.code,
errorPayload?.field
);
}
if (!json || typeof json !== 'object' || !('success' in json) || !json.success) {
throw new ClassroomIoApiError('ClassroomIO returned an invalid response payload', response.status);
}
return json.data;
}
}