Initial curated projectbrain source from 8a7b1e0651dbdab97d744cbd2e653ab3970ac6c5
This commit is contained in:
commit
5aa3e8d685
700 files changed
+132801
No files matched your search
@@ -0,0 +1,83 @@
|
||||
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
||||
import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { loadEnv } from "../src/config/env.js";
|
||||
import {
|
||||
parsePortfolioFetchId,
|
||||
portfolioFetchId,
|
||||
} from "../src/integrations/gitea/portfolio.js";
|
||||
import { registerPortfolioMcpTools } from "../src/mcp/portfolioTools.js";
|
||||
import { createProjectBrainMcpServer } from "../src/mcp/server.js";
|
||||
|
||||
const env = loadEnv({
|
||||
NODE_ENV: "test",
|
||||
DATABASE_URL: "postgresql://example.invalid/projectbrain",
|
||||
PROJECTBRAIN_DATA_SOURCE: "database",
|
||||
PROJECTBRAIN_OWNER_USERNAME: "owner",
|
||||
PROJECTBRAIN_OWNER_PASSWORD: "correct-horse-battery-staple",
|
||||
PROJECTBRAIN_AUTH_SECRET: "test-secret-with-at-least-thirty-two-characters",
|
||||
PROJECTBRAIN_MCP_ENABLED: "true",
|
||||
PROJECTBRAIN_PUBLIC_URL: "https://projectbrain.example.com",
|
||||
PROJECTBRAIN_GITEA_URL: "https://gitea.example.com",
|
||||
PROJECTBRAIN_GITEA_TOKEN: "a-token-with-at-least-twenty-characters",
|
||||
});
|
||||
|
||||
describe("read-only Gitea portfolio MCP projection", () => {
|
||||
it("round-trips canonical repository/ref/path fetch identifiers", () => {
|
||||
const id = portfolioFetchId(
|
||||
{ owner: "Jens", repository: "Mediarr" },
|
||||
"codex/example-branch",
|
||||
"src/a file.ts",
|
||||
);
|
||||
expect(id).toBe(
|
||||
"gitea-repository://Jens/Mediarr/codex%2Fexample-branch/src%2Fa%20file.ts",
|
||||
);
|
||||
expect(parsePortfolioFetchId(id)).toEqual({
|
||||
owner: "Jens",
|
||||
repository: "Mediarr",
|
||||
ref: "codex/example-branch",
|
||||
path: "src/a file.ts",
|
||||
});
|
||||
expect(() => parsePortfolioFetchId("gitea://project/main/file.ts")).toThrow(
|
||||
"MCP_FETCH_ID_INVALID",
|
||||
);
|
||||
});
|
||||
|
||||
it("advertises portfolio tools as distinct read-only capabilities", async () => {
|
||||
const server = createProjectBrainMcpServer(env, "portfolio-contract-test");
|
||||
registerPortfolioMcpTools(server, env, "portfolio-contract-test");
|
||||
const client = new Client({ name: "portfolio-contract-test", version: "1.0.0" });
|
||||
const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
|
||||
|
||||
try {
|
||||
await server.connect(serverTransport);
|
||||
await client.connect(clientTransport);
|
||||
const listed = await client.listTools();
|
||||
const tools = new Map(listed.tools.map((tool) => [tool.name, tool]));
|
||||
for (const name of [
|
||||
"list_portfolio_repositories",
|
||||
"search_portfolio_repositories",
|
||||
"fetch_portfolio_file",
|
||||
]) {
|
||||
const tool = tools.get(name);
|
||||
expect(tool, `${name} should be registered`).toBeDefined();
|
||||
expect(tool?.annotations).toMatchObject({
|
||||
readOnlyHint: true,
|
||||
destructiveHint: false,
|
||||
idempotentHint: true,
|
||||
});
|
||||
}
|
||||
expect(tools.get("list_portfolio_repositories")?.annotations?.openWorldHint).toBe(true);
|
||||
expect(tools.get("search_portfolio_repositories")?.annotations?.openWorldHint).toBe(false);
|
||||
expect(tools.get("fetch_portfolio_file")?.annotations?.openWorldHint).toBe(false);
|
||||
|
||||
// Existing delivery mutations remain separate, linked-project tools.
|
||||
expect(tools.has("write_feature_file")).toBe(true);
|
||||
expect(tools.has("search")).toBe(true);
|
||||
expect(tools.has("fetch")).toBe(true);
|
||||
} finally {
|
||||
await client.close();
|
||||
await server.close();
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user