universal-mcp 0.1.0__tar.gz → 0.1.1rc1__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 (74) hide show
  1. universal_mcp-0.1.1rc1/.github/workflows/publish-pypi.yml +48 -0
  2. universal_mcp-0.1.1rc1/.github/workflows/pull-request-checks.yml +8 -0
  3. universal_mcp-0.1.1rc1/.github/workflows/shared.yml +54 -0
  4. universal_mcp-0.1.1rc1/.gitignore +47 -0
  5. universal_mcp-0.1.1rc1/.pre-commit-config.yaml +24 -0
  6. universal_mcp-0.1.1rc1/CONTRIBUTING.md +78 -0
  7. {universal_mcp-0.1.0 → universal_mcp-0.1.1rc1}/PKG-INFO +47 -5
  8. {universal_mcp-0.1.0 → universal_mcp-0.1.1rc1}/README.md +23 -1
  9. universal_mcp-0.1.1rc1/local_config.json.example +11 -0
  10. universal_mcp-0.1.1rc1/pyproject.toml +149 -0
  11. universal_mcp-0.1.1rc1/src/playground/README.md +65 -0
  12. universal_mcp-0.1.1rc1/src/playground/__init__.py +3 -0
  13. universal_mcp-0.1.1rc1/src/playground/__main__.py +37 -0
  14. universal_mcp-0.1.1rc1/src/playground/agents/react.py +51 -0
  15. universal_mcp-0.1.1rc1/src/playground/client.py +288 -0
  16. universal_mcp-0.1.1rc1/src/playground/memory/__init__.py +14 -0
  17. universal_mcp-0.1.1rc1/src/playground/memory/sqlite.py +9 -0
  18. universal_mcp-0.1.1rc1/src/playground/schema.py +178 -0
  19. universal_mcp-0.1.1rc1/src/playground/service.py +234 -0
  20. universal_mcp-0.1.1rc1/src/playground/settings.py +24 -0
  21. universal_mcp-0.1.1rc1/src/playground/streamlit.py +438 -0
  22. universal_mcp-0.1.1rc1/src/playground/utils.py +76 -0
  23. universal_mcp-0.1.1rc1/src/tests/conftest.py +1 -0
  24. universal_mcp-0.1.1rc1/src/tests/test_api_generator.py +267 -0
  25. universal_mcp-0.1.1rc1/src/tests/test_applications.py +34 -0
  26. universal_mcp-0.1.1rc1/src/tests/test_localserver.py +30 -0
  27. universal_mcp-0.1.1rc1/src/tests/test_zenquotes.py +28 -0
  28. universal_mcp-0.1.1rc1/src/universal_mcp/applications/__init__.py +26 -0
  29. {universal_mcp-0.1.0 → universal_mcp-0.1.1rc1}/src/universal_mcp/applications/application.py +13 -8
  30. universal_mcp-0.1.1rc1/src/universal_mcp/applications/e2b/app.py +74 -0
  31. universal_mcp-0.1.1rc1/src/universal_mcp/applications/firecrawl/app.py +381 -0
  32. universal_mcp-0.1.1rc1/src/universal_mcp/applications/github/README.md +35 -0
  33. {universal_mcp-0.1.0 → universal_mcp-0.1.1rc1}/src/universal_mcp/applications/github/app.py +133 -100
  34. {universal_mcp-0.1.0 → universal_mcp-0.1.1rc1}/src/universal_mcp/applications/google_calendar/app.py +170 -139
  35. {universal_mcp-0.1.0 → universal_mcp-0.1.1rc1}/src/universal_mcp/applications/google_mail/app.py +185 -160
  36. universal_mcp-0.1.1rc1/src/universal_mcp/applications/markitdown/app.py +32 -0
  37. {universal_mcp-0.1.0 → universal_mcp-0.1.1rc1}/src/universal_mcp/applications/reddit/app.py +112 -71
  38. {universal_mcp-0.1.0 → universal_mcp-0.1.1rc1}/src/universal_mcp/applications/resend/app.py +3 -8
  39. universal_mcp-0.1.1rc1/src/universal_mcp/applications/serp/app.py +84 -0
  40. {universal_mcp-0.1.0 → universal_mcp-0.1.1rc1}/src/universal_mcp/applications/tavily/app.py +11 -10
  41. {universal_mcp-0.1.0 → universal_mcp-0.1.1rc1}/src/universal_mcp/applications/zenquotes/app.py +3 -3
  42. universal_mcp-0.1.1rc1/src/universal_mcp/cli.py +165 -0
  43. universal_mcp-0.1.1rc1/src/universal_mcp/config.py +32 -0
  44. {universal_mcp-0.1.0 → universal_mcp-0.1.1rc1}/src/universal_mcp/exceptions.py +1 -3
  45. universal_mcp-0.1.1rc1/src/universal_mcp/integrations/__init__.py +8 -0
  46. {universal_mcp-0.1.0 → universal_mcp-0.1.1rc1}/src/universal_mcp/integrations/agentr.py +26 -24
  47. {universal_mcp-0.1.0 → universal_mcp-0.1.1rc1}/src/universal_mcp/integrations/integration.py +72 -35
  48. universal_mcp-0.1.1rc1/src/universal_mcp/servers/__init__.py +23 -0
  49. {universal_mcp-0.1.0 → universal_mcp-0.1.1rc1}/src/universal_mcp/servers/server.py +77 -45
  50. universal_mcp-0.1.1rc1/src/universal_mcp/stores/__init__.py +16 -0
  51. universal_mcp-0.1.1rc1/src/universal_mcp/stores/store.py +181 -0
  52. universal_mcp-0.1.1rc1/src/universal_mcp/utils/__init__.py +1 -0
  53. universal_mcp-0.1.1rc1/src/universal_mcp/utils/api_generator.py +269 -0
  54. universal_mcp-0.1.1rc1/src/universal_mcp/utils/docgen.py +360 -0
  55. universal_mcp-0.1.1rc1/src/universal_mcp/utils/installation.py +104 -0
  56. universal_mcp-0.1.1rc1/src/universal_mcp/utils/openapi.py +372 -0
  57. universal_mcp-0.1.1rc1/uv.lock +3299 -0
  58. universal_mcp-0.1.0/.gitignore +0 -17
  59. universal_mcp-0.1.0/pyproject.toml +0 -31
  60. universal_mcp-0.1.0/src/universal_mcp/applications/__init__.py +0 -31
  61. universal_mcp-0.1.0/src/universal_mcp/cli.py +0 -111
  62. universal_mcp-0.1.0/src/universal_mcp/config.py +0 -15
  63. universal_mcp-0.1.0/src/universal_mcp/integrations/__init__.py +0 -4
  64. universal_mcp-0.1.0/src/universal_mcp/servers/__init__.py +0 -3
  65. universal_mcp-0.1.0/src/universal_mcp/stores/__init__.py +0 -3
  66. universal_mcp-0.1.0/src/universal_mcp/stores/store.py +0 -71
  67. universal_mcp-0.1.0/src/universal_mcp/utils/openapi.py +0 -274
  68. universal_mcp-0.1.0/uv.lock +0 -510
  69. {universal_mcp-0.1.0 → universal_mcp-0.1.1rc1}/.python-version +0 -0
  70. /universal_mcp-0.1.0/src/universal_mcp/applications/agentr.py → /universal_mcp-0.1.1rc1/src/tests/__init__.py +0 -0
  71. {universal_mcp-0.1.0 → universal_mcp-0.1.1rc1}/src/universal_mcp/__init__.py +0 -0
  72. {universal_mcp-0.1.0 → universal_mcp-0.1.1rc1}/src/universal_mcp/integrations/README.md +0 -0
  73. {universal_mcp-0.1.0 → universal_mcp-0.1.1rc1}/src/universal_mcp/py.typed +0 -0
  74. {universal_mcp-0.1.0 → universal_mcp-0.1.1rc1}/src/universal_mcp/utils/bridge.py +0 -0
