@scalar/agent 0.2.0 → 0.3.0

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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Scalar Agent SDK
2
2
 
3
- Connect your AI agent to Scalar's OpenAPI MCP servers. Provides native integrations for the Vercel AI SDK, OpenAI Agents SDK, and Anthropic Claude SDK.
3
+ Connect your AI agent to Scalar's OpenAPI MCP servers. Provides native integrations for the Vercel AI SDK, OpenAI Agents SDK, and Anthropic Claude Agent SDK.
4
4
 
5
5
  ## Installation
6
6
 
@@ -22,20 +22,12 @@ bun i @scalar/agent
22
22
  import { agentScalar } from '@scalar/agent'
23
23
 
24
24
  const scalar = agentScalar({
25
- agentKey: 'your-agent-key',
25
+ token: 'your-personal-token',
26
26
  })
27
27
 
28
- const session = await scalar.session({
29
- apis: [{ namespace: 'scalar', slug: 'galaxy' }],
30
- })
28
+ const installation = await scalar.installation('your-installation-id')
31
29
  ```
32
30
 
33
- # Agent Key
34
-
35
- An agent key allows access to private APIs as well as a default set of APIs if configured for a key. [Learn more about agent keys](https://scalar.com/products/agent/key).
36
-
37
- Agent keys also identify your team for billing and analytics.
38
-
39
31
  ## Providers
40
32
 
41
33
  ### Vercel AI SDK
@@ -43,126 +35,85 @@ Agent keys also identify your team for billing and analytics.
43
35
  Uses `@ai-sdk/mcp` natively. Returns a tool set ready for `generateText` / `streamText`.
44
36
 
45
37
  ```ts
46
- import { generateText } from 'ai'
47
- import { openai } from '@ai-sdk/openai'
38
+ import { agentScalar } from '@scalar/agent'
39
+ import { generateText, stepCountIs } from 'ai'
48
40
 
49
41
  const scalar = agentScalar({
50
- agentKey: 'your-agent-key',
42
+ token: 'your-personal-token',
51
43
  })
52
44
 
53
- const session = await scalar.session({
54
- apis: [{ namespace: 'scalar', slug: 'galaxy' }],
55
- })
45
+ const installation = await scalar.installation('your-installation-id')
56
46
 
57
- const tools = await session.createVercelAITools()
47
+ const tools = await installation.createVercelAITools()
58
48
 
59
49
  const { text } = await generateText({
60
- model: openai('gpt-4o'),
50
+ model,
61
51
  tools,
62
- prompt: 'List the available endpoints in the Galaxy API',
52
+ stopWhen: stepCountIs(5),
53
+ prompt: 'How do I create a planet?',
63
54
  })
64
55
  ```
65
56
 
66
57
  ### OpenAI Agents SDK
67
58
 
68
- Returns `MCPServerStreamableHttpOptions[]` pass each entry to `new MCPServerStreamableHttp()` from `@openai/agents`. The agent runtime handles tool discovery and execution natively.
59
+ Returns options for `MCPServerStreamableHttp` from `@openai/agents`. The agent runtime handles tool discovery and execution natively.
69
60
 
70
61
  ```ts
62
+ import { agentScalar } from '@scalar/agent'
71
63
  import { Agent, MCPServerStreamableHttp, run } from '@openai/agents'
72
64
 
73
65
  const scalar = agentScalar({
74
- agentKey: 'your-agent-key',
66
+ token: 'your-token',
75
67
  })
76
68
 
77
- const session = await scalar.session({
78
- apis: [{ namespace: 'scalar', slug: 'galaxy' }],
79
- })
69
+ const installation = await scalar.installation('your-installation-id')
80
70
 
81
- const serverOptions = session.createOpenAIMCPServerOptions()
82
- const servers = serverOptions.map((opts) => new MCPServerStreamableHttp(opts))
83
- await Promise.all(servers.map((s) => s.connect()))
71
+ const server = new MCPServerStreamableHttp(installation.createOpenAIMCP())
72
+ await server.connect()
84
73
 
85
74
  const agent = new Agent({
86
75
  name: 'api-agent',
87
- instructions: 'You help users interact with APIs.',
88
- mcpServers: servers,
76
+ mcpServers: [server],
89
77
  })
90
78
 
91
79
  const result = await run(
92
80
  agent,
93
- 'List the available endpoints in the Galaxy API',
81
+ 'Which APIs are available that let me create a planet?',
94
82
  )
95
83
 
96
- await Promise.all(servers.map((s) => s.close()))
84
+ await server.close()
97
85
  ```
98
86
 
99
- ### Anthropic Claude SDK
87
+ ### Anthropic Claude Agent SDK
100
88
 
101
- Uses `@modelcontextprotocol/sdk` directly. Returns `tools` (ready for `messages.create`) and `executeTool` (for handling `tool_use` response blocks).
89
+ Returns an MCP server configuration for `@anthropic-ai/claude-agent-sdk`.
102
90
 
103
91
  ```ts
104
- import Anthropic from '@anthropic-ai/sdk'
92
+ import { agentScalar } from '@scalar/agent'
93
+ import { query } from '@anthropic-ai/claude-agent-sdk'
105
94
 
