@pdpp/mcp-server 0.16.4 → 0.16.6

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 (2) hide show
  1. package/package.json +1 -1
  2. package/src/tools.js +52 -17
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pdpp/mcp-server",
3
- "version": "0.16.4",
3
+ "version": "0.16.6",
4
4
  "description": "Local stdio MCP adapter for grant-scoped PDPP reads and event-subscription management.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/tools.js CHANGED
@@ -1336,7 +1336,7 @@ function toSearchToolResult(response, providerUrl, options = {}) {
1336
1336
  if (!response.ok) {
1337
1337
  return errorToolResult(response, providerUrl);
1338
1338
  }
1339
- const allResults = normalizeSearchResults(response.body, { q: options.q });
1339
+ const allResults = normalizeSearchResults(response.body, { q: options.q, providerUrl });
1340
1340
  const limit = requestedSearchLimit(options.limit);
1341
1341
  const results = allResults.slice(0, limit);
1342
1342
  const summaryBody = allResults.length > results.length
@@ -1597,11 +1597,13 @@ function definedObject(values) {
1597
1597
  return Object.fromEntries(Object.entries(values).filter(([, value]) => value !== undefined && value !== null && value !== ''));
1598
1598
  }
1599
1599
 
1600
- function hideModelVisibleFieldWindowResources(record) {
1601
- if (!record || !Array.isArray(record.field_windows)) return record;
1600
+ function hideModelVisibleResourceUris(record) {
1601
+ if (!record) return record;
1602
+ const { record_uri: _recordUri, recordUri: _recordUriCamel, ...rest } = record;
1603
+ if (!Array.isArray(rest.field_windows)) return rest;
1602
1604
  return {
1603
- ...record,
1604
- field_windows: record.field_windows.map(({ resource_uri: _resourceUri, resourceUri: _resourceUriCamel, ...field }) => field),
1605
+ ...rest,
1606
+ field_windows: rest.field_windows.map(({ resource_uri: _resourceUri, resourceUri: _resourceUriCamel, ...field }) => field),
1605
1607
  };
1606
1608
  }
1607
1609
 
@@ -1626,7 +1628,7 @@ function buildRecordContentLadder(record, fallback = {}) {
1626
1628
  binaryLimit: CONTENT_LADDER_BINARY_FIELD_LIMIT,
1627
1629
  windowLimitChars: CONTENT_LADDER_WINDOW_LIMIT_CHARS,
1628
1630
  });
1629
- return hideModelVisibleFieldWindowResources(ladder);
1631
+ return hideModelVisibleResourceUris(ladder);
1630
1632
  }
1631
1633
 
