alloc-context 0.2.0__tar.gz → 0.2.2__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 (168) hide show
  1. {alloc_context-0.2.0 → alloc_context-0.2.2}/PKG-INFO +12 -3
  2. {alloc_context-0.2.0 → alloc_context-0.2.2}/README.md +9 -0
  3. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloc_context.egg-info/PKG-INFO +12 -3
  4. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloc_context.egg-info/SOURCES.txt +5 -0
  5. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/__init__.py +1 -1
  6. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/mcp/bazaar.py +141 -172
  7. alloc_context-0.2.2/alloccontext/mcp/glama.py +51 -0
  8. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/mcp/http.py +25 -0
  9. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/mcp/server.py +124 -61
  10. alloc_context-0.2.2/alloccontext/mcp/tool_catalog.py +311 -0
  11. alloc_context-0.2.2/alloccontext/mcp/tool_fields.py +130 -0
  12. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/x402_production_check.py +12 -2
  13. {alloc_context-0.2.0 → alloc_context-0.2.2}/pyproject.toml +8 -4
  14. alloc_context-0.2.2/tests/test_glama_well_known.py +51 -0
  15. {alloc_context-0.2.0 → alloc_context-0.2.2}/tests/test_mcp_bazaar.py +34 -0
  16. alloc_context-0.2.2/tests/test_mcp_server.py +47 -0
  17. alloc_context-0.2.2/tests/test_tool_catalog.py +65 -0
  18. {alloc_context-0.2.0 → alloc_context-0.2.2}/tests/test_workflows.py +6 -0
  19. {alloc_context-0.2.0 → alloc_context-0.2.2}/tests/test_x402_production_check.py +3 -3
  20. alloc_context-0.2.0/tests/test_mcp_server.py +0 -26
  21. {alloc_context-0.2.0 → alloc_context-0.2.2}/LICENSE +0 -0
  22. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloc_context.egg-info/dependency_links.txt +0 -0
  23. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloc_context.egg-info/entry_points.txt +0 -0
  24. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloc_context.egg-info/requires.txt +0 -0
  25. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloc_context.egg-info/top_level.txt +0 -0
  26. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/__main__.py +0 -0
  27. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/config.py +0 -0
  28. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/constants.py +0 -0
  29. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/horizon.py +0 -0
  30. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/ingest/__init__.py +0 -0
  31. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/ingest/alt_quote_registry.py +0 -0
  32. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/ingest/alt_quote_store.py +0 -0
  33. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/ingest/alt_quotes.py +0 -0
  34. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/ingest/asset_registry.py +0 -0
  35. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/ingest/cf_benchmarks.py +0 -0
  36. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/ingest/cf_history.py +0 -0
  37. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/ingest/coinbase_client.py +0 -0
  38. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/ingest/coinbase_portfolio.py +0 -0
  39. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/ingest/coingecko.py +0 -0
  40. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/ingest/coinmarketcap.py +0 -0
  41. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/ingest/env_keys.py +0 -0
  42. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/ingest/etf_flows.py +0 -0
  43. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/ingest/exchange/__init__.py +0 -0
  44. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/ingest/exchange/coinbase_adapter.py +0 -0
  45. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/ingest/exchange/kraken_adapter.py +0 -0
  46. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/ingest/exchange/live.py +0 -0
  47. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/ingest/exchange/portfolio.py +0 -0
  48. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/ingest/exchange/registry.py +0 -0
  49. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/ingest/exchange/types.py +0 -0
  50. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/ingest/exchange_http.py +0 -0
  51. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/ingest/fear_greed.py +0 -0
  52. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/ingest/fred.py +0 -0
  53. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/ingest/http_errors.py +0 -0
  54. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/ingest/kalshi.py +0 -0
  55. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/ingest/kalshi_api.py +0 -0
  56. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/ingest/kalshi_client.py +0 -0
  57. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/ingest/kalshi_files.py +0 -0
  58. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/ingest/kalshi_state.py +0 -0
  59. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/ingest/kraken_client.py +0 -0
  60. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/ingest/kraken_portfolio.py +0 -0
  61. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/ingest/macro_calendar.py +0 -0
  62. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/ingest/macro_normalize.py +0 -0
  63. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/ingest/market_snapshots.py +0 -0
  64. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/ingest/outcome.py +0 -0
  65. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/ingest/parse_helpers.py +0 -0
  66. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/ingest/portfolio_holdings.py +0 -0
  67. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/ingest/quote_resolver.py +0 -0
  68. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/ingest/runner.py +0 -0
  69. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/mcp/__init__.py +0 -0
  70. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/mcp/assets.py +0 -0
  71. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/mcp/bridge.py +0 -0
  72. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/mcp/bridge_portfolio.py +0 -0
  73. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/mcp/contracts.py +0 -0
  74. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/mcp/handlers.py +0 -0
  75. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/mcp/instructions.py +0 -0
  76. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/mcp/payer.py +0 -0
  77. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/mcp/payment_middleware.py +0 -0
  78. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/mcp/setup.py +0 -0
  79. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/mcp/staleness.py +0 -0
  80. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/mcp/upstream.py +0 -0
  81. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/mcp/validation.py +0 -0
  82. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/mcp/x402_bazaar_dynamic.py +0 -0
  83. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/mcp/x402_config.py +0 -0
  84. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/mcp/x402_pricing.py +0 -0
  85. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/mcp/x402_stables.py +0 -0
  86. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/rollup/__init__.py +0 -0
  87. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/rollup/allocation_analysis.py +0 -0
  88. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/rollup/band.py +0 -0
  89. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/rollup/breadth.py +0 -0
  90. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/rollup/cf_math.py +0 -0
  91. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/rollup/cluster.py +0 -0
  92. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/rollup/cluster_config.py +0 -0
  93. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/rollup/comparison.py +0 -0
  94. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/rollup/context.py +0 -0
  95. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/rollup/delta.py +0 -0
  96. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/rollup/etf.py +0 -0
  97. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/rollup/fear_greed.py +0 -0
  98. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/rollup/macro.py +0 -0
  99. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/rollup/portfolio.py +0 -0
  100. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/rollup/portfolio_payload.py +0 -0
  101. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/rollup/rebalance.py +0 -0
  102. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/rollup/regime.py +0 -0
  103. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/rollup/sentiment.py +0 -0
  104. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/rollup/snapshots.py +0 -0
  105. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/rollup/tape.py +0 -0
  106. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/status_report.py +0 -0
  107. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/store/__init__.py +0 -0
  108. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/store/db.py +0 -0
  109. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/store/jsonutil.py +0 -0
  110. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/store/meta.py +0 -0
  111. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/store/retention.py +0 -0
  112. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/store/status.py +0 -0
  113. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/timeutil.py +0 -0
  114. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/user_config.py +0 -0
  115. {alloc_context-0.2.0 → alloc_context-0.2.2}/alloccontext/x402_smoke_redact.py +0 -0
  116. {alloc_context-0.2.0 → alloc_context-0.2.2}/setup.cfg +0 -0
  117. {alloc_context-0.2.0 → alloc_context-0.2.2}/tests/test_backup_sqlite.py +0 -0
  118. {alloc_context-0.2.0 → alloc_context-0.2.2}/tests/test_bridge.py +0 -0
  119. {alloc_context-0.2.0 → alloc_context-0.2.2}/tests/test_bridge_portfolio.py +0 -0
  120. {alloc_context-0.2.0 → alloc_context-0.2.2}/tests/test_bump_version.py +0 -0
  121. {alloc_context-0.2.0 → alloc_context-0.2.2}/tests/test_coinbase_portfolio.py +0 -0
  122. {alloc_context-0.2.0 → alloc_context-0.2.2}/tests/test_config_cli.py +0 -0
  123. {alloc_context-0.2.0 → alloc_context-0.2.2}/tests/test_context_bundle_schema.py +0 -0
  124. {alloc_context-0.2.0 → alloc_context-0.2.2}/tests/test_context_snapshots.py +0 -0
  125. {alloc_context-0.2.0 → alloc_context-0.2.2}/tests/test_db_schema.py +0 -0
  126. {alloc_context-0.2.0 → alloc_context-0.2.2}/tests/test_deploy.py +0 -0
  127. {alloc_context-0.2.0 → alloc_context-0.2.2}/tests/test_dev_stack.py +0 -0
  128. {alloc_context-0.2.0 → alloc_context-0.2.2}/tests/test_etf.py +0 -0
  129. {alloc_context-0.2.0 → alloc_context-0.2.2}/tests/test_exchanges_config.py +0 -0
  130. {alloc_context-0.2.0 → alloc_context-0.2.2}/tests/test_fear_greed.py +0 -0
  131. {alloc_context-0.2.0 → alloc_context-0.2.2}/tests/test_fred.py +0 -0
  132. {alloc_context-0.2.0 → alloc_context-0.2.2}/tests/test_holdings_scoped_delta_regime.py +0 -0
  133. {alloc_context-0.2.0 → alloc_context-0.2.2}/tests/test_holdings_scoped_market.py +0 -0
  134. {alloc_context-0.2.0 → alloc_context-0.2.2}/tests/test_horizon.py +0 -0
  135. {alloc_context-0.2.0 → alloc_context-0.2.2}/tests/test_ingest_outcome.py +0 -0
  136. {alloc_context-0.2.0 → alloc_context-0.2.2}/tests/test_ingest_runner.py +0 -0
  137. {alloc_context-0.2.0 → alloc_context-0.2.2}/tests/test_ingest_store_integration.py +0 -0
  138. {alloc_context-0.2.0 → alloc_context-0.2.2}/tests/test_kalshi_api.py +0 -0
  139. {alloc_context-0.2.0 → alloc_context-0.2.2}/tests/test_kraken_portfolio.py +0 -0
  140. {alloc_context-0.2.0 → alloc_context-0.2.2}/tests/test_live_ingest_handlers.py +0 -0
  141. {alloc_context-0.2.0 → alloc_context-0.2.2}/tests/test_macro.py +0 -0
  142. {alloc_context-0.2.0 → alloc_context-0.2.2}/tests/test_market_breadth.py +0 -0
  143. {alloc_context-0.2.0 → alloc_context-0.2.2}/tests/test_mcp_assets_regime.py +0 -0
  144. {alloc_context-0.2.0 → alloc_context-0.2.2}/tests/test_mcp_contracts.py +0 -0
  145. {alloc_context-0.2.0 → alloc_context-0.2.2}/tests/test_mcp_data_staleness.py +0 -0
  146. {alloc_context-0.2.0 → alloc_context-0.2.2}/tests/test_mcp_handlers.py +0 -0
  147. {alloc_context-0.2.0 → alloc_context-0.2.2}/tests/test_mcp_health.py +0 -0
  148. {alloc_context-0.2.0 → alloc_context-0.2.2}/tests/test_mcp_http_lifecycle.py +0 -0
  149. {alloc_context-0.2.0 → alloc_context-0.2.2}/tests/test_mcp_live_portfolio.py +0 -0
  150. {alloc_context-0.2.0 → alloc_context-0.2.2}/tests/test_mcp_validation.py +0 -0
  151. {alloc_context-0.2.0 → alloc_context-0.2.2}/tests/test_mcp_x402.py +0 -0
  152. {alloc_context-0.2.0 → alloc_context-0.2.2}/tests/test_mcp_x402_http.py +0 -0
  153. {alloc_context-0.2.0 → alloc_context-0.2.2}/tests/test_mcp_x402_pricing.py +0 -0
  154. {alloc_context-0.2.0 → alloc_context-0.2.2}/tests/test_mcp_x402_stables.py +0 -0
  155. {alloc_context-0.2.0 → alloc_context-0.2.2}/tests/test_payer.py +0 -0
  156. {alloc_context-0.2.0 → alloc_context-0.2.2}/tests/test_portfolio_holdings.py +0 -0
  157. {alloc_context-0.2.0 → alloc_context-0.2.2}/tests/test_quote_resolver.py +0 -0
  158. {alloc_context-0.2.0 → alloc_context-0.2.2}/tests/test_rebalance.py +0 -0
  159. {alloc_context-0.2.0 → alloc_context-0.2.2}/tests/test_rollup.py +0 -0
  160. {alloc_context-0.2.0 → alloc_context-0.2.2}/tests/test_script_runtime.py +0 -0
  161. {alloc_context-0.2.0 → alloc_context-0.2.2}/tests/test_security_hardening.py +0 -0
  162. {alloc_context-0.2.0 → alloc_context-0.2.2}/tests/test_server_json.py +0 -0
  163. {alloc_context-0.2.0 → alloc_context-0.2.2}/tests/test_setup.py +0 -0
  164. {alloc_context-0.2.0 → alloc_context-0.2.2}/tests/test_snapshots_and_delta.py +0 -0
  165. {alloc_context-0.2.0 → alloc_context-0.2.2}/tests/test_status_report.py +0 -0
  166. {alloc_context-0.2.0 → alloc_context-0.2.2}/tests/test_user_config.py +0 -0
  167. {alloc_context-0.2.0 → alloc_context-0.2.2}/tests/test_x402_bazaar_dynamic.py +0 -0
  168. {alloc_context-0.2.0 → alloc_context-0.2.2}/tests/test_x402_smoke_redact.py +0 -0