@@ -0,0 +1,48 @@
1
+ name: Publishing
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ jobs:
8
+ release-build:
9
+ name: Build distribution
10
+ runs-on: ubuntu-latest
11
+ needs: [checks]
12
+ steps:
13
+ - uses: actions/checkout@v4
14
+
15
+ - name: Install uv
16
+ uses: astral-sh/setup-uv@v3
17
+ with:
18
+ enable-cache: true
19
+
20
+ - name: Build
21
+ run: uv build
22
+
23
+ - name: Upload artifacts
24
+ uses: actions/upload-artifact@v4
25
+ with:
26
+ name: release-dists
27
+ path: dist/
28
+
29
+ checks:
30
+ uses: ./.github/workflows/shared.yml
31
+
32
+ pypi-publish:
33
+ name: Upload release to PyPI
34
+ runs-on: ubuntu-latest
35
+ needs:
36
+ - release-build
37
+ permissions:
38
+ id-token: write # IMPORTANT: this permission is mandatory for trusted publishing
39
+
40
+ steps:
41
+ - name: Retrieve release distributions
42
+ uses: actions/download-artifact@v4
43
+ with:
44
+ name: release-dists
45
+ path: dist/
46
+
47
+ - name: Publish package distributions to PyPI
48
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,8 @@
1
+ name: Pull request checks
2
+
3
+ on:
4
+ pull_request:
5
+
6
+ jobs:
7
+ checks:
8
+ uses: ./.github/workflows/shared.yml
@@ -0,0 +1,54 @@
1
+ name: Shared Checks
2
+
3
+ on:
4
+ workflow_call:
5
+
6
+ jobs:
7
+ format:
8
+ runs-on: ubuntu-latest
9
+ steps:
10
+ - uses: actions/checkout@v4
11
+
12
+ - name: Install uv
13
+ uses: astral-sh/setup-uv@v3
14
+ with:
15
+ enable-cache: true
16
+
17
+ - name: Install the project
18
+ run: uv sync --frozen --all-extras --dev
19
+
20
+ - name: Run ruff format check
21
+ run: uv run --no-sync ruff check .
22
+
23
+ typecheck:
24
+ runs-on: ubuntu-latest
25
+ steps:
26
+ - uses: actions/checkout@v4
27
+
28
+ - name: Install uv
29
+ uses: astral-sh/setup-uv@v3
30
+ with:
31
+ enable-cache: true
32
+
33
+ - name: Install the project
34
+ run: uv sync --frozen --all-extras --dev
35
+
36
+ # - name: Run pyright
37
+ # run: uv run --no-sync pyright
38
+
39
+ test:
40
+ runs-on: ubuntu-latest
41
+
42
+ steps:
43
+ - uses: actions/checkout@v4
44
+
45
+ - name: Install uv
46
+ uses: astral-sh/setup-uv@v3
47
+ with:
48
+ enable-cache: true
49
+
50
+ - name: Install the project
51
+ run: uv sync --frozen --all-extras --dev
52
+
53
+ - name: Run pytest
54
+ run: uv run --no-sync pytest
@@ -0,0 +1,47 @@
1
+ # Python-generated files
2
+ __pycache__/
3
+ *.py[oc]
4
+ build/
5
+ dist/
6
+ wheels/
7
+ *.egg-info
8
+
9
+ # Virtual environments
10
+ .venv
11
+
12
+ # Environment variables
13
+ .env
14
+ .env.local
15
+
16
+
17
+ dump/
18
+
19
+
20
+ # SQLite database
21
+ *.db
22
+ *.sqlite
23
+ *.sqlite3
24
+ *.db-shm
25
+ *.db-wal
26
+
27
+
28
+ # Pyright
29
+ .pyright
30
+
31
+ # Ruff
32
+ .ruff_cache
33
+
34
+ # Pytest
35
+ .pytest_cache
36
+
37
+
38
+ # Local config
39
+ local_config.json
40
+
41
+
42
+ # Test Artifacts
43
+ test_artifacts/
44
+ src/universal_mcp/applications/complex/
45
+ src/universal_mcp/applications/test/
46
+ src/universal_mcp/applications/test_with_docs/
47
+ src/universal_mcp/applications/test_without_docs/
@@ -0,0 +1,24 @@
1
+ fail_fast: true
2
+
3
+ repos:
4
+ - repo: https://github.com/pre-commit/mirrors-prettier
5
+ rev: v3.1.0
6
+ hooks:
7
+ - id: prettier
8
+ types_or: [yaml, json5]
9
+
10
+ - repo: https://github.com/astral-sh/ruff-pre-commit
11
+ rev: v0.8.1
12
+ hooks:
13
+ - id: ruff-format
14
+ - id: ruff
15
+ args: [--fix, --exit-non-zero-on-fix]
16
+
17
+ - repo: local
18
+ hooks:
19
+ - id: uv-lock-check
20
+ name: Check uv.lock is up to date
21
+ entry: uv lock --check
22
+ language: system
23
+ files: ^(pyproject\.toml|uv\.lock)$
24
+ pass_filenames: false
@@ -0,0 +1,78 @@
1
+ # Contributing to AgentR
2
+
3
+ Thank you for your interest in contributing to AgentR! This document provides guidelines and instructions for contributing to the project.
4
+
5
+ ## 🚀 Getting Started
6
+
7
+ 1. Fork the repository at git@github.com:AgentrDev/universal-mcp.git
8
+ 2. Clone your fork
9
+ 3. Create a new branch for your changes:
10
+ ```bash
11
+ git checkout -b feature/your-feature-name
12
+ ```
13
+
14
+ 4. Install development dependencies:
15
+ ```bash
16
+ pip install -e ".[test]"
17
+ ```
18
+
19
+ 5. Make your changes and ensure tests pass:
20
+ ```bash
21
+ pytest
22
+ ```
23
+
24
+ 6. Commit your changes following conventional commits:
25
+ ```bash
26
+ git commit -m "feat: add new feature"
27
+ ```
28
+
29
+ 7. Push to your fork:
30
+ ```bash
31
+ git push origin feature/your-feature-name
32
+ ```
33
+
34
+ 8. Open a Pull Request against the main repository
35
+
36
+ ## 📝 Guidelines
37
+
38
+ ### Code Style
39
+ - Follow PEP 8 guidelines
40
+ - Use type hints where possible
41
+ - Include docstrings for functions and classes
42
+ - Keep functions focused and single-purpose
43
+
44
+ ### Testing
45
+ - Add tests for new features
46
+ - Ensure all tests pass before submitting PR
47
+ - Maintain or improve code coverage
48
+
49
+ ### Pull Requests
50
+ - Keep PRs focused on a single change
51
+ - Include a clear description of changes
52
+ - Reference any related issues
53
+ - Update documentation as needed
54
+
55
+ ### Commit Messages
56
+ Follow conventional commits format:
57
+ - feat: New feature
58
+ - fix: Bug fix
59
+ - docs: Documentation changes
60
+ - style: Code style changes
61
+ - refactor: Code refactoring
62
+ - test: Test updates
63
+ - chore: Maintenance tasks
64
+
65
+ ## 🐛 Reporting Issues
66
+
67
+ - Search existing issues before creating new ones
68
+ - Include clear steps to reproduce
69
+ - Provide system information
70
+ - Add relevant logs or screenshots
71
+
72
+ ## 📚 Documentation
73
+
74
+ - Keep README.md updated
75
+ - Document new features
76
+ - Include docstrings
77
+ - Update CHANGELOG.md for significant changes
78
+
@@ -1,18 +1,38 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: universal-mcp
3
- Version: 0.1.0
3
+ Version: 0.1.1rc1
4
4
  Summary: Universal MCP acts as a middle ware for your API applications. It can store your credentials, authorize, enable disable apps on the fly and much more.
