@scp-dev/mcp 0.1.4 → 0.1.5
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/dist/index.d.ts +3 -1
- package/dist/index.js +21 -2
- package/package.json +3 -3
- package/src/server.ts +26 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as _scp_dev_core from '@scp-dev/core';
|
|
2
|
-
import { Claim } from '@scp-dev/core';
|
|
2
|
+
import { Claim, Wake } from '@scp-dev/core';
|
|
3
3
|
import { RelayClient } from '@scp-dev/broker';
|
|
4
4
|
|
|
5
5
|
declare const MCP_PROTOCOLS: readonly ["2025-11-25", "2025-06-18", "2025-03-26", "2024-11-05"];
|
|
@@ -25,6 +25,8 @@ interface RelayMcpOptions {
|
|
|
25
25
|
channels?: boolean;
|
|
26
26
|
/** the client was started with channels loaded (Claude Code does not declare the capability itself) */
|
|
27
27
|
launchedWithChannels?: boolean;
|
|
28
|
+
/** the wake the endpoint advertises while this shim pushes by channel, over `pi` for a pi client and `channels` for any other */
|
|
29
|
+
wake?: Wake;
|
|
28
30
|
version?: string;
|
|
29
31
|
/** starts a worker for relay_spawn, resolving with its name and its runner's pid once its harness started; without it there is no relay_spawn */
|
|
30
32
|
spawn?: (request: SpawnRequest) => Promise<{
|
package/dist/index.js
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
deliveryText,
|
|
8
8
|
LIMITS,
|
|
9
9
|
PREAMBLE,
|
|
10
|
+
presenceText,
|
|
10
11
|
reachLines,
|
|
11
12
|
receiptLines,
|
|
12
13
|
RelayError,
|
|
@@ -278,7 +279,11 @@ function heldText(held) {
|
|
|
278
279
|
return `held for review by your human: hold ${held.hold_id}; nothing was delivered`;
|
|
279
280
|
}
|
|
280
281
|
function sentContent(result) {
|
|
281
|
-
return {
|
|
282
|
+
return {
|
|
283
|
+
id: result.id,
|
|
284
|
+
thread: result.thread,
|
|
285
|
+
recipients: result.deliveries.map((d) => ({ address: d.address, ...d.state ? { state: d.state } : {}, ...d.wake ? { wake: d.wake } : {} }))
|
|
286
|
+
};
|
|
282
287
|
}
|
|
283
288
|
function redactedText(redacted) {
|
|
284
289
|
return redacted ? `; redacted ${redacted.n} span${redacted.n === 1 ? "" : "s"} (${redacted.kinds.join(", ")}) before delivery` : "";
|
|
@@ -404,6 +409,8 @@ async function runRelayMcp(options) {
|
|
|
404
409
|
let stopped = false;
|
|
405
410
|
const channelPushed = /* @__PURE__ */ new Set();
|
|
406
411
|
let channelLoop;
|
|
412
|
+
let wake;
|
|
413
|
+
let advertised;
|
|
407
414
|
const write = (message) => {
|
|
408
415
|
if (!stopped) options.output(`${JSON.stringify(message)}
|
|
409
416
|
`);
|
|
@@ -446,8 +453,17 @@ async function runRelayMcp(options) {
|
|
|
446
453
|
throw new Error("the relay MCP shim is stopping");
|
|
447
454
|
}
|
|
448
455
|
client = next;
|
|
456
|
+
advertise();
|
|
449
457
|
return next;
|
|
450
458
|
}
|
|
459
|
+
function advertise() {
|
|
460
|
+
if (!client || wake === void 0) return;
|
|
461
|
+
const via = wake ?? "none";
|
|
462
|
+
if (advertised?.client === client && advertised.via === via || via === "none" && !advertised) return;
|
|
463
|
+
advertised = { client, via };
|
|
464
|
+
client.request("wake", { via }).catch(() => {
|
|
465
|
+
});
|
|
466
|
+
}
|
|
451
467
|
function ensure() {
|
|
452
468
|
if (client) return Promise.resolve(client);
|
|
453
469
|
connecting ??= open().finally(() => connecting = void 0);
|
|
@@ -473,7 +489,7 @@ async function runRelayMcp(options) {
|
|
|
473
489
|
return [
|
|
474
490
|
`${e.address}${me && e.id === me.id ? " (you)" : ""}`,
|
|
475
491
|
e.harness ?? e.kind,
|
|
476
|
-
e
|
|
492
|
+
presenceText(e),
|
|
477
493
|
e.title ? `title ${quote(e.title)}` : "",
|
|
478
494
|
status,
|
|
479
495
|
cwd ? quote(cwd) : "",
|
|
@@ -815,6 +831,9 @@ ${wrapMessage(message)}`,
|
|
|
815
831
|
const capabilities = params.capabilities;
|
|
816
832
|
const channel = capabilities?.experimental?.["claude/channel"];
|
|
817
833
|
channelClient = typeof channel === "object" && channel !== null || options.launchedWithChannels === true;
|
|
834
|
+
const clientInfo = params.clientInfo;
|
|
835
|
+
wake = options.channels && channelClient ? options.wake ?? (clientInfo?.name === "pi" ? "pi" : "channels") : null;
|
|
836
|
+
advertise();
|
|
818
837
|
return respond({
|
|
819
838
|
protocolVersion,
|
|
820
839
|
capabilities: { tools: {}, ...options.channels ? { experimental: { "claude/channel": {} } } : {} },
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scp-dev/mcp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "The SCP stdio MCP server: gives an agent session the relay's tools.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://scp.dev",
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
"typecheck": "tsc -p ."
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@scp-dev/broker": "0.1.
|
|
33
|
-
"@scp-dev/core": "0.1.
|
|
32
|
+
"@scp-dev/broker": "0.1.5",
|
|
33
|
+
"@scp-dev/core": "0.1.4"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"tsup": "^8.5.1"
|
package/src/server.ts
CHANGED
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
type SendResult,
|
|
19
19
|
type PeerView,
|
|
20
20
|
PREAMBLE,
|
|
21
|
+
presenceText,
|
|
21
22
|
reachLines,
|
|
22
23
|
receiptLines,
|
|
23
24
|
RelayError,
|
|
@@ -26,6 +27,7 @@ import {
|
|
|
26
27
|
shortId,
|
|
27
28
|
STATUS_STATES,
|
|
28
29
|
type ThreadMessage,
|
|
30
|
+
type Wake,
|
|
29
31
|
type WhyResult,
|
|
30
32
|
widenText,
|
|
31
33
|
wrapMessage,
|
|
@@ -65,6 +67,8 @@ export interface RelayMcpOptions {
|
|
|
65
67
|
channels?: boolean
|
|
66
68
|
/** the client was started with channels loaded (Claude Code does not declare the capability itself) */
|
|
67
69
|
launchedWithChannels?: boolean
|
|
70
|
+
/** the wake the endpoint advertises while this shim pushes by channel, over `pi` for a pi client and `channels` for any other */
|
|
71
|
+
wake?: Wake
|
|
68
72
|
version?: string
|
|
69
73
|
/** starts a worker for relay_spawn, resolving with its name and its runner's pid once its harness started; without it there is no relay_spawn */
|
|
70
74
|
spawn?: (request: SpawnRequest) => Promise<{ name: string; pid: number }>
|
|
@@ -366,7 +370,11 @@ function heldText(held: JudgeHeld): string {
|
|
|
366
370
|
|
|
367
371
|
/** a send's id, thread and recipients with their states, for a result's structuredContent */
|
|
368
372
|
function sentContent(result: SendResult): Record<string, unknown> {
|
|
369
|
-
return {
|
|
373
|
+
return {
|
|
374
|
+
id: result.id,
|
|
375
|
+
thread: result.thread,
|
|
376
|
+
recipients: result.deliveries.map((d) => ({ address: d.address, ...(d.state ? { state: d.state } : {}), ...(d.wake ? { wake: d.wake } : {}) })),
|
|
377
|
+
}
|
|
370
378
|
}
|
|
371
379
|
|
|
372
380
|
function redactedText(redacted: JudgeRedacted | undefined): string {
|
|
@@ -530,6 +538,9 @@ export async function runRelayMcp(options: RelayMcpOptions): Promise<void> {
|
|
|
530
538
|
/** seqs this shim pushed, so a push whose confirm was lost is not pushed again */
|
|
531
539
|
const channelPushed = new Set<number>()
|
|
532
540
|
let channelLoop: Promise<void> | undefined
|
|
541
|
+
/** what the endpoint advertises once initialize said whether the client takes channel pushes; null advertises nothing */
|
|
542
|
+
let wake: Wake | null | undefined
|
|
543
|
+
let advertised: { client: RelayClient; via: Wake } | undefined
|
|
533
544
|
|
|
534
545
|
const write = (message: Json) => {
|
|
535
546
|
if (!stopped) options.output(`${JSON.stringify(message)}\n`)
|
|
@@ -576,9 +587,19 @@ export async function runRelayMcp(options: RelayMcpOptions): Promise<void> {
|
|
|
576
587
|
throw new Error("the relay MCP shim is stopping")
|
|
577
588
|
}
|
|
578
589
|
client = next
|
|
590
|
+
advertise()
|
|
579
591
|
return next
|
|
580
592
|
}
|
|
581
593
|
|
|
594
|
+
/** tells the broker how a message wakes this session, once per connection and value, when both it and the client's capabilities are known */
|
|
595
|
+
function advertise() {
|
|
596
|
+
if (!client || wake === undefined) return
|
|
597
|
+
const via = wake ?? "none"
|
|
598
|
+
if ((advertised?.client === client && advertised.via === via) || (via === "none" && !advertised)) return
|
|
599
|
+
advertised = { client, via }
|
|
600
|
+
client.request("wake", { via }).catch(() => {})
|
|
601
|
+
}
|
|
602
|
+
|
|
582
603
|
function ensure(): Promise<RelayClient> {
|
|
583
604
|
if (client) return Promise.resolve(client)
|
|
584
605
|
connecting ??= open().finally(() => (connecting = undefined))
|
|
@@ -608,7 +629,7 @@ export async function runRelayMcp(options: RelayMcpOptions): Promise<void> {
|
|
|
608
629
|
return [
|
|
609
630
|
`${e.address}${me && e.id === me.id ? " (you)" : ""}`,
|
|
610
631
|
e.harness ?? e.kind,
|
|
611
|
-
e
|
|
632
|
+
presenceText(e),
|
|
612
633
|
e.title ? `title ${quote(e.title)}` : "",
|
|
613
634
|
status,
|
|
614
635
|
cwd ? quote(cwd) : "",
|
|
@@ -960,6 +981,9 @@ export async function runRelayMcp(options: RelayMcpOptions): Promise<void> {
|
|
|
960
981
|
const capabilities = params.capabilities as { experimental?: Record<string, unknown> } | undefined
|
|
961
982
|
const channel = capabilities?.experimental?.["claude/channel"]
|
|
962
983
|
channelClient = (typeof channel === "object" && channel !== null) || options.launchedWithChannels === true
|
|
984
|
+
const clientInfo = params.clientInfo as { name?: unknown } | undefined
|
|
985
|
+
wake = options.channels && channelClient ? (options.wake ?? (clientInfo?.name === "pi" ? "pi" : "channels")) : null
|
|
986
|
+
advertise()
|
|
963
987
|
return respond({
|
|
964
988
|
protocolVersion,
|
|
965
989
|
capabilities: { tools: {}, ...(options.channels ? { experimental: { "claude/channel": {} } } : {}) },
|