Skip to content

Commit adad436

Browse files
committed
feat(mcp-server): add config check mode
1 parent 7f79114 commit adad436

6 files changed

Lines changed: 82 additions & 6 deletions

File tree

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ npx agentdispatch-mcp --config agentdispatch.config.json
2323

2424
The server loads account profiles, SQLite storage, and configured adapters from `agentdispatch.config.json`.
2525

26+
Before wiring it into an MCP client, validate that the stdio server can load config:
27+
28+
```bash
29+
npx agentdispatch-mcp --config agentdispatch.config.json --check
30+
```
31+
2632
Configure `defaults.runtime` for the simple agent path. Agents can then call `spawn_cloud_agent` with only an `instruction`; AgentDispatch resolves provider, account, backend, target mode, framework, and runtime tool defaults from the named runtime profile.
2733

2834
Minimal AWS AgentCore session-mode config:

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@agent-dispatch/mcp-server",
3-
"version": "0.1.1",
3+
"version": "0.1.2",
44
"description": "Provider-neutral MCP server for AgentDispatch.",
55
"type": "module",
66
"license": "Apache-2.0",

src/bin.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
11
#!/usr/bin/env node
22
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3-
import { createRuntimeServiceFromConfigFile } from "./bootstrap.js";
3+
import { createRuntimeCheckReport, createRuntimeServiceFromConfigFile } from "./bootstrap.js";
44
import { createAgentDispatchMcpServer } from "./index.js";
55

66
const configPath = process.argv.includes("--config")
77
? process.argv[process.argv.indexOf("--config") + 1]
88
: undefined;
9+
const checkOnly = process.argv.includes("--check");
910

10-
const transport = new StdioServerTransport();
1111
const runtime = await createRuntimeServiceFromConfigFile({ configPath });
12+
if (checkOnly) {
13+
process.stdout.write(`${JSON.stringify(createRuntimeCheckReport(runtime), null, 2)}\n`);
14+
process.exit(0);
15+
}
16+
17+
const transport = new StdioServerTransport();
1218
const server = createAgentDispatchMcpServer(runtime);
1319
await server.connect(transport);

src/bootstrap.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,28 @@ export async function createRuntimeServiceFromConfigFile(options: RuntimeBootstr
2929
return createRuntimeServiceFromConfig(config, options);
3030
}
3131

32+
export function createRuntimeCheckReport(runtime: RuntimeService) {
33+
return {
34+
ok: true,
35+
providers: runtime.listProviders(),
36+
capabilities: runtime.listCapabilities(),
37+
accounts: runtime.listAccountProfiles().map((account) => ({
38+
name: account.name,
39+
provider: account.provider,
40+
region: account.region,
41+
credentialSource: account.credentialSource
42+
})),
43+
runtimes: runtime.listRuntimeProfiles().map((runtimeProfile) => ({
44+
name: runtimeProfile.name,
45+
provider: runtimeProfile.provider,
46+
account: runtimeProfile.account,
47+
capability: runtimeProfile.capability,
48+
backend: runtimeProfile.backend,
49+
target: runtimeProfile.target
50+
}))
51+
};
52+
}
53+
3254
function createConfiguredAdapters(config: AgentDispatchConfig): BackendAdapter[] {
3355
const adapters: BackendAdapter[] = [];
3456
for (const backend of Object.values(config.backends)) {

test/bootstrap.test.ts

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { join } from "node:path";
33
import { tmpdir } from "node:os";
44
import { afterEach, describe, expect, it } from "vitest";
55
import type { BackendAdapter } from "@agent-dispatch/core";
6-
import { createRuntimeServiceFromConfig, loadAgentDispatchConfig } from "../src/index.js";
6+
import { createRuntimeCheckReport, createRuntimeServiceFromConfig, loadAgentDispatchConfig } from "../src/index.js";
77

88
let stateDir: string | undefined;
99

@@ -69,4 +69,46 @@ describe("MCP bootstrap", () => {
6969

7070
expect(runtime.listProviders()).toEqual(["aws"]);
7171
});
72+
73+
it("creates a safe stdio preflight report", async () => {
74+
stateDir = await mkdtemp(join(tmpdir(), "agentdispatch-mcp-"));
75+
const adapter: BackendAdapter = {
76+
name: "mock",
77+
provider: "aws",
78+
capabilities: () => [{ provider: "aws", capability: "agent-runtime", taskTypes: ["agent.run"], targetModes: ["session"] }],
79+
resolveTarget: async (request) => ({
80+
account: { name: request.accountProfile, provider: request.provider, credentialSource: "test" },
81+
target: { provider: request.provider, accountProfile: request.accountProfile, capability: request.capability, backend: "mock", mode: request.target.mode }
82+
}),
83+
provision: async () => ({}),
84+
startTask: async () => ({ result: { ok: true } }),
85+
streamEvents: async function* () {},
86+
cancel: async () => ({ status: "cancelled" }),
87+
cleanup: async () => ({ status: "skipped" })
88+
};
89+
const runtime = await createRuntimeServiceFromConfig({
90+
stateDir,
91+
accounts: { "dev-aws": { provider: "aws", region: "us-west-2", credentialSource: "aws-sdk-default", details: { secret: "not-returned" } } },
92+
backends: {
93+
mock: { provider: "aws", capability: "agent-runtime", adapter: "mock", account: "dev-aws" }
94+
},
95+
runtimes: {
96+
"research-agent": {
97+
provider: "aws",
98+
account: "dev-aws",
99+
capability: "agent-runtime",
100+
backend: "mock",
101+
target: { mode: "session" }
102+
}
103+
}
104+
}, { adapters: [adapter] });
105+
106+
expect(createRuntimeCheckReport(runtime)).toMatchObject({
107+
ok: true,
108+
providers: ["aws"],
109+
accounts: [{ name: "dev-aws", provider: "aws", region: "us-west-2", credentialSource: "aws-sdk-default" }],
110+
runtimes: [{ name: "research-agent", backend: "mock" }]
111+
});
112+
expect(JSON.stringify(createRuntimeCheckReport(runtime))).not.toContain("not-returned");
113+
});
72114
});

0 commit comments

Comments
 (0)