agentx-kit 0.3.0__tar.gz → 0.4.0__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 (78) hide show
  1. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/PKG-INFO +33 -1
  2. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/README.md +30 -0
  3. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/pyproject.toml +3 -1
  4. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/__init__.py +1 -1
  5. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/cli.py +30 -0
  6. agentx_kit-0.4.0/src/agentx/connector/__init__.py +18 -0
  7. agentx_kit-0.4.0/src/agentx/connector/build.py +111 -0
  8. agentx_kit-0.4.0/src/agentx/connector/recommend.py +116 -0
  9. agentx_kit-0.4.0/src/agentx/connector/server.py +108 -0
  10. agentx_kit-0.4.0/tests/test_connector.py +70 -0
  11. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/.github/workflows/publish.yml +0 -0
  12. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/.gitignore +0 -0
  13. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/DESIGN.md +0 -0
  14. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/LICENSE +0 -0
  15. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/RESEARCH.md +0 -0
  16. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/config.py +0 -0
  17. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/dashboard/__init__.py +0 -0
  18. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/dashboard/app.py +0 -0
  19. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/frameworks/__init__.py +0 -0
  20. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/frameworks/crewai_agent.py +0 -0
  21. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/frameworks/langchain_agent.py +0 -0
  22. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/guardrails.py +0 -0
  23. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/insights/__init__.py +0 -0
  24. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/insights/analyze.py +0 -0
  25. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/insights/log.py +0 -0
  26. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/insights/optimize.py +0 -0
  27. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/insights/tokens.py +0 -0
  28. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/memory/__init__.py +0 -0
  29. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/memory/store.py +0 -0
  30. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/observability.py +0 -0
  31. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/prompts/__init__.py +0 -0
  32. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/prompts/templates.py +0 -0
  33. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/providers/__init__.py +0 -0
  34. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/providers/base.py +0 -0
  35. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/providers/factory.py +0 -0
  36. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/providers/registry.py +0 -0
  37. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/rag/__init__.py +0 -0
  38. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/rag/pipeline.py +0 -0
  39. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/reliability.py +0 -0
  40. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/scaffold/__init__.py +0 -0
  41. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/scaffold/generator.py +0 -0
  42. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/scaffold/prompts_store.py +0 -0
  43. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/scaffold/spec.py +0 -0
  44. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/Dockerfile.j2 +0 -0
  45. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/README.md.j2 +0 -0
  46. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/ci.yml.j2 +0 -0
  47. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/docker-compose.yml.j2 +0 -0
  48. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/dockerignore.j2 +0 -0
  49. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/env.example.j2 +0 -0
  50. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/evals/dataset.json.j2 +0 -0
  51. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/evals/run_evals.py.j2 +0 -0
  52. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/gitignore.j2 +0 -0
  53. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/mcp_servers.json.j2 +0 -0
  54. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/pkg/__init__.py.j2 +0 -0
  55. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/pkg/agents.py.j2 +0 -0
  56. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/pkg/config.py.j2 +0 -0
  57. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/pkg/guardrails.py.j2 +0 -0
  58. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/pkg/main.py.j2 +0 -0
  59. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/pkg/memory.py.j2 +0 -0
  60. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/pkg/observability.py.j2 +0 -0
  61. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/pkg/prompts.py.j2 +0 -0
  62. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/pkg/rag.py.j2 +0 -0
  63. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/pkg/server.py.j2 +0 -0
  64. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/pkg/tools.py.j2 +0 -0
  65. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/pyproject.toml.j2 +0 -0
  66. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/skills_seed.json.j2 +0 -0
  67. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/scaffold/wizard.py +0 -0
  68. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/skills/__init__.py +0 -0
  69. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/skills/registry.py +0 -0
  70. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/structured.py +0 -0
  71. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/tools/__init__.py +0 -0
  72. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/tools/builtin.py +0 -0
  73. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/src/agentx/tools/mcp.py +0 -0
  74. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/tests/test_enterprise.py +0 -0
  75. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/tests/test_insights.py +0 -0
  76. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/tests/test_prompts.py +0 -0
  77. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/tests/test_providers.py +0 -0
  78. {agentx_kit-0.3.0 → agentx_kit-0.4.0}/tests/test_scaffold.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentx-kit
