@qloo/qloo-harness 0.1.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/mcp.js ADDED
@@ -0,0 +1,909 @@
1
+ import { createRequire as __qlooCreateRequire } from "node:module";
2
+ const require = __qlooCreateRequire(import.meta.url);
3
+
4
+ // apps/qloo-harness/dist/mcp.js
5
+ import { createInterface } from "node:readline";
6
+
7
+ // packages/qloo-tool-schema/dist/upstream.lock.json
8
+ var upstream_lock_default = {
9
+ lockVersion: 1,
10
+ source: {
11
+ documentationUrl: "https://docs.qloo.com",
12
+ registryUrl: "https://dash.readme.com/api/v1/api-registry/4svkj1svmrti5tfx",
13
+ registryId: "4svkj1svmrti5tfx",
14
+ retrievedAt: "2026-08-20",
15
+ apiTitle: "Qloo API",
16
+ apiVersion: "2.0",
17
+ openapiVersion: "3.1.0",
18
+ sha256: "da8d4b830f2a646815d25afcaa653f81f1ad939707e2e2560d2d0b9f103076f1"
19
+ },
20
+ expectations: {
21
+ productionServer: "https://api.qloo.com",
22
+ authentication: {
23
+ scheme: "ApiKey",
24
+ type: "apiKey",
25
+ location: "header",
26
+ header: "X-Api-Key"
27
+ },
28
+ getPaths: [
29
+ "/",
30
+ "/entities",
31
+ "/search",
32
+ "/v2/analysis/compare",
33
+ "/v2/audiences",
34
+ "/v2/audiences/types",
35
+ "/v2/insights",
36
+ "/v2/tags",
37
+ "/v2/tags/types",
38
+ "/v2/trending"
39
+ ]
40
+ },
41
+ documentedExceptions: [
42
+ {
43
+ value: "urn:demographics",
44
+ scope: "/v2/insights filter.type",
45
+ status: "documented-but-not-enumerated",
46
+ documentationUrl: "https://docs.qloo.com/reference/demographics-use-case",
47
+ treatment: "Preserve as an explicit documentation exception; do not synthesize an endpoint payload schema from it."
48
+ },
49
+ {
50
+ value: "urn:tag",
51
+ scope: "/v2/insights filter.type",
52
+ status: "documented-but-not-enumerated",
53
+ documentationUrl: "https://docs.qloo.com/reference/taste-analysis",
54
+ treatment: "The pinned specification mentions this value in diversify.by documentation but omits it from the filter.type enum; preserve the discrepancy for review."
55
+ }
56
+ ]
57
+ };
58
+
59
+ // packages/qloo-tool-schema/dist/src/catalog.js
60
+ var QLOO_TOOL_CATALOG_VERSION = "1.0.0";
61
+ var QLOO_TOOL_RESULT_SCHEMA_VERSION = "1.0-preview.1";
62
+ var QLOO_WORKFLOW_OPERATION_IDS = [
63
+ "recommend",
64
+ "rank",
65
+ "describe",
66
+ "where_popular",
67
+ "compare_audiences",
68
+ "entity_tags",
69
+ "audience_demographics",
70
+ "trends",
71
+ "find_tags"
72
+ ];
73
+ var QLOO_CAPABILITIES_TOOL_NAME = "qloo_capabilities";
74
+ var QLOO_INSIGHTS_ENTITY_TYPES = [
75
+ { id: "artist", urn: "urn:entity:artist" },
76
+ { id: "book", urn: "urn:entity:book" },
77
+ { id: "brand", urn: "urn:entity:brand" },
78
+ { id: "movie", urn: "urn:entity:movie" },
79
+ { id: "person", urn: "urn:entity:person" },
80
+ { id: "place", urn: "urn:entity:place" },
81
+ { id: "podcast", urn: "urn:entity:podcast" },
82
+ { id: "tv_show", urn: "urn:entity:tv_show" },
83
+ { id: "videogame", urn: "urn:entity:videogame" }
84
+ ];
85
+ var QLOO_SEARCH_ENTITY_TYPES = [
86
+ ...QLOO_INSIGHTS_ENTITY_TYPES,
87
+ { id: "locality", urn: "urn:entity:locality" },
88
+ { id: "actor", urn: "urn:entity:actor" },
89
+ { id: "album", urn: "urn:entity:album" },
90
+ { id: "author", urn: "urn:entity:author" },
91
+ { id: "director", urn: "urn:entity:director" }
92
+ ];
93
+ function buildEntityTypeAliases(entityTypes) {
94
+ const aliases = /* @__PURE__ */ new Map();
95
+ const urnById = new Map(entityTypes.map(({ id, urn }) => [id, urn]));
96
+ for (const entityType of entityTypes) {
97
+ aliases.set(entityType.id, entityType.urn);
98
+ aliases.set(entityType.urn, entityType.urn);
99
+ aliases.set(`${entityType.id}s`, entityType.urn);
100
+ }
101
+ const addAlias = (alias, id) => {
102
+ const urn = urnById.get(id);
103
+ if (urn)
104
+ aliases.set(alias, urn);
105
+ };
106
+ addAlias("people", "person");
107
+ addAlias("localities", "locality");
108
+ addAlias("tv", "tv_show");
109
+ addAlias("show", "tv_show");
110
+ addAlias("shows", "tv_show");
111
+ addAlias("tv show", "tv_show");
112
+ addAlias("tv shows", "tv_show");
113
+ addAlias("game", "videogame");
114
+ addAlias("games", "videogame");
115
+ addAlias("video game", "videogame");
116
+ addAlias("video games", "videogame");
117
+ return aliases;
118
+ }
119
+ var insightsEntityTypeByAlias = buildEntityTypeAliases(QLOO_INSIGHTS_ENTITY_TYPES);
120
+ var searchEntityTypeByAlias = buildEntityTypeAliases(QLOO_SEARCH_ENTITY_TYPES);
121
+ var operationSummaries = {
122
+ recommend: "Find entities for a taste profile, audience, or collection of signals.",
123
+ rank: "Rank a supplied set of options for signals, location, or audience.",
124
+ describe: "Resolve and describe one Qloo entity.",
125
+ where_popular: "Find geographic areas where an entity has comparatively strong affinity.",
126
+ compare_audiences: "Contrast two signal groups and identify shared or differentiating affinities.",
127
+ entity_tags: "Retrieve concepts and tags that characterize entities.",
128
+ audience_demographics: "Retrieve aggregate audience segments associated with an entity.",
129
+ trends: "Retrieve interest or trend information over a time range.",
130
+ find_tags: "Search the Qloo tag ontology by natural-language concept."
131
+ };
132
+ var QLOO_WORKFLOW_OPERATIONS = Object.freeze(QLOO_WORKFLOW_OPERATION_IDS.map((id) => Object.freeze({
133
+ id,
134
+ toolName: `qloo_${id}`,
135
+ summary: operationSummaries[id],
136
+ since: QLOO_TOOL_CATALOG_VERSION
137
+ })));
138
+ var upstreamLock = upstream_lock_default;
139
+ var upstreamGetPaths = Object.freeze([
140
+ ...upstreamLock.expectations.getPaths
141
+ ]);
142
+ var documentedExceptions = Object.freeze(upstreamLock.documentedExceptions.map((exception) => Object.freeze({ ...exception })));
143
+ var QLOO_CAPABILITIES_TOOL = Object.freeze({
144
+ name: QLOO_CAPABILITIES_TOOL_NAME,
145
+ description: "Return the versioned Qloo workflow catalog and pinned upstream API contract metadata without making a network request.",
146
+ inputSchema: Object.freeze({
147
+ $schema: "https://json-schema.org/draft/2020-12/schema",
148
+ type: "object",
149
+ additionalProperties: false,
150
+ properties: Object.freeze({
151
+ operation_ids: Object.freeze({
152
+ type: "array",
153
+ description: "Optional canonical operation IDs to include. Omit for the complete catalog.",
154
+ uniqueItems: true,
155
+ items: Object.freeze({
156
+ type: "string",
157
+ enum: QLOO_WORKFLOW_OPERATION_IDS
158
+ })
159
+ })
160
+ })
161
+ })
162
+ });
163
+ var operationIds = new Set(QLOO_WORKFLOW_OPERATION_IDS);
164
+ function getQlooCapabilities(input = {}) {
165
+ const selected = input.operation_ids ? new Set(input.operation_ids) : void 0;
166
+ return {
167
+ contract_version: QLOO_TOOL_CATALOG_VERSION,
168
+ introspection_tool: QLOO_CAPABILITIES_TOOL_NAME,
169
+ operations: selected ? QLOO_WORKFLOW_OPERATIONS.filter(({ id }) => selected.has(id)) : QLOO_WORKFLOW_OPERATIONS,
170
+ upstream: {
171
+ documentation_url: upstreamLock.source.documentationUrl,
172
+ api_version: upstreamLock.source.apiVersion,
173
+ openapi_version: upstreamLock.source.openapiVersion,
174
+ production_server: upstreamLock.expectations.productionServer,
175
+ lock_sha256: upstreamLock.source.sha256,
176
+ get_paths: upstreamGetPaths,
177
+ documented_exceptions: documentedExceptions
178
+ }
179
+ };
180
+ }
181
+
182
+ // packages/qloo-tool-schema/dist/src/workflow-contracts.js
183
+ import { createHash } from "node:crypto";
184
+ import { Type } from "typebox";
185
+ import { Value } from "typebox/value";
186
+ var QLOO_TOOL_DEFAULT_LIMIT = 10;
187
+ var QLOO_TOOL_MAX_RESULTS = 20;
188
+ var QLOO_TAG_BOOLEAN_OPERATORS = ["union", "intersection"];
189
+ var insightsEntityTypeIds = QLOO_INSIGHTS_ENTITY_TYPES.map(({ id }) => id);
190
+ var searchEntityTypeIds = QLOO_SEARCH_ENTITY_TYPES.map(({ id }) => id);
191
+ var QLOO_INSIGHTS_ENTITY_TYPE_SCHEMA = Type.String({
192
+ enum: insightsEntityTypeIds,
193
+ description: `Qloo Insights entity type: ${insightsEntityTypeIds.join(", ")}.`
194
+ });
195
+ var QLOO_SEARCH_ENTITY_TYPE_SCHEMA = Type.String({
196
+ enum: searchEntityTypeIds,
197
+ description: `Qloo search entity type: ${searchEntityTypeIds.join(", ")}.`
198
+ });
199
+ var QLOO_TAG_BOOLEAN_OPERATOR_SCHEMA = Type.String({
200
+ enum: QLOO_TAG_BOOLEAN_OPERATORS,
201
+ description: "Combine tag values with union (any) or intersection (all)."
202
+ });
203
+ var QLOO_LIMIT_SCHEMA = Type.Optional(Type.Integer({
204
+ minimum: 1,
205
+ maximum: QLOO_TOOL_MAX_RESULTS,
206
+ default: QLOO_TOOL_DEFAULT_LIMIT,
207
+ description: `Maximum results to return (1-${QLOO_TOOL_MAX_RESULTS}).`
208
+ }));
209
+ var QLOO_ENTITY_INPUTS_SCHEMA = Type.Array(Type.String({ minLength: 1 }), {
210
+ minItems: 1,
211
+ maxItems: 10,
212
+ description: "Entity names or Qloo entity UUIDs. Keep one combined taste profile in one call."
213
+ });
214
+ var QLOO_TAG_INPUTS_SCHEMA = Type.Array(Type.String({ minLength: 1 }), {
215
+ minItems: 1,
216
+ maxItems: 10,
217
+ description: "Natural-language tag concepts or stable Qloo tag URNs."
218
+ });
219
+ var QLOO_DEMOGRAPHIC_SCHEMA = Type.String({
220
+ minLength: 1,
221
+ description: "Audience demographic in natural language, such as 'young women', 'men 25-34', or 'millennials'. It is converted to documented Qloo demographic signals.",
222
+ examples: ["young women", "men 25-34", "millennials"]
223
+ });
224
+ var QLOO_REQUEST_PREVIEW_SCHEMA = Type.Object({
225
+ method: Type.Literal("GET"),
226
+ path: Type.String({ minLength: 1 }),
227
+ query: Type.Unknown()
228
+ }, { additionalProperties: false });
229
+ var QLOO_RESULT_ENVELOPE_SCHEMA = Type.Object({
230
+ schema_version: Type.Literal(QLOO_TOOL_RESULT_SCHEMA_VERSION),
231
+ operation: Type.String(),
232
+ status: Type.Union([
233
+ Type.Literal("ok"),
234
+ Type.Literal("empty"),
235
+ Type.Literal("needs_input"),
236
+ Type.Literal("partial"),
237
+ Type.Literal("degraded"),
238
+ Type.Literal("error")
239
+ ]),
240
+ summary: Type.Optional(Type.String()),
241
+ interpretation: Type.Optional(Type.Unknown()),
242
+ results: Type.Optional(Type.Unknown()),
243
+ result_count: Type.Optional(Type.Integer({ minimum: 0 })),
244
+ warnings: Type.Optional(Type.Array(Type.String())),
245
+ query_intent: Type.Optional(Type.Unknown()),
246
+ error: Type.Optional(Type.Object({
247
+ code: Type.String(),
248
+ layer: Type.String(),
249
+ retryable: Type.Boolean(),
250
+ recovery: Type.String()
251
+ }, { additionalProperties: false })),
252
+ execution: Type.Object({
253
+ transport: Type.String({ enum: ["direct", "cli", "mcp"] }),
254
+ transport_name: Type.String(),
255
+ correlation_id: Type.String(),
256
+ duration_ms: Type.Number({ minimum: 0 })
257
+ }, { additionalProperties: false }),
258
+ provenance: Type.Optional(Type.Object({
259
+ source: Type.String(),
260
+ endpoint: Type.String(),
261
+ documentation: Type.String(),
262
+ transport: Type.Optional(Type.String()),
263
+ requests: Type.Optional(Type.Array(QLOO_REQUEST_PREVIEW_SCHEMA, {
264
+ maxItems: 20
265
+ }))
266
+ }, { additionalProperties: false }))
267
+ }, { additionalProperties: true });
268
+ var QLOO_WORKFLOW_INPUT_SCHEMAS = {
269
+ recommend: Type.Object({
270
+ target_type: QLOO_INSIGHTS_ENTITY_TYPE_SCHEMA,
271
+ signals: Type.Optional(QLOO_ENTITY_INPUTS_SCHEMA),
272
+ signal_tags: Type.Optional(QLOO_TAG_INPUTS_SCHEMA),
273
+ signal_tags_operator: Type.Optional(QLOO_TAG_BOOLEAN_OPERATOR_SCHEMA),
274
+ signal_location: Type.Optional(Type.String({ minLength: 1 })),
275
+ demographic: Type.Optional(QLOO_DEMOGRAPHIC_SCHEMA),
276
+ filter_location: Type.Optional(Type.String({ minLength: 1 })),
277
+ include_tags: Type.Optional(QLOO_TAG_INPUTS_SCHEMA),
278
+ include_tags_operator: Type.Optional(QLOO_TAG_BOOLEAN_OPERATOR_SCHEMA),
279
+ exclude_tags: Type.Optional(QLOO_TAG_INPUTS_SCHEMA),
280
+ exclude_tags_operator: Type.Optional(QLOO_TAG_BOOLEAN_OPERATOR_SCHEMA),
281
+ explain: Type.Optional(Type.Boolean({ default: true })),
282
+ limit: QLOO_LIMIT_SCHEMA
283
+ }, { additionalProperties: false }),
284
+ rank: Type.Object({
285
+ options: QLOO_ENTITY_INPUTS_SCHEMA,
286
+ option_type: QLOO_INSIGHTS_ENTITY_TYPE_SCHEMA,
287
+ signals: Type.Optional(QLOO_ENTITY_INPUTS_SCHEMA),
288
+ signal_location: Type.Optional(Type.String({ minLength: 1 })),
289
+ demographic: Type.Optional(QLOO_DEMOGRAPHIC_SCHEMA),
290
+ include_tags: Type.Optional(QLOO_TAG_INPUTS_SCHEMA),
291
+ exclude_tags: Type.Optional(QLOO_TAG_INPUTS_SCHEMA)
292
+ }, { additionalProperties: false }),
293
+ describe: Type.Object({
294
+ entity: Type.String({ minLength: 1 }),
295
+ type: Type.Optional(QLOO_SEARCH_ENTITY_TYPE_SCHEMA)
296
+ }, { additionalProperties: false }),
297
+ where_popular: Type.Object({
298
+ entity: Type.String({ minLength: 1 }),
299
+ entity_type: Type.Optional(QLOO_SEARCH_ENTITY_TYPE_SCHEMA),
300
+ within: Type.String({
301
+ minLength: 1,
302
+ description: "Required geographic area that constrains the heatmap."
303
+ }),
304
+ limit: QLOO_LIMIT_SCHEMA
305
+ }, { additionalProperties: false }),
306
+ compare_audiences: Type.Object({
307
+ group_a: QLOO_ENTITY_INPUTS_SCHEMA,
308
+ group_b: QLOO_ENTITY_INPUTS_SCHEMA,
309
+ target_type: Type.Optional(QLOO_INSIGHTS_ENTITY_TYPE_SCHEMA),
310
+ limit: QLOO_LIMIT_SCHEMA
311
+ }, { additionalProperties: false }),
312
+ entity_tags: Type.Object({
313
+ entities: QLOO_ENTITY_INPUTS_SCHEMA,
314
+ entity_type: Type.Optional(QLOO_SEARCH_ENTITY_TYPE_SCHEMA),
315
+ limit: QLOO_LIMIT_SCHEMA
316
+ }, { additionalProperties: false }),
317
+ audience_demographics: Type.Object({
318
+ entity: Type.String({ minLength: 1 }),
319
+ entity_type: Type.Optional(QLOO_SEARCH_ENTITY_TYPE_SCHEMA),
320
+ limit: QLOO_LIMIT_SCHEMA
321
+ }, { additionalProperties: false }),
322
+ trends: Type.Object({
323
+ entities: Type.Array(Type.String({ minLength: 1 }), { minItems: 1, maxItems: 5 }),
324
+ entity_type: QLOO_INSIGHTS_ENTITY_TYPE_SCHEMA,
325
+ start_date: Type.String({
326
+ pattern: "^\\d{4}-\\d{2}-\\d{2}$",
327
+ description: "Inclusive start date in YYYY-MM-DD format."
328
+ }),
329
+ end_date: Type.String({
330
+ pattern: "^\\d{4}-\\d{2}-\\d{2}$",
331
+ description: "Inclusive end date in YYYY-MM-DD format."
332
+ }),
333
+ limit: QLOO_LIMIT_SCHEMA
334
+ }, { additionalProperties: false }),
335
+ find_tags: Type.Object({
336
+ query: Type.String({ minLength: 1 }),
337
+ semantic: Type.Optional(Type.Boolean({ default: true })),
338
+ limit: QLOO_LIMIT_SCHEMA
339
+ }, { additionalProperties: false })
340
+ };
341
+ var sharedWorkflowBehavior = Object.freeze({
342
+ readOnly: true,
343
+ idempotent: true,
344
+ mutating: false,
345
+ destructive: false,
346
+ openWorld: true,
347
+ concurrency: "safe_for_independent_inputs",
348
+ requiredCredential: "qloo_api",
349
+ defaultResultBudget: QLOO_TOOL_DEFAULT_LIMIT,
350
+ maximumResultBudget: QLOO_TOOL_MAX_RESULTS,
351
+ safeRetryClasses: Object.freeze(["dns", "connect", "timeout", "rate_limit", "upstream_5xx"]),
352
+ supportedTransports: Object.freeze(["direct", "mcp"])
353
+ });
354
+ var mediumLatencyOperations = /* @__PURE__ */ new Set([
355
+ "recommend",
356
+ "rank",
357
+ "compare_audiences",
358
+ "entity_tags",
359
+ "audience_demographics",
360
+ "trends"
361
+ ]);
362
+ var QLOO_WORKFLOW_BEHAVIORS = Object.freeze(Object.fromEntries(Object.keys(QLOO_WORKFLOW_INPUT_SCHEMAS).map((operation) => [
363
+ operation,
364
+ Object.freeze({
365
+ ...sharedWorkflowBehavior,
366
+ expectedLatency: mediumLatencyOperations.has(operation) ? "medium" : "low"
367
+ })
368
+ ])));
369
+ var QLOO_WORKFLOW_METADATA = {
370
+ recommend: {
371
+ toolName: "qloo_recommend",
372
+ label: "Qloo recommendations",
373
+ description: "Find Qloo entities related to one combined entity, tag, location, and demographic taste profile. Signals influence affinity; filters constrain output.",
374
+ promptSnippet: "Recommend entities from a combined Qloo taste profile",
375
+ promptGuidelines: [
376
+ "Pass every related taste and audience signal together in one qloo_recommend call.",
377
+ "Use signal_location for audience location and filter_location to constrain result geography.",
378
+ "Include demographic and location in the same call when both describe the audience."
379
+ ],
380
+ documentation: ["https://docs.qloo.com/reference/insights-api-deep-dive"]
381
+ },
382
+ rank: {
383
+ toolName: "qloo_rank",
384
+ label: "Qloo rank",
385
+ description: "Rank one supplied option set against one shared entity, location, demographic, and tag profile. Scores from separate calls are not comparable.",
386
+ promptSnippet: "Rank a caller-supplied shortlist with Qloo",
387
+ promptGuidelines: ["Pass every option in one qloo_rank call so scores remain comparable."],
388
+ documentation: ["https://docs.qloo.com/reference/insights-api-deep-dive"]
389
+ },
390
+ describe: {
391
+ toolName: "qloo_describe",
392
+ label: "Qloo entity",
393
+ description: "Resolve one named entity or Qloo UUID and return only metadata present in Qloo.",
394
+ promptSnippet: "Resolve and describe one Qloo entity",
395
+ documentation: ["https://docs.qloo.com/reference/get-search", "https://docs.qloo.com/reference/get-entities"]
396
+ },
397
+ where_popular: {
398
+ toolName: "qloo_where_popular",
399
+ label: "Qloo geographic affinity",
400
+ description: "Find geographic areas where one entity has strong query-relative affinity. This is distinct from filtering recommendations to a place.",
401
+ promptSnippet: "Find where an entity is comparatively popular",
402
+ documentation: ["https://docs.qloo.com/reference/heatmaps-use-case"]
403
+ },
404
+ compare_audiences: {
405
+ toolName: "qloo_compare_audiences",
406
+ label: "Qloo audience comparison",
407
+ description: "Compare two complete groups of entity signals in one Qloo analysis request.",
408
+ promptSnippet: "Compare two Qloo taste-signal groups",
409
+ documentation: ["https://docs.qloo.com/reference/analysis-compare"]
410
+ },
411
+ entity_tags: {
412
+ toolName: "qloo_entity_tags",
413
+ label: "Qloo entity tags",
414
+ description: "Retrieve Qloo concepts that jointly characterize one or more entities using the documented urn:tag Insights workflow.",
415
+ promptSnippet: "Find concepts that characterize Qloo entities",
416
+ documentation: ["https://docs.qloo.com/reference/taste-analysis"]
417
+ },
418
+ audience_demographics: {
419
+ toolName: "qloo_audience_demographics",
420
+ label: "Qloo audience demographics",
421
+ description: "Retrieve aggregate demographic distributions associated with one entity through the documented urn:demographics Insights workflow.",
422
+ promptSnippet: "Inspect aggregate demographics associated with a Qloo entity",
423
+ documentation: ["https://docs.qloo.com/reference/demographics-use-case"]
424
+ },
425
+ trends: {
426
+ toolName: "qloo_trends",
427
+ label: "Qloo trends",
428
+ description: "Retrieve Qloo time-series popularity metrics for one to five resolved entities over an ISO date range.",
429
+ promptSnippet: "Track Qloo entity popularity metrics over time",
430
+ documentation: ["https://docs.qloo.com/reference/get-trending"]
431
+ },
432
+ find_tags: {
433
+ toolName: "qloo_find_tags",
434
+ label: "Qloo tag search",
435
+ description: "Search Qloo's tag ontology by natural-language concept and return stable tag URNs.",
436
+ promptSnippet: "Search the Qloo tag ontology",
437
+ documentation: ["https://docs.qloo.com/reference/get-tags-1"]
438
+ }
439
+ };
440
+ var QLOO_WORKFLOW_CONTRACTS = Object.freeze(Object.fromEntries(Object.entries(QLOO_WORKFLOW_METADATA).map(([id, metadata]) => [
441
+ id,
442
+ Object.freeze({
443
+ id,
444
+ ...metadata,
445
+ behavior: QLOO_WORKFLOW_BEHAVIORS[id],
446
+ inputSchema: QLOO_WORKFLOW_INPUT_SCHEMAS[id],
447
+ resultSchema: QLOO_RESULT_ENVELOPE_SCHEMA
448
+ })
449
+ ])));
450
+ var QLOO_ADAPTER_CONTRACT_MANIFEST_SCHEMA_VERSION = "1.1";
451
+ function getQlooExecutableCapabilities(input = {}) {
452
+ const capabilities = getQlooCapabilities(input);
453
+ return {
454
+ ...capabilities,
455
+ result_schema_version: QLOO_TOOL_RESULT_SCHEMA_VERSION,
456
+ operations: capabilities.operations.map((operation) => {
457
+ const contract = QLOO_WORKFLOW_CONTRACTS[operation.id];
458
+ return {
459
+ ...operation,
460
+ input_schema: contract.inputSchema,
461
+ result_schema: contract.resultSchema,
462
+ documentation: contract.documentation,
463
+ behavior: contract.behavior
464
+ };
465
+ })
466
+ };
467
+ }
468
+ function getQlooAdapterContractManifest() {
469
+ const capabilities = getQlooExecutableCapabilities();
470
+ const contract = {
471
+ manifest_schema_version: QLOO_ADAPTER_CONTRACT_MANIFEST_SCHEMA_VERSION,
472
+ contract_version: capabilities.contract_version,
473
+ capabilities_tool: QLOO_CAPABILITIES_TOOL_NAME,
474
+ result_schema_version: capabilities.result_schema_version,
475
+ result_schema: QLOO_RESULT_ENVELOPE_SCHEMA,
476
+ operations: capabilities.operations.map((operation) => {
477
+ const contract2 = QLOO_WORKFLOW_CONTRACTS[operation.id];
478
+ return {
479
+ id: operation.id,
480
+ shared_tool_name: operation.toolName,
481
+ summary: operation.summary,
482
+ description: contract2.description,
483
+ input_schema: contract2.inputSchema,
484
+ behavior: contract2.behavior,
485
+ documentation: contract2.documentation
486
+ };
487
+ }),
488
+ upstream: capabilities.upstream
489
+ };
490
+ return {
491
+ ...contract,
492
+ contract_checksum: `sha256:${createHash("sha256").update(JSON.stringify(contract)).digest("hex")}`
493
+ };
494
+ }
495
+ function validationIssues(schema, value) {
496
+ return [...Value.Errors(schema, value)].slice(0, 20).map((issue) => ({
497
+ path: issue.keyword === "additionalProperties" && "additionalProperties" in issue.params && Array.isArray(issue.params.additionalProperties) && typeof issue.params.additionalProperties[0] === "string" ? `${issue.instancePath}/${issue.params.additionalProperties[0]}` : issue.instancePath || "/",
498
+ message: issue.message
499
+ }));
500
+ }
501
+ function validateQlooWorkflowResult(value) {
502
+ if (Value.Check(QLOO_RESULT_ENVELOPE_SCHEMA, value)) {
503
+ return { ok: true, value };
504
+ }
505
+ return { ok: false, issues: validationIssues(QLOO_RESULT_ENVELOPE_SCHEMA, value) };
506
+ }
507
+
508
+ // packages/qloo-tool-schema/dist/src/resolution-contracts.js
509
+ import { Type as Type2 } from "typebox";
510
+ var QLOO_RESOLUTION_CONTRACT_VERSION = "1.0-preview.1";
511
+ var QLOO_RESOLUTION_PROVIDER_DESCRIPTOR_SCHEMA = Type2.Object({
512
+ contract_version: Type2.Literal(QLOO_RESOLUTION_CONTRACT_VERSION),
513
+ provider_id: Type2.String({ minLength: 1 }),
514
+ name: Type2.String({ minLength: 1 }),
515
+ entity_strategy: Type2.String({ minLength: 1 }),
516
+ tag_strategy: Type2.String({ minLength: 1 }),
517
+ remote: Type2.Boolean(),
518
+ uses_model: Type2.Boolean(),
519
+ fallback: Type2.Literal("none")
520
+ }, { additionalProperties: false });
521
+ var QLOO_RESOLUTION_CANDIDATE_SCHEMA = Type2.Object({
522
+ id: Type2.String({ minLength: 1 }),
523
+ name: Type2.String({ minLength: 1 }),
524
+ type: Type2.Optional(Type2.String({ minLength: 1 })),
525
+ rank: Type2.Optional(Type2.Integer({ minimum: 1 })),
526
+ score: Type2.Optional(Type2.Number()),
527
+ popularity: Type2.Optional(Type2.Number()),
528
+ parent_types: Type2.Optional(Type2.Array(Type2.String({ minLength: 1 }), {
529
+ maxItems: 20,
530
+ uniqueItems: true
531
+ })),
532
+ description: Type2.Optional(Type2.String({ minLength: 1, maxLength: 500 })),
533
+ release_year: Type2.Optional(Type2.Integer()),
534
+ address: Type2.Optional(Type2.Unknown())
535
+ }, { additionalProperties: false });
536
+ var QLOO_RESOLUTION_PROVENANCE_SCHEMA = Type2.Object({
537
+ contract_version: Type2.Literal(QLOO_RESOLUTION_CONTRACT_VERSION),
538
+ provider_id: Type2.String({ minLength: 1 }),
539
+ provider_name: Type2.String({ minLength: 1 }),
540
+ endpoint: Type2.String({ minLength: 1 }),
541
+ strategy: Type2.String({ minLength: 1 }),
542
+ remote: Type2.Boolean(),
543
+ uses_model: Type2.Boolean(),
544
+ provider_version: Type2.Optional(Type2.String({ minLength: 1 })),
545
+ cache_status: Type2.Optional(Type2.String({ minLength: 1 }))
546
+ }, { additionalProperties: false });
547
+ var QLOO_RESOLUTION_OUTCOME_COMMON_SCHEMA = {
548
+ input: Type2.String({ minLength: 1 }),
549
+ provenance: QLOO_RESOLUTION_PROVENANCE_SCHEMA,
550
+ warnings: Type2.Optional(Type2.Array(Type2.String()))
551
+ };
552
+ var QLOO_RESOLUTION_OUTCOME_SCHEMA = Type2.Union([
553
+ Type2.Object({
554
+ ...QLOO_RESOLUTION_OUTCOME_COMMON_SCHEMA,
555
+ status: Type2.Literal("resolved"),
556
+ match: Type2.Union([
557
+ Type2.Literal("identifier"),
558
+ Type2.Literal("exact"),
559
+ Type2.Literal("semantic")
560
+ ]),
561
+ selected: QLOO_RESOLUTION_CANDIDATE_SCHEMA,
562
+ alternatives: Type2.Optional(Type2.Array(QLOO_RESOLUTION_CANDIDATE_SCHEMA))
563
+ }, { additionalProperties: false }),
564
+ Type2.Object({
565
+ ...QLOO_RESOLUTION_OUTCOME_COMMON_SCHEMA,
566
+ status: Type2.Literal("ambiguous"),
567
+ candidates: Type2.Array(QLOO_RESOLUTION_CANDIDATE_SCHEMA)
568
+ }, { additionalProperties: false }),
569
+ Type2.Object({
570
+ ...QLOO_RESOLUTION_OUTCOME_COMMON_SCHEMA,
571
+ status: Type2.Literal("not_found"),
572
+ candidates: Type2.Optional(Type2.Array(QLOO_RESOLUTION_CANDIDATE_SCHEMA))
573
+ }, { additionalProperties: false })
574
+ ]);
575
+
576
+ // apps/qloo-harness/dist/mcp.js
577
+ import { createQlooToolsFromEnvironment } from "./qloo-tools.js";
578
+ var QLOO_MCP_CONTRACT_RESOURCE_URI = "qloo://contracts/workflows";
579
+ var QLOO_MCP_HELP = `Start the canonical Qloo MCP stdio server
580
+
581
+ Usage:
582
+ qloo mcp
583
+
584
+ The server exposes qloo_capabilities and the nine shared Qloo workflow tools.
585
+ Use qloo api mcp only when you explicitly need the legacy endpoint-shaped server.`;
586
+ function isRecord(value) {
587
+ return value !== null && typeof value === "object" && !Array.isArray(value);
588
+ }
589
+ function adapterCapabilities(manifest, executableOperationIds, argumentsValue) {
590
+ const argumentsRecord = isRecord(argumentsValue) ? argumentsValue : {};
591
+ const knownIds = new Set(manifest.operations.map(({ id }) => id));
592
+ const requestedValues = argumentsRecord.operation_ids;
593
+ const requested = requestedValues === void 0 ? knownIds : new Set(Array.isArray(requestedValues) ? requestedValues.filter((value) => typeof value === "string") : []);
594
+ if (requestedValues !== void 0 && !Array.isArray(requestedValues)) {
595
+ throw new Error("operation_ids must be an array of canonical workflow operation IDs.");
596
+ }
597
+ const unknown = [...requested].filter((id) => !knownIds.has(id)).sort();
598
+ if (unknown.length > 0) {
599
+ throw new Error(`Unknown Qloo workflow operation IDs: ${unknown.join(", ")}`);
600
+ }
601
+ const supportedOperationIds = manifest.operations.map(({ id }) => id).filter((id) => executableOperationIds.has(id));
602
+ return {
603
+ ...manifest,
604
+ adapter: {
605
+ id: "qloo_harness_mcp",
606
+ compatibility: "canonical",
607
+ canonical_workflow_execution: supportedOperationIds.length === manifest.operations.length,
608
+ ready: supportedOperationIds.length === manifest.operations.length,
609
+ supported_operation_ids: supportedOperationIds,
610
+ capabilities_tool: QLOO_CAPABILITIES_TOOL_NAME,
611
+ contract_resource: QLOO_MCP_CONTRACT_RESOURCE_URI,
612
+ tool_name_mapping: Object.fromEntries(manifest.operations.map(({ id, shared_tool_name }) => [id, shared_tool_name])),
613
+ fallback: "none"
614
+ },
615
+ operations: manifest.operations.filter(({ id }) => requested.has(id))
616
+ };
617
+ }
618
+ function capabilitiesOutputSchema() {
619
+ return {
620
+ type: "object",
621
+ required: [
622
+ "manifest_schema_version",
623
+ "contract_version",
624
+ "contract_checksum",
625
+ "result_schema_version",
626
+ "adapter",
627
+ "operations"
628
+ ],
629
+ properties: {
630
+ manifest_schema_version: { type: "string" },
631
+ contract_version: { type: "string" },
632
+ contract_checksum: { type: "string", pattern: "^sha256:[a-f0-9]{64}$" },
633
+ result_schema_version: { type: "string" },
634
+ adapter: { type: "object" },
635
+ operations: { type: "array" }
636
+ },
637
+ additionalProperties: true
638
+ };
639
+ }
640
+ function mcpToolDefinitions(manifest) {
641
+ const contractMetadata = {
642
+ "qloo/contractVersion": manifest.contract_version,
643
+ "qloo/contractChecksum": manifest.contract_checksum
644
+ };
645
+ return [
646
+ {
647
+ name: QLOO_CAPABILITIES_TOOL_NAME,
648
+ title: "Inspect Qloo MCP capabilities",
649
+ description: "Inspect the canonical Qloo workflow contract, checksum, and this server's exact execution readiness without contacting Qloo.",
650
+ inputSchema: {
651
+ type: "object",
652
+ properties: {
653
+ operation_ids: {
654
+ type: "array",
655
+ items: {
656
+ type: "string",
657
+ enum: manifest.operations.map(({ id }) => id)
658
+ },
659
+ uniqueItems: true,
660
+ maxItems: manifest.operations.length
661
+ }
662
+ },
663
+ additionalProperties: false
664
+ },
665
+ outputSchema: capabilitiesOutputSchema(),
666
+ annotations: {
667
+ readOnlyHint: true,
668
+ destructiveHint: false,
669
+ idempotentHint: true,
670
+ openWorldHint: false
671
+ },
672
+ _meta: contractMetadata
673
+ },
674
+ ...manifest.operations.map((operation) => ({
675
+ name: operation.shared_tool_name,
676
+ title: operation.summary,
677
+ description: operation.description,
678
+ inputSchema: operation.input_schema,
679
+ outputSchema: manifest.result_schema,
680
+ annotations: {
681
+ readOnlyHint: operation.behavior.readOnly,
682
+ destructiveHint: operation.behavior.destructive,
683
+ idempotentHint: operation.behavior.idempotent,
684
+ openWorldHint: operation.behavior.openWorld
685
+ },
686
+ _meta: contractMetadata
687
+ }))
688
+ ];
689
+ }
690
+ function respond(writeOut, id, result) {
691
+ const response = { jsonrpc: "2.0", id, result };
692
+ writeOut(`${JSON.stringify(response)}
693
+ `);
694
+ }
695
+ function respondError(writeOut, id, code, message, data) {
696
+ const response = {
697
+ jsonrpc: "2.0",
698
+ id,
699
+ error: { code, message, ...data === void 0 ? {} : { data } }
700
+ };
701
+ writeOut(`${JSON.stringify(response)}
702
+ `);
703
+ }
704
+ function toolResult(result) {
705
+ return {
706
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
707
+ structuredContent: result,
708
+ ...result.status === "error" ? { isError: true } : {}
709
+ };
710
+ }
711
+ function canonicalMcpResult(result) {
712
+ const execution = isRecord(result.execution) ? result.execution : {};
713
+ const provenance = isRecord(result.provenance) ? result.provenance : void 0;
714
+ const normalized = {
715
+ ...result,
716
+ execution: {
717
+ ...execution,
718
+ transport: "mcp",
719
+ transport_name: "Qloo canonical MCP"
720
+ },
721
+ ...provenance ? { provenance: { ...provenance, transport: "mcp" } } : {}
722
+ };
723
+ const validation = validateQlooWorkflowResult(normalized);
724
+ if (!validation.ok) {
725
+ const issues = validation.issues.map(({ path, message }) => `${path}: ${message}`).join("; ");
726
+ throw new Error(`Canonical MCP result failed the shared contract: ${issues}`);
727
+ }
728
+ return validation.value;
729
+ }
730
+ function unavailableResult(operation, correlationId) {
731
+ return {
732
+ schema_version: QLOO_TOOL_RESULT_SCHEMA_VERSION,
733
+ operation,
734
+ status: "error",
735
+ summary: "Qloo workflow execution requires a configured Qloo API credential.",
736
+ results: [],
737
+ result_count: 0,
738
+ error: {
739
+ code: "QLOO_AUTH",
740
+ layer: "qloo",
741
+ retryable: false,
742
+ recovery: "Run qloo setup or set QLOO_API_KEY, then restart the MCP server."
743
+ },
744
+ execution: {
745
+ transport: "mcp",
746
+ transport_name: "Qloo canonical MCP",
747
+ correlation_id: correlationId,
748
+ duration_ms: 0
749
+ }
750
+ };
751
+ }
752
+ function unexpectedFailureResult(operation, correlationId) {
753
+ return {
754
+ schema_version: QLOO_TOOL_RESULT_SCHEMA_VERSION,
755
+ operation,
756
+ status: "error",
757
+ summary: "The Qloo MCP adapter failed before returning a workflow result.",
758
+ results: [],
759
+ result_count: 0,
760
+ error: {
761
+ code: "MCP_ADAPTER_FAILURE",
762
+ layer: "harness",
763
+ retryable: false,
764
+ recovery: "Run qloo doctor --network and inspect the local redacted trace."
765
+ },
766
+ execution: {
767
+ transport: "mcp",
768
+ transport_name: "Qloo canonical MCP",
769
+ correlation_id: correlationId,
770
+ duration_ms: 0
771
+ }
772
+ };
773
+ }
774
+ function startCanonicalMcpServer(options = {}) {
775
+ const manifest = getQlooAdapterContractManifest();
776
+ const tools = options.tools ?? createQlooToolsFromEnvironment({ env: options.env ?? process.env });
777
+ const executableTools = new Map(tools.filter((tool) => tool.name !== QLOO_CAPABILITIES_TOOL_NAME).map((tool) => [tool.name, tool]));
778
+ const operationByToolName = new Map(manifest.operations.map((operation) => [operation.shared_tool_name, operation.id]));
779
+ const executableOperationIds = new Set(manifest.operations.filter(({ shared_tool_name }) => executableTools.has(shared_tool_name)).map(({ id }) => id));
780
+ const definitions = mcpToolDefinitions(manifest);
781
+ const writeOut = options.writeOut ?? ((value) => process.stdout.write(value));
782
+ const readline = createInterface({ input: options.input ?? process.stdin, terminal: false });
783
+ readline.on("line", async (line) => {
784
+ let request;
785
+ try {
786
+ request = JSON.parse(line);
787
+ } catch {
788
+ respondError(writeOut, null, -32700, "Parse error");
789
+ return;
790
+ }
791
+ const id = request.id ?? null;
792
+ try {
793
+ switch (request.method) {
794
+ case "initialize":
795
+ respond(writeOut, id, {
796
+ protocolVersion: "2024-11-05",
797
+ capabilities: { tools: {}, resources: {} },
798
+ serverInfo: {
799
+ name: "qloo-harness",
800
+ version: options.serverVersion ?? "development"
801
+ }
802
+ });
803
+ return;
804
+ case "notifications/initialized":
805
+ case "notifications/cancelled":
806
+ return;
807
+ case "ping":
808
+ respond(writeOut, id, {});
809
+ return;
810
+ case "tools/list":
811
+ respond(writeOut, id, { tools: definitions });
812
+ return;
813
+ case "resources/list":
814
+ respond(writeOut, id, {
815
+ resources: [{
816
+ uri: QLOO_MCP_CONTRACT_RESOURCE_URI,
817
+ name: "qloo_workflow_contract",
818
+ title: "Qloo workflow contract",
819
+ description: "Canonical Qloo workflow schemas and MCP adapter readiness.",
820
+ mimeType: "application/json"
821
+ }]
822
+ });
823
+ return;
824
+ case "resources/read": {
825
+ const uri = isRecord(request.params) ? request.params.uri : void 0;
826
+ if (uri !== QLOO_MCP_CONTRACT_RESOURCE_URI) {
827
+ respondError(writeOut, id, -32602, "Unknown Qloo MCP resource.");
828
+ return;
829
+ }
830
+ const capabilities = adapterCapabilities(manifest, executableOperationIds, {});
831
+ respond(writeOut, id, {
832
+ contents: [{
833
+ uri: QLOO_MCP_CONTRACT_RESOURCE_URI,
834
+ mimeType: "application/json",
835
+ text: JSON.stringify(capabilities)
836
+ }]
837
+ });
838
+ return;
839
+ }
840
+ case "tools/call": {
841
+ const toolName = isRecord(request.params) ? request.params.name : void 0;
842
+ const argumentsValue = isRecord(request.params) ? request.params.arguments : void 0;
843
+ if (typeof toolName !== "string") {
844
+ respondError(writeOut, id, -32602, "tools/call requires a tool name.");
845
+ return;
846
+ }
847
+ if (toolName === QLOO_CAPABILITIES_TOOL_NAME) {
848
+ try {
849
+ const result = adapterCapabilities(manifest, executableOperationIds, argumentsValue);
850
+ respond(writeOut, id, toolResult(result));
851
+ } catch (error) {
852
+ respond(writeOut, id, {
853
+ content: [{
854
+ type: "text",
855
+ text: error instanceof Error ? error.message : String(error)
856
+ }],
857
+ isError: true
858
+ });
859
+ }
860
+ return;
861
+ }
862
+ const operation = operationByToolName.get(toolName);
863
+ if (!operation) {
864
+ respondError(writeOut, id, -32602, `Unknown Qloo MCP tool: ${toolName}`);
865
+ return;
866
+ }
867
+ const correlationId = `mcp-${id === null ? "request" : String(id)}`;
868
+ const tool = executableTools.get(toolName);
869
+ if (!tool) {
870
+ respond(writeOut, id, toolResult(unavailableResult(operation, correlationId)));
871
+ return;
872
+ }
873
+ try {
874
+ const result = await tool.execute(correlationId, isRecord(argumentsValue) ? argumentsValue : {}, void 0, void 0, {});
875
+ if (!isRecord(result.details)) {
876
+ throw new Error(`${toolName} returned no structured workflow result.`);
877
+ }
878
+ respond(writeOut, id, toolResult(canonicalMcpResult(result.details)));
879
+ } catch {
880
+ respond(writeOut, id, toolResult(unexpectedFailureResult(operation, correlationId)));
881
+ }
882
+ return;
883
+ }
884
+ default:
885
+ respondError(writeOut, id, -32601, `Method not found: ${request.method}`);
886
+ }
887
+ } catch {
888
+ respondError(writeOut, id, -32603, "Internal Qloo MCP adapter error.");
889
+ }
890
+ });
891
+ return readline;
892
+ }
893
+ function runQlooMcp(argv, options = {}) {
894
+ if (argv.length === 1 && (argv[0] === "--help" || argv[0] === "-h")) {
895
+ (options.writeOut ?? ((value) => process.stdout.write(value)))(`${QLOO_MCP_HELP}
896
+ `);
897
+ return 0;
898
+ }
899
+ if (argv.length > 0)
900
+ return 2;
901
+ startCanonicalMcpServer(options);
902
+ return 0;
903
+ }
904
+ export {
905
+ QLOO_MCP_CONTRACT_RESOURCE_URI,
906
+ QLOO_MCP_HELP,
907
+ runQlooMcp,
908
+ startCanonicalMcpServer
909
+ };