@octane-xplat/mcp 0.15.0 → 0.16.1
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 +9 -5
- package/dist/_virtual/_rolldown/runtime.js +27 -0
- package/dist/actions/bridge.js +1 -0
- package/dist/context.js +0 -0
- package/dist/contracts/actions.js +1 -0
- package/dist/contracts/boundaries.js +1 -0
- package/dist/contracts/capabilities.js +1 -0
- package/dist/contracts/code.js +1 -0
- package/dist/contracts/errors.js +8 -0
- package/dist/contracts/evidence.js +8 -0
- package/dist/contracts/identity.js +8 -0
- package/dist/contracts/index.js +1 -0
- package/dist/contracts/inspection.js +1 -0
- package/dist/contracts/policy.js +8 -0
- package/dist/contracts/sessions.js +1 -0
- package/dist/contracts/status.js +1 -0
- package/dist/discovery.js +8 -0
- package/dist/docs.js +63 -0
- package/dist/inspection/service.js +3 -0
- package/dist/inspection/tools.js +43 -0
- package/dist/runtime/logs.js +1 -0
- package/dist/runtime/process.js +1 -0
- package/dist/runtime/service.js +1 -0
- package/dist/runtime/targets.js +1 -0
- package/dist/runtime/tools.js +119 -0
- package/dist/server.js +324 -0
- package/dist/status.js +8 -0
- package/dist/xplat-mcp.js +68 -0
- package/package.json +18 -12
- package/src/context.ts +108 -0
- package/src/{docs.mjs → docs.ts} +31 -26
- package/src/inspection/{service.mjs → service.ts} +1 -1
- package/src/inspection/{tools.mjs → tools.ts} +13 -5
- package/src/runtime/{tools.mjs → tools.ts} +16 -6
- package/src/{server.mjs → server.ts} +48 -33
- package/src/{xplat-mcp.mjs → xplat-mcp.ts} +21 -10
- /package/src/actions/{bridge.mjs → bridge.ts} +0 -0
- /package/src/contracts/{actions.mjs → actions.ts} +0 -0
- /package/src/contracts/{boundaries.mjs → boundaries.ts} +0 -0
- /package/src/contracts/{capabilities.mjs → capabilities.ts} +0 -0
- /package/src/contracts/{code.mjs → code.ts} +0 -0
- /package/src/contracts/{errors.mjs → errors.ts} +0 -0
- /package/src/contracts/{evidence.mjs → evidence.ts} +0 -0
- /package/src/contracts/{identity.mjs → identity.ts} +0 -0
- /package/src/contracts/{index.mjs → index.ts} +0 -0
- /package/src/contracts/{inspection.mjs → inspection.ts} +0 -0
- /package/src/contracts/{policy.mjs → policy.ts} +0 -0
- /package/src/contracts/{sessions.mjs → sessions.ts} +0 -0
- /package/src/contracts/{status.mjs → status.ts} +0 -0
- /package/src/{discovery.mjs → discovery.ts} +0 -0
- /package/src/runtime/{logs.mjs → logs.ts} +0 -0
- /package/src/runtime/{process.mjs → process.ts} +0 -0
- /package/src/runtime/{service.mjs → service.ts} +0 -0
- /package/src/runtime/{targets.mjs → targets.ts} +0 -0
- /package/src/{status.mjs → status.ts} +0 -0
- /package/{src → types}/contracts/actions.d.ts +0 -0
- /package/{src → types}/contracts/boundaries.d.ts +0 -0
- /package/{src → types}/contracts/capabilities.d.ts +0 -0
- /package/{src → types}/contracts/code.d.ts +0 -0
- /package/{src → types}/contracts/errors.d.ts +0 -0
- /package/{src → types}/contracts/evidence.d.ts +0 -0
- /package/{src → types}/contracts/identity.d.ts +0 -0
- /package/{src → types}/contracts/index.d.ts +0 -0
- /package/{src → types}/contracts/inspection.d.ts +0 -0
- /package/{src → types}/contracts/policy.d.ts +0 -0
- /package/{src → types}/contracts/sessions.d.ts +0 -0
- /package/{src → types}/contracts/status.d.ts +0 -0
|
@@ -2,13 +2,21 @@
|
|
|
2
2
|
// shared layer at @octane-xplat/cli/mcp/inspection/service; this file only
|
|
3
3
|
// binds it to MCP tools.
|
|
4
4
|
import { z } from 'zod'
|
|
5
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
|
|
6
|
+
import type { Respond, WorkspaceContext } from '../context.ts'
|
|
5
7
|
|
|
6
|
-
export function registerInspectionTools(
|
|
8
|
+
export function registerInspectionTools(
|
|
9
|
+
server: McpServer,
|
|
10
|
+
context: WorkspaceContext,
|
|
11
|
+
respond: Respond,
|
|
12
|
+
) {
|
|
7
13
|
const control = z.object({ kind: z.enum(['id', 'testID']), name: z.string().min(1).max(200) })
|
|
8
|
-
const run =
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
14
|
+
const run =
|
|
15
|
+
(method: 'inspect' | 'interact' | 'screenshot') =>
|
|
16
|
+
async (args: any): Promise<ReturnType<Respond>> => {
|
|
17
|
+
const data = await context.inspection[method](args)
|
|
18
|
+
return data.error ? respond({ ok: false, error: data.error }) : respond({ ok: true, data })
|
|
19
|
+
}
|
|
12
20
|
|
|
13
21
|
server.registerTool(
|
|
14
22
|
'xplat_inspect',
|
|
@@ -3,9 +3,16 @@
|
|
|
3
3
|
// contracts.
|
|
4
4
|
|
|
5
5
|
import { z } from 'zod'
|
|
6
|
-
import {
|
|
6
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
|
|
7
|
+
import { PLATFORMS } from '../contracts/identity.ts'
|
|
8
|
+
import type { Respond, WorkspaceContext } from '../context.ts'
|
|
9
|
+
import type { Platform } from '../../types/contracts/identity'
|
|
7
10
|
|
|
8
|
-
export function registerRuntimeTools(
|
|
11
|
+
export function registerRuntimeTools(
|
|
12
|
+
server: McpServer,
|
|
13
|
+
context: WorkspaceContext,
|
|
14
|
+
respond: Respond,
|
|
15
|
+
) {
|
|
9
16
|
const runtime = context.runtime
|
|
10
17
|
|
|
11
18
|
server.registerTool(
|
|
@@ -14,7 +21,10 @@ export function registerRuntimeTools(server, context, respond) {
|
|
|
14
21
|
description:
|
|
15
22
|
'Discover launchable targets for the bound app: simulators, emulators, devices and host targets with availability, missing-toolchain reasons, and session busy/ownership state.',
|
|
16
23
|
inputSchema: {
|
|
17
|
-
platform: z
|
|
24
|
+
platform: z
|
|
25
|
+
.enum(PLATFORMS as Platform[])
|
|
26
|
+
.optional()
|
|
27
|
+
.describe('Limit to one platform'),
|
|
18
28
|
},
|
|
19
29
|
},
|
|
20
30
|
async ({ platform }) => {
|
|
@@ -31,7 +41,7 @@ export function registerRuntimeTools(server, context, respond) {
|
|
|
31
41
|
description:
|
|
32
42
|
'Build the bound app for one platform as a background job (the same commands `xplat build` runs). Returns a job id — poll xplat_job_status and read output with xplat_logs. Repeating with the same requestKey returns the live job instead of duplicating it.',
|
|
33
43
|
inputSchema: {
|
|
34
|
-
platform: z.enum(PLATFORMS),
|
|
44
|
+
platform: z.enum(PLATFORMS as Platform[]),
|
|
35
45
|
requestKey: z.string().optional().describe('Idempotence key for retries'),
|
|
36
46
|
},
|
|
37
47
|
},
|
|
@@ -49,7 +59,7 @@ export function registerRuntimeTools(server, context, respond) {
|
|
|
49
59
|
description:
|
|
50
60
|
'Start an owned development session: bind one app to one target and run the platform dev command as a job. The job completes when readiness is confirmed — a failed launch after a successful build reports accurately, and the session keeps the app alive until xplat_session_end.',
|
|
51
61
|
inputSchema: {
|
|
52
|
-
platform: z.enum(PLATFORMS),
|
|
62
|
+
platform: z.enum(PLATFORMS as Platform[]),
|
|
53
63
|
targetId: z
|
|
54
64
|
.string()
|
|
55
65
|
.optional()
|
|
@@ -77,7 +87,7 @@ export function registerRuntimeTools(server, context, respond) {
|
|
|
77
87
|
description:
|
|
78
88
|
'Attach to a compatible development session that is already running — never restarts or terminates it. Reports candidates per platform; attach binds a preserved user-owned session.',
|
|
79
89
|
inputSchema: {
|
|
80
|
-
platform: z.enum(PLATFORMS),
|
|
90
|
+
platform: z.enum(PLATFORMS as Platform[]),
|
|
81
91
|
targetId: z
|
|
82
92
|
.string()
|
|
83
93
|
.optional()
|
|
@@ -4,20 +4,27 @@
|
|
|
4
4
|
|
|
5
5
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
|
|
6
6
|
import { readFileSync } from 'node:fs'
|
|
7
|
+
import { dirname, join } from 'node:path'
|
|
8
|
+
import { fileURLToPath } from 'node:url'
|
|
7
9
|
import { z } from 'zod'
|
|
8
|
-
import { contractError, toContractError } from './contracts/errors.
|
|
9
|
-
import { EVIDENCE_KINDS } from './contracts/evidence.
|
|
10
|
-
import { PLATFORMS } from './contracts/identity.
|
|
11
|
-
import { PERMISSION_SCOPES } from './contracts/policy.
|
|
12
|
-
import { discoverWorkspace } from './discovery.
|
|
13
|
-
import { registerRuntimeTools } from './runtime/tools.
|
|
14
|
-
import { registerDocsTools } from './docs.
|
|
15
|
-
import { registerInspectionTools } from './inspection/service.
|
|
16
|
-
import { bindApp, buildProjectStatus, resolveSelection, SERVER_NAME } from './status.
|
|
10
|
+
import { contractError, toContractError } from './contracts/errors.ts'
|
|
11
|
+
import { EVIDENCE_KINDS } from './contracts/evidence.ts'
|
|
12
|
+
import { PLATFORMS } from './contracts/identity.ts'
|
|
13
|
+
import { PERMISSION_SCOPES } from './contracts/policy.ts'
|
|
14
|
+
import { discoverWorkspace } from './discovery.ts'
|
|
15
|
+
import { registerRuntimeTools } from './runtime/tools.ts'
|
|
16
|
+
import { registerDocsTools } from './docs.ts'
|
|
17
|
+
import { registerInspectionTools } from './inspection/service.ts'
|
|
18
|
+
import { bindApp, buildProjectStatus, resolveSelection, SERVER_NAME } from './status.ts'
|
|
19
|
+
import type { Respond, Selection, ToolResponse, WorkspaceContext } from './context.ts'
|
|
20
|
+
import type { ContractError } from '../types/contracts/errors'
|
|
21
|
+
import type { AppRef, Platform, WorkspaceKind } from '../types/contracts/identity'
|
|
22
|
+
import type { PermissionScope } from '../types/contracts/policy'
|
|
23
|
+
import type { EvidenceKind } from '../types/contracts/evidence'
|
|
17
24
|
|
|
18
25
|
// Lockstep releases bump the manifest; the handshake must follow it.
|
|
19
26
|
const SERVER_VERSION = JSON.parse(
|
|
20
|
-
readFileSync(
|
|
27
|
+
readFileSync(join(dirname(fileURLToPath(import.meta.url)), '../package.json'), 'utf8'),
|
|
21
28
|
).version
|
|
22
29
|
|
|
23
30
|
const INSTRUCTIONS =
|
|
@@ -27,18 +34,18 @@ const INSTRUCTIONS =
|
|
|
27
34
|
'For runtime work, check xplat_capability_matrix then xplat_targets; xplat_launch starts an owned session as a job and xplat_attach binds a session you already run. ' +
|
|
28
35
|
'Results always say what was actually checked; a successful build is not proof of behavior.'
|
|
29
36
|
|
|
30
|
-
const respond = (outcome) => ({
|
|
37
|
+
const respond: Respond = (outcome) => ({
|
|
31
38
|
structuredContent: outcome,
|
|
32
39
|
isError: outcome.ok === false,
|
|
33
40
|
content: [{ type: 'text', text: JSON.stringify(outcome, null, 2) }],
|
|
34
41
|
})
|
|
35
42
|
|
|
36
|
-
const ok = (data) => respond({ ok: true, data })
|
|
37
|
-
const fail = (error) => respond({ ok: false, error })
|
|
43
|
+
const ok = (data: unknown): ToolResponse => respond({ ok: true, data })
|
|
44
|
+
const fail = (error: ContractError): ToolResponse => respond({ ok: false, error })
|
|
38
45
|
|
|
39
46
|
/** The bound app for runtime tools — explicit, configured, or sole-app. */
|
|
40
|
-
const boundApp = (context) => {
|
|
41
|
-
const selection = resolveSelection(context)
|
|
47
|
+
const boundApp = (context: WorkspaceContext): AppRef | null => {
|
|
48
|
+
const selection = resolveSelection(context) as Selection
|
|
42
49
|
return selection.state === 'bound' ? selection.app : null
|
|
43
50
|
}
|
|
44
51
|
|
|
@@ -47,7 +54,7 @@ const NO_APP = () =>
|
|
|
47
54
|
recovery: { action: 'Bind an app with xplat_select_app first.' },
|
|
48
55
|
})
|
|
49
56
|
|
|
50
|
-
export function createXplatMcpServer(context) {
|
|
57
|
+
export function createXplatMcpServer(context: WorkspaceContext) {
|
|
51
58
|
const server = new McpServer(
|
|
52
59
|
{ name: SERVER_NAME, version: SERVER_VERSION },
|
|
53
60
|
{ instructions: INSTRUCTIONS },
|
|
@@ -56,7 +63,7 @@ export function createXplatMcpServer(context) {
|
|
|
56
63
|
// Wire the policy elicitation channel now that the protocol exists. The
|
|
57
64
|
// client must advertise elicitation support; without it, grants fall back
|
|
58
65
|
// to developer-side configuration with an honest recovery message.
|
|
59
|
-
context.policy.setElicitor(async (scope, reason) => {
|
|
66
|
+
context.policy.setElicitor(async (scope: PermissionScope, reason: string) => {
|
|
60
67
|
try {
|
|
61
68
|
if (!server.server.getClientCapabilities()?.elicitation) {
|
|
62
69
|
return 'denied'
|
|
@@ -83,7 +90,7 @@ export function createXplatMcpServer(context) {
|
|
|
83
90
|
// search/read a server-side capability — supported on every platform,
|
|
84
91
|
// independent of runtime adapters.
|
|
85
92
|
if (context.code) {
|
|
86
|
-
for (const platform of PLATFORMS) {
|
|
93
|
+
for (const platform of PLATFORMS as Platform[]) {
|
|
87
94
|
context.capabilities.register({
|
|
88
95
|
platform,
|
|
89
96
|
describe: () => [
|
|
@@ -114,9 +121,10 @@ export function createXplatMcpServer(context) {
|
|
|
114
121
|
if (refresh) {
|
|
115
122
|
context.discovery = discoverWorkspace(context.workspaceRoot)
|
|
116
123
|
// A previously bound app may have moved or vanished; re-resolve.
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
context.
|
|
124
|
+
const bound = context.boundApp
|
|
125
|
+
if (bound) {
|
|
126
|
+
const still = context.discovery.apps.find((a) => a.id === bound.id)
|
|
127
|
+
context.boundApp = (still ?? null) as AppRef | null
|
|
120
128
|
context.selectionReason = still ? 'explicit' : null
|
|
121
129
|
}
|
|
122
130
|
}
|
|
@@ -164,13 +172,16 @@ export function createXplatMcpServer(context) {
|
|
|
164
172
|
description:
|
|
165
173
|
'Per-platform capability matrix: build, launch, logs, UI inspection, screenshot, and interaction are separate capabilities. Unsupported or missing capabilities come with an explanation and a usable alternative when one exists.',
|
|
166
174
|
inputSchema: {
|
|
167
|
-
platform: z
|
|
175
|
+
platform: z
|
|
176
|
+
.enum(PLATFORMS as Platform[])
|
|
177
|
+
.optional()
|
|
178
|
+
.describe('Limit to one platform'),
|
|
168
179
|
},
|
|
169
180
|
},
|
|
170
181
|
async ({ platform }) => {
|
|
171
182
|
const status = await buildProjectStatus(context)
|
|
172
183
|
const matrices = platform
|
|
173
|
-
? status.capabilities.filter((m) => m.platform === platform)
|
|
184
|
+
? status.capabilities.filter((m: { platform: string }) => m.platform === platform)
|
|
174
185
|
: status.capabilities
|
|
175
186
|
|
|
176
187
|
return ok({ capabilities: matrices })
|
|
@@ -183,7 +194,7 @@ export function createXplatMcpServer(context) {
|
|
|
183
194
|
description:
|
|
184
195
|
'Report permission grants and their states. Workspace scope and ordinary runtime actions reuse the task authorization; screenshots require an explicit per-task developer grant checked at action time.',
|
|
185
196
|
inputSchema: {
|
|
186
|
-
scope: z.enum(PERMISSION_SCOPES).optional(),
|
|
197
|
+
scope: z.enum(PERMISSION_SCOPES as PermissionScope[]).optional(),
|
|
187
198
|
},
|
|
188
199
|
},
|
|
189
200
|
async ({ scope }) => {
|
|
@@ -364,7 +375,10 @@ export function createXplatMcpServer(context) {
|
|
|
364
375
|
.string()
|
|
365
376
|
.optional()
|
|
366
377
|
.describe('ISO expiration for retain; omit for manual deletion only'),
|
|
367
|
-
kind: z
|
|
378
|
+
kind: z
|
|
379
|
+
.enum(EVIDENCE_KINDS as EvidenceKind[])
|
|
380
|
+
.optional()
|
|
381
|
+
.describe('Filter for list'),
|
|
368
382
|
},
|
|
369
383
|
},
|
|
370
384
|
async ({ op, id, expiresAt, kind }) => {
|
|
@@ -378,21 +392,22 @@ export function createXplatMcpServer(context) {
|
|
|
378
392
|
|
|
379
393
|
if (op === 'retain') {
|
|
380
394
|
const result = context.evidence.retain(id, { expiresAt: expiresAt ?? null })
|
|
381
|
-
return
|
|
395
|
+
return 'error' in result ? fail(result.error) : ok(result)
|
|
382
396
|
}
|
|
383
397
|
|
|
384
398
|
const result = context.evidence.delete(id)
|
|
385
|
-
return
|
|
399
|
+
return 'error' in result ? fail(result.error) : ok(result)
|
|
386
400
|
},
|
|
387
401
|
)
|
|
388
402
|
|
|
389
403
|
// Code retrieval (work item C). Results are leads with provenance and
|
|
390
404
|
// freshness — exact search reads live files, semantic hits are
|
|
391
405
|
// revalidated against current source before serving.
|
|
392
|
-
const boundAppForCode = () => {
|
|
393
|
-
const selection = resolveSelection(context)
|
|
406
|
+
const boundAppForCode = (): { app: AppRef | null; error?: ContractError } => {
|
|
407
|
+
const selection = resolveSelection(context) as Selection
|
|
394
408
|
if (selection.state === 'ambiguous') {
|
|
395
409
|
return {
|
|
410
|
+
app: null,
|
|
396
411
|
error: contractError(
|
|
397
412
|
'ambiguous_selection',
|
|
398
413
|
'Several apps are detected — code retrieval targets the bound app and its installed packages, never a guessed one.',
|
|
@@ -424,7 +439,7 @@ export function createXplatMcpServer(context) {
|
|
|
424
439
|
),
|
|
425
440
|
)
|
|
426
441
|
|
|
427
|
-
const codeResult = (result) => {
|
|
442
|
+
const codeResult = (result: any): ToolResponse => {
|
|
428
443
|
if (!result?.status) {
|
|
429
444
|
return ok(result)
|
|
430
445
|
}
|
|
@@ -456,7 +471,7 @@ export function createXplatMcpServer(context) {
|
|
|
456
471
|
.describe('exact = token search over current files; semantic = local index; auto = both'),
|
|
457
472
|
corpus: z.enum(['app', 'framework', 'all']).optional().describe('Default: all'),
|
|
458
473
|
platform: z
|
|
459
|
-
.enum(PLATFORMS)
|
|
474
|
+
.enum(PLATFORMS as Platform[])
|
|
460
475
|
.optional()
|
|
461
476
|
.describe('Include shared files plus files marked for this platform'),
|
|
462
477
|
package: z.string().optional().describe('Limit the framework corpus to one package'),
|
|
@@ -482,7 +497,7 @@ export function createXplatMcpServer(context) {
|
|
|
482
497
|
return codeResult(
|
|
483
498
|
await context.code.search({
|
|
484
499
|
app,
|
|
485
|
-
workspaceKind: context.discovery.workspace.kind,
|
|
500
|
+
workspaceKind: context.discovery.workspace.kind as WorkspaceKind,
|
|
486
501
|
query,
|
|
487
502
|
mode,
|
|
488
503
|
corpus,
|
|
@@ -533,7 +548,7 @@ export function createXplatMcpServer(context) {
|
|
|
533
548
|
return codeResult(
|
|
534
549
|
await context.code.read({
|
|
535
550
|
app,
|
|
536
|
-
workspaceKind: context.discovery.workspace.kind,
|
|
551
|
+
workspaceKind: context.discovery.workspace.kind as WorkspaceKind,
|
|
537
552
|
ref,
|
|
538
553
|
corpus,
|
|
539
554
|
package: pkg,
|
|
@@ -5,9 +5,13 @@
|
|
|
5
5
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
|
|
6
6
|
import { createCodeService } from '@octane-xplat/cli/mcp/code-service'
|
|
7
7
|
import { readFileSync } from 'node:fs'
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
8
|
+
import { dirname, join } from 'node:path'
|
|
9
|
+
import { fileURLToPath } from 'node:url'
|
|
10
|
+
import { PERMISSION_SCOPES } from './contracts/policy.ts'
|
|
11
|
+
import { createXplatMcpServer } from './server.ts'
|
|
12
|
+
import { createWorkspaceContext } from './status.ts'
|
|
13
|
+
import type { WorkspaceContext } from './context.ts'
|
|
14
|
+
import type { PermissionScope } from '../types/contracts/policy'
|
|
11
15
|
|
|
12
16
|
const usage = `xplat-mcp — Octane Xplat MCP server (stdio)
|
|
13
17
|
|
|
@@ -22,7 +26,7 @@ Workspace reads and ordinary runtime actions reuse the developer's task
|
|
|
22
26
|
authorization; visual-capture always needs an explicit per-task grant.
|
|
23
27
|
`
|
|
24
28
|
|
|
25
|
-
const arg = (name) => {
|
|
29
|
+
const arg = (name: string): string | undefined => {
|
|
26
30
|
const index = process.argv.indexOf(`--${name}`)
|
|
27
31
|
return index >= 0 ? process.argv[index + 1] : undefined
|
|
28
32
|
}
|
|
@@ -37,7 +41,7 @@ const permissionScopes = (arg('permissions') ?? process.env.XPLAT_MCP_PERMISSION
|
|
|
37
41
|
.map((s) => s.trim())
|
|
38
42
|
.filter(Boolean)
|
|
39
43
|
|
|
40
|
-
const unknown = permissionScopes.filter((s) => !PERMISSION_SCOPES.includes(s))
|
|
44
|
+
const unknown = permissionScopes.filter((s) => !PERMISSION_SCOPES.includes(s as PermissionScope))
|
|
41
45
|
if (unknown.length) {
|
|
42
46
|
process.stderr.write(`xplat-mcp: ignoring unknown permission scopes: ${unknown.join(', ')}\n`)
|
|
43
47
|
}
|
|
@@ -46,19 +50,25 @@ const workspaceRoot = arg('workspace') ?? process.env.XPLAT_MCP_WORKSPACE ?? pro
|
|
|
46
50
|
|
|
47
51
|
// The status report's `server` field identifies this entry point — the
|
|
48
52
|
// manifest version follows lockstep bumps automatically.
|
|
49
|
-
const manifest = JSON.parse(
|
|
53
|
+
const manifest = JSON.parse(
|
|
54
|
+
readFileSync(join(dirname(fileURLToPath(import.meta.url)), '../package.json'), 'utf8'),
|
|
55
|
+
)
|
|
50
56
|
|
|
51
|
-
const context = createWorkspaceContext({
|
|
57
|
+
const context: WorkspaceContext = createWorkspaceContext({
|
|
52
58
|
workspaceRoot,
|
|
53
59
|
serverIdentity: { name: '@octane-xplat/mcp', version: manifest.version },
|
|
54
60
|
appSelector: arg('app') ?? process.env.XPLAT_MCP_APP,
|
|
55
|
-
permissionScopes: permissionScopes.filter((s) =>
|
|
61
|
+
permissionScopes: permissionScopes.filter((s): s is PermissionScope =>
|
|
62
|
+
PERMISSION_SCOPES.includes(s as PermissionScope),
|
|
63
|
+
),
|
|
56
64
|
evidenceRoot: arg('evidence-dir') ?? process.env.XPLAT_MCP_EVIDENCE_DIR,
|
|
57
65
|
code: createCodeService({
|
|
58
66
|
workspaceRoot,
|
|
59
67
|
workspaceKind: () => context.discovery.workspace.kind,
|
|
60
68
|
}),
|
|
61
|
-
|
|
69
|
+
// The shared layer attaches docs/devActions/runtime/inspection providers
|
|
70
|
+
// after creating the literal — the .mjs inference cannot see them.
|
|
71
|
+
}) as unknown as WorkspaceContext
|
|
62
72
|
|
|
63
73
|
const { server, shutdown } = createXplatMcpServer(context)
|
|
64
74
|
|
|
@@ -72,7 +82,8 @@ const close = async () => {
|
|
|
72
82
|
try {
|
|
73
83
|
await shutdown()
|
|
74
84
|
} catch (error) {
|
|
75
|
-
|
|
85
|
+
const detail = error instanceof Error ? error.message : String(error)
|
|
86
|
+
process.stderr.write(`xplat-mcp: shutdown cleanup failed: ${detail}\n`)
|
|
76
87
|
} finally {
|
|
77
88
|
await server.close()
|
|
78
89
|
process.exit(0)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|