@@ -1,15 +1,15 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: alloc-context
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: Portfolio-aware crypto context for agents — holdings, market, optional allocation analysis
5
5
  License: Elastic-2.0
6
- Project-URL: Homepage, https://github.com/negillett/alloc-context
6
+ Project-URL: Homepage, https://mcp.alloc-context.com/llms.txt
7
7
  Project-URL: Documentation, https://github.com/negillett/alloc-context/blob/main/docs/agent-integration.md
8
8
  Project-URL: Repository, https://github.com/negillett/alloc-context
9
9
  Project-URL: Issues, https://github.com/negillett/alloc-context/issues
10
10
  Project-URL: Changelog, https://github.com/negillett/alloc-context/releases
11
11
  Project-URL: MCP Server, https://mcp.alloc-context.com/mcp
12
- Keywords: mcp,x402,bitcoin,ethereum,portfolio,allocation,agents,crypto,rebalance
12
+ Keywords: mcp,x402,bitcoin,ethereum,crypto,cryptocurrency,portfolio,allocation,holdings,rebalance,coinbase,kraken,agents
13
13
  Classifier: Development Status :: 4 - Beta
14
14
  Classifier: Intended Audience :: Developers
15
15
  Classifier: Programming Language :: Python :: 3
@@ -44,6 +44,9 @@ Dynamic: license-file
44
44
 
