agent-orchestrator-mcp 1.0.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.
@@ -0,0 +1,26 @@
1
+ name: Publish to Smithery
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ jobs:
8
+ publish:
9
+ name: Publish MCP Server to Smithery
10
+ runs-on: ubuntu-latest
11
+ permissions:
12
+ contents: read
13
+ steps:
14
+ - name: Checkout repository
15
+ uses: actions/checkout@v4
16
+
17
+ - name: Setup Node.js
18
+ uses: actions/setup-node@v4
19
+ with:
20
+ node-version: '20'
21
+
22
+ - name: Publish to Smithery
23
+ env:
24
+ SMITHERY_API_KEY: ${{ secrets.SMITHERY_API_KEY }}
25
+ run: |
26
+ npx @smithery/cli mcp publish "https://github.com/${{ github.repository }}" -n nicholastempleman/${{ github.event.repository.name }}
@@ -0,0 +1,10 @@
1
+ __pycache__/
2
+ *.pyc
3
+ *.pyo
4
+ .env
5
+ .venv/
6
+ dist/
7
+ build/
8
+ *.egg-info/
9
+ .pytest_cache/
10
+ *.db
@@ -0,0 +1,223 @@
1
+ {
2
+ "name": "agent-orchestrator-mcp",
3
+ "description": "> **By [MEOK AI Labs](https://meok.ai)** \u2014 Multi-agent task management: create agents, delegate tasks with trust-based routing, coordinate file",
4
+ "version": "1.0.0",
5
+ "tools": [
6
+ {
7
+ "name": "create_agent",
8
+ "description": "Create a new agent with a name, role, department, and capabilities.",
9
+ "parameters": {
10
+ "type": "object",
11
+ "properties": {
12
+ "name": {
13
+ "type": "string"
14
+ },
15
+ "role": {
16
+ "type": "string"
17
+ },
18
+ "department": {
19
+ "type": "string"
20
+ },
21
+ "capabilities": {
22
+ "type": "array"
23
+ },
24
+ "instructions": {
25
+ "type": "string"
26
+ }
27
+ },
28
+ "required": [
29
+ "name",
30
+ "role"
31
+ ]
32
+ }
33
+ },
34
+ {
35
+ "name": "list_agents",
36
+ "description": "List all registered agents with their trust levels, task counts, and status.",
37
+ "parameters": {
38
+ "type": "object",
39
+ "properties": {
40
+ "department": {
41
+ "type": "string"
42
+ }
43
+ },
44
+ "required": []
45
+ }
46
+ },
47
+ {
48
+ "name": "delegate_task",
49
+ "description": "Delegate a task to a specific agent or auto-route to the best match",
50
+ "parameters": {
51
+ "type": "object",
52
+ "properties": {
53
+ "task": {
54
+ "type": "string"
55
+ },
56
+ "agent_id": {
57
+ "type": "string"
58
+ },
59
+ "capability": {
60
+ "type": "string"
61
+ },
62
+ "department": {
63
+ "type": "string"
64
+ },
65
+ "priority": {
66
+ "type": "string"
67
+ },
68
+ "care_score": {
69
+ "type": "number"
70
+ }
71
+ },
72
+ "required": [
73
+ "task"
74
+ ]
75
+ }
76
+ },
77
+ {
78
+ "name": "complete_task",
79
+ "description": "Mark a task as completed (or failed). Updates the agent's trust level",
80
+ "parameters": {
81
+ "type": "object",
82
+ "properties": {
83
+ "task_id": {
84
+ "type": "string"
85
+ },
86
+ "agent_id": {
87
+ "type": "string"
88
+ },
89
+ "result_summary": {
90
+ "type": "string"
91
+ },
92
+ "care_score": {
93
+ "type": "number"
94
+ },
95
+ "success": {
96
+ "type": "boolean"
97
+ }
98
+ },
99
+ "required": [
100
+ "task_id",
101
+ "agent_id",
102
+ "result_summary"
103
+ ]
104
+ }
105
+ },
106
+ {
107
+ "name": "acquire_files",
108
+ "description": "Acquire file locks for coordinated multi-agent work. Prevents conflicts",
109
+ "parameters": {
110
+ "type": "object",
111
+ "properties": {
112
+ "agent_id": {
113
+ "type": "string"
114
+ },
115
+ "files": {
116
+ "type": "array"
117
+ },
118
+ "task_id": {
119
+ "type": "string"
120
+ },
121
+ "exclusive": {
122
+ "type": "boolean"
123
+ }
124
+ },
125
+ "required": [
126
+ "agent_id",
127
+ "files",
128
+ "task_id"
129
+ ]
130
+ }
131
+ },
132
+ {
133
+ "name": "release_files",
134
+ "description": "Release file locks held by an agent after task completion.",
135
+ "parameters": {
136
+ "type": "object",
137
+ "properties": {
138
+ "agent_id": {
139
+ "type": "string"
140
+ },
141
+ "files": {
142
+ "type": "array"
143
+ }
144
+ },
145
+ "required": [
146
+ "agent_id",
147
+ "files"
148
+ ]
149
+ }
150
+ },
151
+ {
152
+ "name": "start_sprint",
153
+ "description": "Start a focused sprint with named goals and a time limit. Sprints help",
154
+ "parameters": {
155
+ "type": "object",
156
+ "properties": {
157
+ "name": {
158
+ "type": "string"
159
+ },
160
+ "goals": {
161
+ "type": "array"
162
+ },
163
+ "duration_minutes": {
164
+ "type": "integer"
165
+ }
166
+ },
167
+ "required": [
168
+ "name",
169
+ "goals"
170
+ ]
171
+ }
172
+ },
173
+ {
174
+ "name": "complete_sprint",
175
+ "description": "Complete a sprint and record which goals were achieved. Returns the",
176
+ "parameters": {
177
+ "type": "object",
178
+ "properties": {
179
+ "sprint_id": {
180
+ "type": "string"
181
+ },
182
+ "completed_goals": {
183
+ "type": "array"
184
+ },
185
+ "summary": {
186
+ "type": "string"
187
+ }
188
+ },
189
+ "required": [
190
+ "sprint_id"
191
+ ]
192
+ }
193
+ },
194
+ {
195
+ "name": "get_dashboard",
196
+ "description": "Get the full orchestration dashboard: agent count, trust averages,",
197
+ "parameters": {
198
+ "type": "object",
199
+ "properties": {},
200
+ "required": []
201
+ }
202
+ },
203
+ {
204
+ "name": "get_task_queue",
205
+ "description": "Get the task queue, optionally filtered by status (assigned/completed/failed)",
206
+ "parameters": {
207
+ "type": "object",
208
+ "properties": {
209
+ "status": {
210
+ "type": "string"
211
+ },
212
+ "agent_id": {
213
+ "type": "string"
214
+ },
215
+ "limit": {
216
+ "type": "integer"
217
+ }
218
+ },
219
+ "required": []
220
+ }
221
+ }
222
+ ]
223
+ }
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 MEOK AI Labs (meok.ai)
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,36 @@
1
+ Metadata-Version: 2.4
2
+ Name: agent-orchestrator-mcp
3
+ Version: 1.0.0
4
+ Summary: MEOK AI Labs — agent-orchestrator-mcp
5
+ Project-URL: Homepage, https://meok.ai
6
+ Project-URL: Repository, https://github.com/CSOAI-ORG/agent-orchestrator-mcp
7
+ Author-email: MEOK AI Labs <nicholas@meok.ai>
8
+ License: MIT License
9
+
10
+ Copyright (c) 2026 MEOK AI Labs (meok.ai)
11
+
12
+ Permission is hereby granted, free of charge, to any person obtaining a copy
13
+ of this software and associated documentation files (the "Software"), to deal
14
+ in the Software without restriction, including without limitation the rights
15
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16
+ copies of the Software, and to permit persons to whom the Software is
17
+ furnished to do so, subject to the following conditions:
18
+
19
+ The above copyright notice and this permission notice shall be included in all
20
+ copies or substantial portions of the Software.
21
+
22
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28
+ SOFTWARE.
29
+ License-File: LICENSE
30
+ Keywords: agent,ai,mcp,meok,orchestrator
31
+ Classifier: License :: OSI Approved :: MIT License
32
+ Classifier: Operating System :: OS Independent
33
+ Classifier: Programming Language :: Python :: 3
34
+ Classifier: Topic :: Software Development :: Libraries
35
+ Requires-Python: >=3.10
36
+ Requires-Dist: mcp>=1.0.0
@@ -0,0 +1,64 @@
1
+ # Agent Orchestrator MCP Server
2
+
3
+ > **By [MEOK AI Labs](https://meok.ai)** — Sovereign AI tools for everyone.
4
+
5
+ Multi-agent task management system for AI applications. Create agents with roles and capabilities, delegate tasks with trust-based routing, coordinate file access, run focused sprints, and monitor performance through a unified dashboard.
6
+
7
+ [![MCPize](https://img.shields.io/badge/MCPize-Listed-blue)](https://mcpize.com/mcp/agent-orchestrator)
8
+ [![MIT License](https://img.shields.io/badge/License-MIT-green)](LICENSE)
9
+ [![MEOK AI Labs](https://img.shields.io/badge/MEOK_AI_Labs-255+_servers-purple)](https://meok.ai)
10
+
11
+ ## Tools
12
+
13
+ | Tool | Description |
14
+ |------|-------------|
15
+ | `create_agent` | Create a new agent with name, role, and capabilities |
16
+ | `list_agents` | List all registered agents with trust levels and status |
17
+ | `delegate_task` | Delegate a task to an agent or auto-route to best match |
18
+ | `complete_task` | Mark a task as completed or failed |
19
+ | `acquire_files` | Acquire file locks for coordinated multi-agent work |
20
+ | `release_files` | Release file locks held by an agent |
21
+ | `start_sprint` | Start a focused sprint with goals and a time limit |
22
+ | `complete_sprint` | Complete a sprint and record achieved goals |
23
+ | `get_dashboard` | Get the full orchestration dashboard |
24
+ | `get_task_queue` | Get the task queue filtered by status |
25
+
26
+ ## Quick Start
27
+
28
+ ```bash
29
+ pip install mcp
30
+ git clone https://github.com/CSOAI-ORG/agent-orchestrator-mcp.git
31
+ cd agent-orchestrator-mcp
32
+ python server.py
33
+ ```
34
+
35
+ ## Claude Desktop Config
36
+
37
+ ```json
38
+ {
39
+ "mcpServers": {
40
+ "agent-orchestrator": {
41
+ "command": "python",
42
+ "args": ["server.py"],
43
+ "cwd": "/path/to/agent-orchestrator-mcp"
44
+ }
45
+ }
46
+ }
47
+ ```
48
+
49
+ ## Pricing
50
+
51
+ | Plan | Price | Requests |
52
+ |------|-------|----------|
53
+ | Free | $0/mo | 100 calls/day, 10 agents max |
54
+ | Pro | $9/mo | Unlimited agents + webhook notifications |
55
+ | Enterprise | Contact us | Custom + LLM-powered routing |
56
+
57
+ [Get on MCPize](https://mcpize.com/mcp/agent-orchestrator)
58
+
59
+ ## Part of MEOK AI Labs
60
+
61
+ This is one of 255+ MCP servers by MEOK AI Labs. Browse all at [meok.ai](https://meok.ai) or [GitHub](https://github.com/CSOAI-ORG).
62
+
63
+ ---
64
+ **MEOK AI Labs** | [meok.ai](https://meok.ai) | nicholas@meok.ai | United Kingdom
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "agent-orchestrator-mcp",
3
+ "version": "1.0.0",
4
+ "description": "MEOK AI Labs — agent orchestrator MCP Server",
5
+ "main": "server.py",
6
+ "mcp": {
7
+ "name": "agent orchestrator",
8
+ "vendor": "MEOK AI Labs",
9
+ "homepage": "https://meok.ai",
10
+ "repository": "https://github.com/CSOAI-ORG/agent-orchestrator-mcp",
11
+ "runtime": "python",
12
+ "tags": ["mcp", "mcp-server", "meok-ai-labs", "ai-tools"]
13
+ },
14
+ "keywords": ["mcp", "mcp-server", "meok-ai-labs"],
15
+ "author": "MEOK AI Labs <nicholas@meok.ai>",
16
+ "license": "MIT",
17
+ "repository": {"type": "git", "url": "https://github.com/CSOAI-ORG/agent-orchestrator-mcp"}
18
+ }
@@ -0,0 +1,24 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+ [project]
5
+ name = "agent-orchestrator-mcp"
6
+ version = "1.0.0"
7
+ description = "MEOK AI Labs — agent-orchestrator-mcp"
8
+ license = {file = "LICENSE"}
9
+ requires-python = ">=3.10"
10
+ authors = [{name = "MEOK AI Labs", email = "nicholas@meok.ai"}]
11
+ dependencies = ["mcp>=1.0.0"]
12
+ keywords = ["mcp", "ai", "meok", "agent", "orchestrator"]
13
+ classifiers = [
14
+ "Programming Language :: Python :: 3",
15
+ "License :: OSI Approved :: MIT License",
16
+ "Operating System :: OS Independent",
17
+ "Topic :: Software Development :: Libraries",
18
+ ]
19
+ [project.urls]
20
+ Homepage = "https://meok.ai"
21
+ Repository = "https://github.com/CSOAI-ORG/agent-orchestrator-mcp"
22
+ [tool.hatch.build.targets.wheel]
23
+ packages = ["."]
24
+ only-include = ["server.py"]
@@ -0,0 +1,486 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Agent Orchestrator MCP Server
4
+ ===============================
5
+ Multi-agent task management system. Create agents with roles and capabilities,
6
+ delegate tasks with trust-based routing, coordinate multi-agent file access,
7
+ run sprint workflows, and monitor agent performance. Based on the Sovereign
8
+ Temple 47-agent coordination framework.
9
+
10
+ Install: pip install mcp
11
+ Run: python server.py
12
+ """
13
+
14
+
15
+ import sys, os
16
+ sys.path.insert(0, os.path.expanduser('~/clawd/meok-labs-engine/shared'))
17
+ from auth_middleware import check_access
18
+
19
+ import json
20
+ import uuid
21
+ import time
22
+ from datetime import datetime, timedelta
23
+ from pathlib import Path
24
+ from typing import Optional
25
+ from collections import defaultdict
26
+ from mcp.server.fastmcp import FastMCP
27
+
28
+ # ---------------------------------------------------------------------------
29
+ # Rate limiting
30
+ # ---------------------------------------------------------------------------
31
+ FREE_DAILY_LIMIT = 100
32
+ FREE_MAX_AGENTS = 10
33
+ _usage: dict[str, list[datetime]] = defaultdict(list)
34
+
35
+
36
+ def _check_rate_limit(caller: str = "anonymous") -> Optional[str]:
37
+ now = datetime.now()
38
+ cutoff = now - timedelta(days=1)
39
+ _usage[caller] = [t for t in _usage[caller] if t > cutoff]
40
+ if len(_usage[caller]) >= FREE_DAILY_LIMIT:
41
+ return f"Free tier limit reached ({FREE_DAILY_LIMIT}/day). Upgrade to Pro: https://mcpize.com/agent-orchestrator-mcp/pro"
42
+ _usage[caller].append(now)
43
+ return None
44
+
45
+
46
+ # ---------------------------------------------------------------------------
47
+ # Persistent Storage
48
+ # ---------------------------------------------------------------------------
49
+ DATA_DIR = Path.home() / ".mcp-agents"
50
+ DATA_DIR.mkdir(exist_ok=True)
51
+ AGENTS_FILE = DATA_DIR / "agents.json"
52
+ TASKS_FILE = DATA_DIR / "tasks.json"
53
+ SPRINTS_FILE = DATA_DIR / "sprints.json"
54
+
55
+
56
+ def _load_json(path: Path) -> dict:
57
+ if path.exists():
58
+ try:
59
+ return json.loads(path.read_text())
60
+ except json.JSONDecodeError:
61
+ return {}
62
+ return {}
63
+
64
+
65
+ def _save_json(path: Path, data: dict):
66
+ path.write_text(json.dumps(data, indent=2, default=str))
67
+
68
+
69
+ # ---------------------------------------------------------------------------
70
+ # Agent Registry
71
+ # ---------------------------------------------------------------------------
72
+ class AgentStore:
73
+ def __init__(self):
74
+ self.agents = _load_json(AGENTS_FILE)
75
+ self.tasks = _load_json(TASKS_FILE)
76
+ self.sprints = _load_json(SPRINTS_FILE)
77
+ self._file_locks: dict[str, dict] = {} # file -> {"agent": str, "task": str, "exclusive": bool}
78
+
79
+ def save(self):
80
+ _save_json(AGENTS_FILE, self.agents)
81
+ _save_json(TASKS_FILE, self.tasks)
82
+ _save_json(SPRINTS_FILE, self.sprints)
83
+
84
+ def create_agent(self, name: str, role: str, department: str = "general",
85
+ capabilities: list[str] | None = None,
86
+ instructions: str = "") -> dict:
87
+ aid = name.lower().replace(" ", "_")
88
+ if aid in self.agents and len(self.agents) >= FREE_MAX_AGENTS:
89
+ pass # Allow update
90
+ elif len(self.agents) >= FREE_MAX_AGENTS and aid not in self.agents:
91
+ return {"error": f"Free tier limit: max {FREE_MAX_AGENTS} agents. Upgrade for unlimited."}
92
+
93
+ now = datetime.now().isoformat()
94
+ self.agents[aid] = {
95
+ "name": name,
96
+ "role": role,
97
+ "department": department,
98
+ "capabilities": capabilities or [],
99
+ "instructions": instructions,
100
+ "trust_level": 0.5,
101
+ "tasks_completed": self.agents.get(aid, {}).get("tasks_completed", 0),
102
+ "tasks_failed": self.agents.get(aid, {}).get("tasks_failed", 0),
103
+ "created_at": self.agents.get(aid, {}).get("created_at", now),
104
+ "updated_at": now,
105
+ "status": "active",
106
+ }
107
+ self.save()
108
+ return {"status": "created", "agent_id": aid, "name": name, "role": role}
109
+
110
+ def get_agent(self, aid: str) -> Optional[dict]:
111
+ return self.agents.get(aid)
112
+
113
+ def list_agents(self, department: str | None = None) -> list[dict]:
114
+ agents = []
115
+ for aid, agent in self.agents.items():
116
+ if department and agent.get("department") != department:
117
+ continue
118
+ agents.append({"id": aid, **agent})
119
+ return agents
120
+
121
+ def find_best_agent(self, capability: str | None = None,
122
+ department: str | None = None) -> Optional[str]:
123
+ """Find the best agent for a task based on capability match and trust level."""
124
+ candidates = []
125
+ for aid, agent in self.agents.items():
126
+ if agent.get("status") != "active":
127
+ continue
128
+ if department and agent.get("department") != department:
129
+ continue
130
+ if capability and capability not in agent.get("capabilities", []):
131
+ continue
132
+ candidates.append((aid, agent.get("trust_level", 0.5)))
133
+
134
+ if not candidates:
135
+ return None
136
+ # Sort by trust level descending
137
+ candidates.sort(key=lambda x: x[1], reverse=True)
138
+ return candidates[0][0]
139
+
140
+ def delegate_task(self, task_desc: str, agent_id: str | None = None,
141
+ capability: str | None = None,
142
+ department: str | None = None,
143
+ priority: str = "normal",
144
+ care_score: float = 0.5) -> dict:
145
+ """Delegate a task to a specific agent or auto-route to best match."""
146
+ if not agent_id:
147
+ agent_id = self.find_best_agent(capability, department)
148
+ if not agent_id or agent_id not in self.agents:
149
+ return {"error": f"Agent '{agent_id}' not found. Create an agent first."}
150
+
151
+ tid = str(uuid.uuid4())[:8]
152
+ now = datetime.now().isoformat()
153
+ task = {
154
+ "id": tid,
155
+ "description": task_desc,
156
+ "agent_id": agent_id,
157
+ "agent_name": self.agents[agent_id]["name"],
158
+ "status": "assigned",
159
+ "priority": priority,
160
+ "care_score": care_score,
161
+ "created_at": now,
162
+ "updated_at": now,
163
+ "result": None,
164
+ }
165
+ self.tasks[tid] = task
166
+ self.save()
167
+ return {"status": "delegated", "task_id": tid, "agent_id": agent_id,
168
+ "agent_name": self.agents[agent_id]["name"], "task": task_desc}
169
+
170
+ def complete_task(self, task_id: str, agent_id: str,
171
+ result_summary: str, care_score: float = 0.5,
172
+ success: bool = True) -> dict:
173
+ """Mark a task as completed and update agent trust."""
174
+ if task_id not in self.tasks:
175
+ return {"error": f"Task {task_id} not found"}
176
+
177
+ task = self.tasks[task_id]
178
+ task["status"] = "completed" if success else "failed"
179
+ task["result"] = result_summary
180
+ task["care_score"] = care_score
181
+ task["updated_at"] = datetime.now().isoformat()
182
+
183
+ # Update agent trust based on outcome
184
+ if agent_id in self.agents:
185
+ agent = self.agents[agent_id]
186
+ if success:
187
+ agent["tasks_completed"] = agent.get("tasks_completed", 0) + 1
188
+ # Trust increases with successful completions
189
+ trust_delta = 0.02 * care_score
190
+ agent["trust_level"] = min(1.0, agent.get("trust_level", 0.5) + trust_delta)
191
+ else:
192
+ agent["tasks_failed"] = agent.get("tasks_failed", 0) + 1
193
+ trust_delta = -0.05
194
+ agent["trust_level"] = max(0.0, agent.get("trust_level", 0.5) + trust_delta)
195
+
196
+ self.save()
197
+ return {"status": task["status"], "task_id": task_id, "agent_id": agent_id,
198
+ "result": result_summary}
199
+
200
+ def acquire_files(self, agent_id: str, files: list[str], task_id: str,
201
+ exclusive: bool = False) -> dict:
202
+ """Acquire file locks for coordinated multi-agent work."""
203
+ conflicts = []
204
+ for f in files:
205
+ if f in self._file_locks:
206
+ lock = self._file_locks[f]
207
+ if lock["exclusive"] or exclusive:
208
+ conflicts.append({"file": f, "locked_by": lock["agent"]})
209
+
210
+ if conflicts:
211
+ return {"status": "conflict", "conflicts": conflicts}
212
+
213
+ for f in files:
214
+ self._file_locks[f] = {
215
+ "agent": agent_id,
216
+ "task": task_id,
217
+ "exclusive": exclusive,
218
+ "acquired_at": datetime.now().isoformat(),
219
+ }
220
+ return {"status": "acquired", "files": files, "agent_id": agent_id}
221
+
222
+ def release_files(self, agent_id: str, files: list[str]) -> dict:
223
+ """Release file locks."""
224
+ released = []
225
+ for f in files:
226
+ if f in self._file_locks and self._file_locks[f]["agent"] == agent_id:
227
+ del self._file_locks[f]
228
+ released.append(f)
229
+ return {"status": "released", "files": released}
230
+
231
+ def start_sprint(self, name: str, goals: list[str], duration_minutes: int = 60) -> dict:
232
+ """Start a focused sprint with goals and time limit."""
233
+ sid = str(uuid.uuid4())[:8]
234
+ now = datetime.now()
235
+ sprint = {
236
+ "id": sid,
237
+ "name": name,
238
+ "goals": goals,
239
+ "status": "active",
240
+ "started_at": now.isoformat(),
241
+ "ends_at": (now + timedelta(minutes=duration_minutes)).isoformat(),
242
+ "duration_minutes": duration_minutes,
243
+ "completed_goals": [],
244
+ "tasks": [],
245
+ }
246
+ self.sprints[sid] = sprint
247
+ self.save()
248
+ return {"status": "started", "sprint_id": sid, "name": name,
249
+ "ends_at": sprint["ends_at"], "goals": goals}
250
+
251
+ def complete_sprint(self, sprint_id: str, completed_goals: list[str] | None = None,
252
+ summary: str = "") -> dict:
253
+ """Complete a sprint and record results."""
254
+ if sprint_id not in self.sprints:
255
+ return {"error": f"Sprint {sprint_id} not found"}
256
+
257
+ sprint = self.sprints[sprint_id]
258
+ sprint["status"] = "completed"
259
+ sprint["completed_at"] = datetime.now().isoformat()
260
+ sprint["completed_goals"] = completed_goals or []
261
+ sprint["summary"] = summary
262
+
263
+ total = len(sprint["goals"])
264
+ done = len(sprint["completed_goals"])
265
+ sprint["completion_rate"] = round(done / max(total, 1) * 100, 1)
266
+
267
+ self.save()
268
+ return {
269
+ "status": "completed",
270
+ "sprint_id": sprint_id,
271
+ "completion_rate": sprint["completion_rate"],
272
+ "completed": done,
273
+ "total": total,
274
+ "summary": summary,
275
+ }
276
+
277
+ def get_dashboard(self) -> dict:
278
+ """Get full orchestration dashboard."""
279
+ total_agents = len(self.agents)
280
+ active_agents = sum(1 for a in self.agents.values() if a.get("status") == "active")
281
+
282
+ total_tasks = len(self.tasks)
283
+ by_status = defaultdict(int)
284
+ for t in self.tasks.values():
285
+ by_status[t.get("status", "unknown")] += 1
286
+
287
+ avg_trust = 0
288
+ if self.agents:
289
+ avg_trust = sum(a.get("trust_level", 0.5) for a in self.agents.values()) / len(self.agents)
290
+
291
+ active_sprints = [s for s in self.sprints.values() if s.get("status") == "active"]
292
+ file_locks = len(self._file_locks)
293
+
294
+ # Department breakdown
295
+ departments = defaultdict(int)
296
+ for a in self.agents.values():
297
+ departments[a.get("department", "general")] += 1
298
+
299
+ return {
300
+ "agents": {"total": total_agents, "active": active_agents, "avg_trust": round(avg_trust, 3)},
301
+ "tasks": {"total": total_tasks, "by_status": dict(by_status)},
302
+ "sprints": {"active": len(active_sprints), "total": len(self.sprints)},
303
+ "file_locks": file_locks,
304
+ "departments": dict(departments),
305
+ }
306
+
307
+
308
+ # Global store
309
+ store = AgentStore()
310
+
311
+ # ---------------------------------------------------------------------------
312
+ # MCP Server
313
+ # ---------------------------------------------------------------------------
314
+ mcp = FastMCP(
315
+ "Agent Orchestrator MCP",
316
+ instructions="Multi-agent task management: create agents, delegate tasks with trust-based routing, coordinate file access, run sprints, and monitor performance.")
317
+
318
+
319
+ @mcp.tool()
320
+ def create_agent(name: str, role: str, department: str = "general",
321
+ capabilities: list[str] | None = None,
322
+ instructions: str = "", api_key: str = "") -> dict:
323
+ """Create a new agent with a name, role, department, and capabilities.
324
+ Agents accumulate trust through successful task completion.
325
+ Free tier: max 10 agents."""
326
+ allowed, msg, tier = check_access(api_key)
327
+ if not allowed:
328
+ return {"error": msg, "upgrade_url": "https://meok.ai/pricing"}
329
+
330
+ err = _check_rate_limit()
331
+ if err:
332
+ return {"error": err}
333
+ return store.create_agent(name, role, department, capabilities, instructions)
334
+
335
+
336
+ @mcp.tool()
337
+ def list_agents(department: str | None = None, api_key: str = "") -> dict:
338
+ """List all registered agents with their trust levels, task counts, and status.
339
+ Optionally filter by department."""
340
+ allowed, msg, tier = check_access(api_key)
341
+ if not allowed:
342
+ return {"error": msg, "upgrade_url": "https://meok.ai/pricing"}
343
+
344
+ err = _check_rate_limit()
345
+ if err:
346
+ return {"error": err}
347
+ agents = store.list_agents(department)
348
+ return {"agents": agents, "count": len(agents)}
349
+
350
+
351
+ @mcp.tool()
352
+ def delegate_task(task: str, agent_id: str | None = None,
353
+ capability: str | None = None,
354
+ department: str | None = None,
355
+ priority: str = "normal",
356
+ care_score: float = 0.5, api_key: str = "") -> dict:
357
+ """Delegate a task to a specific agent or auto-route to the best match
358
+ based on capability, department, and trust level. Priority: low/normal/high/urgent.
359
+ Care score (0-1) influences trust updates on completion."""
360
+ allowed, msg, tier = check_access(api_key)
361
+ if not allowed:
362
+ return {"error": msg, "upgrade_url": "https://meok.ai/pricing"}
363
+
364
+ err = _check_rate_limit()
365
+ if err:
366
+ return {"error": err}
367
+ return store.delegate_task(task, agent_id, capability, department, priority, care_score)
368
+
369
+
370
+ @mcp.tool()
371
+ def complete_task(task_id: str, agent_id: str, result_summary: str,
372
+ care_score: float = 0.5, success: bool = True, api_key: str = "") -> dict:
373
+ """Mark a task as completed (or failed). Updates the agent's trust level
374
+ based on success/failure and care score. Successful tasks increase trust,
375
+ failed tasks decrease it."""
376
+ allowed, msg, tier = check_access(api_key)
377
+ if not allowed:
378
+ return {"error": msg, "upgrade_url": "https://meok.ai/pricing"}
379
+
380
+ err = _check_rate_limit()
381
+ if err:
382
+ return {"error": err}
383
+ return store.complete_task(task_id, agent_id, result_summary, care_score, success)
384
+
385
+
386
+ @mcp.tool()
387
+ def acquire_files(agent_id: str, files: list[str], task_id: str,
388
+ exclusive: bool = False, api_key: str = "") -> dict:
389
+ """Acquire file locks for coordinated multi-agent work. Prevents conflicts
390
+ when multiple agents need to modify the same files. Set exclusive=true for
391
+ write locks, false for read locks."""
392
+ allowed, msg, tier = check_access(api_key)
393
+ if not allowed:
394
+ return {"error": msg, "upgrade_url": "https://meok.ai/pricing"}
395
+
396
+ err = _check_rate_limit()
397
+ if err:
398
+ return {"error": err}
399
+ return store.acquire_files(agent_id, files, task_id, exclusive)
400
+
401
+
402
+ @mcp.tool()
403
+ def release_files(agent_id: str, files: list[str], api_key: str = "") -> dict:
404
+ """Release file locks held by an agent after task completion."""
405
+ allowed, msg, tier = check_access(api_key)
406
+ if not allowed:
407
+ return {"error": msg, "upgrade_url": "https://meok.ai/pricing"}
408
+
409
+ err = _check_rate_limit()
410
+ if err:
411
+ return {"error": err}
412
+ return store.release_files(agent_id, files)
413
+
414
+
415
+ @mcp.tool()
416
+ def start_sprint(name: str, goals: list[str], duration_minutes: int = 60, api_key: str = "") -> dict:
417
+ """Start a focused sprint with named goals and a time limit. Sprints help
418
+ agents coordinate on a set of objectives within a deadline."""
419
+ allowed, msg, tier = check_access(api_key)
420
+ if not allowed:
421
+ return {"error": msg, "upgrade_url": "https://meok.ai/pricing"}
422
+
423
+ err = _check_rate_limit()
424
+ if err:
425
+ return {"error": err}
426
+ return store.start_sprint(name, goals, duration_minutes)
427
+
428
+
429
+ @mcp.tool()
430
+ def complete_sprint(sprint_id: str, completed_goals: list[str] | None = None,
431
+ summary: str = "", api_key: str = "") -> dict:
432
+ """Complete a sprint and record which goals were achieved. Returns the
433
+ completion rate percentage."""
434
+ allowed, msg, tier = check_access(api_key)
435
+ if not allowed:
436
+ return {"error": msg, "upgrade_url": "https://meok.ai/pricing"}
437
+
438
+ err = _check_rate_limit()
439
+ if err:
440
+ return {"error": err}
441
+ return store.complete_sprint(sprint_id, completed_goals, summary)
442
+
443
+
444
+ @mcp.tool()
445
+ def get_dashboard(api_key: str = "") -> dict:
446
+ """Get the full orchestration dashboard: agent count, trust averages,
447
+ task breakdown by status, active sprints, file locks, and department distribution."""
448
+ allowed, msg, tier = check_access(api_key)
449
+ if not allowed:
450
+ return {"error": msg, "upgrade_url": "https://meok.ai/pricing"}
451
+
452
+ err = _check_rate_limit()
453
+ if err:
454
+ return {"error": err}
455
+ return store.get_dashboard()
456
+
457
+
458
+ @mcp.tool()
459
+ def get_task_queue(status: str | None = None, agent_id: str | None = None,
460
+ limit: int = 20, api_key: str = "") -> dict:
461
+ """Get the task queue, optionally filtered by status (assigned/completed/failed)
462
+ or agent. Returns tasks sorted by most recent."""
463
+ allowed, msg, tier = check_access(api_key)
464
+ if not allowed:
465
+ return {"error": msg, "upgrade_url": "https://meok.ai/pricing"}
466
+
467
+ err = _check_rate_limit()
468
+ if err:
469
+ return {"error": err}
470
+
471
+ tasks = []
472
+ for tid, task in sorted(store.tasks.items(),
473
+ key=lambda x: x[1].get("updated_at", ""), reverse=True):
474
+ if status and task.get("status") != status:
475
+ continue
476
+ if agent_id and task.get("agent_id") != agent_id:
477
+ continue
478
+ tasks.append(task)
479
+ if len(tasks) >= limit:
480
+ break
481
+
482
+ return {"tasks": tasks, "count": len(tasks)}
483
+
484
+
485
+ if __name__ == "__main__":
486
+ mcp.run()
@@ -0,0 +1,132 @@
1
+ name: agent-orchestrator-mcp
2
+ description: 'Multi-agent task management: create agents, delegate tasks with trust-based
3
+ routing, coordinate file'
4
+ version: 1.0.0
5
+ tools:
6
+ - name: create_agent
7
+ description: Create a new agent with a name, role, department, and capabilities.
8
+ parameters:
9
+ - name: name
10
+ type: string
11
+ required: true
12
+ - name: role
13
+ type: string
14
+ required: true
15
+ - name: department
16
+ type: string
17
+ required: false
18
+ - name: capabilities
19
+ type: array
20
+ required: false
21
+ - name: instructions
22
+ type: string
23
+ required: false
24
+ - name: list_agents
25
+ description: List all registered agents with their trust levels, task counts, and
26
+ status.
27
+ parameters:
28
+ - name: department
29
+ type: string
30
+ required: false
31
+ - name: delegate_task
32
+ description: Delegate a task to a specific agent or auto-route to the best match
33
+ parameters:
34
+ - name: task
35
+ type: string
36
+ required: true
37
+ - name: agent_id
38
+ type: string
39
+ required: false
40
+ - name: capability
41
+ type: string
42
+ required: false
43
+ - name: department
44
+ type: string
45
+ required: false
46
+ - name: priority
47
+ type: string
48
+ required: false
49
+ - name: care_score
50
+ type: number
51
+ required: false
52
+ - name: complete_task
53
+ description: Mark a task as completed (or failed). Updates the agent's trust level
54
+ parameters:
55
+ - name: task_id
56
+ type: string
57
+ required: true
58
+ - name: agent_id
59
+ type: string
60
+ required: true
61
+ - name: result_summary
62
+ type: string
63
+ required: true
64
+ - name: care_score
65
+ type: number
66
+ required: false
67
+ - name: success
68
+ type: boolean
69
+ required: false
70
+ - name: acquire_files
71
+ description: Acquire file locks for coordinated multi-agent work. Prevents conflicts
72
+ parameters:
73
+ - name: agent_id
74
+ type: string
75
+ required: true
76
+ - name: files
77
+ type: array
78
+ required: true
79
+ - name: task_id
80
+ type: string
81
+ required: true
82
+ - name: exclusive
83
+ type: boolean
84
+ required: false
85
+ - name: release_files
86
+ description: Release file locks held by an agent after task completion.
87
+ parameters:
88
+ - name: agent_id
89
+ type: string
90
+ required: true
91
+ - name: files
92
+ type: array
93
+ required: true
94
+ - name: start_sprint
95
+ description: Start a focused sprint with named goals and a time limit. Sprints help
96
+ parameters:
97
+ - name: name
98
+ type: string
99
+ required: true
100
+ - name: goals
101
+ type: array
102
+ required: true
103
+ - name: duration_minutes
104
+ type: integer
105
+ required: false
106
+ - name: complete_sprint
107
+ description: Complete a sprint and record which goals were achieved. Returns the
108
+ parameters:
109
+ - name: sprint_id
110
+ type: string
111
+ required: true
112
+ - name: completed_goals
113
+ type: array
114
+ required: false
115
+ - name: summary
116
+ type: string
117
+ required: false
118
+ - name: get_dashboard
119
+ description: 'Get the full orchestration dashboard: agent count, trust averages,'
120
+ parameters: []
121
+ - name: get_task_queue
122
+ description: Get the task queue, optionally filtered by status (assigned/completed/failed)
123
+ parameters:
124
+ - name: status
125
+ type: string
126
+ required: false
127
+ - name: agent_id
128
+ type: string
129
+ required: false
130
+ - name: limit
131
+ type: integer
132
+ required: false