3
- Version: 0.3.0
3
+ Version: 0.4.0
4
4
  Summary: An open-source, provider-agnostic agentic framework + interactive project scaffolder for LangChain and CrewAI. Pick your LLM provider, agents, RAG, memory, MCP tools and skills — generate a ready-to-run uv project.
5
5
  Project-URL: Homepage, https://github.com/muhammadyahiya/agentx-kit
6
6
  Project-URL: Repository, https://github.com/muhammadyahiya/agentx-kit
@@ -59,6 +59,8 @@ Provides-Extra: azure
59
59
  Requires-Dist: langchain-openai>=0.2.0; extra == 'azure'
60
60
  Provides-Extra: bedrock
61
61
  Requires-Dist: langchain-aws>=0.2.0; extra == 'bedrock'
62
+ Provides-Extra: connector
63
+ Requires-Dist: mcp>=1.2.0; extra == 'connector'
62
64
  Provides-Extra: crewai
63
65
  Requires-Dist: crewai>=0.70.0; extra == 'crewai'
64
66
  Provides-Extra: dashboard
@@ -260,6 +262,35 @@ It gives you, live as you edit:
260
262
  Run it inside a generated AgentX project and it reads/writes that project's
261
263
  `prompts.json`; run it anywhere else for a free-form prompt scratchpad.
262
264
 
265
+ ## 🔌 Use as a connector (Claude / Copilot / Codex)
266
+ AgentX-Kit ships an **MCP server**, so any MCP-capable assistant can scaffold a
267
+ complete project from **a single prompt with your problem statement**.
268
+
269
+ ```bash
270
+ pip install "agentx-kit[connector]"
271
+ agentx mcp --print-config # prints the client config below
272
+ ```
273
+
274
+ Add it to your client (then restart it):
275
+ ```jsonc
276
+ // Claude Desktop / Codex / Copilot — under "mcpServers"
277
+ { "mcpServers": { "agentx-kit": { "command": "agentx", "args": ["mcp"] } } }
278
+ ```
279
+ ```bash
280
+ # Claude Code one-liner
281
+ claude mcp add agentx-kit -- agentx mcp
282
+ ```
283
+
284
+ Now just ask, in plain language:
285
+ > *“Build a customer-support agent that answers from our product docs and serves a REST API.”*
286
+
287
+ The assistant calls AgentX-Kit's tools and you get a complete, runnable project:
288
+ - **`recommend_project(problem_statement)`** — suggests framework, provider, agent count, and features.
289
+ - **`create_agent_project(problem_statement, …)`** — generates the project (infers RAG/serve/memory/etc. from the statement, or take explicit overrides / `enterprise=true`) and returns the file tree + key file contents + run steps.
290
+ - **`list_providers`**, **`analyze_prompt`**, **`optimize_prompt`** — provider list + prompt insights.
291
+
292
+ So from one sentence the assistant produces a pre-wired project (prompts already seeded from your use case), ready to `uv sync && uv run`.
293
+
263
294
  ## 🏢 Enterprise pack
264
295
  Generate a production-shaped project with one flag — informed by a survey of
265
296
  CrewAI/LangGraph/create-llama/AgentStack/agno/pydantic-ai (see [RESEARCH.md](RESEARCH.md)):
