universal-agent-context 0.2.0__py3-none-any.whl
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.
- uacs/__init__.py +12 -0
- uacs/adapters/__init__.py +19 -0
- uacs/adapters/agent_skill_adapter.py +202 -0
- uacs/adapters/agents_md_adapter.py +330 -0
- uacs/adapters/base.py +261 -0
- uacs/adapters/clinerules_adapter.py +39 -0
- uacs/adapters/cursorrules_adapter.py +39 -0
- uacs/api.py +262 -0
- uacs/cli/__init__.py +6 -0
- uacs/cli/context.py +349 -0
- uacs/cli/main.py +195 -0
- uacs/cli/mcp.py +115 -0
- uacs/cli/memory.py +142 -0
- uacs/cli/packages.py +309 -0
- uacs/cli/skills.py +144 -0
- uacs/cli/utils.py +24 -0
- uacs/config/repositories.yaml +26 -0
- uacs/context/__init__.py +0 -0
- uacs/context/agent_context.py +406 -0
- uacs/context/shared_context.py +661 -0
- uacs/context/unified_context.py +332 -0
- uacs/mcp_server_entry.py +80 -0
- uacs/memory/__init__.py +5 -0
- uacs/memory/simple_memory.py +255 -0
- uacs/packages/__init__.py +26 -0
- uacs/packages/manager.py +413 -0
- uacs/packages/models.py +60 -0
- uacs/packages/sources.py +270 -0
- uacs/protocols/__init__.py +5 -0
- uacs/protocols/mcp/__init__.py +8 -0
- uacs/protocols/mcp/manager.py +77 -0
- uacs/protocols/mcp/skills_server.py +700 -0
- uacs/skills_validator.py +367 -0
- uacs/utils/__init__.py +5 -0
- uacs/utils/paths.py +24 -0
- uacs/visualization/README.md +132 -0
- uacs/visualization/__init__.py +36 -0
- uacs/visualization/models.py +195 -0
- uacs/visualization/static/index.html +857 -0
- uacs/visualization/storage.py +402 -0
- uacs/visualization/visualization.py +328 -0
- uacs/visualization/web_server.py +364 -0
- universal_agent_context-0.2.0.dist-info/METADATA +873 -0
- universal_agent_context-0.2.0.dist-info/RECORD +47 -0
- universal_agent_context-0.2.0.dist-info/WHEEL +4 -0
- universal_agent_context-0.2.0.dist-info/entry_points.txt +2 -0
- universal_agent_context-0.2.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,700 @@
|
|
|
1
|
+
"""MCP Tools Server for Skills & Context Management.
|
|
2
|
+
|
|
3
|
+
Exposes all unified context capabilities as MCP tools following
|
|
4
|
+
the Model Context Protocol specification.
|
|
5
|
+
|
|
6
|
+
Spec: https://modelcontextprotocol.io/specification/
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import json
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import Any
|
|
12
|
+
|
|
13
|
+
from mcp.server import Server
|
|
14
|
+
from mcp.types import TextContent, Tool
|
|
15
|
+
|
|
16
|
+
# Initialize server
|
|
17
|
+
server = Server("uacs-mcp-server")
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@server.list_tools()
|
|
21
|
+
async def list_tools() -> list[Tool]:
|
|
22
|
+
"""List all available MCP tools."""
|
|
23
|
+
return [
|
|
24
|
+
# Skills Management
|
|
25
|
+
Tool(
|
|
26
|
+
name="skills_list",
|
|
27
|
+
description="List all available agent skills",
|
|
28
|
+
inputSchema={
|
|
29
|
+
"type": "object",
|
|
30
|
+
"properties": {
|
|
31
|
+
"skills_file": {
|
|
32
|
+
"type": "string",
|
|
33
|
+
"description": "Optional path to skills file or directory",
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
),
|
|
38
|
+
Tool(
|
|
39
|
+
name="skills_show",
|
|
40
|
+
description="Show detailed information about a specific skill",
|
|
41
|
+
inputSchema={
|
|
42
|
+
"type": "object",
|
|
43
|
+
"properties": {
|
|
44
|
+
"skill_name": {
|
|
45
|
+
"type": "string",
|
|
46
|
+
"description": "Name of the skill to show",
|
|
47
|
+
},
|
|
48
|
+
"skills_file": {
|
|
49
|
+
"type": "string",
|
|
50
|
+
"description": "Optional path to skills file or directory",
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
"required": ["skill_name"],
|
|
54
|
+
},
|
|
55
|
+
),
|
|
56
|
+
Tool(
|
|
57
|
+
name="skills_test_trigger",
|
|
58
|
+
description="Test which skill would be triggered by a query",
|
|
59
|
+
inputSchema={
|
|
60
|
+
"type": "object",
|
|
61
|
+
"properties": {
|
|
62
|
+
"query": {"type": "string", "description": "Query to test"},
|
|
63
|
+
"skills_file": {
|
|
64
|
+
"type": "string",
|
|
65
|
+
"description": "Optional path to skills file or directory",
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
"required": ["query"],
|
|
69
|
+
},
|
|
70
|
+
),
|
|
71
|
+
Tool(
|
|
72
|
+
name="skills_validate",
|
|
73
|
+
description="Validate agent skills file format",
|
|
74
|
+
inputSchema={
|
|
75
|
+
"type": "object",
|
|
76
|
+
"properties": {
|
|
77
|
+
"skills_file": {
|
|
78
|
+
"type": "string",
|
|
79
|
+
"description": "Path to skills file (SKILL.md or directory)",
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
),
|
|
84
|
+
# Context Management
|
|
85
|
+
Tool(
|
|
86
|
+
name="context_stats",
|
|
87
|
+
description="Get context and token usage statistics",
|
|
88
|
+
inputSchema={"type": "object", "properties": {}},
|
|
89
|
+
),
|
|
90
|
+
Tool(
|
|
91
|
+
name="context_get_compressed",
|
|
92
|
+
description="Get compressed context within token budget",
|
|
93
|
+
inputSchema={
|
|
94
|
+
"type": "object",
|
|
95
|
+
"properties": {
|
|
96
|
+
"agent": {
|
|
97
|
+
"type": "string",
|
|
98
|
+
"description": "Filter by agent name (optional)",
|
|
99
|
+
},
|
|
100
|
+
"max_tokens": {
|
|
101
|
+
"type": "integer",
|
|
102
|
+
"description": "Maximum tokens to return",
|
|
103
|
+
"default": 4000,
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
),
|
|
108
|
+
Tool(
|
|
109
|
+
name="context_add_entry",
|
|
110
|
+
description="Add a new context entry",
|
|
111
|
+
inputSchema={
|
|
112
|
+
"type": "object",
|
|
113
|
+
"properties": {
|
|
114
|
+
"content": {"type": "string", "description": "Context content"},
|
|
115
|
+
"agent": {"type": "string", "description": "Agent name"},
|
|
116
|
+
"references": {
|
|
117
|
+
"type": "array",
|
|
118
|
+
"items": {"type": "string"},
|
|
119
|
+
"description": "Referenced entry IDs",
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
"required": ["content", "agent"],
|
|
123
|
+
},
|
|
124
|
+
),
|
|
125
|
+
Tool(
|
|
126
|
+
name="context_compress",
|
|
127
|
+
description="Manually trigger context compression",
|
|
128
|
+
inputSchema={"type": "object", "properties": {}},
|
|
129
|
+
),
|
|
130
|
+
Tool(
|
|
131
|
+
name="context_graph",
|
|
132
|
+
description="Get context relationship graph",
|
|
133
|
+
inputSchema={"type": "object", "properties": {}},
|
|
134
|
+
),
|
|
135
|
+
# AGENTS.md Management
|
|
136
|
+
Tool(
|
|
137
|
+
name="agents_md_load",
|
|
138
|
+
description="Load and parse AGENTS.md file",
|
|
139
|
+
inputSchema={
|
|
140
|
+
"type": "object",
|
|
141
|
+
"properties": {
|
|
142
|
+
"project_root": {
|
|
143
|
+
"type": "string",
|
|
144
|
+
"description": "Project root directory",
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
),
|
|
149
|
+
Tool(
|
|
150
|
+
name="agents_md_to_prompt",
|
|
151
|
+
description="Convert AGENTS.md to system prompt",
|
|
152
|
+
inputSchema={
|
|
153
|
+
"type": "object",
|
|
154
|
+
"properties": {
|
|
155
|
+
"project_root": {
|
|
156
|
+
"type": "string",
|
|
157
|
+
"description": "Project root directory",
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
),
|
|
162
|
+
# Unified Context
|
|
163
|
+
Tool(
|
|
164
|
+
name="unified_build_prompt",
|
|
165
|
+
description="Build complete agent prompt with all context sources",
|
|
166
|
+
inputSchema={
|
|
167
|
+
"type": "object",
|
|
168
|
+
"properties": {
|
|
169
|
+
"user_query": {"type": "string", "description": "User's query"},
|
|
170
|
+
"agent_name": {
|
|
171
|
+
"type": "string",
|
|
172
|
+
"description": "Agent receiving the prompt",
|
|
173
|
+
},
|
|
174
|
+
"include_history": {
|
|
175
|
+
"type": "boolean",
|
|
176
|
+
"description": "Include shared context history",
|
|
177
|
+
"default": True,
|
|
178
|
+
},
|
|
179
|
+
"max_context_tokens": {
|
|
180
|
+
"type": "integer",
|
|
181
|
+
"description": "Max tokens for context",
|
|
182
|
+
"default": 4000,
|
|
183
|
+
},
|
|
184
|
+
},
|
|
185
|
+
"required": ["user_query", "agent_name"],
|
|
186
|
+
},
|
|
187
|
+
),
|
|
188
|
+
Tool(
|
|
189
|
+
name="unified_capabilities",
|
|
190
|
+
description="Get all unified capabilities (Agent Skills + AGENTS.md + Context)",
|
|
191
|
+
inputSchema={"type": "object", "properties": {}},
|
|
192
|
+
),
|
|
193
|
+
Tool(
|
|
194
|
+
name="unified_token_stats",
|
|
195
|
+
description="Get token usage statistics across all sources",
|
|
196
|
+
inputSchema={"type": "object", "properties": {}},
|
|
197
|
+
),
|
|
198
|
+
# Package Management
|
|
199
|
+
Tool(
|
|
200
|
+
name="install_package",
|
|
201
|
+
description="Install package from GitHub, Git URL, or local path",
|
|
202
|
+
inputSchema={
|
|
203
|
+
"type": "object",
|
|
204
|
+
"properties": {
|
|
205
|
+
"source": {
|
|
206
|
+
"type": "string",
|
|
207
|
+
"description": "Package source (owner/repo, git URL, or local path)",
|
|
208
|
+
},
|
|
209
|
+
"validate": {
|
|
210
|
+
"type": "boolean",
|
|
211
|
+
"description": "Whether to validate before installing",
|
|
212
|
+
"default": True,
|
|
213
|
+
},
|
|
214
|
+
},
|
|
215
|
+
"required": ["source"],
|
|
216
|
+
},
|
|
217
|
+
),
|
|
218
|
+
Tool(
|
|
219
|
+
name="list_installed_packages",
|
|
220
|
+
description="List all installed packages",
|
|
221
|
+
inputSchema={"type": "object", "properties": {}},
|
|
222
|
+
),
|
|
223
|
+
Tool(
|
|
224
|
+
name="validate_package",
|
|
225
|
+
description="Validate a package without installing",
|
|
226
|
+
inputSchema={
|
|
227
|
+
"type": "object",
|
|
228
|
+
"properties": {
|
|
229
|
+
"source": {
|
|
230
|
+
"type": "string",
|
|
231
|
+
"description": "Package source to validate",
|
|
232
|
+
},
|
|
233
|
+
},
|
|
234
|
+
"required": ["source"],
|
|
235
|
+
},
|
|
236
|
+
),
|
|
237
|
+
# Project Validation
|
|
238
|
+
Tool(
|
|
239
|
+
name="project_validate",
|
|
240
|
+
description="Validate AGENTS.md and agent skills configuration",
|
|
241
|
+
inputSchema={
|
|
242
|
+
"type": "object",
|
|
243
|
+
"properties": {
|
|
244
|
+
"project_root": {
|
|
245
|
+
"type": "string",
|
|
246
|
+
"description": "Project root directory",
|
|
247
|
+
},
|
|
248
|
+
"include_suggestions": {
|
|
249
|
+
"type": "boolean",
|
|
250
|
+
"description": "Include suggestions in report",
|
|
251
|
+
"default": True,
|
|
252
|
+
},
|
|
253
|
+
},
|
|
254
|
+
},
|
|
255
|
+
),
|
|
256
|
+
# Claude Code Context Retrieval
|
|
257
|
+
Tool(
|
|
258
|
+
name="uacs_search_context",
|
|
259
|
+
description="Search stored Claude Code conversations by topic or query",
|
|
260
|
+
inputSchema={
|
|
261
|
+
"type": "object",
|
|
262
|
+
"properties": {
|
|
263
|
+
"query": {
|
|
264
|
+
"type": "string",
|
|
265
|
+
"description": "What to search for in stored conversations",
|
|
266
|
+
},
|
|
267
|
+
"topics": {
|
|
268
|
+
"type": "array",
|
|
269
|
+
"items": {"type": "string"},
|
|
270
|
+
"description": "Filter by topics (e.g., security, performance, bug)",
|
|
271
|
+
},
|
|
272
|
+
"max_tokens": {
|
|
273
|
+
"type": "integer",
|
|
274
|
+
"description": "Maximum tokens to return",
|
|
275
|
+
"default": 4000,
|
|
276
|
+
},
|
|
277
|
+
},
|
|
278
|
+
"required": ["query"],
|
|
279
|
+
},
|
|
280
|
+
),
|
|
281
|
+
Tool(
|
|
282
|
+
name="uacs_list_topics",
|
|
283
|
+
description="List all topics in stored Claude Code conversations",
|
|
284
|
+
inputSchema={"type": "object", "properties": {}},
|
|
285
|
+
),
|
|
286
|
+
Tool(
|
|
287
|
+
name="uacs_get_recent_sessions",
|
|
288
|
+
description="Get most recent Claude Code sessions",
|
|
289
|
+
inputSchema={
|
|
290
|
+
"type": "object",
|
|
291
|
+
"properties": {
|
|
292
|
+
"limit": {
|
|
293
|
+
"type": "integer",
|
|
294
|
+
"description": "Number of recent sessions to return",
|
|
295
|
+
"default": 5,
|
|
296
|
+
}
|
|
297
|
+
},
|
|
298
|
+
},
|
|
299
|
+
),
|
|
300
|
+
]
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
@server.call_tool()
|
|
304
|
+
async def call_tool(name: str, arguments: dict[str, Any]) -> list[TextContent]:
|
|
305
|
+
"""Handle tool invocation."""
|
|
306
|
+
from uacs.adapters.agent_skill_adapter import AgentSkillAdapter
|
|
307
|
+
from uacs.adapters.agents_md_adapter import AgentsMDAdapter
|
|
308
|
+
from uacs.context.unified_context import UnifiedContextAdapter
|
|
309
|
+
from uacs.packages import PackageManager
|
|
310
|
+
from uacs.cli.utils import get_project_root
|
|
311
|
+
|
|
312
|
+
# Skills Management Tools
|
|
313
|
+
if name == "skills_list":
|
|
314
|
+
adapters = AgentSkillAdapter.discover_skills(get_project_root())
|
|
315
|
+
skills = [a.parsed.name for a in adapters if a.parsed]
|
|
316
|
+
return [TextContent(type="text", text=json.dumps({"skills": skills}, indent=2))]
|
|
317
|
+
|
|
318
|
+
if name == "skills_show":
|
|
319
|
+
adapters = AgentSkillAdapter.discover_skills(get_project_root())
|
|
320
|
+
skill_name = arguments["skill_name"]
|
|
321
|
+
for adapter in adapters:
|
|
322
|
+
if adapter.parsed and adapter.parsed.name == skill_name:
|
|
323
|
+
return [
|
|
324
|
+
TextContent(
|
|
325
|
+
type="text",
|
|
326
|
+
text=adapter.to_system_prompt(),
|
|
327
|
+
)
|
|
328
|
+
]
|
|
329
|
+
return [TextContent(type="text", text=f"Skill '{skill_name}' not found")]
|
|
330
|
+
|
|
331
|
+
if name == "skills_test_trigger":
|
|
332
|
+
adapters = AgentSkillAdapter.discover_skills(get_project_root())
|
|
333
|
+
query = arguments["query"].lower()
|
|
334
|
+
matched_skill = None
|
|
335
|
+
|
|
336
|
+
for adapter in adapters:
|
|
337
|
+
if adapter.parsed and hasattr(adapter.parsed, "triggers"):
|
|
338
|
+
for trigger in adapter.parsed.triggers:
|
|
339
|
+
if trigger.lower() in query or query in trigger.lower():
|
|
340
|
+
matched_skill = adapter.parsed
|
|
341
|
+
break
|
|
342
|
+
if matched_skill:
|
|
343
|
+
break
|
|
344
|
+
|
|
345
|
+
if matched_skill:
|
|
346
|
+
return [
|
|
347
|
+
TextContent(
|
|
348
|
+
type="text",
|
|
349
|
+
text=json.dumps(
|
|
350
|
+
{
|
|
351
|
+
"matched": True,
|
|
352
|
+
"skill_name": matched_skill.name,
|
|
353
|
+
"triggers": matched_skill.triggers,
|
|
354
|
+
},
|
|
355
|
+
indent=2,
|
|
356
|
+
),
|
|
357
|
+
)
|
|
358
|
+
]
|
|
359
|
+
return [TextContent(type="text", text=json.dumps({"matched": False}, indent=2))]
|
|
360
|
+
|
|
361
|
+
if name == "skills_validate":
|
|
362
|
+
adapters = AgentSkillAdapter.discover_skills(get_project_root())
|
|
363
|
+
issues = []
|
|
364
|
+
skill_count = 0
|
|
365
|
+
for adapter in adapters:
|
|
366
|
+
if adapter.parsed:
|
|
367
|
+
skill_count += 1
|
|
368
|
+
if not adapter.parsed.description:
|
|
369
|
+
issues.append(f"Skill '{adapter.parsed.name}': Missing description")
|
|
370
|
+
if (
|
|
371
|
+
not hasattr(adapter.parsed, "triggers")
|
|
372
|
+
or not adapter.parsed.triggers
|
|
373
|
+
):
|
|
374
|
+
issues.append(f"Skill '{adapter.parsed.name}': No triggers")
|
|
375
|
+
|
|
376
|
+
return [
|
|
377
|
+
TextContent(
|
|
378
|
+
type="text",
|
|
379
|
+
text=json.dumps(
|
|
380
|
+
{
|
|
381
|
+
"valid": len(issues) == 0,
|
|
382
|
+
"skill_count": skill_count,
|
|
383
|
+
"issues": issues,
|
|
384
|
+
},
|
|
385
|
+
indent=2,
|
|
386
|
+
),
|
|
387
|
+
)
|
|
388
|
+
]
|
|
389
|
+
|
|
390
|
+
# Context Management Tools
|
|
391
|
+
if name == "context_stats":
|
|
392
|
+
context_adapter = UnifiedContextAdapter()
|
|
393
|
+
stats = context_adapter.get_token_stats()
|
|
394
|
+
return [TextContent(type="text", text=json.dumps(stats, indent=2))]
|
|
395
|
+
|
|
396
|
+
if name == "context_get_compressed":
|
|
397
|
+
context_adapter = UnifiedContextAdapter()
|
|
398
|
+
context = context_adapter.shared_context.get_compressed_context(
|
|
399
|
+
agent=arguments.get("agent"), max_tokens=arguments.get("max_tokens", 4000)
|
|
400
|
+
)
|
|
401
|
+
return [TextContent(type="text", text=context)]
|
|
402
|
+
|
|
403
|
+
if name == "context_add_entry":
|
|
404
|
+
context_adapter = UnifiedContextAdapter()
|
|
405
|
+
entry_id = context_adapter.shared_context.add_entry(
|
|
406
|
+
content=arguments["content"],
|
|
407
|
+
agent=arguments["agent"],
|
|
408
|
+
references=arguments.get("references", []),
|
|
409
|
+
)
|
|
410
|
+
return [
|
|
411
|
+
TextContent(type="text", text=json.dumps({"entry_id": entry_id}, indent=2))
|
|
412
|
+
]
|
|
413
|
+
|
|
414
|
+
if name == "context_compress":
|
|
415
|
+
context_adapter = UnifiedContextAdapter()
|
|
416
|
+
before = context_adapter.shared_context.get_stats()
|
|
417
|
+
context_adapter.optimize_context()
|
|
418
|
+
after = context_adapter.shared_context.get_stats()
|
|
419
|
+
|
|
420
|
+
return [
|
|
421
|
+
TextContent(
|
|
422
|
+
type="text",
|
|
423
|
+
text=json.dumps(
|
|
424
|
+
{
|
|
425
|
+
"before_tokens": before["total_tokens"],
|
|
426
|
+
"after_tokens": after["total_tokens"],
|
|
427
|
+
"saved": before["total_tokens"] - after["total_tokens"],
|
|
428
|
+
},
|
|
429
|
+
indent=2,
|
|
430
|
+
),
|
|
431
|
+
)
|
|
432
|
+
]
|
|
433
|
+
|
|
434
|
+
if name == "context_graph":
|
|
435
|
+
context_adapter = UnifiedContextAdapter()
|
|
436
|
+
graph = context_adapter.shared_context.get_context_graph()
|
|
437
|
+
return [TextContent(type="text", text=json.dumps(graph, indent=2))]
|
|
438
|
+
|
|
439
|
+
# AGENTS.md Tools
|
|
440
|
+
if name == "agents_md_load":
|
|
441
|
+
agents_adapter = AgentsMDAdapter(
|
|
442
|
+
Path(arguments.get("project_root"))
|
|
443
|
+
if arguments.get("project_root")
|
|
444
|
+
else None
|
|
445
|
+
)
|
|
446
|
+
if agents_adapter.config:
|
|
447
|
+
return [
|
|
448
|
+
TextContent(
|
|
449
|
+
type="text",
|
|
450
|
+
text=json.dumps(agents_adapter.to_adk_capabilities(), indent=2),
|
|
451
|
+
)
|
|
452
|
+
]
|
|
453
|
+
return [TextContent(type="text", text="AGENTS.md not found")]
|
|
454
|
+
|
|
455
|
+
if name == "agents_md_to_prompt":
|
|
456
|
+
agents_adapter = AgentsMDAdapter(
|
|
457
|
+
Path(arguments.get("project_root"))
|
|
458
|
+
if arguments.get("project_root")
|
|
459
|
+
else None
|
|
460
|
+
)
|
|
461
|
+
prompt = agents_adapter.to_system_prompt()
|
|
462
|
+
return [TextContent(type="text", text=prompt)]
|
|
463
|
+
|
|
464
|
+
# Unified Context Tools
|
|
465
|
+
if name == "unified_build_prompt":
|
|
466
|
+
context_adapter = UnifiedContextAdapter()
|
|
467
|
+
prompt = context_adapter.build_agent_prompt(
|
|
468
|
+
user_query=arguments["user_query"],
|
|
469
|
+
agent_name=arguments["agent_name"],
|
|
470
|
+
include_history=arguments.get("include_history", True),
|
|
471
|
+
max_context_tokens=arguments.get("max_context_tokens", 4000),
|
|
472
|
+
)
|
|
473
|
+
return [TextContent(type="text", text=prompt)]
|
|
474
|
+
|
|
475
|
+
if name == "unified_capabilities":
|
|
476
|
+
context_adapter = UnifiedContextAdapter()
|
|
477
|
+
caps = context_adapter.get_unified_capabilities()
|
|
478
|
+
return [TextContent(type="text", text=json.dumps(caps, indent=2))]
|
|
479
|
+
|
|
480
|
+
if name == "unified_token_stats":
|
|
481
|
+
context_adapter = UnifiedContextAdapter()
|
|
482
|
+
stats = context_adapter.get_token_stats()
|
|
483
|
+
return [TextContent(type="text", text=json.dumps(stats, indent=2))]
|
|
484
|
+
|
|
485
|
+
# Package Management Tools
|
|
486
|
+
if name == "install_package":
|
|
487
|
+
project_path = get_project_root()
|
|
488
|
+
manager = PackageManager(project_path)
|
|
489
|
+
try:
|
|
490
|
+
package = manager.install(
|
|
491
|
+
arguments["source"],
|
|
492
|
+
validate=arguments.get("validate", True)
|
|
493
|
+
)
|
|
494
|
+
return [
|
|
495
|
+
TextContent(
|
|
496
|
+
type="text",
|
|
497
|
+
text=json.dumps(
|
|
498
|
+
{
|
|
499
|
+
"installed": True,
|
|
500
|
+
"package_name": package.name,
|
|
501
|
+
"version": package.version,
|
|
502
|
+
"path": str(package.path),
|
|
503
|
+
},
|
|
504
|
+
indent=2,
|
|
505
|
+
),
|
|
506
|
+
)
|
|
507
|
+
]
|
|
508
|
+
except Exception as e:
|
|
509
|
+
return [
|
|
510
|
+
TextContent(
|
|
511
|
+
type="text",
|
|
512
|
+
text=json.dumps(
|
|
513
|
+
{"installed": False, "error": str(e)},
|
|
514
|
+
indent=2,
|
|
515
|
+
),
|
|
516
|
+
)
|
|
517
|
+
]
|
|
518
|
+
|
|
519
|
+
if name == "list_installed_packages":
|
|
520
|
+
project_path = get_project_root()
|
|
521
|
+
manager = PackageManager(project_path)
|
|
522
|
+
packages = manager.list_installed()
|
|
523
|
+
return [
|
|
524
|
+
TextContent(
|
|
525
|
+
type="text",
|
|
526
|
+
text=json.dumps(
|
|
527
|
+
[
|
|
528
|
+
{
|
|
529
|
+
"name": pkg.name,
|
|
530
|
+
"version": pkg.version,
|
|
531
|
+
"source": pkg.source,
|
|
532
|
+
"path": str(pkg.path),
|
|
533
|
+
}
|
|
534
|
+
for pkg in packages
|
|
535
|
+
],
|
|
536
|
+
indent=2,
|
|
537
|
+
),
|
|
538
|
+
)
|
|
539
|
+
]
|
|
540
|
+
|
|
541
|
+
if name == "validate_package":
|
|
542
|
+
project_path = get_project_root()
|
|
543
|
+
manager = PackageManager(project_path)
|
|
544
|
+
try:
|
|
545
|
+
is_valid = manager.validate(arguments["source"])
|
|
546
|
+
return [
|
|
547
|
+
TextContent(
|
|
548
|
+
type="text",
|
|
549
|
+
text=json.dumps(
|
|
550
|
+
{"valid": is_valid},
|
|
551
|
+
indent=2,
|
|
552
|
+
),
|
|
553
|
+
)
|
|
554
|
+
]
|
|
555
|
+
except Exception as e:
|
|
556
|
+
return [
|
|
557
|
+
TextContent(
|
|
558
|
+
type="text",
|
|
559
|
+
text=json.dumps(
|
|
560
|
+
{"valid": False, "error": str(e)},
|
|
561
|
+
indent=2,
|
|
562
|
+
),
|
|
563
|
+
)
|
|
564
|
+
]
|
|
565
|
+
|
|
566
|
+
# Project Validation
|
|
567
|
+
if name == "project_validate":
|
|
568
|
+
# Note: ProjectValidator not yet extracted, will be done in future phase
|
|
569
|
+
return [
|
|
570
|
+
TextContent(
|
|
571
|
+
type="text",
|
|
572
|
+
text=json.dumps(
|
|
573
|
+
{"error": "ProjectValidator not yet available in UACS"}, indent=2
|
|
574
|
+
),
|
|
575
|
+
)
|
|
576
|
+
]
|
|
577
|
+
|
|
578
|
+
# Claude Code Context Retrieval Tools
|
|
579
|
+
if name == "uacs_search_context":
|
|
580
|
+
context_adapter = UnifiedContextAdapter()
|
|
581
|
+
query = arguments["query"]
|
|
582
|
+
topics = arguments.get("topics")
|
|
583
|
+
max_tokens = arguments.get("max_tokens", 4000)
|
|
584
|
+
|
|
585
|
+
# Use focused context if topics provided, otherwise compressed context
|
|
586
|
+
if topics and len(topics) > 0:
|
|
587
|
+
context = context_adapter.shared_context.get_focused_context(
|
|
588
|
+
topics=topics, max_tokens=max_tokens
|
|
589
|
+
)
|
|
590
|
+
else:
|
|
591
|
+
context = context_adapter.shared_context.get_compressed_context(
|
|
592
|
+
max_tokens=max_tokens
|
|
593
|
+
)
|
|
594
|
+
|
|
595
|
+
if not context or len(context.strip()) == 0:
|
|
596
|
+
return [
|
|
597
|
+
TextContent(
|
|
598
|
+
type="text",
|
|
599
|
+
text=json.dumps(
|
|
600
|
+
{
|
|
601
|
+
"found": False,
|
|
602
|
+
"message": f"No stored conversations found for: {query}",
|
|
603
|
+
},
|
|
604
|
+
indent=2,
|
|
605
|
+
),
|
|
606
|
+
)
|
|
607
|
+
]
|
|
608
|
+
|
|
609
|
+
return [
|
|
610
|
+
TextContent(
|
|
611
|
+
type="text",
|
|
612
|
+
text=json.dumps(
|
|
613
|
+
{
|
|
614
|
+
"found": True,
|
|
615
|
+
"query": query,
|
|
616
|
+
"topics": topics,
|
|
617
|
+
"context": context,
|
|
618
|
+
"tokens": context_adapter.shared_context.count_tokens(context),
|
|
619
|
+
},
|
|
620
|
+
indent=2,
|
|
621
|
+
),
|
|
622
|
+
)
|
|
623
|
+
]
|
|
624
|
+
|
|
625
|
+
if name == "uacs_list_topics":
|
|
626
|
+
context_adapter = UnifiedContextAdapter()
|
|
627
|
+
|
|
628
|
+
# Get all unique topics from entries
|
|
629
|
+
topics = set()
|
|
630
|
+
for entry in context_adapter.shared_context.entries.values():
|
|
631
|
+
if entry.topics:
|
|
632
|
+
topics.update(entry.topics)
|
|
633
|
+
|
|
634
|
+
return [
|
|
635
|
+
TextContent(
|
|
636
|
+
type="text",
|
|
637
|
+
text=json.dumps(
|
|
638
|
+
{"topics": sorted(list(topics)), "count": len(topics)}, indent=2
|
|
639
|
+
),
|
|
640
|
+
)
|
|
641
|
+
]
|
|
642
|
+
|
|
643
|
+
if name == "uacs_get_recent_sessions":
|
|
644
|
+
context_adapter = UnifiedContextAdapter()
|
|
645
|
+
limit = arguments.get("limit", 5)
|
|
646
|
+
|
|
647
|
+
# Get entries sorted by timestamp (most recent first)
|
|
648
|
+
all_entries = list(context_adapter.shared_context.entries.values())
|
|
649
|
+
all_entries.sort(key=lambda e: e.timestamp, reverse=True)
|
|
650
|
+
|
|
651
|
+
# Filter for Claude Code sessions
|
|
652
|
+
sessions = []
|
|
653
|
+
seen_sessions = set()
|
|
654
|
+
|
|
655
|
+
for entry in all_entries:
|
|
656
|
+
if len(sessions) >= limit:
|
|
657
|
+
break
|
|
658
|
+
|
|
659
|
+
# Check if from Claude Code hook
|
|
660
|
+
if entry.metadata and entry.metadata.get("source") == "claude-code-hook":
|
|
661
|
+
session_id = entry.metadata.get("session_id")
|
|
662
|
+
if session_id and session_id not in seen_sessions:
|
|
663
|
+
seen_sessions.add(session_id)
|
|
664
|
+
sessions.append({
|
|
665
|
+
"session_id": session_id,
|
|
666
|
+
"timestamp": entry.timestamp,
|
|
667
|
+
"topics": entry.topics,
|
|
668
|
+
"turn_count": entry.metadata.get("turn_count", 0),
|
|
669
|
+
"preview": entry.content[:200] + "..." if len(entry.content) > 200 else entry.content
|
|
670
|
+
})
|
|
671
|
+
|
|
672
|
+
return [
|
|
673
|
+
TextContent(
|
|
674
|
+
type="text",
|
|
675
|
+
text=json.dumps(
|
|
676
|
+
{"sessions": sessions, "count": len(sessions)}, indent=2
|
|
677
|
+
),
|
|
678
|
+
)
|
|
679
|
+
]
|
|
680
|
+
|
|
681
|
+
return [TextContent(type="text", text=f"Unknown tool: {name}")]
|
|
682
|
+
|
|
683
|
+
|
|
684
|
+
async def main():
|
|
685
|
+
"""Run MCP server."""
|
|
686
|
+
from mcp.server.stdio import stdio_server
|
|
687
|
+
|
|
688
|
+
async with stdio_server() as (read_stream, write_stream):
|
|
689
|
+
await server.run(
|
|
690
|
+
read_stream, write_stream, server.create_initialization_options()
|
|
691
|
+
)
|
|
692
|
+
|
|
693
|
+
|
|
694
|
+
if __name__ == "__main__":
|
|
695
|
+
import asyncio
|
|
696
|
+
|
|
697
|
+
asyncio.run(main())
|
|
698
|
+
|
|
699
|
+
|
|
700
|
+
__all__ = ["server", "main"]
|