11import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js" ;
22import { AgentDispatchError , type DispatchRequest , type RuntimeProfile , type RuntimeService } from "@agent-dispatch/core" ;
3+ import { checkAwsAgentCoreLivePreflight , type AwsAgentCoreLivePreflightCheck , type AwsAgentCoreLivePreflightInput } from "@agent-dispatch/adapter-aws-agentcore" ;
34import packageJson from "../package.json" with { type : "json" } ;
45import { mcpToolSchemas } from "./schemas.js" ;
56
6- export function createAgentDispatchMcpServer ( runtime : RuntimeService ) : McpServer {
7+ export interface AgentDispatchMcpServerOptions {
8+ awsAgentCoreLivePreflight ?: ( input : AwsAgentCoreLivePreflightInput ) => Promise < AwsAgentCoreLivePreflightCheck [ ] > ;
9+ }
10+
11+ export function createAgentDispatchMcpServer ( runtime : RuntimeService , options : AgentDispatchMcpServerOptions = { } ) : McpServer {
712 const server = new McpServer ( { name : "agentdispatch" , version : packageJson . version } ) ;
813
914 server . tool ( "list_providers" , mcpToolSchemas . list_providers . shape , async ( ) => jsonContent ( runtime . listProviders ( ) ) ) ;
@@ -14,6 +19,10 @@ export function createAgentDispatchMcpServer(runtime: RuntimeService): McpServer
1419
1520 server . tool ( "list_account_profiles" , mcpToolSchemas . list_account_profiles . shape , async ( ) => jsonContent ( runtime . listAccountProfiles ( ) ) ) ;
1621
22+ server . tool ( "check_cloud_agent_runtime" , mcpToolSchemas . check_cloud_agent_runtime . shape , async ( input ) => {
23+ return jsonContent ( await createCloudAgentRuntimeCheck ( runtime , input , options ) ) ;
24+ } ) ;
25+
1726 server . tool ( "spawn_cloud_agent" , mcpToolSchemas . spawn_cloud_agent . shape , async ( input ) => {
1827 const clarification = createSpawnClarification ( runtime , input ) ;
1928 if ( clarification ) return jsonContent ( clarification ) ;
@@ -56,6 +65,113 @@ export function createAgentDispatchMcpServer(runtime: RuntimeService): McpServer
5665export * from "./bootstrap.js" ;
5766export * from "./schemas.js" ;
5867
68+ async function createCloudAgentRuntimeCheck ( runtime : RuntimeService , input : {
69+ runtime ?: string ;
70+ provider ?: string ;
71+ account_profile ?: string ;
72+ live ?: boolean ;
73+ runtimeArn ?: string ;
74+ runtime_arn ?: string ;
75+ target ?: { mode ?: string ; protocol ?: string ; details ?: Record < string , unknown > } ;
76+ } , options : AgentDispatchMcpServerOptions ) {
77+ const checks : Array < { name : string ; status : "pass" | "warn" | "fail" ; message : string } > = [ ] ;
78+ const defaults = runtime . getDefaults ( ) ;
79+ const profile = selectRuntimeProfileForCheck ( runtime , input . runtime , input . provider ) ;
80+ if ( ! profile ) {
81+ checks . push ( {
82+ name : "runtime" ,
83+ status : "fail" ,
84+ message : input . runtime
85+ ? `Runtime profile ${ input . runtime } is not configured.`
86+ : "No default runtime profile is configured."
87+ } ) ;
88+ return cloudAgentRuntimeCheckResult ( { checks } ) ;
89+ }
90+
91+ const backend = runtime . getBackend ( profile . backend ) ;
92+ const accountName = input . account_profile ?? profile . account ?? defaults . accountProfile ;
93+ const account = runtime . listAccountProfiles ( ) . find ( ( candidate ) => candidate . name === accountName ) ;
94+ const targetMode = input . target ?. mode ?? profile . target ?. mode ?? defaults . targetMode ?? "session" ;
95+ checks . push ( {
96+ name : "runtime" ,
97+ status : "pass" ,
98+ message : `Runtime ${ profile . name } routes ${ profile . provider } /${ profile . capability } /${ targetMode } through ${ profile . backend } .`
99+ } ) ;
100+
101+ if ( ! backend ) {
102+ checks . push ( {
103+ name : "backend" ,
104+ status : "fail" ,
105+ message : `Runtime ${ profile . name } references missing backend ${ profile . backend } .`
106+ } ) ;
107+ return cloudAgentRuntimeCheckResult ( { profile, account, backend, targetMode, checks } ) ;
108+ }
109+ checks . push ( {
110+ name : "backend" ,
111+ status : "pass" ,
112+ message : `Backend ${ profile . backend } uses adapter ${ backend . adapter } .`
113+ } ) ;
114+
115+ if ( ! account ) {
116+ checks . push ( {
117+ name : "account_profile" ,
118+ status : "fail" ,
119+ message : accountName ? `Account profile ${ accountName } is not configured.` : "No account profile is configured for this runtime."
120+ } ) ;
121+ return cloudAgentRuntimeCheckResult ( { profile, account, backend, targetMode, checks } ) ;
122+ }
123+ checks . push ( {
124+ name : "account_profile" ,
125+ status : "pass" ,
126+ message : `Account profile ${ account . name } uses provider ${ account . provider } .`
127+ } ) ;
128+
129+ if ( input . live !== false && account . provider === "aws" && backend . adapter === "aws-agentcore" ) {
130+ const targetDetails = mergeRecords ( profile . target ?. details , spawnTargetDetails ( input ) , input . target ?. details ) ?? { } ;
131+ const preflight = options . awsAgentCoreLivePreflight ?? checkAwsAgentCoreLivePreflight ;
132+ checks . push ( ...await preflight ( {
133+ runtimeName : profile . name ,
134+ region : account . region ?? String ( backend . details ?. region ?? process . env . AWS_REGION ?? "us-east-1" ) ,
135+ mode : targetMode ,
136+ runtimeArn : stringValue ( targetDetails . runtimeArn ) ?? stringValue ( backend . details ?. runtimeArn ) ?? process . env . AGENTDISPATCH_AGENTCORE_RUNTIME_ARN
137+ } ) ) ;
138+ } else if ( input . live !== false ) {
139+ checks . push ( {
140+ name : "live" ,
141+ status : "warn" ,
142+ message : `Live preflight is not implemented for ${ account . provider } /${ backend . adapter } .`
143+ } ) ;
144+ }
145+
146+ return cloudAgentRuntimeCheckResult ( { profile, account, backend, targetMode, checks } ) ;
147+ }
148+
149+ function cloudAgentRuntimeCheckResult ( input : {
150+ profile ?: RuntimeProfile ;
151+ account ?: { name : string ; provider : string ; region ?: string ; credentialSource : string } ;
152+ backend ?: { adapter : string } ;
153+ targetMode ?: string ;
154+ checks : Array < { name : string ; status : "pass" | "warn" | "fail" ; message : string } > ;
155+ } ) {
156+ return {
157+ ok : input . checks . every ( ( check ) => check . status !== "fail" ) ,
158+ runtime : input . profile ?. name ,
159+ provider : input . account ?. provider ?? input . profile ?. provider ,
160+ account_profile : input . account ?. name ?? input . profile ?. account ,
161+ backend : input . profile ?. backend ,
162+ adapter : input . backend ?. adapter ,
163+ target_mode : input . targetMode ,
164+ checks : input . checks
165+ } ;
166+ }
167+
168+ function selectRuntimeProfileForCheck ( runtime : RuntimeService , runtimeName ?: string , provider ?: string ) : RuntimeProfile | undefined {
169+ if ( runtimeName ) return runtime . getRuntimeProfile ( runtimeName ) ;
170+ const defaultProfile = runtime . getDefaultRuntimeProfile ( ) ;
171+ if ( defaultProfile && ( ! provider || defaultProfile . provider === provider ) ) return defaultProfile ;
172+ return runtime . listRuntimeProfiles ( ) . find ( ( profile ) => ! provider || profile . provider === provider ) ;
173+ }
174+
59175function createSpawnCloudAgentRequest ( runtime : RuntimeService , input : {
60176 instruction ?: string ;
61177 runtime ?: string ;
@@ -293,6 +409,10 @@ function stringRecord(key: string, value: unknown): Record<string, unknown> | un
293409 return typeof value === "string" && value . length > 0 ? { [ key ] : value } : undefined ;
294410}
295411
412+ function stringValue ( value : unknown ) : string | undefined {
413+ return typeof value === "string" && value . length > 0 ? value : undefined ;
414+ }
415+
296416function recordRecord ( key : string , value : unknown ) : Record < string , unknown > | undefined {
297417 return value && typeof value === "object" && ! Array . isArray ( value ) ? { [ key ] : value } : undefined ;
298418}
0 commit comments