← Files Biological Sequence & Alignment ViewerARCHIVED FILE
src/views/scientific-platform-client.ts
6.52 KB · Sep 30, 2026 · 23:01 UTC
import type { App } from "@modelcontextprotocol/ext-apps";
import { z } from "zod";
import type { SequenceNativeCheckpointClient } from "../persistent/durable-viewer-state";
import type { ScientificSequenceDataClient } from "../persistent/scientific-data-client";
import {
SEQUENCE_LIST_SCIENTIFIC_RECORDS_TOOL_NAME,
SEQUENCE_PLUGIN_SCIENTIFIC_SOURCE_META_KEY,
SEQUENCE_READ_SCIENTIFIC_WINDOW_TOOL_NAME,
SEQUENCE_RESTORE_SCIENTIFIC_CHECKPOINT_TOOL_NAME,
SEQUENCE_SAVE_SCIENTIFIC_CHECKPOINT_TOOL_NAME,
sequenceScientificSourceSchema,
type SequenceScientificSource,
} from "../scientific-platform-protocol";
const recordPageSchema = z.object({
complete: z.boolean(),
cursor: z.string(),
nextCursor: z.string().nullable(),
records: z
.array(
z.object({
description: z.string(),
id: z.string().min(1),
sequenceLength: z.number().int().nonnegative(),
}),
)
.max(256),
sourceRevision: z.string(),
});
const sequenceWindowSchema = z.object({
end1Decimal: z.string(),
quality: z.string().optional(),
sequence: z.string().max(64 * 1_024),
sourceRevision: z.string(),
start1Decimal: z.string(),
});
const checkpointReceiptSchema = z.object({
checkpointVersion: z.literal(1),
lastAcknowledgedRevision: z.number().int().nonnegative(),
logicalSessionId: z.string().uuid(),
recoveryReference: z.string(),
});
const restoredCheckpointSchema = z.discriminatedUnion("hasCheckpoint", [
z.object({ hasCheckpoint: z.literal(false) }),
z.object({
checkpointBase64: z.string(),
hasCheckpoint: z.literal(true),
lastAcknowledgedRevision: z.number().int().nonnegative(),
recoveryReference: z.string(),
sourceRevision: z.string(),
}),
]);
export function parsePluginScientificSequenceSource(
metadata: unknown,
): SequenceScientificSource | null {
if (metadata == null || typeof metadata !== "object") return null;
const candidate = Object.hasOwn(
metadata,
SEQUENCE_PLUGIN_SCIENTIFIC_SOURCE_META_KEY,
)
? metadata[SEQUENCE_PLUGIN_SCIENTIFIC_SOURCE_META_KEY as keyof typeof metadata]
: undefined;
const parsed = sequenceScientificSourceSchema.safeParse(candidate);
return parsed.success ? parsed.data : null;
}
/** Standard app-only MCP tools: no host extensions, HTTP, or native grants. */
export class PluginScientificSequenceDataClient
implements SequenceNativeCheckpointClient
{
readonly session: SequenceNativeCheckpointClient["session"];
constructor(
private readonly app: Pick<App, "callServerTool">,
readonly source: SequenceScientificSource,
) {
this.session = {
backendGeneration: 0,
backendInstanceId: "sequence-plugin-mcp",
family: "sequence",
logicalSessionId: source.sessionId,
sourceRevision: source.sourceRevision,
};
}
async listRecords(
input: Parameters<ScientificSequenceDataClient["listRecords"]>[0],
): ReturnType<ScientificSequenceDataClient["listRecords"]> {
const result = recordPageSchema.parse(
await this.#request(
SEQUENCE_LIST_SCIENTIFIC_RECORDS_TOOL_NAME,
{
...(input.cursor == null ? {} : { cursor: input.cursor }),
limit: input.limit,
},
input.signal,
),
);
this.#assertRevision(result.sourceRevision);
return result;
}
async readResidueWindow(
input: Parameters<ScientificSequenceDataClient["readResidueWindow"]>[0],
): ReturnType<ScientificSequenceDataClient["readResidueWindow"]> {
const result = sequenceWindowSchema.parse(
await this.#request(
SEQUENCE_READ_SCIENTIFIC_WINDOW_TOOL_NAME,
{
end1Decimal: input.end1Decimal,
includeQuality: input.includeQuality === true,
recordNumber: input.recordNumber,
start1Decimal: input.start1Decimal,
},
input.signal,
),
);
this.#assertRevision(result.sourceRevision);
if (
input.includeQuality === true &&
(result.quality == null || result.quality.length !== result.sequence.length)
) {
throw new Error("The Sequence quality window does not match its residues.");
}
return result;
}
async checkpoint(
input: Parameters<SequenceNativeCheckpointClient["checkpoint"]>[0],
): ReturnType<SequenceNativeCheckpointClient["checkpoint"]> {
const receipt = checkpointReceiptSchema.parse(
await this.#request(
SEQUENCE_SAVE_SCIENTIFIC_CHECKPOINT_TOOL_NAME,
{
checkpointBase64: encodeBase64(input.checkpoint),
lastAcknowledgedRevision: input.lastAcknowledgedRevision,
},
input.signal,
),
);
if (receipt.logicalSessionId !== this.source.sessionId) {
throw new Error("The Sequence checkpoint belongs to another viewer.");
}
return receipt;
}
async restoreCheckpoint(
input?: Parameters<SequenceNativeCheckpointClient["restoreCheckpoint"]>[0],
): ReturnType<SequenceNativeCheckpointClient["restoreCheckpoint"]> {
const restored = restoredCheckpointSchema.parse(
await this.#request(
SEQUENCE_RESTORE_SCIENTIFIC_CHECKPOINT_TOOL_NAME,
{},
input?.signal,
),
);
if (!restored.hasCheckpoint) return restored;
this.#assertRevision(restored.sourceRevision);
const { checkpointBase64, ...receipt } = restored;
return { ...receipt, checkpoint: decodeBase64(checkpointBase64) };
}
async #request(
name: string,
arguments_: Record<string, unknown>,
signal?: AbortSignal,
): Promise<unknown> {
signal?.throwIfAborted();
const result = await this.app.callServerTool(
{
arguments: {
...arguments_,
sessionId: this.source.sessionId,
sourceId: this.source.sourceId,
sourceRevision: this.source.sourceRevision,
},
name,
},
signal == null ? undefined : { signal },
);
signal?.throwIfAborted();
if (result.isError) {
throw new Error("The plugin-owned Sequence source request was refused.");
}
return result.structuredContent;
}
#assertRevision(revision: string): void {
if (revision !== this.source.sourceRevision) {
throw new Error("The Sequence source changed after it was opened.");
}
}
}
function encodeBase64(bytes: Uint8Array): string {
let binary = "";
for (let offset = 0; offset < bytes.byteLength; offset += 8_192) {
binary += String.fromCharCode(...bytes.subarray(offset, offset + 8_192));
}
return btoa(binary);
}
function decodeBase64(value: string): Uint8Array {
const binary = atob(value);
return Uint8Array.from(binary, (character) => character.charCodeAt(0));
}
SHA-256: 6f9e3962d799bd585f475803950d5ad5a36e57f633528bb6f0791cd9fabedbc3