tokrepo-mcp-server 2.6.0 → 2.8.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 +25 -1
- package/bin/server.js +129 -3
- package/package.json +11 -4
package/README.md
CHANGED
|
@@ -42,6 +42,9 @@ Once connected, your AI assistant can:
|
|
|
42
42
|
- **Plan before install** — get install plan v2 with policy decisions, rollback, and verification
|
|
43
43
|
- **Safe Codex install** — dry-run by default; risky assets must be staged or explicitly approved
|
|
44
44
|
- **Lifecycle control** — list, update, uninstall, and roll back managed Codex installs
|
|
45
|
+
- **Project memory** — pair with `tokrepo init-agent --target all` so future agents know to call TokRepo during planning
|
|
46
|
+
- **Discovery surfaces** — official MCP `server.json`, `.well-known`, `llms.txt`, and npm metadata are kept machine-readable for agents and registries
|
|
47
|
+
- **Funnel visibility** — anonymous aggregate events show whether agents actually discover, plan, install, hand off, and push reusable assets
|
|
45
48
|
|
|
46
49
|
## Available Tools
|
|
47
50
|
|
|
@@ -73,6 +76,27 @@ AI: [calls tokrepo_codex_install with dry_run=false, confirm=true] → Writes on
|
|
|
73
76
|
AI: [calls tokrepo_rollback with dry_run=true] → Shows exactly what would be removed before rollback
|
|
74
77
|
```
|
|
75
78
|
|
|
79
|
+
## Make Future Agents Discover TokRepo
|
|
80
|
+
|
|
81
|
+
Run this once in a project:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
npx tokrepo init-agent --target all
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
It writes managed instructions to `AGENTS.md`, `CLAUDE.md`, `GEMINI.md`, Cursor rules, and `.mcp.json`. The rule is simple: during planning, when the agent sees a capability gap, it should call `tokrepo_discover` before inventing a one-off local tool. After a task, agents can run `tokrepo agent-handoff --json` to suggest reusable files for user-confirmed private publishing.
|
|
88
|
+
|
|
89
|
+
## Machine-Readable Listing
|
|
90
|
+
|
|
91
|
+
Registries and agents can discover this server through:
|
|
92
|
+
|
|
93
|
+
- MCP server manifest: [tokrepo.com/.well-known/mcp/server.json](https://tokrepo.com/.well-known/mcp/server.json)
|
|
94
|
+
- TokRepo manifest: [tokrepo.com/.well-known/tokrepo.json](https://tokrepo.com/.well-known/tokrepo.json)
|
|
95
|
+
- Agent instructions: [tokrepo.com/agent-instructions/tokrepo.md](https://tokrepo.com/agent-instructions/tokrepo.md)
|
|
96
|
+
- LLM crawler entry: [tokrepo.com/llms.txt](https://tokrepo.com/llms.txt)
|
|
97
|
+
|
|
98
|
+
TokRepo emits anonymous aggregate funnel events for `tokrepo_discover`, `tokrepo_install_plan`, install dry-runs, installs, handoffs, and pushes. It does not send task text or file contents. Disable with `TOKREPO_TELEMETRY=0`.
|
|
99
|
+
|
|
76
100
|
## Why TokRepo?
|
|
77
101
|
|
|
78
102
|
TokRepo is the **open registry for AI assets** — like npm for packages, but for AI skills, prompts, MCP configs, and workflows.
|
|
@@ -91,7 +115,7 @@ TokRepo is the **open registry for AI assets** — like npm for packages, but fo
|
|
|
91
115
|
|
|
92
116
|
- **Website**: [tokrepo.com](https://tokrepo.com)
|
|
93
117
|
- **CLI**: [npm: tokrepo](https://www.npmjs.com/package/tokrepo)
|
|
94
|
-
- **GitHub**: [tokrepo
|
|
118
|
+
- **GitHub**: [henu-wang/tokrepo-mcp-server](https://github.com/henu-wang/tokrepo-mcp-server)
|
|
95
119
|
- **API**: [tokrepo.com/.well-known/tokrepo.json](https://tokrepo.com/.well-known/tokrepo.json)
|
|
96
120
|
|
|
97
121
|
## License
|
package/bin/server.js
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
const https = require('https');
|
|
15
|
+
const http = require('http');
|
|
15
16
|
const crypto = require('crypto');
|
|
16
17
|
const { execFile } = require('child_process');
|
|
17
18
|
|
|
@@ -19,7 +20,7 @@ const API_BASE = process.env.TOKREPO_API || 'https://api.tokrepo.com';
|
|
|
19
20
|
const TOKREPO_URL = 'https://tokrepo.com';
|
|
20
21
|
const TOKREPO_TOKEN = process.env.TOKREPO_TOKEN || '';
|
|
21
22
|
const TOKREPO_CLI = process.env.TOKREPO_CLI || '';
|
|
22
|
-
const SERVER_VERSION = '2.
|
|
23
|
+
const SERVER_VERSION = '2.8.0';
|
|
23
24
|
|
|
24
25
|
// ─── MCP Protocol (JSON-RPC over stdio) ───
|
|
25
26
|
|
|
@@ -524,6 +525,72 @@ function apiPost(urlPath, body, token) {
|
|
|
524
525
|
});
|
|
525
526
|
}
|
|
526
527
|
|
|
528
|
+
function telemetryDisabled() {
|
|
529
|
+
const value = String(process.env.TOKREPO_TELEMETRY || '').toLowerCase();
|
|
530
|
+
return ['0', 'false', 'off', 'no'].includes(value);
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
function eventForTool(name, args = {}) {
|
|
534
|
+
if (name === 'tokrepo_discover') return 'mcp_discover';
|
|
535
|
+
if (name === 'tokrepo_search') return 'mcp_search';
|
|
536
|
+
if (name === 'tokrepo_detail') return 'mcp_detail';
|
|
537
|
+
if (name === 'tokrepo_install_plan') return 'install_plan';
|
|
538
|
+
if (name === 'tokrepo_codex_install') return args.dry_run === false ? 'install_apply' : 'install_dry_run';
|
|
539
|
+
if (name === 'tokrepo_push') return 'push';
|
|
540
|
+
return '';
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
function candidateCountFromResult(result) {
|
|
544
|
+
const text = result?.content?.map(item => item.text || '').join('\n') || '';
|
|
545
|
+
return (text.match(/"uuid"\s*:/g) || []).length;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
function trackAgentEventForTool(name, args = {}, result = {}) {
|
|
549
|
+
if (telemetryDisabled()) return;
|
|
550
|
+
const event = eventForTool(name, args);
|
|
551
|
+
if (!event) return;
|
|
552
|
+
try {
|
|
553
|
+
const url = new URL('/api/v1/tokenboard/agent/events', API_BASE);
|
|
554
|
+
if (url.protocol === 'http:' && !url.hostname.match(/^(localhost|127\.0\.0\.1)$/)) {
|
|
555
|
+
url.protocol = 'https:';
|
|
556
|
+
}
|
|
557
|
+
const body = JSON.stringify({
|
|
558
|
+
event,
|
|
559
|
+
source: 'mcp',
|
|
560
|
+
version: SERVER_VERSION,
|
|
561
|
+
target: args.target || args?.constraints?.target || 'any',
|
|
562
|
+
kind: args.kind || args?.constraints?.kind || '',
|
|
563
|
+
policy: args.policy || args?.constraints?.policy || '',
|
|
564
|
+
result: result?.isError ? 'error' : 'pass',
|
|
565
|
+
dry_run: name === 'tokrepo_codex_install' ? args.dry_run !== false : undefined,
|
|
566
|
+
candidate_count: candidateCountFromResult(result),
|
|
567
|
+
});
|
|
568
|
+
const isHttps = url.protocol === 'https:';
|
|
569
|
+
const mod = isHttps ? https : http;
|
|
570
|
+
const req = mod.request({
|
|
571
|
+
hostname: url.hostname,
|
|
572
|
+
port: url.port || (isHttps ? 443 : 80),
|
|
573
|
+
path: url.pathname,
|
|
574
|
+
method: 'POST',
|
|
575
|
+
headers: {
|
|
576
|
+
'Content-Type': 'application/json',
|
|
577
|
+
'Content-Length': Buffer.byteLength(body),
|
|
578
|
+
'User-Agent': `tokrepo-mcp-server/${SERVER_VERSION}`,
|
|
579
|
+
},
|
|
580
|
+
timeout: 700,
|
|
581
|
+
}, (res) => {
|
|
582
|
+
res.resume();
|
|
583
|
+
});
|
|
584
|
+
req.on('socket', socket => socket.unref?.());
|
|
585
|
+
req.on('error', () => {});
|
|
586
|
+
req.on('timeout', () => req.destroy());
|
|
587
|
+
req.write(body);
|
|
588
|
+
req.end();
|
|
589
|
+
} catch {
|
|
590
|
+
// Telemetry is best-effort only.
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
|
|
527
594
|
function apiGetAuth(urlPath, token) {
|
|
528
595
|
return new Promise((resolve, reject) => {
|
|
529
596
|
const url = new URL(urlPath, API_BASE);
|
|
@@ -701,7 +768,60 @@ function buildDiscoveryQuery(task, environment, constraints) {
|
|
|
701
768
|
return compactText([...new Set(parts)].join(' '), 100);
|
|
702
769
|
}
|
|
703
770
|
|
|
704
|
-
function
|
|
771
|
+
function scoreDiscoveryCandidate(item, task, target, constraints = {}) {
|
|
772
|
+
const metadata = itemAgentMetadata(item);
|
|
773
|
+
const fit = itemAgentFit(item);
|
|
774
|
+
const tags = itemTags(item);
|
|
775
|
+
const targets = candidateTargets(item, metadata);
|
|
776
|
+
const terms = extractSearchTerms(task, 10);
|
|
777
|
+
const haystack = [
|
|
778
|
+
item.title,
|
|
779
|
+
item.description,
|
|
780
|
+
tags.join(' '),
|
|
781
|
+
metadata.entrypoint,
|
|
782
|
+
metadata.asset_kind,
|
|
783
|
+
].filter(Boolean).join(' ').toLowerCase();
|
|
784
|
+
let score = Number.isFinite(Number(fit.score)) ? Number(fit.score) : 45;
|
|
785
|
+
const reasons = [];
|
|
786
|
+
const matched = terms.filter(term => haystack.includes(term));
|
|
787
|
+
if (matched.length) {
|
|
788
|
+
score += Math.min(24, matched.length * 4);
|
|
789
|
+
reasons.push(`task term match: ${matched.slice(0, 5).join(', ')}`);
|
|
790
|
+
}
|
|
791
|
+
if (target && target !== 'any') {
|
|
792
|
+
if (targets.includes(target) || fit.target === target) {
|
|
793
|
+
score += 12;
|
|
794
|
+
reasons.push(`target matches ${target}`);
|
|
795
|
+
} else if (targets.length) {
|
|
796
|
+
score -= 10;
|
|
797
|
+
reasons.push(`target metadata is ${targets.join(', ')}`);
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
const kind = candidateKind(item, metadata, fit);
|
|
801
|
+
if (constraints.kind && String(kind).toLowerCase() === String(constraints.kind).toLowerCase()) {
|
|
802
|
+
score += 8;
|
|
803
|
+
reasons.push(`kind matches ${constraints.kind}`);
|
|
804
|
+
}
|
|
805
|
+
const policy = fit.policy || item.policy || '';
|
|
806
|
+
if (policy === 'allow') {
|
|
807
|
+
score += 6;
|
|
808
|
+
reasons.push('policy allow');
|
|
809
|
+
} else if (policy === 'deny') {
|
|
810
|
+
score -= 35;
|
|
811
|
+
reasons.push('policy deny');
|
|
812
|
+
} else if (policy === 'stage_only' || policy === 'confirm') {
|
|
813
|
+
score -= 6;
|
|
814
|
+
reasons.push(`policy ${policy}`);
|
|
815
|
+
}
|
|
816
|
+
const trust = item.trust || item.agent_trust || {};
|
|
817
|
+
if (trust.review_status === 'reviewed' || trust.verified_publisher) {
|
|
818
|
+
score += 4;
|
|
819
|
+
reasons.push('reviewed or verified');
|
|
820
|
+
}
|
|
821
|
+
return { score: Math.max(0, Math.min(100, Math.round(score))), reasons };
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
function buildCandidate(item, target, ranking = {}) {
|
|
705
825
|
const uuid = candidateUuid(item);
|
|
706
826
|
const metadata = itemAgentMetadata(item);
|
|
707
827
|
const fit = itemAgentFit(item);
|
|
@@ -734,6 +854,7 @@ function buildCandidate(item, target) {
|
|
|
734
854
|
policy: compactText(fit.policy || item.policy || '', 64),
|
|
735
855
|
why,
|
|
736
856
|
},
|
|
857
|
+
ranking,
|
|
737
858
|
next_mcp_calls: [
|
|
738
859
|
{ tool: 'tokrepo_detail', arguments: { uuid } },
|
|
739
860
|
{ tool: 'tokrepo_install_plan', arguments: { uuid, target: planTarget } },
|
|
@@ -832,7 +953,11 @@ async function handleDiscover(args) {
|
|
|
832
953
|
'Use the installed capability only for the matching subtask, then verify the user goal.',
|
|
833
954
|
'If the agent creates a reusable improvement, ask before publishing and use tokrepo_push with explicit files.',
|
|
834
955
|
],
|
|
835
|
-
candidates: items
|
|
956
|
+
candidates: items
|
|
957
|
+
.map(item => buildCandidate(item, target, scoreDiscoveryCandidate(item, task, target, constraints)))
|
|
958
|
+
.filter(candidate => candidate.uuid)
|
|
959
|
+
.sort((a, b) => (b.ranking?.score || 0) - (a.ranking?.score || 0))
|
|
960
|
+
.slice(0, limit),
|
|
836
961
|
empty_state: items.length ? null : {
|
|
837
962
|
message: discoveryError
|
|
838
963
|
? `TokRepo discovery could not fetch live candidates for "${selectedQuery}".`
|
|
@@ -1365,6 +1490,7 @@ async function handleRequest(msg) {
|
|
|
1365
1490
|
} catch (e) {
|
|
1366
1491
|
result = { content: [{ type: 'text', text: `Error: ${e.message}` }], isError: true };
|
|
1367
1492
|
}
|
|
1493
|
+
trackAgentEventForTool(name, args || {}, result);
|
|
1368
1494
|
return { jsonrpc: '2.0', id, result };
|
|
1369
1495
|
}
|
|
1370
1496
|
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tokrepo-mcp-server",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.8.0",
|
|
4
4
|
"description": "Agent-native MCP server for TokRepo — search, plan, safely install, and push AI assets from MCP clients.",
|
|
5
|
-
"mcpName": "io.github.tokrepo
|
|
5
|
+
"mcpName": "io.github.henu-wang/tokrepo-mcp-server",
|
|
6
6
|
"bin": {
|
|
7
7
|
"tokrepo-mcp-server": "bin/server.js"
|
|
8
8
|
},
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"license": "MIT",
|
|
13
13
|
"repository": {
|
|
14
14
|
"type": "git",
|
|
15
|
-
"url": "git+https://github.com/tokrepo
|
|
15
|
+
"url": "git+https://github.com/henu-wang/tokrepo-mcp-server.git"
|
|
16
16
|
},
|
|
17
17
|
"homepage": "https://tokrepo.com",
|
|
18
18
|
"keywords": [
|
|
@@ -27,7 +27,14 @@
|
|
|
27
27
|
"skills",
|
|
28
28
|
"prompts",
|
|
29
29
|
"workflows",
|
|
30
|
-
"agent"
|
|
30
|
+
"agent",
|
|
31
|
+
"agent-tools",
|
|
32
|
+
"agent-skills",
|
|
33
|
+
"claude-code",
|
|
34
|
+
"openai-codex",
|
|
35
|
+
"mcp-registry",
|
|
36
|
+
"tool-discovery",
|
|
37
|
+
"llms-txt"
|
|
31
38
|
],
|
|
32
39
|
"engines": {
|
|
33
40
|
"node": ">=18"
|