@missionsquad/mcp-msq 0.1.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 ADDED
@@ -0,0 +1,232 @@
1
+ # @missionsquad/mcp-msq
2
+
3
+ MCP server interface for the MissionSquad platform API (`https://missionsquad.ai`).
4
+
5
+ This server exposes MissionSquad account-scoped operations for models, agents, providers, vector stores, files, and core utilities via FastMCP tools.
6
+
7
+ ## Features
8
+
9
+ - FastMCP stdio server (`mcp-msq`)
10
+ - MissionSquad API key support via hidden tool arg (`apiKey`) or env fallback (`MSQ_API_KEY`)
11
+ - MissionSquad base URL override via hidden tool arg (`baseUrl`) or env fallback (`MSQ_BASE_URL`)
12
+ - Strict TypeScript and Zod-validated tool inputs
13
+ - Multipart file upload support (`POST /v1/files`)
14
+ - Bounded binary file-content retrieval (`GET /v1/files/:id/content`) with truncation metadata
15
+ - Build/test CI and npm publish workflow
16
+
17
+ ## Verified API Coverage
18
+
19
+ Implemented from `missionsquad-docs/api/index.md` and the following reference pages:
20
+
21
+ - `chat-completions.md`
22
+ - `embeddings.md`
23
+ - `providers.md`
24
+ - `models.md`
25
+ - `agents.md`
26
+ - `core-utilities.md`
27
+ - `collections.md`
28
+ - `vector-stores.md`
29
+ - `files.md`
30
+ - `convenience.md`
31
+ - `endpoint-index.md`
32
+
33
+ Current implementation intentionally excludes Webhooks endpoints because the reference only lists routes without request/response contracts.
34
+
35
+ ## Requirements
36
+
37
+ - Node.js `>=20`
38
+ - Yarn
39
+
40
+ ## Installation
41
+
42
+ ```bash
43
+ yarn install
44
+ yarn build
45
+ yarn start
46
+ ```
47
+
48
+ Run as CLI after install/publish:
49
+
50
+ ```bash
51
+ mcp-msq
52
+ ```
53
+
54
+ ## Configuration
55
+
56
+ Copy `.env.example` to `.env`.
57
+
58
+ | Variable | Required | Default | Description |
59
+ |---|---|---|---|
60
+ | `MSQ_API_KEY` | No | unset | MissionSquad API key fallback when hidden `apiKey` is not passed |
61
+ | `MSQ_BASE_URL` | No | `https://agents.missionsquad.ai/v1` | Base URL for v1 endpoints |
62
+ | `MSQ_HTTP_TIMEOUT_MS` | No | `30000` | Request timeout in milliseconds |
63
+ | `MSQ_DEFAULT_FILE_CONTENT_MAX_BYTES` | No | `1048576` | Default max bytes returned by `msq_get_file_content` |
64
+
65
+ ## Hidden Arguments
66
+
67
+ The following are intentionally not in tool schemas and should be passed as hidden extra args:
68
+
69
+ - `apiKey`: MissionSquad API key for request authentication
70
+ - `baseUrl`: Optional base URL override
71
+
72
+ Resolution order per request:
73
+
74
+ 1. Hidden extra arg
75
+ 2. Environment fallback
76
+
77
+ If no API key is available, the tool returns a user-facing error.
78
+
79
+ ## Tool Surface
80
+
81
+ ### Core OpenAI-Compatible
82
+
83
+ - `msq_list_models`
84
+ - `msq_get_model_map`
85
+ - `msq_chat_completions`
86
+ - `msq_embeddings`
87
+
88
+ ### Providers
89
+
90
+ - `msq_list_providers`
91
+ - `msq_add_provider`
92
+ - `msq_delete_provider`
93
+
94
+ ### Models
95
+
96
+ - `msq_discover_provider_models`
97
+ - `msq_add_model`
98
+ - `msq_delete_model`
99
+
100
+ ### Agents
101
+
102
+ - `msq_list_agents`
103
+ - `msq_add_agent`
104
+ - `msq_delete_agent`
105
+
106
+ ### Core Utilities
107
+
108
+ - `msq_generate_prompt`
109
+ - `msq_run_agent_workflow`
110
+ - `msq_get_core_config`
111
+ - `msq_scrape_url`
112
+ - `msq_list_tools`
113
+ - `msq_list_servers`
114
+
115
+ ### Core Collections
116
+
117
+ - `msq_list_core_collections`
118
+ - `msq_search_core_collection`
119
+ - `msq_get_core_collection_diagnostics`
120
+ - `msq_recover_core_collection`
121
+
122
+ ### Vector Stores
123
+
124
+ - `msq_list_vector_stores`
125
+ - `msq_create_vector_store`
126
+ - `msq_get_vector_store`
127
+ - `msq_delete_vector_store`
128
+ - `msq_list_vector_store_files`
129
+ - `msq_add_vector_store_file`
130
+ - `msq_get_vector_store_file`
131
+ - `msq_cancel_vector_store_session`
132
+
133
+ ### Files
134
+
135
+ - `msq_list_files`
136
+ - `msq_upload_file`
137
+ - `msq_get_file`
138
+ - `msq_delete_file`
139
+ - `msq_get_file_content`
140
+
141
+ ### Convenience
142
+
143
+ - `msq_list_user_collections`
144
+ - `msq_get_vector_store_file_details`
145
+
146
+ ## File Upload and Download Notes
147
+
148
+ `msq_upload_file` accepts:
149
+
150
+ - `filePath` (required)
151
+ - `purpose` (required)
152
+ - `relativePath` (optional)
153
+ - `collectionName` (optional)
154
+ - `filename` (optional override)
155
+
156
+ `msq_get_file_content` returns:
157
+
158
+ - `contentType`
159
+ - `contentLength`
160
+ - `bytesRead`
161
+ - `truncated`
162
+ - `base64`
163
+
164
+ If response content exceeds `maxBytes` (or `MSQ_DEFAULT_FILE_CONTENT_MAX_BYTES`), payload is truncated safely and reported via `truncated: true`.
165
+
166
+ ## Response Format
167
+
168
+ All tool handlers return deterministic JSON text strings. Parse text content on the client side if structured access is needed.
169
+
170
+ ## Usage Examples
171
+
172
+ ### JSON-RPC tools/call with hidden API key
173
+
174
+ ```json
175
+ {
176
+ "method": "tools/call",
177
+ "params": {
178
+ "name": "msq_list_models",
179
+ "arguments": {
180
+ "apiKey": "msq-..."
181
+ }
182
+ }
183
+ }
184
+ ```
185
+
186
+ ### JSON-RPC tools/call with body args
187
+
188
+ ```json
189
+ {
190
+ "method": "tools/call",
191
+ "params": {
192
+ "name": "msq_chat_completions",
193
+ "arguments": {
194
+ "model": "my-gpt4",
195
+ "messages": [
196
+ { "role": "user", "content": "Hello" }
197
+ ],
198
+ "apiKey": "msq-..."
199
+ }
200
+ }
201
+ }
202
+ ```
203
+
204
+ ### FastMCP-style client call
205
+
206
+ ```ts
207
+ await client.callTool('msq_embeddings', {
208
+ model: 'nomic-embed-text-v1.5',
209
+ input: ['First sentence', 'Second sentence'],
210
+ apiKey: 'msq-...',
211
+ })
212
+ ```
213
+
214
+ ## Development
215
+
216
+ Scripts:
217
+
218
+ - `yarn build`
219
+ - `yarn start`
220
+ - `yarn dev`
221
+ - `yarn inspect`
222
+ - `yarn test`
223
+ - `yarn test:coverage`
224
+
225
+ ## CI/CD
226
+
227
+ - `.github/workflows/build.yaml`: build + test on PR open/sync
228
+ - `.github/workflows/publish.yaml`: build + test + publish on `main` push (markdown-only changes ignored)
229
+
230
+ ## License
231
+
232
+ MIT
@@ -0,0 +1,20 @@
1
+ export declare const DEFAULT_HTTP_TIMEOUT_MS = 30000;
2
+ export declare const DEFAULT_FILE_CONTENT_MAX_BYTES = 1048576;
3
+ export interface AppConfig {
4
+ defaultApiKey: string | undefined;
5
+ defaultBaseUrl: string;
6
+ httpTimeoutMs: number;
7
+ defaultFileContentMaxBytes: number;
8
+ }
9
+ export interface ResolvedRequestConfig {
10
+ apiKey: string;
11
+ baseUrl: string;
12
+ httpTimeoutMs: number;
13
+ defaultFileContentMaxBytes: number;
14
+ }
15
+ export declare const appConfig: AppConfig;
16
+ /**
17
+ * Resolve authentication and base URL for a request.
18
+ * Hidden extra args take precedence over environment defaults.
19
+ */
20
+ export declare function resolveRequestConfig(extraArgs: Record<string, unknown> | undefined, defaults?: AppConfig): ResolvedRequestConfig;
package/dist/config.js ADDED
@@ -0,0 +1,77 @@
1
+ import { UserError } from '@missionsquad/fastmcp';
2
+ import dotenv from 'dotenv';
3
+ import { z } from 'zod';
4
+ import { MsqConfigError } from './errors.js';
5
+ dotenv.config();
6
+ const DEFAULT_BASE_URL = 'https://agents.missionsquad.ai/v1';
7
+ const EXPECTED_BASE_PATH_SUFFIX = '/v1';
8
+ export const DEFAULT_HTTP_TIMEOUT_MS = 30_000;
9
+ export const DEFAULT_FILE_CONTENT_MAX_BYTES = 1_048_576;
10
+ const EnvSchema = z.object({
11
+ MSQ_API_KEY: z.string().optional(),
12
+ MSQ_BASE_URL: z.string().optional(),
13
+ MSQ_HTTP_TIMEOUT_MS: z.coerce.number().int().positive().optional(),
14
+ MSQ_DEFAULT_FILE_CONTENT_MAX_BYTES: z.coerce.number().int().positive().optional(),
15
+ });
16
+ const env = EnvSchema.parse(process.env);
17
+ function normalizeBaseUrl(rawUrl) {
18
+ const trimmed = rawUrl.trim();
19
+ if (trimmed.length === 0) {
20
+ throw new MsqConfigError('MissionSquad base URL must be a non-empty string.');
21
+ }
22
+ let parsed;
23
+ try {
24
+ parsed = new URL(trimmed);
25
+ }
26
+ catch {
27
+ throw new MsqConfigError(`MissionSquad base URL is invalid: ${trimmed}`);
28
+ }
29
+ parsed.search = '';
30
+ parsed.hash = '';
31
+ const normalizedPath = parsed.pathname.replace(/\/+$/, '') || '/';
32
+ parsed.pathname = normalizedPath;
33
+ if (!normalizedPath.endsWith(EXPECTED_BASE_PATH_SUFFIX)) {
34
+ console.warn(`[mcp-msq] Base URL path "${normalizedPath}" does not end with "${EXPECTED_BASE_PATH_SUFFIX}".` +
35
+ ' MissionSquad API requests may fail if this is not a v1 API base URL.');
36
+ }
37
+ return parsed.toString().replace(/\/$/, '');
38
+ }
39
+ function readHiddenString(extraArgs, key) {
40
+ const value = extraArgs?.[key];
41
+ if (value === undefined) {
42
+ return undefined;
43
+ }
44
+ if (typeof value !== 'string') {
45
+ throw new UserError(`Hidden argument "${key}" must be a string when provided.`);
46
+ }
47
+ const trimmed = value.trim();
48
+ if (trimmed.length === 0) {
49
+ throw new UserError(`Hidden argument "${key}" must be a non-empty string when provided.`);
50
+ }
51
+ return trimmed;
52
+ }
53
+ export const appConfig = {
54
+ defaultApiKey: env.MSQ_API_KEY?.trim() || undefined,
55
+ defaultBaseUrl: normalizeBaseUrl(env.MSQ_BASE_URL ?? DEFAULT_BASE_URL),
56
+ httpTimeoutMs: env.MSQ_HTTP_TIMEOUT_MS ?? DEFAULT_HTTP_TIMEOUT_MS,
57
+ defaultFileContentMaxBytes: env.MSQ_DEFAULT_FILE_CONTENT_MAX_BYTES ?? DEFAULT_FILE_CONTENT_MAX_BYTES,
58
+ };
59
+ /**
60
+ * Resolve authentication and base URL for a request.
61
+ * Hidden extra args take precedence over environment defaults.
62
+ */
63
+ export function resolveRequestConfig(extraArgs, defaults = appConfig) {
64
+ const apiKey = readHiddenString(extraArgs, 'apiKey') ?? defaults.defaultApiKey;
65
+ if (apiKey === undefined || apiKey.trim().length === 0) {
66
+ throw new UserError('MissionSquad API key is required. Provide hidden argument "apiKey" or set MSQ_API_KEY.');
67
+ }
68
+ const hiddenBaseUrl = readHiddenString(extraArgs, 'baseUrl');
69
+ const baseUrl = hiddenBaseUrl ? normalizeBaseUrl(hiddenBaseUrl) : defaults.defaultBaseUrl;
70
+ return {
71
+ apiKey: apiKey.trim(),
72
+ baseUrl,
73
+ httpTimeoutMs: defaults.httpTimeoutMs,
74
+ defaultFileContentMaxBytes: defaults.defaultFileContentMaxBytes,
75
+ };
76
+ }
77
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import { UserError } from '@missionsquad/fastmcp';
2
+ export declare class MsqConfigError extends Error {
3
+ constructor(message: string);
4
+ }
5
+ export declare class MsqTransportError extends Error {
6
+ constructor(message: string, cause?: unknown);
7
+ }
8
+ export declare class MsqApiError extends Error {
9
+ readonly status: number;
10
+ readonly statusText: string;
11
+ readonly url: string;
12
+ readonly responseBody: unknown;
13
+ constructor(message: string, status: number, statusText: string, url: string, responseBody: unknown);
14
+ }
15
+ export declare function toUserError(error: unknown, prefix: string): UserError;
package/dist/errors.js ADDED
@@ -0,0 +1,75 @@
1
+ import { UserError } from '@missionsquad/fastmcp';
2
+ export class MsqConfigError extends Error {
3
+ constructor(message) {
4
+ super(message);
5
+ this.name = 'MsqConfigError';
6
+ }
7
+ }
8
+ export class MsqTransportError extends Error {
9
+ constructor(message, cause) {
10
+ super(message);
11
+ this.name = 'MsqTransportError';
12
+ if (cause !== undefined) {
13
+ this.cause = cause;
14
+ }
15
+ }
16
+ }
17
+ export class MsqApiError extends Error {
18
+ status;
19
+ statusText;
20
+ url;
21
+ responseBody;
22
+ constructor(message, status, statusText, url, responseBody) {
23
+ super(message);
24
+ this.status = status;
25
+ this.statusText = statusText;
26
+ this.url = url;
27
+ this.responseBody = responseBody;
28
+ this.name = 'MsqApiError';
29
+ }
30
+ }
31
+ function messageFromResponseBody(responseBody) {
32
+ if (typeof responseBody === 'string') {
33
+ const trimmed = responseBody.trim();
34
+ if (trimmed.length > 0)
35
+ return trimmed;
36
+ return 'No response body.';
37
+ }
38
+ if (responseBody === null || typeof responseBody !== 'object') {
39
+ return 'No response body.';
40
+ }
41
+ const record = responseBody;
42
+ const error = record.error;
43
+ if (typeof error === 'string' && error.trim().length > 0) {
44
+ return error;
45
+ }
46
+ if (error !== null && typeof error === 'object') {
47
+ const errorRecord = error;
48
+ const nestedMessage = errorRecord.message;
49
+ if (typeof nestedMessage === 'string' && nestedMessage.trim().length > 0) {
50
+ return nestedMessage;
51
+ }
52
+ }
53
+ const message = record.message;
54
+ if (typeof message === 'string' && message.trim().length > 0) {
55
+ return message;
56
+ }
57
+ return 'No response body.';
58
+ }
59
+ export function toUserError(error, prefix) {
60
+ if (error instanceof UserError) {
61
+ return error;
62
+ }
63
+ if (error instanceof MsqApiError) {
64
+ const bodyMessage = messageFromResponseBody(error.responseBody);
65
+ return new UserError(`${prefix}: MissionSquad API returned ${error.status} ${error.statusText}. ${bodyMessage}`);
66
+ }
67
+ if (error instanceof MsqConfigError || error instanceof MsqTransportError) {
68
+ return new UserError(`${prefix}: ${error.message}`);
69
+ }
70
+ if (error instanceof Error) {
71
+ return new UserError(`${prefix}: ${error.message}`);
72
+ }
73
+ return new UserError(`${prefix}: ${String(error)}`);
74
+ }
75
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,37 @@
1
+ #!/usr/bin/env node
2
+ import { FastMCP } from '@missionsquad/fastmcp';
3
+ import { routeConsoleStdoutToStderr } from './stdio-safe-console.js';
4
+ import { registerMissionSquadTools } from './tools.js';
5
+ routeConsoleStdoutToStderr();
6
+ const server = new FastMCP({
7
+ name: 'mcp-msq',
8
+ version: '0.1.0',
9
+ });
10
+ registerMissionSquadTools(server);
11
+ async function main() {
12
+ await server.start({ transportType: 'stdio' });
13
+ }
14
+ async function shutdown(exitCode) {
15
+ try {
16
+ await server.stop();
17
+ }
18
+ finally {
19
+ process.exit(exitCode);
20
+ }
21
+ }
22
+ process.on('SIGINT', () => {
23
+ void shutdown(0);
24
+ });
25
+ process.on('SIGTERM', () => {
26
+ void shutdown(0);
27
+ });
28
+ process.on('uncaughtException', () => {
29
+ void shutdown(1);
30
+ });
31
+ process.on('unhandledRejection', () => {
32
+ void shutdown(1);
33
+ });
34
+ void main().catch(() => {
35
+ void shutdown(1);
36
+ });
37
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAA;AAC/C,OAAO,EAAE,0BAA0B,EAAE,MAAM,yBAAyB,CAAA;AACpE,OAAO,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAA;AAEtD,0BAA0B,EAAE,CAAA;AAE5B,MAAM,MAAM,GAAG,IAAI,OAAO,CAAY;IACpC,IAAI,EAAE,SAAS;IACf,OAAO,EAAE,OAAO;CACjB,CAAC,CAAA;AAEF,yBAAyB,CAAC,MAAM,CAAC,CAAA;AAEjC,KAAK,UAAU,IAAI;IACjB,MAAM,MAAM,CAAC,KAAK,CAAC,EAAE,aAAa,EAAE,OAAO,EAAE,CAAC,CAAA;AAChD,CAAC;AAED,KAAK,UAAU,QAAQ,CAAC,QAAgB;IACtC,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,IAAI,EAAE,CAAA;IACrB,CAAC;YAAS,CAAC;QACT,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;IACxB,CAAC;AACH,CAAC;AAED,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;IACxB,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAA;AAClB,CAAC,CAAC,CAAA;AAEF,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE;IACzB,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAA;AAClB,CAAC,CAAC,CAAA;AAEF,OAAO,CAAC,EAAE,CAAC,mBAAmB,EAAE,GAAG,EAAE;IACnC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAA;AAClB,CAAC,CAAC,CAAA;AAEF,OAAO,CAAC,EAAE,CAAC,oBAAoB,EAAE,GAAG,EAAE;IACpC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAA;AAClB,CAAC,CAAC,CAAA;AAEF,KAAK,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE;IACrB,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAA;AAClB,CAAC,CAAC,CAAA"}
package/dist/json.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ /**
2
+ * MCP tools commonly return a string payload. This keeps output deterministic.
3
+ */
4
+ export declare function stringifyResult(value: unknown): string;
package/dist/json.js ADDED
@@ -0,0 +1,13 @@
1
+ /**
2
+ * MCP tools commonly return a string payload. This keeps output deterministic.
3
+ */
4
+ export function stringifyResult(value) {
5
+ const result = JSON.stringify(value, (_key, currentValue) => {
6
+ if (typeof currentValue === 'bigint') {
7
+ return currentValue.toString();
8
+ }
9
+ return currentValue;
10
+ }, 2);
11
+ return result ?? 'null';
12
+ }
13
+ //# sourceMappingURL=json.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json.js","sourceRoot":"","sources":["../src/json.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,KAAc;IAC5C,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAC3B,KAAK,EACL,CAAC,IAAI,EAAE,YAAY,EAAE,EAAE;QACrB,IAAI,OAAO,YAAY,KAAK,QAAQ,EAAE,CAAC;YACrC,OAAO,YAAY,CAAC,QAAQ,EAAE,CAAA;QAChC,CAAC;QACD,OAAO,YAAY,CAAA;IACrB,CAAC,EACD,CAAC,CACF,CAAA;IAED,OAAO,MAAM,IAAI,MAAM,CAAA;AACzB,CAAC"}
@@ -0,0 +1,42 @@
1
+ import { type ResolvedRequestConfig } from './config.js';
2
+ type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';
3
+ interface JsonRequestOptions {
4
+ method: HttpMethod;
5
+ path: string;
6
+ query?: Record<string, string | number | boolean | undefined>;
7
+ body?: unknown;
8
+ headers?: Record<string, string | undefined>;
9
+ }
10
+ interface FileUploadOptions {
11
+ filePath: string;
12
+ purpose: string;
13
+ relativePath?: string;
14
+ collectionName?: string;
15
+ filename?: string;
16
+ }
17
+ interface FileContentRequestOptions {
18
+ fileId: string;
19
+ maxBytes?: number;
20
+ }
21
+ interface FileContentResult {
22
+ contentType: string | null;
23
+ contentLength: number | null;
24
+ bytesRead: number;
25
+ truncated: boolean;
26
+ base64: string;
27
+ }
28
+ export declare class MissionSquadClient {
29
+ private readonly requestConfig;
30
+ constructor(requestConfig: ResolvedRequestConfig);
31
+ requestJson(options: JsonRequestOptions): Promise<unknown>;
32
+ uploadFile(options: FileUploadOptions): Promise<unknown>;
33
+ getFileContent(options: FileContentRequestOptions): Promise<FileContentResult>;
34
+ private buildUrl;
35
+ private compactHeaders;
36
+ private fetchWithTimeout;
37
+ private parseStructuredResponse;
38
+ private parseResponseBody;
39
+ private parseErrorPayload;
40
+ }
41
+ export declare function createMissionSquadClient(extraArgs: Record<string, unknown> | undefined): MissionSquadClient;
42
+ export {};