// src/application/mcp/common.ts
import { PresentationRegistry } from "@contractspec/lib.contracts-spec/presentations";
import { createMcpServer } from "@contractspec/lib.contracts-runtime-server-mcp/provider-mcp";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";
import { Elysia } from "elysia";
import { randomUUID } from "node:crypto";
var baseCtx = {
  actor: "anonymous",
  decide: async () => ({ effect: "allow" })
};
function createJsonRpcErrorResponse(status, code, message, data) {
  return new Response(JSON.stringify({
    jsonrpc: "2.0",
    error: {
      code,
      message,
      ...data ? { data } : {}
    },
    id: null
  }), {
    status,
    headers: {
      "content-type": "application/json"
    }
  });
}
function createSessionState({
  logger,
  serverName,
  ops,
  resources,
  prompts,
  presentations,
  stateful
}) {
  const server = new McpServer({
    name: serverName,
    version: "1.0.0"
  }, {
    capabilities: {
      tools: {},
      resources: {},
      prompts: {},
      logging: {}
    }
  });
  logger.info("Setting up MCP server...");
  createMcpServer(server, ops, resources, prompts, {
    logger,
    toolCtx: () => baseCtx,
    promptCtx: () => ({ locale: "en" }),
    resourceCtx: () => ({ locale: "en" }),
    presentations: new PresentationRegistry(presentations)
  });
  const transport = new WebStandardStreamableHTTPServerTransport({
    sessionIdGenerator: stateful ? () => randomUUID() : undefined,
    enableJsonResponse: true
  });
  return server.connect(transport).then(() => ({ server, transport }));
}
async function closeSessionState(state) {
  await Promise.allSettled([state.transport.close(), state.server.close()]);
}
function toErrorMessage(error) {
  return error instanceof Error ? error.stack ?? error.message : String(error);
}
function createMcpElysiaHandler({
  logger,
  path,
  serverName,
  ops,
  resources,
  prompts,
  presentations,
  validateAuth,
  requiredAuthMethods
}) {
  logger.info("Setting up MCP handler...", {
    requiredAuthMethods: requiredAuthMethods ?? []
  });
  const isStateful = process.env.CONTRACTSPEC_MCP_STATEFUL === "1";
  const sessions = new Map;
  async function handleStateless(request) {
    const state = await createSessionState({
      logger,
      path,
      serverName,
      ops,
      resources,
      prompts,
      presentations,
      stateful: false
    });
    try {
      return await state.transport.handleRequest(request);
    } finally {
      await closeSessionState(state);
    }
  }
  async function closeSession(sessionId) {
    const state = sessions.get(sessionId);
    if (!state)
      return;
    sessions.delete(sessionId);
    await closeSessionState(state);
  }
  async function handleStateful(request) {
    const requestedSessionId = request.headers.get("mcp-session-id");
    let state;
    let createdState = false;
    if (requestedSessionId) {
      const existing = sessions.get(requestedSessionId);
      if (!existing) {
        return createJsonRpcErrorResponse(404, -32001, "Session not found");
      }
      state = existing;
    } else {
      state = await createSessionState({
        logger,
        path,
        serverName,
        ops,
        resources,
        prompts,
        presentations,
        stateful: true
      });
      createdState = true;
    }
    try {
      const response = await state.transport.handleRequest(request);
      const activeSessionId = state.transport.sessionId;
      if (activeSessionId && !sessions.has(activeSessionId)) {
        sessions.set(activeSessionId, state);
      }
      if (request.method === "DELETE" && activeSessionId) {
        await closeSession(activeSessionId);
      } else if (!activeSessionId && createdState) {
        await closeSessionState(state);
      }
      return response;
    } catch (error) {
      if (createdState) {
        await closeSessionState(state);
      }
      throw error;
    }
  }
  return new Elysia({ name: `mcp-${serverName}` }).all(path, async ({ request }) => {
    try {
      if (validateAuth) {
        const authResult = await validateAuth(request);
        if (!authResult.valid) {
          return createJsonRpcErrorResponse(401, -32002, "Authentication failed", authResult.reason);
        }
      }
      if (isStateful) {
        return await handleStateful(request);
      }
      return await handleStateless(request);
    } catch (error) {
      logger.error("Error handling MCP request", {
        path,
        method: request.method,
        error: toErrorMessage(error)
      });
      return createJsonRpcErrorResponse(500, -32000, "Internal error");
    }
  });
}

