Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
85 commits
Select commit Hold shift + click to select a range
136d4dc
test(binding-mcp): scaffold mcp cache binding IT contract (#1737)
claude May 13, 2026
3431b9f
test(binding-mcp): add peer-to-peer CacheIT for warmup scripts (#1737)
claude May 13, 2026
a2e509d
test(binding-mcp): split cache ITs by group and add Group B list scri…
claude May 16, 2026
77f8a34
test(binding-mcp): add downstream-error warmup scenario, drop Group D…
claude May 16, 2026
caa0941
test(binding-mcp): regroup cache ITs by MCP method kind (#1737)
claude May 16, 2026
661a012
test(binding-mcp): fold cache into mcp.proxy with options.cache (#1737)
claude May 16, 2026
9d412a5
test(binding-mcp): flatten cache scenario + method names (#1737)
claude May 16, 2026
a3a6bf6
test(binding-mcp): add cache refresh scenarios + tests (#1737)
claude May 16, 2026
c87ea1e
test(binding-mcp): add hydrating scenarios per list method (#1737)
claude May 16, 2026
cc8649f
test(engine): add entries option to test store for seeded state
claude May 16, 2026
e3af9da
test(binding-mcp): scaffold cache refresh contention test (#1737)
claude May 16, 2026
a681d4a
test(binding-mcp): proper contention scripts with multi-worker engine…
claude May 16, 2026
c9e6e58
test(binding-mcp): address review feedback on PR #1774
claude May 16, 2026
6f3c4b4
test(binding-mcp): fix checkstyle import ordering in McpProxyCacheCon…
claude May 16, 2026
7c94898
test(binding-mcp): @Ignore engine-driven cache ITs until impl lands
claude May 16, 2026
bb0533f
feat(binding-mcp): add McpCacheConfig POJO + JSON adapter (#1737)
claude May 16, 2026
404ac76
feat(binding-mcp): originate hydrate lifecycle session at bring-up (#…
claude May 16, 2026
88d4e1b
feat(binding-mcp): hydrate per-method list enumeration (#1737)
claude May 16, 2026
66a561d
feat(binding-mcp): persist hydrate response bodies to store (#1737)
claude May 16, 2026
7ffe2cf
feat(binding-mcp): serve list responses from cache (#1737)
claude May 16, 2026
3e279fa
refactor(binding-mcp): introduce McpListCache; hydrate kinds in paral…
claude May 16, 2026
37a405e
refactor(binding-mcp): address PR #1774 review feedback
claude May 16, 2026
243712b
refactor(binding-mcp): hoist sessions and hydrate state onto McpBindi…
claude May 16, 2026
31ea5a4
refactor(binding-mcp): extract McpProxyLifecycleFactory + dispatch table
claude May 16, 2026
92ba681
refactor(binding-mcp): extract McpProxyItemFactory for tools/call, pr…
claude May 16, 2026
c9b95a1
test(binding-mcp): add MCP_HYDRATE_KIND_FILTER to scope per-kind cach…
claude May 17, 2026
28038c7
refactor(binding-mcp): extract McpProxyListFactory for tools/list, pr…
claude May 17, 2026
12cb94e
fix(binding-mcp): pre-seed cache for non-hydrating cache.serve ITs
claude May 17, 2026
d0ce2fd
feat(binding-mcp): gate agent lifecycle BEGIN reply on hydrate complete
claude May 17, 2026
0a7231c
feat(binding-mcp): periodic refresh per kind on TTL elapse
claude May 17, 2026
7e2c9fb
feat(binding-mcp): cache hydrate session emits authorized BEGINs to d…
claude May 17, 2026
8d070a8
feat(binding-mcp): putIfAbsent lease coordination for hydrate + refresh
claude May 17, 2026
e4a29cb
refactor(binding-mcp): rename HydrateListStream to McpHydrateListStream
claude May 17, 2026
30a8606
test(engine): share TestStore entries across workers via per-Store map
claude May 17, 2026
6c6073c
Merge branch 'develop' into feature/1737-mcp-cache
claude May 18, 2026
f12b674
refactor(binding-mcp): extract McpCacheHydrater from McpProxyFactory
claude May 18, 2026
07cbaa6
refactor(binding-mcp): per-kind cache hydrater hierarchy
claude May 18, 2026
ced20e3
refactor(binding-mcp): split per-kind subclasses into top-level files
claude May 18, 2026
8f6402b
refactor(binding-mcp): collapse options.cache.ttl to a single Duration
claude May 18, 2026
682cfe1
fix(binding-mcp): reschedule cache refresh when lease lost
claude May 18, 2026
a5fd9a9
refactor(binding-mcp): pass EngineContext to McpBindingConfig
claude May 18, 2026
5b682bb
refactor(binding-mcp): address PR #1774 review batch (phases A–M)
claude May 18, 2026
2025ad5
refactor(binding-mcp): address PR #1774 review batch
claude May 18, 2026
9f51254
feat(engine): add Signaler.signalAt(Instant) overloads
claude May 19, 2026
35f4623
refactor(binding-mcp): address PR #1774 review batch
claude May 19, 2026
b5533f5
test(engine): cover Signaler.signalAt(Instant) default methods
claude May 19, 2026
718a4a6
refactor(binding-mcp): reuse McpAuthorizationConfig under cache
claude May 19, 2026
aa2e680
refactor(binding-mcp): self-target binding for multi-route hydrate
claude May 19, 2026
d41b05b
refactor(binding-mcp): mechanical review cleanups
claude May 19, 2026
c2235f9
refactor(binding-mcp): defer list hydrate END to initial window
claude May 19, 2026
54ec4d2
refactor(engine): remove default modifier on Signaler.signalAt(Instant)
claude May 19, 2026
d76fa00
test(binding-mcp): re-enable seeded-mode cache serve ITs
claude May 19, 2026
f6fc706
test(binding-mcp): drop redundant shouldHydrate IT
claude May 19, 2026
5ceabd3
test(binding-mcp): rename shouldHydratePersist to shouldHydrate
claude May 19, 2026
6f50892
test(binding-mcp): re-author cache hydrate scenarios for self-target
claude May 20, 2026
7e4d257
test(binding-mcp): drop redundant per-kind hydrate scenarios
claude May 20, 2026
ccc22a9
test(binding-mcp): cache hydrate across multiple toolkit routes
claude May 20, 2026
c99665c
test(binding-mcp): pair-up cache.hydrate.toolkit peer-to-peer
claude May 20, 2026
2c3b519
refactor(binding-mcp): consolidate cache state in McpCacheContext
claude May 20, 2026
5d8b180
refactor(binding-mcp): share McpProxyCacheHydrater across bindings
claude May 20, 2026
df3ba2c
refactor(binding-mcp): drop unused McpCacheContext.listCache(kind)
claude May 20, 2026
d1b8685
refactor(binding-mcp): drop unused per-kind cleanup hooks
claude May 20, 2026
7907e66
refactor(binding-mcp): drop hydrater reference from cache context
claude May 20, 2026
da67784
refactor(binding-mcp): move orchestration into cache context
claude May 20, 2026
ca39dbe
refactor(binding-mcp): cancellable signals, deferred work, cascade cl…
claude May 20, 2026
ebed18d
refactor(binding-mcp): cache-populated readiness with backoff poll
claude May 20, 2026
a5f842b
refactor(binding-mcp): review-comment cleanups
claude May 20, 2026
2e4d01a
refactor(binding-mcp): move cache resolution into McpCacheContext ctor
claude May 20, 2026
af5eff2
refactor(binding-mcp): split cache Handler from Manager
claude May 20, 2026
fb29bec
test(binding-mcp): cover stream-error retry and awaiter-during-hydrate
claude May 20, 2026
5f8cbba
refactor(binding-mcp): rename Manager.scheduleKindRetry to scheduleHy…
claude May 20, 2026
1a9755d
refactor(binding-mcp): rename Manager.onHydrateFire to onHydrated
claude May 20, 2026
cb53b7f
refactor(binding-mcp): align timer callback names
claude May 20, 2026
0c7d87a
test(binding-mcp): WIP gap 1 lifecycle-reconnect IT (currently failing)
claude May 20, 2026
f4357ba
fix(binding-mcp): pass through lifecycle terminals end-to-end in proxy
claude May 21, 2026
3d58526
test(binding-mcp): proxy-only lifecycle terminal ITs
claude May 21, 2026
7dea436
test(binding-mcp): cover lifecycle reconnect with refresh-style re-hy…
claude May 21, 2026
3dadfa0
Merge remote-tracking branch 'origin/develop' into claude/mcp-cache-f…
claude May 21, 2026
1e94702
test(binding-mcp): consolidate cache ITs into McpProxyCacheIT / Proxy…
claude May 21, 2026
0a90a29
refactor(binding-mcp): drive cache from list-cache map and consolidat…
claude May 21, 2026
c9c2cf5
refactor(binding-mcp): use Int2ObjectHashMap for cache, reorder scripts
claude May 21, 2026
7839709
refactor(binding-mcp): hold supplyManager Function instead of Factory…
claude May 21, 2026
6e98cdb
test(binding-mcp): cover hydrate and serve at 10k and 100k payloads
claude May 21, 2026
7169de4
refactor(binding-mcp): rename HandlerImpl.lifecycleStream and McpHydr…
claude May 21, 2026
bd3667e
refactor(binding-mcp): make McpProxyItemFactory.sessionId abstract
claude May 21, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import static io.aklivity.zilla.runtime.engine.concurrent.Signaler.NO_CANCEL_ID;
import static java.lang.System.currentTimeMillis;

import java.time.Instant;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.IntConsumer;
Expand Down Expand Up @@ -591,6 +592,15 @@ public long signalAt(
return delegate.signalAt(timeMillis, signalId, handler);
}

@Override
public long signalAt(
Instant time,
int signalId,
IntConsumer handler)
{
return delegate.signalAt(time, signalId, handler);
}

@Override
public void signalNow(
long originId,
Expand Down Expand Up @@ -639,6 +649,19 @@ public long signalAt(
return stream.doStreamSignalAt(traceId, timeMillis, signalId);
}

@Override
public long signalAt(
Instant time,
long originId,
long routedId,
long streamId,
long traceId,
int signalId,
int contextId)
{
return signalAt(time.toEpochMilli(), originId, routedId, streamId, traceId, signalId, contextId);
}

@Override
public long signalTask(
Runnable task,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
public final class McpAuthorizationConfig
{
public final String name;
public final String credentials;

public transient String qname;

Expand All @@ -36,8 +37,10 @@ public static <T> McpAuthorizationConfigBuilder<T> builder(
}

McpAuthorizationConfig(
String name)
String name,
String credentials)
{
this.name = name;
this.credentials = credentials;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public final class McpAuthorizationConfigBuilder<T> extends ConfigBuilder<T, Mcp
private final Function<McpAuthorizationConfig, T> mapper;

private String name;
private String credentials;

McpAuthorizationConfigBuilder(
Function<McpAuthorizationConfig, T> mapper)
Expand All @@ -44,9 +45,16 @@ public McpAuthorizationConfigBuilder<T> name(
return this;
}

public McpAuthorizationConfigBuilder<T> credentials(
String credentials)
{
this.credentials = credentials;
return this;
}

@Override
public T build()
{
return mapper.apply(new McpAuthorizationConfig(name));
return mapper.apply(new McpAuthorizationConfig(name, credentials));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright 2021-2024 Aklivity Inc
*
* Licensed under the Aklivity Community License (the "License"); you may not use
* this file except in compliance with the License. You may obtain a copy of the
* License at
*
* https://www.aklivity.io/aklivity-community-license/
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package io.aklivity.zilla.runtime.binding.mcp.config;

import static java.util.function.Function.identity;

import java.time.Duration;
import java.util.function.Function;

public final class McpCacheConfig
{
public final String store;
public final Duration ttl;
public final McpAuthorizationConfig authorization;

McpCacheConfig(
String store,
Duration ttl,
McpAuthorizationConfig authorization)
{
this.store = store;
this.ttl = ttl;
this.authorization = authorization;
}

public static McpCacheConfigBuilder<McpCacheConfig> builder()
{
return new McpCacheConfigBuilder<>(identity());
}

public static <T> McpCacheConfigBuilder<T> builder(
Function<McpCacheConfig, T> mapper)
{
return new McpCacheConfigBuilder<>(mapper);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* Copyright 2021-2024 Aklivity Inc
*
* Licensed under the Aklivity Community License (the "License"); you may not use
* this file except in compliance with the License. You may obtain a copy of the
* License at
*
* https://www.aklivity.io/aklivity-community-license/
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package io.aklivity.zilla.runtime.binding.mcp.config;

import java.time.Duration;
import java.util.function.Function;

import io.aklivity.zilla.runtime.engine.config.ConfigBuilder;

public final class McpCacheConfigBuilder<T> extends ConfigBuilder<T, McpCacheConfigBuilder<T>>
{
private final Function<McpCacheConfig, T> mapper;

private String store;
private Duration ttl;
private McpAuthorizationConfig authorization;

McpCacheConfigBuilder(
Function<McpCacheConfig, T> mapper)
{
this.mapper = mapper;
}

@Override
@SuppressWarnings("unchecked")
protected Class<McpCacheConfigBuilder<T>> thisType()
{
return (Class<McpCacheConfigBuilder<T>>) getClass();
}

public McpCacheConfigBuilder<T> store(
String store)
{
this.store = store;
return this;
}

public McpCacheConfigBuilder<T> ttl(
Duration ttl)
{
this.ttl = ttl;
return this;
}

public McpCacheConfigBuilder<T> authorization(
McpAuthorizationConfig authorization)
{
this.authorization = authorization;
return this;
}

public McpAuthorizationConfigBuilder<McpCacheConfigBuilder<T>> authorization()
{
return McpAuthorizationConfig.builder(this::authorization);
}

@Override
public T build()
{
return mapper.apply(new McpCacheConfig(store, ttl, authorization));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,18 @@ public final class McpOptionsConfig extends OptionsConfig
public final List<McpPromptConfig> prompts;
public final McpElicitationConfig elicitation;
public final McpAuthorizationConfig authorization;
public final McpCacheConfig cache;

public McpOptionsConfig(
McpOptionsConfig(
List<McpPromptConfig> prompts,
McpElicitationConfig elicitation,
McpAuthorizationConfig authorization)
McpAuthorizationConfig authorization,
McpCacheConfig cache)
{
this.prompts = prompts;
this.elicitation = elicitation;
this.authorization = authorization;
this.cache = cache;
}

public static McpOptionsConfigBuilder<McpOptionsConfig> builder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public final class McpOptionsConfigBuilder<T> extends ConfigBuilder<T, McpOption
private List<McpPromptConfig> prompts;
private McpElicitationConfig elicitation;
private McpAuthorizationConfig authorization;
private McpCacheConfig cache;

public McpOptionsConfigBuilder(
Function<OptionsConfig, T> mapper)
Expand Down Expand Up @@ -71,6 +72,18 @@ public McpAuthorizationConfigBuilder<McpOptionsConfigBuilder<T>> authorization()
return McpAuthorizationConfig.builder(this::authorization);
}

public McpOptionsConfigBuilder<T> cache(
McpCacheConfig cache)
{
this.cache = cache;
return this;
}

public McpCacheConfigBuilder<McpOptionsConfigBuilder<T>> cache()
{
return McpCacheConfig.builder(this::cache);
}

@Override
@SuppressWarnings("unchecked")
protected Class<McpOptionsConfigBuilder<T>> thisType()
Expand All @@ -81,6 +94,6 @@ protected Class<McpOptionsConfigBuilder<T>> thisType()
@Override
public T build()
{
return mapper.apply(new McpOptionsConfig(prompts, elicitation, authorization));
return mapper.apply(new McpOptionsConfig(prompts, elicitation, authorization, cache));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,21 @@
*/
package io.aklivity.zilla.runtime.binding.mcp.internal;

import static io.aklivity.zilla.runtime.binding.mcp.internal.types.stream.McpBeginExFW.KIND_PROMPTS_LIST;
import static io.aklivity.zilla.runtime.binding.mcp.internal.types.stream.McpBeginExFW.KIND_RESOURCES_LIST;
import static io.aklivity.zilla.runtime.binding.mcp.internal.types.stream.McpBeginExFW.KIND_TOOLS_LIST;
import static io.aklivity.zilla.runtime.engine.EngineConfiguration.ENGINE_WORKERS;

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.security.SecureRandom;
import java.time.Duration;
import java.util.HashSet;
import java.util.HexFormat;
import java.util.Set;
import java.util.UUID;
import java.util.function.IntPredicate;
import java.util.function.Supplier;

import org.agrona.LangUtil;
Expand All @@ -46,6 +52,9 @@ public class McpConfiguration extends Configuration
public static final PropertyDef<Duration> MCP_SSE_KEEPALIVE_INTERVAL;
public static final BooleanPropertyDef MCP_ALT_SVC_ENABLED;
public static final PropertyDef<Duration> MCP_ALT_SVC_MAX_AGE;
public static final PropertyDef<IntPredicate> MCP_HYDRATE_FILTER;
public static final PropertyDef<Duration> MCP_LEASE_TTL;
public static final PropertyDef<Duration> MCP_LEASE_RETRY;

static
{
Expand All @@ -72,6 +81,12 @@ public class McpConfiguration extends Configuration
MCP_ALT_SVC_ENABLED = config.property("alt.svc.enabled", McpConfiguration::defaultAltSvcEnabled);
MCP_ALT_SVC_MAX_AGE = config.property(Duration.class, "alt.svc.max.age",
(c, v) -> Duration.parse(v), "PT24H");
MCP_HYDRATE_FILTER = config.property(IntPredicate.class, "hydrate.filter",
McpConfiguration::decodeHydrateFilter, McpConfiguration::defaultHydrateFilter);
MCP_LEASE_TTL = config.property(Duration.class, "lease.ttl",
(c, v) -> Duration.parse(v), "PT30S");
MCP_LEASE_RETRY = config.property(Duration.class, "lease.retry",
(c, v) -> Duration.parse(v), "PT0.1S");
MCP_CONFIG = config;
}

Expand Down Expand Up @@ -146,6 +161,21 @@ public Duration altSvcMaxAge()
return MCP_ALT_SVC_MAX_AGE.get(this);
}

public IntPredicate hydrateFilter()
{
return MCP_HYDRATE_FILTER.get(this);
}

public Duration leaseTtl()
{
return MCP_LEASE_TTL.get(this);
}

public Duration leaseRetry()
{
return MCP_LEASE_RETRY.get(this);
}

@FunctionalInterface
public interface SessionIdSupplier
{
Expand Down Expand Up @@ -258,6 +288,36 @@ private static ElicitationIdSupplier decodeElicitationIdSupplier(
return supplier;
}

private static IntPredicate decodeHydrateFilter(
String value)
{
final Set<Integer> kinds = new HashSet<>();
for (String name : value.split("\\s+"))
{
switch (name)
{
case "tools":
kinds.add(KIND_TOOLS_LIST);
break;
case "resources":
kinds.add(KIND_RESOURCES_LIST);
break;
case "prompts":
kinds.add(KIND_PROMPTS_LIST);
break;
default:
break;
}
}
return kinds::contains;
}

private static boolean defaultHydrateFilter(
int kind)
{
return true;
}

private static String defaultElicitationIdSupplier()
{
final byte[] bytes = new byte[4];
Expand Down
Loading
Loading