spice-mcp 0.1.0__py3-none-any.whl → 0.1.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of spice-mcp might be problematic. Click here for more details.

@@ -3,6 +3,7 @@ from __future__ import annotations
3
3
  import io
4
4
  import time
5
5
  from typing import TYPE_CHECKING, overload
6
+ import os
6
7
 
7
8
  from ..http_client import HttpClient
8
9
  from . import cache as _cache
@@ -32,6 +33,10 @@ from .typing_utils import resolve_raw_sql_template_id
32
33
 
33
34
  ADAPTER_VERSION = "spice-mcp-adapter"
34
35
 
36
+ # Runtime-configurable HTTP timeouts (helps avoid host-level timeouts)
37
+ _GET_TIMEOUT: float = float(os.getenv("SPICE_DUNE_GET_TIMEOUT", os.getenv("SPICE_HTTP_TIMEOUT", "30")))
38
+ _POST_TIMEOUT: float = float(os.getenv("SPICE_DUNE_POST_TIMEOUT", os.getenv("SPICE_HTTP_TIMEOUT", "30")))
39
+
35
40
  if TYPE_CHECKING:
36
41
  from collections.abc import Mapping, Sequence
37
42
  from typing import Any, Literal
@@ -749,7 +754,7 @@ def _execute(
749
754
  print('executing query, query_id = ' + str(query_id))
750
755
 
751
756
  # perform request
752
- response = _transport_post(url, headers=headers, json=data, timeout=15.0)
757
+ response = _transport_post(url, headers=headers, json=data, timeout=_POST_TIMEOUT)
753
758
  result: Mapping[str, Any] = response.json()
754
759
 
755
760
  # check for errors
@@ -786,7 +791,7 @@ async def _async_execute(
786
791
  print('executing query, query_id = ' + str(query_id))
787
792
 
788
793
  # perform request
789
- timeout = aiohttp.ClientTimeout(total=30)
794
+ timeout = aiohttp.ClientTimeout(total=_POST_TIMEOUT)
790
795
  async with aiohttp.ClientSession(timeout=timeout) as session:
791
796
  async with session.post(url, headers=headers, json=data) as response:
792
797
  result: Mapping[str, Any] = await response.json()
@@ -862,12 +867,12 @@ def _get_results(
862
867
  def _get_with_retries(u: str):
863
868
  client = current_http_client()
864
869
  if client is not None:
865
- return client.request("GET", u, headers=headers, timeout=30.0)
870
+ return client.request("GET", u, headers=headers, timeout=_GET_TIMEOUT)
866
871
 
867
872
  attempts = 0
868
873
  backoff = 0.5
869
874
  while True:
870
- resp = _transport_get(u, headers=headers, timeout=30.0)
875
+ resp = _transport_get(u, headers=headers, timeout=_GET_TIMEOUT)
871
876
  if resp.status_code in (429, 502):
872
877
  attempts += 1
873
878
  if attempts >= 3:
@@ -963,7 +968,7 @@ async def _async_get_results(
963
968
  print('getting results, execution_id = ' + str(execution['execution_id']))
964
969
 
965
970
  # perform request
966
- timeout = aiohttp.ClientTimeout(total=30)
971
+ timeout = aiohttp.ClientTimeout(total=_GET_TIMEOUT)
967
972
  async with aiohttp.ClientSession(timeout=timeout) as session:
968
973
  # GET with simple retry/backoff for 429/502
969
974
  attempts = 0
@@ -1169,7 +1174,7 @@ def _poll_execution(
1169
1174
  )
1170
1175
 
1171
1176
  # poll
1172
- response = _http_get(url, headers=headers, timeout=15.0)
1177
+ response = _http_get(url, headers=headers, timeout=_GET_TIMEOUT)
1173
1178
  result = response.json()
1174
1179
  if (
1175
1180
  'is_execution_finished' not in result
@@ -1243,7 +1248,7 @@ async def _async_poll_execution(
1243
1248
  t_start = time.time()
1244
1249
 
1245
1250
  # poll until completion
1246
- timeout = aiohttp.ClientTimeout(total=30)
1251
+ timeout = aiohttp.ClientTimeout(total=_GET_TIMEOUT)
1247
1252
  async with aiohttp.ClientSession(timeout=timeout) as session:
1248
1253
  sleep_amount = poll_interval
1249
1254
  while True:
@@ -1,5 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import os
4
+
3
5
 
4
6
  def resolve_raw_sql_template_id() -> int:
5
7
  """Return a stable template ID used for executing raw SQL text.
@@ -7,4 +9,4 @@ def resolve_raw_sql_template_id() -> int:
7
9
  Tests stub HTTP boundaries and only require a consistent integer. This
8
10
  placeholder can be adjusted if upstream semantics change.
9
11
  """
10
- return 0
12
+ return int(os.getenv("SPICE_RAW_SQL_QUERY_ID", "4060379"))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: spice-mcp
3
- Version: 0.1.0
3
+ Version: 0.1.1
4
4
  Summary: MCP server for Dune Analytics data access
5
5
  Author-email: Evan-Kim2028 <ekcopersonal@gmail.com>
6
6
  License-File: LICENSE
@@ -21,27 +21,87 @@ Description-Content-Type: text/markdown
21
21
 
22
22
  # spice-mcp
23
23
 
24
- spice-mcp is an MCP server for Dune Analytics. It wraps a curated subset of the original Spice client inside a clean architecture (`core` models/ports → `adapters.dune` → service layer → FastMCP tools) and adds agent-friendly workflows for discovery and Sui package exploration. Results are Polars-first in Python and compact, token-efficient in MCP responses.
24
+ spice-mcp is an MCP server for [Dune](https://dune.com/) Analytics. It wraps a curated subset of the original Spice client inside a clean architecture (`core` models/ports → `adapters.dune` → service layer → FastMCP tools) and adds agent-friendly workflows for discovery and Sui package exploration. Results are Polars-first in Python and compact, token-efficient in MCP responses.
25
25
 
26
26
  Requirements: Python 3.13+
27
27
 
28
28
  This project uses FastMCP for typed, decorator-registered tools and resources.
29
29
 
30
- Highlights
30
+ ## Highlights
31
31
  - Polars LazyFrame-first pipeline: results stay lazy until explicitly materialized
32
- - Ports/adapters layering for maintainable integrations (`docs/architecture.md`)
32
+ - Ports/adapters layering for maintainable integrations ([docs/architecture.md](docs/architecture.md))
33
33
  - Discovery utilities (find schemas/tables, describe columns)
34
34
  - Sui package workflows (events/transactions/objects) with safe defaults
35
35
  - JSONL query history + SQL artifacts (SHA-256) for reproducibility
36
36
  - Rich MCP surface: query info/run, discovery, health, Sui, and Dune admin (create/update/fork)
37
37
 
38
- Quick Start
38
+ ## What is Dune?
39
+ [Dune](https://dune.com/) is a crypto data platform providing curated blockchain datasets and a public API to run and fetch query results. See the [Dune Docs](https://dune.com/docs) and [Dune API](https://dune.com/docs/api/) for full details.
40
+
41
+ ## Quick Start
39
42
  - Export `DUNE_API_KEY` in your shell (the server can also load a local `.env`; set `SPICE_MCP_SKIP_DOTENV=1` to skip during tests).
40
43
  - Install dependencies (`uv sync` or `pip install -e .`).
41
44
  - Start the FastMCP stdio server:
42
45
  - `python -m spice_mcp.mcp.server --env PYTHONPATH=$(pwd)/src`
43
46
  - or install the console script via `uv tool install .` and run `spice-mcp`.
44
47
 
48
+ ## Cursor IDE Setup
49
+
50
+ To use spice-mcp with Cursor IDE:
51
+
52
+ 1. **Install the MCP Server**:
53
+ ```bash
54
+ # Install dependencies and package
55
+ uv sync
56
+ pip install -e .
57
+
58
+ # Or install via uv tool (creates console script)
59
+ uv tool install .
60
+ ```
61
+
62
+ 2. **Configure Cursor**:
63
+ - Open Cursor Settings → MCP Servers
64
+ - Add new MCP server configuration:
65
+ ```json
66
+ {
67
+ "name": "spice-mcp",
68
+ "command": "spice-mcp",
69
+ "env": {
70
+ "DUNE_API_KEY": "your-dune-api-key-here"
71
+ },
72
+ "disabled": false
73
+ }
74
+ ```
75
+ Alternatively, if you prefer running from source:
76
+ ```json
77
+ {
78
+ "name": "spice-mcp",
79
+ "command": "python",
80
+ "args": ["-m", "spice_mcp.mcp.server"],
81
+ "env": {
82
+ "PYTHONPATH": "/path/to/your/spice-mcp/src",
83
+ "DUNE_API_KEY": "your-dune-api-key-here"
84
+ },
85
+ "disabled": false
86
+ }
87
+ ```
88
+
89
+ 3. **Restart Cursor** to load the MCP server
90
+
91
+ 4. **Verify Connection**:
92
+ - Open Cursor and use the command palette (Cmd/Ctrl + Shift + P)
93
+ - Search for "MCP" or "spice" commands
94
+ - Test with `dune_health_check` to verify the connection
95
+
96
+ 5. **Available Tools in Cursor**:
97
+ - `dune_query`: Run Dune queries by ID, URL, or raw SQL
98
+ - `dune_find_tables`: Search schemas and list tables
99
+ - `dune_describe_table`: Get column metadata
100
+ - `sui_package_overview`: Analyze Sui packages
101
+ - `dune_health_check`: Verify API connection
102
+
103
+ **Tip**: Create a `.env` file in your project root with `DUNE_API_KEY=your-key-here` for easier configuration.
104
+
45
105
  ## MCP Tools and Features
46
106
 
47
107
  All tools expose typed parameters, titles, and tags; failures return a consistent error envelope.
@@ -114,16 +174,16 @@ Core Tools (with parameters)
114
174
  - Use: Verify API key presence and logging paths
115
175
  - Output: `api_key_present`, `query_history_path`, `logging_enabled`, `status`
116
176
 
117
- Docs
118
- - See `docs/index.md` for full documentation:
119
- - Dune API structure and capabilities: `docs/dune_api.md`
120
- - Discovery patterns and examples: `docs/discovery.md`
121
- - Sui package workflows: `docs/sui_packages.md`
122
- - Tool reference and schemas: `docs/tools.md`
123
- - Codex CLI + tooling integration: `docs/codex_cli.md`, `docs/codex_cli_tools.md`
124
- - Architecture overview: `docs/architecture.md`
125
- - Installation and configuration: `docs/installation.md`, `docs/config.md`
126
- - Development and linting: `docs/development.md`
177
+ ## Docs
178
+ - See [docs/index.md](docs/index.md) for full documentation:
179
+ - Dune API structure and capabilities: [docs/dune_api.md](docs/dune_api.md)
180
+ - Discovery patterns and examples: [docs/discovery.md](docs/discovery.md)
181
+ - Sui package workflows: [docs/sui_packages.md](docs/sui_packages.md)
182
+ - Tool reference and schemas: [docs/tools.md](docs/tools.md)
183
+ - Codex CLI + tooling integration: [docs/codex_cli.md](docs/codex_cli.md), [docs/codex_cli_tools.md](docs/codex_cli_tools.md)
184
+ - Architecture overview: [docs/architecture.md](docs/architecture.md)
185
+ - Installation and configuration: [docs/installation.md](docs/installation.md), [docs/config.md](docs/config.md)
186
+ - Development and linting: [docs/development.md](docs/development.md)
127
187
 
128
188
  Notes
129
189
  - Legacy Spice code now lives under `src/spice_mcp/adapters/dune` (extract, cache, urls, types).
@@ -8,11 +8,11 @@ spice_mcp/adapters/dune/__init__.py,sha256=8HRHPxkz0y2cyHSs4oCkHq_LQaUW5MBevbeNx
8
8
  spice_mcp/adapters/dune/admin.py,sha256=yxOueVz-rmgC-ZFbT06k59G24yRgYjiEkZlall5hXNQ,3157
9
9
  spice_mcp/adapters/dune/cache.py,sha256=7UmmxpBNeSGPH3KYBBSPHlVXCpiZUi4-X300U2FsSBs,5252
10
10
  spice_mcp/adapters/dune/client.py,sha256=JPrQZ_dtaPcGf6lYUguDxGweOtxG-8qMqOiXuhWL9QA,9122
11
- spice_mcp/adapters/dune/extract.py,sha256=MkPX8C5pLMB5oWjqEGwoVadYA4pOYt0MjdLBpru24G8,48154
11
+ spice_mcp/adapters/dune/extract.py,sha256=frIFRUNJ99UlP26N9F-p1psX-e_TVq9vJTQxh0MBCr8,48510
12
12
  spice_mcp/adapters/dune/helpers.py,sha256=BgDKr_g-UqmU2hoMb0ejQZHta_NbKwR1eDJp33sJYNk,227
13
13
  spice_mcp/adapters/dune/transport.py,sha256=eRP-jPY2ZXxvTX9HSjIFqFUlbIzXspgH95jBFoTlpaQ,1436
14
14
  spice_mcp/adapters/dune/types.py,sha256=57TMX07u-Gq4BYwRAuZV0xI81nVXgtpp7KBID9YbKyQ,1195
15
- spice_mcp/adapters/dune/typing_utils.py,sha256=izRaHUzt883KDAOA7rNgm6arZAovsGbMk2DBAn_Fdhs,306
15
+ spice_mcp/adapters/dune/typing_utils.py,sha256=QSgPSsRZ88GEUdr55OwbYb9wVlT8bkS0iBDWlzzO5g0,367
16
16
  spice_mcp/adapters/dune/urls.py,sha256=bcuPERkFQduRTT2BrgzVhoFrMn-Lkvw9NmktcBZYEig,3902
17
17
  spice_mcp/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
18
  spice_mcp/core/errors.py,sha256=jlfTuyRaAaA_oU07KUk-1pDAAa43KG0BbZc5CINXtoE,3256
@@ -32,8 +32,8 @@ spice_mcp/service_layer/discovery_service.py,sha256=202O0SzCZGQukd9kb2JYfarLygZH
32
32
  spice_mcp/service_layer/query_admin_service.py,sha256=4q1NAAuTui7cm83Aq2rFDLIzKTHX17yzbSoSJyCmLbI,1356
33
33
  spice_mcp/service_layer/query_service.py,sha256=q0eAVW5I3sUxm29DgzPN_cH3rZEzmKwmdE3Xj4qP9lI,3878
34
34
  spice_mcp/service_layer/sui_service.py,sha256=G-LOsl-z-ldMxAYAetnG17IQlpVtLchGUjN6opU-PF0,4712
35
- spice_mcp-0.1.0.dist-info/METADATA,sha256=h4MsHI5EjkLfPWYxzC9N6Fe7ac7z3d9odv0WX1drF1A,7278
36
- spice_mcp-0.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
37
- spice_mcp-0.1.0.dist-info/entry_points.txt,sha256=4XiXX13Vy-oiUJwlcO_82OltBaxFnEnkJ-76sZGm5os,56
38
- spice_mcp-0.1.0.dist-info/licenses/LICENSE,sha256=r0GNDnDY1RSkVQp7kEEf6MQU21OrNGJkxUHIsv6eyLk,1079
39
- spice_mcp-0.1.0.dist-info/RECORD,,
35
+ spice_mcp-0.1.1.dist-info/METADATA,sha256=WghxqMf1wdHX3M_GgfPiP-ZRMg9apFZSVetiOzuL1qQ,9316
36
+ spice_mcp-0.1.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
37
+ spice_mcp-0.1.1.dist-info/entry_points.txt,sha256=4XiXX13Vy-oiUJwlcO_82OltBaxFnEnkJ-76sZGm5os,56
38
+ spice_mcp-0.1.1.dist-info/licenses/LICENSE,sha256=r0GNDnDY1RSkVQp7kEEf6MQU21OrNGJkxUHIsv6eyLk,1079
39
+ spice_mcp-0.1.1.dist-info/RECORD,,