codens-mcp 0.1.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.
- codens_mcp-0.1.0/.gitignore +93 -0
- codens_mcp-0.1.0/CHANGELOG.md +34 -0
- codens_mcp-0.1.0/LICENSE +21 -0
- codens_mcp-0.1.0/PKG-INFO +141 -0
- codens_mcp-0.1.0/README.md +108 -0
- codens_mcp-0.1.0/pyproject.toml +63 -0
- codens_mcp-0.1.0/src/codens_mcp/__init__.py +2 -0
- codens_mcp-0.1.0/src/codens_mcp/__main__.py +3 -0
- codens_mcp-0.1.0/src/codens_mcp/client/__init__.py +15 -0
- codens_mcp-0.1.0/src/codens_mcp/client/auth.py +23 -0
- codens_mcp-0.1.0/src/codens_mcp/client/auth_helper.py +33 -0
- codens_mcp-0.1.0/src/codens_mcp/client/blue.py +32 -0
- codens_mcp-0.1.0/src/codens_mcp/client/green.py +32 -0
- codens_mcp-0.1.0/src/codens_mcp/client/red.py +32 -0
- codens_mcp-0.1.0/src/codens_mcp/server.py +30 -0
- codens_mcp-0.1.0/src/codens_mcp/tools/__init__.py +0 -0
- codens_mcp-0.1.0/src/codens_mcp/tools/auth_tools.py +47 -0
- codens_mcp-0.1.0/src/codens_mcp/tools/blue_tools.py +94 -0
- codens_mcp-0.1.0/src/codens_mcp/tools/green_tools.py +115 -0
- codens_mcp-0.1.0/src/codens_mcp/tools/purple_tools.py +28 -0
- codens_mcp-0.1.0/src/codens_mcp/tools/red_tools.py +110 -0
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
.Python
|
|
7
|
+
build/
|
|
8
|
+
develop-eggs/
|
|
9
|
+
dist/
|
|
10
|
+
downloads/
|
|
11
|
+
eggs/
|
|
12
|
+
.eggs/
|
|
13
|
+
/lib/
|
|
14
|
+
lib64/
|
|
15
|
+
parts/
|
|
16
|
+
sdist/
|
|
17
|
+
var/
|
|
18
|
+
wheels/
|
|
19
|
+
*.egg-info/
|
|
20
|
+
.installed.cfg
|
|
21
|
+
*.egg
|
|
22
|
+
MANIFEST
|
|
23
|
+
|
|
24
|
+
# Virtual environments
|
|
25
|
+
venv/
|
|
26
|
+
env/
|
|
27
|
+
ENV/
|
|
28
|
+
.venv
|
|
29
|
+
|
|
30
|
+
# IDEs
|
|
31
|
+
.vscode/
|
|
32
|
+
.idea/
|
|
33
|
+
*.swp
|
|
34
|
+
*.swo
|
|
35
|
+
*~
|
|
36
|
+
|
|
37
|
+
# OS
|
|
38
|
+
.DS_Store
|
|
39
|
+
Thumbs.db
|
|
40
|
+
|
|
41
|
+
# Testing
|
|
42
|
+
.pytest_cache/
|
|
43
|
+
.coverage
|
|
44
|
+
htmlcov/
|
|
45
|
+
.tox/
|
|
46
|
+
.hypothesis/
|
|
47
|
+
|
|
48
|
+
# Environment variables
|
|
49
|
+
.env
|
|
50
|
+
.env.local
|
|
51
|
+
.env.*.local
|
|
52
|
+
|
|
53
|
+
# Logs
|
|
54
|
+
*.log
|
|
55
|
+
logs/
|
|
56
|
+
|
|
57
|
+
# Database
|
|
58
|
+
*.db
|
|
59
|
+
*.sqlite
|
|
60
|
+
*.sqlite3
|
|
61
|
+
|
|
62
|
+
# Node.js
|
|
63
|
+
node_modules/
|
|
64
|
+
npm-debug.log*
|
|
65
|
+
yarn-debug.log*
|
|
66
|
+
yarn-error.log*
|
|
67
|
+
.pnpm-debug.log*
|
|
68
|
+
|
|
69
|
+
# Next.js
|
|
70
|
+
.next/
|
|
71
|
+
out/
|
|
72
|
+
|
|
73
|
+
# Production
|
|
74
|
+
/build
|
|
75
|
+
/dist
|
|
76
|
+
|
|
77
|
+
# Temporary files
|
|
78
|
+
*.tmp
|
|
79
|
+
*.temp
|
|
80
|
+
.cache/
|
|
81
|
+
|
|
82
|
+
# Terraform
|
|
83
|
+
*.tfstate
|
|
84
|
+
*.tfstate.*
|
|
85
|
+
.terraform/
|
|
86
|
+
.terraform.lock.hcl
|
|
87
|
+
tfplan
|
|
88
|
+
|
|
89
|
+
# AWS
|
|
90
|
+
.aws-sam/
|
|
91
|
+
|
|
92
|
+
# serena memories (keep but optional)
|
|
93
|
+
# .serena/
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `codens-mcp` are documented here.
|
|
4
|
+
|
|
5
|
+
## [0.1.0] - 2026-05-06
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Initial release of `codens-mcp` — the unified MCP server for the Codens family.
|
|
10
|
+
- **Purple tools (16)**: All tools re-exported from `purple-codens-mcp>=0.2.0`.
|
|
11
|
+
- Auth: `purple_login`, `purple_whoami`
|
|
12
|
+
- Project: `purple_analyze_repo`, `purple_list_projects`, `purple_init_project`
|
|
13
|
+
- Repository: `purple_add_repository`, `purple_list_repositories`
|
|
14
|
+
- Instructions: `purple_import_instructions`, `purple_list_instructions`, `purple_sync_instructions`
|
|
15
|
+
- Workflow: `purple_create_workflow`, `purple_get_run_status`, `purple_list_runs`, `purple_cancel_run`, `purple_inject_message`
|
|
16
|
+
- SSE: `purple_subscribe_run_events`
|
|
17
|
+
- **Red tools (4)**: Red Codens bug-report and auto-fix integration.
|
|
18
|
+
- `red_create_bug_report` — POST `/api/v1/agent/create-bug-report`
|
|
19
|
+
- `red_get_bug_report` — GET `/api/v1/organizations/{org}/bug-reports/{id}`
|
|
20
|
+
- `red_analyze_bug_report` — POST `/api/v1/organizations/{org}/bug-reports/{id}/analyze`
|
|
21
|
+
- `red_submit_bug_fix_plan_to_purple` — POST `/api/v1/organizations/{org}/bug-fix-plans/{id}/submit`
|
|
22
|
+
- **Blue tools (4)**: Blue Codens QA/E2E automation.
|
|
23
|
+
- `blue_list_e2e_tests`
|
|
24
|
+
- `blue_generate_e2e_test`
|
|
25
|
+
- `blue_run_e2e_test`
|
|
26
|
+
- `blue_get_e2e_test_results`
|
|
27
|
+
- **Green tools (4)**: Green Codens PRD consultation and kickoff.
|
|
28
|
+
- `green_create_consultation_with_message`
|
|
29
|
+
- `green_send_consultation_message`
|
|
30
|
+
- `green_convert_consultation_to_prd`
|
|
31
|
+
- `green_create_kickoff`
|
|
32
|
+
- **Auth tools (2)**: Auth Codens agent signup and public pricing.
|
|
33
|
+
- `auth_agent_signup`
|
|
34
|
+
- `auth_get_pricing`
|
codens_mcp-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright 2026 Corevice Inc.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: codens-mcp
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Unified MCP server for Codens family — Red (auto-fix), Blue (QA), Green (PRD), Auth, plus all Purple tools via purple-codens-mcp.
|
|
5
|
+
Project-URL: Homepage, https://github.com/Corevice/purple-codens/tree/main/codens-mcp
|
|
6
|
+
Project-URL: Repository, https://github.com/Corevice/purple-codens
|
|
7
|
+
Project-URL: Issues, https://github.com/Corevice/purple-codens/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/Corevice/purple-codens/blob/main/codens-mcp/CHANGELOG.md
|
|
9
|
+
Author-email: Corevice <engineering@corevice.com>
|
|
10
|
+
License: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: agent,auto-fix,automation,claude,codens,mcp,prd,qa,workflow
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
21
|
+
Requires-Python: >=3.11
|
|
22
|
+
Requires-Dist: anyio>=4.0.0
|
|
23
|
+
Requires-Dist: httpx>=0.27.0
|
|
24
|
+
Requires-Dist: mcp>=1.0.0
|
|
25
|
+
Requires-Dist: purple-codens-mcp>=0.2.0
|
|
26
|
+
Requires-Dist: pydantic>=2.0.0
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: build>=1.0.0; extra == 'dev'
|
|
29
|
+
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
|
|
30
|
+
Requires-Dist: pytest-cov>=4.1.0; extra == 'dev'
|
|
31
|
+
Requires-Dist: pytest>=8.0.0; extra == 'dev'
|
|
32
|
+
Description-Content-Type: text/markdown
|
|
33
|
+
|
|
34
|
+
# codens-mcp
|
|
35
|
+
|
|
36
|
+
[](https://pypi.org/project/codens-mcp/)
|
|
37
|
+
[](https://pypi.org/project/codens-mcp/)
|
|
38
|
+
[](LICENSE)
|
|
39
|
+
|
|
40
|
+
Unified MCP server for the **Codens family** — lets Claude Code and other AI agents operate all Codens services through a single package.
|
|
41
|
+
|
|
42
|
+
Includes all 16 **Purple** tools (re-exported from `purple-codens-mcp`) plus new tools for **Red** (auto-fix), **Blue** (QA), **Green** (PRD), and **Auth Codens**.
|
|
43
|
+
|
|
44
|
+
## Installation
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
pip install codens-mcp
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Quick Start (Claude Code)
|
|
51
|
+
|
|
52
|
+
Add to your `.claude/settings.json`:
|
|
53
|
+
|
|
54
|
+
```json
|
|
55
|
+
{
|
|
56
|
+
"mcpServers": {
|
|
57
|
+
"codens": {
|
|
58
|
+
"command": "codens-mcp",
|
|
59
|
+
"args": []
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Then log in once via `purple_login` — the JWT issued by Auth Codens is accepted by all family backends.
|
|
66
|
+
|
|
67
|
+
## Available Tools (30 total)
|
|
68
|
+
|
|
69
|
+
### Auth / Session (Purple)
|
|
70
|
+
| Tool | Description |
|
|
71
|
+
|------|-------------|
|
|
72
|
+
| `purple_login` | Log in via browser OAuth, device code, or email+password |
|
|
73
|
+
| `purple_whoami` | Show current authenticated user and organization |
|
|
74
|
+
|
|
75
|
+
### Project Setup (Purple)
|
|
76
|
+
| Tool | Description |
|
|
77
|
+
|------|-------------|
|
|
78
|
+
| `purple_analyze_repo` | Scan local repo and return structured analysis |
|
|
79
|
+
| `purple_list_projects` | List all projects in the organization |
|
|
80
|
+
| `purple_init_project` | Full project setup: create → link repo → import instructions |
|
|
81
|
+
|
|
82
|
+
### Repository (Purple)
|
|
83
|
+
| Tool | Description |
|
|
84
|
+
|------|-------------|
|
|
85
|
+
| `purple_add_repository` | Link a GitHub repository to a project |
|
|
86
|
+
| `purple_list_repositories` | List repositories linked to a project |
|
|
87
|
+
|
|
88
|
+
### Instruction Files (Purple)
|
|
89
|
+
| Tool | Description |
|
|
90
|
+
|------|-------------|
|
|
91
|
+
| `purple_import_instructions` | Import CLAUDE.md + .claude/rules/ from GitHub |
|
|
92
|
+
| `purple_list_instructions` | List instruction files for a project |
|
|
93
|
+
| `purple_sync_instructions` | Diff local vs remote, update changed files |
|
|
94
|
+
|
|
95
|
+
### Workflow & Runs (Purple)
|
|
96
|
+
| Tool | Description |
|
|
97
|
+
|------|-------------|
|
|
98
|
+
| `purple_create_workflow` | Create a new workflow |
|
|
99
|
+
| `purple_get_run_status` | Get current status of a workflow run |
|
|
100
|
+
| `purple_list_runs` | List workflow runs (filter by project/status) |
|
|
101
|
+
| `purple_cancel_run` | Cancel a running workflow |
|
|
102
|
+
| `purple_inject_message` | Inject a message into a heartbeat run |
|
|
103
|
+
| `purple_subscribe_run_events` | Stream SSE events for a workflow run |
|
|
104
|
+
|
|
105
|
+
### Red Codens — Auto-Fix
|
|
106
|
+
| Tool | Description |
|
|
107
|
+
|------|-------------|
|
|
108
|
+
| `red_create_bug_report` | Create a bug report (agent endpoint) |
|
|
109
|
+
| `red_get_bug_report` | Get a bug report by ID |
|
|
110
|
+
| `red_analyze_bug_report` | Trigger AI analysis for a bug report |
|
|
111
|
+
| `red_submit_bug_fix_plan_to_purple` | Submit a fix plan to Purple for execution |
|
|
112
|
+
|
|
113
|
+
### Blue Codens — QA Automation
|
|
114
|
+
| Tool | Description |
|
|
115
|
+
|------|-------------|
|
|
116
|
+
| `blue_list_e2e_tests` | List E2E tests |
|
|
117
|
+
| `blue_generate_e2e_test` | Generate an E2E test from a natural-language requirement |
|
|
118
|
+
| `blue_run_e2e_test` | Trigger a run for an existing E2E test |
|
|
119
|
+
| `blue_get_e2e_test_results` | Get results for an E2E test (latest run) |
|
|
120
|
+
|
|
121
|
+
### Green Codens — PRD Management
|
|
122
|
+
| Tool | Description |
|
|
123
|
+
|------|-------------|
|
|
124
|
+
| `green_create_consultation_with_message` | Start a consultation and send the first message |
|
|
125
|
+
| `green_send_consultation_message` | Send a message in an existing consultation |
|
|
126
|
+
| `green_convert_consultation_to_prd` | Convert a consultation into a PRD |
|
|
127
|
+
| `green_create_kickoff` | Create a Kickoff in Green Codens |
|
|
128
|
+
|
|
129
|
+
### Auth Codens
|
|
130
|
+
| Tool | Description |
|
|
131
|
+
|------|-------------|
|
|
132
|
+
| `auth_agent_signup` | Issue capability_token via existing user's API key |
|
|
133
|
+
| `auth_get_pricing` | Public pricing.json (no auth required) |
|
|
134
|
+
|
|
135
|
+
## Changelog
|
|
136
|
+
|
|
137
|
+
See [CHANGELOG.md](CHANGELOG.md).
|
|
138
|
+
|
|
139
|
+
## License
|
|
140
|
+
|
|
141
|
+
MIT — Copyright 2026 Corevice Inc.
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# codens-mcp
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/codens-mcp/)
|
|
4
|
+
[](https://pypi.org/project/codens-mcp/)
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
|
|
7
|
+
Unified MCP server for the **Codens family** — lets Claude Code and other AI agents operate all Codens services through a single package.
|
|
8
|
+
|
|
9
|
+
Includes all 16 **Purple** tools (re-exported from `purple-codens-mcp`) plus new tools for **Red** (auto-fix), **Blue** (QA), **Green** (PRD), and **Auth Codens**.
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pip install codens-mcp
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Quick Start (Claude Code)
|
|
18
|
+
|
|
19
|
+
Add to your `.claude/settings.json`:
|
|
20
|
+
|
|
21
|
+
```json
|
|
22
|
+
{
|
|
23
|
+
"mcpServers": {
|
|
24
|
+
"codens": {
|
|
25
|
+
"command": "codens-mcp",
|
|
26
|
+
"args": []
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Then log in once via `purple_login` — the JWT issued by Auth Codens is accepted by all family backends.
|
|
33
|
+
|
|
34
|
+
## Available Tools (30 total)
|
|
35
|
+
|
|
36
|
+
### Auth / Session (Purple)
|
|
37
|
+
| Tool | Description |
|
|
38
|
+
|------|-------------|
|
|
39
|
+
| `purple_login` | Log in via browser OAuth, device code, or email+password |
|
|
40
|
+
| `purple_whoami` | Show current authenticated user and organization |
|
|
41
|
+
|
|
42
|
+
### Project Setup (Purple)
|
|
43
|
+
| Tool | Description |
|
|
44
|
+
|------|-------------|
|
|
45
|
+
| `purple_analyze_repo` | Scan local repo and return structured analysis |
|
|
46
|
+
| `purple_list_projects` | List all projects in the organization |
|
|
47
|
+
| `purple_init_project` | Full project setup: create → link repo → import instructions |
|
|
48
|
+
|
|
49
|
+
### Repository (Purple)
|
|
50
|
+
| Tool | Description |
|
|
51
|
+
|------|-------------|
|
|
52
|
+
| `purple_add_repository` | Link a GitHub repository to a project |
|
|
53
|
+
| `purple_list_repositories` | List repositories linked to a project |
|
|
54
|
+
|
|
55
|
+
### Instruction Files (Purple)
|
|
56
|
+
| Tool | Description |
|
|
57
|
+
|------|-------------|
|
|
58
|
+
| `purple_import_instructions` | Import CLAUDE.md + .claude/rules/ from GitHub |
|
|
59
|
+
| `purple_list_instructions` | List instruction files for a project |
|
|
60
|
+
| `purple_sync_instructions` | Diff local vs remote, update changed files |
|
|
61
|
+
|
|
62
|
+
### Workflow & Runs (Purple)
|
|
63
|
+
| Tool | Description |
|
|
64
|
+
|------|-------------|
|
|
65
|
+
| `purple_create_workflow` | Create a new workflow |
|
|
66
|
+
| `purple_get_run_status` | Get current status of a workflow run |
|
|
67
|
+
| `purple_list_runs` | List workflow runs (filter by project/status) |
|
|
68
|
+
| `purple_cancel_run` | Cancel a running workflow |
|
|
69
|
+
| `purple_inject_message` | Inject a message into a heartbeat run |
|
|
70
|
+
| `purple_subscribe_run_events` | Stream SSE events for a workflow run |
|
|
71
|
+
|
|
72
|
+
### Red Codens — Auto-Fix
|
|
73
|
+
| Tool | Description |
|
|
74
|
+
|------|-------------|
|
|
75
|
+
| `red_create_bug_report` | Create a bug report (agent endpoint) |
|
|
76
|
+
| `red_get_bug_report` | Get a bug report by ID |
|
|
77
|
+
| `red_analyze_bug_report` | Trigger AI analysis for a bug report |
|
|
78
|
+
| `red_submit_bug_fix_plan_to_purple` | Submit a fix plan to Purple for execution |
|
|
79
|
+
|
|
80
|
+
### Blue Codens — QA Automation
|
|
81
|
+
| Tool | Description |
|
|
82
|
+
|------|-------------|
|
|
83
|
+
| `blue_list_e2e_tests` | List E2E tests |
|
|
84
|
+
| `blue_generate_e2e_test` | Generate an E2E test from a natural-language requirement |
|
|
85
|
+
| `blue_run_e2e_test` | Trigger a run for an existing E2E test |
|
|
86
|
+
| `blue_get_e2e_test_results` | Get results for an E2E test (latest run) |
|
|
87
|
+
|
|
88
|
+
### Green Codens — PRD Management
|
|
89
|
+
| Tool | Description |
|
|
90
|
+
|------|-------------|
|
|
91
|
+
| `green_create_consultation_with_message` | Start a consultation and send the first message |
|
|
92
|
+
| `green_send_consultation_message` | Send a message in an existing consultation |
|
|
93
|
+
| `green_convert_consultation_to_prd` | Convert a consultation into a PRD |
|
|
94
|
+
| `green_create_kickoff` | Create a Kickoff in Green Codens |
|
|
95
|
+
|
|
96
|
+
### Auth Codens
|
|
97
|
+
| Tool | Description |
|
|
98
|
+
|------|-------------|
|
|
99
|
+
| `auth_agent_signup` | Issue capability_token via existing user's API key |
|
|
100
|
+
| `auth_get_pricing` | Public pricing.json (no auth required) |
|
|
101
|
+
|
|
102
|
+
## Changelog
|
|
103
|
+
|
|
104
|
+
See [CHANGELOG.md](CHANGELOG.md).
|
|
105
|
+
|
|
106
|
+
## License
|
|
107
|
+
|
|
108
|
+
MIT — Copyright 2026 Corevice Inc.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "codens-mcp"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Unified MCP server for Codens family — Red (auto-fix), Blue (QA), Green (PRD), Auth, plus all Purple tools via purple-codens-mcp."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.11"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
authors = [{ name = "Corevice", email = "engineering@corevice.com" }]
|
|
13
|
+
keywords = ["mcp", "claude", "agent", "codens", "workflow", "automation", "qa", "prd", "auto-fix"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 4 - Beta",
|
|
16
|
+
"Intended Audience :: Developers",
|
|
17
|
+
"License :: OSI Approved :: MIT License",
|
|
18
|
+
"Programming Language :: Python :: 3",
|
|
19
|
+
"Programming Language :: Python :: 3.11",
|
|
20
|
+
"Programming Language :: Python :: 3.12",
|
|
21
|
+
"Programming Language :: Python :: 3.13",
|
|
22
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
23
|
+
]
|
|
24
|
+
dependencies = [
|
|
25
|
+
"mcp>=1.0.0",
|
|
26
|
+
"httpx>=0.27.0",
|
|
27
|
+
"pydantic>=2.0.0",
|
|
28
|
+
"anyio>=4.0.0",
|
|
29
|
+
"purple-codens-mcp>=0.2.0",
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
[project.urls]
|
|
33
|
+
Homepage = "https://github.com/Corevice/purple-codens/tree/main/codens-mcp"
|
|
34
|
+
Repository = "https://github.com/Corevice/purple-codens"
|
|
35
|
+
Issues = "https://github.com/Corevice/purple-codens/issues"
|
|
36
|
+
Changelog = "https://github.com/Corevice/purple-codens/blob/main/codens-mcp/CHANGELOG.md"
|
|
37
|
+
|
|
38
|
+
[project.scripts]
|
|
39
|
+
codens-mcp = "codens_mcp.server:main"
|
|
40
|
+
|
|
41
|
+
[project.optional-dependencies]
|
|
42
|
+
dev = [
|
|
43
|
+
"pytest>=8.0.0",
|
|
44
|
+
"pytest-asyncio>=0.23.0",
|
|
45
|
+
"pytest-cov>=4.1.0",
|
|
46
|
+
"build>=1.0.0",
|
|
47
|
+
]
|
|
48
|
+
|
|
49
|
+
[tool.hatch.build.targets.sdist]
|
|
50
|
+
include = ["src/codens_mcp", "README.md", "CHANGELOG.md", "LICENSE"]
|
|
51
|
+
|
|
52
|
+
[tool.hatch.build.targets.wheel]
|
|
53
|
+
packages = ["src/codens_mcp"]
|
|
54
|
+
|
|
55
|
+
[tool.pytest.ini_options]
|
|
56
|
+
asyncio_mode = "auto"
|
|
57
|
+
|
|
58
|
+
[tool.ruff]
|
|
59
|
+
line-length = 100
|
|
60
|
+
|
|
61
|
+
[tool.mypy]
|
|
62
|
+
python_version = "3.11"
|
|
63
|
+
strict = false
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from .auth_helper import AuthenticationError, Credentials, load_codens_credentials
|
|
2
|
+
from .red import RedClient
|
|
3
|
+
from .blue import BlueClient
|
|
4
|
+
from .green import GreenClient
|
|
5
|
+
from .auth import AuthClient
|
|
6
|
+
|
|
7
|
+
__all__ = [
|
|
8
|
+
"AuthenticationError",
|
|
9
|
+
"Credentials",
|
|
10
|
+
"load_codens_credentials",
|
|
11
|
+
"RedClient",
|
|
12
|
+
"BlueClient",
|
|
13
|
+
"GreenClient",
|
|
14
|
+
"AuthClient",
|
|
15
|
+
]
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""HTTP client for Auth Codens (agent-signup and public endpoints)."""
|
|
2
|
+
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
import httpx
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class AuthClient:
|
|
9
|
+
def __init__(self, api_url: str, token: Optional[str] = None) -> None:
|
|
10
|
+
self.api_url = api_url.rstrip("/")
|
|
11
|
+
self.token = token
|
|
12
|
+
|
|
13
|
+
def get_no_auth(self, path: str) -> dict:
|
|
14
|
+
with httpx.Client(timeout=10.0) as c:
|
|
15
|
+
r = c.get(f"{self.api_url}{path}")
|
|
16
|
+
r.raise_for_status()
|
|
17
|
+
return r.json()
|
|
18
|
+
|
|
19
|
+
def post(self, path: str, json: dict) -> dict:
|
|
20
|
+
with httpx.Client(timeout=10.0) as c:
|
|
21
|
+
r = c.post(f"{self.api_url}{path}", json=json)
|
|
22
|
+
r.raise_for_status()
|
|
23
|
+
return r.json()
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""Shared credential helper for Codens family clients.
|
|
2
|
+
|
|
3
|
+
Reuses the credential store written by purple_login (~/.purple-codens/credentials.json).
|
|
4
|
+
Auth Codens is the single OIDC issuer for the family, so the same JWT is accepted
|
|
5
|
+
by Red, Blue, and Green backends.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from dataclasses import dataclass
|
|
9
|
+
|
|
10
|
+
from purple_codens_mcp.auth import get_credentials
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class AuthenticationError(Exception):
|
|
14
|
+
"""Raised when credentials are missing or invalid."""
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass
|
|
18
|
+
class Credentials:
|
|
19
|
+
token: str
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def load_codens_credentials(api_url: str, service: str) -> Credentials:
|
|
23
|
+
"""Load JWT from the purple-codens-mcp credential store.
|
|
24
|
+
|
|
25
|
+
For v0.1.0 all Codens backends share the JWT issued by Auth Codens via
|
|
26
|
+
purple_login. Future versions may use per-service capability_tokens.
|
|
27
|
+
"""
|
|
28
|
+
creds = get_credentials(api_url)
|
|
29
|
+
if creds is None:
|
|
30
|
+
raise AuthenticationError(
|
|
31
|
+
f"Not logged in for {api_url}. Run purple_login first."
|
|
32
|
+
)
|
|
33
|
+
return Credentials(token=creds["token"])
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""HTTP client for Blue Codens (QA automation service)."""
|
|
2
|
+
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
import httpx
|
|
6
|
+
|
|
7
|
+
from .auth_helper import AuthenticationError
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class BlueClient:
|
|
11
|
+
def __init__(self, api_url: str, token: str) -> None:
|
|
12
|
+
self.api_url = api_url.rstrip("/")
|
|
13
|
+
self.token = token
|
|
14
|
+
|
|
15
|
+
def _headers(self) -> dict:
|
|
16
|
+
return {"Authorization": f"Bearer {self.token}", "Content-Type": "application/json"}
|
|
17
|
+
|
|
18
|
+
def get(self, path: str, params: Optional[dict] = None) -> dict:
|
|
19
|
+
with httpx.Client(timeout=30.0) as c:
|
|
20
|
+
r = c.get(f"{self.api_url}{path}", headers=self._headers(), params=params)
|
|
21
|
+
if r.status_code == 401:
|
|
22
|
+
raise AuthenticationError("401 from Blue Codens — token may be expired")
|
|
23
|
+
r.raise_for_status()
|
|
24
|
+
return r.json()
|
|
25
|
+
|
|
26
|
+
def post(self, path: str, json: Optional[dict] = None) -> dict:
|
|
27
|
+
with httpx.Client(timeout=30.0) as c:
|
|
28
|
+
r = c.post(f"{self.api_url}{path}", headers=self._headers(), json=json or {})
|
|
29
|
+
if r.status_code == 401:
|
|
30
|
+
raise AuthenticationError("401 from Blue Codens — token may be expired")
|
|
31
|
+
r.raise_for_status()
|
|
32
|
+
return r.json()
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""HTTP client for Green Codens (PRD management service)."""
|
|
2
|
+
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
import httpx
|
|
6
|
+
|
|
7
|
+
from .auth_helper import AuthenticationError
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class GreenClient:
|
|
11
|
+
def __init__(self, api_url: str, token: str) -> None:
|
|
12
|
+
self.api_url = api_url.rstrip("/")
|
|
13
|
+
self.token = token
|
|
14
|
+
|
|
15
|
+
def _headers(self) -> dict:
|
|
16
|
+
return {"Authorization": f"Bearer {self.token}", "Content-Type": "application/json"}
|
|
17
|
+
|
|
18
|
+
def get(self, path: str, params: Optional[dict] = None) -> dict:
|
|
19
|
+
with httpx.Client(timeout=30.0) as c:
|
|
20
|
+
r = c.get(f"{self.api_url}{path}", headers=self._headers(), params=params)
|
|
21
|
+
if r.status_code == 401:
|
|
22
|
+
raise AuthenticationError("401 from Green Codens — token may be expired")
|
|
23
|
+
r.raise_for_status()
|
|
24
|
+
return r.json()
|
|
25
|
+
|
|
26
|
+
def post(self, path: str, json: Optional[dict] = None) -> dict:
|
|
27
|
+
with httpx.Client(timeout=30.0) as c:
|
|
28
|
+
r = c.post(f"{self.api_url}{path}", headers=self._headers(), json=json or {})
|
|
29
|
+
if r.status_code == 401:
|
|
30
|
+
raise AuthenticationError("401 from Green Codens — token may be expired")
|
|
31
|
+
r.raise_for_status()
|
|
32
|
+
return r.json()
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""HTTP client for Red Codens (auto-fix service)."""
|
|
2
|
+
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
import httpx
|
|
6
|
+
|
|
7
|
+
from .auth_helper import AuthenticationError
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class RedClient:
|
|
11
|
+
def __init__(self, api_url: str, token: str) -> None:
|
|
12
|
+
self.api_url = api_url.rstrip("/")
|
|
13
|
+
self.token = token
|
|
14
|
+
|
|
15
|
+
def _headers(self) -> dict:
|
|
16
|
+
return {"Authorization": f"Bearer {self.token}", "Content-Type": "application/json"}
|
|
17
|
+
|
|
18
|
+
def get(self, path: str, params: Optional[dict] = None) -> dict:
|
|
19
|
+
with httpx.Client(timeout=30.0) as c:
|
|
20
|
+
r = c.get(f"{self.api_url}{path}", headers=self._headers(), params=params)
|
|
21
|
+
if r.status_code == 401:
|
|
22
|
+
raise AuthenticationError("401 from Red Codens — token may be expired")
|
|
23
|
+
r.raise_for_status()
|
|
24
|
+
return r.json()
|
|
25
|
+
|
|
26
|
+
def post(self, path: str, json: Optional[dict] = None) -> dict:
|
|
27
|
+
with httpx.Client(timeout=30.0) as c:
|
|
28
|
+
r = c.post(f"{self.api_url}{path}", headers=self._headers(), json=json or {})
|
|
29
|
+
if r.status_code == 401:
|
|
30
|
+
raise AuthenticationError("401 from Red Codens — token may be expired")
|
|
31
|
+
r.raise_for_status()
|
|
32
|
+
return r.json()
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"""Unified MCP server entry point for the Codens family."""
|
|
2
|
+
|
|
3
|
+
from mcp.server.fastmcp import FastMCP
|
|
4
|
+
|
|
5
|
+
from .tools.auth_tools import register_auth_tools
|
|
6
|
+
from .tools.blue_tools import register_blue_tools
|
|
7
|
+
from .tools.green_tools import register_green_tools
|
|
8
|
+
from .tools.purple_tools import register_purple_tools
|
|
9
|
+
from .tools.red_tools import register_red_tools
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def main() -> None:
|
|
13
|
+
mcp = FastMCP(
|
|
14
|
+
"codens",
|
|
15
|
+
instructions=(
|
|
16
|
+
"Codens unified MCP server. "
|
|
17
|
+
"Use purple_login first, then use Red/Blue/Green/Auth tools as needed. "
|
|
18
|
+
"All tools that call Codens APIs require the api_url parameter."
|
|
19
|
+
),
|
|
20
|
+
)
|
|
21
|
+
register_purple_tools(mcp)
|
|
22
|
+
register_red_tools(mcp)
|
|
23
|
+
register_blue_tools(mcp)
|
|
24
|
+
register_green_tools(mcp)
|
|
25
|
+
register_auth_tools(mcp)
|
|
26
|
+
mcp.run()
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
if __name__ == "__main__":
|
|
30
|
+
main()
|
|
File without changes
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"""Auth Codens MCP tools: agent signup and public pricing."""
|
|
2
|
+
|
|
3
|
+
from mcp.server.fastmcp import FastMCP
|
|
4
|
+
|
|
5
|
+
from ..client.auth import AuthClient
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def register_auth_tools(mcp: FastMCP) -> None:
|
|
9
|
+
|
|
10
|
+
@mcp.tool()
|
|
11
|
+
async def auth_agent_signup(
|
|
12
|
+
api_url: str,
|
|
13
|
+
existing_api_key: str,
|
|
14
|
+
agent_identity_token: str,
|
|
15
|
+
agent_identity_provider: str = "anthropic",
|
|
16
|
+
) -> dict:
|
|
17
|
+
"""
|
|
18
|
+
Issue a capability_token and register an agent member via the existing user's API key.
|
|
19
|
+
|
|
20
|
+
Path: POST /api/v1/auth/agent-signup
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
api_url: Auth Codens API base URL
|
|
24
|
+
existing_api_key: The user's existing API key (used to authorize agent registration)
|
|
25
|
+
agent_identity_token: Identity token issued by the agent provider
|
|
26
|
+
agent_identity_provider: Provider name (default: anthropic)
|
|
27
|
+
"""
|
|
28
|
+
return AuthClient(api_url).post(
|
|
29
|
+
"/api/v1/auth/agent-signup",
|
|
30
|
+
json={
|
|
31
|
+
"existing_api_key": existing_api_key,
|
|
32
|
+
"agent_identity_token": agent_identity_token,
|
|
33
|
+
"agent_identity_provider": agent_identity_provider,
|
|
34
|
+
},
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
@mcp.tool()
|
|
38
|
+
async def auth_get_pricing(api_url: str) -> dict:
|
|
39
|
+
"""
|
|
40
|
+
Return the public pricing.json (proxied from BCP, 5-min cache + fallback). No auth required.
|
|
41
|
+
|
|
42
|
+
Path: GET /.well-known/pricing.json
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
api_url: Auth Codens API base URL
|
|
46
|
+
"""
|
|
47
|
+
return AuthClient(api_url).get_no_auth("/.well-known/pricing.json")
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"""Blue Codens MCP tools: E2E test generation and execution."""
|
|
2
|
+
|
|
3
|
+
from mcp.server.fastmcp import FastMCP
|
|
4
|
+
|
|
5
|
+
from ..client.auth_helper import load_codens_credentials
|
|
6
|
+
from ..client.blue import BlueClient
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def _client(api_url: str) -> BlueClient:
|
|
10
|
+
creds = load_codens_credentials(api_url, service="blue")
|
|
11
|
+
return BlueClient(api_url, creds.token)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def register_blue_tools(mcp: FastMCP) -> None:
|
|
15
|
+
|
|
16
|
+
@mcp.tool()
|
|
17
|
+
async def blue_list_e2e_tests(
|
|
18
|
+
api_url: str,
|
|
19
|
+
page: int = 1,
|
|
20
|
+
page_size: int = 20,
|
|
21
|
+
) -> dict:
|
|
22
|
+
"""
|
|
23
|
+
List E2E tests.
|
|
24
|
+
|
|
25
|
+
Path: GET /api/v1/e2e-tests
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
api_url: Blue Codens API base URL
|
|
29
|
+
page: Page number (default: 1)
|
|
30
|
+
page_size: Results per page (default: 20)
|
|
31
|
+
"""
|
|
32
|
+
return _client(api_url).get(
|
|
33
|
+
"/api/v1/e2e-tests",
|
|
34
|
+
params={"page": page, "page_size": page_size},
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
@mcp.tool()
|
|
38
|
+
async def blue_generate_e2e_test(
|
|
39
|
+
api_url: str,
|
|
40
|
+
project_id: str,
|
|
41
|
+
requirement: str,
|
|
42
|
+
language: str = "playwright",
|
|
43
|
+
) -> dict:
|
|
44
|
+
"""
|
|
45
|
+
Generate an E2E test from a natural-language requirement.
|
|
46
|
+
|
|
47
|
+
Path: POST /api/v1/ai/generate/e2e-test
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
api_url: Blue Codens API base URL
|
|
51
|
+
project_id: Project ID
|
|
52
|
+
requirement: Natural-language description of the test scenario
|
|
53
|
+
language: Test framework (default: playwright)
|
|
54
|
+
"""
|
|
55
|
+
return _client(api_url).post(
|
|
56
|
+
"/api/v1/ai/generate/e2e-test",
|
|
57
|
+
json={
|
|
58
|
+
"project_id": project_id,
|
|
59
|
+
"requirement": requirement,
|
|
60
|
+
"language": language,
|
|
61
|
+
},
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
@mcp.tool()
|
|
65
|
+
async def blue_run_e2e_test(
|
|
66
|
+
api_url: str,
|
|
67
|
+
e2e_test_id: str,
|
|
68
|
+
) -> dict:
|
|
69
|
+
"""
|
|
70
|
+
Trigger a run for an existing E2E test.
|
|
71
|
+
|
|
72
|
+
Path: POST /api/v1/e2e-tests/{e2e_test_id}/run
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
api_url: Blue Codens API base URL
|
|
76
|
+
e2e_test_id: E2E test ID
|
|
77
|
+
"""
|
|
78
|
+
return _client(api_url).post(f"/api/v1/e2e-tests/{e2e_test_id}/run", json={})
|
|
79
|
+
|
|
80
|
+
@mcp.tool()
|
|
81
|
+
async def blue_get_e2e_test_results(
|
|
82
|
+
api_url: str,
|
|
83
|
+
e2e_test_id: str,
|
|
84
|
+
) -> dict:
|
|
85
|
+
"""
|
|
86
|
+
Get results for an E2E test (latest run).
|
|
87
|
+
|
|
88
|
+
Path: GET /api/v1/e2e-tests/{e2e_test_id}/results
|
|
89
|
+
|
|
90
|
+
Args:
|
|
91
|
+
api_url: Blue Codens API base URL
|
|
92
|
+
e2e_test_id: E2E test ID
|
|
93
|
+
"""
|
|
94
|
+
return _client(api_url).get(f"/api/v1/e2e-tests/{e2e_test_id}/results")
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"""Green Codens MCP tools: PRD consultations and kickoffs."""
|
|
2
|
+
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
from mcp.server.fastmcp import FastMCP
|
|
6
|
+
|
|
7
|
+
from ..client.auth_helper import load_codens_credentials
|
|
8
|
+
from ..client.green import GreenClient
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def _client(api_url: str) -> GreenClient:
|
|
12
|
+
creds = load_codens_credentials(api_url, service="green")
|
|
13
|
+
return GreenClient(api_url, creds.token)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def register_green_tools(mcp: FastMCP) -> None:
|
|
17
|
+
|
|
18
|
+
@mcp.tool()
|
|
19
|
+
async def green_create_consultation_with_message(
|
|
20
|
+
api_url: str,
|
|
21
|
+
organization_id: str,
|
|
22
|
+
project_id: str,
|
|
23
|
+
message: str,
|
|
24
|
+
) -> dict:
|
|
25
|
+
"""
|
|
26
|
+
Create a new consultation session and send the first message in one call (lazy creation).
|
|
27
|
+
|
|
28
|
+
Path: POST /api/v1/organizations/{organization_id}/consultations/with-message
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
api_url: Green Codens API base URL
|
|
32
|
+
organization_id: Organization ID
|
|
33
|
+
project_id: Project ID
|
|
34
|
+
message: First message to send in the consultation
|
|
35
|
+
"""
|
|
36
|
+
return _client(api_url).post(
|
|
37
|
+
f"/api/v1/organizations/{organization_id}/consultations/with-message",
|
|
38
|
+
json={"project_id": project_id, "message": message},
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
@mcp.tool()
|
|
42
|
+
async def green_send_consultation_message(
|
|
43
|
+
api_url: str,
|
|
44
|
+
organization_id: str,
|
|
45
|
+
consultation_id: str,
|
|
46
|
+
message: str,
|
|
47
|
+
) -> dict:
|
|
48
|
+
"""
|
|
49
|
+
Send a message in an existing consultation and get the AI reply.
|
|
50
|
+
|
|
51
|
+
Path: POST /api/v1/organizations/{organization_id}/consultations/{consultation_id}/messages
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
api_url: Green Codens API base URL
|
|
55
|
+
organization_id: Organization ID
|
|
56
|
+
consultation_id: Consultation session ID
|
|
57
|
+
message: Message to send
|
|
58
|
+
"""
|
|
59
|
+
return _client(api_url).post(
|
|
60
|
+
f"/api/v1/organizations/{organization_id}/consultations/{consultation_id}/messages",
|
|
61
|
+
json={"message": message},
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
@mcp.tool()
|
|
65
|
+
async def green_convert_consultation_to_prd(
|
|
66
|
+
api_url: str,
|
|
67
|
+
organization_id: str,
|
|
68
|
+
consultation_id: str,
|
|
69
|
+
title: Optional[str] = None,
|
|
70
|
+
) -> dict:
|
|
71
|
+
"""
|
|
72
|
+
Convert a consultation session into a PRD.
|
|
73
|
+
|
|
74
|
+
Path: POST /api/v1/organizations/{organization_id}/consultations/{consultation_id}/convert-to-prd
|
|
75
|
+
|
|
76
|
+
Args:
|
|
77
|
+
api_url: Green Codens API base URL
|
|
78
|
+
organization_id: Organization ID
|
|
79
|
+
consultation_id: Consultation session ID
|
|
80
|
+
title: Optional PRD title (auto-generated if omitted)
|
|
81
|
+
"""
|
|
82
|
+
body = {"title": title} if title else {}
|
|
83
|
+
return _client(api_url).post(
|
|
84
|
+
f"/api/v1/organizations/{organization_id}/consultations/{consultation_id}/convert-to-prd",
|
|
85
|
+
json=body,
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
@mcp.tool()
|
|
89
|
+
async def green_create_kickoff(
|
|
90
|
+
api_url: str,
|
|
91
|
+
organization_id: str,
|
|
92
|
+
project_id: str,
|
|
93
|
+
title: str,
|
|
94
|
+
description: str,
|
|
95
|
+
) -> dict:
|
|
96
|
+
"""
|
|
97
|
+
Create a Kickoff in Green Codens.
|
|
98
|
+
|
|
99
|
+
Path: POST /api/v1/organizations/{organization_id}/kickoffs
|
|
100
|
+
|
|
101
|
+
Args:
|
|
102
|
+
api_url: Green Codens API base URL
|
|
103
|
+
organization_id: Organization ID
|
|
104
|
+
project_id: Project ID
|
|
105
|
+
title: Kickoff title
|
|
106
|
+
description: Kickoff description
|
|
107
|
+
"""
|
|
108
|
+
return _client(api_url).post(
|
|
109
|
+
f"/api/v1/organizations/{organization_id}/kickoffs",
|
|
110
|
+
json={
|
|
111
|
+
"project_id": project_id,
|
|
112
|
+
"title": title,
|
|
113
|
+
"description": description,
|
|
114
|
+
},
|
|
115
|
+
)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""Re-export all 16 Purple tools from purple-codens-mcp dependency."""
|
|
2
|
+
|
|
3
|
+
from mcp.server.fastmcp import FastMCP
|
|
4
|
+
from purple_codens_mcp.client import PurpleCodensClient
|
|
5
|
+
from purple_codens_mcp.tools.auth_tools import register_auth_tools as _register_purple_auth
|
|
6
|
+
from purple_codens_mcp.tools.instruction_tools import register_instruction_tools as _register_instructions
|
|
7
|
+
from purple_codens_mcp.tools.project_tools import register_project_tools as _register_projects
|
|
8
|
+
from purple_codens_mcp.tools.repo_tools import register_repo_tools as _register_repos
|
|
9
|
+
from purple_codens_mcp.tools.sse_tools import register_sse_tools as _register_sse
|
|
10
|
+
from purple_codens_mcp.tools.workflow_tools import register_workflow_tools as _register_workflows
|
|
11
|
+
|
|
12
|
+
_purple_clients: dict[str, PurpleCodensClient] = {}
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _purple_get_client(api_url: str, force_reload: bool = False) -> PurpleCodensClient:
|
|
16
|
+
if force_reload or api_url not in _purple_clients:
|
|
17
|
+
_purple_clients[api_url] = PurpleCodensClient(api_url)
|
|
18
|
+
return _purple_clients[api_url]
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def register_purple_tools(mcp: FastMCP) -> None:
|
|
22
|
+
"""Register all 16 Purple tools (auth/project/repo/instruction/workflow/sse)."""
|
|
23
|
+
_register_purple_auth(mcp, _purple_get_client)
|
|
24
|
+
_register_projects(mcp, _purple_get_client)
|
|
25
|
+
_register_repos(mcp, _purple_get_client)
|
|
26
|
+
_register_instructions(mcp, _purple_get_client)
|
|
27
|
+
_register_workflows(mcp, _purple_get_client)
|
|
28
|
+
_register_sse(mcp, _purple_get_client)
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"""Red Codens MCP tools: bug reports and auto-fix plan submission."""
|
|
2
|
+
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
from mcp.server.fastmcp import FastMCP
|
|
6
|
+
|
|
7
|
+
from ..client.auth_helper import load_codens_credentials
|
|
8
|
+
from ..client.red import RedClient
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def _client(api_url: str) -> RedClient:
|
|
12
|
+
creds = load_codens_credentials(api_url, service="red")
|
|
13
|
+
return RedClient(api_url, creds.token)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def register_red_tools(mcp: FastMCP) -> None:
|
|
17
|
+
|
|
18
|
+
@mcp.tool()
|
|
19
|
+
async def red_create_bug_report(
|
|
20
|
+
api_url: str,
|
|
21
|
+
organization_id: str,
|
|
22
|
+
project_id: str,
|
|
23
|
+
title: str,
|
|
24
|
+
description: str,
|
|
25
|
+
attachment_urls: Optional[list[str]] = None,
|
|
26
|
+
) -> dict:
|
|
27
|
+
"""
|
|
28
|
+
Create a bug report via Red Codens agent endpoint.
|
|
29
|
+
|
|
30
|
+
Path: POST /api/v1/agent/create-bug-report
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
api_url: Red Codens API base URL
|
|
34
|
+
organization_id: Organization ID
|
|
35
|
+
project_id: Project ID
|
|
36
|
+
title: Bug report title
|
|
37
|
+
description: Bug description
|
|
38
|
+
attachment_urls: Optional list of attachment URLs (screenshots, logs)
|
|
39
|
+
"""
|
|
40
|
+
body: dict = {
|
|
41
|
+
"organization_id": organization_id,
|
|
42
|
+
"project_id": project_id,
|
|
43
|
+
"title": title,
|
|
44
|
+
"description": description,
|
|
45
|
+
}
|
|
46
|
+
if attachment_urls:
|
|
47
|
+
body["attachment_urls"] = attachment_urls
|
|
48
|
+
return _client(api_url).post("/api/v1/agent/create-bug-report", json=body)
|
|
49
|
+
|
|
50
|
+
@mcp.tool()
|
|
51
|
+
async def red_get_bug_report(
|
|
52
|
+
api_url: str,
|
|
53
|
+
organization_id: str,
|
|
54
|
+
bug_id: str,
|
|
55
|
+
) -> dict:
|
|
56
|
+
"""
|
|
57
|
+
Get a bug report by ID.
|
|
58
|
+
|
|
59
|
+
Path: GET /api/v1/organizations/{organization_id}/bug-reports/{bug_id}
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
api_url: Red Codens API base URL
|
|
63
|
+
organization_id: Organization ID
|
|
64
|
+
bug_id: Bug report ID
|
|
65
|
+
"""
|
|
66
|
+
return _client(api_url).get(
|
|
67
|
+
f"/api/v1/organizations/{organization_id}/bug-reports/{bug_id}"
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
@mcp.tool()
|
|
71
|
+
async def red_analyze_bug_report(
|
|
72
|
+
api_url: str,
|
|
73
|
+
organization_id: str,
|
|
74
|
+
bug_id: str,
|
|
75
|
+
) -> dict:
|
|
76
|
+
"""
|
|
77
|
+
Trigger AI analysis for a bug report.
|
|
78
|
+
|
|
79
|
+
Path: POST /api/v1/organizations/{organization_id}/bug-reports/{bug_id}/analyze
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
api_url: Red Codens API base URL
|
|
83
|
+
organization_id: Organization ID
|
|
84
|
+
bug_id: Bug report ID
|
|
85
|
+
"""
|
|
86
|
+
return _client(api_url).post(
|
|
87
|
+
f"/api/v1/organizations/{organization_id}/bug-reports/{bug_id}/analyze",
|
|
88
|
+
json={},
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
@mcp.tool()
|
|
92
|
+
async def red_submit_bug_fix_plan_to_purple(
|
|
93
|
+
api_url: str,
|
|
94
|
+
organization_id: str,
|
|
95
|
+
plan_id: str,
|
|
96
|
+
) -> dict:
|
|
97
|
+
"""
|
|
98
|
+
Submit DRAFT BugFixTasks of a plan to Purple Codens for execution.
|
|
99
|
+
|
|
100
|
+
Path: POST /api/v1/organizations/{organization_id}/bug-fix-plans/{plan_id}/submit
|
|
101
|
+
|
|
102
|
+
Args:
|
|
103
|
+
api_url: Red Codens API base URL
|
|
104
|
+
organization_id: Organization ID
|
|
105
|
+
plan_id: Bug fix plan ID
|
|
106
|
+
"""
|
|
107
|
+
return _client(api_url).post(
|
|
108
|
+
f"/api/v1/organizations/{organization_id}/bug-fix-plans/{plan_id}/submit",
|
|
109
|
+
json={},
|
|
110
|
+
)
|