// src/infrastructure/elysia/logger.ts
import { Logger, LogLevel } from "@contractspec/lib.logger";
var createAppLogger = () => new Logger({
  level: LogLevel.INFO,
  environment: "production",
  enableTracing: true,
  enableTiming: true,
  enableContext: true,
  enableColors: false
});
var appLogger = createAppLogger();
var dbLogger = new Logger({
  level: LogLevel.WARN,
  environment: "production",
  enableTracing: true,
  enableTiming: true,
  enableContext: true,
  enableColors: false
});
var authLogger = new Logger({
  level: LogLevel.INFO,
  environment: "production",
  enableTracing: true,
  enableTiming: true,
  enableContext: true,
  enableColors: false
});
// src/application/mcp/contractsMcpTools.ts
import {
  defineCommand,
  installOp,
  OperationSpecRegistry
} from "@contractspec/lib.contracts-spec";
import { defineSchemaModel, ScalarTypeEnum } from "@contractspec/lib.schema";
var OWNERS = ["@contractspec"];
var TAGS = ["contracts", "mcp"];
function buildContractsOps(services) {
  const registry = new OperationSpecRegistry;
  const ListInput = defineSchemaModel({
    name: "ContractsListInput",
    fields: {
      pattern: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
      type: { type: ScalarTypeEnum.String_unsecure(), isOptional: true }
    }
  });
  const ListOutput = defineSchemaModel({
    name: "ContractsListOutput",
    fields: {
      specs: { type: ScalarTypeEnum.JSON(), isOptional: false },
      total: { type: ScalarTypeEnum.Int_unsecure(), isOptional: false }
    }
  });
  installOp(registry, defineCommand({
    meta: {
      key: "contracts.list",
      version: "1.0.0",
      stability: "beta",
      owners: OWNERS,
      tags: TAGS,
      description: "List contract specs in the workspace.",
      goal: "Discover available contracts by type, pattern, or owner.",
      context: "Contracts MCP server."
    },
    io: { input: ListInput, output: ListOutput },
    policy: { auth: "anonymous" }
  }), async ({ pattern, type }) => {
    const specs = await services.listSpecs({ pattern, type });
    return { specs, total: specs.length };
  });
  const GetInput = defineSchemaModel({
    name: "ContractsGetInput",
    fields: {
      path: { type: ScalarTypeEnum.String_unsecure(), isOptional: false }
    }
  });
  const GetOutput = defineSchemaModel({
    name: "ContractsGetOutput",
    fields: {
      content: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
      info: { type: ScalarTypeEnum.JSON(), isOptional: false }
    }
  });
  installOp(registry, defineCommand({
    meta: {
      key: "contracts.get",
      version: "1.0.0",
      stability: "beta",
      owners: OWNERS,
      tags: TAGS,
      description: "Read a single contract spec file.",
      goal: "Fetch spec content and parsed metadata.",
      context: "Contracts MCP server."
    },
    io: { input: GetInput, output: GetOutput },
    policy: { auth: "anonymous" }
  }), async ({ path }) => {
    const result = await services.getSpec(path);
    if (!result)
      throw new Error(`Spec not found: ${path}`);
    return result;
  });
  const ValidateInput = defineSchemaModel({
    name: "ContractsValidateInput",
    fields: {
      path: { type: ScalarTypeEnum.String_unsecure(), isOptional: false }
    }
  });
  const ValidateOutput = defineSchemaModel({
    name: "ContractsValidateOutput",
    fields: {
      valid: { type: ScalarTypeEnum.Boolean(), isOptional: false },
      errors: { type: ScalarTypeEnum.JSON(), isOptional: false },
      warnings: { type: ScalarTypeEnum.JSON(), isOptional: false }
    }
  });
  installOp(registry, defineCommand({
    meta: {
      key: "contracts.validate",
      version: "1.0.0",
      stability: "beta",
      owners: OWNERS,
      tags: TAGS,
      description: "Validate a contract spec structure.",
      goal: "Check spec for structural or policy issues.",
      context: "Contracts MCP server."
    },
    io: { input: ValidateInput, output: ValidateOutput },
    policy: { auth: "anonymous" }
  }), async ({ path }) => services.validateSpec(path));
  const BuildInput = defineSchemaModel({
    name: "ContractsBuildInput",
    fields: {
      path: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
      dryRun: { type: ScalarTypeEnum.Boolean(), isOptional: true }
    }
  });
  const BuildOutput = defineSchemaModel({
    name: "ContractsBuildOutput",
    fields: {
      results: { type: ScalarTypeEnum.JSON(), isOptional: false }
    }
  });
  installOp(registry, defineCommand({
    meta: {
      key: "contracts.build",
      version: "1.0.0",
      stability: "beta",
      owners: OWNERS,
      tags: TAGS,
      description: "Generate implementation code from a contract spec.",
      goal: "Produce handler, component, or test skeletons.",
      context: "Contracts MCP server."
    },
    io: { input: BuildInput, output: BuildOutput },
    policy: { auth: "user" }
  }), async ({ path, dryRun }) => services.buildSpec(path, { dryRun }));
  registerMutationTools(registry, services);
  return registry;
}
function registerMutationTools(registry, services) {
  const UpdateInput = defineSchemaModel({
    name: "ContractsUpdateInput",
    fields: {
      path: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
      content: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
      fields: { type: ScalarTypeEnum.JSON(), isOptional: true }
    }
  });
  const UpdateOutput = defineSchemaModel({
    name: "ContractsUpdateOutput",
    fields: {
      updated: { type: ScalarTypeEnum.Boolean(), isOptional: false },
      errors: { type: ScalarTypeEnum.JSON(), isOptional: false },
      warnings: { type: ScalarTypeEnum.JSON(), isOptional: false }
    }
  });
  installOp(registry, defineCommand({
    meta: {
      key: "contracts.update",
      version: "1.0.0",
      stability: "beta",
      owners: OWNERS,
      tags: TAGS,
      description: "Update an existing contract spec.",
      goal: "Modify spec content or individual fields with validation.",
      context: "Contracts MCP server."
    },
    io: { input: UpdateInput, output: UpdateOutput },
    policy: { auth: "user" }
  }), async ({ path, content, fields }) => services.updateSpec(path, {
    content,
    fields: Array.isArray(fields) ? fields : undefined
  }));
  const DeleteInput = defineSchemaModel({
    name: "ContractsDeleteInput",
    fields: {
      path: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
      clean: { type: ScalarTypeEnum.Boolean(), isOptional: true }
    }
  });
  const DeleteOutput = defineSchemaModel({
    name: "ContractsDeleteOutput",
    fields: {
      deleted: { type: ScalarTypeEnum.Boolean(), isOptional: false },
      cleanedFiles: { type: ScalarTypeEnum.JSON(), isOptional: false },
      errors: { type: ScalarTypeEnum.JSON(), isOptional: false }
    }
  });
  installOp(registry, defineCommand({
    meta: {
      key: "contracts.delete",
      version: "1.0.0",
      stability: "beta",
      owners: OWNERS,
      tags: TAGS,
      description: "Delete a contract spec and optionally its artifacts.",
      goal: "Remove a spec file and clean generated handlers/tests.",
      context: "Contracts MCP server."
    },
    io: { input: DeleteInput, output: DeleteOutput },
    policy: { auth: "user" }
  }), async ({ path, clean }) => services.deleteSpec(path, { clean }));
}

