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.
- universal_mcp-0.1.1rc1/.github/workflows/publish-pypi.yml +48 -0
- universal_mcp-0.1.1rc1/.github/workflows/pull-request-checks.yml +8 -0
- universal_mcp-0.1.1rc1/.github/workflows/shared.yml +54 -0
- universal_mcp-0.1.1rc1/.gitignore +47 -0
- universal_mcp-0.1.1rc1/.pre-commit-config.yaml +24 -0
- universal_mcp-0.1.1rc1/CONTRIBUTING.md +78 -0
- {universal_mcp-0.1.0 → universal_mcp-0.1.1rc1}/PKG-INFO +47 -5
- {universal_mcp-0.1.0 → universal_mcp-0.1.1rc1}/README.md +23 -1
- universal_mcp-0.1.1rc1/local_config.json.example +11 -0
- universal_mcp-0.1.1rc1/pyproject.toml +149 -0
- universal_mcp-0.1.1rc1/src/playground/README.md +65 -0
- universal_mcp-0.1.1rc1/src/playground/__init__.py +3 -0
- universal_mcp-0.1.1rc1/src/playground/__main__.py +37 -0
- universal_mcp-0.1.1rc1/src/playground/agents/react.py +51 -0
- universal_mcp-0.1.1rc1/src/playground/client.py +288 -0
- universal_mcp-0.1.1rc1/src/playground/memory/__init__.py +14 -0
- universal_mcp-0.1.1rc1/src/playground/memory/sqlite.py +9 -0
- universal_mcp-0.1.1rc1/src/playground/schema.py +178 -0
- universal_mcp-0.1.1rc1/src/playground/service.py +234 -0
- universal_mcp-0.1.1rc1/src/playground/settings.py +24 -0
- universal_mcp-0.1.1rc1/src/playground/streamlit.py +438 -0
- universal_mcp-0.1.1rc1/src/playground/utils.py +76 -0
- universal_mcp-0.1.1rc1/src/tests/conftest.py +1 -0
- universal_mcp-0.1.1rc1/src/tests/test_api_generator.py +267 -0
- universal_mcp-0.1.1rc1/src/tests/test_applications.py +34 -0
- universal_mcp-0.1.1rc1/src/tests/test_localserver.py +30 -0
- universal_mcp-0.1.1rc1/src/tests/test_zenquotes.py +28 -0
- universal_mcp-0.1.1rc1/src/universal_mcp/applications/__init__.py +26 -0
- {universal_mcp-0.1.0 → universal_mcp-0.1.1rc1}/src/universal_mcp/applications/application.py +13 -8
- universal_mcp-0.1.1rc1/src/universal_mcp/applications/e2b/app.py +74 -0
- universal_mcp-0.1.1rc1/src/universal_mcp/applications/firecrawl/app.py +381 -0
- universal_mcp-0.1.1rc1/src/universal_mcp/applications/github/README.md +35 -0
- {universal_mcp-0.1.0 → universal_mcp-0.1.1rc1}/src/universal_mcp/applications/github/app.py +133 -100
- {universal_mcp-0.1.0 → universal_mcp-0.1.1rc1}/src/universal_mcp/applications/google_calendar/app.py +170 -139
- {universal_mcp-0.1.0 → universal_mcp-0.1.1rc1}/src/universal_mcp/applications/google_mail/app.py +185 -160
- universal_mcp-0.1.1rc1/src/universal_mcp/applications/markitdown/app.py +32 -0
- {universal_mcp-0.1.0 → universal_mcp-0.1.1rc1}/src/universal_mcp/applications/reddit/app.py +112 -71
- {universal_mcp-0.1.0 → universal_mcp-0.1.1rc1}/src/universal_mcp/applications/resend/app.py +3 -8
- universal_mcp-0.1.1rc1/src/universal_mcp/applications/serp/app.py +84 -0
- {universal_mcp-0.1.0 → universal_mcp-0.1.1rc1}/src/universal_mcp/applications/tavily/app.py +11 -10
- {universal_mcp-0.1.0 → universal_mcp-0.1.1rc1}/src/universal_mcp/applications/zenquotes/app.py +3 -3
- universal_mcp-0.1.1rc1/src/universal_mcp/cli.py +165 -0
- universal_mcp-0.1.1rc1/src/universal_mcp/config.py +32 -0
- {universal_mcp-0.1.0 → universal_mcp-0.1.1rc1}/src/universal_mcp/exceptions.py +1 -3
- universal_mcp-0.1.1rc1/src/universal_mcp/integrations/__init__.py +8 -0
- {universal_mcp-0.1.0 → universal_mcp-0.1.1rc1}/src/universal_mcp/integrations/agentr.py +26 -24
- {universal_mcp-0.1.0 → universal_mcp-0.1.1rc1}/src/universal_mcp/integrations/integration.py +72 -35
- universal_mcp-0.1.1rc1/src/universal_mcp/servers/__init__.py +23 -0
- {universal_mcp-0.1.0 → universal_mcp-0.1.1rc1}/src/universal_mcp/servers/server.py +77 -45
- universal_mcp-0.1.1rc1/src/universal_mcp/stores/__init__.py +16 -0
- universal_mcp-0.1.1rc1/src/universal_mcp/stores/store.py +181 -0
- universal_mcp-0.1.1rc1/src/universal_mcp/utils/__init__.py +1 -0
- universal_mcp-0.1.1rc1/src/universal_mcp/utils/api_generator.py +269 -0
- universal_mcp-0.1.1rc1/src/universal_mcp/utils/docgen.py +360 -0
- universal_mcp-0.1.1rc1/src/universal_mcp/utils/installation.py +104 -0
- universal_mcp-0.1.1rc1/src/universal_mcp/utils/openapi.py +372 -0
- universal_mcp-0.1.1rc1/uv.lock +3299 -0
- universal_mcp-0.1.0/.gitignore +0 -17
- universal_mcp-0.1.0/pyproject.toml +0 -31
- universal_mcp-0.1.0/src/universal_mcp/applications/__init__.py +0 -31
- universal_mcp-0.1.0/src/universal_mcp/cli.py +0 -111
- universal_mcp-0.1.0/src/universal_mcp/config.py +0 -15
- universal_mcp-0.1.0/src/universal_mcp/integrations/__init__.py +0 -4
- universal_mcp-0.1.0/src/universal_mcp/servers/__init__.py +0 -3
- universal_mcp-0.1.0/src/universal_mcp/stores/__init__.py +0 -3
- universal_mcp-0.1.0/src/universal_mcp/stores/store.py +0 -71
- universal_mcp-0.1.0/src/universal_mcp/utils/openapi.py +0 -274
- universal_mcp-0.1.0/uv.lock +0 -510
- {universal_mcp-0.1.0 → universal_mcp-0.1.1rc1}/.python-version +0 -0
- /universal_mcp-0.1.0/src/universal_mcp/applications/agentr.py → /universal_mcp-0.1.1rc1/src/tests/__init__.py +0 -0
- {universal_mcp-0.1.0 → universal_mcp-0.1.1rc1}/src/universal_mcp/__init__.py +0 -0
- {universal_mcp-0.1.0 → universal_mcp-0.1.1rc1}/src/universal_mcp/integrations/README.md +0 -0
- {universal_mcp-0.1.0 → universal_mcp-0.1.1rc1}/src/universal_mcp/py.typed +0 -0
- {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,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.
|
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:
|
14
|
-
Requires-Dist:
|
15
|
-
Requires-Dist:
|
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
|
-
|
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
|
-
|
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,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,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())
|