@adrkit/mcp 0.2.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 +99 -0
- package/dist/LICENSE +201 -0
- package/dist/NOTICE +11 -0
- package/dist/bin.d.ts +8 -0
- package/dist/bin.js +1156 -0
- package/dist/corpus/ordering.d.ts +17 -0
- package/dist/corpus/projection.d.ts +47 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +1093 -0
- package/dist/main-module.d.ts +11 -0
- package/dist/pagination/cursor.d.ts +67 -0
- package/dist/search/normalize.d.ts +7 -0
- package/dist/server.d.ts +16 -0
- package/dist/tools/get-decision-context.d.ts +11 -0
- package/dist/tools/get-decision.d.ts +11 -0
- package/dist/tools/list-superseded.d.ts +11 -0
- package/dist/tools/search-decisions.d.ts +11 -0
- package/dist/tools/shared.d.ts +252 -0
- package/package.json +59 -0
- package/src/bin.ts +13 -0
- package/src/corpus/ordering.ts +41 -0
- package/src/corpus/projection.ts +299 -0
- package/src/index.ts +96 -0
- package/src/main-module.ts +82 -0
- package/src/pagination/cursor.ts +162 -0
- package/src/search/normalize.ts +9 -0
- package/src/server.ts +27 -0
- package/src/tools/get-decision-context.ts +137 -0
- package/src/tools/get-decision.ts +169 -0
- package/src/tools/list-superseded.ts +148 -0
- package/src/tools/search-decisions.ts +131 -0
- package/src/tools/shared.ts +583 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @adrkit/mcp — CLI/startup helpers for the `adrkit-mcp` bin.
|
|
3
|
+
*
|
|
4
|
+
* The only place `process.argv`/`process.env` are read, the FR-036 startup check
|
|
5
|
+
* lives, and the `isMainModule()` guard is defined. A local helper mirroring
|
|
6
|
+
* `packages/cli/src/main-module.ts` (not imported from it). stdout is reserved for
|
|
7
|
+
* protocol frames; every diagnostic goes to stderr.
|
|
8
|
+
*/
|
|
9
|
+
export declare function isMainModule(moduleUrl: string, argvPath: string | undefined): boolean;
|
|
10
|
+
export declare function reportUnhandledRejection(reason: unknown, write?: (text: string) => void, fail?: () => void): void;
|
|
11
|
+
export declare function main(argv: string[], env: Record<string, string | undefined>): Promise<0 | 1 | 2>;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @adrkit/mcp — opaque, versioned, query-bound pagination cursors and the
|
|
3
|
+
* query-shape hash (contracts/pagination-and-cursors.md).
|
|
4
|
+
*/
|
|
5
|
+
export type CursorScope = 'search.results' | 'search.findings' | 'get_decision.candidates' | 'get_decision.findings' | 'context.results' | 'context.findings' | 'superseded.results' | 'superseded.findings';
|
|
6
|
+
export interface CursorPayloadV1 {
|
|
7
|
+
readonly v: 1;
|
|
8
|
+
readonly scope: CursorScope;
|
|
9
|
+
readonly fp: string;
|
|
10
|
+
readonly qh: string;
|
|
11
|
+
readonly offset: number;
|
|
12
|
+
}
|
|
13
|
+
export type InvalidCursorReason = 'decode-failed' | 'version-unsupported' | 'wrong-channel' | 'corpus-changed' | 'query-mismatch' | 'cursor-not-applicable' | 'offset-out-of-range';
|
|
14
|
+
export interface Page<T> {
|
|
15
|
+
readonly items: readonly T[];
|
|
16
|
+
readonly cursor: string | null;
|
|
17
|
+
}
|
|
18
|
+
/** Fixed-field-order base64url(no-pad) UTF-8 JSON — byte-identical for identical payloads. */
|
|
19
|
+
export declare function encodeCursor(payload: CursorPayloadV1): string;
|
|
20
|
+
/** SHA-256 hex over a fixed-order canonical JSON array of the hashed parameters. */
|
|
21
|
+
export declare function queryShapeHash(parts: readonly unknown[]): string;
|
|
22
|
+
export interface VerifyCursorOptions {
|
|
23
|
+
readonly cursor: string;
|
|
24
|
+
readonly expectedScope: CursorScope;
|
|
25
|
+
readonly fp: string;
|
|
26
|
+
readonly qh: string;
|
|
27
|
+
}
|
|
28
|
+
export type VerifyCursorResult = {
|
|
29
|
+
readonly ok: true;
|
|
30
|
+
readonly offset: number;
|
|
31
|
+
} | {
|
|
32
|
+
readonly ok: false;
|
|
33
|
+
readonly reason: InvalidCursorReason;
|
|
34
|
+
};
|
|
35
|
+
/** Decode/verify steps 1-6 (pagination §2). */
|
|
36
|
+
export declare function verifyCursor(options: VerifyCursorOptions): VerifyCursorResult;
|
|
37
|
+
export interface PaginateOptions<T> {
|
|
38
|
+
readonly items: readonly T[];
|
|
39
|
+
readonly cursor: string | undefined;
|
|
40
|
+
readonly limit: number;
|
|
41
|
+
readonly scope: CursorScope;
|
|
42
|
+
readonly fp: string;
|
|
43
|
+
readonly qh: string;
|
|
44
|
+
}
|
|
45
|
+
export type PaginateResult<T> = {
|
|
46
|
+
readonly ok: true;
|
|
47
|
+
readonly page: Page<T>;
|
|
48
|
+
} | {
|
|
49
|
+
readonly ok: false;
|
|
50
|
+
readonly reason: InvalidCursorReason;
|
|
51
|
+
};
|
|
52
|
+
/** Full applicable-channel pagination: verify (1-6), range-check (8), slice (9), mint. */
|
|
53
|
+
export declare function paginate<T>(options: PaginateOptions<T>): PaginateResult<T>;
|
|
54
|
+
export interface InapplicablePrimaryOptions {
|
|
55
|
+
readonly cursor: string | undefined;
|
|
56
|
+
readonly scope: CursorScope;
|
|
57
|
+
readonly fp: string;
|
|
58
|
+
readonly qh: string;
|
|
59
|
+
}
|
|
60
|
+
export type InapplicablePrimaryResult = {
|
|
61
|
+
readonly ok: true;
|
|
62
|
+
} | {
|
|
63
|
+
readonly ok: false;
|
|
64
|
+
readonly reason: InvalidCursorReason;
|
|
65
|
+
};
|
|
66
|
+
/** A primary cursor supplied against an outcome with no primary channel (step 7). */
|
|
67
|
+
export declare function checkInapplicablePrimaryCursor(options: InapplicablePrimaryOptions): InapplicablePrimaryResult;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @adrkit/mcp — deterministic search normalization (research §R5).
|
|
3
|
+
*
|
|
4
|
+
* `normalize(s) = s.trim().normalize('NFKC').toLowerCase()` — engine-builtin,
|
|
5
|
+
* non-ICU, locale-independent. No stemming, fuzzy, weighting, or ranking.
|
|
6
|
+
*/
|
|
7
|
+
export declare function normalize(value: string): string;
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @adrkit/mcp — internal server assembly (package-internal, never publicly exported).
|
|
3
|
+
*
|
|
4
|
+
* Owns the concrete `McpServer`, its registration APIs, and the in-memory builder
|
|
5
|
+
* used only by in-process conformance tests. The public factory (`./index.ts`)
|
|
6
|
+
* exposes only the sealed lifecycle handle. This module is absent from
|
|
7
|
+
* `package.json#exports` and every public subpath.
|
|
8
|
+
*/
|
|
9
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
10
|
+
import type { ToolConfig } from './tools/shared.js';
|
|
11
|
+
export declare const SERVER_INFO: {
|
|
12
|
+
readonly name: "@adrkit/mcp";
|
|
13
|
+
readonly version: "0.1.0";
|
|
14
|
+
};
|
|
15
|
+
/** Package-internal: build the concrete server with exactly the four ratified tools. */
|
|
16
|
+
export declare function buildRegisteredServer(config: ToolConfig): McpServer;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @adrkit/mcp — the `get_decision_context` tool (US2, contracts/tools.md §6).
|
|
3
|
+
*
|
|
4
|
+
* Reports governing, active-proposal, and historical records for logical file
|
|
5
|
+
* paths using the existing `resolveAffects` resolver, once per record, without ever
|
|
6
|
+
* reading a caller-supplied path. One canonical flat walk is paginated, then the
|
|
7
|
+
* page is partitioned by status.
|
|
8
|
+
*/
|
|
9
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
10
|
+
import { type ToolConfig } from './shared.js';
|
|
11
|
+
export declare function registerGetDecisionContext(server: McpServer, config: ToolConfig): void;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @adrkit/mcp — the `get_decision` tool (US1, contracts/tools.md §4).
|
|
3
|
+
*
|
|
4
|
+
* Fetches one within-limit decision by ref. `parseAdrRef` detects a log-qualified
|
|
5
|
+
* ref first (→ federated-log-unavailable, never a local substitute); a bare id is
|
|
6
|
+
* resolved through the fresh local `byId` bucket into found / not-found /
|
|
7
|
+
* ambiguous-local-id. Relation refs are surfaced verbatim, never expanded.
|
|
8
|
+
*/
|
|
9
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
10
|
+
import { type ToolConfig } from './shared.js';
|
|
11
|
+
export declare function registerGetDecision(server: McpServer, config: ToolConfig): void;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @adrkit/mcp — the `list_superseded` tool (US4, contracts/tools.md §7).
|
|
3
|
+
*
|
|
4
|
+
* Lists every superseded record with its DIRECT local replacement state, resolving
|
|
5
|
+
* only unqualified local targets through the fresh `byId` bucket. Never walks
|
|
6
|
+
* lineage, never embeds candidate arrays, and mints only the two specified derived
|
|
7
|
+
* finding templates.
|
|
8
|
+
*/
|
|
9
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
10
|
+
import { type ToolConfig } from './shared.js';
|
|
11
|
+
export declare function registerListSuperseded(server: McpServer, config: ToolConfig): void;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @adrkit/mcp — the `search_decisions` tool (US3, contracts/tools.md §5).
|
|
3
|
+
*
|
|
4
|
+
* Deterministic normalized literal substring search over id, title, tags, and
|
|
5
|
+
* body. Filters (status any-of, scope any-of, tags all-of, ANDed) apply before the
|
|
6
|
+
* normalizer. Graveyard records are included by default. Returns bounded summaries
|
|
7
|
+
* only — never a body, ranking score, or hidden index.
|
|
8
|
+
*/
|
|
9
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
10
|
+
import { type ToolConfig } from './shared.js';
|
|
11
|
+
export declare function registerSearchDecisions(server: McpServer, config: ToolConfig): void;
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @adrkit/mcp — the shared tool contract: strict Zod input/output schemas, the
|
|
3
|
+
* fixed annotations, the deterministic text renderer (contracts/tools.md §2.1),
|
|
4
|
+
* and the wire shapes every tool returns. This is the ONE place limits, the text
|
|
5
|
+
* templates, and the envelope live.
|
|
6
|
+
*/
|
|
7
|
+
import { z } from 'zod';
|
|
8
|
+
import { AdrFrontmatter, Status, Scope, type Finding, type FiredMatcher } from '@adrkit/core';
|
|
9
|
+
import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
|
|
10
|
+
import { type CorpusHealth, type CorpusProjection, type CorpusUnavailableReason } from '../corpus/projection.js';
|
|
11
|
+
import type { InvalidCursorReason, Page } from '../pagination/cursor.js';
|
|
12
|
+
export type { Finding, FiredMatcher } from '@adrkit/core';
|
|
13
|
+
export type { CorpusHealth } from '../corpus/projection.js';
|
|
14
|
+
export declare const LIMITS: {
|
|
15
|
+
readonly query: {
|
|
16
|
+
readonly min: 1;
|
|
17
|
+
readonly max: 256;
|
|
18
|
+
};
|
|
19
|
+
readonly ref: {
|
|
20
|
+
readonly min: 1;
|
|
21
|
+
readonly max: 128;
|
|
22
|
+
};
|
|
23
|
+
readonly status: {
|
|
24
|
+
readonly min: 1;
|
|
25
|
+
readonly max: 6;
|
|
26
|
+
};
|
|
27
|
+
readonly scope: {
|
|
28
|
+
readonly min: 1;
|
|
29
|
+
readonly max: 3;
|
|
30
|
+
};
|
|
31
|
+
readonly tags: {
|
|
32
|
+
readonly min: 1;
|
|
33
|
+
readonly max: 32;
|
|
34
|
+
};
|
|
35
|
+
readonly tag: {
|
|
36
|
+
readonly min: 1;
|
|
37
|
+
readonly max: 64;
|
|
38
|
+
};
|
|
39
|
+
readonly fileLength: {
|
|
40
|
+
readonly min: 1;
|
|
41
|
+
readonly max: 1024;
|
|
42
|
+
};
|
|
43
|
+
readonly files: {
|
|
44
|
+
readonly min: 1;
|
|
45
|
+
readonly max: 256;
|
|
46
|
+
};
|
|
47
|
+
readonly page: {
|
|
48
|
+
readonly min: 1;
|
|
49
|
+
readonly max: 100;
|
|
50
|
+
readonly default: 20;
|
|
51
|
+
};
|
|
52
|
+
readonly cursorBytes: number;
|
|
53
|
+
readonly textCap: 512;
|
|
54
|
+
};
|
|
55
|
+
export declare const ANNOTATIONS: {
|
|
56
|
+
readonly readOnlyHint: true;
|
|
57
|
+
readonly destructiveHint: false;
|
|
58
|
+
readonly idempotentHint: true;
|
|
59
|
+
readonly openWorldHint: false;
|
|
60
|
+
};
|
|
61
|
+
export declare const INVALID_CURSOR_MESSAGES: Record<InvalidCursorReason, string>;
|
|
62
|
+
export declare const CORPUS_UNAVAILABLE_MESSAGES: Record<CorpusUnavailableReason, string>;
|
|
63
|
+
/** `n === 1 ? one : many`. */
|
|
64
|
+
export declare function plural(n: number, one: string, many: string): string;
|
|
65
|
+
/** Immutable per-server config every tool handler reads to load its projection. */
|
|
66
|
+
export interface ToolConfig {
|
|
67
|
+
readonly configuredCwd: string;
|
|
68
|
+
readonly configuredDir: string;
|
|
69
|
+
readonly expectedCanonicalCwd: string;
|
|
70
|
+
readonly maxSourceBytes: number;
|
|
71
|
+
}
|
|
72
|
+
export type StatusValue = z.infer<typeof Status>;
|
|
73
|
+
export type ScopeValue = z.infer<typeof Scope>;
|
|
74
|
+
export interface DecisionSummary {
|
|
75
|
+
readonly id: string;
|
|
76
|
+
readonly title: string;
|
|
77
|
+
readonly status: StatusValue;
|
|
78
|
+
readonly sourcePath: string;
|
|
79
|
+
}
|
|
80
|
+
export interface RelationRefs {
|
|
81
|
+
readonly supersedes: readonly string[];
|
|
82
|
+
readonly supersededBy: string | null;
|
|
83
|
+
readonly relatesTo: readonly string[];
|
|
84
|
+
readonly conflictsWith: readonly string[];
|
|
85
|
+
}
|
|
86
|
+
export interface FullDecision {
|
|
87
|
+
readonly requestedRef: string;
|
|
88
|
+
readonly id: string;
|
|
89
|
+
readonly title: string;
|
|
90
|
+
readonly status: StatusValue;
|
|
91
|
+
readonly sourcePath: string;
|
|
92
|
+
readonly frontmatter: z.infer<typeof AdrFrontmatter>;
|
|
93
|
+
readonly body: string;
|
|
94
|
+
}
|
|
95
|
+
export interface SearchMatch extends DecisionSummary {
|
|
96
|
+
readonly matchedFields: readonly ('id' | 'title' | 'tag' | 'body')[];
|
|
97
|
+
}
|
|
98
|
+
export interface ContextEntry extends DecisionSummary {
|
|
99
|
+
readonly firedMatchers: readonly FiredMatcher[];
|
|
100
|
+
readonly relations: RelationRefs;
|
|
101
|
+
}
|
|
102
|
+
export type SupersededByState = {
|
|
103
|
+
readonly resolved: true;
|
|
104
|
+
readonly target: DecisionSummary;
|
|
105
|
+
} | {
|
|
106
|
+
readonly resolved: false;
|
|
107
|
+
readonly targetRef: string;
|
|
108
|
+
readonly reason: 'dangling';
|
|
109
|
+
} | {
|
|
110
|
+
readonly resolved: false;
|
|
111
|
+
readonly targetRef: string;
|
|
112
|
+
readonly reason: 'ambiguous';
|
|
113
|
+
readonly candidateCount: number;
|
|
114
|
+
} | {
|
|
115
|
+
readonly resolved: false;
|
|
116
|
+
readonly targetRef: string;
|
|
117
|
+
readonly reason: 'federated-unavailable';
|
|
118
|
+
readonly log: string;
|
|
119
|
+
readonly id: string;
|
|
120
|
+
};
|
|
121
|
+
export interface SupersededEntry extends DecisionSummary {
|
|
122
|
+
readonly supersededBy: SupersededByState;
|
|
123
|
+
}
|
|
124
|
+
export type FindingsPage = Page<Finding>;
|
|
125
|
+
export interface InvalidCursorOutcome {
|
|
126
|
+
readonly outcome: 'invalid-cursor';
|
|
127
|
+
readonly reason: InvalidCursorReason;
|
|
128
|
+
readonly message: string;
|
|
129
|
+
}
|
|
130
|
+
export interface CorpusUnavailableOutcome {
|
|
131
|
+
readonly outcome: 'corpus-unavailable';
|
|
132
|
+
readonly reason: CorpusUnavailableReason;
|
|
133
|
+
readonly message: string;
|
|
134
|
+
}
|
|
135
|
+
export type SearchDecisionsResult = {
|
|
136
|
+
outcome: 'results';
|
|
137
|
+
items: readonly SearchMatch[];
|
|
138
|
+
cursor: string | null;
|
|
139
|
+
findings: FindingsPage;
|
|
140
|
+
} | InvalidCursorOutcome | CorpusUnavailableOutcome;
|
|
141
|
+
export type GetDecisionResult = {
|
|
142
|
+
outcome: 'found';
|
|
143
|
+
decision: FullDecision;
|
|
144
|
+
findings: FindingsPage;
|
|
145
|
+
} | {
|
|
146
|
+
outcome: 'not-found';
|
|
147
|
+
requestedRef: string;
|
|
148
|
+
findings: FindingsPage;
|
|
149
|
+
} | {
|
|
150
|
+
outcome: 'ambiguous-local-id';
|
|
151
|
+
requestedRef: string;
|
|
152
|
+
candidates: readonly DecisionSummary[];
|
|
153
|
+
cursor: string | null;
|
|
154
|
+
findings: FindingsPage;
|
|
155
|
+
} | {
|
|
156
|
+
outcome: 'federated-log-unavailable';
|
|
157
|
+
requestedRef: string;
|
|
158
|
+
log: string;
|
|
159
|
+
id: string;
|
|
160
|
+
findings: FindingsPage;
|
|
161
|
+
} | InvalidCursorOutcome | CorpusUnavailableOutcome;
|
|
162
|
+
export type GetDecisionContextResult = {
|
|
163
|
+
outcome: 'matches';
|
|
164
|
+
governing: readonly ContextEntry[];
|
|
165
|
+
activeProposals: readonly ContextEntry[];
|
|
166
|
+
history: readonly ContextEntry[];
|
|
167
|
+
cursor: string | null;
|
|
168
|
+
findings: FindingsPage;
|
|
169
|
+
} | InvalidCursorOutcome | CorpusUnavailableOutcome;
|
|
170
|
+
export type ListSupersededResult = {
|
|
171
|
+
outcome: 'entries';
|
|
172
|
+
items: readonly SupersededEntry[];
|
|
173
|
+
cursor: string | null;
|
|
174
|
+
findings: FindingsPage;
|
|
175
|
+
} | InvalidCursorOutcome | CorpusUnavailableOutcome;
|
|
176
|
+
export type TextSpec = {
|
|
177
|
+
kind: 'results';
|
|
178
|
+
itemsLength: number;
|
|
179
|
+
findings: number;
|
|
180
|
+
} | {
|
|
181
|
+
kind: 'found';
|
|
182
|
+
id: string;
|
|
183
|
+
findings: number;
|
|
184
|
+
} | {
|
|
185
|
+
kind: 'not-found';
|
|
186
|
+
requestedRef: string;
|
|
187
|
+
findings: number;
|
|
188
|
+
} | {
|
|
189
|
+
kind: 'ambiguous-local-id';
|
|
190
|
+
candidatesLength: number;
|
|
191
|
+
requestedRef: string;
|
|
192
|
+
findings: number;
|
|
193
|
+
} | {
|
|
194
|
+
kind: 'federated-log-unavailable';
|
|
195
|
+
requestedRef: string;
|
|
196
|
+
findings: number;
|
|
197
|
+
} | {
|
|
198
|
+
kind: 'matches';
|
|
199
|
+
governing: number;
|
|
200
|
+
activeProposals: number;
|
|
201
|
+
history: number;
|
|
202
|
+
findings: number;
|
|
203
|
+
} | {
|
|
204
|
+
kind: 'entries';
|
|
205
|
+
itemsLength: number;
|
|
206
|
+
findings: number;
|
|
207
|
+
} | {
|
|
208
|
+
kind: 'invalid-cursor';
|
|
209
|
+
reason: InvalidCursorReason;
|
|
210
|
+
} | {
|
|
211
|
+
kind: 'corpus-unavailable';
|
|
212
|
+
reason: CorpusUnavailableReason;
|
|
213
|
+
};
|
|
214
|
+
/** Cap a rendered string at 512 UTF-16 code units. */
|
|
215
|
+
export declare function cap512(value: string): string;
|
|
216
|
+
export declare function renderResponseText(spec: TextSpec): string;
|
|
217
|
+
export type ToolInputSchema = z.ZodType;
|
|
218
|
+
export type ToolOutputSchema = z.ZodRawShape;
|
|
219
|
+
export declare function searchDecisionsInputSchema(): ToolInputSchema;
|
|
220
|
+
export declare function getDecisionInputSchema(): ToolInputSchema;
|
|
221
|
+
export declare function getDecisionContextInputSchema(): ToolInputSchema;
|
|
222
|
+
export declare function listSupersededInputSchema(): ToolInputSchema;
|
|
223
|
+
export declare function findingSchema(): z.ZodType;
|
|
224
|
+
export declare function corpusHealthSchema(): z.ZodType;
|
|
225
|
+
export declare function searchDecisionsOutputSchema(): ToolOutputSchema;
|
|
226
|
+
export declare function getDecisionOutputSchema(): ToolOutputSchema;
|
|
227
|
+
export declare function getDecisionContextOutputSchema(): ToolOutputSchema;
|
|
228
|
+
export declare function listSupersededOutputSchema(): ToolOutputSchema;
|
|
229
|
+
export type StructuredResult = CallToolResult;
|
|
230
|
+
export declare function structuredResult(result: unknown, text: string, corpusHealth: CorpusHealth | undefined): CallToolResult;
|
|
231
|
+
export declare function corpusHealthOf(projection: CorpusProjection): CorpusHealth;
|
|
232
|
+
export declare function invalidCursor(reason: InvalidCursorReason): InvalidCursorOutcome;
|
|
233
|
+
export declare function corpusUnavailable(reason: CorpusUnavailableReason): CorpusUnavailableOutcome;
|
|
234
|
+
export type LoadResult = {
|
|
235
|
+
readonly ok: true;
|
|
236
|
+
readonly projection: CorpusProjection;
|
|
237
|
+
} | {
|
|
238
|
+
readonly ok: false;
|
|
239
|
+
readonly outcome: CorpusUnavailableOutcome;
|
|
240
|
+
};
|
|
241
|
+
/** Load the fresh projection, mapping a typed `CorpusUnavailableError` to its outcome. */
|
|
242
|
+
export declare function loadProjection(config: ToolConfig): Promise<LoadResult>;
|
|
243
|
+
/** Every tool derives its DecisionSummary from an Adr record the same way. */
|
|
244
|
+
export declare function toSummary(record: {
|
|
245
|
+
frontmatter: {
|
|
246
|
+
id: string;
|
|
247
|
+
title: string;
|
|
248
|
+
status: StatusValue;
|
|
249
|
+
};
|
|
250
|
+
path: string;
|
|
251
|
+
}): DecisionSummary;
|
|
252
|
+
export declare function toRelationRefs(frontmatter: z.infer<typeof AdrFrontmatter>): RelationRefs;
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@adrkit/mcp",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Local, read-only Model Context Protocol server exposing adrkit decision retrieval over stdio.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "Apache-2.0",
|
|
7
|
+
"homepage": "https://adrkit.dev",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/mbeacom/adrkit.git",
|
|
11
|
+
"directory": "packages/mcp"
|
|
12
|
+
},
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/mbeacom/adrkit/issues"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"adr",
|
|
18
|
+
"architecture-decision-records",
|
|
19
|
+
"mcp",
|
|
20
|
+
"model-context-protocol",
|
|
21
|
+
"governance"
|
|
22
|
+
],
|
|
23
|
+
"engines": {
|
|
24
|
+
"node": ">=22"
|
|
25
|
+
},
|
|
26
|
+
"publishConfig": {
|
|
27
|
+
"access": "public"
|
|
28
|
+
},
|
|
29
|
+
"bin": {
|
|
30
|
+
"adrkit-mcp": "./dist/bin.js"
|
|
31
|
+
},
|
|
32
|
+
"exports": {
|
|
33
|
+
".": {
|
|
34
|
+
"bun": "./src/index.ts",
|
|
35
|
+
"types": "./dist/index.d.ts",
|
|
36
|
+
"import": "./dist/index.js",
|
|
37
|
+
"default": "./dist/index.js"
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"scripts": {
|
|
41
|
+
"build": "rm -rf dist && bun build ./src/index.ts ./src/bin.ts --target=node --outdir=dist --packages=external && tsc --project tsconfig.build.json && bun ../../scripts/normalize-dts-imports.ts dist && cp ../../LICENSE ../../NOTICE dist/ && chmod +x dist/bin.js",
|
|
42
|
+
"lint": "bun run typecheck",
|
|
43
|
+
"prepack": "bun run build",
|
|
44
|
+
"typecheck": "tsc --noEmit --customConditions bun --project ../../tsconfig.json"
|
|
45
|
+
},
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"@adrkit/core": "0.2.0",
|
|
48
|
+
"@modelcontextprotocol/sdk": "1.29.0",
|
|
49
|
+
"zod": "^4"
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"@types/bun": "latest"
|
|
53
|
+
},
|
|
54
|
+
"files": [
|
|
55
|
+
"dist",
|
|
56
|
+
"README.md",
|
|
57
|
+
"src"
|
|
58
|
+
]
|
|
59
|
+
}
|
package/src/bin.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* @adrkit/mcp — the `adrkit-mcp` stdio entrypoint.
|
|
4
|
+
*
|
|
5
|
+
* Never imported by anything except the compiled `bin` entry itself. Reserves
|
|
6
|
+
* stdout for protocol frames; all diagnostics go to stderr.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { isMainModule, main } from './main-module.ts';
|
|
10
|
+
|
|
11
|
+
if (isMainModule(import.meta.url, process.argv[1])) {
|
|
12
|
+
process.exitCode = await main(process.argv.slice(2), process.env);
|
|
13
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @adrkit/mcp — the one locale-independent comparator and the canonical orderings
|
|
3
|
+
* every channel uses. Never `String.prototype.localeCompare` (research §R6).
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { Finding } from '@adrkit/core';
|
|
7
|
+
|
|
8
|
+
/** The sole code-unit comparator: `a < b ? -1 : a > b ? 1 : 0` over UTF-16 units. */
|
|
9
|
+
export function compareCodeUnits(a: string, b: string): number {
|
|
10
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface OrderedSummary {
|
|
14
|
+
readonly id: string;
|
|
15
|
+
readonly sourcePath: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** Canonical `(id, sourcePath)` ascending order; sourcePath is the unique tiebreak. */
|
|
19
|
+
export function compareByIdThenPath(a: OrderedSummary, b: OrderedSummary): number {
|
|
20
|
+
return compareCodeUnits(a.id, b.id) || compareCodeUnits(a.sourcePath, b.sourcePath);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Canonical finding order using `sortFindings`' field tuple with the code-unit comparator. */
|
|
24
|
+
export function compareFindings(a: Finding, b: Finding): number {
|
|
25
|
+
return (
|
|
26
|
+
compareCodeUnits(a.rule, b.rule) ||
|
|
27
|
+
compareCodeUnits(a.id ?? '', b.id ?? '') ||
|
|
28
|
+
compareCodeUnits(a.pattern ?? '', b.pattern ?? '') ||
|
|
29
|
+
compareCodeUnits(a.path ?? '', b.path ?? '') ||
|
|
30
|
+
compareCodeUnits(a.field ?? '', b.field ?? '') ||
|
|
31
|
+
compareCodeUnits(a.message, b.message)
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function sortFindingsCanonical(findings: readonly Finding[]): Finding[] {
|
|
36
|
+
return [...findings].sort(compareFindings);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function sortByIdThenPath<T extends OrderedSummary>(items: readonly T[]): T[] {
|
|
40
|
+
return [...items].sort(compareByIdThenPath);
|
|
41
|
+
}
|