106
95
  const scalar = agentScalar({
107
- agentKey: 'your-agent-key',
108
- })
109
-
110
- const session = await scalar.session({
111
- apis: [{ namespace: 'scalar', slug: 'galaxy' }],
96
+ token: 'your-token',
112
97
  })
113
98
 
114
- const client = new Anthropic()
115
- const { tools, executeTool } = await session.createAnthropicTools()
116
-
117
- const messages: Anthropic.MessageParam[] = [
118
- { role: 'user', content: 'List the available endpoints in the Galaxy API' },
119
- ]
120
-
121
- // Agentic loop
122
- while (true) {
123
- const response = await client.messages.create({
124
- model: 'claude-opus-4-6',
125
- max_tokens: 4096,
126
- tools,
127
- messages,
128
- })
129
-
130
- messages.push({ role: 'assistant', content: response.content })
131
-
132
- if (response.stop_reason !== 'tool_use') break
133
-
134
- const toolResults: Anthropic.ToolResultBlockParam[] = await Promise.all(
135
- response.content
136
- .filter(
137
- (block): block is Anthropic.ToolUseBlock => block.type === 'tool_use',
138
- )
139
- .map(async (block) => ({
140
- type: 'tool_result',
141
- tool_use_id: block.id,
142
- content: await executeTool(
143
- block.name,
144
- block.input as Record<string, unknown>,
145
- ),
146
- })),
147
- )
148
-
149
- messages.push({ role: 'user', content: toolResults })
99
+ const installation = await scalar.installation('your-installation-id')
100
+
101
+ for await (const message of query({
102
+ prompt: 'Which APIs are available that let me create a planet?',
103
+ options: {
104
+ mcpServers: {
105
+ scalar: installation.createAnthropicMCP(),
106
+ },
107
+ allowedTools: ['mcp__scalar__*'],
108
+ },
109
+ })) {
110
+ if ('result' in message) console.log(message.result)
150
111
  }
151
112
  ```
152
113
 
153
114
  ## Configuration
154
115
 
155
- | Option | Type | Description |
156
- | ---------- | -------- | ---------------------------------------------------------------------- |
157
- | `agentKey` | `string` | Scalar agent key, sent as the authorization request header |
158
- | `baseUrl` | `string` | Base URL of the Scalar MCP server. Defaults to the staging environment |
159
-
160
- ## How it works
161
-
162
- Each Scalar API is exposed as an MCP (Model Context Protocol) server. The SDK connects to these servers and surfaces their tools to your AI framework of choice. Every API exposes three tools:
163
-
164
- - **`get-openapi-specs-summary`** — lists the available endpoints
165
- - **`get-mini-openapi-spec`** — fetches a trimmed OpenAPI spec for specific endpoints
166
- - **`execute-request`** — executes an HTTP request against the API
167
-
168
- Tools are namespaced by API to avoid collisions when connecting multiple APIs at once: `{namespace}{delimiter}{slug}__{toolName}`.
116
+ | Option | Type | Description |
117
+ | --------- | -------- | --------------------------------------------------------------------- |
118
+ | `token` | `string` | Your Scalar Personal Token used to authenticate requests to your MCP |
119
+ | `baseUrl` | `string` | Base URL of the Scalar MCP server. Defaults to the Scalar environment |
@@ -0,0 +1,6 @@
1
+ export declare enum Provider {
2
+ VERCEL = "VERCEL",
3
+ OPENAI = "OPENAI",
4
+ ANTHROPIC = "ANTHROPIC"
5
+ }
6
+ export declare const SDK_PROVIDER_HEADER_NAME = "X-Scalar-SDK-Provider";
@@ -0,0 +1,11 @@
1
+ var Provider = /* @__PURE__ */ ((Provider2) => {
2
+ Provider2["VERCEL"] = "VERCEL";
3
+ Provider2["OPENAI"] = "OPENAI";
4
+ Provider2["ANTHROPIC"] = "ANTHROPIC";
5
+ return Provider2;
6
+ })(Provider || {});
7
+ const SDK_PROVIDER_HEADER_NAME = "X-Scalar-SDK-Provider";
8
+ export {
9
+ Provider,
10
+ SDK_PROVIDER_HEADER_NAME
11
+ };
package/dist/index.d.ts CHANGED
@@ -1,158 +1,113 @@
1
- import type Anthropic from '@anthropic-ai/sdk';
2
- import z from 'zod';
1
+ import type { McpServerConfig } from '@anthropic-ai/claude-agent-sdk';
2
+ import type { ToolSet } from 'ai';
3
3
  export interface AgentSDKConfig {
4
4
  /** Base URL of the Scalar MCP server. Defaults to the Scalar staging environment. */
5
5
  baseUrl?: string;
6
- /** Sent as the `x-scalar-agent-key` request header. */
7
- agentKey?: string;
6
+ /** Your Scalar Personal Token used to authenticate requests to your MCP. */
7
+ token: string;
8
8
  }
9
- type Api = {
10
- namespace: string;
11
- slug: string;
12
- };
13
9
  export type MCPServerOptions = {
14
10
  url: string;
15
11
  name: string;
16
12
  fetch: (url: RequestInfo | URL, options?: RequestInit) => Promise<Response>;
17
13
  };
18
- export declare const EXECUTE_REQUEST_TOOL_NAME = "execute-request";
19
- export declare const executeRequestToolInputSchema: z.ZodObject<{
20
- method: z.ZodString;
21
- path: z.ZodString;
22
- headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
23
- body: z.ZodOptional<z.ZodString>;
24
- }, z.core.$strip>;
25
- export declare const mcpToolSchemas: {
26
- "execute-request": {
27
- inputSchema: z.ZodObject<{
28
- method: z.ZodString;
29
- path: z.ZodString;
30
- headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
31
- body: z.ZodOptional<z.ZodString>;
32
- }, z.core.$strip>;
33
- };
34
- "get-mini-openapi-spec": {
35
- inputSchema: z.ZodObject<{
36
- question: z.ZodString;
37
- }, z.core.$strip>;
38
- };
39
- "get-openapi-specs-summary": {
40
- inputSchema: z.ZodObject<{}, z.core.$strip>;
41
- };
42
- };
43
14
  /**
44
15
  * Creates a Scalar agent client configured to connect to Scalar's MCP servers.
45
16
  *
46
17
  * @example
47
18
  * ```ts
48
- * const scalar = agentScalar({ agentKey: 'your-agent-key' })
19
+ * const scalar = agentScalar({ token: 'your-personal-token' })
20
+ * const installation = await scalar.installation('your-installation-id')
49
21
  * ```
50
22
  */
51
- export declare const agentScalar: (config?: AgentSDKConfig) => {
52
- session: ({ apis }: {
53
- apis: Api[];
54
- }) => Promise<{
23
+ export declare const agentScalar: (config: AgentSDKConfig) => {
24
+ installation: (installationId: string) => Promise<{
55
25
  /**
56
26
  * Returns tools in Vercel AI SDK format.
57
27
  * Uses `@ai-sdk/mcp` natively.
58
28
  *
59
29
  * @example
60
30
  * ```ts
61
- * import { agentScalar } from '@scalar/agent'
62
- * import { generateText } from 'ai'
63
- * import { openai } from '@ai-sdk/openai'
31
+ * import { agentScalar } from "@scalar/agent";
32
+ * import { generateText, stepCountIs } from "ai";
64
33
  *
65
- * const scalar = agentScalar({ agentKey: 'your-agent-key' })
66
- * const session = await scalar.session({ apis: [{ namespace: 'scalar', slug: 'galaxy' }] })
34
+ * const scalar = agentScalar({
35
+ * token: "your-personal-token",
36
+ * });
37
+ * const installation = await scalar.installation("0c1ea059-58ad-41ec-bcf7-331fefa0f61c");
67
38
  *
68
- * const tools = await session.createVercelAITools()
39
+ * const tools = await installation.createVercelAITools();
69
40
  *
70
41
  * const { text } = await generateText({
71
- * model: openai('gpt-4o'),
42
+ * model,
72
43
  * tools,
73
- * prompt: 'List the available endpoints in the Petstore API',
74
- * })
44
+ * stopWhen: stepCountIs(5),
45
+ * prompt: "How do I create a planet?",
46
+ * });
75
47
  * ```
76
48
  */
77
- createVercelAITools: () => Promise<any>;
49
+ createVercelAITools: () => Promise<ToolSet>;
78
50
  /**
79
- * Returns options for creating `MCPServerStreamableHttp` instances via `@openai/agents`.
51
+ * Returns options for creating an `MCPServerStreamableHttp` instance via `@openai/agents`.
80
52
  * The agent handles tool discovery and execution natively.
81
53
  *
82
54
  * @example
83
55
  * ```ts
