catence 0.2.1-beta.24 → 0.2.1-beta.25

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.
@@ -3,7 +3,7 @@
3
3
  * Keep these values synchronized with release/manifest.json; release checks
4
4
  * deliberately reject drift before a package can be published.
5
5
  */
6
- export declare const CATENCE_RUNTIME_VERSION = "0.2.1-beta.24";
6
+ export declare const CATENCE_RUNTIME_VERSION = "0.2.1-beta.25";
7
7
  export declare const CATENCE_PROTOCOL_VERSION = 1;
8
8
  export type CatenceRuntimeCapabilities = {
9
9
  mcp: true;
@@ -3,7 +3,7 @@
3
3
  * Keep these values synchronized with release/manifest.json; release checks
4
4
  * deliberately reject drift before a package can be published.
5
5
  */
6
- export const CATENCE_RUNTIME_VERSION = '0.2.1-beta.24';
6
+ export const CATENCE_RUNTIME_VERSION = '0.2.1-beta.25';
7
7
  export const CATENCE_PROTOCOL_VERSION = 1;
8
8
  export function catenceRuntimeHealth() {
9
9
  return {
@@ -109,6 +109,11 @@ export async function createOAuthApp(options) {
109
109
  app.get('/.well-known/oauth-authorization-server', serveMetadata(oauthMetadata));
110
110
  app.get('/.well-known/oauth-protected-resource', serveMetadata(protectedResourceMetadata));
111
111
  app.get('/.well-known/oauth-protected-resource/mcp', serveMetadata(protectedResourceMetadata));
112
+ // The connector platform probes OIDC-style discovery on every validation
113
+ // pass (observed hitting the auth gate as a 401 right after fetching the
114
+ // RFC 8414 document); answer it publicly with the same metadata.
115
+ app.get('/.well-known/openid-configuration', serveMetadata(oauthMetadata));
116
+ app.get('/.well-known/openid-configuration/mcp', serveMetadata(oauthMetadata));
112
117
  // DCR runs through the library's router, whose own express.json() would
113
118
  // re-parse (and reject) an already-consumed stream; parsing here first
114
119
  // leaves the sanitized body in place for it.
@@ -33,6 +33,9 @@ function logRequestCompletion(request, response, pathname) {
33
33
  if (process.env.CATENCE_HTTP_ACCESS_LOG === '0')
34
34
  return;
35
35
  const startedAt = Date.now();
36
+ // Captured before the compatibility bridge rewrites the header so the log
37
+ // always shows the value the client actually sent.
38
+ const rawProtocolVersion = request.headers['mcp-protocol-version'];
36
39
  response.once('finish', () => {
37
40
  const status = response.statusCode;
38
41
  const interesting = pathname === '/mcp' ||
@@ -46,7 +49,7 @@ function logRequestCompletion(request, response, pathname) {
46
49
  const userAgent = request.headers['user-agent'];
47
50
  if (typeof userAgent === 'string' && userAgent)
48
51
  parts.push(`ua="${userAgent.slice(0, 120)}"`);
49
- const protocolVersion = request.headers['mcp-protocol-version'];
52
+ const protocolVersion = rawProtocolVersion;
50
53
  if (typeof protocolVersion === 'string' && protocolVersion)
51
54
  parts.push(`mcp-protocol-version=${protocolVersion}`);
52
55
  const mcpMethod = request.headers['mcp-method'];
@@ -526,7 +529,11 @@ async function handleUnauthenticatedDiscovery(request, response, paths) {
526
529
  * The bundled SDK emits the legacy shape, so responses negotiated under a
527
530
  * dated 2026 revision are rewritten on the way out. List results vary with the
528
531
  * caller's scope, so cacheable responses from this server are always
529
- * `private`. Errors and notifications carry no result and pass through.
532
+ * `private`. Every result also repeats the server identity in `_meta`, and
533
+ * tool definitions drop the SDK's `execution` field — neither the per-result
534
+ * `_meta.serverInfo` nor `execution` appeared in the revision's schemas for
535
+ * earlier SDKs, but the revision asks for the former and omits the latter.
536
+ * Errors and notifications carry no result and pass through.
530
537
  */
531
538
  const MODERN_CACHEABLE_METHODS = new Set(['server/discover', 'tools/list', 'prompts/list', 'resources/list', 'resources/templates/list', 'resources/read']);
532
539
  const MODERN_RESULT_TTL_MS = 300_000;
@@ -551,6 +558,25 @@ function frameModernRpcPayload(payload, method) {
551
558
  framed.resultType = 'complete';
552
559
  changed = true;
553
560
  }
561
+ if (!('_meta' in framed)) {
562
+ framed._meta = { 'io.modelcontextprotocol/serverInfo': CATENCE_MCP_SERVER_INFO };
563
+ changed = true;
564
+ }
565
+ if (method === 'tools/list' && Array.isArray(framed.tools)) {
566
+ let stripped = false;
567
+ const tools = framed.tools.map((tool) => {
568
+ if (typeof tool !== 'object' || tool === null || Array.isArray(tool) || !('execution' in tool))
569
+ return tool;
570
+ const copy = { ...tool };
571
+ delete copy.execution;
572
+ stripped = true;
573
+ return copy;
574
+ });
575
+ if (stripped) {
576
+ framed.tools = tools;
577
+ changed = true;
578
+ }
579
+ }
554
580
  if (method !== undefined && MODERN_CACHEABLE_METHODS.has(method)) {
555
581
  if (!('ttlMs' in framed)) {
556
582
  framed.ttlMs = MODERN_RESULT_TTL_MS;
@@ -810,7 +836,7 @@ export function createCatenceHttpServer(options = {}) {
810
836
  // The OAuth endpoints are the auth surface itself: they bypass the gate
811
837
  // and CORS entirely and are delegated to the Express sub-app. When OAuth
812
838
  // is effectively disabled they answer 404 — no metadata is advertised.
813
- if (pathname.startsWith('/.well-known/oauth-') || pathname.startsWith('/oauth/')) {
839
+ if (pathname.startsWith('/.well-known/oauth-') || pathname.startsWith('/.well-known/openid-configuration') || pathname.startsWith('/oauth/')) {
814
840
  const config = effectiveOauth();
815
841
  if (config.enabled && config.publicUrl !== undefined) {
816
842
  const handle = await getOauthApp(config.publicUrl);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "catence",
3
- "version": "0.2.1-beta.24",
3
+ "version": "0.2.1-beta.25",
4
4
  "description": "Local MCP access to normalized Garmin, Intervals.icu, and targeted Strava fitness data.",
5
5
  "license": "AGPL-3.0-or-later",
6
6
  "repository": {