5
5
  Author-email: Manoj Bajaj <manojbajaj95@gmail.com>
6
6
  Requires-Python: >=3.11
7
+ Requires-Dist: keyring>=25.6.0
8
+ Requires-Dist: litellm>=1.30.7
7
9
  Requires-Dist: loguru>=0.7.3
10
+ Requires-Dist: markitdown[all]>=0.1.1
8
11
  Requires-Dist: mcp>=1.5.0
9
12
  Requires-Dist: pydantic-settings>=2.8.1
10
13
  Requires-Dist: pydantic>=2.11.1
11
14
  Requires-Dist: pyyaml>=6.0.2
12
15
  Requires-Dist: typer>=0.15.2
13
- Provides-Extra: test
14
- Requires-Dist: pytest-asyncio>=0.26.0; extra == 'test'
15
- Requires-Dist: pytest>=8.3.5; extra == 'test'
16
+ Provides-Extra: dev
17
+ Requires-Dist: litellm>=1.30.7; extra == 'dev'
18
+ Requires-Dist: pyright>=1.1.398; extra == 'dev'
19
+ Requires-Dist: pytest-asyncio>=0.26.0; extra == 'dev'
20
+ Requires-Dist: pytest>=8.3.5; extra == 'dev'
21
+ Requires-Dist: ruff>=0.11.4; extra == 'dev'
22
+ Provides-Extra: e2b
23
+ Requires-Dist: e2b-code-interpreter>=1.2.0; extra == 'e2b'
24
+ Provides-Extra: firecrawl
25
+ Requires-Dist: firecrawl-py>=1.15.0; extra == 'firecrawl'
26
+ Provides-Extra: playground
27
+ Requires-Dist: fastapi[standard]>=0.115.12; extra == 'playground'
28
+ Requires-Dist: langchain-anthropic>=0.3.10; extra == 'playground'
29
+ Requires-Dist: langchain-mcp-adapters>=0.0.3; extra == 'playground'
30
+ Requires-Dist: langgraph-checkpoint-sqlite>=2.0.6; extra == 'playground'
31
+ Requires-Dist: langgraph>=0.3.24; extra == 'playground'
32
+ Requires-Dist: python-dotenv>=1.0.1; extra == 'playground'
33
+ Requires-Dist: streamlit>=1.44.1; extra == 'playground'
34
+ Provides-Extra: serpapi
35
+ Requires-Dist: google-search-results>=2.4.2; extra == 'serpapi'
16
36
  Description-Content-Type: text/markdown
