feat: initial commit - Jhonny Editor
- Adicionado estrutura completa do projeto - Configurado MCP server para Premiere Pro - Adicionado documentação e skills - Configurado Gitignore para o projeto
This commit is contained in:
+172
@@ -0,0 +1,172 @@
|
||||
import { describe, it, expect, vi, beforeEach } from "vitest";
|
||||
import { createServer, SERVER_VERSION } from "../src/server.js";
|
||||
import { readFileSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
import { z } from "zod";
|
||||
import { Client, InMemoryTransport } from "@modelcontextprotocol/client";
|
||||
|
||||
const { getDiscoveryTools } = vi.hoisted(() => ({
|
||||
getDiscoveryTools: vi.fn(() => ({
|
||||
mock_discovery_tool: {
|
||||
description: "A mock discovery tool",
|
||||
parameters: {
|
||||
type: "object",
|
||||
properties: {
|
||||
name: { type: "string", description: "Name param" },
|
||||
},
|
||||
required: ["name"],
|
||||
},
|
||||
handler: vi.fn().mockResolvedValue({ success: true, data: { found: true } }),
|
||||
},
|
||||
})),
|
||||
}));
|
||||
|
||||
// Mock all tool modules to return simple tool definitions
|
||||
vi.mock("../src/bridge/file-bridge.js", () => ({
|
||||
sendCommand: vi.fn().mockResolvedValue({ success: true, data: {} }),
|
||||
sendRawCommand: vi.fn().mockResolvedValue({ success: true, data: {} }),
|
||||
getTempDir: vi.fn().mockReturnValue("/tmp/test"),
|
||||
cleanupTempDir: vi.fn(),
|
||||
}));
|
||||
|
||||
// We need the real tool modules to verify registration,
|
||||
// but mock sendCommand so handlers don't actually do file I/O
|
||||
vi.mock("../src/tools/discovery.js", () => ({
|
||||
getDiscoveryTools,
|
||||
}));
|
||||
|
||||
vi.mock("../src/tools/project.js", () => ({ getProjectTools: () => ({}) }));
|
||||
vi.mock("../src/tools/media.js", () => ({ getMediaTools: () => ({}) }));
|
||||
vi.mock("../src/tools/sequence.js", () => ({ getSequenceTools: () => ({}) }));
|
||||
vi.mock("../src/tools/timeline.js", () => ({ getTimelineTools: () => ({}) }));
|
||||
vi.mock("../src/tools/effects.js", () => ({ getEffectsTools: () => ({}) }));
|
||||
vi.mock("../src/tools/transitions.js", () => ({ getTransitionsTools: () => ({}) }));
|
||||
vi.mock("../src/tools/audio.js", () => ({ getAudioTools: () => ({}) }));
|
||||
vi.mock("../src/tools/text.js", () => ({ getTextTools: () => ({}) }));
|
||||
vi.mock("../src/tools/markers.js", () => ({ getMarkerTools: () => ({}) }));
|
||||
vi.mock("../src/tools/tracks.js", () => ({ getTrackTools: () => ({}) }));
|
||||
vi.mock("../src/tools/playhead.js", () => ({ getPlayheadTools: () => ({}) }));
|
||||
vi.mock("../src/tools/metadata.js", () => ({ getMetadataTools: () => ({}) }));
|
||||
vi.mock("../src/tools/export.js", () => ({ getExportTools: () => ({}) }));
|
||||
vi.mock("../src/tools/media-analysis.js", () => ({ getMediaAnalysisTools: () => ({}) }));
|
||||
vi.mock("../src/tools/interchange-analysis.js", () => ({ getInterchangeAnalysisTools: () => ({}) }));
|
||||
vi.mock("../src/tools/advanced.js", () => ({ getAdvancedTools: () => ({}) }));
|
||||
vi.mock("../src/tools/keyframes.js", () => ({ getKeyframeTools: () => ({}) }));
|
||||
vi.mock("../src/tools/scripting.js", () => ({ getScriptingTools: () => ({}) }));
|
||||
vi.mock("../src/tools/inspection.js", () => ({ getInspectionTools: () => ({}) }));
|
||||
vi.mock("../src/tools/selection.js", () => ({ getSelectionTools: () => ({}) }));
|
||||
vi.mock("../src/tools/clipboard.js", () => ({ getClipboardTools: () => ({}) }));
|
||||
vi.mock("../src/tools/source-monitor.js", () => ({ getSourceMonitorTools: () => ({}) }));
|
||||
vi.mock("../src/tools/track-targeting.js", () => ({ getTrackTargetingTools: () => ({}) }));
|
||||
vi.mock("../src/tools/utility.js", () => ({ getUtilityTools: () => ({}) }));
|
||||
vi.mock("../src/tools/health.js", () => ({ getHealthTools: () => ({}) }));
|
||||
vi.mock("../src/tools/workspace.js", () => ({ getWorkspaceTools: () => ({}) }));
|
||||
vi.mock("../src/tools/captions.js", () => ({ getCaptionTools: () => ({}) }));
|
||||
vi.mock("../src/tools/playback.js", () => ({ getPlaybackTools: () => ({}) }));
|
||||
vi.mock("../src/tools/project-manager.js", () => ({ getProjectManagerTools: () => ({}) }));
|
||||
vi.mock("../src/resources/extendscript-reference.js", () => ({
|
||||
EXTENDSCRIPT_REFERENCE: "mock reference",
|
||||
}));
|
||||
|
||||
describe("createServer", () => {
|
||||
it("returns an McpServer instance", () => {
|
||||
const server = createServer({});
|
||||
expect(server).toBeDefined();
|
||||
expect(typeof server.registerTool).toBe("function");
|
||||
expect(typeof server.registerResource).toBe("function");
|
||||
expect(typeof server.connect).toBe("function");
|
||||
});
|
||||
|
||||
it("registers tools from all modules", () => {
|
||||
const toolSpy = vi.fn();
|
||||
const originalTool = createServer({}).registerTool;
|
||||
|
||||
// Create a new server and spy on tool registration
|
||||
const server = createServer({});
|
||||
// The server should have been created successfully with registered tools
|
||||
expect(server).toBeDefined();
|
||||
});
|
||||
|
||||
it("does not throw with empty bridge options", () => {
|
||||
expect(() => createServer({})).not.toThrow();
|
||||
});
|
||||
|
||||
it("does not throw with custom bridge options", () => {
|
||||
expect(() =>
|
||||
createServer({ tempDir: "/custom/tmp", timeoutMs: 5000 })
|
||||
).not.toThrow();
|
||||
});
|
||||
|
||||
it("reuses immutable tool definitions for equivalent server configurations", () => {
|
||||
getDiscoveryTools.mockClear();
|
||||
const bridgeOptions = { tempDir: "/tmp/server-static-catalog-cache" };
|
||||
|
||||
createServer(bridgeOptions);
|
||||
createServer(bridgeOptions);
|
||||
|
||||
expect(getDiscoveryTools).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("registers and serves the bounded live context resources", async () => {
|
||||
const server = createServer({});
|
||||
const client = new Client({ name: "live-resource-test", version: "1.0.0" });
|
||||
const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
|
||||
await Promise.all([server.connect(serverTransport), client.connect(clientTransport)]);
|
||||
|
||||
try {
|
||||
const resources = await client.listResources();
|
||||
expect(resources.resources.map((resource) => resource.uri)).toEqual(expect.arrayContaining([
|
||||
"premiere://project/info",
|
||||
"premiere://project/sequences",
|
||||
"premiere://project/media",
|
||||
"premiere://project/bins",
|
||||
"premiere://timeline/active",
|
||||
"premiere://effects/available",
|
||||
"premiere://effects/applied",
|
||||
"premiere://transitions/available",
|
||||
"premiere://export/presets",
|
||||
"premiere://project/metadata",
|
||||
]));
|
||||
|
||||
const read = await client.readResource({ uri: "premiere://project/info" });
|
||||
expect(JSON.parse(read.contents[0].text as string)).toMatchObject({
|
||||
ok: true,
|
||||
resource: "premiere://project/info",
|
||||
resourceSchemaVersion: 1,
|
||||
});
|
||||
} finally {
|
||||
await client.close();
|
||||
await server.close();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("jsonSchemaToInputSchema (tested via createServer)", () => {
|
||||
// We test the schema adapter indirectly by verifying the server
|
||||
// successfully registers tools with different parameter types.
|
||||
// The function is private, so we test through the public API.
|
||||
|
||||
it("handles tools with string parameters", () => {
|
||||
// The mock_discovery_tool has a required string parameter.
|
||||
// If schema conversion fails, createServer would throw.
|
||||
expect(() => createServer({})).not.toThrow();
|
||||
});
|
||||
|
||||
it("handles tools with no parameters", () => {
|
||||
// Many tools (health ping, etc.) have empty parameters.
|
||||
expect(() => createServer({})).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe("SERVER_VERSION", () => {
|
||||
it("matches the version in package.json", () => {
|
||||
const pkg = JSON.parse(
|
||||
readFileSync(join(process.cwd(), "package.json"), "utf-8"),
|
||||
);
|
||||
expect(SERVER_VERSION).toBe(pkg.version);
|
||||
});
|
||||
|
||||
it("is a concrete semver, never the 'unknown' fallback", () => {
|
||||
expect(SERVER_VERSION).toMatch(/^\d+\.\d+\.\d+/);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user