loopctl-mcp-server 1.4.0 → 1.6.0
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.
- package/README.md +11 -2
- package/index.js +169 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
MCP (Model Context Protocol) server for [loopctl](https://loopctl.com) -- structural trust for AI development loops.
|
|
4
4
|
|
|
5
|
-
Wraps the loopctl REST API into
|
|
5
|
+
Wraps the loopctl REST API into 41 typed MCP tools so AI coding agents (Claude Code, etc.) can interact with loopctl without writing curl commands.
|
|
6
6
|
|
|
7
7
|
## Installation
|
|
8
8
|
|
|
@@ -66,7 +66,7 @@ Or if installed locally:
|
|
|
66
66
|
|
|
67
67
|
Key resolution priority: `LOOPCTL_API_KEY` > tool-specific key > `LOOPCTL_ORCH_KEY`.
|
|
68
68
|
|
|
69
|
-
## Tools (
|
|
69
|
+
## Tools (41)
|
|
70
70
|
|
|
71
71
|
### Project Tools
|
|
72
72
|
|
|
@@ -149,6 +149,15 @@ Key resolution priority: `LOOPCTL_API_KEY` > tool-specific key > `LOOPCTL_ORCH_K
|
|
|
149
149
|
| `knowledge_ingest_batch` | Submit up to 50 ingestion items in a single request. Each item has the same shape as `knowledge_ingest`. Returns per-item results. Required: `items`. Optional: batch-level `project_id` default. |
|
|
150
150
|
| `knowledge_ingestion_jobs` | List recent content ingestion jobs (last 7 days, max 50). |
|
|
151
151
|
|
|
152
|
+
### Knowledge Analytics Tools (orchestrator key)
|
|
153
|
+
|
|
154
|
+
| Tool | Description |
|
|
155
|
+
|---|---|
|
|
156
|
+
| `knowledge_analytics_top` | Top accessed knowledge articles for the tenant. Optional: `limit` (default 20, max 100), `since_days` (default 7), `access_type` (`search`, `get`, `context`, `index`). |
|
|
157
|
+
| `knowledge_article_stats` | Per-article usage stats: total accesses, unique agents, by-type breakdown, recent events. Required: `article_id`. |
|
|
158
|
+
| `knowledge_agent_usage` | Per-agent (api_key) knowledge usage: total reads, unique articles, top read articles. Required: `agent_id`. Optional: `limit`, `since_days`. |
|
|
159
|
+
| `knowledge_unused_articles` | Published articles with zero accesses in the window. Optional: `days_unused` (default 30), `limit` (default 50, max 200). |
|
|
160
|
+
|
|
152
161
|
### Discovery Tools
|
|
153
162
|
|
|
154
163
|
| Tool | Description |
|
package/index.js
CHANGED
|
@@ -159,11 +159,12 @@ async function listProjects() {
|
|
|
159
159
|
return toContent(result);
|
|
160
160
|
}
|
|
161
161
|
|
|
162
|
-
async function createProject({ name, slug, repo_url, description, tech_stack }) {
|
|
162
|
+
async function createProject({ name, slug, repo_url, description, tech_stack, mission }) {
|
|
163
163
|
const body = { name, slug };
|
|
164
164
|
if (repo_url) body.repo_url = repo_url;
|
|
165
165
|
if (description) body.description = description;
|
|
166
166
|
if (tech_stack) body.tech_stack = tech_stack;
|
|
167
|
+
if (mission) body.mission = mission;
|
|
167
168
|
const result = await apiCall("POST", "/api/v1/projects", body, process.env.LOOPCTL_ORCH_KEY);
|
|
168
169
|
return toContent(result);
|
|
169
170
|
}
|
|
@@ -528,6 +529,55 @@ async function knowledgeIngestionJobs() {
|
|
|
528
529
|
return toContent(result);
|
|
529
530
|
}
|
|
530
531
|
|
|
532
|
+
// --- Knowledge Analytics Tools (orch key) ---
|
|
533
|
+
|
|
534
|
+
async function knowledgeAnalyticsTop({ limit, since_days, access_type } = {}) {
|
|
535
|
+
const params = new URLSearchParams();
|
|
536
|
+
if (limit != null) params.set("limit", String(limit));
|
|
537
|
+
if (since_days != null) params.set("since_days", String(since_days));
|
|
538
|
+
if (access_type) params.set("access_type", access_type);
|
|
539
|
+
const qs = params.toString();
|
|
540
|
+
const path = qs
|
|
541
|
+
? `/api/v1/knowledge/analytics/top-articles?${qs}`
|
|
542
|
+
: "/api/v1/knowledge/analytics/top-articles";
|
|
543
|
+
const result = await apiCall("GET", path, null, process.env.LOOPCTL_ORCH_KEY);
|
|
544
|
+
return toContent(result);
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
async function knowledgeArticleStats({ article_id }) {
|
|
548
|
+
const result = await apiCall(
|
|
549
|
+
"GET",
|
|
550
|
+
`/api/v1/knowledge/articles/${article_id}/stats`,
|
|
551
|
+
null,
|
|
552
|
+
process.env.LOOPCTL_ORCH_KEY
|
|
553
|
+
);
|
|
554
|
+
return toContent(result);
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
async function knowledgeAgentUsage({ agent_id, limit, since_days } = {}) {
|
|
558
|
+
const params = new URLSearchParams();
|
|
559
|
+
if (limit != null) params.set("limit", String(limit));
|
|
560
|
+
if (since_days != null) params.set("since_days", String(since_days));
|
|
561
|
+
const qs = params.toString();
|
|
562
|
+
const path = qs
|
|
563
|
+
? `/api/v1/knowledge/analytics/agents/${agent_id}?${qs}`
|
|
564
|
+
: `/api/v1/knowledge/analytics/agents/${agent_id}`;
|
|
565
|
+
const result = await apiCall("GET", path, null, process.env.LOOPCTL_ORCH_KEY);
|
|
566
|
+
return toContent(result);
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
async function knowledgeUnusedArticles({ days_unused, limit } = {}) {
|
|
570
|
+
const params = new URLSearchParams();
|
|
571
|
+
if (days_unused != null) params.set("days_unused", String(days_unused));
|
|
572
|
+
if (limit != null) params.set("limit", String(limit));
|
|
573
|
+
const qs = params.toString();
|
|
574
|
+
const path = qs
|
|
575
|
+
? `/api/v1/knowledge/analytics/unused-articles?${qs}`
|
|
576
|
+
: "/api/v1/knowledge/analytics/unused-articles";
|
|
577
|
+
const result = await apiCall("GET", path, null, process.env.LOOPCTL_ORCH_KEY);
|
|
578
|
+
return toContent(result);
|
|
579
|
+
}
|
|
580
|
+
|
|
531
581
|
async function knowledgeExport({ project_id }) {
|
|
532
582
|
const basePath = project_id
|
|
533
583
|
? `/api/v1/projects/${project_id}/knowledge/export`
|
|
@@ -588,6 +638,11 @@ const TOOLS = [
|
|
|
588
638
|
repo_url: { type: "string", description: "GitHub repo URL." },
|
|
589
639
|
description: { type: "string", description: "Project description." },
|
|
590
640
|
tech_stack: { type: "string", description: "Tech stack summary." },
|
|
641
|
+
mission: {
|
|
642
|
+
type: "string",
|
|
643
|
+
description:
|
|
644
|
+
"Optional project mission/goal statement that cascades into story context. Surfaces in get_story responses as project_mission so agents see the why without a second fetch. Max 2000 chars.",
|
|
645
|
+
},
|
|
591
646
|
},
|
|
592
647
|
required: ["name", "slug"],
|
|
593
648
|
},
|
|
@@ -1437,6 +1492,106 @@ const TOOLS = [
|
|
|
1437
1492
|
},
|
|
1438
1493
|
},
|
|
1439
1494
|
|
|
1495
|
+
// Knowledge Analytics Tools (orchestrator key)
|
|
1496
|
+
{
|
|
1497
|
+
name: "knowledge_analytics_top",
|
|
1498
|
+
description:
|
|
1499
|
+
"Return the top accessed knowledge articles for the tenant. " +
|
|
1500
|
+
"Use to identify which articles agents actually read. Requires orchestrator role.",
|
|
1501
|
+
inputSchema: {
|
|
1502
|
+
type: "object",
|
|
1503
|
+
properties: {
|
|
1504
|
+
limit: {
|
|
1505
|
+
type: "integer",
|
|
1506
|
+
description: "Max rows to return. Default 20, max 100.",
|
|
1507
|
+
minimum: 1,
|
|
1508
|
+
maximum: 100,
|
|
1509
|
+
},
|
|
1510
|
+
since_days: {
|
|
1511
|
+
type: "integer",
|
|
1512
|
+
description: "Look back this many days. Default 7.",
|
|
1513
|
+
minimum: 1,
|
|
1514
|
+
maximum: 365,
|
|
1515
|
+
},
|
|
1516
|
+
access_type: {
|
|
1517
|
+
type: "string",
|
|
1518
|
+
enum: ["search", "get", "context", "index"],
|
|
1519
|
+
description: "Optional: restrict to a single access type.",
|
|
1520
|
+
},
|
|
1521
|
+
},
|
|
1522
|
+
required: [],
|
|
1523
|
+
},
|
|
1524
|
+
},
|
|
1525
|
+
{
|
|
1526
|
+
name: "knowledge_article_stats",
|
|
1527
|
+
description:
|
|
1528
|
+
"Return per-article usage statistics: total accesses, unique agents, " +
|
|
1529
|
+
"by-type breakdown, and the 10 most recent events. Requires orchestrator role.",
|
|
1530
|
+
inputSchema: {
|
|
1531
|
+
type: "object",
|
|
1532
|
+
properties: {
|
|
1533
|
+
article_id: {
|
|
1534
|
+
type: "string",
|
|
1535
|
+
description: "The UUID of the article to inspect.",
|
|
1536
|
+
},
|
|
1537
|
+
},
|
|
1538
|
+
required: ["article_id"],
|
|
1539
|
+
},
|
|
1540
|
+
},
|
|
1541
|
+
{
|
|
1542
|
+
name: "knowledge_agent_usage",
|
|
1543
|
+
description:
|
|
1544
|
+
"Return knowledge usage for a specific agent (api_key): total reads, " +
|
|
1545
|
+
"unique articles, access type breakdown, and top read articles. " +
|
|
1546
|
+
"Requires orchestrator role.",
|
|
1547
|
+
inputSchema: {
|
|
1548
|
+
type: "object",
|
|
1549
|
+
properties: {
|
|
1550
|
+
agent_id: {
|
|
1551
|
+
type: "string",
|
|
1552
|
+
description: "API key UUID identifying the agent identity.",
|
|
1553
|
+
},
|
|
1554
|
+
limit: {
|
|
1555
|
+
type: "integer",
|
|
1556
|
+
description: "Max top articles to return. Default 20, max 100.",
|
|
1557
|
+
minimum: 1,
|
|
1558
|
+
maximum: 100,
|
|
1559
|
+
},
|
|
1560
|
+
since_days: {
|
|
1561
|
+
type: "integer",
|
|
1562
|
+
description: "Look back this many days. Default 7.",
|
|
1563
|
+
minimum: 1,
|
|
1564
|
+
maximum: 365,
|
|
1565
|
+
},
|
|
1566
|
+
},
|
|
1567
|
+
required: ["agent_id"],
|
|
1568
|
+
},
|
|
1569
|
+
},
|
|
1570
|
+
{
|
|
1571
|
+
name: "knowledge_unused_articles",
|
|
1572
|
+
description:
|
|
1573
|
+
"Return published articles that have not been accessed in the configured " +
|
|
1574
|
+
"time window. Use to identify dead-weight knowledge. Requires orchestrator role.",
|
|
1575
|
+
inputSchema: {
|
|
1576
|
+
type: "object",
|
|
1577
|
+
properties: {
|
|
1578
|
+
days_unused: {
|
|
1579
|
+
type: "integer",
|
|
1580
|
+
description: "Window length in days. Default 30.",
|
|
1581
|
+
minimum: 1,
|
|
1582
|
+
maximum: 365,
|
|
1583
|
+
},
|
|
1584
|
+
limit: {
|
|
1585
|
+
type: "integer",
|
|
1586
|
+
description: "Max rows to return. Default 50, max 200.",
|
|
1587
|
+
minimum: 1,
|
|
1588
|
+
maximum: 200,
|
|
1589
|
+
},
|
|
1590
|
+
},
|
|
1591
|
+
required: [],
|
|
1592
|
+
},
|
|
1593
|
+
},
|
|
1594
|
+
|
|
1440
1595
|
// Discovery Tools
|
|
1441
1596
|
{
|
|
1442
1597
|
name: "list_routes",
|
|
@@ -1589,6 +1744,19 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1589
1744
|
case "knowledge_ingestion_jobs":
|
|
1590
1745
|
return await knowledgeIngestionJobs();
|
|
1591
1746
|
|
|
1747
|
+
// Knowledge Analytics Tools
|
|
1748
|
+
case "knowledge_analytics_top":
|
|
1749
|
+
return await knowledgeAnalyticsTop(args);
|
|
1750
|
+
|
|
1751
|
+
case "knowledge_article_stats":
|
|
1752
|
+
return await knowledgeArticleStats(args);
|
|
1753
|
+
|
|
1754
|
+
case "knowledge_agent_usage":
|
|
1755
|
+
return await knowledgeAgentUsage(args);
|
|
1756
|
+
|
|
1757
|
+
case "knowledge_unused_articles":
|
|
1758
|
+
return await knowledgeUnusedArticles(args);
|
|
1759
|
+
|
|
1592
1760
|
// Discovery Tools
|
|
1593
1761
|
case "list_routes":
|
|
1594
1762
|
return await listRoutes();
|