Skip to content

Commit 60bd229

Browse files
committed
refactor: divide main to smaller files
1 parent e8c86ff commit 60bd229

File tree

7 files changed

+1398
-1378
lines changed

7 files changed

+1398
-1378
lines changed

src/constants.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
pub const GATEWAY_URL: &str = "https://gateway.thegraph.com/api";
3+
pub const GRAPH_NETWORK_SUBGRAPH_ARBITRUM: &str = "QmdKXcBUHR3UyURqVRQHu1oV6VUkBrhi2vNvMx3bNDnUCc";
4+
pub const GATEWAY_QOS_ORACLE: &str = "QmZmb6z87QmqBLmkMhaqWy7h2GLF1ey8Qj7YSRuqSGMjeH";
5+
6+
pub const SERVER_INSTRUCTIONS: &str = "**Interacting with The Graph Subgraphs**
7+
**IMPORTANT: ALWAYS verify query volumes using `get_deployment_30day_query_counts` for any potential subgraph candidate *before* selecting or querying it. This step is NON-OPTIONAL. Failure to do so may result in using outdated or irrelevant data.**
8+
**Follow this sequence strictly:**
9+
1. **Analyze User Request:**
10+
* Identify the **protocol name** (e.g., \"Uniswap\", \"Aave\", \"ENS\").
11+
* Note any specific **version** or **blockchain network** mentioned by the user.
12+
* Determine the **goal**: Query data? Get schema?
13+
2. **Initial Search & Preliminary Analysis:**
14+
* Use `search_subgraphs_by_keyword` with the most generic term for the protocol (e.g., if \"Uniswap v3 on Ethereum\", initially search only for \"Uniswap\").
15+
* Examine `displayName` and other metadata in the search results for version and network information.
16+
3. **Mandatory Query Volume Check & Clarification (If Needed):**
17+
* **ALWAYS** extract the IPFS hashes (`ipfsHash`) for all potentially relevant subgraphs identified in Step 2.
18+
* **ALWAYS** use `get_deployment_30day_query_counts` for these IPFS hashes.
19+
* **If Ambiguous (Multiple Versions/Chains with significant volume):**
20+
* Present a summary to the user, **including the 30-day query counts for each option**. For example: \"I found several Uniswap subgraphs. Uniswap v3 on Ethereum is the most active (X queries last 30 days). I also see Uniswap v2 on Ethereum (Y queries) and Uniswap v3 on Arbitrum (Z queries). Which specific version and network are you interested in?\"
21+
* **If Still Unclear (Information Missing and Not Inferable even with query volumes):**
22+
* If version/chain information is genuinely missing from search results and user input, and query volumes don't offer a clear path (e.g. all relevant subgraphs have very low or no volume), ask for clarification directly. Example: \"I found several subgraphs for 'ExampleProtocol', but none have significant query activity. Could you please specify the version and blockchain network you're interested in?\"
23+
* **Do NOT proceed to Step 4 without completing this query volume verification.**
24+
4. **Select Final Subgraph (Post Query Volume Check & Clarification):**
25+
* After the keyword search, mandatory query volume check, and any necessary clarification, you should have a clear target protocol, version, and network.
26+
* Identify all candidate subgraphs from your Step 2 `search_subgraphs_by_keyword` results that match these clarified criteria.
27+
* **If there is more than one such matching subgraph:**
28+
* You should have already fetched their query counts in Step 3.
29+
* **Select the subgraph with the highest `total_query_count`** among them.
30+
* **If only one subgraph precisely matches the criteria**, that is your selected subgraph.
31+
* When presenting your chosen subgraph or asking for final confirmation before querying, **ALWAYS state its 30-day query volume** to demonstrate this check has been performed. For example: \"I've selected the 'Uniswap v3 Ethereum' subgraph, which has X queries in the last 30 days. Shall I proceed to get its schema?\"
32+
* If the selected subgraph's query count is very low (and this wasn't already discussed during clarification), briefly inform the user.
33+
5. **Execute Action Using the Identified Subgraph:**
34+
* **Identify the ID Type:** (Subgraph ID, Deployment ID, or IPFS Hash - note that `search_subgraphs_by_keyword` returns `id` for Subgraph ID and `ipfsHash` for current deployment's IPFS hash).
35+
* **Determine the Correct Tool based on Goal & ID Type:**
36+
* **Goal: Query Data**
37+
* Subgraph ID (`id` from search) → `execute_query_by_subgraph_id`
38+
* Deployment ID / IPFS Hash (`ipfsHash` from search) → `execute_query_by_deployment_id`
39+
* **Goal: Get Schema**
40+
* Subgraph ID → `get_schema_by_subgraph_id`
41+
* Deployment ID → `get_schema_by_deployment_id`
42+
* IPFS Hash → `get_schema_by_ipfs_hash`
43+
* **Write Clean GraphQL Queries:** Simple structure, omit 'variables' if unused, include only essential fields.
44+
**Special Case: Contract Address Lookup**
45+
* ONLY when a user explicitly provides a **contract address** (0x...) AND asks for subgraphs related to it:
46+
* Identify the blockchain network for the address (ask user if unclear).
47+
* Use `get_top_subgraph_deployments` with the provided contract address and chain name.
48+
* Process and use the resulting deployment IDs as needed. **Crucially, before using any of these deployment IDs for querying, first use `get_deployment_30day_query_counts` with their IPFS hashes (which are the deployment IDs themselves in this context) to verify activity.**
49+
**ID Type Reference:**
50+
* **Subgraph ID**: Typically starts with digits and letters (e.g., 5zvR82...)
51+
* **Deployment ID / IPFS Hash**: For the purpose of `get_deployment_30day_query_counts`, the 'IPFS Hash' (Qm...) or 'Deployment ID' (0x...) can be used. Note `search_subgraphs_by_keyword` returns `ipfsHash`. `get_top_subgraph_deployments` returns `id` which is the Deployment ID (0x...).
52+
53+
**Best Practices:**
54+
* When using GraphQL, if unsure about the structure, first get the schema to understand available entities and fields.
55+
* Create focused queries that only request necessary fields.
56+
* For paginated data, use appropriate limit parameters.
57+
* Use variables for dynamic values in queries.";

src/error.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
use thiserror::Error;
3+
4+
#[derive(Debug, Error)]
5+
pub enum SubgraphError {
6+
#[error("API key not set")]
7+
ApiKeyNotSet,
8+
#[error("HTTP error: {0}")]
9+
HttpError(#[from] reqwest::Error),
10+
#[error("GraphQL error: {0}")]
11+
GraphQlError(String),
12+
#[error("JSON error: {0}")]
13+
JsonError(#[from] serde_json::Error),
14+
#[error("Internal processing error: {0}")]
15+
InternalProcessingError(String),
16+
}

src/http_utils.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
use http::HeaderMap;
3+
use rmcp::{
4+
handler::server::tool::{FromToolCallContextPart, ToolCallContext},
5+
Error as McpError,
6+
};
7+
8+
#[derive(Debug)]
9+
pub struct HttpRequestHeaders(pub Option<HeaderMap>);
10+
11+
impl<'a, S> FromToolCallContextPart<'a, S> for HttpRequestHeaders {
12+
fn from_tool_call_context_part(
13+
context: ToolCallContext<'a, S>,
14+
) -> Result<(Self, ToolCallContext<'a, S>), McpError> {
15+
let headers_opt = context
16+
.request_context()
17+
.extensions
18+
.get::<HeaderMap>()
19+
.cloned();
20+
Ok((HttpRequestHeaders(headers_opt), context))
21+
}
22+
}

0 commit comments

Comments
 (0)