1632
1634
  function toFetchToolResult(response, providerUrl, requestedId) {
@@ -2423,13 +2425,19 @@ function normalizeSearchResults(body, options = {}) {
2423
2425
  const candidates = searchCandidatesFromBody(body);
2424
2426
  return candidates.map((hit, index) => {
2425
2427
  const source = objectValue(hit?.source) || {};
2426
- const stream = streamForHit(hit);
2427
- const recordKey = recordKeyForHit(hit);
2428
- const connectionId = firstString(hit?.connection_id, hit?.connector_instance_id, source.connection_id);
2428
+ const recordUriRef = recordUriRefForHit(hit);
2429
+ const stream = firstString(streamForHit(hit), recordUriRef?.stream);
2430
+ const recordKey = firstString(recordKeyForHit(hit), recordUriRef?.recordId);
2431
+ const connectionId = firstString(
2432
+ hit?.connection_id,
2433
+ hit?.connector_instance_id,
2434
+ source.connection_id,
2435
+ recordUriRef?.connectionId,
2436
+ );
2429
2437
  // The id is the single opaque handle a model carries into `fetch`; encode
2430
2438
  // the hit's connection so multi-source grants resolve without a second
2431
2439
  // model-carried `connection_id` field.
2432
- const id = selfContainedResultId(resultIdForHit(hit, index), connectionId);
2440
+ const id = selfContainedResultId(resultIdForHit(hit, index, { stream, recordKey }), connectionId);
2433
2441
  const displayName = firstString(hit?.display_name, source.display_name);
2434
2442
  const connectorKey = firstString(hit?.connector_key, hit?.connector_id, source.connector_key, source.connector_id);
2435
2443
  const snippet = snippetForSearchHit(hit);
@@ -2438,7 +2446,7 @@ function normalizeSearchResults(body, options = {}) {
2438
2446
  const normalized = {
2439
2447
  id,
2440
2448
  title: titleForSearchHit(hit, id, { stream, recordKey, connectionId, displayName, connectorKey }),
2441
- url: urlForRecord(hit, id),
2449
+ url: urlForRecord(hit, id, options.providerUrl),
2442
2450
  };
2443
2451
  if (stream) normalized.stream = stream;
2444
2452
  if (recordKey) normalized.record_key = recordKey;
@@ -2583,18 +2591,45 @@ function compactSearchEnvelopeDataObject(data, { resultCount } = {}) {
2583
2591
  return out;
2584
2592
  }
2585
2593
 
2586
- function resultIdForHit(hit, index) {
2587
- const directId = stringValue(hit?.result_id ?? hit?.resultId ?? hit?.record_uri ?? hit?.recordUri);
2594
+ function resultIdForHit(hit, index, fallback = {}) {
2595
+ const directId = stringValue(hit?.result_id ?? hit?.resultId);
2596
+ const directRef = parseRecordResultIdOrNull(directId);
2597
+ if (directRef) return selfContainedRecordId(directRef);
2588
2598
  if (directId) return directId;
2589
2599
 
2590
- const stream = streamForHit(hit);
2591
- const recordId = stringValue(hit?.id ?? hit?.record_id ?? hit?.recordId ?? hit?.record_key ?? hit?.recordKey);
2600
+ // REST search envelopes may include a canonical `pdpp://record/...`
2601
+ // resource URI. Keep that accepted as input, but do not make it the
2602
+ // ordinary model-visible result id: some ChatGPT hosts do not route generic
2603
+ // resource reads for templates. A visible id must be directly usable by
2604
+ // `fetch` and `read_record_field`, so normalize parseable record URIs into
2605
+ // the self-contained tool id grammar.
2606
+ const recordUriRef = recordUriRefForHit(hit);
2607
+ if (recordUriRef) return selfContainedRecordId(recordUriRef);
2608
+
2609
+ const stream = fallback.stream ?? streamForHit(hit);
2610
+ const recordId =
2611
+ fallback.recordKey ??
2612
+ stringValue(hit?.id ?? hit?.record_id ?? hit?.recordId ?? hit?.record_key ?? hit?.recordKey);
2592
2613
  if (stream && recordId) {
2593
2614
  return `${stream}:${recordId}`;
2594
2615
  }
2595
2616
 
2596
- const fallback = stringValue(hit?.id ?? hit?.url);
2597
- return fallback || `result:${index + 1}`;
2617
+ const fallbackId = stringValue(hit?.id ?? hit?.url);
2618
+ return fallbackId || `result:${index + 1}`;
2619
+ }
2620
+
2621
+ function recordUriRefForHit(hit) {
2622
+ for (const value of [hit?.record_uri, hit?.recordUri, hit?.id]) {
2623
+ const raw = stringValue(value);
2624
+ if (!raw || !raw.startsWith('pdpp://record/')) continue;
2625
+ const parsed = parseRecordResultIdOrNull(raw);
2626
+ if (parsed) return parsed;
2627
+ }
2628
+ return null;
2629
+ }
2630
+
2631
+ function selfContainedRecordId(ref) {
2632
+ return ref.connectionId ? `${ref.connectionId}/${ref.stream}:${ref.recordId}` : `${ref.stream}:${ref.recordId}`;
2598
2633
  }
2599
2634
 
2600
2635
  function streamForHit(hit) {