Skip to content

Commit 56a3a39

Browse files
committed
feat(mcp): per-server code_mode_run_js tool, merging code-mode-v2
Merges code-mode-v2 (#2825) and adds a per-sub-server code_mode_run_js MCP tool that lets an LLM compose multiple operations in one V8-sandboxed JS call instead of N MCP round-trips. The new tool is auto-registered on every MultiServer sub-server that has at least one operation loaded. Each sub-server gets its own sandbox bound to its upstream URL; tools.<name>(vars) dispatches via the existing op catalog (no Yoko, no storage backend, no session state). Reuses the codemode/sandbox, codemode/harness, and codemode/tsgen packages from the merged PR. Description bundled inline includes the typed TS catalog plus shape constraints (single async-arrow root, no top-level await, no IIFE, sandbox console disabled, etc.) so the LLM lands on the right syntax first try. Compile fixes from the merge: - Add EnsureIndexed(ctx) error to yoko.Searcher and *yoko.Client - Rename opsFragment -> newOpsFragment to match call sites/tests - Update fakeYoko test fake with EnsureIndexed counter - Resolve mcpServer field conflict in router_config.go (keep MultiServer type, add codeModeServer alongside)
2 parents 1720a92 + 939da74 commit 56a3a39

343 files changed

Lines changed: 47187 additions & 6466 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ lerna-debug.log
1616
/demo/cmd/subscriptiontest/subscriptiontest
1717
.github/scripts/keycloak-22.0.4/**
1818
.github/scripts/keycloak-22.0.4.zip
19-
/router-tests/cmd/config-validator/router-configs/**
2019

2120
# Go workspace files
2221
go.work
@@ -27,3 +26,7 @@ go.work.sum
2726

2827
# Serena
2928
.serena/
29+
30+
# Local agent / planning artifacts (not for public commits)
31+
.claude/
32+
docs/superpowers/

Makefile

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ generate:
116116
make generate-go
117117

118118
generate-go:
119-
rm -rf router/gen && buf generate --path proto/wg/cosmo/node --path proto/wg/cosmo/common --path proto/wg/cosmo/graphqlmetrics --template buf.router.go.gen.yaml
119+
rm -rf router/gen && buf generate --path proto/wg/cosmo/node --path proto/wg/cosmo/common --path proto/wg/cosmo/graphqlmetrics --path proto/wg/cosmo/code_mode/yoko/v1 --template buf.router.go.gen.yaml
120120
rm -rf graphqlmetrics/gen && buf generate --path proto/wg/cosmo/graphqlmetrics --path proto/wg/cosmo/common --template buf.graphqlmetrics.go.gen.yaml
121121
rm -rf connect-go/wg && buf generate --path proto/wg/cosmo/platform --path proto/wg/cosmo/notifications --path proto/wg/cosmo/common --path proto/wg/cosmo/node --template buf.connect-go.go.gen.yaml
122122

@@ -187,6 +187,45 @@ docker-build-minikube: docker-build-local
187187
run-subgraphs-local:
188188
cd demo && go run cmd/all/main.go
189189

190+
CODE_MODE_GOCACHE ?= /tmp/cosmo-code-mode-go-build-cache
191+
192+
.PHONY: code-mode-demo code-mode-demo-down code-mode-connect-demo code-mode-connect-demo-down
193+
194+
# Local Code Mode demo: small federation (employees, family, availability,
195+
# mood) + Yoko mock + Cosmo Router with Code Mode and named operations.
196+
# Router GraphQL on :3002, MCP on :5027. Full instructions, prerequisites
197+
# (codex CLI on PATH), and tear-down: demo/code-mode/README.md.
198+
code-mode-demo:
199+
mkdir -p $(CODE_MODE_GOCACHE)
200+
GOCACHE=$(CODE_MODE_GOCACHE) $(MAKE) -C router build
201+
GOCACHE=$(CODE_MODE_GOCACHE) $(MAKE) -C demo/code-mode build-yoko
202+
GOCACHE=$(CODE_MODE_GOCACHE) $(MAKE) -C demo/code-mode build-stdio-proxy
203+
$(MAKE) -C demo/code-mode compose
204+
./demo/code-mode/start.sh
205+
206+
# Tear down anything left behind by code-mode-demo.
207+
code-mode-demo-down:
208+
./demo/code-mode/start.sh --down
209+
210+
# Runs the code-mode router from source against the yoko Connect supergraph
211+
# (plugins + composed config live in $(YOKO_DIR)). Uses different ports than
212+
# code-mode-demo (router 3012, MCP 5037, yoko-mock 5038) so both can run at
213+
# the same time. Set YOKO_DIR to your local yoko checkout, e.g.
214+
# `make code-mode-connect-demo YOKO_DIR=/path/to/yoko`.
215+
# Full instructions and prerequisites: demo/code-mode-connect/README.md.
216+
YOKO_DIR ?=
217+
218+
code-mode-connect-demo:
219+
@if [ -z "$(YOKO_DIR)" ]; then echo "YOKO_DIR is required (path to your yoko checkout). See demo/code-mode-connect/README.md" >&2; exit 1; fi
220+
mkdir -p $(CODE_MODE_GOCACHE)
221+
GOCACHE=$(CODE_MODE_GOCACHE) $(MAKE) -C router build
222+
GOCACHE=$(CODE_MODE_GOCACHE) $(MAKE) -C demo/code-mode build-yoko
223+
YOKO_DIR=$(YOKO_DIR) ./demo/code-mode-connect/start.sh
224+
225+
# Tear down anything left behind by code-mode-connect-demo.
226+
code-mode-connect-demo-down:
227+
./demo/code-mode-connect/start.sh --down
228+
190229
sync-go-workspace:
191230
cd router && go mod tidy
192231
cd demo && make bump-deps

cdn-server/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ Binaries are attached to the github release otherwise all images can be found [h
44
All notable changes to this project will be documented in this file.
55
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
66

7+
## [0.20.1](https://github.com/wundergraph/cosmo/compare/cdn@0.20.0...cdn@0.20.1) (2026-05-01)
8+
9+
**Note:** Version bump only for package cdn
10+
711
# [0.20.0](https://github.com/wundergraph/cosmo/compare/cdn@0.19.0...cdn@0.20.0) (2026-04-29)
812

913
### Features

cdn-server/cdn/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ Binaries are attached to the github release otherwise all images can be found [h
44
All notable changes to this project will be documented in this file.
55
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
66

7+
## [0.14.1](https://github.com/wundergraph/cosmo/compare/@wundergraph/cosmo-cdn@0.14.0...@wundergraph/cosmo-cdn@0.14.1) (2026-05-01)
8+
9+
**Note:** Version bump only for package @wundergraph/cosmo-cdn
10+
711
# [0.14.0](https://github.com/wundergraph/cosmo/compare/@wundergraph/cosmo-cdn@0.13.0...@wundergraph/cosmo-cdn@0.14.0) (2026-04-29)
812

913
### Features

cdn-server/cdn/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@wundergraph/cosmo-cdn",
3-
"version": "0.14.0",
3+
"version": "0.14.1",
44
"author": {
55
"name": "WunderGraph Maintainers",
66
"email": "info@wundergraph.com"

cdn-server/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "cdn",
3-
"version": "0.20.0",
3+
"version": "0.20.1",
44
"private": true,
55
"author": {
66
"name": "WunderGraph Maintainers",

cli/.env.example

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ COSMO_API_KEY=cosmo_669b576aaadc10ee1ae81d9193425705
22
COSMO_API_URL=http://localhost:3001
33
CDN_URL=http://localhost:11000
44
PLUGIN_REGISTRY_URL=
5+
DEFAULT_TELEMETRY_ENDPOINT=http://localhost:4318
6+
GRAPHQL_METRICS_COLLECTOR_ENDPOINT=http://localhost:4005
57

68
# configure running wgc behind a proxy
79
# HTTPS_PROXY=""

cli/CHANGELOG.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,24 @@ Binaries are attached to the github release otherwise all images can be found [h
44
All notable changes to this project will be documented in this file.
55
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
66

7+
## [0.117.2](https://github.com/wundergraph/cosmo/compare/wgc@0.117.1...wgc@0.117.2) (2026-05-01)
8+
9+
**Note:** Version bump only for package wgc
10+
11+
## [0.117.1](https://github.com/wundergraph/cosmo/compare/wgc@0.117.0...wgc@0.117.1) (2026-05-01)
12+
13+
**Note:** Version bump only for package wgc
14+
15+
# [0.117.0](https://github.com/wundergraph/cosmo/compare/wgc@0.116.0...wgc@0.117.0) (2026-04-30)
16+
17+
### Bug Fixes
18+
19+
* drop NodeJS 20 support ([#2805](https://github.com/wundergraph/cosmo/issues/2805)) ([7a61b3c](https://github.com/wundergraph/cosmo/commit/7a61b3c1be86566847d2baa39d7b30cd2c0e6d32)) (@comatory)
20+
21+
### Features
22+
23+
* onboarding wizard ([#2790](https://github.com/wundergraph/cosmo/issues/2790)) ([3227519](https://github.com/wundergraph/cosmo/commit/3227519b3cc7b2dbc163856967bfe36cebf81887)) (@comatory)
24+
725
# [0.116.0](https://github.com/wundergraph/cosmo/compare/wgc@0.115.1...wgc@0.116.0) (2026-04-29)
826

927
### Features

cli/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "wgc",
3-
"version": "0.116.0",
3+
"version": "0.117.2",
44
"description": "The official CLI tool to manage the GraphQL Federation Platform Cosmo",
55
"type": "module",
66
"main": "dist/src/index.js",

cli/src/commands/demo/api.ts

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
import { EnumStatusCode } from '@wundergraph/cosmo-connect/dist/common/common_pb';
2+
import type { FederatedGraph, Subgraph } from '@wundergraph/cosmo-connect/dist/platform/v1/platform_pb';
3+
import type { BaseCommandOptions } from '../../core/types/types.js';
4+
import { getBaseHeaders } from '../../core/config.js';
5+
6+
/**
7+
* Retrieve user information [email] and [organization name]
8+
*/
9+
export async function fetchUserInfo(client: BaseCommandOptions['client']) {
10+
try {
11+
const response = await client.platform.whoAmI(
12+
{},
13+
{
14+
headers: getBaseHeaders(),
15+
},
16+
);
17+
18+
switch (response.response?.code) {
19+
case EnumStatusCode.OK: {
20+
return {
21+
userInfo: response,
22+
error: null,
23+
};
24+
}
25+
default: {
26+
return {
27+
userInfo: null,
28+
error: new Error(response.response?.details ?? 'An unknown error occurred.'),
29+
};
30+
}
31+
}
32+
} catch (err) {
33+
return {
34+
userInfo: null,
35+
error: err instanceof Error ? err : new Error('An unknown error occurred.'),
36+
};
37+
}
38+
}
39+
40+
/**
41+
* Retrieve onboarding record. Provides information about allowed [status]:
42+
* [error] | [not-allowed] | [ok]
43+
* If record exists, returns [onboarding] metadata.
44+
*/
45+
export async function checkExistingOnboarding(client: BaseCommandOptions['client']) {
46+
const { response, finishedAt, enabled } = await client.platform.getOnboarding(
47+
{},
48+
{
49+
headers: getBaseHeaders(),
50+
},
51+
);
52+
53+
if (response?.code !== EnumStatusCode.OK) {
54+
return {
55+
error: new Error(response?.details ?? 'Failed to fetch onboarding metadata.'),
56+
status: 'error',
57+
} as const;
58+
}
59+
60+
if (!enabled) {
61+
return {
62+
status: 'not-allowed',
63+
} as const;
64+
}
65+
66+
return {
67+
onboarding: {
68+
finishedAt,
69+
},
70+
status: 'ok',
71+
} as const;
72+
}
73+
74+
/**
75+
* Retrieves federated graph by [name] *demo*. Missing federated graph
76+
* is a valid state.
77+
*/
78+
export async function fetchFederatedGraphByName(
79+
client: BaseCommandOptions['client'],
80+
{ name, namespace }: { name: string; namespace: string },
81+
) {
82+
const { response, graph, subgraphs } = await client.platform.getFederatedGraphByName(
83+
{
84+
name,
85+
namespace,
86+
},
87+
{
88+
headers: getBaseHeaders(),
89+
},
90+
);
91+
92+
switch (response?.code) {
93+
case EnumStatusCode.OK: {
94+
return { data: { graph, subgraphs }, error: null };
95+
}
96+
case EnumStatusCode.ERR_NOT_FOUND: {
97+
return { data: null, error: null };
98+
}
99+
default: {
100+
return {
101+
data: null,
102+
error: new Error(response?.details ?? 'An unknown error occured'),
103+
};
104+
}
105+
}
106+
}
107+
108+
/**
109+
* Cleans up the federated graph by [name] _demo_ and its related
110+
* subgraphs.
111+
*/
112+
export async function cleanUpFederatedGraph(
113+
client: BaseCommandOptions['client'],
114+
graphData: {
115+
graph: FederatedGraph;
116+
subgraphs: Subgraph[];
117+
},
118+
) {
119+
const subgraphDeleteResponses = await Promise.all(
120+
graphData.subgraphs.map(({ name, namespace }) =>
121+
client.platform.deleteFederatedSubgraph(
122+
{
123+
namespace,
124+
subgraphName: name,
125+
disableResolvabilityValidation: false,
126+
},
127+
{
128+
headers: getBaseHeaders(),
129+
},
130+
),
131+
),
132+
);
133+
134+
const failedSubgraphDeleteResponses = subgraphDeleteResponses.filter(
135+
({ response }) => response?.code !== EnumStatusCode.OK,
136+
);
137+
138+
if (failedSubgraphDeleteResponses.length > 0) {
139+
return {
140+
error: new Error(
141+
failedSubgraphDeleteResponses.map(({ response }) => response?.details ?? 'Unknown error occurred.').join('. '),
142+
),
143+
};
144+
}
145+
146+
const federatedGraphDeleteResponse = await client.platform.deleteFederatedGraph(
147+
{
148+
name: graphData.graph.name,
149+
namespace: graphData.graph.namespace,
150+
},
151+
{
152+
headers: getBaseHeaders(),
153+
},
154+
);
155+
156+
switch (federatedGraphDeleteResponse.response?.code) {
157+
case EnumStatusCode.OK: {
158+
return {
159+
error: null,
160+
};
161+
}
162+
default: {
163+
return {
164+
error: new Error(federatedGraphDeleteResponse.response?.details ?? 'Unknown error occurred.'),
165+
};
166+
}
167+
}
168+
}
169+
170+
/**
171+
* Creates federated graph using default [name] and [namespace], with pre-defined
172+
* [labelMatcher] which identify the graph as _demo_.
173+
*/
174+
export async function createFederatedGraph(
175+
client: BaseCommandOptions['client'],
176+
options: {
177+
name: string;
178+
namespace: string;
179+
labelMatcher: string;
180+
routingUrl: URL;
181+
},
182+
) {
183+
const createFedGraphResponse = await client.platform.createFederatedGraph(
184+
{
185+
name: options.name,
186+
namespace: options.namespace,
187+
routingUrl: options.routingUrl.toString(),
188+
labelMatchers: [options.labelMatcher],
189+
},
190+
{
191+
headers: getBaseHeaders(),
192+
},
193+
);
194+
195+
switch (createFedGraphResponse.response?.code) {
196+
case EnumStatusCode.OK: {
197+
return { error: null };
198+
}
199+
default: {
200+
return {
201+
error: new Error(createFedGraphResponse.response?.details ?? 'An unknown error occured'),
202+
};
203+
}
204+
}
205+
}

0 commit comments

Comments
 (0)