github_mcp/tools/call_tool.rs
1// GitHub v3 REST API MCP server — generated by mcpify. Do not hand-edit.
2
3use crate::auth::auth_manager::AuthManager;
4use crate::auth::request_credentials::RequestCredentials;
5use crate::core::config_schema::Config;
6use crate::data::store::EndpointRecord;
7use crate::services::api_client::ApiClient;
8use crate::validation::validator::{validate_input, validate_output};
9
10/// Validates arguments against the input schema, injects the active auth
11/// strategy's credentials, executes the live HTTP request, and checks the
12/// response against the output schema before returning it — PRD §1.5's
13/// `call` pipeline (architecture.md's 4-step `call` pipeline).
14///
15/// An output-schema mismatch is only logged, not raised: real-world OpenAPI
16/// specs (e.g. Atlassian's published Jira Data Center spec) are frequently
17/// wrong about response shape — declaring a single object where the API
18/// actually returns an array, or an overly narrow `additionalProperties`
19/// for a free-form bag of fields — and rejecting an otherwise-successful
20/// call over a documentation bug would deny the caller real data it
21/// already has in hand. Input validation still hard-fails: those arguments
22/// are under the caller's control, not the upstream API's.
23///
24/// Takes an already-looked-up `EndpointRecord` rather than a `Connection`
25/// and an `operation_id` to look up itself: `rusqlite::Connection` isn't
26/// `Sync`, so a `&Connection` held across this function's `.await` points
27/// (the HTTP call) would make the caller's future non-`Send` — a hard
28/// requirement for `#[tool]` methods (Story R6). Callers look the
29/// endpoint up (a synchronous, `Connection`-scoped step) before calling
30/// this function, not inside it.
31pub async fn call_operation(
32 endpoint: &EndpointRecord,
33 config: &Config,
34 auth_manager: &mut AuthManager,
35 operation_id: &str,
36 args: serde_json::Value,
37 request_override: Option<&RequestCredentials>,
38) -> anyhow::Result<serde_json::Value> {
39 validate_input(&config.api_version, operation_id, &args)?;
40
41 let client = ApiClient::new(config.clone());
42 let response = client
43 .execute(endpoint, &args, auth_manager, request_override)
44 .await?;
45
46 if let Err(err) = validate_output(&config.api_version, operation_id, &response) {
47 tracing::warn!(
48 operation_id,
49 error = %err,
50 "response did not match the documented schema; returning it as-is"
51 );
52 }
53 Ok(response)
54}