onlymcp 0.1.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/LICENSE +21 -0
- package/README.md +59 -0
- package/dist/apiClient.d.ts +55 -0
- package/dist/apiClient.js +59 -0
- package/dist/apiClient.js.map +1 -0
- package/dist/auth/deviceLogin.d.ts +5 -0
- package/dist/auth/deviceLogin.js +36 -0
- package/dist/auth/deviceLogin.js.map +1 -0
- package/dist/auth/keyring.d.ts +5 -0
- package/dist/auth/keyring.js +28 -0
- package/dist/auth/keyring.js.map +1 -0
- package/dist/bin/cli.d.ts +2 -0
- package/dist/bin/cli.js +173 -0
- package/dist/bin/cli.js.map +1 -0
- package/dist/bin/mcp.d.ts +2 -0
- package/dist/bin/mcp.js +67 -0
- package/dist/bin/mcp.js.map +1 -0
- package/dist/cache.d.ts +7 -0
- package/dist/cache.js +32 -0
- package/dist/cache.js.map +1 -0
- package/dist/install.d.ts +12 -0
- package/dist/install.js +82 -0
- package/dist/install.js.map +1 -0
- package/dist/instructions.d.ts +2 -0
- package/dist/instructions.js +46 -0
- package/dist/instructions.js.map +1 -0
- package/dist/memoryPath.d.ts +1 -0
- package/dist/memoryPath.js +13 -0
- package/dist/memoryPath.js.map +1 -0
- package/dist/paths.d.ts +2 -0
- package/dist/paths.js +28 -0
- package/dist/paths.js.map +1 -0
- package/dist/stubs.d.ts +5 -0
- package/dist/stubs.js +52 -0
- package/dist/stubs.js.map +1 -0
- package/dist/tools/getAgentDefinition.d.ts +26 -0
- package/dist/tools/getAgentDefinition.js +26 -0
- package/dist/tools/getAgentDefinition.js.map +1 -0
- package/dist/tools/getSkill.d.ts +26 -0
- package/dist/tools/getSkill.js +26 -0
- package/dist/tools/getSkill.js.map +1 -0
- package/dist/tools/lists.d.ts +38 -0
- package/dist/tools/lists.js +39 -0
- package/dist/tools/lists.js.map +1 -0
- package/dist/tools/memoryRead.d.ts +25 -0
- package/dist/tools/memoryRead.js +33 -0
- package/dist/tools/memoryRead.js.map +1 -0
- package/dist/tools/memoryWrite.d.ts +27 -0
- package/dist/tools/memoryWrite.js +32 -0
- package/dist/tools/memoryWrite.js.map +1 -0
- package/package.json +58 -0
package/dist/install.js
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { join } from 'node:path';
|
|
2
|
+
/** Das npm-Paket, das sowohl `onlymcp` als auch `onlymcp-mcp` mitbringt. */
|
|
3
|
+
export const PACKAGE = 'onlymcp';
|
|
4
|
+
// Gestartet wird ueber npx und nicht als blosser Binaername `onlymcp-mcp`.
|
|
5
|
+
// Die Startseite bewirbt `npx onlymcp install`, und npx fuehrt ein Paket
|
|
6
|
+
// einmal aus, ohne irgendetwas auf dem PATH zu hinterlassen. Ein Eintrag mit
|
|
7
|
+
// nacktem `onlymcp-mcp` waere also erfolgreich geschrieben und beim naechsten
|
|
8
|
+
// Start des Clients trotzdem tot - der Fehler faellt genau dann auf, wenn der
|
|
9
|
+
// Nutzer laengst weitergezogen ist. `-p onlymcp` ist dabei Pflicht, weil der
|
|
10
|
+
// Binaername vom Paketnamen abweicht; ohne das sucht npx ein Paket namens
|
|
11
|
+
// `onlymcp-mcp`, das es nicht gibt.
|
|
12
|
+
//
|
|
13
|
+
// Bewusst ohne feste Version: der Server spricht mit einer Cloud-API, die sich
|
|
14
|
+
// weiterbewegt, und darf nicht auf einem Stand einfrieren, den danach niemand
|
|
15
|
+
// mehr anfasst.
|
|
16
|
+
const COMMAND = 'npx';
|
|
17
|
+
const ARGS = ['-y', '-p', PACKAGE, 'onlymcp-mcp'];
|
|
18
|
+
// TOML-Basic-Strings deuten den Rueckwaertsschraegstrich als Escape. Ein
|
|
19
|
+
// Windows-Heimatpfad wuerde ohne diese Behandlung eine kaputte Datei
|
|
20
|
+
// erzeugen, ein Anfuehrungszeichen im Pfad ebenso.
|
|
21
|
+
function tomlString(value) {
|
|
22
|
+
return `"${value.replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"`;
|
|
23
|
+
}
|
|
24
|
+
function jsonSnippet(env) {
|
|
25
|
+
const server = env
|
|
26
|
+
? { command: COMMAND, args: ARGS, env }
|
|
27
|
+
: { command: COMMAND, args: ARGS };
|
|
28
|
+
return JSON.stringify({ mcpServers: { onlymcp: server } }, null, 2);
|
|
29
|
+
}
|
|
30
|
+
function tomlSnippet(env) {
|
|
31
|
+
const lines = [
|
|
32
|
+
'[mcp_servers.onlymcp]',
|
|
33
|
+
`command = ${tomlString(COMMAND)}`,
|
|
34
|
+
`args = [${ARGS.map(tomlString).join(', ')}]`,
|
|
35
|
+
];
|
|
36
|
+
// Inline-Tabelle statt eigenem [mcp_servers.onlymcp.env]-Abschnitt: der
|
|
37
|
+
// Schnipsel wird an eine bestehende Datei angehaengt, und ein zweiter
|
|
38
|
+
// Abschnitt wuerde jede spaeter angehaengte Tabelle in ihn hineinziehen.
|
|
39
|
+
for (const [k, v] of Object.entries(env ?? {})) {
|
|
40
|
+
lines.push(`env = { ${k} = ${tomlString(v)} }`);
|
|
41
|
+
}
|
|
42
|
+
return `${lines.join('\n')}\n`;
|
|
43
|
+
}
|
|
44
|
+
// `home` ist ein Parameter und nicht homedir(), damit jeder Test gegen einen
|
|
45
|
+
// Wegwerf-Ordner laeuft. Die Leitplanke aus Spec Abschnitt 13 ist damit im
|
|
46
|
+
// Typ verankert und nicht bloss eine Absicht.
|
|
47
|
+
export function targets(home) {
|
|
48
|
+
// Geprueft an Codex 0.147.0: ~/.codex/skills wird direkt gescannt.
|
|
49
|
+
const codexStubs = join(home, '.codex', 'skills');
|
|
50
|
+
return [
|
|
51
|
+
{
|
|
52
|
+
id: 'claude',
|
|
53
|
+
label: 'Claude Code',
|
|
54
|
+
configPath: join(home, '.claude.json'),
|
|
55
|
+
// Die Stubs setzt bei Claude Code die Plugin-Installation ueber
|
|
56
|
+
// CLAUDE_PLUGIN_ROOT, nicht dieser Befehl.
|
|
57
|
+
stubDir: null,
|
|
58
|
+
snippet: jsonSnippet(),
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
id: 'codex',
|
|
62
|
+
label: 'Codex',
|
|
63
|
+
configPath: join(home, '.codex', 'config.toml'),
|
|
64
|
+
stubDir: codexStubs,
|
|
65
|
+
// Ohne ONLYMCP_STUB_DIRS im Eintrag selbst faellt stubDirs() auf
|
|
66
|
+
// ~/.claude/onlymcp/plugin zurueck: die Stubs landen dann an einer
|
|
67
|
+
// Stelle, die Codex nie liest, und ~/.codex/skills bleibt leer. Die
|
|
68
|
+
// Variable gehoert deshalb in die Konfiguration und nicht bloss als
|
|
69
|
+
// Hinweis in die Ausgabe.
|
|
70
|
+
snippet: tomlSnippet({ ONLYMCP_STUB_DIRS: codexStubs }),
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
id: 'gemini',
|
|
74
|
+
label: 'Gemini CLI',
|
|
75
|
+
configPath: join(home, '.gemini', 'settings.json'),
|
|
76
|
+
// Kein eigener Skill-Begriff: laeuft ueber instructions und list_skills.
|
|
77
|
+
stubDir: null,
|
|
78
|
+
snippet: jsonSnippet(),
|
|
79
|
+
},
|
|
80
|
+
];
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=install.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install.js","sourceRoot":"","sources":["../src/install.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// Harte Grenze aus dem Spike vom 21.08.2026 (Memory
|
|
2
|
+
// sol-mcp-instructions-cloud-skills-spike): Claude Code schneidet das
|
|
3
|
+
// instructions-Feld bei rund 2000 Zeichen STUMM ab, ohne Warnung und ohne
|
|
4
|
+
// Fehler. 1800 ist der Sicherheitsabstand. Codex zeigt das Feld nicht im
|
|
5
|
+
// Kontext, nutzt es aber, und seine Doku verlangt selbsttragende erste 512
|
|
6
|
+
// Zeichen. Beides zusammen ergibt: Anleitung nach vorn, Namensliste nach
|
|
7
|
+
// hinten. Wird abgeschnitten, geht die Liste verloren, nie die Anleitung.
|
|
8
|
+
export const INSTRUCTIONS_BUDGET = 1800;
|
|
9
|
+
const PREAMBLE = [
|
|
10
|
+
"OnlyMCP holds this user's skills, agents and memory in the cloud, identical",
|
|
11
|
+
'on every machine. The names below are names only, not content: call',
|
|
12
|
+
'get_skill(name) to load a skill before following it, and',
|
|
13
|
+
'get_agent_definition(name) for an agent. Call list_skills or list_agents for',
|
|
14
|
+
'anything not named here. Memory is live: memory_read(path) and',
|
|
15
|
+
'memory_write(path, content).',
|
|
16
|
+
].join(' ');
|
|
17
|
+
function section(label, tool, names, used) {
|
|
18
|
+
if (names.length === 0)
|
|
19
|
+
return '';
|
|
20
|
+
const kept = [];
|
|
21
|
+
for (const name of names) {
|
|
22
|
+
const rest = names.length - kept.length - 1;
|
|
23
|
+
const tail = rest > 0 ? ` (+${rest} more, call ${tool})` : '';
|
|
24
|
+
const line = `\n\n${label}: ${[...kept, name].join(', ')}${tail}`;
|
|
25
|
+
if (used + line.length > INSTRUCTIONS_BUDGET)
|
|
26
|
+
break;
|
|
27
|
+
kept.push(name);
|
|
28
|
+
}
|
|
29
|
+
if (kept.length === 0)
|
|
30
|
+
return `\n\n${label}: call ${tool}`;
|
|
31
|
+
const rest = names.length - kept.length;
|
|
32
|
+
const tail = rest > 0 ? ` (+${rest} more, call ${tool})` : '';
|
|
33
|
+
return `\n\n${label}: ${kept.join(', ')}${tail}`;
|
|
34
|
+
}
|
|
35
|
+
export function buildInstructions(skills, agents) {
|
|
36
|
+
let out = PREAMBLE;
|
|
37
|
+
// Platz fuer die Agents-Zeile zuruecklegen, BEVOR die Skills ihn aufbrauchen.
|
|
38
|
+
// Ohne diese Reserve frisst eine lange Skill-Liste das ganze Budget, die
|
|
39
|
+
// Agents-Zeile wird trotzdem angehaengt, und das Feld ueberschreitet 1800.
|
|
40
|
+
// Beim Nachrechnen mit je 400 Namen waren es 1817 Zeichen, mit Reserve 1800.
|
|
41
|
+
const reserve = agents.length > 0 ? '\n\nAgents: call list_agents'.length : 0;
|
|
42
|
+
out += section('Skills', 'list_skills', skills, out.length + reserve);
|
|
43
|
+
out += section('Agents', 'list_agents', agents, out.length);
|
|
44
|
+
return out;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=instructions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instructions.js","sourceRoot":"","sources":["../src/instructions.ts"],"names":[],"mappings":"AAAA,oDAAoD;AACpD,sEAAsE;AACtE,0EAA0E;AAC1E,yEAAyE;AACzE,2EAA2E;AAC3E,yEAAyE;AACzE,0EAA0E;AAC1E,MAAM,CAAC,MAAM,mBAAmB,GAAG,IAAI,CAAC;AAExC,MAAM,QAAQ,GAAG;IACf,6EAA6E;IAC7E,qEAAqE;IACrE,0DAA0D;IAC1D,8EAA8E;IAC9E,gEAAgE;IAChE,8BAA8B;CAC/B,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAEZ,SAAS,OAAO,CAAC,KAAa,EAAE,IAAY,EAAE,KAAe,EAAE,IAAY;IACzE,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAClC,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;QAC5C,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,IAAI,eAAe,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9D,MAAM,IAAI,GAAG,OAAO,KAAK,KAAK,CAAC,GAAG,IAAI,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,EAAE,CAAC;QAClE,IAAI,IAAI,GAAG,IAAI,CAAC,MAAM,GAAG,mBAAmB;YAAE,MAAM;QACpD,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAClB,CAAC;IACD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,OAAO,KAAK,UAAU,IAAI,EAAE,CAAC;IAC3D,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;IACxC,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,IAAI,eAAe,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9D,OAAO,OAAO,KAAK,KAAK,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,EAAE,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,MAAgB,EAAE,MAAgB;IAClE,IAAI,GAAG,GAAG,QAAQ,CAAC;IACnB,8EAA8E;IAC9E,yEAAyE;IACzE,2EAA2E;IAC3E,6EAA6E;IAC7E,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,8BAA8B,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9E,GAAG,IAAI,OAAO,CAAC,QAAQ,EAAE,aAAa,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,GAAG,OAAO,CAAC,CAAC;IACtE,GAAG,IAAI,OAAO,CAAC,QAAQ,EAAE,aAAa,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC5D,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function isSafeMemoryPath(path: string): boolean;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// Client-seitige Kopie der Server-Regel (packages/api/src/http/names.ts,
|
|
2
|
+
// memoryPath). Ohne diese Pruefung baut apiClient.ts den Pfad nur segmentweise
|
|
3
|
+
// per encodeURIComponent zusammen, und encodeURIComponent laesst ".." als
|
|
4
|
+
// literale zwei Punkte durch. Bei einem falsch konfigurierten oder
|
|
5
|
+
// kompromittierten ONLYMCP_API_URL koennte ein Traversal-Segment so bis zur
|
|
6
|
+
// Anfrage durchrutschen, bevor der Server ihn (server-seitig, aber eben erst
|
|
7
|
+
// dort) ablehnt. Client und Server pruefen deshalb beide, unabhaengig
|
|
8
|
+
// voneinander.
|
|
9
|
+
const MEMORY_PATH = /^[a-z0-9][a-z0-9._-]*(\/[a-z0-9][a-z0-9._-]*)*\.md$/i;
|
|
10
|
+
export function isSafeMemoryPath(path) {
|
|
11
|
+
return MEMORY_PATH.test(path) && !path.split('/').includes('..');
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=memoryPath.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memoryPath.js","sourceRoot":"","sources":["../src/memoryPath.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,+EAA+E;AAC/E,0EAA0E;AAC1E,mEAAmE;AACnE,4EAA4E;AAC5E,6EAA6E;AAC7E,sEAAsE;AACtE,eAAe;AACf,MAAM,WAAW,GAAG,sDAAsD,CAAC;AAE3E,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,OAAO,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACnE,CAAC"}
|
package/dist/paths.d.ts
ADDED
package/dist/paths.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { homedir } from 'node:os';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
function base() {
|
|
4
|
+
return process.env.ONLYMCP_HOME ?? join(homedir(), '.claude', 'onlymcp');
|
|
5
|
+
}
|
|
6
|
+
export function cacheDir() {
|
|
7
|
+
return join(base(), 'cache');
|
|
8
|
+
}
|
|
9
|
+
export function stubDirs() {
|
|
10
|
+
// Mehrzahl, weil mehrere Clients gleichzeitig auf demselben Geraet laufen
|
|
11
|
+
// koennen und jeder einen anderen Ordner scannt.
|
|
12
|
+
const dirs = [];
|
|
13
|
+
// Claude Code setzt CLAUDE_PLUGIN_ROOT, wenn es den MCP-Server aus dem
|
|
14
|
+
// Plugin heraus startet. Nur dort liegen Stubs an einer Stelle, die der
|
|
15
|
+
// Skill- und Agent-Scanner ueberhaupt liest.
|
|
16
|
+
if (process.env.CLAUDE_PLUGIN_ROOT)
|
|
17
|
+
dirs.push(process.env.CLAUDE_PLUGIN_ROOT);
|
|
18
|
+
// Alle uebrigen Clients mit eigenem Scanner, gesetzt von `onlymcp install`
|
|
19
|
+
// (heute Codex mit ~/.codex/skills). Mehrere durch Doppelpunkt getrennt wie
|
|
20
|
+
// PATH: ein Client mehr ist ein Eintrag mehr, keine Codeaenderung.
|
|
21
|
+
for (const d of (process.env.ONLYMCP_STUB_DIRS ?? '').split(':')) {
|
|
22
|
+
if (d)
|
|
23
|
+
dirs.push(d);
|
|
24
|
+
}
|
|
25
|
+
// Rueckfall fuer CLI und Tests ohne jeden Client-Kontext.
|
|
26
|
+
return dirs.length > 0 ? dirs : [join(base(), 'plugin')];
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,SAAS,IAAI;IACX,OAAO,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;AAC3E,CAAC;AAED,MAAM,UAAU,QAAQ;IACtB,OAAO,IAAI,CAAC,IAAI,EAAE,EAAE,OAAO,CAAC,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,QAAQ;IACtB,0EAA0E;IAC1E,iDAAiD;IACjD,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,uEAAuE;IACvE,wEAAwE;IACxE,6CAA6C;IAC7C,IAAI,OAAO,CAAC,GAAG,CAAC,kBAAkB;QAAE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;IAC9E,2EAA2E;IAC3E,4EAA4E;IAC5E,mEAAmE;IACnE,KAAK,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QACjE,IAAI,CAAC;YAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACtB,CAAC;IACD,0DAA0D;IAC1D,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,QAAQ,CAAC,CAAC,CAAC;AAC3D,CAAC"}
|
package/dist/stubs.d.ts
ADDED
package/dist/stubs.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { mkdir, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
// Gleiche Positivliste wie server-seitig (packages/api/src/http/names.ts,
|
|
4
|
+
// skillName/agentName). Dieses Paket haengt nicht von @onlymcp/api ab, also
|
|
5
|
+
// keine gemeinsame Konstante, aber ein Name, der so nie in der Datenbank
|
|
6
|
+
// entstehen sollte, darf trotzdem nie als Pfadsegment landen: ein falsch
|
|
7
|
+
// konfiguriertes oder kompromittiertes ONLYMCP_API_URL soll niemals Dateien
|
|
8
|
+
// ausserhalb von `dir` schreiben koennen, egal was der Server zurueckgibt.
|
|
9
|
+
const SAFE_NAME = /^[a-z0-9]+(-[a-z0-9]+)*$/;
|
|
10
|
+
// Frontmatter ist YAML, aber die Werte (description, model, jeder Tool-Name)
|
|
11
|
+
// kommen ungeprueft vom Server. Ein Wert mit Zeilenumbruch koennte sonst aus
|
|
12
|
+
// seiner eigenen Zeile ausbrechen und zusaetzliche Frontmatter-Felder
|
|
13
|
+
// einschleusen (z.B. ein erfundenes weiteres `tools:`). Zeilenumbrueche
|
|
14
|
+
// werden deshalb entfernt, nicht escaped: ein Skill-/Agent-Name oder eine
|
|
15
|
+
// Beschreibung braucht nie einen Zeilenumbruch, um sinnvoll zu sein.
|
|
16
|
+
function yamlSafe(value) {
|
|
17
|
+
return value.replace(/[\r\n]+/g, ' ').trim();
|
|
18
|
+
}
|
|
19
|
+
export async function writeStubs(api, dir) {
|
|
20
|
+
const [{ skills }, { agents }] = await Promise.all([api.listSkills(), api.listAgents()]);
|
|
21
|
+
for (const s of skills) {
|
|
22
|
+
if (!SAFE_NAME.test(s.name))
|
|
23
|
+
continue;
|
|
24
|
+
const target = join(dir, 'skills', s.name);
|
|
25
|
+
await mkdir(target, { recursive: true });
|
|
26
|
+
await writeFile(join(target, 'SKILL.md'), `---
|
|
27
|
+
name: ${s.name}
|
|
28
|
+
description: Synchronisiert ueber OnlyMCP. Inhalt wird bei Bedarf geladen.
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
Rufe \`get_skill({ name: "${s.name}" })\` am OnlyMCP-Server auf und befolge, was zurueckkommt.
|
|
32
|
+
`, 'utf8');
|
|
33
|
+
}
|
|
34
|
+
await mkdir(join(dir, 'agents'), { recursive: true });
|
|
35
|
+
for (const a of agents) {
|
|
36
|
+
if (!SAFE_NAME.test(a.name))
|
|
37
|
+
continue;
|
|
38
|
+
const description = yamlSafe(a.description);
|
|
39
|
+
const model = a.model ? yamlSafe(a.model) : '';
|
|
40
|
+
const tools = a.tools.map(yamlSafe).join(', ');
|
|
41
|
+
await writeFile(join(dir, 'agents', `${a.name}.md`), `---
|
|
42
|
+
name: ${a.name}
|
|
43
|
+
description: ${description}
|
|
44
|
+
${model ? `model: ${model}\n` : ''}tools: ${tools}
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
Rufe \`get_agent_definition({ name: "${a.name}" })\` am OnlyMCP-Server auf und befolge, was zurueckkommt.
|
|
48
|
+
`, 'utf8');
|
|
49
|
+
}
|
|
50
|
+
return { skills: skills.length, agents: agents.length };
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=stubs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stubs.js","sourceRoot":"","sources":["../src/stubs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC,0EAA0E;AAC1E,4EAA4E;AAC5E,yEAAyE;AACzE,yEAAyE;AACzE,4EAA4E;AAC5E,2EAA2E;AAC3E,MAAM,SAAS,GAAG,0BAA0B,CAAC;AAE7C,6EAA6E;AAC7E,6EAA6E;AAC7E,sEAAsE;AACtE,wEAAwE;AACxE,0EAA0E;AAC1E,qEAAqE;AACrE,SAAS,QAAQ,CAAC,KAAa;IAC7B,OAAO,KAAK,CAAC,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;AAC/C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,GAAc,EAAE,GAAW;IAC1D,MAAM,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,UAAU,EAAE,EAAE,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;IAEzF,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACvB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;YAAE,SAAS;QACtC,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;QAC3C,MAAM,KAAK,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACzC,MAAM,SAAS,CACb,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,EACxB;QACE,CAAC,CAAC,IAAI;;;;4BAIc,CAAC,CAAC,IAAI;CACjC,EACK,MAAM,CACP,CAAC;IACJ,CAAC;IAED,MAAM,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACtD,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACvB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;YAAE,SAAS;QACtC,MAAM,WAAW,GAAG,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;QAC5C,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/C,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/C,MAAM,SAAS,CACb,IAAI,CAAC,GAAG,EAAE,QAAQ,EAAE,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC,EACnC;QACE,CAAC,CAAC,IAAI;eACC,WAAW;EACxB,KAAK,CAAC,CAAC,CAAC,UAAU,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,UAAU,KAAK;;;uCAGV,CAAC,CAAC,IAAI;CAC5C,EACK,MAAM,CACP,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;AAC1D,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { ApiClient } from '../apiClient.js';
|
|
3
|
+
import type { TtlCache } from '../cache.js';
|
|
4
|
+
export declare const GetAgentInput: z.ZodObject<{
|
|
5
|
+
name: z.ZodString;
|
|
6
|
+
}, z.core.$strip>;
|
|
7
|
+
export declare function createGetAgentDefinitionTool(api: ApiClient, cache: TtlCache): {
|
|
8
|
+
name: string;
|
|
9
|
+
description: string;
|
|
10
|
+
inputSchema: z.ZodObject<{
|
|
11
|
+
name: z.ZodString;
|
|
12
|
+
}, z.core.$strip>;
|
|
13
|
+
handler(args: z.infer<typeof GetAgentInput>): Promise<{
|
|
14
|
+
content: {
|
|
15
|
+
type: "text";
|
|
16
|
+
text: string;
|
|
17
|
+
}[];
|
|
18
|
+
isError?: undefined;
|
|
19
|
+
} | {
|
|
20
|
+
content: {
|
|
21
|
+
type: "text";
|
|
22
|
+
text: string;
|
|
23
|
+
}[];
|
|
24
|
+
isError: boolean;
|
|
25
|
+
}>;
|
|
26
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { ApiError } from '../apiClient.js';
|
|
3
|
+
export const GetAgentInput = z.object({ name: z.string().min(1).max(64) });
|
|
4
|
+
export function createGetAgentDefinitionTool(api, cache) {
|
|
5
|
+
return {
|
|
6
|
+
name: 'get_agent_definition',
|
|
7
|
+
description: 'Liefert den System-Prompt eines Agenten aus der OnlyMCP-Cloud.',
|
|
8
|
+
inputSchema: GetAgentInput,
|
|
9
|
+
async handler(args) {
|
|
10
|
+
const key = `agent:${args.name}`;
|
|
11
|
+
const cached = await cache.get(key);
|
|
12
|
+
if (cached !== null)
|
|
13
|
+
return { content: [{ type: 'text', text: cached }] };
|
|
14
|
+
try {
|
|
15
|
+
const a = await api.getAgent(args.name);
|
|
16
|
+
await cache.set(key, a.body);
|
|
17
|
+
return { content: [{ type: 'text', text: a.body }] };
|
|
18
|
+
}
|
|
19
|
+
catch (e) {
|
|
20
|
+
const code = e instanceof ApiError ? e.code : 'errors.UNKNOWN';
|
|
21
|
+
return { content: [{ type: 'text', text: code }], isError: true };
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=getAgentDefinition.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getAgentDefinition.js","sourceRoot":"","sources":["../../src/tools/getAgentDefinition.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAG3C,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AAE3E,MAAM,UAAU,4BAA4B,CAAC,GAAc,EAAE,KAAe;IAC1E,OAAO;QACL,IAAI,EAAE,sBAAsB;QAC5B,WAAW,EAAE,gEAAgE;QAC7E,WAAW,EAAE,aAAa;QAC1B,KAAK,CAAC,OAAO,CAAC,IAAmC;YAC/C,MAAM,GAAG,GAAG,SAAS,IAAI,CAAC,IAAI,EAAE,CAAC;YACjC,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YACpC,IAAI,MAAM,KAAK,IAAI;gBAAE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;YACnF,IAAI,CAAC;gBACH,MAAM,CAAC,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACxC,MAAM,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;gBAC7B,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;YAChE,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,MAAM,IAAI,GAAG,CAAC,YAAY,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,gBAAgB,CAAC;gBAC/D,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;YAC7E,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { ApiClient } from '../apiClient.js';
|
|
3
|
+
import type { TtlCache } from '../cache.js';
|
|
4
|
+
export declare const GetSkillInput: z.ZodObject<{
|
|
5
|
+
name: z.ZodString;
|
|
6
|
+
}, z.core.$strip>;
|
|
7
|
+
export declare function createGetSkillTool(api: ApiClient, cache: TtlCache): {
|
|
8
|
+
name: string;
|
|
9
|
+
description: string;
|
|
10
|
+
inputSchema: z.ZodObject<{
|
|
11
|
+
name: z.ZodString;
|
|
12
|
+
}, z.core.$strip>;
|
|
13
|
+
handler(args: z.infer<typeof GetSkillInput>): Promise<{
|
|
14
|
+
content: {
|
|
15
|
+
type: "text";
|
|
16
|
+
text: string;
|
|
17
|
+
}[];
|
|
18
|
+
isError?: undefined;
|
|
19
|
+
} | {
|
|
20
|
+
content: {
|
|
21
|
+
type: "text";
|
|
22
|
+
text: string;
|
|
23
|
+
}[];
|
|
24
|
+
isError: boolean;
|
|
25
|
+
}>;
|
|
26
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { ApiError } from '../apiClient.js';
|
|
3
|
+
export const GetSkillInput = z.object({ name: z.string().min(1).max(64) });
|
|
4
|
+
export function createGetSkillTool(api, cache) {
|
|
5
|
+
return {
|
|
6
|
+
name: 'get_skill',
|
|
7
|
+
description: 'Liefert den vollstaendigen Inhalt eines Skills aus der OnlyMCP-Cloud. Wird von den Stub-Dateien aufgerufen.',
|
|
8
|
+
inputSchema: GetSkillInput,
|
|
9
|
+
async handler(args) {
|
|
10
|
+
const key = `skill:${args.name}`;
|
|
11
|
+
const cached = await cache.get(key);
|
|
12
|
+
if (cached !== null)
|
|
13
|
+
return { content: [{ type: 'text', text: cached }] };
|
|
14
|
+
try {
|
|
15
|
+
const skill = await api.getSkill(args.name);
|
|
16
|
+
await cache.set(key, skill.body);
|
|
17
|
+
return { content: [{ type: 'text', text: skill.body }] };
|
|
18
|
+
}
|
|
19
|
+
catch (e) {
|
|
20
|
+
const code = e instanceof ApiError ? e.code : 'errors.UNKNOWN';
|
|
21
|
+
return { content: [{ type: 'text', text: code }], isError: true };
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=getSkill.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getSkill.js","sourceRoot":"","sources":["../../src/tools/getSkill.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAG3C,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AAE3E,MAAM,UAAU,kBAAkB,CAAC,GAAc,EAAE,KAAe;IAChE,OAAO;QACL,IAAI,EAAE,WAAW;QACjB,WAAW,EACT,6GAA6G;QAC/G,WAAW,EAAE,aAAa;QAC1B,KAAK,CAAC,OAAO,CAAC,IAAmC;YAC/C,MAAM,GAAG,GAAG,SAAS,IAAI,CAAC,IAAI,EAAE,CAAC;YACjC,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YACpC,IAAI,MAAM,KAAK,IAAI;gBAAE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;YACnF,IAAI,CAAC;gBACH,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC5C,MAAM,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;gBACjC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;YACpE,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,MAAM,IAAI,GAAG,CAAC,YAAY,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,gBAAgB,CAAC;gBAC/D,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;YAC7E,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { ApiClient } from '../apiClient.js';
|
|
3
|
+
export declare function createListSkillsTool(api: ApiClient): {
|
|
4
|
+
name: string;
|
|
5
|
+
description: string;
|
|
6
|
+
inputSchema: z.ZodObject<{}, z.core.$strip>;
|
|
7
|
+
handler(): Promise<{
|
|
8
|
+
content: {
|
|
9
|
+
type: "text";
|
|
10
|
+
text: string;
|
|
11
|
+
}[];
|
|
12
|
+
isError?: undefined;
|
|
13
|
+
} | {
|
|
14
|
+
content: {
|
|
15
|
+
type: "text";
|
|
16
|
+
text: string;
|
|
17
|
+
}[];
|
|
18
|
+
isError: boolean;
|
|
19
|
+
}>;
|
|
20
|
+
};
|
|
21
|
+
export declare function createListAgentsTool(api: ApiClient): {
|
|
22
|
+
name: string;
|
|
23
|
+
description: string;
|
|
24
|
+
inputSchema: z.ZodObject<{}, z.core.$strip>;
|
|
25
|
+
handler(): Promise<{
|
|
26
|
+
content: {
|
|
27
|
+
type: "text";
|
|
28
|
+
text: string;
|
|
29
|
+
}[];
|
|
30
|
+
isError?: undefined;
|
|
31
|
+
} | {
|
|
32
|
+
content: {
|
|
33
|
+
type: "text";
|
|
34
|
+
text: string;
|
|
35
|
+
}[];
|
|
36
|
+
isError: boolean;
|
|
37
|
+
}>;
|
|
38
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { ApiError } from '../apiClient.js';
|
|
3
|
+
const empty = z.object({});
|
|
4
|
+
export function createListSkillsTool(api) {
|
|
5
|
+
return {
|
|
6
|
+
name: 'list_skills',
|
|
7
|
+
description: 'List every skill name available to this user. Use when a skill you need is not named in the server instructions.',
|
|
8
|
+
inputSchema: empty,
|
|
9
|
+
async handler() {
|
|
10
|
+
try {
|
|
11
|
+
const { skills } = await api.listSkills();
|
|
12
|
+
return { content: [{ type: 'text', text: skills.map((s) => s.name).join('\n') }] };
|
|
13
|
+
}
|
|
14
|
+
catch (e) {
|
|
15
|
+
const code = e instanceof ApiError ? e.code : 'errors.UNKNOWN';
|
|
16
|
+
return { content: [{ type: 'text', text: code }], isError: true };
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export function createListAgentsTool(api) {
|
|
22
|
+
return {
|
|
23
|
+
name: 'list_agents',
|
|
24
|
+
description: 'List every agent available to this user, with its description. Use when this client has no agent files of its own.',
|
|
25
|
+
inputSchema: empty,
|
|
26
|
+
async handler() {
|
|
27
|
+
try {
|
|
28
|
+
const { agents } = await api.listAgents();
|
|
29
|
+
const text = agents.map((a) => `${a.name}: ${a.description}`).join('\n');
|
|
30
|
+
return { content: [{ type: 'text', text }] };
|
|
31
|
+
}
|
|
32
|
+
catch (e) {
|
|
33
|
+
const code = e instanceof ApiError ? e.code : 'errors.UNKNOWN';
|
|
34
|
+
return { content: [{ type: 'text', text: code }], isError: true };
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=lists.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lists.js","sourceRoot":"","sources":["../../src/tools/lists.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE3C,MAAM,KAAK,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;AAE3B,MAAM,UAAU,oBAAoB,CAAC,GAAc;IACjD,OAAO;QACL,IAAI,EAAE,aAAa;QACnB,WAAW,EACT,kHAAkH;QACpH,WAAW,EAAE,KAAK;QAClB,KAAK,CAAC,OAAO;YACX,IAAI,CAAC;gBACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,CAAC,UAAU,EAAE,CAAC;gBAC1C,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;YAC9F,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,MAAM,IAAI,GAAG,CAAC,YAAY,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,gBAAgB,CAAC;gBAC/D,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;YAC7E,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,GAAc;IACjD,OAAO;QACL,IAAI,EAAE,aAAa;QACnB,WAAW,EACT,oHAAoH;QACtH,WAAW,EAAE,KAAK;QAClB,KAAK,CAAC,OAAO;YACX,IAAI,CAAC;gBACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,CAAC,UAAU,EAAE,CAAC;gBAC1C,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACzE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;YACxD,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,MAAM,IAAI,GAAG,CAAC,YAAY,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,gBAAgB,CAAC;gBAC/D,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;YAC7E,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { ApiClient } from '../apiClient.js';
|
|
3
|
+
export declare const MemoryReadInput: z.ZodObject<{
|
|
4
|
+
path: z.ZodString;
|
|
5
|
+
}, z.core.$strip>;
|
|
6
|
+
export declare function createMemoryReadTool(api: ApiClient): {
|
|
7
|
+
name: string;
|
|
8
|
+
description: string;
|
|
9
|
+
inputSchema: z.ZodObject<{
|
|
10
|
+
path: z.ZodString;
|
|
11
|
+
}, z.core.$strip>;
|
|
12
|
+
handler(args: z.infer<typeof MemoryReadInput>): Promise<{
|
|
13
|
+
content: {
|
|
14
|
+
type: "text";
|
|
15
|
+
text: string;
|
|
16
|
+
}[];
|
|
17
|
+
isError: boolean;
|
|
18
|
+
} | {
|
|
19
|
+
content: {
|
|
20
|
+
type: "text";
|
|
21
|
+
text: string;
|
|
22
|
+
}[];
|
|
23
|
+
isError?: undefined;
|
|
24
|
+
}>;
|
|
25
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { ApiError } from '../apiClient.js';
|
|
3
|
+
import { isSafeMemoryPath } from '../memoryPath.js';
|
|
4
|
+
export const MemoryReadInput = z.object({ path: z.string().min(3).max(256) });
|
|
5
|
+
export function createMemoryReadTool(api) {
|
|
6
|
+
const inFlight = new Map();
|
|
7
|
+
return {
|
|
8
|
+
name: 'memory_read',
|
|
9
|
+
description: 'Liest eine Memory-Datei live aus der OnlyMCP-Cloud. Kein Diskcache.',
|
|
10
|
+
inputSchema: MemoryReadInput,
|
|
11
|
+
async handler(args) {
|
|
12
|
+
if (!isSafeMemoryPath(args.path)) {
|
|
13
|
+
return { content: [{ type: 'text', text: 'errors.INVALID_PATH' }], isError: true };
|
|
14
|
+
}
|
|
15
|
+
try {
|
|
16
|
+
// Nur exakt gleichzeitige Wiederholungen teilen sich eine Anfrage.
|
|
17
|
+
// Kein Zeit-Cache: nach dem Aufloesen ist der Eintrag weg.
|
|
18
|
+
let p = inFlight.get(args.path);
|
|
19
|
+
if (!p) {
|
|
20
|
+
p = api.readMemory(args.path).then((f) => f.content);
|
|
21
|
+
inFlight.set(args.path, p);
|
|
22
|
+
p.finally(() => inFlight.delete(args.path));
|
|
23
|
+
}
|
|
24
|
+
return { content: [{ type: 'text', text: await p }] };
|
|
25
|
+
}
|
|
26
|
+
catch (e) {
|
|
27
|
+
const code = e instanceof ApiError ? e.code : 'errors.UNKNOWN';
|
|
28
|
+
return { content: [{ type: 'text', text: code }], isError: true };
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=memoryRead.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memoryRead.js","sourceRoot":"","sources":["../../src/tools/memoryRead.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEpD,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AAE9E,MAAM,UAAU,oBAAoB,CAAC,GAAc;IACjD,MAAM,QAAQ,GAAG,IAAI,GAAG,EAA2B,CAAC;IAEpD,OAAO;QACL,IAAI,EAAE,aAAa;QACnB,WAAW,EAAE,qEAAqE;QAClF,WAAW,EAAE,eAAe;QAC5B,KAAK,CAAC,OAAO,CAAC,IAAqC;YACjD,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;gBACjC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,qBAAqB,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;YAC9F,CAAC;YACD,IAAI,CAAC;gBACH,mEAAmE;gBACnE,2DAA2D;gBAC3D,IAAI,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAChC,IAAI,CAAC,CAAC,EAAE,CAAC;oBACP,CAAC,GAAG,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;oBACrD,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;oBAC3B,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;gBAC9C,CAAC;gBACD,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;YACjE,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,MAAM,IAAI,GAAG,CAAC,YAAY,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,gBAAgB,CAAC;gBAC/D,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;YAC7E,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { ApiClient } from '../apiClient.js';
|
|
3
|
+
export declare const MemoryWriteInput: z.ZodObject<{
|
|
4
|
+
path: z.ZodString;
|
|
5
|
+
content: z.ZodString;
|
|
6
|
+
}, z.core.$strip>;
|
|
7
|
+
export declare function createMemoryWriteTool(api: ApiClient): {
|
|
8
|
+
name: string;
|
|
9
|
+
description: string;
|
|
10
|
+
inputSchema: z.ZodObject<{
|
|
11
|
+
path: z.ZodString;
|
|
12
|
+
content: z.ZodString;
|
|
13
|
+
}, z.core.$strip>;
|
|
14
|
+
handler(args: z.infer<typeof MemoryWriteInput>): Promise<{
|
|
15
|
+
content: {
|
|
16
|
+
type: "text";
|
|
17
|
+
text: string;
|
|
18
|
+
}[];
|
|
19
|
+
isError: boolean;
|
|
20
|
+
} | {
|
|
21
|
+
content: {
|
|
22
|
+
type: "text";
|
|
23
|
+
text: string;
|
|
24
|
+
}[];
|
|
25
|
+
isError?: undefined;
|
|
26
|
+
}>;
|
|
27
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { hostname } from 'node:os';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { ApiError } from '../apiClient.js';
|
|
4
|
+
import { isSafeMemoryPath } from '../memoryPath.js';
|
|
5
|
+
export const MemoryWriteInput = z.object({
|
|
6
|
+
path: z.string().min(3).max(256),
|
|
7
|
+
content: z.string().max(1_000_000),
|
|
8
|
+
});
|
|
9
|
+
export function createMemoryWriteTool(api) {
|
|
10
|
+
return {
|
|
11
|
+
name: 'memory_write',
|
|
12
|
+
description: 'Schreibt eine Memory-Datei live in die OnlyMCP-Cloud (write-through).',
|
|
13
|
+
inputSchema: MemoryWriteInput,
|
|
14
|
+
async handler(args) {
|
|
15
|
+
if (!isSafeMemoryPath(args.path)) {
|
|
16
|
+
return { content: [{ type: 'text', text: 'errors.INVALID_PATH' }], isError: true };
|
|
17
|
+
}
|
|
18
|
+
try {
|
|
19
|
+
const res = await api.writeMemory(args.path, args.content, hostname());
|
|
20
|
+
const text = res.warning
|
|
21
|
+
? `${res.path} ${res.updatedAt} ${res.warning.code} ${JSON.stringify(res.warning.params)}`
|
|
22
|
+
: `${res.path} ${res.updatedAt}`;
|
|
23
|
+
return { content: [{ type: 'text', text }] };
|
|
24
|
+
}
|
|
25
|
+
catch (e) {
|
|
26
|
+
const code = e instanceof ApiError ? e.code : 'errors.UNKNOWN';
|
|
27
|
+
return { content: [{ type: 'text', text: code }], isError: true };
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=memoryWrite.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memoryWrite.js","sourceRoot":"","sources":["../../src/tools/memoryWrite.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEpD,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IACvC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;IAChC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC;CACnC,CAAC,CAAC;AAEH,MAAM,UAAU,qBAAqB,CAAC,GAAc;IAClD,OAAO;QACL,IAAI,EAAE,cAAc;QACpB,WAAW,EAAE,uEAAuE;QACpF,WAAW,EAAE,gBAAgB;QAC7B,KAAK,CAAC,OAAO,CAAC,IAAsC;YAClD,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;gBACjC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,qBAAqB,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;YAC9F,CAAC;YACD,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC;gBACvE,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO;oBACtB,CAAC,CAAC,GAAG,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE;oBAC1F,CAAC,CAAC,GAAG,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,SAAS,EAAE,CAAC;gBACnC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;YACxD,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,MAAM,IAAI,GAAG,CAAC,YAAY,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,gBAAgB,CAAC;gBAC/D,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;YAC7E,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
|