dataquery-sdk 1.2.4__tar.gz → 1.2.6__tar.gz

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.
Files changed (50) hide show
  1. {dataquery_sdk-1.2.4 → dataquery_sdk-1.2.6}/CHANGELOG.md +5 -2
  2. {dataquery_sdk-1.2.4 → dataquery_sdk-1.2.6}/PKG-INFO +159 -5
  3. {dataquery_sdk-1.2.4 → dataquery_sdk-1.2.6}/README.md +156 -2
  4. {dataquery_sdk-1.2.4 → dataquery_sdk-1.2.6}/dataquery/__init__.py +1 -1
  5. {dataquery_sdk-1.2.4 → dataquery_sdk-1.2.6}/dataquery/cli.py +20 -4
  6. {dataquery_sdk-1.2.4 → dataquery_sdk-1.2.6}/dataquery/mcp_proxy.py +12 -2
  7. {dataquery_sdk-1.2.4 → dataquery_sdk-1.2.6}/dataquery/types/models.py +4 -0
  8. {dataquery_sdk-1.2.4 → dataquery_sdk-1.2.6}/dataquery/utils.py +4 -0
  9. {dataquery_sdk-1.2.4 → dataquery_sdk-1.2.6}/dataquery_sdk.egg-info/PKG-INFO +159 -5
  10. {dataquery_sdk-1.2.4 → dataquery_sdk-1.2.6}/dataquery_sdk.egg-info/requires.txt +2 -2
  11. {dataquery_sdk-1.2.4 → dataquery_sdk-1.2.6}/pyproject.toml +2 -2
  12. {dataquery_sdk-1.2.4 → dataquery_sdk-1.2.6}/CONTRIBUTING.md +0 -0
  13. {dataquery_sdk-1.2.4 → dataquery_sdk-1.2.6}/LICENSE +0 -0
  14. {dataquery_sdk-1.2.4 → dataquery_sdk-1.2.6}/MANIFEST.in +0 -0
  15. {dataquery_sdk-1.2.4 → dataquery_sdk-1.2.6}/dataquery/config/__init__.py +0 -0
  16. {dataquery_sdk-1.2.4 → dataquery_sdk-1.2.6}/dataquery/config/env.py +0 -0
  17. {dataquery_sdk-1.2.4 → dataquery_sdk-1.2.6}/dataquery/config/logging.py +0 -0
  18. {dataquery_sdk-1.2.4 → dataquery_sdk-1.2.6}/dataquery/constants/__init__.py +0 -0
  19. {dataquery_sdk-1.2.4 → dataquery_sdk-1.2.6}/dataquery/constants/api.py +0 -0
  20. {dataquery_sdk-1.2.4 → dataquery_sdk-1.2.6}/dataquery/constants/download.py +0 -0
  21. {dataquery_sdk-1.2.4 → dataquery_sdk-1.2.6}/dataquery/constants/rate_limit.py +0 -0
  22. {dataquery_sdk-1.2.4 → dataquery_sdk-1.2.6}/dataquery/constants/sse.py +0 -0
  23. {dataquery_sdk-1.2.4 → dataquery_sdk-1.2.6}/dataquery/core/__init__.py +0 -0
  24. {dataquery_sdk-1.2.4 → dataquery_sdk-1.2.6}/dataquery/core/_mixins.py +0 -0
  25. {dataquery_sdk-1.2.4 → dataquery_sdk-1.2.6}/dataquery/core/_sync.py +0 -0
  26. {dataquery_sdk-1.2.4 → dataquery_sdk-1.2.6}/dataquery/core/client.py +0 -0
  27. {dataquery_sdk-1.2.4 → dataquery_sdk-1.2.6}/dataquery/data/function.json +0 -0
  28. {dataquery_sdk-1.2.4 → dataquery_sdk-1.2.6}/dataquery/dataquery.py +0 -0
  29. {dataquery_sdk-1.2.4 → dataquery_sdk-1.2.6}/dataquery/download/__init__.py +0 -0
  30. {dataquery_sdk-1.2.4 → dataquery_sdk-1.2.6}/dataquery/download/parallel.py +0 -0
  31. {dataquery_sdk-1.2.4 → dataquery_sdk-1.2.6}/dataquery/download/utils.py +0 -0
  32. {dataquery_sdk-1.2.4 → dataquery_sdk-1.2.6}/dataquery/export.py +0 -0
  33. {dataquery_sdk-1.2.4 → dataquery_sdk-1.2.6}/dataquery/function_registry.py +0 -0
  34. {dataquery_sdk-1.2.4 → dataquery_sdk-1.2.6}/dataquery/py.typed +0 -0
  35. {dataquery_sdk-1.2.4 → dataquery_sdk-1.2.6}/dataquery/sse/__init__.py +0 -0
  36. {dataquery_sdk-1.2.4 → dataquery_sdk-1.2.6}/dataquery/sse/client.py +0 -0
  37. {dataquery_sdk-1.2.4 → dataquery_sdk-1.2.6}/dataquery/sse/event_store.py +0 -0
  38. {dataquery_sdk-1.2.4 → dataquery_sdk-1.2.6}/dataquery/sse/subscriber.py +0 -0
  39. {dataquery_sdk-1.2.4 → dataquery_sdk-1.2.6}/dataquery/transport/__init__.py +0 -0
  40. {dataquery_sdk-1.2.4 → dataquery_sdk-1.2.6}/dataquery/transport/auth.py +0 -0
  41. {dataquery_sdk-1.2.4 → dataquery_sdk-1.2.6}/dataquery/transport/connection_pool.py +0 -0
  42. {dataquery_sdk-1.2.4 → dataquery_sdk-1.2.6}/dataquery/transport/rate_limiter.py +0 -0
  43. {dataquery_sdk-1.2.4 → dataquery_sdk-1.2.6}/dataquery/transport/retry.py +0 -0
  44. {dataquery_sdk-1.2.4 → dataquery_sdk-1.2.6}/dataquery/types/__init__.py +0 -0
  45. {dataquery_sdk-1.2.4 → dataquery_sdk-1.2.6}/dataquery/types/exceptions.py +0 -0
  46. {dataquery_sdk-1.2.4 → dataquery_sdk-1.2.6}/dataquery_sdk.egg-info/SOURCES.txt +0 -0
  47. {dataquery_sdk-1.2.4 → dataquery_sdk-1.2.6}/dataquery_sdk.egg-info/dependency_links.txt +0 -0
  48. {dataquery_sdk-1.2.4 → dataquery_sdk-1.2.6}/dataquery_sdk.egg-info/entry_points.txt +0 -0
  49. {dataquery_sdk-1.2.4 → dataquery_sdk-1.2.6}/dataquery_sdk.egg-info/top_level.txt +0 -0
  50. {dataquery_sdk-1.2.4 → dataquery_sdk-1.2.6}/setup.cfg +0 -0