45
45
  # AllocContext
46
46
 
47
+ [![smithery badge](https://smithery.ai/badge/@negillett/alloc-context)](https://smithery.ai/server/@negillett/alloc-context)
48
+ [![Glama MCP server](https://glama.ai/mcp/servers/negillett/alloc-context/badges/score.svg)](https://glama.ai/mcp/servers/negillett/alloc-context)
49
+
47
50
  mcp-name: io.github.negillett/alloc-context
48
51
 
49
52
  **Portfolio-aware crypto context for agents** — discover holdings, market,
@@ -110,6 +113,7 @@ Not financial advice.
110
113
  | **Discovery** | [llms.txt](https://mcp.alloc-context.com/llms.txt), [x402 manifest](https://mcp.alloc-context.com/.well-known/x402.json) |
111
114
  | **Pricing** | **$0.02** cached context/math · **$0.05** live ingest or portfolio |
112
115
  | **Payment** | x402 on Base — USDC or EURC |
116
+ | **Market scope** | Holdings-scoped (BTC/ETH OHLC; alt quote snapshots); bridge auto-scopes from portfolio |
113
117
 
114
118
  Agents and wallets connect directly to the hosted endpoint — see
115
119
  [agent-integration.md](docs/agent-integration.md). The Cursor bridge above
@@ -128,6 +132,11 @@ combines local portfolio reads with this upstream for market context.
128
132
  | `check_allocation_bands` | Batch band checks for multiple target scenarios |
129
133
  | `get_portfolio_state` | Live NAV and holdings from Kraken or Coinbase |
130
134
 
135
+ Market context is **holdings-scoped**: band assets (BTC/ETH) use OHLC bars; alt
136
+ holdings (e.g. HYPE) use quote snapshots when cached. The bridge auto-scopes
137
+ `assets` from your portfolio (symbols only upstream). See
138
+ [context-bundle.md#market-coverage](docs/context-bundle.md#market-coverage).
139
+
131
140
  See [mcp.md](docs/mcp.md) for arguments, pricing, and resources.
132
141
 
133
142
  ## Self-host and development
@@ -1,5 +1,8 @@
1
1
  # AllocContext
2
2
 
3
+ [![smithery badge](https://smithery.ai/badge/@negillett/alloc-context)](https://smithery.ai/server/@negillett/alloc-context)
4
+ [![Glama MCP server](https://glama.ai/mcp/servers/negillett/alloc-context/badges/score.svg)](https://glama.ai/mcp/servers/negillett/alloc-context)
5
+
3
6
  mcp-name: io.github.negillett/alloc-context
4
7
 
5
8
  **Portfolio-aware crypto context for agents** — discover holdings, market,
@@ -66,6 +69,7 @@ Not financial advice.
66
69
  | **Discovery** | [llms.txt](https://mcp.alloc-context.com/llms.txt), [x402 manifest](https://mcp.alloc-context.com/.well-known/x402.json) |
67
70
  | **Pricing** | **$0.02** cached context/math · **$0.05** live ingest or portfolio |
68
71
  | **Payment** | x402 on Base — USDC or EURC |
72
+ | **Market scope** | Holdings-scoped (BTC/ETH OHLC; alt quote snapshots); bridge auto-scopes from portfolio |
69
73
 
70
74
  Agents and wallets connect directly to the hosted endpoint — see
71
75
  [agent-integration.md](docs/agent-integration.md). The Cursor bridge above
@@ -84,6 +88,11 @@ combines local portfolio reads with this upstream for market context.
84
88
  | `check_allocation_bands` | Batch band checks for multiple target scenarios |
85
89
  | `get_portfolio_state` | Live NAV and holdings from Kraken or Coinbase |
86
90
 
91
+ Market context is **holdings-scoped**: band assets (BTC/ETH) use OHLC bars; alt
92
+ holdings (e.g. HYPE) use quote snapshots when cached. The bridge auto-scopes
93
+ `assets` from your portfolio (symbols only upstream). See
94
+ [context-bundle.md#market-coverage](docs/context-bundle.md#market-coverage).
95
+
87
96
  See [mcp.md](docs/mcp.md) for arguments, pricing, and resources.
88
97
 
89
98
  ## Self-host and development
@@ -1,15 +1,15 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: alloc-context
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: Portfolio-aware crypto context for agents — holdings, market, optional allocation analysis
5
5
  License: Elastic-2.0
6
- Project-URL: Homepage, https://github.com/negillett/alloc-context
6
+ Project-URL: Homepage, https://mcp.alloc-context.com/llms.txt
7
7
  Project-URL: Documentation, https://github.com/negillett/alloc-context/blob/main/docs/agent-integration.md
8
8
  Project-URL: Repository, https://github.com/negillett/alloc-context
9
9
  Project-URL: Issues, https://github.com/negillett/alloc-context/issues
10
10
  Project-URL: Changelog, https://github.com/negillett/alloc-context/releases
11
11
  Project-URL: MCP Server, https://mcp.alloc-context.com/mcp
12
- Keywords: mcp,x402,bitcoin,ethereum,portfolio,allocation,agents,crypto,rebalance
12
+ Keywords: mcp,x402,bitcoin,ethereum,crypto,cryptocurrency,portfolio,allocation,holdings,rebalance,coinbase,kraken,agents
13
13
  Classifier: Development Status :: 4 - Beta
14
14
  Classifier: Intended Audience :: Developers
15
15
  Classifier: Programming Language :: Python :: 3
@@ -44,6 +44,9 @@ Dynamic: license-file
44
44
 
45
45
  # AllocContext
46
46
 
47
+ [![smithery badge](https://smithery.ai/badge/@negillett/alloc-context)](https://smithery.ai/server/@negillett/alloc-context)
48
+ [![Glama MCP server](https://glama.ai/mcp/servers/negillett/alloc-context/badges/score.svg)](https://glama.ai/mcp/servers/negillett/alloc-context)
49
+
47
50
  mcp-name: io.github.negillett/alloc-context
48
51
 
49
52
  **Portfolio-aware crypto context for agents** — discover holdings, market,
@@ -110,6 +113,7 @@ Not financial advice.
110
113
  | **Discovery** | [llms.txt](https://mcp.alloc-context.com/llms.txt), [x402 manifest](https://mcp.alloc-context.com/.well-known/x402.json) |
111
114
  | **Pricing** | **$0.02** cached context/math · **$0.05** live ingest or portfolio |
112
115
  | **Payment** | x402 on Base — USDC or EURC |
116
+ | **Market scope** | Holdings-scoped (BTC/ETH OHLC; alt quote snapshots); bridge auto-scopes from portfolio |
113
117
 
114
118
  Agents and wallets connect directly to the hosted endpoint — see
115
119
  [agent-integration.md](docs/agent-integration.md). The Cursor bridge above
@@ -128,6 +132,11 @@ combines local portfolio reads with this upstream for market context.
128
132
  | `check_allocation_bands` | Batch band checks for multiple target scenarios |
129
133
  | `get_portfolio_state` | Live NAV and holdings from Kraken or Coinbase |
130
134
 
135
+ Market context is **holdings-scoped**: band assets (BTC/ETH) use OHLC bars; alt
136
+ holdings (e.g. HYPE) use quote snapshots when cached. The bridge auto-scopes
137
+ `assets` from your portfolio (symbols only upstream). See
138
+ [context-bundle.md#market-coverage](docs/context-bundle.md#market-coverage).
139
+
131
140
  See [mcp.md](docs/mcp.md) for arguments, pricing, and resources.
132
141
 
133
142
  ## Self-host and development
@@ -62,6 +62,7 @@ alloccontext/mcp/bazaar.py
62
62
  alloccontext/mcp/bridge.py
63
63
  alloccontext/mcp/bridge_portfolio.py
64
64
  alloccontext/mcp/contracts.py
65
+ alloccontext/mcp/glama.py
65
66
  alloccontext/mcp/handlers.py
66
67
  alloccontext/mcp/http.py
67
68
  alloccontext/mcp/instructions.py
@@ -70,6 +71,8 @@ alloccontext/mcp/payment_middleware.py
70
71
  alloccontext/mcp/server.py
71
72
  alloccontext/mcp/setup.py
72
73
  alloccontext/mcp/staleness.py
74
+ alloccontext/mcp/tool_catalog.py
75
+ alloccontext/mcp/tool_fields.py
73
76
  alloccontext/mcp/upstream.py
74
77
  alloccontext/mcp/validation.py
75
78
  alloccontext/mcp/x402_bazaar_dynamic.py
@@ -117,6 +120,7 @@ tests/test_etf.py
117
120
  tests/test_exchanges_config.py
118
121
  tests/test_fear_greed.py
119
122
  tests/test_fred.py
123
+ tests/test_glama_well_known.py
120
124
  tests/test_holdings_scoped_delta_regime.py
121
125
  tests/test_holdings_scoped_market.py
122
126
  tests/test_horizon.py
@@ -153,6 +157,7 @@ tests/test_server_json.py
153
157
  tests/test_setup.py
154
158
  tests/test_snapshots_and_delta.py
155
159
  tests/test_status_report.py
160
+ tests/test_tool_catalog.py
156
161
  tests/test_user_config.py
157
162
  tests/test_workflows.py
158
163
  tests/test_x402_bazaar_dynamic.py
@@ -1,3 +1,3 @@
1
1
  """AllocContext — portfolio-aware crypto context for agents (MCP)."""
2
2
 
3
- __version__ = "0.2.0"
3
+ __version__ = "0.2.2"
@@ -10,6 +10,24 @@ from x402.extensions.bazaar import (
10
10
  declare_mcp_discovery_extension,
11
11
  )
12
12
 
13
+ from alloccontext.mcp.tool_catalog import (
14
+ ASSET_FILTER_SCHEMA,
15
+ AS_OF_SCHEMA,
16
+ BAND_SCHEMA,
17
+ CURRENT_AS_OF_SCHEMA,
18
+ FRESHNESS_SCHEMA,
19
+ MATCH_SCHEMA,
20
+ MCP_SERVER_PROMPTS,
21
+ MCP_SERVER_RESOURCES,
22
+ OPTIONAL_TARGET_PCT_SCHEMA,
23
+ PRIOR_AS_OF_SCHEMA,
24
+ SCENARIOS_SCHEMA,
25
+ SCOPE_SCHEMA,
26
+ TARGET_PCT_SCHEMA,
27
+ allocation_pct_schema,
28
+ server_card_tool_entry,
29
+ )
30
+
13
31
  SERVICE_NAME = "AllocContext"
14
32
  OFFICIAL_HOSTED_MCP_URL = "https://mcp.alloc-context.com/mcp"
15
33
  USE_DOCS_PATH = "docs/USE.md"
@@ -43,28 +61,49 @@ SERVICE_TITLE = (
43
61
  # CDP Bazaar indexes service_name (≤32 chars) and up to five tags from payments.
44
62
  BAZAAR_SERVICE_NAME = "AllocContext portfolio MCP"
45
63
  SERVICE_TAGS = (
64
+ "crypto",
65
+ "cryptocurrency",
66
+ "bitcoin",
46
67
  "btc",
68
+ "ethereum",
47
69
  "eth",
48
70
  "holdings",
49
71
  "portfolio",
50
- "crypto",
51
- "bitcoin",
52
- "agent-tools",
53
- "mcp",
72
+ "allocation",
73
+ "rebalance",
54
74
  "sentiment",
55
75
  "macro",
56
- "rebalance",
57
- "allocation",
76
+ "coinbase",
77
+ "kraken",
78
+ "agent-tools",
79
+ "mcp",
80
+ "x402",
81
+ )
82
+ BAZAAR_INDEX_TAGS = (
83
+ "crypto",
84
+ "cryptocurrency",
85
+ "portfolio",
86
+ "holdings",
87
+ "btc",
58
88
  )
59
- BAZAAR_INDEX_TAGS = ("btc", "eth", "portfolio", "holdings", "mcp")
60
89
 
61
90
  DISCOVERY_KEYWORD_MARKERS = (
91
+ "crypto",
92
+ "cryptocurrency",
93
+ "digital assets",
94
+ "crypto portfolio",
62
95
  "portfolio allocation",
96
+ "portfolio context",
63
97
  "allocation drift",
64
98
  "rebalance plan",
65
99
  "fear and greed",
66
100
  "etf flows",
67
101
  "holdings",
102
+ "holdings-scoped",
103
+ "coinbase",
104
+ "kraken",
105
+ "market context",
106
+ "sentiment",
68
107
  )
69
108
 
70
109
  LISTING_DESCRIPTION = (
@@ -77,54 +116,22 @@ LISTING_DESCRIPTION = (
77
116
  f"MCP at {OFFICIAL_HOSTED_MCP_URL} — see {USE_DOCS_PATH}."
78
117
  )
79
118
 
80
- _ASSET_FILTER_SCHEMA = {
81
- "type": "array",
82
- "items": {"type": "string", "enum": ["BTC", "ETH", "CASH"]},
83
- "description": "Subset market and ETF fields (default BTC and ETH).",
84
- }
85
-
86
- _TARGET_PCT_SCHEMA = {
87
- "type": "object",
88
- "description": "Target weights keyed by BTC, ETH, CASH.",
89
- "properties": {
90
- "BTC": {"type": "number"},
91
- "ETH": {"type": "number"},
92
- "CASH": {"type": "number"},
93
- },
94
- "required": ["BTC", "ETH", "CASH"],
95
- }
96
-
97
- _BAND_SCHEMA = {
98
- "type": "number",
99
- "description": "Drift band width (for example 0.15 = 15%).",
100
- }
101
-
102
119
  _MCP_TOOLS: tuple[dict[str, Any], ...] = (
103
120
  {
104
121
  "tool_name": "get_market_context",
105
122
  "description": (
106
- "Fused market backdrop for portfolio context: Fear & Greed, Kalshi "
107
- "sentiment, macro calendar, FRED indicators, ETF flows, and breadth. "
108
- "Use freshness=cached for hosted cache; freshness=live runs ingest "
109
- "first (requires ingest API keys on the host)."
123
+ "Return read-only fused market backdrop for crypto portfolio context: "
124
+ "sentiment (Fear & Greed, Kalshi), macro events, FRED indicators, ETF "
125
+ "flows, and market breadth no portfolio holdings. Use "
126
+ "get_context_bundle when you also need holdings, delta, or regime. "
127
+ "freshness=cached reads the ingest DB; freshness=live runs ingest first."
110
128
  ),
111
129
  "input_schema": {
112
130
  "type": "object",
113
131
  "properties": {
114
- "scope": {
115
- "type": "string",
116
- "enum": ["daily", "weekly"],
117
- "description": "Rollup horizon for macro and context bundle.",
118
- },
119
- "freshness": {
120
- "type": "string",
121
- "enum": ["cached", "live"],
122
- "description": (
123
- "cached reads the ingest DB; live runs ingest first "
124
- "(requires ingest API keys on the host)."
125
- ),
126
- },
127
- "assets": _ASSET_FILTER_SCHEMA,
132
+ "scope": SCOPE_SCHEMA,
133
+ "freshness": FRESHNESS_SCHEMA,
134
+ "assets": ASSET_FILTER_SCHEMA,
128
135
  },
129
136
  },
130
137
  "example": {"scope": "daily", "freshness": "cached", "assets": ["BTC", "ETH"]},
@@ -142,25 +149,20 @@ _MCP_TOOLS: tuple[dict[str, Any], ...] = (
142
149
  {
143
150
  "tool_name": "get_context_bundle",
144
151
  "description": (
145
- "Full ContextBundle JSON: portfolio holdings and band weights, "
146
- "market, sentiment, macro, regime hints, and delta vs the prior "
147
- "saved snapshot. Optional target_pct and band enable "
148
- "allocation_analysis (opt-in drift math)."
152
+ "Return the full read-only ContextBundle JSON: portfolio holdings, "
153
+ "market, sentiment, macro, regime hints, and delta vs the prior saved "
154
+ "snapshot. Use get_market_context for market-only; use get_context_at "
155
+ "for a historical snapshot. Optional target_pct and band attach "
156
+ "allocation_analysis drift math."
149
157
  ),
150
158
  "input_schema": {
151
159
  "type": "object",
152
160
  "properties": {
153
- "scope": {
154
- "type": "string",
155
- "enum": ["daily", "weekly"],
156
- },
157
- "freshness": {
158
- "type": "string",
159
- "enum": ["cached", "live"],
160
- },
161
- "assets": _ASSET_FILTER_SCHEMA,
162
- "target_pct": _TARGET_PCT_SCHEMA,
163
- "band": _BAND_SCHEMA,
161
+ "scope": SCOPE_SCHEMA,
162
+ "freshness": FRESHNESS_SCHEMA,
163
+ "assets": ASSET_FILTER_SCHEMA,
164
+ "target_pct": TARGET_PCT_SCHEMA,
165
+ "band": BAND_SCHEMA,
164
166
  },
165
167
  },
166
168
  "example": {
@@ -190,45 +192,28 @@ _MCP_TOOLS: tuple[dict[str, Any], ...] = (
190
192
  {
191
193
  "tool_name": "get_rebalance_plan",
192
194
  "description": (
193
- "Compute USD deltas and exchange-style move lines toward a target "
194
- "BTC/ETH/CASH allocation from current band weights and NAV. Pure "
195
- "math explicit inputs required."
195
+ "Compute read-only USD deltas and suggested exchange move lines to "
196
+ "reach a BTC/ETH/CASH target split. Pure math no exchange API calls. "
197
+ "Requires allocation_pct, target_pct, and nav_usd. Use get_portfolio_state "
198
+ "or get_context_bundle when you need live weights first."
196
199
  ),
197
200
  "input_schema": {
198
201
  "type": "object",
199
202
  "properties": {
200
- "allocation_pct": {
201
- "type": "object",
202
- "description": "Current weights keyed by BTC, ETH, CASH.",
203
- "properties": {
204
- "BTC": {"type": "number"},
205
- "ETH": {"type": "number"},
206
- "CASH": {"type": "number"},
207
- },
208
- "required": ["BTC", "ETH", "CASH"],
209
- },
210
- "target_pct": {
211
- "type": "object",
212
- "description": "Target weights keyed by BTC, ETH, CASH.",
213
- "properties": {
214
- "BTC": {"type": "number"},
215
- "ETH": {"type": "number"},
216
- "CASH": {"type": "number"},
217
- },
218
- "required": ["BTC", "ETH", "CASH"],
219
- },
203
+ "allocation_pct": allocation_pct_schema(role="Current"),
204
+ "target_pct": allocation_pct_schema(role="Target"),
220
205
  "nav_usd": {
221
206
  "type": "number",
222
- "description": "Portfolio NAV in USD.",
207
+ "description": "Portfolio net asset value in USD.",
223
208
  },
224
209
  "exchange": {
225
210
  "type": "string",
226
211
  "enum": ["kraken", "coinbase"],
227
212
  "description": (
228
- "Exchange-specific move wording (default kraken)."
213
+ "Spot exchange for move wording: kraken (default) or coinbase."
229
214
  ),
230
215
  },
231
- "band": _BAND_SCHEMA,
216
+ "band": BAND_SCHEMA,
232
217
  },
233
218
  "required": ["allocation_pct", "target_pct", "nav_usd"],
234
219
  },
@@ -251,10 +236,10 @@ _MCP_TOOLS: tuple[dict[str, Any], ...] = (
251
236
  {
252
237
  "tool_name": "get_portfolio_state",
253
238
  "description": (
254
- "Live portfolio read: NAV, holdings[], band weights, and optional "
255
- "allocation_analysis when target_pct is supplied. Pass read-only "
256
- "Kraken or Coinbase credentials in the request; never stored "
257
- "server-side."
239
+ "Fetch live read-only portfolio NAV, holdings[], and band weights from "
240
+ "Kraken or Coinbase credentials passed in this call (never stored). "
241
+ "Requires exchange, api_key, and api_secret. Returns available=false "
242
+ "with reason on invalid credentials — no side effects."
258
243
  ),
259
244
  "input_schema": {
260
245
  "type": "object",
@@ -262,11 +247,13 @@ _MCP_TOOLS: tuple[dict[str, Any], ...] = (
262
247
  "exchange": {
263
248
  "type": "string",
264
249
  "enum": ["kraken", "coinbase"],
265
- "description": "Spot exchange to query.",
250
+ "description": "Spot exchange to query: kraken or coinbase.",
266
251
  },
267
252
  "api_key": {
268
253
  "type": "string",
269
- "description": "Read-only API key (CDP key name for Coinbase).",
254
+ "description": (
255
+ "Read-only exchange API key (Coinbase CDP key name)."
256
+ ),
270
257
  },
271
258
  "api_secret": {
272
259
  "type": "string",
@@ -274,19 +261,8 @@ _MCP_TOOLS: tuple[dict[str, Any], ...] = (
274
261
  "Read-only API secret (Kraken base64 secret or Coinbase EC PEM)."
275
262
  ),
276
263
  },
277
- "target_pct": {
278
- "type": "object",
279
- "description": "Optional target weights for allocation_analysis.",
280
- "properties": {
281
- "BTC": {"type": "number"},
282
- "ETH": {"type": "number"},
283
- "CASH": {"type": "number"},
284
- },
285
- },
286
- "band": {
287
- "type": "number",
288
- "description": "Drift band width when target_pct is supplied (e.g. 0.15).",
289
- },
264
+ "target_pct": OPTIONAL_TARGET_PCT_SCHEMA,
265
+ "band": BAND_SCHEMA,
290
266
  },
291
267
  "required": ["exchange", "api_key", "api_secret"],
292
268
  },
@@ -309,34 +285,19 @@ _MCP_TOOLS: tuple[dict[str, Any], ...] = (
309
285
  {
310
286
  "tool_name": "check_allocation_band",
311
287
  "description": (
312
- "Check whether band weights (BTC/ETH/CASH) are outside a drift band "
313
- "vs target and return hint (within_band, consider_rebalance, etc.). "
314
- "Explicit inputs required."
288
+ "Check read-only drift: are BTC/ETH/CASH band weights outside the drift "
289
+ "band vs target_pct? Returns rebalance_hint (within_band, "
290
+ "consider_rebalance, etc.). Single scenario — use check_allocation_bands "
291
+ "for multiple targets. Use get_rebalance_plan when you need USD move lines."
315
292
  ),
316
293
  "input_schema": {
317
294
  "type": "object",
318
295
  "properties": {
319
- "allocation_pct": {
320
- "type": "object",
321
- "properties": {
322
- "BTC": {"type": "number"},
323
- "ETH": {"type": "number"},
324
- "CASH": {"type": "number"},
325
- },
326
- "required": ["BTC", "ETH", "CASH"],
327
- },
328
- "target_pct": {
329
- "type": "object",
330
- "properties": {
331
- "BTC": {"type": "number"},
332
- "ETH": {"type": "number"},
333
- "CASH": {"type": "number"},
334
- },
335
- "required": ["BTC", "ETH", "CASH"],
336
- },
296
+ "allocation_pct": allocation_pct_schema(role="Current"),
297
+ "target_pct": allocation_pct_schema(role="Target"),
337
298
  "band": {
338
299
  "type": "number",
339
- "description": "Drift band width (default 0.15 = 15%).",
300
+ "description": "Drift band width as a fraction (default 0.15 = 15%).",
340
301
  },
341
302
  },
342
303
  "required": ["allocation_pct", "target_pct"],
@@ -357,16 +318,20 @@ _MCP_TOOLS: tuple[dict[str, Any], ...] = (
357
318
  {
358
319
  "tool_name": "get_context_at",
359
320
  "description": (
360
- "Load a saved ContextBundle snapshot from ingest history by ISO "
361
- "timestamp (match exact or at_or_before)."
321
+ "Load a read-only ContextBundle snapshot from ingest history at a point "
322
+ "in time. Use get_context_bundle for the latest snapshot; use "
323
+ "get_context_delta to compare two timestamps. Returns unavailable when "
324
+ "no snapshot matches as_of and match."
362
325
  ),
363
326
  "input_schema": {
364
327
  "type": "object",
365
328
  "properties": {
366
- "as_of": {"type": "string", "description": "ISO timestamp."},
367
- "scope": {"type": "string", "enum": ["daily", "weekly"]},
368
- "match": {"type": "string", "enum": ["exact", "at_or_before"]},
369
- "assets": _ASSET_FILTER_SCHEMA,
329
+ "as_of": AS_OF_SCHEMA,
330
+ "scope": SCOPE_SCHEMA,
331
+ "match": MATCH_SCHEMA,
332
+ "assets": ASSET_FILTER_SCHEMA,
333
+ "target_pct": TARGET_PCT_SCHEMA,
334
+ "band": BAND_SCHEMA,
370
335
  },
371
336
  "required": ["as_of"],
372
337
  },
@@ -385,15 +350,18 @@ _MCP_TOOLS: tuple[dict[str, Any], ...] = (
385
350
  {
386
351
  "tool_name": "get_context_delta",
387
352
  "description": (
388
- "Compare two ContextBundle snapshots and return notable_shifts."
353
+ "Compare two read-only ContextBundle snapshots and return notable_shifts "
354
+ "between them. Requires prior_as_of; omit current_as_of to diff against "
355
+ "the latest live bundle. Use get_context_at to load one snapshot without "
356
+ "diffing."
389
357
  ),
390
358
  "input_schema": {
391
359
  "type": "object",
392
360
  "properties": {
393
- "prior_as_of": {"type": "string"},
394
- "scope": {"type": "string", "enum": ["daily", "weekly"]},
395
- "current_as_of": {"type": "string"},
396
- "assets": _ASSET_FILTER_SCHEMA,
361
+ "prior_as_of": PRIOR_AS_OF_SCHEMA,
362
+ "scope": SCOPE_SCHEMA,
363
+ "current_as_of": CURRENT_AS_OF_SCHEMA,
364
+ "assets": ASSET_FILTER_SCHEMA,
397
365
  },
398
366
  "required": ["prior_as_of"],
399
367
  },
@@ -410,39 +378,15 @@ _MCP_TOOLS: tuple[dict[str, Any], ...] = (
410
378
  {
411
379
  "tool_name": "check_allocation_bands",
412
380
  "description": (
413
- "Evaluate allocation drift against multiple target/band scenarios."
381
+ "Evaluate read-only allocation drift against multiple target_pct/band "
382
+ "scenarios in one call. Each scenario requires target_pct; optional name "
383
+ "and band (default 0.15). Use check_allocation_band for a single target."
414
384
  ),
415
385
  "input_schema": {
416
386
  "type": "object",
417
387
  "properties": {
418
- "allocation_pct": {
419
- "type": "object",
420
- "properties": {
421
- "BTC": {"type": "number"},
422
- "ETH": {"type": "number"},
423
- "CASH": {"type": "number"},
424
- },
425
- "required": ["BTC", "ETH", "CASH"],
426
- },
427
- "scenarios": {
428
- "type": "array",
429
- "items": {
430
- "type": "object",
431
- "properties": {
432
- "name": {"type": "string"},
433
- "target_pct": {
434
- "type": "object",
435
- "properties": {
436
- "BTC": {"type": "number"},
437
- "ETH": {"type": "number"},
438
- "CASH": {"type": "number"},
439
- },
440
- },
441
- "band": {"type": "number"},
442
- },
443
- "required": ["target_pct"],
444
- },
445
- },
388
+ "allocation_pct": allocation_pct_schema(role="Current"),
389
+ "scenarios": SCENARIOS_SCHEMA,
446
390
  },
447
391
  "required": ["allocation_pct", "scenarios"],
448
392
  },
@@ -616,9 +560,12 @@ portfolio never persist on our servers.
616
560
 
617
561
  ## Search keywords
618
562
 
619
- bitcoin, ethereum, btc, eth, portfolio allocation, portfolio context, holdings,
620
- market context, sentiment, macro calendar, etf flows, allocation drift,
621
- rebalance plan, fear and greed, agent tools, mcp, x402
563
+ bitcoin, ethereum, btc, eth, crypto, cryptocurrency, digital assets, altcoin,
564
+ stablecoin, crypto portfolio, portfolio allocation, portfolio context, holdings,
565
+ holdings-scoped, coinbase, kraken, market context, market data, sentiment,
566
+ macro calendar, etf flows, allocation drift, allocation bands, rebalance plan,
567
+ fear and greed, fear greed index, nav, agent tools, ai agents, mcp, x402,
568
+ model context protocol, context bundle
622
569
 
623
570
  ## Examples
624
571
 
@@ -673,3 +620,25 @@ def build_well_known_x402(
673
620
  },
674
621
  },
675
622
  }
623
+
624
+
625
+ def build_mcp_server_card(*, version: str) -> dict[str, Any]:
626
+ """Smithery static server card (SEP-1649) — free metadata when POST /mcp is x402."""
627
+ return {
628
+ "serverInfo": {
629
+ "name": SERVICE_TITLE,
630
+ "version": version,
631
+ "description": LISTING_DESCRIPTION,
632
+ },
633
+ "authentication": {
634
+ "required": True,
635
+ "schemes": ["x402"],
636
+ "description": (
637
+ "x402 exact payment on Base mainnet (USDC or EURC) per tool call; "
638
+ "see /.well-known/x402.json for pricing."
639
+ ),
640
+ },
641
+ "tools": [server_card_tool_entry(spec) for spec in _MCP_TOOLS],
642
+ "resources": list(MCP_SERVER_RESOURCES),
643
+ "prompts": list(MCP_SERVER_PROMPTS),
644
+ }