17
37
 
18
38
  # Universal MCP
@@ -87,6 +107,24 @@ if __name__ == "__main__":
87
107
  server.run()
88
108
  ```
89
109
 
110
+ ## Using Playground
111
+
112
+ Start MCP Server
113
+ ```bash
114
+ universal_mcp run -t sse
115
+ ```
116
+
117
+ Start FastAPI app
118
+ ```bash
119
+ fastapi run src/playground
120
+ ```
121
+
122
+ Start Frontend
123
+ ```bash
124
+ streamlit run src/playground/streamlit.py
125
+ ```
126
+
127
+
90
128
  ## 🧩 Available Applications
91
129
  AgentR comes with several pre-built applications:
92
130
 
@@ -141,7 +179,11 @@ AgentR includes a command-line interface for common operations:
141
179
  agentr version
142
180
 
143
181
  # Generate API client from OpenAPI schema
144
- agentr generate --schema path/to/openapi.yaml
182
+
183
+ # Use the name of the API as the output filename (e.g., twitter, petstore, github)
184
+ universal_mcp generate --schema petstore.json --output outputfilename
185
+
186
+ # The tool will create src/universal_mcp/applications/petstore/ with app.py and README.md
145
187
 
146
188
  # Run the test server
147
189
  agentr run
@@ -70,6 +70,24 @@ if __name__ == "__main__":
70
70
  server.run()
71
71
  ```
