adaptive-memory-multi-model-router 2.16.0 → 2.16.2
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.
- package/.github/workflows/adapters-ci.yml +142 -0
- package/.github/workflows/auto-submit-sitemap.yml +41 -0
- package/.github/workflows/ci.yml +2 -5
- package/.github/workflows/mcp-pypi-publish.yml +34 -0
- package/.github/workflows/pypi-publish.yml +146 -0
- package/.github/workflows/tmlpd-publish.yml +23 -0
- package/README.md +245 -148
- package/RELEASE_v2.16.0.md +149 -0
- package/TECHNICAL_README.md +253 -0
- package/adapters/README.md +36 -0
- package/adapters/__init__.py +25 -0
- package/adapters/a3m_adapter/__init__.py +51 -0
- package/adapters/a3m_adapter/adapter/__init__.py +22 -0
- package/adapters/a3m_adapter/adapter/autogen.py +169 -0
- package/adapters/a3m_adapter/adapter/config.py +100 -0
- package/adapters/a3m_adapter/adapter/haystack.py +197 -0
- package/adapters/a3m_adapter/adapter/langchain.py +155 -0
- package/adapters/a3m_adapter/adapter/langgraph.py +196 -0
- package/adapters/a3m_adapter/adapter/llamaindex.py +162 -0
- package/adapters/a3m_adapter/adapter/pinecone.py +217 -0
- package/adapters/a3m_adapter/adapter/vercel.py +188 -0
- package/adapters/a3m_adapter/tests/__init__.py +1 -0
- package/adapters/a3m_adapter/tests/test_adapters.py +118 -0
- package/adapters/a3m_adapter/tests/test_integration.py +80 -0
- package/adapters/requirements-dev.txt +6 -0
- package/adapters/requirements.txt +4 -0
- package/adapters/setup.py +23 -0
- package/demo.py +251 -0
- package/discoverability-diagnosis.md +280 -0
- package/dist/analytics/costAnalytics.d.ts.map +1 -1
- package/dist/benchmark/reproducible.d.ts.map +1 -1
- package/dist/cache/semanticCache.d.ts.map +1 -1
- package/dist/cli/setupWizard.d.ts +257 -50
- package/dist/cli/setupWizard.d.ts.map +1 -1
- package/dist/cli/setupWizard.js +419 -109
- package/dist/cli/setupWizard.js.map +1 -1
- package/dist/cli/tui.d.ts +6 -0
- package/dist/cli/tui.js +96 -67
- package/dist/cli/tui.js.map +1 -0
- package/dist/cli.js +9 -0
- package/dist/cost/budgetEnforcer.d.ts.map +1 -1
- package/dist/cost/costTracker.d.ts.map +1 -1
- package/dist/ensemble/multiRoundDialog.d.ts.map +1 -1
- package/dist/ensemble/shapleyValue.d.ts.map +1 -1
- package/dist/ensemble.d.ts +1 -1
- package/dist/ensemble.js +141 -0
- package/dist/integrations/langchainAdapter.d.ts.map +1 -1
- package/dist/integrations/langchainAdapter.js +3 -3
- package/dist/integrations/langchainAdapter.js.map +1 -1
- package/dist/integrations/oauth.d.ts.map +1 -1
- package/dist/integrations/scienceAdapter.d.ts.map +1 -1
- package/dist/memory/autoFetch.d.ts.map +1 -1
- package/dist/memory/hybridMemory.d.ts.map +1 -1
- package/dist/memory/memoryTree.d.ts.map +1 -1
- package/dist/memory/obsidianVault.d.ts.map +1 -1
- package/dist/memory/reasoningBank.d.ts.map +1 -1
- package/dist/observability/metrics.d.ts.map +1 -1
- package/dist/observability/tracer.d.ts.map +1 -1
- package/dist/providers/providerConfig.d.ts.map +1 -1
- package/dist/providers/providerConfig.js +32 -17
- package/dist/providers/providerConfig.js.map +1 -1
- package/dist/routing/advancedRouter.d.ts.map +1 -1
- package/dist/routing/advancedRouter.js +106 -14
- package/dist/routing/advancedRouter.js.map +1 -1
- package/dist/routing/providerHealth.d.ts.map +1 -1
- package/dist/routing/providerRetry.d.ts.map +1 -1
- package/dist/routing/shadowSampler.d.ts.map +1 -0
- package/dist/routing/shadowSampler.js.map +1 -1
- package/dist/security/guardrails.d.ts.map +1 -1
- package/dist/server/handlers/chatHandler.d.ts.map +1 -1
- package/dist/server/handlers/completionsHandler.d.ts.map +1 -1
- package/dist/server/handlers/embeddingsHandler.d.ts.map +1 -1
- package/dist/server/handlers/healthHandler.d.ts.map +1 -1
- package/dist/server/handlers/metricsHandler.d.ts.map +1 -1
- package/dist/server/handlers/modelsHandler.d.ts.map +1 -1
- package/dist/server/metrics.d.ts.map +1 -1
- package/dist/server/proxyServer.d.ts.map +1 -1
- package/dist/server/router.d.ts.map +1 -1
- package/dist/server/state.d.ts.map +1 -1
- package/dist/skills/__tests__/skill_manager.test.js +5 -265
- package/dist/skills/__tests__/skill_manager.test.js.map +1 -1
- package/dist/utils/tokenUtils.d.ts.map +1 -1
- package/docker-compose.yml +84 -60
- package/docs/ARTICLE_Biology_Inspired_Routing.md +208 -0
- package/docs/ARTICLE_Master.md +78 -0
- package/docs/ARTICLE_Master_CN.md +78 -0
- package/docs/ARTICLE_OpenRouter_Stripe.md +140 -0
- package/docs/DEVPTO_ARTICLE.md +84 -0
- package/docs/HUMAN_STYLE_GUIDE.md +75 -0
- package/docs/IMPRINT_PLAN.md +88 -0
- package/docs/OPENROUTER_ALTERNATIVE.md +184 -0
- package/docs/SOCIAL_CAMPAIGN.md +316 -0
- package/docs/anthropic.html +45 -0
- package/docs/best-llm-routers-2025.html +157 -0
- package/docs/cerebras.html +43 -0
- package/docs/cli-cheatsheet.md +286 -212
- package/docs/comparison.md +2 -2
- package/docs/deepseek.html +44 -0
- package/docs/google.html +47 -0
- package/docs/groq.html +44 -0
- package/docs/llms-full.txt +360 -138
- package/docs/llms.txt +70 -71
- package/docs/mistral.html +43 -0
- package/docs/ollama.html +50 -0
- package/docs/openai.html +57 -0
- package/docs/sitemap.xml +69 -57
- package/docs-site/blog/best-llm-routers-2025.html +157 -0
- package/docs-site/index.html +68 -9
- package/docs-site/providers/anthropic.html +45 -0
- package/docs-site/providers/cerebras.html +43 -0
- package/docs-site/providers/deepseek.html +44 -0
- package/docs-site/providers/google.html +47 -0
- package/docs-site/providers/groq.html +44 -0
- package/docs-site/providers/index.html +41 -0
- package/docs-site/providers/mistral.html +43 -0
- package/docs-site/providers/ollama.html +50 -0
- package/docs-site/providers/openai.html +57 -0
- package/docs-site/sitemap.xml +69 -0
- package/llms.txt +70 -62
- package/package.json +44 -182
- package/packages/agentkit-adapter/LICENSE +21 -0
- package/packages/agentkit-adapter/README.md +126 -0
- package/packages/agentkit-adapter/examples/agentkit-example.ts +139 -0
- package/packages/agentkit-adapter/package.json +57 -0
- package/packages/agentkit-adapter/src/adapter.ts +381 -0
- package/packages/agentkit-adapter/src/index.ts +36 -0
- package/packages/agentkit-adapter/src/types.ts +105 -0
- package/packages/agentkit-adapter/src/util.ts +13 -0
- package/packages/agentkit-adapter/tsconfig.json +22 -0
- package/prometheus.yml +8 -0
- package/python/README.md +35 -81
- package/python/a3m/__init__.py +32 -3
- package/python/a3m/adapters/__init__.py +21 -0
- package/python/a3m/adapters/langchain.py +190 -0
- package/python/a3m/adapters/llamaindex.py +249 -0
- package/python/a3m/adapters/qdrant.py +240 -0
- package/python/a3m/adapters/weaviate.py +263 -0
- package/python/a3m/client.py +5 -0
- package/python/build_verify.sh +32 -0
- package/python/mcp-server/README.md +172 -0
- package/python/mcp-server/a3m_mcp/__init__.py +25 -0
- package/python/mcp-server/a3m_mcp/__main__.py +15 -0
- package/python/mcp-server/a3m_mcp/server.py +205 -0
- package/python/mcp-server/pyproject.toml +24 -0
- package/python/pyproject.toml +60 -6
- package/python/setup.py +3 -28
- package/scripts/submit-sitemap.sh +52 -0
- package/src/__types__/registry.d.ts +14 -0
- package/src/cli/setupWizard.ts +443 -112
- package/src/cli/tui.ts +159 -0
- package/src/ensemble.ts +154 -1
- package/src/integrations/langchainAdapter.ts +2 -2
- package/src/providers/providerConfig.ts +32 -17
- package/src/providers/registry.js +27 -0
- package/src/routing/advancedRouter.ts +99 -14
- package/src/routing/shadowSampler.ts +1 -1
- package/test-install/package.json +12 -0
- package/tests/tsconfig.json +0 -1
- package/tmlpd-pi-extension/README.md +105 -44
- package/tmlpd-pi-extension/docs/demo.svg +33 -0
- package/tmlpd-pi-extension/package.json +35 -106
- package/tmlpd-pi-extension/src/tokenOptimization/contextStratifier.ts +163 -0
- package/tmlpd-pi-extension/src/tokenOptimization/fetchOnceLocal.ts +136 -0
- package/tmlpd-pi-extension/src/tokenOptimization/index.ts +197 -0
- package/tmlpd-pi-extension/src/tokenOptimization/interAgentCompression.ts +157 -0
- package/tmlpd-pi-extension/src/tokenOptimization/schemaContract.ts +101 -0
- package/tmlpd-pi-extension/src/tokenOptimization/semanticCache.ts +248 -0
- package/tmlpd-pi-extension/src/tokenOptimization/tokenAwareFallback.ts +192 -0
- package/tmlpd-pi-extension/test/verify.js +21 -0
- package/tsconfig.build.json +3 -2
- package/packages/a3m-vercel-ai/dist/a3m-language-model.d.ts +0 -12
- package/packages/a3m-vercel-ai/dist/a3m-language-model.d.ts.map +0 -1
- package/packages/a3m-vercel-ai/dist/a3m-language-model.js +0 -289
- package/packages/a3m-vercel-ai/dist/a3m-language-model.js.map +0 -1
- package/packages/a3m-vercel-ai/dist/index.d.ts +0 -82
- package/packages/a3m-vercel-ai/dist/index.d.ts.map +0 -1
- package/packages/a3m-vercel-ai/dist/index.js +0 -79
- package/packages/a3m-vercel-ai/dist/index.js.map +0 -1
- package/packages/a3m-vercel-ai/dist/types.d.ts +0 -97
- package/packages/a3m-vercel-ai/dist/types.d.ts.map +0 -1
- package/packages/a3m-vercel-ai/dist/types.js +0 -5
- package/packages/a3m-vercel-ai/dist/types.js.map +0 -1
- package/src/skills/__tests__/skill_manager.test.ts +0 -328
- package/tmlpd-pi-extension/dist/cache/prefixCache.d.ts +0 -114
- package/tmlpd-pi-extension/dist/cache/prefixCache.d.ts.map +0 -1
- package/tmlpd-pi-extension/dist/cache/prefixCache.js +0 -285
- package/tmlpd-pi-extension/dist/cache/prefixCache.js.map +0 -1
- package/tmlpd-pi-extension/dist/cache/responseCache.d.ts +0 -58
- package/tmlpd-pi-extension/dist/cache/responseCache.d.ts.map +0 -1
- package/tmlpd-pi-extension/dist/cache/responseCache.js +0 -153
- package/tmlpd-pi-extension/dist/cache/responseCache.js.map +0 -1
- package/tmlpd-pi-extension/dist/cli.js +0 -59
- package/tmlpd-pi-extension/dist/cost/costTracker.d.ts +0 -95
- package/tmlpd-pi-extension/dist/cost/costTracker.d.ts.map +0 -1
- package/tmlpd-pi-extension/dist/cost/costTracker.js +0 -240
- package/tmlpd-pi-extension/dist/cost/costTracker.js.map +0 -1
- package/tmlpd-pi-extension/dist/index.d.ts +0 -723
- package/tmlpd-pi-extension/dist/index.d.ts.map +0 -1
- package/tmlpd-pi-extension/dist/index.js +0 -239
- package/tmlpd-pi-extension/dist/index.js.map +0 -1
- package/tmlpd-pi-extension/dist/memory/episodicMemory.d.ts +0 -82
- package/tmlpd-pi-extension/dist/memory/episodicMemory.d.ts.map +0 -1
- package/tmlpd-pi-extension/dist/memory/episodicMemory.js +0 -145
- package/tmlpd-pi-extension/dist/memory/episodicMemory.js.map +0 -1
- package/tmlpd-pi-extension/dist/orchestration/haloOrchestrator.d.ts +0 -102
- package/tmlpd-pi-extension/dist/orchestration/haloOrchestrator.d.ts.map +0 -1
- package/tmlpd-pi-extension/dist/orchestration/haloOrchestrator.js +0 -207
- package/tmlpd-pi-extension/dist/orchestration/haloOrchestrator.js.map +0 -1
- package/tmlpd-pi-extension/dist/orchestration/mctsWorkflow.d.ts +0 -85
- package/tmlpd-pi-extension/dist/orchestration/mctsWorkflow.d.ts.map +0 -1
- package/tmlpd-pi-extension/dist/orchestration/mctsWorkflow.js +0 -210
- package/tmlpd-pi-extension/dist/orchestration/mctsWorkflow.js.map +0 -1
- package/tmlpd-pi-extension/dist/providers/localProvider.d.ts +0 -102
- package/tmlpd-pi-extension/dist/providers/localProvider.d.ts.map +0 -1
- package/tmlpd-pi-extension/dist/providers/localProvider.js +0 -338
- package/tmlpd-pi-extension/dist/providers/localProvider.js.map +0 -1
- package/tmlpd-pi-extension/dist/providers/registry.d.ts +0 -55
- package/tmlpd-pi-extension/dist/providers/registry.d.ts.map +0 -1
- package/tmlpd-pi-extension/dist/providers/registry.js +0 -138
- package/tmlpd-pi-extension/dist/providers/registry.js.map +0 -1
- package/tmlpd-pi-extension/dist/routing/advancedRouter.d.ts +0 -68
- package/tmlpd-pi-extension/dist/routing/advancedRouter.d.ts.map +0 -1
- package/tmlpd-pi-extension/dist/routing/advancedRouter.js +0 -332
- package/tmlpd-pi-extension/dist/routing/advancedRouter.js.map +0 -1
- package/tmlpd-pi-extension/dist/tools/tmlpdTools.d.ts +0 -101
- package/tmlpd-pi-extension/dist/tools/tmlpdTools.d.ts.map +0 -1
- package/tmlpd-pi-extension/dist/tools/tmlpdTools.js +0 -368
- package/tmlpd-pi-extension/dist/tools/tmlpdTools.js.map +0 -1
- package/tmlpd-pi-extension/dist/utils/batchProcessor.d.ts +0 -96
- package/tmlpd-pi-extension/dist/utils/batchProcessor.d.ts.map +0 -1
- package/tmlpd-pi-extension/dist/utils/batchProcessor.js +0 -170
- package/tmlpd-pi-extension/dist/utils/batchProcessor.js.map +0 -1
- package/tmlpd-pi-extension/dist/utils/compression.d.ts +0 -61
- package/tmlpd-pi-extension/dist/utils/compression.d.ts.map +0 -1
- package/tmlpd-pi-extension/dist/utils/compression.js +0 -281
- package/tmlpd-pi-extension/dist/utils/compression.js.map +0 -1
- package/tmlpd-pi-extension/dist/utils/reliability.d.ts +0 -74
- package/tmlpd-pi-extension/dist/utils/reliability.d.ts.map +0 -1
- package/tmlpd-pi-extension/dist/utils/reliability.js +0 -177
- package/tmlpd-pi-extension/dist/utils/reliability.js.map +0 -1
- package/tmlpd-pi-extension/dist/utils/speculativeDecoding.d.ts +0 -117
- package/tmlpd-pi-extension/dist/utils/speculativeDecoding.d.ts.map +0 -1
- package/tmlpd-pi-extension/dist/utils/speculativeDecoding.js +0 -246
- package/tmlpd-pi-extension/dist/utils/speculativeDecoding.js.map +0 -1
- package/tmlpd-pi-extension/dist/utils/tokenUtils.d.ts +0 -50
- package/tmlpd-pi-extension/dist/utils/tokenUtils.d.ts.map +0 -1
- package/tmlpd-pi-extension/dist/utils/tokenUtils.js +0 -124
- package/tmlpd-pi-extension/dist/utils/tokenUtils.js.map +0 -1
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# A3M Router MCP Server (Python)
|
|
2
|
+
|
|
3
|
+
[MCP (Model Context Protocol)](https://modelcontextprotocol.io/) server for [A3M Router](https://github.com/Das-rebel/a3m-router) — parallel multi-LLM execution for AI agents.
|
|
4
|
+
|
|
5
|
+
Allows any MCP-compatible AI agent (Claude Desktop, Cursor, Windsurf, Codex, n8n, etc.) to use A3M's intelligent routing and ensemble execution directly from Python.
|
|
6
|
+
|
|
7
|
+
## Tools
|
|
8
|
+
|
|
9
|
+
| Tool | Description |
|
|
10
|
+
|------|-------------|
|
|
11
|
+
| `a3m_route` | Route a query to the optimal LLM provider — returns model, tier, cost, reasoning |
|
|
12
|
+
| `a3m_ensemble` | Execute a query across multiple providers in parallel and merge results |
|
|
13
|
+
| `a3m_classify` | Classify query type (fast/creative/deep/code) and get provider recommendations |
|
|
14
|
+
| `a3m_providers` | List all configured providers with cost and availability |
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# From source
|
|
20
|
+
cd python/mcp-server
|
|
21
|
+
pip install -e .
|
|
22
|
+
|
|
23
|
+
# Or install the package directly (when published)
|
|
24
|
+
pip install a3m-mcp-server
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Configuration
|
|
28
|
+
|
|
29
|
+
Set environment variables:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
# Required: A3M Router URL (must be running)
|
|
33
|
+
export A3M_BASE_URL=http://localhost:8787
|
|
34
|
+
|
|
35
|
+
# Optional
|
|
36
|
+
export A3M_API_KEY=not-needed # default
|
|
37
|
+
export A3M_TIMEOUT=30.0
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Start A3M Router
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
# Node.js way
|
|
44
|
+
npx a3m-router serve
|
|
45
|
+
|
|
46
|
+
# Python way
|
|
47
|
+
pip install a3m-router
|
|
48
|
+
a3m-router serve
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Usage
|
|
52
|
+
|
|
53
|
+
### Claude Desktop
|
|
54
|
+
|
|
55
|
+
Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
|
|
56
|
+
|
|
57
|
+
```json
|
|
58
|
+
{
|
|
59
|
+
"mcpServers": {
|
|
60
|
+
"a3m-router": {
|
|
61
|
+
"command": "python",
|
|
62
|
+
"args": ["-m", "a3m_mcp"],
|
|
63
|
+
"env": {
|
|
64
|
+
"A3M_BASE_URL": "http://localhost:8787"
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Cursor
|
|
72
|
+
|
|
73
|
+
Settings → Features → MCP Servers → Add:
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
Name: A3M Router
|
|
77
|
+
Command: python
|
|
78
|
+
Arguments: -m a3m_mcp
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### n8n MCP Trigger
|
|
82
|
+
|
|
83
|
+
Add MCP Trigger node with:
|
|
84
|
+
|
|
85
|
+
```json
|
|
86
|
+
{
|
|
87
|
+
"server": "a3m-router",
|
|
88
|
+
"command": "python",
|
|
89
|
+
"args": ["-m", "a3m_mcp"]
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Direct stdio (pipe JSON-RPC)
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
# List tools
|
|
97
|
+
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | python -m a3m_mcp
|
|
98
|
+
|
|
99
|
+
# Call a3m_route
|
|
100
|
+
echo '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"a3m_route","arguments":{"query":"Write a Python quicksort"}}}' | python -m a3m_mcp
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Examples
|
|
104
|
+
|
|
105
|
+
### Route a query
|
|
106
|
+
|
|
107
|
+
```python
|
|
108
|
+
# a3m_route tool
|
|
109
|
+
Input: {"query": "Write a Python function to sort a list"}
|
|
110
|
+
Output:
|
|
111
|
+
{
|
|
112
|
+
"model": "groq/llama-3.3-70b-versatile",
|
|
113
|
+
"tier": "cheap",
|
|
114
|
+
"cost": 0.000012,
|
|
115
|
+
"reasoning": "Code query detected, routing to fast coding provider",
|
|
116
|
+
"classification": "code"
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Ensemble execution
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
# a3m_ensemble tool
|
|
124
|
+
Input: {"query": "Explain quantum computing in 3 sentences", "providers": ["groq", "google", "cerebras"]}
|
|
125
|
+
Output:
|
|
126
|
+
{
|
|
127
|
+
"query": "Explain quantum computing in 3 sentences",
|
|
128
|
+
"parallel_responses": [
|
|
129
|
+
{"provider": "groq", "content": "Quantum computing is..."},
|
|
130
|
+
{"provider": "google", "content": "At its core, quantum..."},
|
|
131
|
+
{"provider": "cerebras", "content": "Quantum computing leverages..."}
|
|
132
|
+
],
|
|
133
|
+
"best_answer": "Quantum computing is...",
|
|
134
|
+
"stats": {"total_providers": 3, "successful": 3, "failed": 0}
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Architecture
|
|
139
|
+
|
|
140
|
+
```
|
|
141
|
+
┌──────────────────────────────────────────────────────┐
|
|
142
|
+
│ MCP Client (Claude, Cursor, Codex, n8n) │
|
|
143
|
+
└──────────────────────┬───────────────────────────────┘
|
|
144
|
+
│ MCP Protocol (stdio)
|
|
145
|
+
┌──────────────────────▼───────────────────────────────┐
|
|
146
|
+
│ A3M Router MCP Server (Python) │
|
|
147
|
+
│ │
|
|
148
|
+
│ a3m_route a3m_ensemble a3m_classify a3m_providers │
|
|
149
|
+
└──────────────────────┬───────────────────────────────┘
|
|
150
|
+
│ HTTP API
|
|
151
|
+
┌──────────────────────▼───────────────────────────────┐
|
|
152
|
+
│ A3M Router (a3m-router serve) │
|
|
153
|
+
│ │
|
|
154
|
+
│ routeQuery() parallelEnsemble() providers │
|
|
155
|
+
└───────┬────────────┬────────────┬─────────────────────┘
|
|
156
|
+
│ │ │
|
|
157
|
+
┌────▼───┐ ┌────▼───┐ ┌────▼───┐
|
|
158
|
+
│ Groq │ │ Google │ │Cerebras│ ...
|
|
159
|
+
└────────┘ └────────┘ └────────┘
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Testing
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
cd python/mcp-server
|
|
166
|
+
pip install -e ".[dev]"
|
|
167
|
+
pytest
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## License
|
|
171
|
+
|
|
172
|
+
MIT
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""
|
|
2
|
+
A3M Router MCP Server
|
|
3
|
+
|
|
4
|
+
MCP (Model Context Protocol) server for A3M Router.
|
|
5
|
+
Provides intelligent LLM routing and ensemble execution as MCP tools.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
__version__ = "1.0.0"
|
|
9
|
+
|
|
10
|
+
# Try to import MCP components
|
|
11
|
+
HAS_MCP = False
|
|
12
|
+
SERVER_NAME = "a3m-router"
|
|
13
|
+
|
|
14
|
+
try:
|
|
15
|
+
from mcp.server.lowlevel import Server
|
|
16
|
+
from mcp import Tool
|
|
17
|
+
HAS_MCP = True
|
|
18
|
+
except ImportError:
|
|
19
|
+
pass
|
|
20
|
+
|
|
21
|
+
# Import main if available
|
|
22
|
+
try:
|
|
23
|
+
from .server import main
|
|
24
|
+
except ImportError:
|
|
25
|
+
main = None
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""Entry point: python -m a3m_mcp"""
|
|
2
|
+
import sys
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
# Add parent directory to path so a3m_mcp can find sibling packages
|
|
6
|
+
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
7
|
+
|
|
8
|
+
from .server import main, HAS_MCP
|
|
9
|
+
|
|
10
|
+
if __name__ == "__main__":
|
|
11
|
+
if not HAS_MCP:
|
|
12
|
+
print("ERROR: mcp package required. Install with: pip install mcp", file=sys.stderr)
|
|
13
|
+
sys.exit(1)
|
|
14
|
+
import asyncio
|
|
15
|
+
asyncio.run(main())
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
"""
|
|
2
|
+
A3M Router MCP Server - MCP Protocol Server for A3M Router
|
|
3
|
+
|
|
4
|
+
MCP 2.0.0 compatible server that provides A3M Router functionality
|
|
5
|
+
as MCP tools for AI agents.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import os
|
|
9
|
+
import asyncio
|
|
10
|
+
import json
|
|
11
|
+
from typing import Optional, List, Any
|
|
12
|
+
|
|
13
|
+
try:
|
|
14
|
+
from mcp.server.lowlevel import Server
|
|
15
|
+
from mcp import Tool, ListToolsResult
|
|
16
|
+
from mcp.types import CallToolResult, TextContent
|
|
17
|
+
from mcp.server.stdio import stdio_server
|
|
18
|
+
HAS_MCP = True
|
|
19
|
+
except ImportError:
|
|
20
|
+
HAS_MCP = False
|
|
21
|
+
print("WARNING: mcp package not installed. Run: pip install mcp", flush=True)
|
|
22
|
+
|
|
23
|
+
# A3M Router client
|
|
24
|
+
try:
|
|
25
|
+
import a3m
|
|
26
|
+
A3MRouter = a3m.A3MRouter
|
|
27
|
+
except ImportError:
|
|
28
|
+
A3MRouter = None
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
SERVER_NAME = "a3m-router"
|
|
32
|
+
SERVER_VERSION = "1.0.0"
|
|
33
|
+
|
|
34
|
+
_router: Optional["A3MRouter"] = None
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def get_router() -> "A3MRouter":
|
|
38
|
+
"""Get or create A3MRouter instance."""
|
|
39
|
+
global _router
|
|
40
|
+
if _router is None:
|
|
41
|
+
base_url = os.environ.get("A3M_BASE_URL", "http://localhost:8787")
|
|
42
|
+
api_key = os.environ.get("A3M_API_KEY", "")
|
|
43
|
+
_router = A3MRouter(base_url=base_url, api_key=api_key)
|
|
44
|
+
return _router
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
# Tool definitions
|
|
48
|
+
TOOLS = [
|
|
49
|
+
Tool(
|
|
50
|
+
name="a3m_route",
|
|
51
|
+
title="Route Query",
|
|
52
|
+
description="Route a query to the optimal LLM provider using A3M's adaptive routing. Returns model selection, tier, estimated cost, and reasoning.",
|
|
53
|
+
inputSchema={
|
|
54
|
+
"type": "object",
|
|
55
|
+
"properties": {
|
|
56
|
+
"query": {
|
|
57
|
+
"type": "string",
|
|
58
|
+
"description": "The user query to route (e.g. 'Write Python code to sort a list')",
|
|
59
|
+
},
|
|
60
|
+
"provider": {
|
|
61
|
+
"type": "string",
|
|
62
|
+
"description": "Optional: Force a specific provider (e.g. 'groq', 'google')",
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
"required": ["query"],
|
|
66
|
+
},
|
|
67
|
+
),
|
|
68
|
+
Tool(
|
|
69
|
+
name="a3m_chat",
|
|
70
|
+
title="Chat with A3M",
|
|
71
|
+
description="Send a chat message through A3M Router's adaptive routing.",
|
|
72
|
+
inputSchema={
|
|
73
|
+
"type": "object",
|
|
74
|
+
"properties": {
|
|
75
|
+
"query": {
|
|
76
|
+
"type": "string",
|
|
77
|
+
"description": "The user query",
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
"required": ["query"],
|
|
81
|
+
},
|
|
82
|
+
),
|
|
83
|
+
Tool(
|
|
84
|
+
name="a3m_cost_report",
|
|
85
|
+
title="Cost Report",
|
|
86
|
+
description="Get cost analytics across all providers.",
|
|
87
|
+
inputSchema={
|
|
88
|
+
"type": "object",
|
|
89
|
+
"properties": {},
|
|
90
|
+
},
|
|
91
|
+
),
|
|
92
|
+
Tool(
|
|
93
|
+
name="a3m_models",
|
|
94
|
+
title="List Models",
|
|
95
|
+
description="List all available models with cost/latency info.",
|
|
96
|
+
inputSchema={
|
|
97
|
+
"type": "object",
|
|
98
|
+
"properties": {},
|
|
99
|
+
},
|
|
100
|
+
),
|
|
101
|
+
]
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class A3MServer:
|
|
105
|
+
"""A3M Router MCP Server with tool handlers."""
|
|
106
|
+
|
|
107
|
+
def __init__(self):
|
|
108
|
+
pass
|
|
109
|
+
|
|
110
|
+
async def handle_list_tools(self, request_context=None) -> ListToolsResult:
|
|
111
|
+
"""Handle tools/list request."""
|
|
112
|
+
return ListToolsResult(
|
|
113
|
+
tools=[
|
|
114
|
+
{
|
|
115
|
+
"name": t.name,
|
|
116
|
+
"description": t.description,
|
|
117
|
+
"inputSchema": t.inputSchema,
|
|
118
|
+
}
|
|
119
|
+
for t in TOOLS
|
|
120
|
+
]
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
async def handle_call_tool(self, request_context, name: str, arguments: dict) -> CallToolResult:
|
|
124
|
+
"""Handle tools/call request."""
|
|
125
|
+
try:
|
|
126
|
+
if name == "a3m_route":
|
|
127
|
+
router = get_router()
|
|
128
|
+
query = arguments.get("query")
|
|
129
|
+
provider = arguments.get("provider")
|
|
130
|
+
|
|
131
|
+
result = router.route(query, provider=provider)
|
|
132
|
+
return CallToolResult(
|
|
133
|
+
content=[TextContent(type="text", text=json.dumps(result, indent=2))]
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
elif name == "a3m_chat":
|
|
137
|
+
router = get_router()
|
|
138
|
+
query = arguments.get("query")
|
|
139
|
+
|
|
140
|
+
result = router.chat(query)
|
|
141
|
+
return CallToolResult(
|
|
142
|
+
content=[TextContent(type="text", text=str(result))]
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
elif name == "a3m_cost_report":
|
|
146
|
+
router = get_router()
|
|
147
|
+
report = router.cost_report()
|
|
148
|
+
return CallToolResult(
|
|
149
|
+
content=[TextContent(type="text", text=json.dumps(report, indent=2))]
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
elif name == "a3m_models":
|
|
153
|
+
router = get_router()
|
|
154
|
+
models = router.models()
|
|
155
|
+
return CallToolResult(
|
|
156
|
+
content=[TextContent(type="text", text=json.dumps(models, indent=2))]
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
else:
|
|
160
|
+
return CallToolResult(
|
|
161
|
+
content=[TextContent(type="text", text=f"Unknown tool: {name}")],
|
|
162
|
+
isError=True,
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
except Exception as e:
|
|
166
|
+
return CallToolResult(
|
|
167
|
+
content=[TextContent(type="text", text=f"Error: {str(e)}")],
|
|
168
|
+
isError=True,
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
if HAS_MCP:
|
|
173
|
+
# Create server with handlers
|
|
174
|
+
a3m_server = A3MServer()
|
|
175
|
+
|
|
176
|
+
server = Server(
|
|
177
|
+
SERVER_NAME,
|
|
178
|
+
version=SERVER_VERSION,
|
|
179
|
+
on_list_tools=a3m_server.handle_list_tools,
|
|
180
|
+
on_call_tool=a3m_server.handle_call_tool,
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
async def main():
|
|
185
|
+
"""Main entry point for MCP server."""
|
|
186
|
+
if not HAS_MCP:
|
|
187
|
+
print("ERROR: mcp package not installed", flush=True)
|
|
188
|
+
return
|
|
189
|
+
|
|
190
|
+
print(f"Starting {SERVER_NAME} MCP Server v{SERVER_VERSION}", flush=True)
|
|
191
|
+
|
|
192
|
+
async with stdio_server() as (read_stream, write_stream):
|
|
193
|
+
await server.run(
|
|
194
|
+
read_stream,
|
|
195
|
+
write_stream,
|
|
196
|
+
server.create_initialization_options(),
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
if __name__ == "__main__":
|
|
201
|
+
if HAS_MCP:
|
|
202
|
+
asyncio.run(main())
|
|
203
|
+
else:
|
|
204
|
+
print("ERROR: mcp package required", flush=True)
|
|
205
|
+
print("Run: pip install mcp", flush=True)
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "a3m-mcp-server"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "MCP server for A3M Router — parallel multi-LLM execution for AI agents"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = {text = "MIT"}
|
|
11
|
+
requires-python = ">=3.10"
|
|
12
|
+
dependencies = [
|
|
13
|
+
"mcp>=1.0.0",
|
|
14
|
+
"httpx>=0.24.0",
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
[project.optional-dependencies]
|
|
18
|
+
dev = ["pytest>=7.4.0", "pytest-asyncio>=0.21.0", "black>=23.0.0"]
|
|
19
|
+
|
|
20
|
+
[project.urls]
|
|
21
|
+
Homepage = "https://github.com/Das-rebel/a3m-router"
|
|
22
|
+
|
|
23
|
+
[tool.setuptools.packages.find]
|
|
24
|
+
where = ["."]
|
package/python/pyproject.toml
CHANGED
|
@@ -1,23 +1,77 @@
|
|
|
1
1
|
[build-system]
|
|
2
|
-
requires = ["setuptools>=
|
|
3
|
-
build-backend = "setuptools.
|
|
2
|
+
requires = ["setuptools>=61.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "a3m-router"
|
|
7
|
-
version = "2.
|
|
8
|
-
description = "
|
|
7
|
+
version = "2.16.2"
|
|
8
|
+
description = "Auto-selects cheapest capable LLM from 47+ providers — 70-95% cost savings"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = {text = "MIT"}
|
|
11
11
|
requires-python = ">=3.8"
|
|
12
12
|
dependencies = ["httpx>=0.24.0"]
|
|
13
|
-
|
|
13
|
+
|
|
14
|
+
keywords = [
|
|
15
|
+
"llm",
|
|
16
|
+
"routing",
|
|
17
|
+
"openai",
|
|
18
|
+
"proxy",
|
|
19
|
+
"ai-gateway",
|
|
20
|
+
"routellm",
|
|
21
|
+
"litellm",
|
|
22
|
+
"multi-llm",
|
|
23
|
+
"model-selection",
|
|
24
|
+
"cost-optimization",
|
|
25
|
+
"langchain",
|
|
26
|
+
"llamaindex",
|
|
27
|
+
"rag",
|
|
28
|
+
"vector-search",
|
|
29
|
+
"embeddings",
|
|
30
|
+
"parallel",
|
|
31
|
+
"ensemble",
|
|
32
|
+
"router",
|
|
33
|
+
]
|
|
34
|
+
|
|
14
35
|
classifiers = [
|
|
15
36
|
"Development Status :: 4 - Beta",
|
|
16
37
|
"Intended Audience :: Developers",
|
|
17
38
|
"License :: OSI Approved :: MIT License",
|
|
39
|
+
"Operating System :: OS Independent",
|
|
18
40
|
"Programming Language :: Python :: 3",
|
|
41
|
+
"Programming Language :: Python :: 3.8",
|
|
42
|
+
"Programming Language :: Python :: 3.9",
|
|
43
|
+
"Programming Language :: Python :: 3.10",
|
|
44
|
+
"Programming Language :: Python :: 3.11",
|
|
45
|
+
"Programming Language :: Python :: 3.12",
|
|
19
46
|
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
47
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
20
48
|
]
|
|
21
49
|
|
|
50
|
+
[project.optional-dependencies]
|
|
51
|
+
langchain = ["langchain>=0.1.0"]
|
|
52
|
+
llamaindex = ["llamaindex>=0.9.0"]
|
|
53
|
+
qdrant = ["qdrant-client>=1.7.0"]
|
|
54
|
+
weaviate = ["weaviate-client>=4.0.0"]
|
|
55
|
+
adapters = [
|
|
56
|
+
"langchain>=0.1.0",
|
|
57
|
+
"llamaindex>=0.9.0",
|
|
58
|
+
"qdrant-client>=1.7.0",
|
|
59
|
+
"weaviate-client>=4.0.0",
|
|
60
|
+
]
|
|
61
|
+
dev = ["pytest>=7.4.0", "pytest-asyncio>=0.21.0", "black>=23.0.0"]
|
|
62
|
+
|
|
22
63
|
[project.urls]
|
|
23
|
-
Homepage = "https://github.com/Das-rebel/a3m-router"
|
|
64
|
+
Homepage = "https://github.com/Das-rebel/a3m-router#a3m-router"
|
|
65
|
+
Documentation = "https://github.com/Das-rebel/a3m-router#readme"
|
|
66
|
+
Repository = "https://github.com/Das-rebel/a3m-router"
|
|
67
|
+
Changelog = "https://github.com/Das-rebel/a3m-router/releases"
|
|
68
|
+
"NPM Package" = "https://www.npmjs.com/package/adaptive-memory-multi-model-router"
|
|
69
|
+
"PyPI Package" = "https://pypi.org/project/a3m-router/"
|
|
70
|
+
"GitHub Stars" = "https://github.com/Das-rebel/a3m-router/stargazers"
|
|
71
|
+
|
|
72
|
+
[tool.setuptools.packages.find]
|
|
73
|
+
where = ["."]
|
|
74
|
+
include = ["a3m*"]
|
|
75
|
+
|
|
76
|
+
[tool.black]
|
|
77
|
+
line-length = 100
|
package/python/setup.py
CHANGED
|
@@ -1,28 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
"description": "Python bindings for tmlpd-pi - Parallel Multi-LLM Processing with TypeScript compatibility",
|
|
5
|
-
"main": "tmlpd.py",
|
|
6
|
-
"keywords": [
|
|
7
|
-
"tmlpd",
|
|
8
|
-
"python",
|
|
9
|
-
"bindings",
|
|
10
|
-
"parallel",
|
|
11
|
-
"multi-llm",
|
|
12
|
-
"llm",
|
|
13
|
-
"openai",
|
|
14
|
-
"anthropic",
|
|
15
|
-
"google",
|
|
16
|
-
"groq",
|
|
17
|
-
"cerebras",
|
|
18
|
-
"langchain",
|
|
19
|
-
"agent",
|
|
20
|
-
"orchestration"
|
|
21
|
-
],
|
|
22
|
-
"author": "Subho Das",
|
|
23
|
-
"license": "MIT",
|
|
24
|
-
"python_requires": ">=3.8",
|
|
25
|
-
"dependencies": {},
|
|
26
|
-
"devDependencies": {},
|
|
27
|
-
"readme": "See python/examples.py for usage"
|
|
28
|
-
}
|
|
1
|
+
from setuptools import setup
|
|
2
|
+
|
|
3
|
+
setup()
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
#
|
|
3
|
+
# A3M Router — Sitemap Submission Script
|
|
4
|
+
# Submits sitemap to Google, Bing, and IndexNow for faster indexing
|
|
5
|
+
#
|
|
6
|
+
set -e
|
|
7
|
+
|
|
8
|
+
SITEMAP_URL="${SITEMAP_URL:-https://a3m-router.com/sitemap.xml}"
|
|
9
|
+
INDEXNOW_KEY="${INDEXNOW_KEY:-}"
|
|
10
|
+
|
|
11
|
+
echo "=== A3M Router Sitemap Submission ==="
|
|
12
|
+
echo "Sitemap: $SITEMAP_URL"
|
|
13
|
+
echo ""
|
|
14
|
+
|
|
15
|
+
# ─── Google ───────────────────────────────────────────
|
|
16
|
+
echo "[1/3] Submitting to Google..."
|
|
17
|
+
GOOGLE_STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
|
|
18
|
+
"https://www.google.com/ping?sitemap=$SITEMAP_URL")
|
|
19
|
+
if [ "$GOOGLE_STATUS" = "200" ]; then
|
|
20
|
+
echo " ✅ Google: OK (HTTP $GOOGLE_STATUS)"
|
|
21
|
+
else
|
|
22
|
+
echo " ⚠️ Google: HTTP $GOOGLE_STATUS"
|
|
23
|
+
fi
|
|
24
|
+
|
|
25
|
+
# ─── Bing ─────────────────────────────────────────────
|
|
26
|
+
echo "[2/3] Submitting to Bing..."
|
|
27
|
+
BING_STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
|
|
28
|
+
"https://www.bing.com/ping?sitemap=$SITEMAP_URL")
|
|
29
|
+
if [ "$BING_STATUS" = "200" ]; then
|
|
30
|
+
echo " ✅ Bing: OK (HTTP $BING_STATUS)"
|
|
31
|
+
else
|
|
32
|
+
echo " ⚠️ Bing: HTTP $BING_STATUS"
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
# ─── IndexNow ─────────────────────────────────────────
|
|
36
|
+
echo "[3/3] Submitting to IndexNow..."
|
|
37
|
+
if [ -z "$INDEXNOW_KEY" ]; then
|
|
38
|
+
echo " ⚠️ Skipped: INDEXNOW_KEY env var not set"
|
|
39
|
+
echo " To enable IndexNow: export INDEXNOW_KEY=your_key_from_indexnow.org"
|
|
40
|
+
else
|
|
41
|
+
# Get the sitemap URLs and submit each to IndexNow
|
|
42
|
+
curl -s "$SITEMAP_URL" | grep -oP '(?<=<loc>)[^<]+' | while read -r url; do
|
|
43
|
+
RESPONSE=$(curl -s -w "%{http_code}" -o /dev/null -X POST \
|
|
44
|
+
"https://indexnow.org/ping" \
|
|
45
|
+
-H "Content-Type: text/plain" \
|
|
46
|
+
-d "url=$url&key=$INDEXNOW_KEY")
|
|
47
|
+
echo " IndexNow: $url → HTTP $RESPONSE"
|
|
48
|
+
done
|
|
49
|
+
fi
|
|
50
|
+
|
|
51
|
+
echo ""
|
|
52
|
+
echo "=== Done ==="
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
declare module '@my-org/a3m-router/src/providers/registry' {
|
|
2
|
+
const PROVIDERS: Map<string, any>;
|
|
3
|
+
const registry: Map<string, any>;
|
|
4
|
+
export function registerProvider(name: string, config: any): void;
|
|
5
|
+
export function getProvider(name: string): any;
|
|
6
|
+
export function listProviders(): Array<[string, any]>;
|
|
7
|
+
export interface ProviderRegistry {
|
|
8
|
+
registerProvider: (name: string, config: any) => void;
|
|
9
|
+
getProvider: (name: string) => any;
|
|
10
|
+
listProviders: () => Array<[string, any]>;
|
|
11
|
+
}
|
|
12
|
+
const registryInstance: ProviderRegistry;
|
|
13
|
+
export default registryInstance;
|
|
14
|
+
}
|