@@ -53,5 +53,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
53
53
  - Exports: `Paginated`, `Link`, `APIResponseError` are now part of the public API
54
54
  ## [1.2.4] - 2026-08-12
55
55
  - MCP: `mcp-connect` accepts `--client-id`, `--client-secret` and `--bearer-token` and exports them into the `DATAQUERY_*` environment of the process, so the MCP bridge and the SDK share one credential set instead of each needing its own setup
56
-
57
-
56
+ ## [1.2.5] - 2026-08-21
57
+ - MCP: `mcp-connect --url` is now optional
58
+ ## [1.2.6] - 2026-09-24
59
+ - Bug fixes
60
+ - MCP: capped the `mcp` extra to `fastmcp>=2.14,<4` — fastmcp 4.x repackages onto `httpx2` and drops `FastMCP.as_proxy()`, which broke `mcp-connect`; installs now resolve to the 3.x line
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dataquery-sdk
3
- Version: 1.2.4
3
+ Version: 1.2.6
4
4
  Summary: Python SDK for DATAQUERY Data API - Query, download, and check availability of economic data files
5
5
  Author-email: DATAQUERY SDK Team <dataquery_support@jpmorgan.com>
6
6
  Project-URL: Homepage, https://github.com/jpmorganchase/dataquery-sdk
@@ -50,7 +50,7 @@ Requires-Dist: pymdown-extensions>=11.0.0; extra == "docs"
50
50
  Provides-Extra: pandas
51
51
  Requires-Dist: pandas>=2.0.0; extra == "pandas"
52
52
  Provides-Extra: mcp
53
- Requires-Dist: fastmcp>=2.14; extra == "mcp"
53
+ Requires-Dist: fastmcp<4,>=2.14; extra == "mcp"
54
54
  Provides-Extra: all
55
55
  Requires-Dist: pytest>=7.0.0; extra == "all"
56
56
  Requires-Dist: pytest-asyncio>=0.21.0; extra == "all"
@@ -63,7 +63,7 @@ Requires-Dist: mkdocs-material>=9.0.0; extra == "all"
63
63
  Requires-Dist: mkdocstrings[python]>=0.24.0; extra == "all"
64
64
  Requires-Dist: mike>=1.1.0; extra == "all"
65
65
  Requires-Dist: pandas>=2.0.0; extra == "all"
66
- Requires-Dist: fastmcp>=2.14; extra == "all"
66
+ Requires-Dist: fastmcp<4,>=2.14; extra == "all"
67
67
  Requires-Dist: pip-audit>=2.7.0; extra == "all"
68
68
  Requires-Dist: build>=1.3.0; extra == "all"
69
69
  Requires-Dist: urllib3>=2.7.0; extra == "all"