72
72
 
73
+ ## Using Playground
74
+
75
+ Start MCP Server
76
+ ```bash
77
+ universal_mcp run -t sse
78
+ ```
79
+
80
+ Start FastAPI app
81
+ ```bash
82
+ fastapi run src/playground
83
+ ```
84
+
85
+ Start Frontend
86
+ ```bash
87
+ streamlit run src/playground/streamlit.py
88
+ ```
89
+
90
+
73
91
  ## 🧩 Available Applications
74
92
  AgentR comes with several pre-built applications:
75
93
 
@@ -124,7 +142,11 @@ AgentR includes a command-line interface for common operations:
124
142
  agentr version
125
143
 
126
144
  # Generate API client from OpenAPI schema
127
- agentr generate --schema path/to/openapi.yaml
145
+
146
+ # Use the name of the API as the output filename (e.g., twitter, petstore, github)
147
+ universal_mcp generate --schema petstore.json --output outputfilename
148
+
149
+ # The tool will create src/universal_mcp/applications/petstore/ with app.py and README.md
128
150
 
129
151
  # Run the test server
130
152
  agentr run
@@ -0,0 +1,11 @@
1
+ {
2
+ "name": "Local Server",
3
+ "description": "Local server for testing",
4
+ "type": "local",
5
+ "transport": "sse",
6
+ "apps": [
7
+ {
8
+ "name": "markitdown"
9
+ }
10
+ ]
11
+ }
@@ -0,0 +1,149 @@
1
+ [project]
2
+ name = "universal-mcp"
3
+ version = "0.1.1rc1"
4
+ description = "Universal MCP acts as a middle ware for your API applications. It can store your credentials, authorize, enable disable apps on the fly and much more."
5
+ readme = "README.md"
6
+ authors = [
7
+ { name = "Manoj Bajaj", email = "manojbajaj95@gmail.com" }
8
+ ]
9
+ requires-python = ">=3.11"
10
+ dependencies = [
11
+ "pydantic>=2.11.1",
12
+ "pydantic-settings>=2.8.1",
13
+ "loguru>=0.7.3",
14
+ "mcp>=1.5.0",
15
+ "pyyaml>=6.0.2",
16
+ "typer>=0.15.2",
17
+ "markitdown[all]>=0.1.1",
18
+ "keyring>=25.6.0",
19
+ "litellm>=1.30.7",
20
+ ]
21
+
22
+ [project.optional-dependencies]
23
+ playground = [
24
+ "fastapi[standard]>=0.115.12",
25
+ "langchain-anthropic>=0.3.10",
26
+ "langchain-mcp-adapters>=0.0.3",
27
+ "langgraph>=0.3.24",
28
+ "langgraph-checkpoint-sqlite>=2.0.6",
29
+ "streamlit>=1.44.1",
30
+ "python-dotenv>=1.0.1",
31
+ ]
32
+ dev = [
33
+ "ruff>=0.11.4",
34
+ "pytest>=8.3.5",
35
+ "pytest-asyncio>=0.26.0",
36
+ "pyright>=1.1.398",
37
+ "litellm>=1.30.7",
38
+ ]
39
+ e2b = [
40
+ "e2b-code-interpreter>=1.2.0",
41
+ ]
42
+ firecrawl=[
43
+ "firecrawl-py>=1.15.0",
44
+ ]
45
+ serpapi = [
46
+ "google-search-results>=2.4.2",
47
+ ]
48
+ [project.scripts]
49
+ universal_mcp = "universal_mcp.cli:app"
50
+
51
+ [build-system]
52
+ requires = ["hatchling"]
53
+ build-backend = "hatchling.build"
54
+
55
+ [tool.ruff]
56
+ # Exclude a variety of commonly ignored directories.
57
+ exclude = [
58
+ ".bzr",
59
+ ".direnv",
60
+ ".eggs",
61
+ ".git",
62
+ ".git-rewrite",
63
+ ".hg",
64
+ ".ipynb_checkpoints",
65
+ ".mypy_cache",
66
+ ".nox",
67
+ ".pants.d",
68
+ ".pyenv",
69
+ ".pytest_cache",
70
+ ".pytype",
71
+ ".ruff_cache",
72
+ ".svn",
73
+ ".tox",
74
+ ".venv",
75
+ ".vscode",
76
+ "__pypackages__",
77
+ "_build",
78
+ "buck-out",
79
+ "build",
80
+ "dist",
81
+ "node_modules",
82
+ "site-packages",
83
+ "venv",
84
+ ]
85
+
86
+ # Same as Black.
87
+ line-length = 88
88
+ indent-width = 4
89
+
90
+ # Assume Python 3.12
91
+ target-version = "py312"
92
+
93
+ [tool.ruff.lint]
94
+ # Enable Pyflakes (`F`) and a subset of the pycodestyle (`E`) codes by default.
95
+ # Unlike Flake8, Ruff doesn't enable pycodestyle warnings (`W`) or
96
+ # McCabe complexity (`C901`) by default.
97
+ select = [
98
+ # pycodestyle
99
+ "E",
100
+ # Pyflakes
101
+ "F",
102
+ # pyupgrade
103
+ "UP",
104
+ # flake8-bugbear
105
+ "B",
106
+ # flake8-simplify
107
+ "SIM",
108
+ # isort
109
+ "I",
110
+ ]
111
+ ignore = ['E501', 'B008']
112
+
113
+ # Allow fix for all enabled rules (when `--fix`) is provided.
114
+ fixable = ["ALL"]
115
+ unfixable = []
116
+
117
+ # Allow unused variables when underscore-prefixed.
118
+ dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
119
+
120
+ [tool.ruff.format]
121
+ # Like Black, use double quotes for strings.
122
+ quote-style = "double"
123
+
124
+ # Like Black, indent with spaces, rather than tabs.
125
+ indent-style = "space"
126
+
127
+ # Like Black, respect magic trailing commas.
128
+ skip-magic-trailing-comma = false
129
+
130
+ # Like Black, automatically detect the appropriate line ending.
131
+ line-ending = "auto"
132
+
133
+ # Enable auto-formatting of code examples in docstrings. Markdown,
134
+ # reStructuredText code/literal blocks and doctests are all supported.
135
+ #
136
+ # This is currently disabled by default, but it is planned for this
137
+ # to be opt-out in the future.
138
+ docstring-code-format = false
139
+
140
+ # Set the line length limit used when formatting code snippets in
141
+ # docstrings.
142
+ #
143
+ # This only has an effect when the `docstring-code-format` setting is
144
+ # enabled.
145
+ docstring-code-line-length = "dynamic"
146
+
147
+ [tool.pytest.ini_options]
148
+ asyncio_mode = "strict"
149
+ asyncio_default_fixture_loop_scope = "function"
@@ -0,0 +1,65 @@
1
+ ## Running the Playground
2
+
3
+ ### Automated Startup (Recommended)
4
+
5
+ To easily start all necessary services (MCP Server, FastAPI Backend, Streamlit Frontend), you can use the provided Python startup script. This script will attempt to open each service in sequence and ensures they are terminated gracefully upon interruption.
6
+
7
+ **Prerequisites:**
8
+
9
+ * Python 3 installed and available in your PATH.
10
+ * All project dependencies installed (ensure you've run `pip install ...` for all requirements).
11
+ * **`local_config.json` file:** This configuration file for the MCP server must exist in the **project root directory**. It should contain a JSON array defining the MCP tools to load. For example:
12
+ ```json
13
+ {
14
+ "name": "Local Server",
15
+ "description": "Local server for testing",
16
+ "type": "local",
17
+ "transport": "sse",
18
+ "apps": [
19
+ {
20
+ "name": "zenquotes"
21
+ }
22
+ ]
23
+ }
24
+ ```
25
+ *(Adapt the content based on the actual MCP tools you intend to use.)*
26
+ * A compatible terminal environment for the script:
27
+ * On **macOS**, requires the standard `Terminal.app`.
28
+ * On **Linux**, assumes `gnome-terminal` is available (common on Ubuntu/Fedora). You may need to modify `src/playground/__main__.py` if you use a different terminal like `konsole` or `xfce4-terminal`.
29
+ * On **Windows**, requires the standard `cmd.exe`.
30
+
31
+ **Instructions:**
32
+
33
+ 1. Open your terminal application.
34
+ 2. Navigate (`cd`) to the **root directory** of this project (the directory containing the `src/` folder and `local_config.json`).
35
+ 3. Execute the startup script using Python:
36
+
37
+ ```bash
38
+ python src/playground
39
+ ```
40
+
41
+ *(Note: If your system uses `python3` to invoke Python 3, use that command instead: `python3 src/playground`)*
42
+
43
+ After running the command, you should see messages indicating that the components are being launched.
44
+
45
+ ### Manual Startup (Alternative)
46
+
47
+ If you prefer, or if the automated script does not work on your specific system configuration, you can still start each component manually. Make sure you run each command from the **project root directory** in a separate terminal window:
48
+
49
+ 1. **Terminal 1 (MCP Server):**
50
+ *(Ensure `local_config.json` exists in the project root as described above)*
51
+ ```bash
52
+ universal_mcp run -c local_config.json
53
+ ```
54
+ 2. **Terminal 2 (FastAPI App):**
55
+ ```bash
56
+ fastapi run src/playground
57
+ ```
58
+ 3. **Terminal 3 (Streamlit App):**
59
+ ```bash
60
+ streamlit run src/playground/streamlit.py
61
+ ```
62
+
63
+ ### Stopping the Services
64
+
65
+ To stop the running services, go to each of the terminal windows that were opened (either by the script or manually) and press `Ctrl + C`.
@@ -0,0 +1,3 @@
1
+ from playground.service import app
2
+
3
+ __all__ = ["app"]
@@ -0,0 +1,37 @@
1
+ import subprocess
2
+ import time
3
+
4
+ from loguru import logger
5
+
6
+
7
+ def main():
8
+ processes = []
9
+
10
+ # Start MCP server first
11
+ mcp_process = subprocess.Popen(["universal_mcp", "run", "-c", "local_config.json"])
12
+ processes.append(mcp_process)
13
+ time.sleep(3) # Give MCP server time to start
14
+ logger.info("MCP server started")
15
+
16
+ # Start FastAPI app second
17
+ fastapi_process = subprocess.Popen(["fastapi", "run", "src/playground"])
18
+ processes.append(fastapi_process)
19
+ time.sleep(3) # Give FastAPI time to start
20
+ logger.info("FastAPI app started")
21
+ # Start Streamlit app last
22
+ streamlit_process = subprocess.Popen(
23
+ ["streamlit", "run", "src/playground/streamlit.py"]
24
+ )
25
+ processes.append(streamlit_process)
26
+ logger.info("Streamlit app started")
27
+ try:
28
+ for p in processes:
29
+ p.wait()
30
+ except KeyboardInterrupt:
31
+ for p in processes:
32
+ p.terminate()
33
+ p.wait()
34
+
35
+
36
+ if __name__ == "__main__":
37
+ main()
@@ -0,0 +1,51 @@
1
+ import asyncio
2
+ from contextlib import asynccontextmanager
3
+
4
+ from langchain_anthropic import ChatAnthropic
5
+ from langchain_core.messages import HumanMessage
6
+ from langchain_mcp_adapters.client import MultiServerMCPClient
7
+ from langgraph.prebuilt import create_react_agent
8
+
9
+
10
+ @asynccontextmanager
11
+ async def load_tools():
12
+ async with MultiServerMCPClient(
13
+ {
14
+ "agentr": {
15
+ "url": "http://localhost:8005/sse",
16
+ "transport": "sse",
17
+ },
18
+ }
19
+ ) as client:
20
+ tools = client.get_tools()
21
+ yield tools
22
+
23
+
24
+ @asynccontextmanager
25
+ async def create_agent():
26
+ llm = ChatAnthropic(model="claude-3-5-sonnet-latest")
27
+ async with load_tools() as tools:
28
+ yield create_react_agent(
29
+ model=llm,
30
+ tools=tools,
31
+ debug=False,
32
+ )
33
+
34
+
35
+ async def main():
36
+ async with create_agent() as agent:
37
+ print("Welcome to the agent!")
38
+ messages = []
39
+ while True:
40
+ human_input = input("Enter your message: ")
41
+ if human_input.lower() in ["exit", "quit", "q"]:
42
+ break
43
+ messages.append(HumanMessage(content=human_input))
44
+ results = await agent.ainvoke({"messages": messages})
45
+ ai_message = results["messages"][-1]
46
+ messages.append(ai_message)
47
+ print(ai_message.content)
48
+
49
+
50
+ if __name__ == "__main__":
51
+ asyncio.run(main())