@@ -309,6 +340,7 @@ llm = build_resilient_chat("openai", "gpt-4o-mini", fallbacks=[("anthropic", "cl
309
340
  | `observability` | `opentelemetry-*`, `openinference-*` | tracing |
310
341
  | `server` | `fastapi`, `uvicorn` | serving |
311
342
  | `dashboard` | `streamlit`, `tiktoken`, `pandas` | prompt observability dashboard |
343
+ | `connector` | `mcp` | MCP server for Claude/Copilot/Codex |
312
344
  | `all` | everything above | kitchen sink |
313
345
 
314
346
  See [DESIGN.md](DESIGN.md) for the architecture and [RESEARCH.md](RESEARCH.md) for the competitive analysis behind these features.
@@ -158,6 +158,35 @@ It gives you, live as you edit:
158
158
  Run it inside a generated AgentX project and it reads/writes that project's
159
159
  `prompts.json`; run it anywhere else for a free-form prompt scratchpad.
160
160
 
161
+ ## 🔌 Use as a connector (Claude / Copilot / Codex)
162
+ AgentX-Kit ships an **MCP server**, so any MCP-capable assistant can scaffold a
163
+ complete project from **a single prompt with your problem statement**.
164
+
165
+ ```bash
166
+ pip install "agentx-kit[connector]"
167
+ agentx mcp --print-config # prints the client config below
168
+ ```
169
+
170
+ Add it to your client (then restart it):
171
+ ```jsonc
172
+ // Claude Desktop / Codex / Copilot — under "mcpServers"
173
+ { "mcpServers": { "agentx-kit": { "command": "agentx", "args": ["mcp"] } } }
174
+ ```
175
+ ```bash
176
+ # Claude Code one-liner
177
+ claude mcp add agentx-kit -- agentx mcp
178
+ ```
179
+
180
+ Now just ask, in plain language:
181
+ > *“Build a customer-support agent that answers from our product docs and serves a REST API.”*
182
+
183
+ The assistant calls AgentX-Kit's tools and you get a complete, runnable project:
184
+ - **`recommend_project(problem_statement)`** — suggests framework, provider, agent count, and features.
185
+ - **`create_agent_project(problem_statement, …)`** — generates the project (infers RAG/serve/memory/etc. from the statement, or take explicit overrides / `enterprise=true`) and returns the file tree + key file contents + run steps.
186
+ - **`list_providers`**, **`analyze_prompt`**, **`optimize_prompt`** — provider list + prompt insights.
187
+
188
+ So from one sentence the assistant produces a pre-wired project (prompts already seeded from your use case), ready to `uv sync && uv run`.
189
+
161
190
  ## 🏢 Enterprise pack
162
191
  Generate a production-shaped project with one flag — informed by a survey of
163
192
  CrewAI/LangGraph/create-llama/AgentStack/agno/pydantic-ai (see [RESEARCH.md](RESEARCH.md)):
@@ -207,6 +236,7 @@ llm = build_resilient_chat("openai", "gpt-4o-mini", fallbacks=[("anthropic", "cl
207
236
  | `observability` | `opentelemetry-*`, `openinference-*` | tracing |
208
237
  | `server` | `fastapi`, `uvicorn` | serving |
209
238
  | `dashboard` | `streamlit`, `tiktoken`, `pandas` | prompt observability dashboard |
239
+ | `connector` | `mcp` | MCP server for Claude/Copilot/Codex |
210
240
  | `all` | everything above | kitchen sink |
211
241
 
212
242
  See [DESIGN.md](DESIGN.md) for the architecture and [RESEARCH.md](RESEARCH.md) for the competitive analysis behind these features.
@@ -1,7 +1,7 @@
1
1
  [project]
2
2
  # PyPI distribution name (import name + CLI stay `agentx`; `agentx` was taken).
3
3
  name = "agentx-kit"
4
- version = "0.3.0"
4
+ version = "0.4.0"
5
5
  description = "An open-source, provider-agnostic agentic framework + interactive project scaffolder for LangChain and CrewAI. Pick your LLM provider, agents, RAG, memory, MCP tools and skills — generate a ready-to-run uv project."
6
6
  readme = "README.md"
7
7
  requires-python = ">=3.10,<3.14"
@@ -60,6 +60,7 @@ observability = [
60
60
  ]
61
61
  server = ["fastapi>=0.110.0", "uvicorn[standard]>=0.29.0", "sse-starlette>=2.0.0"]
62
62
  dashboard = ["streamlit>=1.40.0", "tiktoken>=0.7.0", "pandas>=2.0.0"]
63
+ connector = ["mcp>=1.2.0"]
63
64
 
64
65
  # ---- Bundles ----
65
66
  all = [
@@ -73,6 +74,7 @@ all = [
73
74
  "openinference-instrumentation-langchain>=0.1.0",
74
75
  "fastapi>=0.110.0", "uvicorn[standard]>=0.29.0", "sse-starlette>=2.0.0",
75
76
  "streamlit>=1.40.0", "tiktoken>=0.7.0", "pandas>=2.0.0",
77
+ "mcp>=1.2.0",
76
78
  ]
77
79
  dev = ["pytest>=8.0.0", "pytest-cov>=5.0.0"]
78
80
 
@@ -16,7 +16,7 @@ is enough to get started.
16
16
  """
17
17
  from __future__ import annotations
18
18
 
19
- __version__ = "0.3.0"
19
+ __version__ = "0.4.0"
20
20
 
21
21
  from .providers import ( # noqa: E402
22
22
  ProviderSpec,
@@ -68,6 +68,36 @@ def dashboard(
68
68
  raise typer.Exit(1) from exc
69
69
 
70
70
 
71
+ @app.command()
72
+ def mcp(
73
+ print_config: bool = typer.Option(False, "--print-config", help="Print MCP client config for Claude/Codex/Copilot and exit."),
74
+ ) -> None:
75
+ """Run AgentX-Kit as an MCP server (connector for Claude / Copilot / Codex).
76
+
77
+ Once connected, a single prompt with a problem statement generates a complete
78
+ project. Add it to a client with the config from `agentx mcp --print-config`.
79
+ """
80
+ if print_config:
81
+ import json
82
+
83
+ from .connector import client_config
84
+
85
+ cfg = client_config()
86
+ console.print("[bold]MCP client config[/] (Claude Desktop / Claude Code / Codex / Copilot):\n")
87
+ console.print(json.dumps(cfg, indent=2))
88
+ console.print("\n[bold]Claude Code one-liner:[/]")
89
+ console.print(" claude mcp add agentx-kit -- agentx mcp")
90
+ console.print("\n[dim]Add the JSON under \"mcpServers\" in your client's MCP config "
91
+ "(e.g. claude_desktop_config.json), then restart the client.[/]")
92
+ return
93
+ try:
94
+ from .connector import run
95
+ except RuntimeError as exc:
96
+ console.print(f"[red]{exc}[/]")
97
+ raise typer.Exit(1) from exc
98
+ run() # stdio; no console output (the client drives it)
99
+
100
+
71
101
  def _result_panel(result, spec: ProjectSpec) -> None:
72
102
  lines = [f"[bold green]✓[/] Project '{spec.slug}' created at:", f" {result.target_dir}", ""]
73
103
  lines += [f" • {m}" for m in result.messages]
@@ -0,0 +1,18 @@
1
+ """MCP connector — expose AgentX-Kit to Claude / Copilot / Codex.
2
+
3
+ `recommend_spec` and `build_project_from_statement` are pure (no MCP dep);
4
+ `build_server`/`run` require ``agentx-kit[connector]``.
5
+ """
6
+ from .build import build_project_from_statement
7
+ from .recommend import recommend_spec
8
+
9
+ __all__ = ["recommend_spec", "build_project_from_statement", "build_server", "run", "client_config"]
10
+
11
+
12
+ def __getattr__(name: str):
13
+ # Lazy: only import the MCP SDK when the server is actually requested.
14
+ if name in ("build_server", "run", "client_config"):
15
+ from . import server
16
+
17
+ return getattr(server, name)
18
+ raise AttributeError(name)
@@ -0,0 +1,111 @@
1
+ """Turn a problem statement (+ optional overrides) into a generated project.
2
+
3
+ Pure orchestration over the scaffolder — no MCP dependency — so it's testable
4
+ and reusable. The MCP tools in ``server.py`` are thin wrappers around this.
5
+ """
6
+ from __future__ import annotations
7
+
8
+ from pathlib import Path
9
+
10
+ from ..scaffold import AgentSpec, ProjectSpec, generate_project
11
+ from .recommend import recommend_spec
12
+
13
+ _ALL_FEATURES = ["rag", "memory", "mcp", "skills", "observability", "guardrails", "serve", "docker", "ci", "evals"]
14
+ _KEY_FILES_MAX = 6000
15
+
16
+
17
+ def _apply_features(spec: ProjectSpec, features: list[str]) -> None:
18
+ fl = set(features or [])
19
+ spec.use_rag = "rag" in fl
20
+ spec.memory = "both" if "memory" in fl else "none"
21
+ spec.use_mcp = "mcp" in fl
22
+ spec.use_skills = "skills" in fl
23
+ spec.observability = "observability" in fl
24
+ spec.guardrails = "guardrails" in fl
25
+ spec.serve = "serve" in fl
26
+ spec.docker = "docker" in fl
27
+ spec.ci = "ci" in fl
28
+ spec.evals = "evals" in fl
29
+
30
+
31
+ def build_project_from_statement(
32
+ problem_statement: str,
33
+ name: str = "",
34
+ framework: str = "",
35
+ provider: str = "",
36
+ model: str = "",
37
+ agents: int = 0,
38
+ features: list[str] | None = None,
39
+ enterprise: bool = False,
40
+ output_dir: str = "",
41
+ create_venv: bool = False,
42
+ overwrite: bool = True,
43
+ ) -> dict:
44
+ """Generate a complete project for a problem statement; return a summary."""
45
+ rec = recommend_spec(problem_statement)
46
+ name = name or rec["name"]
47
+ framework = framework or rec["framework"]
48
+ provider = provider or rec["provider"]
49
+ model = model or rec["model"]
50
+ n_agents = agents or rec["agents"]
51
+ feats = list(features) if features is not None else list(rec["features"])
52
+
53
+ # First agent carries the role/goal/prompt derived from the problem statement.
54
+ agent_specs = [AgentSpec(name="assistant" if n_agents == 1 else "agent_1",
55
+ role=rec["role"], goal=rec["goal"], system_prompt=rec["system_prompt"])]
56
+ for i in range(1, n_agents):
57
+ agent_specs.append(AgentSpec(name=f"agent_{i + 1}", role=rec["role"]))
58
+
59
+ spec = ProjectSpec(
60
+ name=name, framework=framework, provider=provider, model=model,
61
+ agents=agent_specs, prompt_style="custom", create_venv=create_venv,
62
+ )
63
+ if enterprise:
64
+ spec.enable_enterprise()
65
+ feats = _ALL_FEATURES
66
+ else:
67
+ _apply_features(spec, feats)
68
+
69
+ target = Path(output_dir).expanduser() if output_dir else Path.cwd() / spec.slug
70
+ result = generate_project(spec, target, overwrite=overwrite)
71
+ root = result.target_dir
72
+
73
+ # Collect a compact view for the calling LLM.
74
+ tree = sorted(str(p.relative_to(root)) for p in root.glob("**/*") if p.is_file())
75
+ pkg = spec.package
76
+ key_paths = [
77
+ "pyproject.toml", "prompts.json", "agentx.json",
78
+ f"src/{pkg}/main.py", f"src/{pkg}/agents.py", f"src/{pkg}/prompts.py",
79
+ ]
80
+ if spec.serve:
81
+ key_paths.append(f"src/{pkg}/server.py")
82
+ key_files = {}
83
+ for rel in key_paths:
84
+ fp = root / rel
85
+ if fp.exists():
86
+ key_files[rel] = fp.read_text(encoding="utf-8")[:_KEY_FILES_MAX]
87
+
88
+ run_cmd = (
89
+ f"uv run uvicorn {pkg}.server:app --reload" if spec.serve else f"uv run {spec.slug}"
90
+ )
91
+ next_steps = [
92
+ f"cd {root.name}",
93
+ "cp .env.example .env # add your provider API key(s)",
94
+ "uv venv && uv sync",
95
+ run_cmd,
96
+ ]
97
+
98
+ return {
99
+ "ok": True,
100
+ "target_dir": str(root),
101
+ "name": spec.slug,
102
+ "framework": framework,
103
+ "provider": provider,
104
+ "model": model or "(provider default)",
105
+ "agents": [a.name for a in agent_specs],
106
+ "features": feats,
107
+ "rationale": rec["rationale"],
108
+ "file_tree": tree,
109
+ "key_files": key_files,
110
+ "next_steps": next_steps,
111
+ }
@@ -0,0 +1,116 @@
1
+ """Map a natural-language problem statement to a recommended ProjectSpec.
2
+
3
+ Pure and dependency-free so it's testable and usable without the MCP SDK. The
4
+ connector uses this to turn a single user prompt into a complete project.
5
+ """
6
+ from __future__ import annotations
7
+
8
+ import re
9
+
10
+ _STOP = {
11
+ "a", "an", "the", "for", "with", "that", "this", "and", "or", "to", "of", "in",
12
+ "on", "is", "are", "be", "build", "create", "make", "want", "need", "should",
13
+ "able", "can", "will", "agent", "agents", "ai", "app", "application", "using",
14
+ "use", "my", "our", "me", "you", "it", "system", "assistant", "bot", "help",
15
+ }
16
+
17
+ _ROLE_MAP = [
18
+ (("support", "ticket", "helpdesk", "customer"), "Customer Support Agent"),
19
+ (("research", "literature", "analyze papers", "summarize papers"), "Research Agent"),
20
+ (("code", "developer", "programming", "refactor", "review pull"), "Coding Assistant"),
21
+ (("data", "analytics", "sql", "report", "dashboard"), "Data Analyst"),
22
+ (("sales", "lead", "crm", "outreach"), "Sales Assistant"),
23
+ (("legal", "contract", "compliance", "policy"), "Compliance Assistant"),
24
+ (("medical", "clinical", "patient", "health"), "Clinical Assistant"),
25
+ (("devops", "infrastructure", "kubernetes", "deploy"), "DevOps Assistant"),
26
+ ]
27
+
28
+
29
+ def _has(text: str, *kw: str) -> bool:
30
+ return any(k in text for k in kw)
31
+
32
+
33
+ def _slug_from(text: str) -> str:
34
+ words = [w for w in re.findall(r"[a-z0-9]+", text.lower()) if w not in _STOP and len(w) > 2]
35
+ picked = words[:3] or ["agentx", "app"]
36
+ return "-".join(picked)
37
+
38
+
39
+ def _role_for(text: str) -> str:
40
+ for keys, role in _ROLE_MAP:
41
+ if _has(text, *keys):
42
+ return role
43
+ return "Assistant"
44
+
45
+
46
+ def recommend_spec(problem_statement: str) -> dict:
47
+ """Return a recommended spec dict + rationale for a problem statement."""
48
+ text = (problem_statement or "").lower().strip()
49
+
50
+ multi = _has(text, "multi-agent", "multi agent", "multiple agents", "team of",
51
+ "crew", "collaborat", "debate", "researcher and", "reviewer", "planner")
52
+ framework = "crewai" if multi else "langgraph"
53
+
54
+ rag = _has(text, "document", "knowledge", "docs", "rag", "retriev", "pdf",
55
+ "manual", "faq", "knowledge base", " kb", "our data", "company data",
56
+ "search through", "cite", "sources")
57
+ memory = _has(text, "remember", "conversation history", "multi-turn", "multi turn",
58
+ "across sessions", "previous", "chat history", "follow-up", "follow up")
59
+ mcp = _has(text, "mcp", "external tool", "integrate with", "third-party", "third party",
60
+ "plugin", "connect to", "external api")
61
+ skills = _has(text, "guideline", "standard", "compliance", "policy", "style guide",
62
+ "best practice", "framework method")
63
+ serve = _has(text, "api", "endpoint", "serve", "rest", "http", "backend",
64
+ "microservice", "webhook", "chat ui", "web app")
65
+ production = _has(text, "production", "enterprise", "scalable", "observability",
66
+ "monitor", "trace", "secure", "reliable", "deploy", "high traffic")
67
+ coding = _has(text, "coding", "write code", "code generation", "programming task")
68
+
69
+ features: list[str] = []
70
+ if rag:
71
+ features.append("rag")
72
+ if memory:
73
+ features.append("memory")
74
+ if mcp:
75
+ features.append("mcp")
76
+ if skills:
77
+ features.append("skills")
78
+ if serve or production:
79
+ features.append("serve")
80
+ if production:
81
+ features += ["observability", "guardrails", "docker", "ci", "evals"]
82
+ # de-dupe, stable order
83
+ seen: list[str] = []
84
+ for f in features:
85
+ if f not in seen:
86
+ seen.append(f)
87
+
88
+ agents = 3 if framework == "crewai" else 1
89
+ role = _role_for(text)
90
+ goal = (problem_statement or "Help the user accomplish their task accurately.").strip()
91
+ system_prompt = (
92
+ f"You are a {role}. {goal} "
93
+ "Be accurate and concise, use your tools/knowledge before guessing, "
94
+ "cite sources when available, and ask for clarification when the request is ambiguous."
95
+ )
96
+
97
+ rationale = (
98
+ f"Chose **{framework}** ({'multi-agent collaboration detected' if multi else 'single-agent task'}); "
99
+ f"features: {', '.join(seen) or 'none'}. "
100
+ f"{'RAG (knowledge grounding). ' if rag else ''}"
101
+ f"{'Serving/API layer. ' if serve or production else ''}"
102
+ f"{'Full enterprise pack (tracing/guardrails/docker/CI/evals). ' if production else ''}"
103
+ ).strip()
104
+
105
+ return {
106
+ "name": _slug_from(text),
107
+ "framework": framework,
108
+ "provider": "openai",
109
+ "model": "",
110
+ "agents": agents,
111
+ "role": role,
112
+ "goal": goal[:300],
113
+ "system_prompt": system_prompt[:600],
114
+ "features": seen,
115
+ "rationale": rationale,
116
+ }
@@ -0,0 +1,108 @@
1
+ """MCP server exposing AgentX-Kit to Claude / Copilot / Codex as a connector.
2
+
3
+ Run over stdio with ``agentx mcp``. Any MCP-capable client (Claude Desktop,
4
+ Claude Code, GitHub Copilot, OpenAI Codex) can then, from a single prompt with a
5
+ problem statement, generate a complete, ready-to-run agent project.
6
+
7
+ Tools:
8
+ • recommend_project(problem_statement) → suggested stack + features
9
+ • create_agent_project(problem_statement, …) → generates the project, returns files
10
+ • list_providers() → supported LLM providers
11
+ • analyze_prompt(prompt) / optimize_prompt(…) → prompt insights
12
+ """
13
+ from __future__ import annotations
14
+
15
+ from typing import Any
16
+
17
+ from ..providers import all_specs
18
+ from .build import build_project_from_statement
19
+ from .recommend import recommend_spec
20
+
21
+
22
+ def build_server():
23
+ """Construct the FastMCP server. Requires ``agentx-kit[connector]``."""
24
+ try:
25
+ from mcp.server.fastmcp import FastMCP
26
+ except ImportError as exc: # pragma: no cover
27
+ raise RuntimeError(
28
+ "The MCP connector needs the MCP SDK. Install it with:\n"
29
+ " pip install 'agentx-kit[connector]'"
30
+ ) from exc
31
+
32
+ mcp = FastMCP("agentx-kit")
33
+
34
+ @mcp.tool()
35
+ def list_providers() -> list[dict]:
36
+ """List the LLM providers AgentX-Kit can target and the env vars each needs."""
37
+ return [
38
+ {"id": s.id, "label": s.label, "default_model": s.default_model, "env_vars": list(s.env_vars)}
39
+ for s in all_specs()
40
+ ]
41
+
42
+ @mcp.tool()
43
+ def recommend_project(problem_statement: str) -> dict:
44
+ """Recommend a framework, provider, agent count and features for a use case.
45
+
46
+ Call this first to preview the stack; then call create_agent_project.
47
+ """
48
+ return recommend_spec(problem_statement)
49
+
50
+ @mcp.tool()
51
+ def create_agent_project(
52
+ problem_statement: str,
53
+ name: str = "",
54
+ framework: str = "",
55
+ provider: str = "",
56
+ model: str = "",
57
+ agents: int = 0,
58
+ features: list[str] | None = None,
59
+ enterprise: bool = False,
60
+ output_dir: str = "",
61
+ ) -> dict:
62
+ """Generate a complete, runnable agent project from a problem statement.
63
+
64
+ Leave optional args blank to let AgentX infer them from the problem
65
+ statement. ``features`` may include: rag, memory, mcp, skills,
66
+ observability, guardrails, serve, docker, ci, evals. Set ``enterprise``
67
+ true for the full production pack. Returns the target dir, file tree,
68
+ key file contents, and run steps.
69
+ """
70
+ try:
71
+ return build_project_from_statement(
72
+ problem_statement, name=name, framework=framework, provider=provider,
73
+ model=model, agents=agents, features=features, enterprise=enterprise,
74
+ output_dir=output_dir, create_venv=False, overwrite=True,
75
+ )
76
+ except Exception as exc: # noqa: BLE001
77
+ return {"ok": False, "error": str(exc)}
78
+
79
+ @mcp.tool()
80
+ def analyze_prompt(prompt: str, model: str = "gpt-4o-mini") -> dict:
81
+ """Analyse a prompt: token count, quality score (0-100), suggestions, warnings."""
82
+ from ..insights import analyze_prompt as _analyze
83
+
84
+ a = _analyze(prompt, model)
85
+ return {
86
+ "tokens": a.tokens, "quality_score": a.quality_score,
87
+ "checks": a.checks, "suggestions": a.suggestions, "warnings": a.warnings,
88
+ }
89
+
90
+ @mcp.tool()
91
+ def optimize_prompt(prompt: str, provider: str = "openai", model: str = "", feedback: str = "") -> dict:
92
+ """Refine a prompt with an LLM (preserving intent); returns improved prompt + rationale."""
93
+ from ..insights import optimize_prompt as _optimize
94
+
95
+ r = _optimize(prompt, provider, model or None, feedback=feedback)
96
+ return {"ok": r.ok, "improved": r.improved, "rationale": r.rationale, "error": r.error}
97
+
98
+ return mcp
99
+
100
+
101
+ def run() -> None:
102
+ """Run the MCP server over stdio (for Claude/Copilot/Codex)."""
103
+ build_server().run()
104
+
105
+
106
+ def client_config(command: str = "agentx") -> dict[str, Any]:
107
+ """Return an MCP client config snippet for this server."""
108
+ return {"mcpServers": {"agentx-kit": {"command": command, "args": ["mcp"]}}}
@@ -0,0 +1,70 @@
1
+ """Tests for the MCP connector's recommender + project builder (no MCP transport)."""
2
+ import py_compile
3
+
4
+ from agentx.connector import build_project_from_statement, recommend_spec
5
+
6
+
7
+ # ----- recommender heuristics -----
8
+ def test_recommend_rag_support_use_case():
9
+ rec = recommend_spec("Build a customer support agent that answers from our help docs and PDFs.")
10
+ assert rec["framework"] == "langgraph"
11
+ assert "rag" in rec["features"]
12
+ assert rec["role"] == "Customer Support Agent"
13
+ assert rec["name"] # non-empty slug
14
+
15
+
16
+ def test_recommend_multi_agent_research():
17
+ rec = recommend_spec("A team of agents: a researcher and a reviewer that collaborate to write reports.")
18
+ assert rec["framework"] == "crewai"
19
+ assert rec["agents"] >= 2
20
+
21
+
22
+ def test_recommend_production_api_enables_enterprise_features():
23
+ rec = recommend_spec("Production-ready REST API agent, scalable with observability and monitoring.")
24
+ for f in ("serve", "observability", "guardrails", "docker", "ci", "evals"):
25
+ assert f in rec["features"], f
26
+
27
+
28
+ def test_recommend_minimal():
29
+ rec = recommend_spec("just chat with me")
30
+ assert rec["framework"] == "langgraph"
31
+ assert rec["features"] == []
32
+
33
+
34
+ # ----- builder produces a real, compilable project -----
35
+ def test_build_project_from_statement(tmp_path):
36
+ out = build_project_from_statement(
37
+ "Build a support agent that answers from our documentation and serves an API.",
38
+ output_dir=str(tmp_path / "proj"), create_venv=False, overwrite=True,
39
+ )
40
+ assert out["ok"] is True
41
+ assert "rag" in out["features"] and "serve" in out["features"]
42
+ assert "prompts.json" in out["key_files"]
43
+ assert "agentx.json" in out["key_files"]
44
+ # the derived system prompt carries the use case
45
+ import json
46
+ prompts = json.loads(out["key_files"]["prompts.json"])
47
+ sp = next(iter(prompts["agents"].values()))["system_prompt"]
48
+ assert "documentation" in sp.lower() or "support" in sp.lower()
49
+ # generated python compiles
50
+ from pathlib import Path
51
+ for py in Path(out["target_dir"]).glob("**/*.py"):
52
+ py_compile.compile(str(py), doraise=True)
53
+ assert any(p.endswith("server.py") for p in out["file_tree"])
54
+
55
+
56
+ def test_build_explicit_overrides(tmp_path):
57
+ out = build_project_from_statement(
58
+ "chat assistant", name="my-bot", framework="crewai", provider="ollama",
59
+ features=["memory"], output_dir=str(tmp_path / "o"), create_venv=False, overwrite=True,
60
+ )
61
+ assert out["name"] == "my-bot"
62
+ assert out["framework"] == "crewai"
63
+ assert "memory" in out["features"]
64
+
65
+
66
+ def test_client_config_shape():
67
+ from agentx.connector import client_config
68
+
69
+ cfg = client_config()
70
+ assert cfg["mcpServers"]["agentx-kit"]["args"] == ["mcp"]
File without changes
File without changes
File without changes
File without changes