@@ -98,6 +98,7 @@ built in for both.
98
98
  - [Quick start — JSON Data API](#quick-start--json-data-api)
99
99
  - [Auto-download (SSE)](#auto-download-sse)
100
100
  - [CLI](#cli)
101
+ - [MCP bridge (`mcp-connect`)](#mcp-bridge-mcp-connect)
101
102
  - [Configuration](#configuration)
102
103
  - [Logging](#logging)
103
104
  - [Error handling](#error-handling)
@@ -140,6 +141,9 @@ through one `DataQuery` client — pick the methods that match what you need.
140
141
  - **Retry + circuit breaker** — exponential backoff, configurable failure threshold
141
142
  - **Sync and async APIs** — every operation has `_async` and sync variants
142
143
  - **CLI** — `dataquery groups | files | availability | download | download-group | auth | config`
144
+ - **MCP bridge** — `dataquery mcp-connect` connects any stdio MCP client
145
+ (Claude Desktop, Claude Code, …) to the remote DataQuery MCP server, minting
146
+ OAuth tokens for it
143
147
 
144
148
  ## New here? Three steps to your first download
145
149
 
@@ -172,6 +176,9 @@ pip install dataquery-sdk
172
176
  # With pandas DataFrame conversion
173
177
  pip install "dataquery-sdk[pandas]"
174
178
 
179
+ # With the MCP bridge (dataquery mcp-connect)
180
+ pip install "dataquery-sdk[mcp]"
181
+
175
182
  # With dev tooling (ruff, mypy, pytest)
176
183
  pip install "dataquery-sdk[dev]"
177
184
  ```
@@ -439,8 +446,134 @@ dataquery config template --output .env
439
446
  dataquery auth test
440
447
  ```
441
448
 
442
- Every subcommand accepts `--env-file PATH` (to point at a non-default `.env`) and
443
- most accept `--json` for machine-readable output.
449
+ `--env-file PATH` (to point at a non-default `.env`) is a top-level flag, so it
450
+ goes *before* the subcommand: `dataquery --env-file .env.prod groups`. Most
451
+ subcommands accept `--json` for machine-readable output.
452
+
453
+ ## MCP bridge (`mcp-connect`)
454
+
455
+ `dataquery mcp-connect` connects a desktop MCP client — Claude Desktop, Claude
456
+ Code, or any stdio MCP host — to the remote DataQuery MCP server. It speaks
457
+ stdio to the client and streamable HTTP to the server, stamping every outbound
458
+ request with a fresh OAuth (AuthE) bearer token minted from your `DATAQUERY_*`
459
+ credentials. Tokens are refreshed for the life of the session, and the MCP host
460
+ itself never handles your client secret.
461
+
462
+ It needs the `mcp` extra:
463
+
464
+ ```bash
465
+ pip install "dataquery-sdk[mcp]"
466
+ ```
467
+
468
+ ### Wire it into an MCP client
469
+
470
+ Add the server to your client's MCP config (`claude_desktop_config.json`,
471
+ `.mcp.json`, or the equivalent for your host):
472
+
473
+ ```json
474
+ {
475
+ "mcpServers": {
476
+ "dataquery": {
477
+ "command": "dataquery",
478
+ "args": ["mcp-connect", "--save-credentials"],
479
+ "env": {
480
+ "DATAQUERY_CLIENT_ID": "your_client_id",
481
+ "DATAQUERY_CLIENT_SECRET": "your_client_secret"
482
+ }
483
+ }
484
+ }
485
+ }
486
+ ```
487
+
488
+ `--save-credentials` copies the credentials it resolved into
489
+ `~/.dataquery/.env` on the first launch (see [Credentials](#credentials)). From
490
+ then on the bridge — and every other SDK call and CLI run on the machine —
491
+ finds them there, so you can drop the `env` block from the config and keep your
492
+ secret out of a file your MCP client reads on every start:
493
+
494
+ ```json
495
+ {
496
+ "mcpServers": {
497
+ "dataquery": {
498
+ "command": "dataquery",
499
+ "args": ["mcp-connect"]
500
+ }
501
+ }
502
+ }
503
+ ```
504
+
505
+ To skip installing anything, run it straight from PyPI with `uvx`:
506
+
507
+ ```json
508
+ {
509
+ "mcpServers": {
510
+ "dataquery": {
511
+ "command": "uvx",
512
+ "args": ["--from", "dataquery-sdk[mcp]", "dataquery", "mcp-connect", "--save-credentials"],
513
+ "env": {
514
+ "DATAQUERY_CLIENT_ID": "your_client_id",
515
+ "DATAQUERY_CLIENT_SECRET": "your_client_secret"
516
+ }
517
+ }
518
+ }
519
+ }
520
+ ```
521
+
522
+ ### Endpoint
523
+
524
+ `--url` is optional. The endpoint resolves as `--url` → `DATAQUERY_MCP_URL` →
525
+ the production server
526
+ `https://api-dataquery.jpmchase.com/research/dataquery-authe/v2/mcp`:
527
+
528
+ ```bash
529
+ # Production (no arguments needed)
530
+ dataquery mcp-connect
531
+
532
+ # Another environment
533
+ dataquery mcp-connect --url https://host/research/dataquery-authe/v2/mcp
534
+ DATAQUERY_MCP_URL=https://host/research/dataquery-authe/v2/mcp dataquery mcp-connect
535
+ ```
536
+
537
+ ### Credentials
538
+
539
+ Credentials resolve exactly as they do everywhere else in the SDK — flags win,
540
+ then the process environment (what your MCP client exports), then a `.env`,
541
+ then the saved user-level file:
542
+
543
+ ```bash
544
+ # From the environment (recommended)
545
+ dataquery mcp-connect
546
+
547
+ # From flags — visible in the process list, so avoid on shared machines
548
+ dataquery mcp-connect --client-id ID --client-secret SECRET
549
+
550
+ # From a non-default .env (top-level flag: before the subcommand)
551
+ dataquery --env-file .env.prod mcp-connect
552
+
553
+ # Bearer token instead of OAuth
554
+ dataquery mcp-connect --bearer-token TOKEN
555
+ ```
556
+
557
+ Pass `--save-credentials` once and the resolved credentials are written to
558
+ `~/.dataquery/.env` (owner-only `0600` file in a `0700` directory; override the
559
+ directory with `DATAQUERY_CONFIG_DIR`). Every later SDK call and CLI run reads
560
+ that file as a last-resort fallback, so a plain `DataQuery()` in a script
561
+ authenticates with no environment of its own — while shell variables and a
562
+ local `.env` still take precedence over it.
563
+
564
+ ### Flags
565
+
566
+ | Flag | Default | Purpose |
567
+ |---|---|---|
568
+ | `--url URL` | `DATAQUERY_MCP_URL`, else the PROD endpoint | Remote MCP endpoint |
569
+ | `--name NAME` | `dataquery-mcp` | Proxy server name reported to the MCP client |
570
+ | `--client-id ID` | _(from env)_ | OAuth client ID; exported as `DATAQUERY_CLIENT_ID` |
571
+ | `--client-secret SECRET` | _(from env)_ | OAuth client secret; exported as `DATAQUERY_CLIENT_SECRET` |
572
+ | `--bearer-token TOKEN` | _(from env)_ | Use a bearer token instead of OAuth |
573
+ | `--save-credentials` | off | Also persist the resolved credentials to `~/.dataquery/.env` |
574
+
575
+ Because stdout carries the JSON-RPC channel, all logging and diagnostics go to
576
+ stderr — look in your MCP client's server log when something fails.
444
577
 
445
578
  ## Configuration
446
579
 
@@ -457,6 +590,16 @@ All environment variables use the `DATAQUERY_` prefix.
457
590
  | `DATAQUERY_BEARER_TOKEN` | _(none)_ | Alternative to OAuth |
458
591
  | `DATAQUERY_OAUTH_ENABLED` | `true` | Set `false` to use bearer-token mode |
459
592
 
593
+ **Endpoints**
594
+
595
+ | Variable | Default | Notes |
596
+ |---|---|---|
597
+ | `DATAQUERY_BASE_URL` | `https://api-dataquery.jpmchase.com` | Host for both API surfaces |
598
+ | `DATAQUERY_FILES_BASE_URL` | same as `BASE_URL` | Override only if file endpoints live on another host |
599
+ | `DATAQUERY_OAUTH_TOKEN_URL` | `https://authe.jpmorgan.com/as/token.oauth2` | Token endpoint |
600
+ | `DATAQUERY_OAUTH_AUD` | PROD audience | Set to the value provisioned for your client |
601
+ | `DATAQUERY_MCP_URL` | PROD MCP endpoint | Endpoint used by [`mcp-connect`](#mcp-bridge-mcp-connect); `--url` overrides it |
602
+
460
603
  **HTTP / retry / rate limit**
461
604
 
462
605
  | Variable | Default |
@@ -621,6 +764,17 @@ async with DataQuery() as dq:
621
764
  `manager.clear_event_id()` (or `dataquery download --watch --reset-event-id`)
622
765
  only when you intentionally want a clean slate.
623
766
 
767
+ **MCP client shows the server as failed**
768
+
769
+ - `The MCP bridge requires the 'mcp' extra` in the server log means `fastmcp`
770
+ is missing — `pip install "dataquery-sdk[mcp]"`, or use the `uvx` form.
771
+ - MCP hosts usually launch the command with a minimal environment, so a
772
+ `.env` in your shell's working directory may not be visible. Put the
773
+ credentials in the server's `env` block, or run `dataquery mcp-connect
774
+ --save-credentials` once from a terminal where they do resolve.
775
+ - Auth failures surface as `Could not obtain an OAuth token`; verify the same
776
+ credentials with `dataquery auth test` before debugging the bridge.
777
+
624
778
  ## Date formats
625
779
 
626
780
  ```python
@@ -26,6 +26,7 @@ built in for both.
26
26
  - [Quick start — JSON Data API](#quick-start--json-data-api)
27
27
  - [Auto-download (SSE)](#auto-download-sse)
28
28
  - [CLI](#cli)
29
+ - [MCP bridge (`mcp-connect`)](#mcp-bridge-mcp-connect)
29
30
  - [Configuration](#configuration)
30
31
  - [Logging](#logging)
31
32
  - [Error handling](#error-handling)
@@ -68,6 +69,9 @@ through one `DataQuery` client — pick the methods that match what you need.
68
69
  - **Retry + circuit breaker** — exponential backoff, configurable failure threshold
69
70
  - **Sync and async APIs** — every operation has `_async` and sync variants
70
71
  - **CLI** — `dataquery groups | files | availability | download | download-group | auth | config`
72
+ - **MCP bridge** — `dataquery mcp-connect` connects any stdio MCP client
73
+ (Claude Desktop, Claude Code, …) to the remote DataQuery MCP server, minting
74
+ OAuth tokens for it
71
75
 
72
76
  ## New here? Three steps to your first download
73
77
 
@@ -100,6 +104,9 @@ pip install dataquery-sdk
100
104
  # With pandas DataFrame conversion
101
105
  pip install "dataquery-sdk[pandas]"
102
106
 
107
+ # With the MCP bridge (dataquery mcp-connect)
108
+ pip install "dataquery-sdk[mcp]"
109
+
103
110
  # With dev tooling (ruff, mypy, pytest)
104
111
  pip install "dataquery-sdk[dev]"
105
112
  ```
@@ -367,8 +374,134 @@ dataquery config template --output .env
367
374
  dataquery auth test
368
375
  ```
369
376
 
370
- Every subcommand accepts `--env-file PATH` (to point at a non-default `.env`) and
371
- most accept `--json` for machine-readable output.
377
+ `--env-file PATH` (to point at a non-default `.env`) is a top-level flag, so it
378
+ goes *before* the subcommand: `dataquery --env-file .env.prod groups`. Most
379
+ subcommands accept `--json` for machine-readable output.
380
+
381
+ ## MCP bridge (`mcp-connect`)
382
+
383
+ `dataquery mcp-connect` connects a desktop MCP client — Claude Desktop, Claude
384
+ Code, or any stdio MCP host — to the remote DataQuery MCP server. It speaks
385
+ stdio to the client and streamable HTTP to the server, stamping every outbound
386
+ request with a fresh OAuth (AuthE) bearer token minted from your `DATAQUERY_*`
387
+ credentials. Tokens are refreshed for the life of the session, and the MCP host
388
+ itself never handles your client secret.
389
+
390
+ It needs the `mcp` extra:
391
+
392
+ ```bash
393
+ pip install "dataquery-sdk[mcp]"
394
+ ```
395
+
396
+ ### Wire it into an MCP client
397
+
398
+ Add the server to your client's MCP config (`claude_desktop_config.json`,
399
+ `.mcp.json`, or the equivalent for your host):
400
+
401
+ ```json
402
+ {
403
+ "mcpServers": {
404
+ "dataquery": {
405
+ "command": "dataquery",
406
+ "args": ["mcp-connect", "--save-credentials"],
407
+ "env": {
408
+ "DATAQUERY_CLIENT_ID": "your_client_id",
409
+ "DATAQUERY_CLIENT_SECRET": "your_client_secret"
410
+ }
411
+ }
412
+ }
413
+ }
414
+ ```
415
+
416
+ `--save-credentials` copies the credentials it resolved into
417
+ `~/.dataquery/.env` on the first launch (see [Credentials](#credentials)). From
418
+ then on the bridge — and every other SDK call and CLI run on the machine —
419
+ finds them there, so you can drop the `env` block from the config and keep your
420
+ secret out of a file your MCP client reads on every start:
421
+
422
+ ```json
423
+ {
424
+ "mcpServers": {
425
+ "dataquery": {
426
+ "command": "dataquery",
427
+ "args": ["mcp-connect"]
428
+ }
429
+ }
430
+ }
431
+ ```
432
+
433
+ To skip installing anything, run it straight from PyPI with `uvx`:
434
+
435
+ ```json
436
+ {
437
+ "mcpServers": {
438
+ "dataquery": {
439
+ "command": "uvx",
440
+ "args": ["--from", "dataquery-sdk[mcp]", "dataquery", "mcp-connect", "--save-credentials"],
441
+ "env": {
442
+ "DATAQUERY_CLIENT_ID": "your_client_id",
443
+ "DATAQUERY_CLIENT_SECRET": "your_client_secret"
444
+ }
445
+ }
446
+ }
447
+ }
448
+ ```
449
+
450
+ ### Endpoint
451
+
452
+ `--url` is optional. The endpoint resolves as `--url` → `DATAQUERY_MCP_URL` →
453
+ the production server
454
+ `https://api-dataquery.jpmchase.com/research/dataquery-authe/v2/mcp`:
455
+
456
+ ```bash
457
+ # Production (no arguments needed)
458
+ dataquery mcp-connect
459
+
460
+ # Another environment
461
+ dataquery mcp-connect --url https://host/research/dataquery-authe/v2/mcp
462
+ DATAQUERY_MCP_URL=https://host/research/dataquery-authe/v2/mcp dataquery mcp-connect
463
+ ```
464
+
465
+ ### Credentials
466
+
467
+ Credentials resolve exactly as they do everywhere else in the SDK — flags win,
468
+ then the process environment (what your MCP client exports), then a `.env`,
469
+ then the saved user-level file:
470
+
471
+ ```bash
472
+ # From the environment (recommended)
473
+ dataquery mcp-connect
474
+
475
+ # From flags — visible in the process list, so avoid on shared machines
476
+ dataquery mcp-connect --client-id ID --client-secret SECRET
477
+
478
+ # From a non-default .env (top-level flag: before the subcommand)
479
+ dataquery --env-file .env.prod mcp-connect
480
+
481
+ # Bearer token instead of OAuth
482
+ dataquery mcp-connect --bearer-token TOKEN
483
+ ```
484
+
485
+ Pass `--save-credentials` once and the resolved credentials are written to
486
+ `~/.dataquery/.env` (owner-only `0600` file in a `0700` directory; override the
487
+ directory with `DATAQUERY_CONFIG_DIR`). Every later SDK call and CLI run reads
488
+ that file as a last-resort fallback, so a plain `DataQuery()` in a script
489
+ authenticates with no environment of its own — while shell variables and a
490
+ local `.env` still take precedence over it.
491
+
492
+ ### Flags
493
+
494
+ | Flag | Default | Purpose |
495
+ |---|---|---|
496
+ | `--url URL` | `DATAQUERY_MCP_URL`, else the PROD endpoint | Remote MCP endpoint |
497
+ | `--name NAME` | `dataquery-mcp` | Proxy server name reported to the MCP client |
498
+ | `--client-id ID` | _(from env)_ | OAuth client ID; exported as `DATAQUERY_CLIENT_ID` |
499
+ | `--client-secret SECRET` | _(from env)_ | OAuth client secret; exported as `DATAQUERY_CLIENT_SECRET` |
500
+ | `--bearer-token TOKEN` | _(from env)_ | Use a bearer token instead of OAuth |
501
+ | `--save-credentials` | off | Also persist the resolved credentials to `~/.dataquery/.env` |
502
+
503
+ Because stdout carries the JSON-RPC channel, all logging and diagnostics go to
504
+ stderr — look in your MCP client's server log when something fails.
372
505
 
373
506
  ## Configuration
374
507
 
@@ -385,6 +518,16 @@ All environment variables use the `DATAQUERY_` prefix.
385
518
  | `DATAQUERY_BEARER_TOKEN` | _(none)_ | Alternative to OAuth |
386
519
  | `DATAQUERY_OAUTH_ENABLED` | `true` | Set `false` to use bearer-token mode |
387
520
 
521
+ **Endpoints**
522
+
523
+ | Variable | Default | Notes |
524
+ |---|---|---|
525
+ | `DATAQUERY_BASE_URL` | `https://api-dataquery.jpmchase.com` | Host for both API surfaces |
526
+ | `DATAQUERY_FILES_BASE_URL` | same as `BASE_URL` | Override only if file endpoints live on another host |
527
+ | `DATAQUERY_OAUTH_TOKEN_URL` | `https://authe.jpmorgan.com/as/token.oauth2` | Token endpoint |
528
+ | `DATAQUERY_OAUTH_AUD` | PROD audience | Set to the value provisioned for your client |
529
+ | `DATAQUERY_MCP_URL` | PROD MCP endpoint | Endpoint used by [`mcp-connect`](#mcp-bridge-mcp-connect); `--url` overrides it |
530
+
388
531
  **HTTP / retry / rate limit**
389
532
 
390
533
  | Variable | Default |
@@ -549,6 +692,17 @@ async with DataQuery() as dq:
549
692
  `manager.clear_event_id()` (or `dataquery download --watch --reset-event-id`)
550
693
  only when you intentionally want a clean slate.
551
694
 
695
+ **MCP client shows the server as failed**
696
+
697
+ - `The MCP bridge requires the 'mcp' extra` in the server log means `fastmcp`
698
+ is missing — `pip install "dataquery-sdk[mcp]"`, or use the `uvx` form.
699
+ - MCP hosts usually launch the command with a minimal environment, so a
700
+ `.env` in your shell's working directory may not be visible. Put the
701
+ credentials in the server's `env` block, or run `dataquery mcp-connect
702
+ --save-credentials` once from a terminal where they do resolve.
703
+ - Auth failures surface as `Could not obtain an OAuth token`; verify the same
704
+ credentials with `dataquery auth test` before debugging the bridge.
705
+
552
706
  ## Date formats
553
707
 
554
708
  ```python
@@ -1,6 +1,6 @@
1
1
  """DATAQUERY SDK - Python SDK for DATAQUERY Data API."""
2
2
 
3
- __version__ = "1.2.4"
3
+ __version__ = "1.2.6"
4
4
  __author__ = "DATAQUERY SDK Team"
5
5
  __email__ = "dataquery_support@jpmorgan.com"
6
6
  __license__ = "MIT"
@@ -353,7 +353,10 @@ def create_parser() -> argparse.ArgumentParser:
353
353
  "Bridge a desktop MCP client (stdio) to a remote streamable-HTTP MCP\n"
354
354
  "server, authenticating with an OAuth client-credentials (AuthE) token\n"
355
355
  "minted from the DATAQUERY_* environment. Point your MCP client's\n"
356
- "`command` at: dataquery mcp-connect --url <MCP_URL>\n"
356
+ "`command` at: dataquery mcp-connect\n"
357
+ "\n"
358
+ "The endpoint defaults to the PROD MCP server; override it with --url\n"
359
+ "or DATAQUERY_MCP_URL to reach a different environment.\n"
357
360
  "\n"
358
361
  "Credentials passed as flags are exported into the DATAQUERY_*\n"
359
362
  "environment of this process; add --save-credentials to also write\n"
@@ -362,7 +365,11 @@ def create_parser() -> argparse.ArgumentParser:
362
365
  ),
363
366
  formatter_class=argparse.RawDescriptionHelpFormatter,
364
367
  )
365
- p_connect.add_argument("--url", required=True, help="Remote MCP endpoint URL")
368
+ p_connect.add_argument(
369
+ "--url",
370
+ default=None,
371
+ help="Remote MCP endpoint URL (default: DATAQUERY_MCP_URL, else the PROD MCP endpoint)",
372
+ )
366
373
  p_connect.add_argument("--name", default="dataquery-mcp", help="Proxy server name (default: dataquery-mcp)")
367
374
  p_connect.add_argument("--client-id", default=None, help="OAuth client ID (exported as DATAQUERY_CLIENT_ID)")
368
375
  p_connect.add_argument(
@@ -817,7 +824,7 @@ async def cmd_mcp_connect(args: argparse.Namespace) -> int:
817
824
  "The MCP bridge requires the 'mcp' extra. Install it with:\n"
818
825
  " pip install 'dataquery-sdk[mcp]'\n"
819
826
  "or run it directly with:\n"
820
- " uvx --from 'dataquery-sdk[mcp]' dataquery mcp-connect --url <MCP_URL>",
827
+ " uvx --from 'dataquery-sdk[mcp]' dataquery mcp-connect",
821
828
  file=sys.stderr,
822
829
  )
823
830
  return 1
@@ -836,6 +843,15 @@ async def cmd_mcp_connect(args: argparse.Namespace) -> int:
836
843
  _save_mcp_credentials(savable)
837
844
 
838
845
  config = EnvConfig.create_client_config()
846
+ # --url wins; otherwise DATAQUERY_MCP_URL, and failing that the model
847
+ # default (PROD). Only an explicitly emptied env var leaves it unset.
848
+ url = getattr(args, "url", None) or config.mcp_url
849
+ if not url:
850
+ print(
851
+ "No MCP endpoint configured: pass --url or set DATAQUERY_MCP_URL.",
852
+ file=sys.stderr,
853
+ )
854
+ return 1
839
855
  token_manager = TokenManager(config)
840
856
 
841
857
  class _AutheAuth(httpx.Auth):
@@ -852,7 +868,7 @@ async def cmd_mcp_connect(args: argparse.Namespace) -> int:
852
868
  request.headers["Authorization"] = header
853
869
  yield request
854
870
 
855
- transport = StreamableHttpTransport(args.url, auth=_AutheAuth())
871
+ transport = StreamableHttpTransport(url, auth=_AutheAuth())
856
872
  proxy = FastMCP.as_proxy(transport, name=args.name)
857
873
  await proxy.run_async(transport="stdio", show_banner=False)
858
874
  return 0
@@ -212,10 +212,20 @@ def _emit_stdout(message: Dict[str, Any]) -> None:
212
212
  sys.stdout.flush()
213
213
 
214
214
 
215
- async def run_mcp_proxy(url: str, env_file: Optional[Path] = None) -> int:
216
- """Run the stdio <-> Streamable HTTP proxy until stdin closes."""
215
+ async def run_mcp_proxy(url: Optional[str] = None, env_file: Optional[Path] = None) -> int:
216
+ """Run the stdio <-> Streamable HTTP proxy until stdin closes.
217
+
218
+ ``url`` defaults to ``DATAQUERY_MCP_URL``, and failing that to the PROD MCP
219
+ endpoint carried by :class:`ClientConfig`.
220
+ """
217
221
  _configure_stderr_logging()
218
222
  try:
223
+ if env_file is not None:
224
+ EnvConfig.load_env_file(env_file)
225
+ EnvConfig.load_user_env_file()
226
+ url = url or EnvConfig.get_env_var("MCP_URL")
227
+ if not url:
228
+ raise ConfigurationError("No MCP endpoint configured: pass a url or set DATAQUERY_MCP_URL")
219
229
  oauth = _build_oauth_manager(url, env_file)
220
230
  await oauth.authenticate()
221
231
  except (ConfigurationError, AuthenticationError) as exc:
@@ -63,6 +63,10 @@ class ClientConfig(BaseModel):
63
63
  default="/research/dataquery-authe/api/v2",
64
64
  description="Context path for the files host",
65
65
  )
66
+ mcp_url: Optional[str] = Field(
67
+ default="https://api-dataquery.jpmchase.com/research/dataquery-authe/v2/mcp",
68
+ description="Remote MCP endpoint bridged by `dataquery mcp-connect`",
69
+ )
66
70
 
67
71
  oauth_enabled: bool = Field(default=True, description="Enable OAuth authentication")
68
72
  oauth_token_url: Optional[str] = Field(
@@ -52,6 +52,10 @@ DATAQUERY_BASE_URL=https://api-dataquery.jpmchase.com
52
52
  # DATAQUERY_FILES_BASE_URL=https://api-dataquery.jpmchase.com
53
53
  # DATAQUERY_FILES_CONTEXT_PATH=/research/dataquery-authe/api/v2
54
54
 
55
+ # Optional: remote MCP endpoint bridged by `dataquery mcp-connect`
56
+ # Defaults to the PROD endpoint below; override for another environment.
57
+ # DATAQUERY_MCP_URL=https://api-dataquery.jpmchase.com/research/dataquery-authe/v2/mcp
58
+
55
59
  # =============================================================================
56
60
  # AUTHENTICATION: OAuth 2.0 Configuration (Recommended)
57
61
  # =============================================================================
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dataquery-sdk
3
- Version: 1.2.4
3
+ Version: 1.2.6
4
4
  Summary: Python SDK for DATAQUERY Data API - Query, download, and check availability of economic data files
5
5
  Author-email: DATAQUERY SDK Team <dataquery_support@jpmorgan.com>
6
6
  Project-URL: Homepage, https://github.com/jpmorganchase/dataquery-sdk
@@ -50,7 +50,7 @@ Requires-Dist: pymdown-extensions>=11.0.0; extra == "docs"
50
50
  Provides-Extra: pandas
51
51
  Requires-Dist: pandas>=2.0.0; extra == "pandas"
52
52
  Provides-Extra: mcp
53
- Requires-Dist: fastmcp>=2.14; extra == "mcp"
53
+ Requires-Dist: fastmcp<4,>=2.14; extra == "mcp"
54
54
  Provides-Extra: all
55
55
  Requires-Dist: pytest>=7.0.0; extra == "all"
56
56
  Requires-Dist: pytest-asyncio>=0.21.0; extra == "all"
@@ -63,7 +63,7 @@ Requires-Dist: mkdocs-material>=9.0.0; extra == "all"
63
63
  Requires-Dist: mkdocstrings[python]>=0.24.0; extra == "all"
64
64
  Requires-Dist: mike>=1.1.0; extra == "all"
65
65
  Requires-Dist: pandas>=2.0.0; extra == "all"
66
- Requires-Dist: fastmcp>=2.14; extra == "all"
66
+ Requires-Dist: fastmcp<4,>=2.14; extra == "all"
67
67
  Requires-Dist: pip-audit>=2.7.0; extra == "all"
68
68
  Requires-Dist: build>=1.3.0; extra == "all"
69
69
  Requires-Dist: urllib3>=2.7.0; extra == "all"
@@ -98,6 +98,7 @@ built in for both.
98
98
  - [Quick start — JSON Data API](#quick-start--json-data-api)
99
99
  - [Auto-download (SSE)](#auto-download-sse)
100
100
  - [CLI](#cli)
101
+ - [MCP bridge (`mcp-connect`)](#mcp-bridge-mcp-connect)
101
102
  - [Configuration](#configuration)
102
103
  - [Logging](#logging)
103
104
  - [Error handling](#error-handling)
@@ -140,6 +141,9 @@ through one `DataQuery` client — pick the methods that match what you need.
140
141
  - **Retry + circuit breaker** — exponential backoff, configurable failure threshold
141
142
  - **Sync and async APIs** — every operation has `_async` and sync variants
142
143
  - **CLI** — `dataquery groups | files | availability | download | download-group | auth | config`
144
+ - **MCP bridge** — `dataquery mcp-connect` connects any stdio MCP client
145
+ (Claude Desktop, Claude Code, …) to the remote DataQuery MCP server, minting
146
+ OAuth tokens for it
143
147
 
144
148
  ## New here? Three steps to your first download
145
149
 
@@ -172,6 +176,9 @@ pip install dataquery-sdk
172
176
  # With pandas DataFrame conversion
173
177
  pip install "dataquery-sdk[pandas]"
174
178
 
179
+ # With the MCP bridge (dataquery mcp-connect)
180
+ pip install "dataquery-sdk[mcp]"
181
+
175
182
  # With dev tooling (ruff, mypy, pytest)
176
183
  pip install "dataquery-sdk[dev]"
177
184
  ```
@@ -439,8 +446,134 @@ dataquery config template --output .env
439
446
  dataquery auth test
440
447
  ```
441
448
 
442
- Every subcommand accepts `--env-file PATH` (to point at a non-default `.env`) and
443
- most accept `--json` for machine-readable output.
449
+ `--env-file PATH` (to point at a non-default `.env`) is a top-level flag, so it
450
+ goes *before* the subcommand: `dataquery --env-file .env.prod groups`. Most
451
+ subcommands accept `--json` for machine-readable output.
452
+
453
+ ## MCP bridge (`mcp-connect`)
454
+
455
+ `dataquery mcp-connect` connects a desktop MCP client — Claude Desktop, Claude
456
+ Code, or any stdio MCP host — to the remote DataQuery MCP server. It speaks
457
+ stdio to the client and streamable HTTP to the server, stamping every outbound
458
+ request with a fresh OAuth (AuthE) bearer token minted from your `DATAQUERY_*`
459
+ credentials. Tokens are refreshed for the life of the session, and the MCP host
460
+ itself never handles your client secret.
461
+
462
+ It needs the `mcp` extra:
463
+
464
+ ```bash
465
+ pip install "dataquery-sdk[mcp]"
466
+ ```
467
+
468
+ ### Wire it into an MCP client
469
+
470
+ Add the server to your client's MCP config (`claude_desktop_config.json`,
471
+ `.mcp.json`, or the equivalent for your host):
472
+
473
+ ```json
474
+ {
475
+ "mcpServers": {
476
+ "dataquery": {
477
+ "command": "dataquery",
478
+ "args": ["mcp-connect", "--save-credentials"],
479
+ "env": {
480
+ "DATAQUERY_CLIENT_ID": "your_client_id",
481
+ "DATAQUERY_CLIENT_SECRET": "your_client_secret"
482
+ }
483
+ }
484
+ }
485
+ }
486
+ ```
487
+
488
+ `--save-credentials` copies the credentials it resolved into
489
+ `~/.dataquery/.env` on the first launch (see [Credentials](#credentials)). From
490
+ then on the bridge — and every other SDK call and CLI run on the machine —
491
+ finds them there, so you can drop the `env` block from the config and keep your
492
+ secret out of a file your MCP client reads on every start:
493
+
494
+ ```json
495
+ {
496
+ "mcpServers": {
497
+ "dataquery": {
498
+ "command": "dataquery",
499
+ "args": ["mcp-connect"]
500
+ }
501
+ }
502
+ }
503
+ ```
504
+
505
+ To skip installing anything, run it straight from PyPI with `uvx`:
506
+
507
+ ```json
508
+ {
509
+ "mcpServers": {
510
+ "dataquery": {
511
+ "command": "uvx",
512
+ "args": ["--from", "dataquery-sdk[mcp]", "dataquery", "mcp-connect", "--save-credentials"],
513
+ "env": {
514
+ "DATAQUERY_CLIENT_ID": "your_client_id",
515
+ "DATAQUERY_CLIENT_SECRET": "your_client_secret"
516
+ }
517
+ }
518
+ }
519
+ }
520
+ ```
521
+
522
+ ### Endpoint
523
+
524
+ `--url` is optional. The endpoint resolves as `--url` → `DATAQUERY_MCP_URL` →
525
+ the production server
526
+ `https://api-dataquery.jpmchase.com/research/dataquery-authe/v2/mcp`:
527
+
528
+ ```bash
529
+ # Production (no arguments needed)
530
+ dataquery mcp-connect
531
+
532
+ # Another environment
533
+ dataquery mcp-connect --url https://host/research/dataquery-authe/v2/mcp
534
+ DATAQUERY_MCP_URL=https://host/research/dataquery-authe/v2/mcp dataquery mcp-connect
535
+ ```
536
+
537
+ ### Credentials
538
+
539
+ Credentials resolve exactly as they do everywhere else in the SDK — flags win,
540
+ then the process environment (what your MCP client exports), then a `.env`,
541
+ then the saved user-level file:
542
+
543
+ ```bash
544
+ # From the environment (recommended)
545
+ dataquery mcp-connect
546
+
547
+ # From flags — visible in the process list, so avoid on shared machines
548
+ dataquery mcp-connect --client-id ID --client-secret SECRET
549
+
550
+ # From a non-default .env (top-level flag: before the subcommand)
551
+ dataquery --env-file .env.prod mcp-connect
552
+
553
+ # Bearer token instead of OAuth
554
+ dataquery mcp-connect --bearer-token TOKEN
555
+ ```
556
+
557
+ Pass `--save-credentials` once and the resolved credentials are written to
558
+ `~/.dataquery/.env` (owner-only `0600` file in a `0700` directory; override the
559
+ directory with `DATAQUERY_CONFIG_DIR`). Every later SDK call and CLI run reads
560
+ that file as a last-resort fallback, so a plain `DataQuery()` in a script
561
+ authenticates with no environment of its own — while shell variables and a
562
+ local `.env` still take precedence over it.
563
+
564
+ ### Flags
565
+
566
+ | Flag | Default | Purpose |
567
+ |---|---|---|
568
+ | `--url URL` | `DATAQUERY_MCP_URL`, else the PROD endpoint | Remote MCP endpoint |
569
+ | `--name NAME` | `dataquery-mcp` | Proxy server name reported to the MCP client |
570
+ | `--client-id ID` | _(from env)_ | OAuth client ID; exported as `DATAQUERY_CLIENT_ID` |
571
+ | `--client-secret SECRET` | _(from env)_ | OAuth client secret; exported as `DATAQUERY_CLIENT_SECRET` |
572
+ | `--bearer-token TOKEN` | _(from env)_ | Use a bearer token instead of OAuth |
573
+ | `--save-credentials` | off | Also persist the resolved credentials to `~/.dataquery/.env` |
574
+
575
+ Because stdout carries the JSON-RPC channel, all logging and diagnostics go to
576
+ stderr — look in your MCP client's server log when something fails.
444
577
 
445
578
  ## Configuration
446
579
 
@@ -457,6 +590,16 @@ All environment variables use the `DATAQUERY_` prefix.
457
590
  | `DATAQUERY_BEARER_TOKEN` | _(none)_ | Alternative to OAuth |
458
591
  | `DATAQUERY_OAUTH_ENABLED` | `true` | Set `false` to use bearer-token mode |
459
592
 
593
+ **Endpoints**
594
+
595
+ | Variable | Default | Notes |
596
+ |---|---|---|
597
+ | `DATAQUERY_BASE_URL` | `https://api-dataquery.jpmchase.com` | Host for both API surfaces |
598
+ | `DATAQUERY_FILES_BASE_URL` | same as `BASE_URL` | Override only if file endpoints live on another host |
599
+ | `DATAQUERY_OAUTH_TOKEN_URL` | `https://authe.jpmorgan.com/as/token.oauth2` | Token endpoint |
600
+ | `DATAQUERY_OAUTH_AUD` | PROD audience | Set to the value provisioned for your client |
601
+ | `DATAQUERY_MCP_URL` | PROD MCP endpoint | Endpoint used by [`mcp-connect`](#mcp-bridge-mcp-connect); `--url` overrides it |
602
+
460
603
  **HTTP / retry / rate limit**
461
604
 
462
605
  | Variable | Default |
@@ -621,6 +764,17 @@ async with DataQuery() as dq:
621
764
  `manager.clear_event_id()` (or `dataquery download --watch --reset-event-id`)
622
765
  only when you intentionally want a clean slate.
623
766
 
767
+ **MCP client shows the server as failed**
768
+
769
+ - `The MCP bridge requires the 'mcp' extra` in the server log means `fastmcp`
770
+ is missing — `pip install "dataquery-sdk[mcp]"`, or use the `uvx` form.
771
+ - MCP hosts usually launch the command with a minimal environment, so a
772
+ `.env` in your shell's working directory may not be visible. Put the
773
+ credentials in the server's `env` block, or run `dataquery mcp-connect
774
+ --save-credentials` once from a terminal where they do resolve.
775
+ - Auth failures surface as `Could not obtain an OAuth token`; verify the same
776
+ credentials with `dataquery auth test` before debugging the bridge.
777
+
624
778
  ## Date formats
625
779
 
626
780
  ```python
@@ -16,7 +16,7 @@ mkdocs-material>=9.0.0
16
16
  mkdocstrings[python]>=0.24.0
17
17
  mike>=1.1.0
18
18
  pandas>=2.0.0
19
- fastmcp>=2.14
19
+ fastmcp<4,>=2.14
20
20
  pip-audit>=2.7.0
21
21
  build>=1.3.0
22
22
  urllib3>=2.7.0
@@ -42,7 +42,7 @@ mike>=1.1.0
42
42
  pymdown-extensions>=11.0.0
43
43
 
44
44
  [mcp]
45
- fastmcp>=2.14
45
+ fastmcp<4,>=2.14
46
46
 
47
47
  [pandas]
48
48
  pandas>=2.0.0
@@ -77,7 +77,7 @@ pandas = [
77
77
  "pandas>=2.0.0",
78
78
  ]
79
79
  mcp = [
80
- "fastmcp>=2.14",
80
+ "fastmcp>=2.14,<4",
81
81
  ]
82
82
  all = [
83
83
  "pytest>=7.0.0",
@@ -91,7 +91,7 @@ all = [
91
91
  "mkdocstrings[python]>=0.24.0",
92
92
  "mike>=1.1.0",
93
93
  "pandas>=2.0.0",
94
- "fastmcp>=2.14",
94
+ "fastmcp>=2.14,<4",
95
95
  "pip-audit>=2.7.0",
96
96
  "build>=1.3.0",
97
97
  "urllib3>=2.7.0",
File without changes
File without changes
File without changes