@slashfi/agents-sdk 0.30.1 → 0.31.0-pr.dev.4fd2a3c
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.
- package/dist/call-agent-schema.d.ts +155 -0
- package/dist/call-agent-schema.d.ts.map +1 -1
- package/dist/call-agent-schema.js +13 -0
- package/dist/call-agent-schema.js.map +1 -1
- package/dist/cjs/call-agent-schema.js +14 -1
- package/dist/cjs/call-agent-schema.js.map +1 -1
- package/dist/cjs/define-config.js +1 -0
- package/dist/cjs/define-config.js.map +1 -1
- package/dist/cjs/index.js +3 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/registry-consumer.js +110 -33
- package/dist/cjs/registry-consumer.js.map +1 -1
- package/dist/cjs/registry.js +35 -0
- package/dist/cjs/registry.js.map +1 -1
- package/dist/cjs/server.js +31 -12
- package/dist/cjs/server.js.map +1 -1
- package/dist/define-config.d.ts +4 -0
- package/dist/define-config.d.ts.map +1 -1
- package/dist/define-config.js +1 -0
- package/dist/define-config.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/registry-consumer.d.ts +13 -0
- package/dist/registry-consumer.d.ts.map +1 -1
- package/dist/registry-consumer.js +110 -33
- package/dist/registry-consumer.js.map +1 -1
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +35 -0
- package/dist/registry.js.map +1 -1
- package/dist/server.d.ts +22 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +31 -12
- package/dist/server.js.map +1 -1
- package/dist/types.d.ts +53 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/call-agent-schema.ts +21 -0
- package/src/codegen.test.ts +10 -0
- package/src/consumer.test.ts +132 -0
- package/src/define-config.ts +6 -0
- package/src/index.ts +6 -0
- package/src/registry-consumer.ts +155 -34
- package/src/registry.ts +39 -0
- package/src/server.ts +56 -12
- package/src/types.ts +59 -0
package/src/registry-consumer.ts
CHANGED
|
@@ -37,6 +37,8 @@ import type {
|
|
|
37
37
|
ResolvedRef,
|
|
38
38
|
ResolvedRegistry,
|
|
39
39
|
} from "./define-config.js";
|
|
40
|
+
import type { CallAgentRequest } from "./call-agent-schema.js";
|
|
41
|
+
import type { SecuritySchemeSummary } from "./types.js";
|
|
40
42
|
import {
|
|
41
43
|
isSecretUri,
|
|
42
44
|
normalizeRef,
|
|
@@ -121,6 +123,60 @@ async function resolveTemplates<T>(
|
|
|
121
123
|
return obj;
|
|
122
124
|
}
|
|
123
125
|
|
|
126
|
+
// ============================================
|
|
127
|
+
// Registry Auth Headers
|
|
128
|
+
// ============================================
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Build auth headers for a registry based on its auth config and custom headers.
|
|
132
|
+
* Merges typed auth (bearer, api-key) with arbitrary custom headers.
|
|
133
|
+
*/
|
|
134
|
+
function buildRegistryAuthHeaders(
|
|
135
|
+
registry: ResolvedRegistry,
|
|
136
|
+
fallbackToken?: string,
|
|
137
|
+
): Record<string, string> {
|
|
138
|
+
const headers: Record<string, string> = {};
|
|
139
|
+
|
|
140
|
+
// Apply typed auth
|
|
141
|
+
switch (registry.auth.type) {
|
|
142
|
+
case "bearer": {
|
|
143
|
+
const token = ("token" in registry.auth ? registry.auth.token : undefined) ?? fallbackToken;
|
|
144
|
+
if (token) {
|
|
145
|
+
headers.Authorization = `Bearer ${token}`;
|
|
146
|
+
}
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
case "api-key": {
|
|
150
|
+
if ("key" in registry.auth && registry.auth.key) {
|
|
151
|
+
const headerName = ("header" in registry.auth ? registry.auth.header : undefined) ?? "x-api-key";
|
|
152
|
+
headers[headerName] = registry.auth.key;
|
|
153
|
+
}
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
case "jwt": {
|
|
157
|
+
// JWT auth would require token exchange — not yet implemented
|
|
158
|
+
if (fallbackToken) {
|
|
159
|
+
headers.Authorization = `Bearer ${fallbackToken}`;
|
|
160
|
+
}
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
case "none":
|
|
164
|
+
default: {
|
|
165
|
+
if (fallbackToken) {
|
|
166
|
+
headers.Authorization = `Bearer ${fallbackToken}`;
|
|
167
|
+
}
|
|
168
|
+
break;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Merge custom headers (these override auth-generated headers)
|
|
173
|
+
if (registry.headers) {
|
|
174
|
+
Object.assign(headers, registry.headers);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return headers;
|
|
178
|
+
}
|
|
179
|
+
|
|
124
180
|
// ============================================
|
|
125
181
|
// Registry Discovery Types
|
|
126
182
|
// ============================================
|
|
@@ -152,6 +208,14 @@ export interface AgentListing {
|
|
|
152
208
|
}>;
|
|
153
209
|
/** Whether it requires auth */
|
|
154
210
|
requiresAuth?: boolean;
|
|
211
|
+
/** Security scheme summary (machine-readable auth type) */
|
|
212
|
+
security?: SecuritySchemeSummary;
|
|
213
|
+
/** Available resources (e.g., AUTH.md) */
|
|
214
|
+
resources?: Array<{
|
|
215
|
+
uri: string;
|
|
216
|
+
name?: string;
|
|
217
|
+
mimeType?: string;
|
|
218
|
+
}>;
|
|
155
219
|
/** Integration config if applicable */
|
|
156
220
|
integration?: {
|
|
157
221
|
provider: string;
|
|
@@ -441,6 +505,15 @@ export interface RegistryConsumer {
|
|
|
441
505
|
/** Discover a registry's configuration */
|
|
442
506
|
discover(registryUrl: string): Promise<RegistryConfiguration>;
|
|
443
507
|
|
|
508
|
+
/** Browse agents from a specific registry (or all if url omitted) */
|
|
509
|
+
browse(registryUrl?: string): Promise<AgentListing[]>;
|
|
510
|
+
|
|
511
|
+
/** Inspect a specific agent — returns tools, auth requirements, resources */
|
|
512
|
+
inspect(
|
|
513
|
+
agentPath: string,
|
|
514
|
+
registryUrl?: string,
|
|
515
|
+
): Promise<AgentListing | null>;
|
|
516
|
+
|
|
444
517
|
/** Resolve a secret URL to its value */
|
|
445
518
|
resolveSecret(url: string): Promise<string>;
|
|
446
519
|
|
|
@@ -481,12 +554,15 @@ export async function createRegistryConsumer(
|
|
|
481
554
|
const discoveryCache = new Map<string, RegistryConfiguration>();
|
|
482
555
|
|
|
483
556
|
// Discover a registry
|
|
484
|
-
async function discover(registryUrl: string): Promise<RegistryConfiguration> {
|
|
557
|
+
async function discover(registryUrl: string, registry?: ResolvedRegistry): Promise<RegistryConfiguration> {
|
|
485
558
|
const cached = discoveryCache.get(registryUrl);
|
|
486
559
|
if (cached) return cached;
|
|
487
560
|
|
|
488
561
|
const url = `${registryUrl.replace(/\/$/, "")}/.well-known/configuration`;
|
|
489
|
-
const
|
|
562
|
+
const headers: Record<string, string> = registry
|
|
563
|
+
? buildRegistryAuthHeaders(registry, options.token)
|
|
564
|
+
: (options.token ? { Authorization: `Bearer ${options.token}` } : {});
|
|
565
|
+
const res = await fetchFn(url, { headers });
|
|
490
566
|
if (!res.ok) {
|
|
491
567
|
throw new Error(
|
|
492
568
|
`Failed to discover registry ${registryUrl}: ${res.status}`,
|
|
@@ -501,17 +577,12 @@ export async function createRegistryConsumer(
|
|
|
501
577
|
async function listFromRegistry(
|
|
502
578
|
registry: ResolvedRegistry,
|
|
503
579
|
): Promise<AgentListing[]> {
|
|
504
|
-
const configuration = await discover(registry.url);
|
|
580
|
+
const configuration = await discover(registry.url, registry);
|
|
505
581
|
const listUrl =
|
|
506
582
|
configuration.agents_endpoint ??
|
|
507
583
|
`${registry.url.replace(/\/$/, "")}/list`;
|
|
508
584
|
|
|
509
|
-
const headers
|
|
510
|
-
if (registry.auth.type === "bearer" && "token" in registry.auth) {
|
|
511
|
-
headers.Authorization = `Bearer ${registry.auth.token}`;
|
|
512
|
-
} else if (options.token) {
|
|
513
|
-
headers.Authorization = `Bearer ${options.token}`;
|
|
514
|
-
}
|
|
585
|
+
const headers = buildRegistryAuthHeaders(registry, options.token);
|
|
515
586
|
|
|
516
587
|
const res = await fetchFn(listUrl, { headers });
|
|
517
588
|
if (!res.ok) {
|
|
@@ -537,26 +608,19 @@ export async function createRegistryConsumer(
|
|
|
537
608
|
}));
|
|
538
609
|
}
|
|
539
610
|
|
|
540
|
-
//
|
|
541
|
-
async function
|
|
611
|
+
// Send any call_agent request through a registry's MCP endpoint
|
|
612
|
+
async function callRegistry(
|
|
542
613
|
registry: ResolvedRegistry,
|
|
543
|
-
|
|
544
|
-
tool: string,
|
|
545
|
-
params: Record<string, unknown>,
|
|
614
|
+
request: CallAgentRequest,
|
|
546
615
|
): Promise<unknown> {
|
|
547
|
-
const configuration = await discover(registry.url);
|
|
548
|
-
// MCP endpoint is the base URL (POST /), not /call
|
|
616
|
+
const configuration = await discover(registry.url, registry);
|
|
549
617
|
const mcpUrl =
|
|
550
618
|
configuration.call_endpoint ?? registry.url.replace(/\/$/, "");
|
|
551
619
|
|
|
552
620
|
const headers: Record<string, string> = {
|
|
553
621
|
"Content-Type": "application/json",
|
|
622
|
+
...buildRegistryAuthHeaders(registry, options.token),
|
|
554
623
|
};
|
|
555
|
-
if (registry.auth.type === "bearer" && "token" in registry.auth) {
|
|
556
|
-
headers.Authorization = `Bearer ${registry.auth.token}`;
|
|
557
|
-
} else if (options.token) {
|
|
558
|
-
headers.Authorization = `Bearer ${options.token}`;
|
|
559
|
-
}
|
|
560
624
|
|
|
561
625
|
const requestId = `call-${Date.now()}`;
|
|
562
626
|
const res = await fetchFn(mcpUrl, {
|
|
@@ -568,14 +632,7 @@ export async function createRegistryConsumer(
|
|
|
568
632
|
method: "tools/call",
|
|
569
633
|
params: {
|
|
570
634
|
name: "call_agent",
|
|
571
|
-
arguments: {
|
|
572
|
-
request: {
|
|
573
|
-
action: "execute_tool",
|
|
574
|
-
path: agentPath,
|
|
575
|
-
tool,
|
|
576
|
-
params,
|
|
577
|
-
},
|
|
578
|
-
},
|
|
635
|
+
arguments: { request },
|
|
579
636
|
},
|
|
580
637
|
}),
|
|
581
638
|
});
|
|
@@ -583,7 +640,7 @@ export async function createRegistryConsumer(
|
|
|
583
640
|
if (!res.ok) {
|
|
584
641
|
const text = await res.text().catch(() => "unknown error");
|
|
585
642
|
throw new Error(
|
|
586
|
-
`
|
|
643
|
+
`Registry call failed (${registry.url}): ${res.status} ${text}`,
|
|
587
644
|
);
|
|
588
645
|
}
|
|
589
646
|
|
|
@@ -599,7 +656,7 @@ export async function createRegistryConsumer(
|
|
|
599
656
|
|
|
600
657
|
if (rpcResponse.error) {
|
|
601
658
|
throw new Error(
|
|
602
|
-
`
|
|
659
|
+
`Registry RPC error: ${rpcResponse.error.message}`,
|
|
603
660
|
);
|
|
604
661
|
}
|
|
605
662
|
|
|
@@ -607,10 +664,10 @@ export async function createRegistryConsumer(
|
|
|
607
664
|
if (mcpResult?.isError) {
|
|
608
665
|
const errorText =
|
|
609
666
|
mcpResult.content?.map((c) => c.text).join("\n") ?? "Unknown error";
|
|
610
|
-
throw new Error(`
|
|
667
|
+
throw new Error(`Registry call error: ${errorText}`);
|
|
611
668
|
}
|
|
612
669
|
|
|
613
|
-
// Parse text content
|
|
670
|
+
// Parse text content
|
|
614
671
|
const textContent = mcpResult?.content?.find((c) => c.type === "text");
|
|
615
672
|
if (textContent?.text) {
|
|
616
673
|
try {
|
|
@@ -623,6 +680,21 @@ export async function createRegistryConsumer(
|
|
|
623
680
|
return mcpResult;
|
|
624
681
|
}
|
|
625
682
|
|
|
683
|
+
// Call a tool via a registry (convenience wrapper)
|
|
684
|
+
async function callTool(
|
|
685
|
+
registry: ResolvedRegistry,
|
|
686
|
+
agentPath: string,
|
|
687
|
+
tool: string,
|
|
688
|
+
params: Record<string, unknown>,
|
|
689
|
+
): Promise<unknown> {
|
|
690
|
+
return callRegistry(registry, {
|
|
691
|
+
action: "execute_tool",
|
|
692
|
+
path: agentPath,
|
|
693
|
+
tool,
|
|
694
|
+
params,
|
|
695
|
+
});
|
|
696
|
+
}
|
|
697
|
+
|
|
626
698
|
// Build the consumer
|
|
627
699
|
const consumer: RegistryConsumer = {
|
|
628
700
|
async list(): Promise<AgentListing[]> {
|
|
@@ -721,7 +793,56 @@ export async function createRegistryConsumer(
|
|
|
721
793
|
return callTool(registry, ref.ref, tool, params);
|
|
722
794
|
},
|
|
723
795
|
|
|
724
|
-
discover
|
|
796
|
+
discover(registryUrl: string) {
|
|
797
|
+
// Find matching resolved registry for auth headers
|
|
798
|
+
const registry = resolvedRegistries.find((r) => r.url === registryUrl);
|
|
799
|
+
return discover(registryUrl, registry);
|
|
800
|
+
},
|
|
801
|
+
|
|
802
|
+
async browse(registryUrl?: string): Promise<AgentListing[]> {
|
|
803
|
+
// List agents from a specific registry, or all registries if not specified
|
|
804
|
+
const targets = registryUrl
|
|
805
|
+
? resolvedRegistries.filter(
|
|
806
|
+
(r) => r.url === registryUrl || r.name === registryUrl,
|
|
807
|
+
)
|
|
808
|
+
: resolvedRegistries;
|
|
809
|
+
const results = await Promise.allSettled(targets.map(listFromRegistry));
|
|
810
|
+
return results.flatMap((r) =>
|
|
811
|
+
r.status === "fulfilled" ? r.value : [],
|
|
812
|
+
);
|
|
813
|
+
},
|
|
814
|
+
|
|
815
|
+
async inspect(
|
|
816
|
+
agentPath: string,
|
|
817
|
+
registryUrl?: string,
|
|
818
|
+
): Promise<AgentListing | null> {
|
|
819
|
+
const targetRegistries = registryUrl
|
|
820
|
+
? resolvedRegistries.filter((r) => r.url === registryUrl || r.name === registryUrl)
|
|
821
|
+
: resolvedRegistries;
|
|
822
|
+
|
|
823
|
+
// Parallel O(1) lookups via describe_tools
|
|
824
|
+
const results = await Promise.allSettled(
|
|
825
|
+
targetRegistries.map(async (registry) => {
|
|
826
|
+
const data = (await callRegistry(registry, {
|
|
827
|
+
action: "describe_tools",
|
|
828
|
+
path: agentPath,
|
|
829
|
+
tools: [],
|
|
830
|
+
})) as { tools?: unknown[]; description?: string } | null;
|
|
831
|
+
if (!data) return null;
|
|
832
|
+
return {
|
|
833
|
+
path: agentPath,
|
|
834
|
+
publisher: registry.publisher,
|
|
835
|
+
tools: data.tools,
|
|
836
|
+
description: data.description,
|
|
837
|
+
} as AgentListing;
|
|
838
|
+
}),
|
|
839
|
+
);
|
|
840
|
+
|
|
841
|
+
for (const r of results) {
|
|
842
|
+
if (r.status === "fulfilled" && r.value) return r.value;
|
|
843
|
+
}
|
|
844
|
+
return null;
|
|
845
|
+
},
|
|
725
846
|
|
|
726
847
|
async resolveSecret(url: string): Promise<string> {
|
|
727
848
|
return resolveSecretFn(url, { token: options.token });
|
package/src/registry.ts
CHANGED
|
@@ -17,6 +17,8 @@ import type {
|
|
|
17
17
|
CallAgentExecuteToolResponse,
|
|
18
18
|
CallAgentLoadRequest,
|
|
19
19
|
CallAgentLoadResponse,
|
|
20
|
+
CallAgentListResourcesResponse,
|
|
21
|
+
CallAgentReadResourcesResponse,
|
|
20
22
|
CallAgentRequest,
|
|
21
23
|
CallAgentResponse,
|
|
22
24
|
ToolContext,
|
|
@@ -31,6 +33,8 @@ const DEFAULT_SUPPORTED_ACTIONS: AgentAction[] = [
|
|
|
31
33
|
"execute_tool",
|
|
32
34
|
"describe_tools",
|
|
33
35
|
"load",
|
|
36
|
+
"list_resources",
|
|
37
|
+
"read_resources",
|
|
34
38
|
];
|
|
35
39
|
|
|
36
40
|
// ============================================
|
|
@@ -729,6 +733,41 @@ export function createAgentRegistry(
|
|
|
729
733
|
return defaultLoad(agent, request);
|
|
730
734
|
}
|
|
731
735
|
|
|
736
|
+
case "list_resources": {
|
|
737
|
+
const resources = (agent.config?.resources ?? []).map((r) => ({
|
|
738
|
+
uri: r.uri,
|
|
739
|
+
name: r.name,
|
|
740
|
+
mimeType: r.mimeType,
|
|
741
|
+
}));
|
|
742
|
+
return {
|
|
743
|
+
success: true,
|
|
744
|
+
agentPath: agent.path,
|
|
745
|
+
resources,
|
|
746
|
+
} as CallAgentListResourcesResponse;
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
case "read_resources": {
|
|
750
|
+
const uris = request.uris;
|
|
751
|
+
const agentResources = agent.config?.resources ?? [];
|
|
752
|
+
const results = uris.map((uri) => {
|
|
753
|
+
const resource = agentResources.find((r) => r.uri === uri);
|
|
754
|
+
if (!resource) {
|
|
755
|
+
return { uri, error: `Resource not found: ${uri}` };
|
|
756
|
+
}
|
|
757
|
+
return {
|
|
758
|
+
uri: resource.uri,
|
|
759
|
+
name: resource.name,
|
|
760
|
+
mimeType: resource.mimeType,
|
|
761
|
+
content: resource.content,
|
|
762
|
+
};
|
|
763
|
+
});
|
|
764
|
+
return {
|
|
765
|
+
success: true,
|
|
766
|
+
agentPath: agent.path,
|
|
767
|
+
resources: results,
|
|
768
|
+
} as CallAgentReadResourcesResponse;
|
|
769
|
+
}
|
|
770
|
+
|
|
732
771
|
default: {
|
|
733
772
|
// TypeScript exhaustiveness check
|
|
734
773
|
const _exhaustive: never = request;
|
package/src/server.ts
CHANGED
|
@@ -120,6 +120,28 @@ export interface AgentServerOptions {
|
|
|
120
120
|
keyStore?: import("./key-manager.js").KeyStore;
|
|
121
121
|
/** OIDC provider for user sign-in (authorization code flow) */
|
|
122
122
|
oidcProvider?: OIDCProviderConfig;
|
|
123
|
+
/**
|
|
124
|
+
* Custom auth resolver — called before the built-in JWT/header auth.
|
|
125
|
+
* Return a ResolvedAuth to authenticate the request, or null to fall
|
|
126
|
+
* through to the default auth chain.
|
|
127
|
+
*
|
|
128
|
+
* Use this when the server is mounted behind a proxy or middleware
|
|
129
|
+
* that handles its own auth (e.g., API key validation).
|
|
130
|
+
*
|
|
131
|
+
* @example
|
|
132
|
+
* ```typescript
|
|
133
|
+
* createAgentServer(registry, {
|
|
134
|
+
* resolveAuth: async (req) => {
|
|
135
|
+
* const apiKey = req.headers.get('x-api-key');
|
|
136
|
+
* if (apiKey === process.env.API_KEY) {
|
|
137
|
+
* return { callerId: 'api-client', callerType: 'system', scopes: ['*'], claims: {} };
|
|
138
|
+
* }
|
|
139
|
+
* return null;
|
|
140
|
+
* },
|
|
141
|
+
* });
|
|
142
|
+
* ```
|
|
143
|
+
*/
|
|
144
|
+
resolveAuth?: (req: Request) => Promise<ResolvedAuth | null>;
|
|
123
145
|
/**
|
|
124
146
|
* Registry capabilities — advertised in MCP initialize response.
|
|
125
147
|
* When set, this server identifies as an agent registry (superset of MCP).
|
|
@@ -454,7 +476,7 @@ function getToolDefinitions() {
|
|
|
454
476
|
{
|
|
455
477
|
name: "call_agent",
|
|
456
478
|
description:
|
|
457
|
-
"Execute a tool on a registered agent. Provide the agent path and tool name.",
|
|
479
|
+
"Execute a tool on a registered agent. Provide the agent path and tool name.\n\nSupported actions:\n- invoke: Fire-and-forget agent invocation\n- ask: Invoke and wait for response\n- execute_tool: Call a specific tool on an agent\n- describe_tools: Get tool schemas for an agent\n- load: Get agent definition/system prompt\n- list_resources: List all resources available on an agent (docs, auth instructions, config schemas, etc.)\n- read_resources: Fetch one or more resources by URI",
|
|
458
480
|
inputSchema: callAgentInputSchema,
|
|
459
481
|
},
|
|
460
482
|
{
|
|
@@ -647,6 +669,14 @@ export function createAgentServer(
|
|
|
647
669
|
description: agent.config?.description,
|
|
648
670
|
supportedActions: agent.config?.supportedActions,
|
|
649
671
|
integration: agent.config?.integration || null,
|
|
672
|
+
security: agent.config?.security
|
|
673
|
+
? { type: agent.config.security.type }
|
|
674
|
+
: undefined,
|
|
675
|
+
resources: agent.config?.resources?.map((r) => ({
|
|
676
|
+
uri: r.uri,
|
|
677
|
+
name: r.name,
|
|
678
|
+
mimeType: r.mimeType,
|
|
679
|
+
})),
|
|
650
680
|
tools: agent.tools
|
|
651
681
|
.filter((t) => {
|
|
652
682
|
const tv = t.visibility ?? "internal";
|
|
@@ -1024,11 +1054,16 @@ export function createAgentServer(
|
|
|
1024
1054
|
return new Response(null, { status: 204, headers: corsHeaders() });
|
|
1025
1055
|
}
|
|
1026
1056
|
|
|
1027
|
-
// Resolve auth
|
|
1028
|
-
const
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1057
|
+
// Resolve auth: custom resolver first, then built-in JWT/header chain
|
|
1058
|
+
const customAuth = options.resolveAuth
|
|
1059
|
+
? await options.resolveAuth(req)
|
|
1060
|
+
: null;
|
|
1061
|
+
const auth =
|
|
1062
|
+
customAuth ??
|
|
1063
|
+
(await resolveAuth(req, authConfig, {
|
|
1064
|
+
signingKeys: serverSigningKeys,
|
|
1065
|
+
trustedIssuers: configTrustedIssuers,
|
|
1066
|
+
}));
|
|
1032
1067
|
|
|
1033
1068
|
// Also check header-based identity (for proxied requests)
|
|
1034
1069
|
const headerAuth: ResolvedAuth | null = !auth
|
|
@@ -1231,9 +1266,12 @@ export function createAgentServer(
|
|
|
1231
1266
|
// Public registries (e.g. registry.slash.com) skip this entirely.
|
|
1232
1267
|
if (
|
|
1233
1268
|
path === "/.well-known/oauth-authorization-server" &&
|
|
1234
|
-
req.method === "GET"
|
|
1235
|
-
(options.registry?.oauthCallbackUrl || serverSigningKeys.length > 0)
|
|
1269
|
+
req.method === "GET"
|
|
1236
1270
|
) {
|
|
1271
|
+
if (!(options.registry?.oauthCallbackUrl || serverSigningKeys.length > 0)) {
|
|
1272
|
+
const res = new Response("Not Found", { status: 404 });
|
|
1273
|
+
return cors ? addCors(res) : res;
|
|
1274
|
+
}
|
|
1237
1275
|
const baseUrl = resolveBaseUrl(req);
|
|
1238
1276
|
const res = jsonResponse({
|
|
1239
1277
|
issuer: baseUrl,
|
|
@@ -1581,10 +1619,16 @@ export function createAgentServer(
|
|
|
1581
1619
|
},
|
|
1582
1620
|
|
|
1583
1621
|
async resolveAuth(req: Request): Promise<ResolvedAuth | null> {
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1622
|
+
const customAuth = options.resolveAuth
|
|
1623
|
+
? await options.resolveAuth(req)
|
|
1624
|
+
: null;
|
|
1625
|
+
return (
|
|
1626
|
+
customAuth ??
|
|
1627
|
+
resolveAuth(req, authConfig, {
|
|
1628
|
+
signingKeys: serverSigningKeys,
|
|
1629
|
+
trustedIssuers: configTrustedIssuers,
|
|
1630
|
+
})
|
|
1631
|
+
);
|
|
1588
1632
|
},
|
|
1589
1633
|
|
|
1590
1634
|
addTrustedIssuer(issuerUrl: string, scopes?: string[]): void {
|
package/src/types.ts
CHANGED
|
@@ -259,6 +259,32 @@ export type SecurityScheme =
|
|
|
259
259
|
| HttpSecurityScheme
|
|
260
260
|
| NoneSecurityScheme;
|
|
261
261
|
|
|
262
|
+
/**
|
|
263
|
+
* Lightweight security summary for agent listings.
|
|
264
|
+
* The full SecurityScheme has all the details; this is the
|
|
265
|
+
* directory-level overview (e.g., in list_agents responses).
|
|
266
|
+
*/
|
|
267
|
+
export interface SecuritySchemeSummary {
|
|
268
|
+
type: SecurityScheme['type'];
|
|
269
|
+
[key: string]: unknown;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* A static resource exposed by an agent.
|
|
274
|
+
* Well-known resources:
|
|
275
|
+
* - `AUTH.md` — LLM-readable auth/connection setup instructions
|
|
276
|
+
*/
|
|
277
|
+
export interface AgentResource {
|
|
278
|
+
/** Resource URI (e.g., 'AUTH.md') */
|
|
279
|
+
uri: string;
|
|
280
|
+
/** Human-readable name */
|
|
281
|
+
name?: string;
|
|
282
|
+
/** MIME type (defaults to text/markdown for .md) */
|
|
283
|
+
mimeType?: string;
|
|
284
|
+
/** The resource content (populated on read_resources, omitted on list) */
|
|
285
|
+
content?: string;
|
|
286
|
+
}
|
|
287
|
+
|
|
262
288
|
// ============================================
|
|
263
289
|
// Agent Configuration
|
|
264
290
|
// ============================================
|
|
@@ -313,6 +339,13 @@ export interface AgentConfig {
|
|
|
313
339
|
*/
|
|
314
340
|
security?: SecurityScheme;
|
|
315
341
|
|
|
342
|
+
/**
|
|
343
|
+
* Agent resources — static files/documents the agent exposes.
|
|
344
|
+
* Well-known resources:
|
|
345
|
+
* - `AUTH.md` — LLM-readable auth setup instructions
|
|
346
|
+
*/
|
|
347
|
+
resources?: AgentResource[];
|
|
348
|
+
|
|
316
349
|
/** Additional configuration */
|
|
317
350
|
/** Agent refs (paths to other agents this agent can call) */
|
|
318
351
|
refs?: Record<string, { description?: string }>;
|
|
@@ -747,6 +780,30 @@ export interface CallAgentCallbackResponse {
|
|
|
747
780
|
callbackId: string;
|
|
748
781
|
}
|
|
749
782
|
|
|
783
|
+
/** List resources response */
|
|
784
|
+
export interface CallAgentListResourcesResponse {
|
|
785
|
+
success: true;
|
|
786
|
+
agentPath: string;
|
|
787
|
+
resources: Array<{
|
|
788
|
+
uri: string;
|
|
789
|
+
name?: string;
|
|
790
|
+
mimeType?: string;
|
|
791
|
+
}>;
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
/** Read resources response */
|
|
795
|
+
export interface CallAgentReadResourcesResponse {
|
|
796
|
+
success: true;
|
|
797
|
+
agentPath: string;
|
|
798
|
+
resources: Array<{
|
|
799
|
+
uri: string;
|
|
800
|
+
name?: string;
|
|
801
|
+
mimeType?: string;
|
|
802
|
+
content?: string;
|
|
803
|
+
error?: string;
|
|
804
|
+
}>;
|
|
805
|
+
}
|
|
806
|
+
|
|
750
807
|
/** Error response */
|
|
751
808
|
export interface CallAgentErrorResponse {
|
|
752
809
|
success: false;
|
|
@@ -762,4 +819,6 @@ export type CallAgentResponse =
|
|
|
762
819
|
| CallAgentDescribeToolsResponse
|
|
763
820
|
| CallAgentLoadResponse
|
|
764
821
|
| CallAgentCallbackResponse
|
|
822
|
+
| CallAgentListResourcesResponse
|
|
823
|
+
| CallAgentReadResourcesResponse
|
|
765
824
|
| CallAgentErrorResponse;
|