@inspectr/mcplab 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 (136) hide show
  1. package/README.md +762 -0
  2. package/dist/app/android-chrome-192x192.png +0 -0
  3. package/dist/app/android-chrome-512x512.png +0 -0
  4. package/dist/app/apple-touch-icon.png +0 -0
  5. package/dist/app/assets/index-DT-Z4AVG.js +249 -0
  6. package/dist/app/assets/index-EP4WAY8u.css +1 -0
  7. package/dist/app/favicon-16x16.png +0 -0
  8. package/dist/app/favicon-32x32.png +0 -0
  9. package/dist/app/favicon.svg +13 -0
  10. package/dist/app/index.html +26 -0
  11. package/dist/app/inspectr_logo_color.svg +9 -0
  12. package/dist/app/mcp.png +0 -0
  13. package/dist/app/mcp.svg +1 -0
  14. package/dist/app/robots.txt +14 -0
  15. package/dist/app/site.webmanifest +1 -0
  16. package/dist/app-server/app-context.d.ts +164 -0
  17. package/dist/app-server/app-context.d.ts.map +1 -0
  18. package/dist/app-server/app-context.js +2 -0
  19. package/dist/app-server/app-context.js.map +1 -0
  20. package/dist/app-server/assistant-common.d.ts +41 -0
  21. package/dist/app-server/assistant-common.d.ts.map +1 -0
  22. package/dist/app-server/assistant-common.js +104 -0
  23. package/dist/app-server/assistant-common.js.map +1 -0
  24. package/dist/app-server/config-store.d.ts +15 -0
  25. package/dist/app-server/config-store.d.ts.map +1 -0
  26. package/dist/app-server/config-store.js +67 -0
  27. package/dist/app-server/config-store.js.map +1 -0
  28. package/dist/app-server/dev-mcp.d.ts +6 -0
  29. package/dist/app-server/dev-mcp.d.ts.map +1 -0
  30. package/dist/app-server/dev-mcp.js +71 -0
  31. package/dist/app-server/dev-mcp.js.map +1 -0
  32. package/dist/app-server/evals-routes.d.ts +22 -0
  33. package/dist/app-server/evals-routes.d.ts.map +1 -0
  34. package/dist/app-server/evals-routes.js +135 -0
  35. package/dist/app-server/evals-routes.js.map +1 -0
  36. package/dist/app-server/http.d.ts +5 -0
  37. package/dist/app-server/http.d.ts.map +1 -0
  38. package/dist/app-server/http.js +31 -0
  39. package/dist/app-server/http.js.map +1 -0
  40. package/dist/app-server/index.d.ts +3 -0
  41. package/dist/app-server/index.d.ts.map +1 -0
  42. package/dist/app-server/index.js +2 -0
  43. package/dist/app-server/index.js.map +1 -0
  44. package/dist/app-server/jobs.d.ts +15 -0
  45. package/dist/app-server/jobs.d.ts.map +1 -0
  46. package/dist/app-server/jobs.js +11 -0
  47. package/dist/app-server/jobs.js.map +1 -0
  48. package/dist/app-server/libraries-store.d.ts +15 -0
  49. package/dist/app-server/libraries-store.d.ts.map +1 -0
  50. package/dist/app-server/libraries-store.js +61 -0
  51. package/dist/app-server/libraries-store.js.map +1 -0
  52. package/dist/app-server/markdown-reports.d.ts +12 -0
  53. package/dist/app-server/markdown-reports.d.ts.map +1 -0
  54. package/dist/app-server/markdown-reports.js +145 -0
  55. package/dist/app-server/markdown-reports.js.map +1 -0
  56. package/dist/app-server/oauth-debugger-domain.d.ts +230 -0
  57. package/dist/app-server/oauth-debugger-domain.d.ts.map +1 -0
  58. package/dist/app-server/oauth-debugger-domain.js +1098 -0
  59. package/dist/app-server/oauth-debugger-domain.js.map +1 -0
  60. package/dist/app-server/oauth-debugger.d.ts +20 -0
  61. package/dist/app-server/oauth-debugger.d.ts.map +1 -0
  62. package/dist/app-server/oauth-debugger.js +193 -0
  63. package/dist/app-server/oauth-debugger.js.map +1 -0
  64. package/dist/app-server/provider-models.d.ts +8 -0
  65. package/dist/app-server/provider-models.d.ts.map +1 -0
  66. package/dist/app-server/provider-models.js +60 -0
  67. package/dist/app-server/provider-models.js.map +1 -0
  68. package/dist/app-server/result-assistant-domain.d.ts +87 -0
  69. package/dist/app-server/result-assistant-domain.d.ts.map +1 -0
  70. package/dist/app-server/result-assistant-domain.js +212 -0
  71. package/dist/app-server/result-assistant-domain.js.map +1 -0
  72. package/dist/app-server/result-assistant.d.ts +22 -0
  73. package/dist/app-server/result-assistant.d.ts.map +1 -0
  74. package/dist/app-server/result-assistant.js +328 -0
  75. package/dist/app-server/result-assistant.js.map +1 -0
  76. package/dist/app-server/router.d.ts +4 -0
  77. package/dist/app-server/router.d.ts.map +1 -0
  78. package/dist/app-server/router.js +374 -0
  79. package/dist/app-server/router.js.map +1 -0
  80. package/dist/app-server/runs-routes.d.ts +44 -0
  81. package/dist/app-server/runs-routes.d.ts.map +1 -0
  82. package/dist/app-server/runs-routes.js +555 -0
  83. package/dist/app-server/runs-routes.js.map +1 -0
  84. package/dist/app-server/runs-store.d.ts +23 -0
  85. package/dist/app-server/runs-store.d.ts.map +1 -0
  86. package/dist/app-server/runs-store.js +84 -0
  87. package/dist/app-server/runs-store.js.map +1 -0
  88. package/dist/app-server/scenario-assistant-domain.d.ts +162 -0
  89. package/dist/app-server/scenario-assistant-domain.d.ts.map +1 -0
  90. package/dist/app-server/scenario-assistant-domain.js +269 -0
  91. package/dist/app-server/scenario-assistant-domain.js.map +1 -0
  92. package/dist/app-server/scenario-assistant.d.ts +29 -0
  93. package/dist/app-server/scenario-assistant.d.ts.map +1 -0
  94. package/dist/app-server/scenario-assistant.js +246 -0
  95. package/dist/app-server/scenario-assistant.js.map +1 -0
  96. package/dist/app-server/settings-store.d.ts +4 -0
  97. package/dist/app-server/settings-store.d.ts.map +1 -0
  98. package/dist/app-server/settings-store.js +32 -0
  99. package/dist/app-server/settings-store.js.map +1 -0
  100. package/dist/app-server/snapshots-routes.d.ts +24 -0
  101. package/dist/app-server/snapshots-routes.d.ts.map +1 -0
  102. package/dist/app-server/snapshots-routes.js +82 -0
  103. package/dist/app-server/snapshots-routes.js.map +1 -0
  104. package/dist/app-server/static-serving.d.ts +17 -0
  105. package/dist/app-server/static-serving.d.ts.map +1 -0
  106. package/dist/app-server/static-serving.js +64 -0
  107. package/dist/app-server/static-serving.js.map +1 -0
  108. package/dist/app-server/store-utils.d.ts +5 -0
  109. package/dist/app-server/store-utils.d.ts.map +1 -0
  110. package/dist/app-server/store-utils.js +26 -0
  111. package/dist/app-server/store-utils.js.map +1 -0
  112. package/dist/app-server/tool-analysis-domain.d.ts +146 -0
  113. package/dist/app-server/tool-analysis-domain.d.ts.map +1 -0
  114. package/dist/app-server/tool-analysis-domain.js +556 -0
  115. package/dist/app-server/tool-analysis-domain.js.map +1 -0
  116. package/dist/app-server/tool-analysis-storage.d.ts +41 -0
  117. package/dist/app-server/tool-analysis-storage.d.ts.map +1 -0
  118. package/dist/app-server/tool-analysis-storage.js +110 -0
  119. package/dist/app-server/tool-analysis-storage.js.map +1 -0
  120. package/dist/app-server/tool-analysis.d.ts +22 -0
  121. package/dist/app-server/tool-analysis.d.ts.map +1 -0
  122. package/dist/app-server/tool-analysis.js +271 -0
  123. package/dist/app-server/tool-analysis.js.map +1 -0
  124. package/dist/app-server/types.d.ts +28 -0
  125. package/dist/app-server/types.d.ts.map +1 -0
  126. package/dist/app-server/types.js +2 -0
  127. package/dist/app-server/types.js.map +1 -0
  128. package/dist/cli.d.ts +3 -0
  129. package/dist/cli.d.ts.map +1 -0
  130. package/dist/cli.js +544 -0
  131. package/dist/cli.js.map +1 -0
  132. package/dist/snapshot.d.ts +80 -0
  133. package/dist/snapshot.d.ts.map +1 -0
  134. package/dist/snapshot.js +401 -0
  135. package/dist/snapshot.js.map +1 -0
  136. package/package.json +55 -0