84
- * import { agentScalar } from '@scalar/agent'
85
- * import { Agent, MCPServerStreamableHttp, run } from '@openai/agents'
56
+ * import { agentScalar } from "@scalar/agent";
57
+ * import { Agent, MCPServerStreamableHttp, run } from "@openai/agents";
86
58
  *
87
- * const scalar = agentScalar({ agentKey: 'your-agent-key' })
88
- * const session = await scalar.session({ apis: [{ namespace: 'scalar', slug: 'galaxy' }] })
59
+ * const scalar = agentScalar({
60
+ * token: "your-token",
61
+ * });
62
+ * const installation = await scalar.installation("your-installation-id");
89
63
  *
90
- * const servers = (await session.createOpenAIMCP()).map((opts) => new MCPServerStreamableHttp(opts))
91
- * await Promise.all(servers.map((s) => s.connect()))
64
+ * const server = new MCPServerStreamableHttp(installation.createOpenAIMCP());
65
+ * await server.connect();
92
66
  *
93
67
  * const agent = new Agent({
94
- * name: 'api-agent',
95
- * instructions: 'You help users interact with APIs.',
96
- * mcpServers: servers,
97
- * })
68
+ * name: "api-agent",
69
+ * mcpServers: [server],
70
+ * });
71
+ *
72
+ * const result = await run(
73
+ * agent,
74
+ * "Which APIs are available that let me create a planet?",
75
+ * );
98
76
  *
