@descryy/mcp 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.
Files changed (118) hide show
  1. package/LICENSE +21 -0
  2. package/dist/action-handshake.d.ts +86 -0
  3. package/dist/action-handshake.d.ts.map +1 -0
  4. package/dist/action-handshake.js +144 -0
  5. package/dist/action-handshake.js.map +1 -0
  6. package/dist/bin/descry-mcp.d.ts +18 -0
  7. package/dist/bin/descry-mcp.d.ts.map +1 -0
  8. package/dist/bin/descry-mcp.js +54 -0
  9. package/dist/bin/descry-mcp.js.map +1 -0
  10. package/dist/index.d.ts +32 -0
  11. package/dist/index.d.ts.map +1 -0
  12. package/dist/index.js +15 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/language-guess.d.ts +17 -0
  15. package/dist/language-guess.d.ts.map +1 -0
  16. package/dist/language-guess.js +43 -0
  17. package/dist/language-guess.js.map +1 -0
  18. package/dist/protocol.d.ts +91 -0
  19. package/dist/protocol.d.ts.map +1 -0
  20. package/dist/protocol.js +127 -0
  21. package/dist/protocol.js.map +1 -0
  22. package/dist/registry.d.ts +72 -0
  23. package/dist/registry.d.ts.map +1 -0
  24. package/dist/registry.js +136 -0
  25. package/dist/registry.js.map +1 -0
  26. package/dist/render.d.ts +275 -0
  27. package/dist/render.d.ts.map +1 -0
  28. package/dist/render.js +333 -0
  29. package/dist/render.js.map +1 -0
  30. package/dist/server.d.ts +42 -0
  31. package/dist/server.d.ts.map +1 -0
  32. package/dist/server.js +263 -0
  33. package/dist/server.js.map +1 -0
  34. package/dist/session.d.ts +164 -0
  35. package/dist/session.d.ts.map +1 -0
  36. package/dist/session.js +302 -0
  37. package/dist/session.js.map +1 -0
  38. package/dist/tools/analyze.d.ts +124 -0
  39. package/dist/tools/analyze.d.ts.map +1 -0
  40. package/dist/tools/analyze.js +411 -0
  41. package/dist/tools/analyze.js.map +1 -0
  42. package/dist/tools/contracts.d.ts +105 -0
  43. package/dist/tools/contracts.d.ts.map +1 -0
  44. package/dist/tools/contracts.js +141 -0
  45. package/dist/tools/contracts.js.map +1 -0
  46. package/dist/tools/cross-pr.d.ts +137 -0
  47. package/dist/tools/cross-pr.d.ts.map +1 -0
  48. package/dist/tools/cross-pr.js +216 -0
  49. package/dist/tools/cross-pr.js.map +1 -0
  50. package/dist/tools/git-diff.d.ts +29 -0
  51. package/dist/tools/git-diff.d.ts.map +1 -0
  52. package/dist/tools/git-diff.js +117 -0
  53. package/dist/tools/git-diff.js.map +1 -0
  54. package/dist/tools/git-history.d.ts +27 -0
  55. package/dist/tools/git-history.d.ts.map +1 -0
  56. package/dist/tools/git-history.js +91 -0
  57. package/dist/tools/git-history.js.map +1 -0
  58. package/dist/tools/history.d.ts +63 -0
  59. package/dist/tools/history.d.ts.map +1 -0
  60. package/dist/tools/history.js +114 -0
  61. package/dist/tools/history.js.map +1 -0
  62. package/dist/tools/impact.d.ts +81 -0
  63. package/dist/tools/impact.d.ts.map +1 -0
  64. package/dist/tools/impact.js +229 -0
  65. package/dist/tools/impact.js.map +1 -0
  66. package/dist/tools/index.d.ts +33 -0
  67. package/dist/tools/index.d.ts.map +1 -0
  68. package/dist/tools/index.js +47 -0
  69. package/dist/tools/index.js.map +1 -0
  70. package/dist/tools/kit.d.ts +183 -0
  71. package/dist/tools/kit.d.ts.map +1 -0
  72. package/dist/tools/kit.js +117 -0
  73. package/dist/tools/kit.js.map +1 -0
  74. package/dist/tools/link-workspace.d.ts +62 -0
  75. package/dist/tools/link-workspace.d.ts.map +1 -0
  76. package/dist/tools/link-workspace.js +156 -0
  77. package/dist/tools/link-workspace.js.map +1 -0
  78. package/dist/tools/lookup.d.ts +29 -0
  79. package/dist/tools/lookup.d.ts.map +1 -0
  80. package/dist/tools/lookup.js +73 -0
  81. package/dist/tools/lookup.js.map +1 -0
  82. package/dist/tools/pr-analysis.d.ts +89 -0
  83. package/dist/tools/pr-analysis.d.ts.map +1 -0
  84. package/dist/tools/pr-analysis.js +169 -0
  85. package/dist/tools/pr-analysis.js.map +1 -0
  86. package/dist/tools/propagation.d.ts +74 -0
  87. package/dist/tools/propagation.d.ts.map +1 -0
  88. package/dist/tools/propagation.js +194 -0
  89. package/dist/tools/propagation.js.map +1 -0
  90. package/dist/tools/questions.d.ts +80 -0
  91. package/dist/tools/questions.d.ts.map +1 -0
  92. package/dist/tools/questions.js +213 -0
  93. package/dist/tools/questions.js.map +1 -0
  94. package/dist/tools/refusal-fetch.d.ts +71 -0
  95. package/dist/tools/refusal-fetch.d.ts.map +1 -0
  96. package/dist/tools/refusal-fetch.js +137 -0
  97. package/dist/tools/refusal-fetch.js.map +1 -0
  98. package/dist/tools/scope.d.ts +60 -0
  99. package/dist/tools/scope.d.ts.map +1 -0
  100. package/dist/tools/scope.js +160 -0
  101. package/dist/tools/scope.js.map +1 -0
  102. package/dist/tools/similar-incidents.d.ts +105 -0
  103. package/dist/tools/similar-incidents.d.ts.map +1 -0
  104. package/dist/tools/similar-incidents.js +228 -0
  105. package/dist/tools/similar-incidents.js.map +1 -0
  106. package/dist/tools/validate.d.ts +103 -0
  107. package/dist/tools/validate.d.ts.map +1 -0
  108. package/dist/tools/validate.js +176 -0
  109. package/dist/tools/validate.js.map +1 -0
  110. package/dist/tools/verification-status.d.ts +68 -0
  111. package/dist/tools/verification-status.d.ts.map +1 -0
  112. package/dist/tools/verification-status.js +179 -0
  113. package/dist/tools/verification-status.js.map +1 -0
  114. package/dist/transport.d.ts +58 -0
  115. package/dist/transport.d.ts.map +1 -0
  116. package/dist/transport.js +115 -0
  117. package/dist/transport.js.map +1 -0
  118. package/package.json +33 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Descry
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,86 @@
1
+ /**
2
+ * The two-call action-tool handshake — `ai-tool-contract.md` §7, DEC-278's
3
+ * `action` class.
4
+ *
5
+ * G5, the action gate, does not run in MCP mode: no pipeline sits between an
6
+ * external model and this server, so there is no control flow to hold the
7
+ * gate. The handshake is what replaces it. An unconfirmed call to an
8
+ * `action`-class tool performs nothing and returns a token plus a
9
+ * plain-English description of what confirming would do; only a second call
10
+ * presenting that exact token performs anything, and it performs the
11
+ * arguments frozen when the token was minted — never whatever the second
12
+ * call happens to supply. **The gate holds without the client's
13
+ * cooperation, because the server owns both the decision and the state.**
14
+ *
15
+ * ## Generic by construction
16
+ *
17
+ * A tool takes part by declaring `class: "action"` and providing
18
+ * `describeAction`, nothing else — the mint/redeem/expiry/single-use
19
+ * machinery below is shared by every present and future action tool rather
20
+ * than reimplemented per tool. `describeAction` returning `undefined` means
21
+ * *this particular call* has nothing to confirm — `questions` called with no
22
+ * `answer` is a pure read of the open-question queue, and gating that behind
23
+ * a token would make the tool unable to answer the first question asked of
24
+ * it (the same failure §4 names for over-gating `stateful-read`).
25
+ *
26
+ * ## The seam with the server's dispatch loop
27
+ *
28
+ * `resolveActionDispatch` decides *before* the caller's budget timer starts:
29
+ * a mint has no real work to time out on (no I/O, no `tool.run`), so it must
30
+ * not be raced against `tools.md` §6's budget the way a real call is. The
31
+ * caller (`server.ts`) checks `decision.kind` — `"handshake"` renders via
32
+ * `render.ts`'s `renderHandshake` immediately; `"run"` proceeds exactly as
33
+ * an ungated call would, using `decision.args` (the original arguments for
34
+ * a `read`/`stateful-read` tool or a pass-through `action` call, or the
35
+ * arguments captured at mint time for a redeemed one).
36
+ *
37
+ * ## Token design, decided here because nothing upstream decides it
38
+ *
39
+ * - **Binds to call 1's exact arguments.** The token is not a bare
40
+ * capability — it is minted together with a stored copy of the arguments
41
+ * that produced its `willDo`. Redeeming it runs *that* stored copy,
42
+ * ignoring whatever the redeeming call supplies alongside the token. A
43
+ * client cannot describe one action and, on confirmation, have a
44
+ * different one performed.
45
+ * - **Single-use.** A token is deleted from the store the moment it is
46
+ * looked up for redemption, whether or not that redemption goes on to
47
+ * succeed — replay is not a retry, and a caller that wants to do the same
48
+ * thing twice must be told about it twice.
49
+ * - **Five-minute expiry.** A starting value, not a measurement (no
50
+ * confirmation flow has run yet to measure a real gap between mint and
51
+ * confirm) — long enough for a human or a model to read `willDo` and
52
+ * decide, short enough that a token is not a standing credential.
53
+ * - **Unknown, expired or wrong-tool token → `ToolInputError`, never a
54
+ * silent no-op.** This is an argument the caller can fix (ask again,
55
+ * without `confirmToken`, for a fresh one) so it takes the same path as
56
+ * any other bad argument — a tool result the caller can read and act on,
57
+ * not a protocol error and not a quiet success that performed nothing.
58
+ * - **Session-scoped.** One MCP server process serves exactly one `Session`
59
+ * (`McpServerOptions` takes a single session, not a pool), so the store is
60
+ * keyed on the `Session` instance via a `WeakMap` rather than kept as
61
+ * module-global mutable state — the scoping a second session would need is
62
+ * already correct without anything having to change if one is ever added.
63
+ */
64
+ import { type ToolContext, type ToolDefinition } from "./tools/kit.ts";
65
+ export type ActionDispatch = {
66
+ readonly kind: "run";
67
+ readonly args: Record<string, unknown>;
68
+ } | {
69
+ readonly kind: "handshake";
70
+ readonly token: string;
71
+ readonly willDo: string;
72
+ };
73
+ /**
74
+ * Decides what a call to `tool` should do, before any budget timer starts.
75
+ *
76
+ * `read` and `stateful-read` tools, and an `action` tool whose
77
+ * `describeAction` says this call has nothing to confirm, resolve to
78
+ * `{ kind: "run", args }` with `args` unchanged. An unconfirmed call to a
79
+ * gated `action` tool resolves to `{ kind: "handshake", token, willDo }` —
80
+ * the caller must render this directly and must not call `tool.run`. A
81
+ * confirmed call (an `args.confirmToken` that redeems) resolves to `{ kind:
82
+ * "run", args }` with `args` replaced by the arguments captured at mint
83
+ * time.
84
+ */
85
+ export declare function resolveActionDispatch(tool: ToolDefinition, args: Record<string, unknown>, ctx: ToolContext): Promise<ActionDispatch>;
86
+ //# sourceMappingURL=action-handshake.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"action-handshake.d.ts","sourceRoot":"","sources":["../src/action-handshake.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8DG;AAIH,OAAO,EAAkB,KAAK,WAAW,EAAE,KAAK,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAiCvF,MAAM,MAAM,cAAc,GACtB;IAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GAChE;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpF;;;;;;;;;;;GAWG;AACH,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,cAAc,EACpB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,GAAG,EAAE,WAAW,GACf,OAAO,CAAC,cAAc,CAAC,CAazB"}
@@ -0,0 +1,144 @@
1
+ /**
2
+ * The two-call action-tool handshake — `ai-tool-contract.md` §7, DEC-278's
3
+ * `action` class.
4
+ *
5
+ * G5, the action gate, does not run in MCP mode: no pipeline sits between an
6
+ * external model and this server, so there is no control flow to hold the
7
+ * gate. The handshake is what replaces it. An unconfirmed call to an
8
+ * `action`-class tool performs nothing and returns a token plus a
9
+ * plain-English description of what confirming would do; only a second call
10
+ * presenting that exact token performs anything, and it performs the
11
+ * arguments frozen when the token was minted — never whatever the second
12
+ * call happens to supply. **The gate holds without the client's
13
+ * cooperation, because the server owns both the decision and the state.**
14
+ *
15
+ * ## Generic by construction
16
+ *
17
+ * A tool takes part by declaring `class: "action"` and providing
18
+ * `describeAction`, nothing else — the mint/redeem/expiry/single-use
19
+ * machinery below is shared by every present and future action tool rather
20
+ * than reimplemented per tool. `describeAction` returning `undefined` means
21
+ * *this particular call* has nothing to confirm — `questions` called with no
22
+ * `answer` is a pure read of the open-question queue, and gating that behind
23
+ * a token would make the tool unable to answer the first question asked of
24
+ * it (the same failure §4 names for over-gating `stateful-read`).
25
+ *
26
+ * ## The seam with the server's dispatch loop
27
+ *
28
+ * `resolveActionDispatch` decides *before* the caller's budget timer starts:
29
+ * a mint has no real work to time out on (no I/O, no `tool.run`), so it must
30
+ * not be raced against `tools.md` §6's budget the way a real call is. The
31
+ * caller (`server.ts`) checks `decision.kind` — `"handshake"` renders via
32
+ * `render.ts`'s `renderHandshake` immediately; `"run"` proceeds exactly as
33
+ * an ungated call would, using `decision.args` (the original arguments for
34
+ * a `read`/`stateful-read` tool or a pass-through `action` call, or the
35
+ * arguments captured at mint time for a redeemed one).
36
+ *
37
+ * ## Token design, decided here because nothing upstream decides it
38
+ *
39
+ * - **Binds to call 1's exact arguments.** The token is not a bare
40
+ * capability — it is minted together with a stored copy of the arguments
41
+ * that produced its `willDo`. Redeeming it runs *that* stored copy,
42
+ * ignoring whatever the redeeming call supplies alongside the token. A
43
+ * client cannot describe one action and, on confirmation, have a
44
+ * different one performed.
45
+ * - **Single-use.** A token is deleted from the store the moment it is
46
+ * looked up for redemption, whether or not that redemption goes on to
47
+ * succeed — replay is not a retry, and a caller that wants to do the same
48
+ * thing twice must be told about it twice.
49
+ * - **Five-minute expiry.** A starting value, not a measurement (no
50
+ * confirmation flow has run yet to measure a real gap between mint and
51
+ * confirm) — long enough for a human or a model to read `willDo` and
52
+ * decide, short enough that a token is not a standing credential.
53
+ * - **Unknown, expired or wrong-tool token → `ToolInputError`, never a
54
+ * silent no-op.** This is an argument the caller can fix (ask again,
55
+ * without `confirmToken`, for a fresh one) so it takes the same path as
56
+ * any other bad argument — a tool result the caller can read and act on,
57
+ * not a protocol error and not a quiet success that performed nothing.
58
+ * - **Session-scoped.** One MCP server process serves exactly one `Session`
59
+ * (`McpServerOptions` takes a single session, not a pool), so the store is
60
+ * keyed on the `Session` instance via a `WeakMap` rather than kept as
61
+ * module-global mutable state — the scoping a second session would need is
62
+ * already correct without anything having to change if one is ever added.
63
+ */
64
+ import { randomBytes } from "node:crypto";
65
+ import { ToolInputError } from "./tools/kit.js";
66
+ const TOKEN_TTL_MS = 5 * 60 * 1000;
67
+ const storesBySession = new WeakMap();
68
+ function storeFor(session) {
69
+ let store = storesBySession.get(session);
70
+ if (store === undefined) {
71
+ store = new Map();
72
+ storesBySession.set(session, store);
73
+ }
74
+ return store;
75
+ }
76
+ function prune(store) {
77
+ const now = Date.now();
78
+ for (const [token, pending] of store) {
79
+ if (pending.expiresAt < now)
80
+ store.delete(token);
81
+ }
82
+ }
83
+ function mintToken() {
84
+ return `act_${randomBytes(9).toString("base64url")}`;
85
+ }
86
+ /**
87
+ * Decides what a call to `tool` should do, before any budget timer starts.
88
+ *
89
+ * `read` and `stateful-read` tools, and an `action` tool whose
90
+ * `describeAction` says this call has nothing to confirm, resolve to
91
+ * `{ kind: "run", args }` with `args` unchanged. An unconfirmed call to a
92
+ * gated `action` tool resolves to `{ kind: "handshake", token, willDo }` —
93
+ * the caller must render this directly and must not call `tool.run`. A
94
+ * confirmed call (an `args.confirmToken` that redeems) resolves to `{ kind:
95
+ * "run", args }` with `args` replaced by the arguments captured at mint
96
+ * time.
97
+ */
98
+ export async function resolveActionDispatch(tool, args, ctx) {
99
+ if (tool.class !== "action")
100
+ return { kind: "run", args };
101
+ const confirmToken = args["confirmToken"];
102
+ if (confirmToken !== undefined && typeof confirmToken !== "string") {
103
+ throw new ToolInputError('"confirmToken" must be a string');
104
+ }
105
+ if (confirmToken === undefined) {
106
+ return mintOrPassThrough(tool, args, ctx);
107
+ }
108
+ return redeem(tool, confirmToken, ctx);
109
+ }
110
+ async function mintOrPassThrough(tool, args, ctx) {
111
+ if (tool.describeAction === undefined) {
112
+ // A bug in the tool registry, not a caller mistake: an author declared
113
+ // `class: "action"` without saying how to describe it. Thrown, not
114
+ // returned as a refusal — there is no argument the caller could change
115
+ // to fix this.
116
+ throw new Error(`${tool.name} declares class "action" but has no describeAction`);
117
+ }
118
+ const willDo = await tool.describeAction(args, ctx);
119
+ if (willDo === undefined)
120
+ return { kind: "run", args };
121
+ const store = storeFor(ctx.session);
122
+ prune(store);
123
+ const token = mintToken();
124
+ store.set(token, { toolName: tool.name, args, expiresAt: Date.now() + TOKEN_TTL_MS });
125
+ return { kind: "handshake", token, willDo };
126
+ }
127
+ async function redeem(tool, confirmToken, ctx) {
128
+ const store = storeFor(ctx.session);
129
+ const pending = store.get(confirmToken);
130
+ // Deleted on lookup, not on success: a replayed token is a used token
131
+ // whether or not what follows here succeeds.
132
+ store.delete(confirmToken);
133
+ if (pending === undefined) {
134
+ throw new ToolInputError(`"confirmToken" is unknown or was already used. Call ${tool.name} again without confirmToken for a fresh one.`);
135
+ }
136
+ if (pending.expiresAt < Date.now()) {
137
+ throw new ToolInputError(`"confirmToken" expired. Call ${tool.name} again without confirmToken for a fresh one.`);
138
+ }
139
+ if (pending.toolName !== tool.name) {
140
+ throw new ToolInputError(`"confirmToken" was not issued for ${tool.name}.`);
141
+ }
142
+ return { kind: "run", args: pending.args };
143
+ }
144
+ //# sourceMappingURL=action-handshake.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"action-handshake.js","sourceRoot":"","sources":["../src/action-handshake.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * The executable an MCP host launches.
4
+ *
5
+ * Takes the repository path as its only argument, defaulting to the working
6
+ * directory — which is what a host passes when it starts the server inside a
7
+ * project. Everything else comes from `.descry/config.json`.
8
+ *
9
+ * ## Nothing may print before the transport is installed
10
+ *
11
+ * `serveStdio` redirects every console channel to stderr on its first line. Any
12
+ * output *before* that call goes to real stdout and corrupts the very first
13
+ * frame — the handshake — which is the worst place to fail, because the host
14
+ * reports it as "server did not start" with no further detail. So this file
15
+ * writes nothing itself and does its argument handling before opening anything.
16
+ */
17
+ export {};
18
+ //# sourceMappingURL=descry-mcp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"descry-mcp.d.ts","sourceRoot":"","sources":["../../src/bin/descry-mcp.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;GAcG"}
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * The executable an MCP host launches.
4
+ *
5
+ * Takes the repository path as its only argument, defaulting to the working
6
+ * directory — which is what a host passes when it starts the server inside a
7
+ * project. Everything else comes from `.descry/config.json`.
8
+ *
9
+ * ## Nothing may print before the transport is installed
10
+ *
11
+ * `serveStdio` redirects every console channel to stderr on its first line. Any
12
+ * output *before* that call goes to real stdout and corrupts the very first
13
+ * frame — the handshake — which is the worst place to fail, because the host
14
+ * reports it as "server did not start" with no further detail. So this file
15
+ * writes nothing itself and does its argument handling before opening anything.
16
+ */
17
+ import process from "node:process";
18
+ import { resolve } from "node:path";
19
+ import { createMcpServer } from "../server.js";
20
+ import { Session } from "../session.js";
21
+ import { serveStdio } from "../transport.js";
22
+ const USAGE = `descry-mcp — Descry's MCP server (stdio)
23
+
24
+ descry-mcp [repository-path]
25
+
26
+ Reads .descry/config.json from the repository for the graph location and the
27
+ list of adapter packages to load. Runs until stdin closes.
28
+ `;
29
+ async function main() {
30
+ const args = process.argv.slice(2);
31
+ if (args.includes("--help") || args.includes("-h")) {
32
+ process.stderr.write(USAGE);
33
+ return 0;
34
+ }
35
+ const repoPath = resolve(args[0] ?? process.cwd());
36
+ const session = await Session.open({ repoPath });
37
+ const server = createMcpServer({ session, name: "descry", version: "0.0.0" });
38
+ try {
39
+ await serveStdio({ stdin: process.stdin, stdout: process.stdout, stderr: process.stderr }, (line, transport) => server.dispatch(line, transport));
40
+ return 0;
41
+ }
42
+ finally {
43
+ // The SQLite handle and anything else with a lifetime. Held open past the
44
+ // end of stdin, a WAL journal outlives the process that owned it.
45
+ session.close();
46
+ }
47
+ }
48
+ main().then((code) => {
49
+ process.exitCode = code;
50
+ }, (error) => {
51
+ process.stderr.write(`descry-mcp: ${error instanceof Error ? error.stack ?? error.message : String(error)}\n`);
52
+ process.exitCode = 1;
53
+ });
54
+ //# sourceMappingURL=descry-mcp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"descry-mcp.js","sourceRoot":"","sources":["../../src/bin/descry-mcp.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,OAAO,MAAM,cAAc,CAAC;AACnC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,MAAM,KAAK,GAAG;;;;;;CAMb,CAAC;AAEF,KAAK,UAAU,IAAI;IACjB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACnD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC5B,OAAO,CAAC,CAAC;IACX,CAAC;IAED,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IACnD,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC;IACjD,MAAM,MAAM,GAAG,eAAe,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;IAE9E,IAAI,CAAC;QACH,MAAM,UAAU,CACd,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,EACxE,CAAC,IAAI,EAAE,SAAS,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC,CACtD,CAAC;QACF,OAAO,CAAC,CAAC;IACX,CAAC;YAAS,CAAC;QACT,0EAA0E;QAC1E,kEAAkE;QAClE,OAAO,CAAC,KAAK,EAAE,CAAC;IAClB,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC,IAAI,CACT,CAAC,IAAI,EAAE,EAAE;IACP,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;AAC1B,CAAC,EACD,CAAC,KAAc,EAAE,EAAE;IACjB,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,eAAe,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CACzF,CAAC;IACF,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC,CACF,CAAC"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * `@descryy/mcp` — the agent-facing front door.
3
+ *
4
+ * A thin wrapper over the query layer, as DEC-002 requires: every consumer goes
5
+ * through here and **nothing touches storage directly**. That is why the tools
6
+ * hold a `Session` and not a driver.
7
+ */
8
+ export { createMcpServer } from "./server.ts";
9
+ export type { McpServer, McpServerOptions } from "./server.ts";
10
+ export { Session, loadConfig, writeConfig, writeSources, ConfigError, CONFIG_RELATIVE_PATH, DEFAULT_GRAPH_RELATIVE_PATH, } from "./session.ts";
11
+ export type { DescryConfig, SessionOptions, ConfigPatch } from "./session.ts";
12
+ export { loadSources, detectSources, normaliseSpec } from "./registry.ts";
13
+ export type { SourceSpec, LoadedSource, SourceLoadFailure, RegistryResult } from "./registry.ts";
14
+ export { renderAnswer, renderFailed, renderHandshake, renderTimedOut, renderToolError, DisclosureError, TOOL_TIERS, } from "./render.ts";
15
+ export type { AnswerEnvelope, CallToolResult, Provenance, ResultState, ToolAnswer, ToolTier, TruncationDetail, } from "./render.ts";
16
+ export { TOOLS, TOOLS_BY_NAME, ToolInputError, resolveOneNode } from "./tools/index.ts";
17
+ export type { BriefNode, NodeCandidates, Progress, ToolContext, ToolDefinition, } from "./tools/index.ts";
18
+ /**
19
+ * The shape each tool puts in `AnswerEnvelope.data`.
20
+ *
21
+ * `data` is `unknown` in the envelope by design — it differs per tool — but
22
+ * "read the handler" is not a contract, and an AI caller cannot rely on a
23
+ * shape nobody wrote down. Each of these describes what its tool returns
24
+ * **today**; where a tool's payload is genuinely conditional the type is a
25
+ * union that says so rather than a widening to `unknown`.
26
+ */
27
+ export type { AffectedNode, AnalyzeData, BlockedCheck, CoChangedFile, ConfigDependencyReport, ContractPathFinding, ContractShapeMismatchReport, ContractShapeStatus, ContractsData, CrossPrData, CrossPrEmptyDiff, CrossPrGitFailure, CrossPrReport, EnvFindingReport, HiddenDependencyCheck, HiddenDependencyFinding, HistoryData, HistoryFile, HistoryFileResolved, HistoryFileUnresolved, HistoryReport, ImpactData, ImpactReport, ImpactedNode, LinkWorkspaceData, LinkedRepo, OverlapCheck, OverlapReportChecked, PrAnalysisData, PrAnalysisEmptyDiff, PrAnalysisGitFailure, PrAnalysisRange, PrAnalysisReport, PrAnalysisUnresolved, PropagationData, PropagationReport, QuestionsData, ReachedNode, RelatedNode, ScopeData, ScopeNotSeeded, ScopeReport, ScopeTierCount, ScopedNodeReport, SimilarIncidentReport, SimilarIncidentSignalReport, SimilarIncidentsData, SourceRun, SupersededCheck, TracedPath, ValidateData, } from "./tools/index.ts";
28
+ export { serveStdio, guardStdout, createLineReader } from "./transport.ts";
29
+ export type { Transport, StdioOptions } from "./transport.ts";
30
+ export { PROTOCOL_VERSION, SUPPORTED_PROTOCOL_VERSIONS, negotiateVersion, parseMessage, ProtocolError, } from "./protocol.ts";
31
+ export type { RpcRequest, RpcNotification, RpcResponse, RpcMessage, RpcId } from "./protocol.ts";
32
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,YAAY,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/D,OAAO,EACL,OAAO,EACP,UAAU,EACV,WAAW,EACX,YAAY,EACZ,WAAW,EACX,oBAAoB,EACpB,2BAA2B,GAC5B,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE9E,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC1E,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEjG,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,cAAc,EACd,eAAe,EACf,eAAe,EACf,UAAU,GACX,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,cAAc,EACd,cAAc,EACd,UAAU,EACV,WAAW,EACX,UAAU,EACV,QAAQ,EACR,gBAAgB,GACjB,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACxF,YAAY,EACV,SAAS,EACT,cAAc,EACd,QAAQ,EACR,WAAW,EACX,cAAc,GACf,MAAM,kBAAkB,CAAC;AAE1B;;;;;;;;GAQG;AACH,YAAY,EACV,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,aAAa,EACb,sBAAsB,EACtB,mBAAmB,EACnB,2BAA2B,EAC3B,mBAAmB,EACnB,aAAa,EACb,WAAW,EACX,gBAAgB,EAChB,iBAAiB,EACjB,aAAa,EACb,gBAAgB,EAChB,qBAAqB,EACrB,uBAAuB,EACvB,WAAW,EACX,WAAW,EACX,mBAAmB,EACnB,qBAAqB,EACrB,aAAa,EACb,UAAU,EACV,YAAY,EACZ,YAAY,EACZ,iBAAiB,EACjB,UAAU,EACV,YAAY,EACZ,oBAAoB,EACpB,cAAc,EACd,mBAAmB,EACnB,oBAAoB,EACpB,eAAe,EACf,gBAAgB,EAChB,oBAAoB,EACpB,eAAe,EACf,iBAAiB,EACjB,aAAa,EACb,WAAW,EACX,WAAW,EACX,SAAS,EACT,cAAc,EACd,WAAW,EACX,cAAc,EACd,gBAAgB,EAChB,qBAAqB,EACrB,2BAA2B,EAC3B,oBAAoB,EACpB,SAAS,EACT,eAAe,EACf,UAAU,EACV,YAAY,GACb,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAC3E,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9D,OAAO,EACL,gBAAgB,EAChB,2BAA2B,EAC3B,gBAAgB,EAChB,YAAY,EACZ,aAAa,GACd,MAAM,eAAe,CAAC;AACvB,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,WAAW,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,15 @@
1
+ /**
2
+ * `@descryy/mcp` — the agent-facing front door.
3
+ *
4
+ * A thin wrapper over the query layer, as DEC-002 requires: every consumer goes
5
+ * through here and **nothing touches storage directly**. That is why the tools
6
+ * hold a `Session` and not a driver.
7
+ */
8
+ export { createMcpServer } from "./server.js";
9
+ export { Session, loadConfig, writeConfig, writeSources, ConfigError, CONFIG_RELATIVE_PATH, DEFAULT_GRAPH_RELATIVE_PATH, } from "./session.js";
10
+ export { loadSources, detectSources, normaliseSpec } from "./registry.js";
11
+ export { renderAnswer, renderFailed, renderHandshake, renderTimedOut, renderToolError, DisclosureError, TOOL_TIERS, } from "./render.js";
12
+ export { TOOLS, TOOLS_BY_NAME, ToolInputError, resolveOneNode } from "./tools/index.js";
13
+ export { serveStdio, guardStdout, createLineReader } from "./transport.js";
14
+ export { PROTOCOL_VERSION, SUPPORTED_PROTOCOL_VERSIONS, negotiateVersion, parseMessage, ProtocolError, } from "./protocol.js";
15
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAG9C,OAAO,EACL,OAAO,EACP,UAAU,EACV,WAAW,EACX,YAAY,EACZ,WAAW,EACX,oBAAoB,EACpB,2BAA2B,GAC5B,MAAM,cAAc,CAAC;AAGtB,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAG1E,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,cAAc,EACd,eAAe,EACf,eAAe,EACf,UAAU,GACX,MAAM,aAAa,CAAC;AAWrB,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAwExF,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAG3E,OAAO,EACL,gBAAgB,EAChB,2BAA2B,EAC3B,gBAAgB,EAChB,YAAY,EACZ,aAAa,GACd,MAAM,eAAe,CAAC"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * A guess, never an assertion — this module names its own limits so nothing
3
+ * downstream mistakes its output for a confirmed fact.
4
+ *
5
+ * `verification_status` needs a language name for a ref that resolved to
6
+ * nothing in the graph, to check whether a *configured, declared* source
7
+ * covers it (`registry.ts`'s `SourceSpec.language`). Extension alone cannot
8
+ * confirm a file's language — a `.h` file could be C or C++, a build script
9
+ * could be anything — so this table only maps extensions unambiguous enough
10
+ * that a wrong guess would be a surprise, and returns `null` rather than a
11
+ * plausible-but-unconfirmed answer for everything else. `null` here means
12
+ * exactly what it always meant one layer up: "this tool did not determine
13
+ * one," never "no language exists."
14
+ */
15
+ /** `null` on anything not confidently namable — see the module header. */
16
+ export declare function guessLanguageFromPath(path: string): string | null;
17
+ //# sourceMappingURL=language-guess.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"language-guess.d.ts","sourceRoot":"","sources":["../src/language-guess.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAwBH,0EAA0E;AAC1E,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAIjE"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * A guess, never an assertion — this module names its own limits so nothing
3
+ * downstream mistakes its output for a confirmed fact.
4
+ *
5
+ * `verification_status` needs a language name for a ref that resolved to
6
+ * nothing in the graph, to check whether a *configured, declared* source
7
+ * covers it (`registry.ts`'s `SourceSpec.language`). Extension alone cannot
8
+ * confirm a file's language — a `.h` file could be C or C++, a build script
9
+ * could be anything — so this table only maps extensions unambiguous enough
10
+ * that a wrong guess would be a surprise, and returns `null` rather than a
11
+ * plausible-but-unconfirmed answer for everything else. `null` here means
12
+ * exactly what it always meant one layer up: "this tool did not determine
13
+ * one," never "no language exists."
14
+ */
15
+ const EXTENSION_TO_LANGUAGE = {
16
+ ts: "typescript",
17
+ tsx: "typescript",
18
+ js: "javascript",
19
+ jsx: "javascript",
20
+ mjs: "javascript",
21
+ cjs: "javascript",
22
+ py: "python",
23
+ go: "go",
24
+ java: "java",
25
+ kt: "kotlin",
26
+ kts: "kotlin",
27
+ cs: "csharp",
28
+ php: "php",
29
+ rb: "ruby",
30
+ rs: "rust",
31
+ swift: "swift",
32
+ sql: "sql",
33
+ sh: "bash",
34
+ bash: "bash",
35
+ };
36
+ /** `null` on anything not confidently namable — see the module header. */
37
+ export function guessLanguageFromPath(path) {
38
+ const match = /\.([^./]+)$/.exec(path);
39
+ if (match === null)
40
+ return null;
41
+ return EXTENSION_TO_LANGUAGE[match[1].toLowerCase()] ?? null;
42
+ }
43
+ //# sourceMappingURL=language-guess.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"language-guess.js","sourceRoot":"","sources":["../src/language-guess.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,MAAM,qBAAqB,GAAqC;IAC9D,EAAE,EAAE,YAAY;IAChB,GAAG,EAAE,YAAY;IACjB,EAAE,EAAE,YAAY;IAChB,GAAG,EAAE,YAAY;IACjB,GAAG,EAAE,YAAY;IACjB,GAAG,EAAE,YAAY;IACjB,EAAE,EAAE,QAAQ;IACZ,EAAE,EAAE,IAAI;IACR,IAAI,EAAE,MAAM;IACZ,EAAE,EAAE,QAAQ;IACZ,GAAG,EAAE,QAAQ;IACb,EAAE,EAAE,QAAQ;IACZ,GAAG,EAAE,KAAK;IACV,EAAE,EAAE,MAAM;IACV,EAAE,EAAE,MAAM;IACV,KAAK,EAAE,OAAO;IACd,GAAG,EAAE,KAAK;IACV,EAAE,EAAE,MAAM;IACV,IAAI,EAAE,MAAM;CACb,CAAC;AAEF,0EAA0E;AAC1E,MAAM,UAAU,qBAAqB,CAAC,IAAY;IAChD,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACvC,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAChC,OAAO,qBAAqB,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,WAAW,EAAE,CAAC,IAAI,IAAI,CAAC;AAChE,CAAC"}
@@ -0,0 +1,91 @@
1
+ /**
2
+ * JSON-RPC 2.0 and the slice of MCP this server speaks.
3
+ *
4
+ * ## Why this is hand-written
5
+ *
6
+ * `@modelcontextprotocol/sdk` is the obvious answer and the blueprint's
7
+ * dependency table names it. It was measured rather than assumed: version 1.30.0
8
+ * declares **seventeen direct dependencies** — `express`, `hono`,
9
+ * `@hono/node-server`, `cors`, `express-rate-limit`, `jose`, `pkce-challenge`,
10
+ * `eventsource`, `ajv`, `zod` — essentially all of which exist to serve the HTTP
11
+ * and OAuth transports. This server speaks stdio to a coding agent on the same
12
+ * machine. It will never open a socket.
13
+ *
14
+ * The rest of this project has made the same call four times — `node:sqlite`
15
+ * over `better-sqlite3`, `node --test` over a test runner, `tsc` over a bundler,
16
+ * `git` invoked directly over a git library — every time on the same grounds:
17
+ * this is a **locally installed developer tool**, and a dependency tree is a
18
+ * distribution problem before it is anything else. Both shipped packages have
19
+ * zero runtime dependencies today. Seventeen transitively-hundreds is a large
20
+ * price for newline-delimited JSON.
21
+ *
22
+ * **The cost is named, not waved away.** Hand-rolling means spec drift is
23
+ * silent: the wire format changes, the client stops working, and nothing in this
24
+ * repository fails. Two things pay it down. `PROTOCOL_VERSION` is pinned and
25
+ * `SUPPORTED_PROTOCOL_VERSIONS` is explicit, so an unknown version is negotiated
26
+ * rather than assumed compatible; and the handshake is covered by tests that
27
+ * assert the exact frames, so a change to the shape is a red test rather than a
28
+ * user-visible mystery. If the protocol moves past what is here, the fix is to
29
+ * add a version to the list — not to discover it from a bug report.
30
+ */
31
+ /** JSON-RPC 2.0 ids: string or number, never null in a request. */
32
+ export type RpcId = string | number;
33
+ export interface RpcRequest {
34
+ readonly jsonrpc: "2.0";
35
+ readonly id: RpcId;
36
+ readonly method: string;
37
+ readonly params?: Record<string, unknown>;
38
+ }
39
+ export interface RpcNotification {
40
+ readonly jsonrpc: "2.0";
41
+ readonly method: string;
42
+ readonly params?: Record<string, unknown>;
43
+ }
44
+ export interface RpcError {
45
+ readonly code: number;
46
+ readonly message: string;
47
+ readonly data?: unknown;
48
+ }
49
+ export interface RpcResponse {
50
+ readonly jsonrpc: "2.0";
51
+ readonly id: RpcId;
52
+ readonly result?: unknown;
53
+ readonly error?: RpcError;
54
+ }
55
+ export type RpcMessage = RpcRequest | RpcNotification;
56
+ /** Standard JSON-RPC codes. MCP adds none of its own at this layer. */
57
+ export declare const RPC_PARSE_ERROR = -32700;
58
+ export declare const RPC_INVALID_REQUEST = -32600;
59
+ export declare const RPC_METHOD_NOT_FOUND = -32601;
60
+ export declare const RPC_INVALID_PARAMS = -32602;
61
+ export declare const RPC_INTERNAL_ERROR = -32603;
62
+ /**
63
+ * The version this server implements.
64
+ *
65
+ * Newest first. Negotiation echoes the client's version when it is on this list
66
+ * and otherwise answers with `PROTOCOL_VERSION`, which is what the spec asks for
67
+ * — the client then decides whether it can proceed. Answering with the client's
68
+ * unknown version instead would be a claim of compatibility nobody has checked.
69
+ */
70
+ export declare const PROTOCOL_VERSION = "2025-06-18";
71
+ export declare const SUPPORTED_PROTOCOL_VERSIONS: readonly string[];
72
+ export declare function negotiateVersion(requested: unknown): string;
73
+ /**
74
+ * A frame that could not be understood well enough to answer.
75
+ *
76
+ * Distinguished from a request that is merely wrong, because JSON-RPC says a
77
+ * message with no usable id gets no response at all — replying to it with a
78
+ * fabricated id would put a frame on the wire the client cannot correlate.
79
+ */
80
+ export declare class ProtocolError extends Error {
81
+ readonly code: number;
82
+ /** Null when the frame carried no usable id and must therefore go unanswered. */
83
+ readonly id: RpcId | null;
84
+ constructor(code: number, message: string, id: RpcId | null);
85
+ }
86
+ /** Parse one line into a request or notification, or throw `ProtocolError`. */
87
+ export declare function parseMessage(line: string): RpcMessage;
88
+ export declare function isRequest(message: RpcMessage): message is RpcRequest;
89
+ export declare function ok(id: RpcId, result: unknown): RpcResponse;
90
+ export declare function fail(id: RpcId, code: number, message: string, data?: unknown): RpcResponse;
91
+ //# sourceMappingURL=protocol.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,mEAAmE;AACnE,MAAM,MAAM,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC;AAEpC,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC;IACxB,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IACnB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC3C;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC3C;AAED,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC;IACxB,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IACnB,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAC;CAC3B;AAED,MAAM,MAAM,UAAU,GAAG,UAAU,GAAG,eAAe,CAAC;AAEtD,uEAAuE;AACvE,eAAO,MAAM,eAAe,SAAS,CAAC;AACtC,eAAO,MAAM,mBAAmB,SAAS,CAAC;AAC1C,eAAO,MAAM,oBAAoB,SAAS,CAAC;AAC3C,eAAO,MAAM,kBAAkB,SAAS,CAAC;AACzC,eAAO,MAAM,kBAAkB,SAAS,CAAC;AAEzC;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB,eAAe,CAAC;AAC7C,eAAO,MAAM,2BAA2B,EAAE,SAAS,MAAM,EAIxD,CAAC;AAEF,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,OAAO,GAAG,MAAM,CAI3D;AAMD;;;;;;GAMG;AACH,qBAAa,aAAc,SAAQ,KAAK;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,iFAAiF;IACjF,QAAQ,CAAC,EAAE,EAAE,KAAK,GAAG,IAAI,CAAC;gBAEd,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,KAAK,GAAG,IAAI;CAM5D;AAMD,+EAA+E;AAC/E,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAsCrD;AAED,wBAAgB,SAAS,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,IAAI,UAAU,CAEpE;AAED,wBAAgB,EAAE,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,GAAG,WAAW,CAE1D;AAED,wBAAgB,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,WAAW,CAM1F"}