@@ -0,0 +1,145 @@
1
+ import { basename, extname, relative, resolve, sep } from 'node:path';
2
+ import { readdirSync, readFileSync, statSync } from 'node:fs';
3
+ const MAX_REPORT_BYTES = 2 * 1024 * 1024;
4
+ export async function handleMarkdownReportsRoutes(params) {
5
+ const { req, res, pathname, method, settings, deps } = params;
6
+ const { asJson } = deps;
7
+ if (pathname === '/api/markdown-reports' && method === 'GET') {
8
+ const root = resolveReportsRoot(settings);
9
+ const items = listMarkdownFilesRecursive(root, settings.workspaceRoot);
10
+ asJson(res, 200, {
11
+ root,
12
+ exists: safeIsDirectory(root),
13
+ items
14
+ });
15
+ return true;
16
+ }
17
+ if (pathname === '/api/markdown-reports/content' && method === 'GET') {
18
+ const url = new URL(req.url ?? '/', `http://${req.headers.host ?? 'localhost'}`);
19
+ const pathParam = String(url.searchParams.get('path') ?? '').trim();
20
+ if (!pathParam) {
21
+ asJson(res, 400, { error: 'path is required' });
22
+ return true;
23
+ }
24
+ const root = resolveReportsRoot(settings);
25
+ let targetPath;
26
+ try {
27
+ targetPath = resolveReportPath(root, pathParam);
28
+ }
29
+ catch (error) {
30
+ asJson(res, 400, { error: error instanceof Error ? error.message : String(error) });
31
+ return true;
32
+ }
33
+ if (!isMarkdownExt(targetPath)) {
34
+ asJson(res, 400, { error: 'path must point to a .md or .markdown file' });
35
+ return true;
36
+ }
37
+ let st;
38
+ try {
39
+ st = statSync(targetPath);
40
+ }
41
+ catch {
42
+ asJson(res, 404, { error: 'Report not found' });
43
+ return true;
44
+ }
45
+ if (!st.isFile()) {
46
+ asJson(res, 404, { error: 'Report not found' });
47
+ return true;
48
+ }
49
+ if (st.size > MAX_REPORT_BYTES) {
50
+ asJson(res, 413, { error: `Report exceeds ${MAX_REPORT_BYTES} bytes` });
51
+ return true;
52
+ }
53
+ try {
54
+ const content = readFileSync(targetPath, 'utf8');
55
+ const relativePath = relative(root, targetPath).split(sep).join('/');
56
+ asJson(res, 200, {
57
+ root,
58
+ path: relative(settings.workspaceRoot, targetPath).split(sep).join('/'),
59
+ relativePath,
60
+ name: basename(targetPath),
61
+ sizeBytes: st.size,
62
+ mtime: st.mtime.toISOString(),
63
+ content
64
+ });
65
+ }
66
+ catch (error) {
67
+ asJson(res, 500, { error: error instanceof Error ? error.message : String(error) });
68
+ }
69
+ return true;
70
+ }
71
+ return false;
72
+ }
73
+ function resolveReportsRoot(settings) {
74
+ return resolve(settings.workspaceRoot, 'mcplab/reports');
75
+ }
76
+ function resolveReportPath(root, relativePath) {
77
+ if (!relativePath.trim())
78
+ throw new Error('path is required');
79
+ const target = resolve(root, relativePath);
80
+ const withinRoot = target === root || target.startsWith(`${root}${sep}`);
81
+ if (!withinRoot) {
82
+ throw new Error('path escapes reports root');
83
+ }
84
+ return target;
85
+ }
86
+ function isMarkdownExt(path) {
87
+ const ext = extname(path).toLowerCase();
88
+ return ext === '.md' || ext === '.markdown';
89
+ }
90
+ function listMarkdownFilesRecursive(root, workspaceRoot) {
91
+ if (!safeIsDirectory(root))
92
+ return [];
93
+ const items = [];
94
+ const walk = (dir) => {
95
+ let entries;
96
+ try {
97
+ entries = readdirSync(dir, { withFileTypes: true });
98
+ }
99
+ catch {
100
+ return;
101
+ }
102
+ for (const entry of entries) {
103
+ const fullPath = resolve(dir, entry.name);
104
+ if (entry.isDirectory()) {
105
+ walk(fullPath);
106
+ continue;
107
+ }
108
+ if (!entry.isFile())
109
+ continue;
110
+ if (!isMarkdownExt(fullPath))
111
+ continue;
112
+ try {
113
+ const st = statSync(fullPath);
114
+ if (!st.isFile())
115
+ continue;
116
+ items.push({
117
+ path: relative(workspaceRoot, fullPath).split(sep).join('/'),
118
+ relativePath: relative(root, fullPath).split(sep).join('/'),
119
+ name: basename(fullPath),
120
+ sizeBytes: st.size,
121
+ mtime: st.mtime.toISOString()
122
+ });
123
+ }
124
+ catch {
125
+ // Skip unreadable/broken entries in listing.
126
+ }
127
+ }
128
+ };
129
+ walk(root);
130
+ items.sort((a, b) => {
131
+ if (a.mtime === b.mtime)
132
+ return a.path.localeCompare(b.path);
133
+ return b.mtime.localeCompare(a.mtime);
134
+ });
135
+ return items;
136
+ }
137
+ function safeIsDirectory(path) {
138
+ try {
139
+ return statSync(path).isDirectory();
140
+ }
141
+ catch {
142
+ return false;
143
+ }
144
+ }
145
+ //# sourceMappingURL=markdown-reports.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown-reports.js","sourceRoot":"","sources":["../../src/app-server/markdown-reports.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,230 @@
1
+ import type { ServerResponse } from 'node:http';
2
+ import type { EvalConfig } from '@inspectr/mcplab-core';
3
+ type SessionStatus =
4
+ | 'configuring'
5
+ | 'running'
6
+ | 'waiting_for_user'
7
+ | 'waiting_for_browser_callback'
8
+ | 'completed'
9
+ | 'error'
10
+ | 'stopped';
11
+ type RegistrationMethod = 'pre_registered' | 'dcr' | 'cimd';
12
+ export interface OAuthDebuggerSessionConfigInput {
13
+ profile: 'latest';
14
+ target: {
15
+ serverName: string;
16
+ overrides?: {
17
+ authorizationServerMetadataUrl?: string;
18
+ authorizationEndpoint?: string;
19
+ tokenEndpoint?: string;
20
+ registrationEndpoint?: string;
21
+ cimdUrl?: string;
22
+ resourceBaseUrl?: string;
23
+ };
24
+ };
25
+ registrationMethod: RegistrationMethod;
26
+ clientConfig: {
27
+ preRegistered?: {
28
+ clientId: string;
29
+ clientSecret?: string;
30
+ tokenEndpointAuthMethod?: string;
31
+ };
32
+ dcr?: {
33
+ metadata?: Record<string, unknown>;
34
+ tokenEndpointAuthMethod?: string;
35
+ };
36
+ cimd?: {
37
+ cimdUrl?: string;
38
+ expectedClientId?: string;
39
+ };
40
+ };
41
+ runtime: {
42
+ redirectMode: 'local_callback' | 'manual';
43
+ scopes?: string[];
44
+ resource?: string;
45
+ usePkce?: boolean;
46
+ codeChallengeMethod?: 'S256';
47
+ state?: string;
48
+ nonce?: string;
49
+ extraAuthParams?: Record<string, string>;
50
+ };
51
+ display?: {
52
+ showSensitiveValues?: boolean;
53
+ };
54
+ }
55
+ export interface OAuthNetworkExchange {
56
+ id: string;
57
+ stepId: string;
58
+ kind: 'http';
59
+ phase: 'request' | 'response';
60
+ label: string;
61
+ method?: string;
62
+ url: string;
63
+ headers: Record<string, string>;
64
+ bodyText?: string;
65
+ status?: number;
66
+ durationMs?: number;
67
+ timestamp: string;
68
+ sensitiveFields?: Array<{
69
+ path: string;
70
+ type: 'token' | 'secret' | 'authorization_header';
71
+ }>;
72
+ }
73
+ export interface OAuthValidationFinding {
74
+ id: string;
75
+ stepId: string;
76
+ severity: 'error' | 'warning' | 'info';
77
+ code: string;
78
+ title: string;
79
+ detail: string;
80
+ specReference?: string;
81
+ recommendation?: string;
82
+ }
83
+ export interface OAuthDebuggerStepState {
84
+ id: string;
85
+ title: string;
86
+ description: string;
87
+ status: 'pending' | 'active' | 'completed' | 'failed' | 'skipped';
88
+ startedAt?: string;
89
+ finishedAt?: string;
90
+ outcomeSummary?: string;
91
+ teachableMoment?: string;
92
+ networkExchangeIds: string[];
93
+ validationIds: string[];
94
+ }
95
+ export interface OAuthSequenceEvent {
96
+ id: string;
97
+ ts: string;
98
+ from: 'User' | 'Debugger' | 'Auth Server' | 'Token Endpoint' | 'MCP/Resource';
99
+ to: 'User' | 'Debugger' | 'Auth Server' | 'Token Endpoint' | 'MCP/Resource';
100
+ label: string;
101
+ stepId?: string;
102
+ networkExchangeId?: string;
103
+ }
104
+ export interface OAuthDebuggerSession {
105
+ id: string;
106
+ createdAt: number;
107
+ updatedAt: number;
108
+ status: SessionStatus;
109
+ config: {
110
+ profile: 'latest';
111
+ target: OAuthDebuggerSessionConfigInput['target'];
112
+ registrationMethod: RegistrationMethod;
113
+ clientConfig: OAuthDebuggerSessionConfigInput['clientConfig'];
114
+ runtime: Required<
115
+ Pick<
116
+ OAuthDebuggerSessionConfigInput['runtime'],
117
+ 'redirectMode' | 'usePkce' | 'codeChallengeMethod'
118
+ >
119
+ > &
120
+ Omit<
121
+ OAuthDebuggerSessionConfigInput['runtime'],
122
+ 'redirectMode' | 'usePkce' | 'codeChallengeMethod'
123
+ >;
124
+ display: {
125
+ showSensitiveValues: boolean;
126
+ };
127
+ };
128
+ steps: OAuthDebuggerStepState[];
129
+ validations: OAuthValidationFinding[];
130
+ network: OAuthNetworkExchange[];
131
+ sequence: OAuthSequenceEvent[];
132
+ events: Array<{
133
+ type: string;
134
+ ts: string;
135
+ payload: Record<string, unknown>;
136
+ }>;
137
+ clients: Set<ServerResponse>;
138
+ abortController: AbortController;
139
+ serverConfig?: EvalConfig['servers'][string];
140
+ context: {
141
+ resourceMetadata?: any;
142
+ authServerMetadata?: any;
143
+ registration?: any;
144
+ resolvedClient?: {
145
+ clientId: string;
146
+ clientSecret?: string;
147
+ tokenEndpointAuthMethod?: string;
148
+ };
149
+ pkce?: {
150
+ verifier: string;
151
+ challenge: string;
152
+ method: 'S256';
153
+ };
154
+ authorizationRequestUrl?: string;
155
+ callbackResult?: {
156
+ rawUrl?: string;
157
+ code?: string;
158
+ state?: string;
159
+ error?: string;
160
+ errorDescription?: string;
161
+ };
162
+ tokenResponse?: any;
163
+ probeResponse?: {
164
+ status: number;
165
+ bodyText: string;
166
+ url: string;
167
+ };
168
+ callbackUrl?: string;
169
+ };
170
+ }
171
+ export interface OAuthDebuggerSessionView {
172
+ id: string;
173
+ status: SessionStatus;
174
+ createdAt: string;
175
+ updatedAt: string;
176
+ profile: 'latest';
177
+ registrationMethod: RegistrationMethod;
178
+ stepStates: OAuthDebuggerStepState[];
179
+ validations: OAuthValidationFinding[];
180
+ network: OAuthNetworkExchange[];
181
+ networkSummary: {
182
+ requestCount: number;
183
+ errorCount: number;
184
+ };
185
+ sequence: OAuthSequenceEvent[];
186
+ uiHints: {
187
+ nextAction?: 'start' | 'open_authorize_url' | 'paste_callback_url' | 'none';
188
+ authorizationUrl?: string;
189
+ callbackMode?: 'local_callback' | 'manual';
190
+ callbackUrl?: string;
191
+ };
192
+ summary?: {
193
+ issuer?: string;
194
+ clientId?: string;
195
+ redirectUri?: string;
196
+ tokenEndpointStatus?: number;
197
+ tokenType?: string;
198
+ grantedScopes?: string[];
199
+ };
200
+ }
201
+ export declare function cleanupOAuthDebuggerSessions(
202
+ sessions: Map<string, OAuthDebuggerSession>,
203
+ now?: number
204
+ ): void;
205
+ export declare function createOAuthDebuggerSession(params: {
206
+ config: OAuthDebuggerSessionConfigInput;
207
+ serverConfig?: EvalConfig['servers'][string];
208
+ }): OAuthDebuggerSession;
209
+ export declare function oauthDebuggerSessionView(
210
+ session: OAuthDebuggerSession
211
+ ): OAuthDebuggerSessionView;
212
+ export declare function startOrResumeOAuthDebuggerSession(params: {
213
+ session: OAuthDebuggerSession;
214
+ appBaseUrl: string;
215
+ }): Promise<void>;
216
+ export declare function submitManualCallbackToSession(params: {
217
+ session: OAuthDebuggerSession;
218
+ redirectUrl?: string;
219
+ code?: string;
220
+ state?: string;
221
+ }): void;
222
+ export declare function submitBrowserCallbackToSession(params: {
223
+ session: OAuthDebuggerSession;
224
+ rawUrl: string;
225
+ }): void;
226
+ export declare function stopOAuthDebuggerSession(session: OAuthDebuggerSession): void;
227
+ export declare function oauthDebuggerExportMarkdown(session: OAuthDebuggerSession): string;
228
+ export declare function oauthDebuggerExportRawTrace(session: OAuthDebuggerSession): string;
229
+ export {};
230
+ //# sourceMappingURL=oauth-debugger-domain.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oauth-debugger-domain.d.ts","sourceRoot":"","sources":["../../src/app-server/oauth-debugger-domain.ts"],"names":[],"mappings":"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"}