99
- * const result = await run(agent, 'List the available endpoints in the Petstore API')
100
- * await Promise.all(servers.map((s) => s.close()))
77
+ * await server.close();
101
78
  * ```
102
79
  */
103
- createOpenAIMCP: () => Promise<MCPServerOptions[]>;
80
+ createOpenAIMCP: () => {
81
+ url: string;
82
+ name: string;
83
+ fetch: (url: RequestInfo | URL, options?: RequestInit) => Promise<Response>;
84
+ };
104
85
  /**
105
- * Returns tools in `@anthropic-ai/sdk` format.
106
- * Uses `@modelcontextprotocol/sdk` Client directly — `listTools()` already returns
107
- * JSON Schema so no conversion needed. Tool calls are routed back via `callTool()`.
86
+ * Returns an MCP server configuration for `@anthropic-ai/claude-agent-sdk`.
108
87
  *
109
88
  * @example
110
89
  * ```ts
111
- * import { agentScalar } from '@scalar/agent'
112
- * import Anthropic from '@anthropic-ai/sdk'
113
- *
114
- * const scalar = agentScalar({ agentKey: 'your-agent-key' })
115
- * const session = await scalar.session({ apis: [{ namespace: 'scalar', slug: 'galaxy' }] })
116
- *
117
- * const client = new Anthropic()
118
- * const { tools, executeTool } = await session.createAnthropicTools()
119
- *
120
- * const messages: Anthropic.MessageParam[] = [
121
- * { role: 'user', content: 'List the available endpoints in the Petstore API' },
122
- * ]
123
- *
124
- * // Agentic loop
125
- * while (true) {
126
- * const response = await client.messages.create({
127
- * model: 'claude-opus-4-6',
128
- * max_tokens: 4096,
129
- * tools,
130
- * messages,
131
- * })
132
- *
133
- * messages.push({ role: 'assistant', content: response.content })
134
- *
135
- * if (response.stop_reason !== 'tool_use') break
136
- *
137
- * const toolResults = await Promise.all(
138
- * response.content
139
- * .filter((b): b is Anthropic.ToolUseBlock => b.type === 'tool_use')
140
- * .map(async (b) => ({
141
- * type: 'tool_result' as const,
142
- * tool_use_id: b.id,
143
- * content: await executeTool(b.name, b.input as Record<string, unknown>),
144
- * })),
145
- * )
146
- *
147
- * messages.push({ role: 'user', content: toolResults })
90
+ * import { agentScalar } from "@scalar/agent";
91
+ * import { query } from "@anthropic-ai/claude-agent-sdk";
92
+ *
93
+ * const scalar = agentScalar({
94
+ * token: "your-token",
95
+ * });
96
+ * const installation = await scalar.installation("your-installation-id");
97
+ *
98
+ * for await (const message of query({
99
+ * prompt: "Which APIs are available that let me create a planet?",
100
+ * options: {
101
+ * mcpServers: {
102
+ * scalar: installation.createAnthropicMCP(),
103
+ * },
104
+ * allowedTools: ["mcp__scalar__*"],
105
+ * },
106
+ * })) {
107
+ * if ("result" in message) console.log(message.result);
148
108
  * }
149
109
  * ```
150
110
  */
151
- createAnthropicTools: () => Promise<{
152
- tools: Anthropic.Tool[];
153
- executeTool: (toolName: string, input: Record<string, unknown>) => Promise<string>;
154
- }>;
111
+ createAnthropicMCP: () => McpServerConfig;
155
112
  }>;
156
113
  };
157
- export {};
158
- //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -1,78 +1,22 @@
1
1
  import { createMCPClient } from "@ai-sdk/mcp";
2
- import { Client } from "@modelcontextprotocol/sdk/client/index.js";
3
2
  import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
4
- import z from "zod";
5
- import {
6
- GET_MINI_OPENAPI_SPEC_TOOL_NAME,
7
- GET_OPENAPI_SPECS_SUMMARY_TOOL_NAME,
8
- getMiniOpenAPIDocToolInputSchema,
9
- TOOL_NAMESPACE_SLUG_DELIMITER
10
- } from "@scalar/agent-chat/entities";
11
- import { createWorkspaceStore } from "@scalar/workspace-store/client";
12
- const EXECUTE_REQUEST_TOOL_NAME = "execute-request";
13
- const executeRequestToolInputSchema = z.object({
14
- method: z.string(),
15
- path: z.string(),
16
- headers: z.record(z.string(), z.string()).optional(),
17
- body: z.string().optional()
18
- });
19
- const mcpToolSchemas = {
20
- [EXECUTE_REQUEST_TOOL_NAME]: { inputSchema: executeRequestToolInputSchema },
21
- [GET_MINI_OPENAPI_SPEC_TOOL_NAME]: {
22
- inputSchema: getMiniOpenAPIDocToolInputSchema
23
- },
24
- [GET_OPENAPI_SPECS_SUMMARY_TOOL_NAME]: { inputSchema: z.object({}) }
25
- };
26
- function safeParseJson(value) {
27
- try {
28
- return { success: true, data: JSON.parse(value) };
29
- } catch {
30
- return { success: false };
31
- }
32
- }
33
- async function resolveActiveServerUrl(api) {
34
- const store = createWorkspaceStore();
35
- const key = `${api.namespace}/${api.slug}`;
36
- await store.addDocument({
37
- name: key,
38
- url: `https://registry.scalar.com/@${api.namespace}/apis/${api.slug}`
39
- });
40
- return store.workspace.documents[key]?.servers?.[0]?.url ?? "";
41
- }
42
- function buildMCPUrl(api, baseUrl, serverUrl) {
43
- return new URL(
44
- `/vector/mcp/${api.namespace}/${api.slug}?activeServerUrl=${encodeURIComponent(serverUrl)}`,
45
- baseUrl
46
- );
47
- }
48
- function buildFetch(agentKey) {
49
- return (url, options) => {
50
- const parsed = safeParseJson(options?.body);
51
- if (!parsed.success) return fetch(url, options);
52
- if (parsed.data.params) {
53
- parsed.data.params._meta = { securitySchemes: [] };
3
+ import { Provider, SDK_PROVIDER_HEADER_NAME } from "./constants";
4
+ function buildFetch(token, provider) {
5
+ return async (url, options) => await fetch(url, {
6
+ ...options,
7
+ headers: {
8
+ "content-type": "application/json",
9
+ accept: "application/json, text/event-stream",
10
+ [SDK_PROVIDER_HEADER_NAME]: provider,
11
+ ...options?.headers,
12
+ ...token && { Authorization: token }
54
13
  }
55
- return fetch(url, {
56
- ...options,
57
- headers: {
58
- "Content-Type": "application/json",
59
- Accept: "application/json, text/event-stream",
60
- ...options?.headers,
61
- ...agentKey && { "x-scalar-agent-key": agentKey }
62
- },
63
- body: JSON.stringify(parsed.data)
64
- });
65
- };
66
- }
67
- function namespaceTool(api, toolName) {
68
- return `${api.namespace}${TOOL_NAMESPACE_SLUG_DELIMITER}${api.slug}__${toolName}`;
14
+ });
69
15
  }
70
- const agentScalar = (config = {}) => {
16
+ const agentScalar = (config) => {
71
17
  const baseUrl = config.baseUrl ?? "https://services.scalar.com";
72
- const session = async ({ apis }) => {
73
- const mcpFetch = buildFetch(config.agentKey);
74
- const serverUrls = await Promise.all(apis.map(resolveActiveServerUrl));
75
- const mcpUrl = (api) => buildMCPUrl(api, baseUrl, serverUrls[apis.indexOf(api)]);
18
+ const installation = async (installationId) => {
19
+ const url = new URL(`/vector/mcp/${installationId}`, baseUrl);
76
20
  return {
77
21
  /**
78
22
  * Returns tools in Vercel AI SDK format.
@@ -80,175 +24,109 @@ const agentScalar = (config = {}) => {
80
24
  *
81
25
  * @example
82
26
  * ```ts
83
- * import { agentScalar } from '@scalar/agent'
84
- * import { generateText } from 'ai'
85
- * import { openai } from '@ai-sdk/openai'
27
+ * import { agentScalar } from "@scalar/agent";
28
+ * import { generateText, stepCountIs } from "ai";
86
29
  *
87
- * const scalar = agentScalar({ agentKey: 'your-agent-key' })
88
- * const session = await scalar.session({ apis: [{ namespace: 'scalar', slug: 'galaxy' }] })
30
+ * const scalar = agentScalar({
31
+ * token: "your-personal-token",
32
+ * });
33
+ * const installation = await scalar.installation("0c1ea059-58ad-41ec-bcf7-331fefa0f61c");
89
34
  *
90
- * const tools = await session.createVercelAITools()
35
+ * const tools = await installation.createVercelAITools();
91
36
  *
92
37
  * const { text } = await generateText({
93
- * model: openai('gpt-4o'),
38
+ * model,
94
39
  * tools,
95
- * prompt: 'List the available endpoints in the Petstore API',
96
- * })
40
+ * stopWhen: stepCountIs(5),
41
+ * prompt: "How do I create a planet?",
42
+ * });
97
43
  * ```
98
44
  */
99
45
  createVercelAITools: async () => {
100
- const clients = await Promise.all(
101
- apis.map(async (api) => ({
102
- client: await createMCPClient({
103
- transport: new StreamableHTTPClientTransport(mcpUrl(api), {
104
- fetch: mcpFetch
105
- })
106
- }),
107
- api
108
- }))
109
- );
110
- const toolSets = await Promise.all(
111
- clients.map(async ({ client, api }) => {
112
- const tools = await client.tools({ schemas: mcpToolSchemas });
113
- return Object.fromEntries(
114
- Object.entries(tools).map(([toolName, tool]) => [
115
- namespaceTool(api, toolName),
116
- tool
117
- ])
118
- );
46
+ const mcpFetch = buildFetch(config.token, Provider.VERCEL);
47
+ const client = await createMCPClient({
48
+ transport: new StreamableHTTPClientTransport(url, {
49
+ fetch: mcpFetch
119
50
  })
120
- );
121
- return Object.assign({}, ...toolSets);
51
+ });
52
+ return client.tools();
122
53
  },
123
54
  /**
124
- * Returns options for creating `MCPServerStreamableHttp` instances via `@openai/agents`.
55
+ * Returns options for creating an `MCPServerStreamableHttp` instance via `@openai/agents`.
125
56
  * The agent handles tool discovery and execution natively.
126
57
  *
127
58
  * @example
128
59
  * ```ts
129
- * import { agentScalar } from '@scalar/agent'
130
- * import { Agent, MCPServerStreamableHttp, run } from '@openai/agents'
60
+ * import { agentScalar } from "@scalar/agent";
61
+ * import { Agent, MCPServerStreamableHttp, run } from "@openai/agents";
131
62
  *
132
- * const scalar = agentScalar({ agentKey: 'your-agent-key' })
133
- * const session = await scalar.session({ apis: [{ namespace: 'scalar', slug: 'galaxy' }] })
63
+ * const scalar = agentScalar({
64
+ * token: "your-token",
65
+ * });
66
+ * const installation = await scalar.installation("your-installation-id");
134
67
  *
135
- * const servers = (await session.createOpenAIMCP()).map((opts) => new MCPServerStreamableHttp(opts))
136
- * await Promise.all(servers.map((s) => s.connect()))
68
+ * const server = new MCPServerStreamableHttp(installation.createOpenAIMCP());
69
+ * await server.connect();
137
70
  *
138
71
  * const agent = new Agent({
139
- * name: 'api-agent',
140
- * instructions: 'You help users interact with APIs.',
141
- * mcpServers: servers,
142
- * })
72
+ * name: "api-agent",
73
+ * mcpServers: [server],
74
+ * });
143
75
  *
144
- * const result = await run(agent, 'List the available endpoints in the Petstore API')
145
- * await Promise.all(servers.map((s) => s.close()))
76
+ * const result = await run(
77
+ * agent,
78
+ * "Which APIs are available that let me create a planet?",
79
+ * );
80
+ *
81
+ * await server.close();
146
82
  * ```
147
83
  */
148
- createOpenAIMCP: async () => Promise.all(
149
- apis.map(async (api) => ({
150
- url: mcpUrl(api).toString(),
151
- name: `${api.namespace}/${api.slug}`,
84
+ createOpenAIMCP: () => {
85
+ const mcpFetch = buildFetch(config.token, Provider.OPENAI);
86
+ return {
87
+ url: url.toString(),
88
+ name: installationId,
152
89
  fetch: mcpFetch
153
- }))
154
- ),
90
+ };
91
+ },
155
92
  /**
156
- * Returns tools in `@anthropic-ai/sdk` format.
157
- * Uses `@modelcontextprotocol/sdk` Client directly — `listTools()` already returns
158
- * JSON Schema so no conversion needed. Tool calls are routed back via `callTool()`.
93
+ * Returns an MCP server configuration for `@anthropic-ai/claude-agent-sdk`.
159
94
  *
160
95
  * @example
161
96
  * ```ts
162
- * import { agentScalar } from '@scalar/agent'
163
- * import Anthropic from '@anthropic-ai/sdk'
164
- *
165
- * const scalar = agentScalar({ agentKey: 'your-agent-key' })
166
- * const session = await scalar.session({ apis: [{ namespace: 'scalar', slug: 'galaxy' }] })
167
- *
168
- * const client = new Anthropic()
169
- * const { tools, executeTool } = await session.createAnthropicTools()
170
- *
171
- * const messages: Anthropic.MessageParam[] = [
172
- * { role: 'user', content: 'List the available endpoints in the Petstore API' },
173
- * ]
174
- *
175
- * // Agentic loop
176
- * while (true) {
177
- * const response = await client.messages.create({
178
- * model: 'claude-opus-4-6',
179
- * max_tokens: 4096,
180
- * tools,
181
- * messages,
182
- * })
183
- *
184
- * messages.push({ role: 'assistant', content: response.content })
185
- *
186
- * if (response.stop_reason !== 'tool_use') break
187
- *
188
- * const toolResults = await Promise.all(
189
- * response.content
190
- * .filter((b): b is Anthropic.ToolUseBlock => b.type === 'tool_use')
191
- * .map(async (b) => ({
192
- * type: 'tool_result' as const,
193
- * tool_use_id: b.id,
194
- * content: await executeTool(b.name, b.input as Record<string, unknown>),
195
- * })),
196
- * )
197
- *
198
- * messages.push({ role: 'user', content: toolResults })
97
+ * import { agentScalar } from "@scalar/agent";
98
+ * import { query } from "@anthropic-ai/claude-agent-sdk";
99
+ *
100
+ * const scalar = agentScalar({
101
+ * token: "your-token",
102
+ * });
103
+ * const installation = await scalar.installation("your-installation-id");
104
+ *
105
+ * for await (const message of query({
106
+ * prompt: "Which APIs are available that let me create a planet?",
107
+ * options: {
108
+ * mcpServers: {
109
+ * scalar: installation.createAnthropicMCP(),
110
+ * },
111
+ * allowedTools: ["mcp__scalar__*"],
112
+ * },
113
+ * })) {
114
+ * if ("result" in message) console.log(message.result);
199
115
  * }
200
116
  * ```
201
117
  */
202
- createAnthropicTools: async () => {
203
- const clients = await Promise.all(
204
- apis.map(async (api) => {
205
- const client = new Client({
206
- name: "scalar-agent-sdk",
207
- version: "0.1.0"
208
- });
209
- await client.connect(
210
- new StreamableHTTPClientTransport(mcpUrl(api), {
211
- fetch: mcpFetch
212
- })
213
- );
214
- return { client, api };
215
- })
216
- );
217
- const toolRoutes = /* @__PURE__ */ new Map();
218
- const anthropicTools = [];
219
- for (const { client, api } of clients) {
220
- const { tools } = await client.listTools();
221
- for (const tool of tools) {
222
- const name = namespaceTool(api, tool.name);
223
- anthropicTools.push({
224
- name,
225
- description: tool.description,
226
- input_schema: tool.inputSchema
227
- });
228
- toolRoutes.set(name, { client, originalName: tool.name });
229
- }
118
+ createAnthropicMCP: () => ({
119
+ type: "http",
120
+ url: url.toString(),
121
+ headers: {
122
+ Authorization: config.token,
123
+ [SDK_PROVIDER_HEADER_NAME]: Provider.ANTHROPIC
230
124
  }
231
- const executeTool = async (toolName, input) => {
232
- const route = toolRoutes.get(toolName);
233
- if (!route) {
234
- throw new Error(`Tool "${toolName}" not found`);
235
- }
236
- const result = await route.client.callTool({
237
- name: route.originalName,
238
- arguments: input
239
- });
240
- const content = result.content;
241
- return content.filter((c) => c.type === "text").map((c) => c.text ?? "").join("\n");
242
- };
243
- return { tools: anthropicTools, executeTool };
244
- }
125
+ })
245
126
  };
246
127
  };
247
- return { session };
128
+ return { installation };
248
129
  };
249
130
  export {
250
- EXECUTE_REQUEST_TOOL_NAME,
251
- agentScalar,
252
- executeRequestToolInputSchema,
253
- mcpToolSchemas
131
+ agentScalar
254
132
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@scalar/agent",
3
3
  "description": "Scalar Agent SDK",
4
- "version": "0.2.0",
4
+ "version": "0.3.0",
5
5
  "author": "Scalar (https://github.com/scalar)",
6
6
  "license": "MIT",
7
7
  "private": false,
@@ -17,14 +17,14 @@
17
17
  "import": "./dist/index.js",
18
18
  "types": "./dist/index.d.ts",
19
19
  "default": "./dist/index.js"
20
+ },
21
+ "./constants": {
22
+ "import": "./dist/constants.js",
23
+ "types": "./dist/constants.d.ts",
24
+ "default": "./dist/constants.js"
20
25
  }
21
26
  },
22
27
  "dependencies": {
23
- "@ai-sdk/mcp": "^1.0.14",
24
- "@anthropic-ai/sdk": "^0.78.0",
25
- "@modelcontextprotocol/sdk": "^1.27.1",
26
- "@scalar/workspace-store": "^0.34.2",
27
- "@scalar/agent-chat": "^0.5.16",
28
- "zod": "^4.3.6"
28
+ "@modelcontextprotocol/sdk": "^1.27.1"
29
29
  }
30
30
  }
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,SAAS,MAAM,mBAAmB,CAAA;AAG9C,OAAO,CAAC,MAAM,KAAK,CAAA;AAUnB,MAAM,WAAW,cAAc;IAC7B,qFAAqF;IACrF,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,uDAAuD;IACvD,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,KAAK,GAAG,GAAG;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAA;AAE9C,MAAM,MAAM,gBAAgB,GAAG;IAC7B,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,CAAC,GAAG,EAAE,WAAW,GAAG,GAAG,EAAE,OAAO,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAA;CAC5E,CAAA;AAED,eAAO,MAAM,yBAAyB,oBAAoB,CAAA;AAE1D,eAAO,MAAM,6BAA6B;;;;;iBAKxC,CAAA;AAEF,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;CAM1B,CAAA;AA2DD;;;;;;;GAOG;AACH,eAAO,MAAM,WAAW,GAAI,SAAQ,cAAmB;wBAuBpB;QAAE,IAAI,EAAE,GAAG,EAAE,CAAA;KAAE;QAS5C;;;;;;;;;;;;;;;;;;;;;WAqBG;;QA6BH;;;;;;;;;;;;;;;;;;;;;;;;WAwBG;+BACwB,OAAO,CAAC,gBAAgB,EAAE,CAAC;QAStD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;WA8CG;oCAC6B,OAAO,CAAC;YACtC,KAAK,EAAE,SAAS,CAAC,IAAI,EAAE,CAAA;YACvB,WAAW,EAAE,CACX,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC3B,OAAO,CAAC,MAAM,CAAC,CAAA;SACrB,CAAC;;CAyEP,CAAA"}
package/dist/index.js.map DELETED
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/index.ts"],
4
- "sourcesContent": ["import { createMCPClient, type MCPClient } from '@ai-sdk/mcp'\nimport { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js'\nimport { createNeverpanic } from 'neverpanic'\nimport z from 'zod'\n\nimport {\n GET_MINI_OPENAPI_SPEC_TOOL_NAME,\n GET_OPENAPI_SPECS_SUMMARY_TOOL_NAME,\n getMiniOpenAPIDocToolInputSchema,\n TOOL_NAMESPACE_SLUG_DELIMITER,\n} from '@scalar/agent-chat/entities'\n\nexport type AgentError<D> = {\n code: string\n detail: D\n}\n\nexport const n = createNeverpanic<unknown, AgentError<unknown>>()\n\nexport interface AgentSDKConfig {\n baseUrl?: string\n agentKey?: string\n}\n\ntype Api = {\n namespace: string\n slug: string\n}\n\nexport const EXECUTE_REQUEST_TOOL_NAME = 'execute-request'\n\nexport const executeRequestToolInputSchema = z.object({\n method: z.string(),\n path: z.string(),\n headers: z.record(z.string(), z.string()).optional(),\n body: z.string().optional(),\n})\n\nexport const mcpToolSchemas = {\n [EXECUTE_REQUEST_TOOL_NAME]: { inputSchema: executeRequestToolInputSchema },\n [GET_MINI_OPENAPI_SPEC_TOOL_NAME]: {\n inputSchema: getMiniOpenAPIDocToolInputSchema,\n },\n [GET_OPENAPI_SPECS_SUMMARY_TOOL_NAME]: {\n inputSchema: z.object(),\n },\n}\n\nexport const safeParseJson = n.safeFn(\n (value: any) => ({ success: true, data: JSON.parse(value) }),\n (originalError) =>\n n.err({ code: 'FAILED_TO_PARSE_JSON', detail: originalError }),\n)\n\nconst createClients = n.safeFn(\n async ({\n baseUrl,\n agentKey,\n apis,\n }: {\n baseUrl: string\n agentKey?: string\n apis: Api[]\n }) => {\n const clients = await Promise.all(\n apis.map(async (api) => {\n const mcpUrl = new URL(\n `/vector/mcp/${api.namespace}/${api.slug}?activeServerUrl=${encodeURIComponent('https://galaxy.scalar.com')}`,\n baseUrl,\n )\n\n const mcpClient = await createMCPClient({\n transport: new StreamableHTTPClientTransport(mcpUrl, {\n fetch(url, options) {\n const parsedJsonBodyResult = safeParseJson(options?.body)\n if (!parsedJsonBodyResult.success) return fetch(url, options)\n\n if (parsedJsonBodyResult.data.params)\n parsedJsonBodyResult.data.params._meta = {\n securitySchemes: [],\n }\n\n return fetch(url, {\n ...options,\n headers: {\n 'Content-Type': 'application/json',\n 'Accept': 'application/json, text/event-stream',\n ...options?.headers,\n ...(agentKey && {\n 'x-scalar-agent-key': agentKey,\n }),\n },\n body: JSON.stringify(parsedJsonBodyResult.data),\n })\n },\n }),\n })\n\n return {\n mcpClient,\n api,\n }\n }),\n )\n\n return {\n success: true,\n data: clients,\n }\n },\n (originalError) =>\n n.err({ code: 'FAILED_TO_CREATE_MCP_CLIENTS', detail: originalError }),\n)\n\n/**\n * Create AI SDK tools from an MCP clients returned tools.\n * Applies prefix for tool name uniqueness.\n */\nexport const createTools = n.safeFn(\n async (mcpClients: { mcpClient: MCPClient; api: Api }[]) => {\n const toolSets = await Promise.all(\n mcpClients.map(async ({ mcpClient, api }) => {\n const tools = await mcpClient.tools({\n schemas: mcpToolSchemas,\n })\n\n return Object.fromEntries(\n Object.entries(tools).map(([toolName, tool]) => [\n `${api.namespace}${TOOL_NAMESPACE_SLUG_DELIMITER}${api.slug}__${toolName}`,\n tool,\n ]),\n ) as any\n }),\n )\n\n function merge<T>(sources: T[]): T {\n return Object.assign({}, ...sources)\n }\n\n return {\n success: true,\n data: merge(toolSets),\n }\n },\n (originalError) =>\n n.err({ code: 'FAILED_TO_CREATE_MCP_TOOLS', detail: originalError }),\n)\n\nexport const agentScalar = (config: AgentSDKConfig = {}) => {\n const baseUrl = config.baseUrl ?? 'https://services.staging.scalar.com'\n\n const session = async ({ apis }: { apis: Api[] }) => {\n const createClientsResult = await createClients({\n agentKey: config.agentKey,\n baseUrl,\n apis,\n })\n\n if (!createClientsResult.success) {\n throw createClientsResult.error\n }\n\n return {\n tools: async () => {\n const toolsResult = await createTools(createClientsResult.data)\n\n if (!toolsResult.success) {\n throw Error(toolsResult.error.code)\n }\n\n return toolsResult.data\n },\n }\n }\n\n return {\n session,\n }\n}\n"],
5
- "mappings": "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",
6
- "names": []
7
- }