// src/application/mcp/contractsMcpResources.ts
import {
  definePrompt,
  defineResourceTemplate,
  PromptRegistry,
  ResourceRegistry
} from "@contractspec/lib.contracts-spec";
import z from "zod";
var OWNERS2 = ["@contractspec"];
var TAGS2 = ["contracts", "mcp"];
function buildContractsResources(services) {
  const resources = new ResourceRegistry;
  resources.register(defineResourceTemplate({
    meta: {
      uriTemplate: "contracts://list",
      title: "Contract specs list",
      description: "JSON list of all contract specs in the workspace.",
      mimeType: "application/json",
      tags: TAGS2
    },
    input: z.object({}),
    resolve: async () => {
      const specs = await services.listSpecs();
      return {
        uri: "contracts://list",
        mimeType: "application/json",
        data: JSON.stringify(specs, null, 2)
      };
    }
  }));
  resources.register(defineResourceTemplate({
    meta: {
      uriTemplate: "contracts://spec/{path}",
      title: "Contract spec content",
      description: "Read a single contract spec file by path.",
      mimeType: "text/plain",
      tags: TAGS2
    },
    input: z.object({ path: z.string() }),
    resolve: async ({ path }) => {
      const result = await services.getSpec(path);
      if (!result) {
        return {
          uri: `contracts://spec/${encodeURIComponent(path)}`,
          mimeType: "text/plain",
          data: `Spec not found: ${path}`
        };
      }
      return {
        uri: `contracts://spec/${encodeURIComponent(path)}`,
        mimeType: "text/plain",
        data: result.content
      };
    }
  }));
  resources.register(defineResourceTemplate({
    meta: {
      uriTemplate: "contracts://registry/manifest",
      title: "Remote registry manifest",
      description: "Contract registry manifest from the remote server.",
      mimeType: "application/json",
      tags: TAGS2
    },
    input: z.object({}),
    resolve: async () => {
      const manifest = await services.fetchRegistryManifest();
      return {
        uri: "contracts://registry/manifest",
        mimeType: "application/json",
        data: JSON.stringify(manifest, null, 2)
      };
    }
  }));
  return resources;
}
function buildContractsPrompts() {
  const prompts = new PromptRegistry;
  prompts.register(definePrompt({
    meta: {
      key: "contracts.editor",
      version: "1.0.0",
      title: "Contract editing guide",
      description: "Guide AI agents through reading, editing, and validating contracts.",
      tags: TAGS2,
      stability: "beta",
      owners: OWNERS2
    },
    args: [
      {
        name: "goal",
        description: "What the agent wants to achieve with the contract.",
        required: false,
        schema: z.string().optional()
      }
    ],
    input: z.object({ goal: z.string().optional() }),
    render: async ({ goal }) => [
      {
        type: "text",
        text: [
          "Contract editing workflow:",
          "1. Use contracts.list to discover specs",
          "2. Use contracts.get to read a spec",
          "3. Edit content and call contracts.update",
          "4. Run contracts.validate to verify changes",
          "5. Run contracts.build to regenerate artifacts",
          goal ? `Agent goal: ${goal}` : ""
        ].filter(Boolean).join(`
`)
      },
      {
        type: "resource",
        uri: "contracts://list",
        title: "Available contracts"
      }
    ]
  }));
  return prompts;
}

// src/application/mcp/contractsMcp.ts
function createContractsMcpHandler(path = "/api/mcp/contracts", services) {
  return createMcpElysiaHandler({
    logger: appLogger,
    path,
    serverName: "contractspec-contracts-mcp",
    ops: buildContractsOps(services),
    resources: buildContractsResources(services),
    prompts: buildContractsPrompts()
  });
}
export {
  createContractsMcpHandler
};
