tandem-server 0.7.0

HTTP server for Tandem engine APIs
// Copyright (c) 2026 Frumu LTD
// Licensed under the Business Source License 1.1

fn with_coder_mcp_phase_authority(
    mut args: Value,
    server_name: &str,
    tool_name: &str,
    phase: &str,
) -> Value {
    let allowed_tool = format!(
        "mcp.{}.{}",
        crate::http::mcp::mcp_namespace_segment(server_name),
        crate::http::mcp::mcp_namespace_segment(tool_name)
    );
    args["__phase_tool_authority"] = json!({
        "phase": phase,
        "allowed_tools": [allowed_tool],
        "source": "coder_server_dispatch",
        "policy_id": "coder_endpoint_tool_authority",
    });
    args
}

async fn call_create_pull_request(
    state: &AppState,
    tenant_context: &tandem_types::TenantContext,
    verified_tenant_context: Option<&tandem_types::VerifiedTenantContext>,
    server_name: &str,
    tool_name: &str,
    input_schema: &Value,
    owner: &str,
    repo: &str,
    title: &str,
    body: &str,
    base_branch: &str,
    head_branch: &str,
) -> Result<tandem_types::ToolResult, StatusCode> {
    let args = github_create_pull_request_args(
        input_schema,
        owner,
        repo,
        title,
        body,
        base_branch,
        head_branch,
    );
    let args = with_coder_mcp_phase_authority(args, server_name, tool_name, "coder_pr_submit");
    crate::http::mcp_run_as::call_mcp_tool_for_tenant_with_verified_context(
        state,
        server_name,
        tool_name,
        args,
        tenant_context,
        verified_tenant_context,
    )
    .await
    .map_err(|_| StatusCode::BAD_GATEWAY)
}

fn github_create_pull_request_args(
    input_schema: &Value,
    owner: &str,
    repo: &str,
    title: &str,
    body: &str,
    base_branch: &str,
    head_branch: &str,
) -> Value {
    let mut args = json!({
        "owner": owner,
        "repo": repo,
        "title": title,
        "body": body,
        "base": base_branch,
        "head": head_branch,
        "draft": true,
    });
    let properties = input_schema.get("properties").and_then(Value::as_object);
    if properties.is_none_or(|fields| fields.is_empty() || fields.contains_key("method")) {
        args["method"] = json!("create");
    }
    args
}