BEGIN; CREATE TABLE IF NOT EXISTS mcp_settings ( id integer PRIMARY KEY CHECK(id=1), enabled boolean NOT NULL DEFAULT false, requests_retention_days integer NOT NULL DEFAULT 30 CHECK(requests_retention_days BETWEEN 1 AND 365), audit_retention_days integer NOT NULL DEFAULT 180 CHECK(audit_retention_days BETWEEN 30 AND 3650), updated_at timestamptz NOT NULL DEFAULT now() ); INSERT INTO mcp_settings(id) VALUES(1) ON CONFLICT DO NOTHING; CREATE TABLE IF NOT EXISTS mcp_connections ( id uuid PRIMARY KEY, name text NOT NULL, owner_id text NOT NULL, owner_permissions jsonb NOT NULL, policy jsonb NOT NULL, generation text NOT NULL, created_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now(), last_used_at timestamptz ); CREATE TABLE IF NOT EXISTS mcp_credentials ( id uuid PRIMARY KEY, connection_id uuid NOT NULL REFERENCES mcp_connections(id) ON DELETE CASCADE, digest text NOT NULL UNIQUE, kind text NOT NULL CHECK(kind IN ('bearer','access','refresh')), expires_at timestamptz NOT NULL, revoked_at timestamptz, created_at timestamptz NOT NULL DEFAULT now(), family_id uuid, client_id text, audience text ); CREATE INDEX IF NOT EXISTS mcp_credentials_connection ON mcp_credentials(connection_id); CREATE TABLE IF NOT EXISTS mcp_audit ( id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY, actor_id text NOT NULL, action text NOT NULL, connection_id uuid, payload jsonb NOT NULL DEFAULT '{}', created_at timestamptz NOT NULL DEFAULT now() ); CREATE INDEX IF NOT EXISTS mcp_audit_time ON mcp_audit(created_at,id); CREATE TABLE IF NOT EXISTS mcp_requests ( id uuid PRIMARY KEY, connection_id uuid REFERENCES mcp_connections(id) ON DELETE SET NULL, actor_id text, tool text NOT NULL, server_ids bigint[] NOT NULL DEFAULT '{}', status text NOT NULL, input jsonb NOT NULL DEFAULT '{}', result jsonb, error_code text, duration_ms integer, created_at timestamptz NOT NULL DEFAULT now(), finished_at timestamptz ); CREATE INDEX IF NOT EXISTS mcp_requests_connection_time ON mcp_requests(connection_id,created_at,id); CREATE INDEX IF NOT EXISTS mcp_requests_server ON mcp_requests USING gin(server_ids); CREATE TABLE IF NOT EXISTS mcp_protections ( id uuid PRIMARY KEY, object_ref jsonb NOT NULL, reason text NOT NULL DEFAULT '', created_by text NOT NULL, created_at timestamptz NOT NULL DEFAULT now() ); CREATE TABLE IF NOT EXISTS mcp_plans ( id uuid PRIMARY KEY, connection_id uuid NOT NULL REFERENCES mcp_connections(id), operation_id text NOT NULL, operation_version integer NOT NULL, policy_version integer NOT NULL, generation text NOT NULL, payload jsonb NOT NULL, evidence jsonb NOT NULL, state text NOT NULL, expires_at timestamptz NOT NULL, approved_by text, approved_at timestamptz, created_at timestamptz NOT NULL DEFAULT now() ); CREATE INDEX IF NOT EXISTS mcp_plans_connection ON mcp_plans(connection_id,created_at); CREATE TABLE IF NOT EXISTS mcp_operations ( id uuid PRIMARY KEY, plan_id uuid NOT NULL UNIQUE REFERENCES mcp_plans(id), connection_id uuid NOT NULL REFERENCES mcp_connections(id), idempotency_key text NOT NULL, state text NOT NULL DEFAULT 'pending', verification text NOT NULL DEFAULT 'pending', result jsonb, error_code text, created_at timestamptz NOT NULL DEFAULT now(), finished_at timestamptz, UNIQUE(connection_id,idempotency_key) ); CREATE TABLE IF NOT EXISTS mcp_operation_steps ( operation_id uuid NOT NULL REFERENCES mcp_operations(id), step_index integer NOT NULL, server_id bigint, state text NOT NULL, before_state jsonb, intended_state jsonb, result jsonb, created_at timestamptz NOT NULL DEFAULT now(), finished_at timestamptz, PRIMARY KEY(operation_id,step_index) ); CREATE TABLE IF NOT EXISTS mcp_budget_buckets ( connection_id uuid NOT NULL REFERENCES mcp_connections(id) ON DELETE CASCADE, kind text NOT NULL, bucket timestamptz NOT NULL, used integer NOT NULL CHECK(used>=0), PRIMARY KEY(connection_id,kind,bucket) ); CREATE TABLE IF NOT EXISTS mcp_read_leases ( id uuid PRIMARY KEY, connection_id uuid NOT NULL REFERENCES mcp_connections(id) ON DELETE CASCADE, expires_at timestamptz NOT NULL ); CREATE TABLE IF NOT EXISTS mcp_grants ( id uuid PRIMARY KEY, connection_id uuid NOT NULL REFERENCES mcp_connections(id) ON DELETE CASCADE, payload jsonb NOT NULL, revoked_at timestamptz ); CREATE TABLE IF NOT EXISTS mcp_secrets ( id uuid PRIMARY KEY, purpose text NOT NULL, server_id bigint, ciphertext text NOT NULL, created_by text NOT NULL, created_at timestamptz NOT NULL DEFAULT now() ); CREATE TABLE IF NOT EXISTS mcp_artifacts ( id uuid PRIMARY KEY, connection_id uuid NOT NULL REFERENCES mcp_connections(id), filename text NOT NULL, media_type text NOT NULL, ciphertext text NOT NULL, expires_at timestamptz NOT NULL, created_at timestamptz NOT NULL DEFAULT now() ); CREATE TABLE IF NOT EXISTS mcp_oauth_clients ( id text PRIMARY KEY, name text NOT NULL, redirect_uris jsonb NOT NULL, enabled boolean NOT NULL DEFAULT true, created_at timestamptz NOT NULL DEFAULT now() ); CREATE TABLE IF NOT EXISTS mcp_oauth_requests ( id uuid PRIMARY KEY, client_id text NOT NULL REFERENCES mcp_oauth_clients(id), redirect_uri text NOT NULL, challenge text NOT NULL, state text, resource text NOT NULL, scope text NOT NULL, expires_at timestamptz NOT NULL, consumed_at timestamptz, connection_id uuid REFERENCES mcp_connections(id), code_digest text UNIQUE ); CREATE TABLE IF NOT EXISTS mcp_routing_profiles ( id uuid PRIMARY KEY, connection_id uuid NOT NULL REFERENCES mcp_connections(id), version integer NOT NULL DEFAULT 1, config jsonb NOT NULL, state jsonb NOT NULL DEFAULT '{}', enabled boolean NOT NULL DEFAULT false, grant_expires_at timestamptz NOT NULL, updated_at timestamptz NOT NULL DEFAULT now() ); CREATE TABLE IF NOT EXISTS mcp_drift ( id uuid PRIMARY KEY, operation_id uuid NOT NULL REFERENCES mcp_operations(id), server_id bigint, expected jsonb NOT NULL, observed jsonb NOT NULL, acknowledged_at timestamptz, detected_at timestamptz NOT NULL DEFAULT now() ); COMMIT;