@anyproto/anytype-mcp 1.0.7 → 1.0.8
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/.github/workflows/ci.yml +4 -4
- package/.github/workflows/release.yml +4 -5
- package/README.md +5 -5
- package/bin/cli.mjs +100 -58
- package/package.json +28 -28
- package/scripts/tools.json +857 -219
- package/server.json +1 -1
- package/src/client/__tests__/http-client.test.ts +23 -17
- package/src/openapi/__tests__/parser.test.ts +136 -0
- package/src/openapi/parser.ts +6 -21
package/server.json
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
},
|
|
20
20
|
"environment_variables": [
|
|
21
21
|
{
|
|
22
|
-
"description": "JSON string of headers for Anytype API. Example: {\"Authorization\":\"Bearer <YOUR_API_KEY>\", \"Anytype-Version\":\"2025-
|
|
22
|
+
"description": "JSON string of headers for Anytype API. Example: {\"Authorization\":\"Bearer <YOUR_API_KEY>\", \"Anytype-Version\":\"2025-11-08\"}",
|
|
23
23
|
"is_required": true,
|
|
24
24
|
"format": "string",
|
|
25
25
|
"is_secret": true,
|
|
@@ -5,16 +5,19 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
5
5
|
import { HttpClient } from "../http-client";
|
|
6
6
|
|
|
7
7
|
// Mock the OpenAPIClientAxios initialization
|
|
8
|
+
const mockApi = {
|
|
9
|
+
getPet: vi.fn(),
|
|
10
|
+
testOperation: vi.fn(),
|
|
11
|
+
complexOperation: vi.fn(),
|
|
12
|
+
};
|
|
13
|
+
|
|
8
14
|
vi.mock("openapi-client-axios", () => {
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
};
|
|
15
|
+
const MockOpenAPIClientAxios = vi.fn(function (this: any) {
|
|
16
|
+
this.init = vi.fn().mockResolvedValue(mockApi);
|
|
17
|
+
return this;
|
|
18
|
+
});
|
|
14
19
|
return {
|
|
15
|
-
default:
|
|
16
|
-
init: vi.fn().mockResolvedValue(mockApi),
|
|
17
|
-
})),
|
|
20
|
+
default: MockOpenAPIClientAxios,
|
|
18
21
|
};
|
|
19
22
|
});
|
|
20
23
|
|
|
@@ -473,12 +476,13 @@ describe("HttpClient", () => {
|
|
|
473
476
|
testOperation: vi.fn().mockRejectedValue(errorResponse),
|
|
474
477
|
};
|
|
475
478
|
|
|
476
|
-
// Mock the OpenAPIClientAxios initialization
|
|
477
|
-
const MockOpenAPIClientAxios = vi.fn(
|
|
478
|
-
init
|
|
479
|
-
|
|
479
|
+
// Mock the OpenAPIClientAxios initialization - use function keyword for constructor support
|
|
480
|
+
const MockOpenAPIClientAxios = vi.fn(function (this: any) {
|
|
481
|
+
this.init = vi.fn().mockResolvedValue(mockAxiosInstance);
|
|
482
|
+
return this;
|
|
483
|
+
});
|
|
480
484
|
|
|
481
|
-
vi.mocked(OpenAPIClientAxios).mockImplementation(
|
|
485
|
+
vi.mocked(OpenAPIClientAxios).mockImplementation(MockOpenAPIClientAxios as any);
|
|
482
486
|
|
|
483
487
|
const client = new HttpClient(mockConfig, mockOpenApiSpec);
|
|
484
488
|
const operation = mockOpenApiSpec.paths["/test"]?.post;
|
|
@@ -510,11 +514,13 @@ describe("HttpClient", () => {
|
|
|
510
514
|
}),
|
|
511
515
|
};
|
|
512
516
|
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
517
|
+
// Mock the OpenAPIClientAxios initialization - use function keyword for constructor support
|
|
518
|
+
const MockOpenAPIClientAxios = vi.fn(function (this: any) {
|
|
519
|
+
this.init = vi.fn().mockResolvedValue(mockAxiosInstance);
|
|
520
|
+
return this;
|
|
521
|
+
});
|
|
516
522
|
|
|
517
|
-
vi.mocked(OpenAPIClientAxios).mockImplementation(
|
|
523
|
+
vi.mocked(OpenAPIClientAxios).mockImplementation(MockOpenAPIClientAxios as any);
|
|
518
524
|
|
|
519
525
|
const client = new HttpClient(mockConfig, mockOpenApiSpec);
|
|
520
526
|
const operation = mockOpenApiSpec.paths["/test"]?.post;
|
|
@@ -855,6 +855,142 @@ describe("OpenAPIToMCPConverter", () => {
|
|
|
855
855
|
description: "A schema description",
|
|
856
856
|
});
|
|
857
857
|
});
|
|
858
|
+
|
|
859
|
+
describe("Delete Operations Support", () => {
|
|
860
|
+
const deleteSpec: OpenAPIV3.Document = {
|
|
861
|
+
openapi: "3.0.0",
|
|
862
|
+
info: {
|
|
863
|
+
title: "Delete Test API",
|
|
864
|
+
version: "1.0.0",
|
|
865
|
+
},
|
|
866
|
+
paths: {
|
|
867
|
+
"/objects/{object_id}": {
|
|
868
|
+
delete: {
|
|
869
|
+
operationId: "delete_object",
|
|
870
|
+
summary: "Delete an object",
|
|
871
|
+
parameters: [
|
|
872
|
+
{
|
|
873
|
+
name: "object_id",
|
|
874
|
+
in: "path",
|
|
875
|
+
required: true,
|
|
876
|
+
description: "The ID of the object to delete",
|
|
877
|
+
schema: {
|
|
878
|
+
type: "string",
|
|
879
|
+
},
|
|
880
|
+
},
|
|
881
|
+
],
|
|
882
|
+
responses: {
|
|
883
|
+
"200": {
|
|
884
|
+
description: "Object deleted successfully",
|
|
885
|
+
content: {
|
|
886
|
+
"application/json": {
|
|
887
|
+
schema: {
|
|
888
|
+
type: "object",
|
|
889
|
+
properties: {
|
|
890
|
+
id: { type: "string" },
|
|
891
|
+
deleted: { type: "boolean" },
|
|
892
|
+
},
|
|
893
|
+
},
|
|
894
|
+
},
|
|
895
|
+
},
|
|
896
|
+
},
|
|
897
|
+
},
|
|
898
|
+
},
|
|
899
|
+
},
|
|
900
|
+
"/lists/{list_id}/objects/{object_id}": {
|
|
901
|
+
delete: {
|
|
902
|
+
operationId: "remove_list_object",
|
|
903
|
+
summary: "Remove object from list",
|
|
904
|
+
parameters: [
|
|
905
|
+
{
|
|
906
|
+
name: "list_id",
|
|
907
|
+
in: "path",
|
|
908
|
+
required: true,
|
|
909
|
+
description: "The ID of the list",
|
|
910
|
+
schema: { type: "string" },
|
|
911
|
+
},
|
|
912
|
+
{
|
|
913
|
+
name: "object_id",
|
|
914
|
+
in: "path",
|
|
915
|
+
required: true,
|
|
916
|
+
description: "The ID of the object to remove",
|
|
917
|
+
schema: { type: "string" },
|
|
918
|
+
},
|
|
919
|
+
],
|
|
920
|
+
responses: {
|
|
921
|
+
"200": {
|
|
922
|
+
description: "Object removed from list",
|
|
923
|
+
content: {
|
|
924
|
+
"application/json": {
|
|
925
|
+
schema: {
|
|
926
|
+
type: "object",
|
|
927
|
+
properties: {
|
|
928
|
+
success: { type: "boolean" },
|
|
929
|
+
},
|
|
930
|
+
},
|
|
931
|
+
},
|
|
932
|
+
},
|
|
933
|
+
},
|
|
934
|
+
},
|
|
935
|
+
},
|
|
936
|
+
},
|
|
937
|
+
},
|
|
938
|
+
};
|
|
939
|
+
|
|
940
|
+
it("should include delete operations in MCP tools", () => {
|
|
941
|
+
const converter = new OpenAPIToMCPConverter(deleteSpec);
|
|
942
|
+
const { tools, openApiLookup } = converter.convertToMCPTools();
|
|
943
|
+
|
|
944
|
+
expect(tools).toHaveProperty("API");
|
|
945
|
+
expect(tools.API.methods).toHaveLength(2);
|
|
946
|
+
|
|
947
|
+
const deleteObjectMethod = tools.API.methods.find((m) => m.name === "delete-object");
|
|
948
|
+
const removeListObjectMethod = tools.API.methods.find((m) => m.name === "remove-list-object");
|
|
949
|
+
|
|
950
|
+
expect(deleteObjectMethod).toBeDefined();
|
|
951
|
+
expect(removeListObjectMethod).toBeDefined();
|
|
952
|
+
|
|
953
|
+
// Check that delete operations are in the lookup
|
|
954
|
+
expect(openApiLookup).toHaveProperty("API-delete-object");
|
|
955
|
+
expect(openApiLookup).toHaveProperty("API-remove-list-object");
|
|
956
|
+
|
|
957
|
+
// Verify delete object method parameters
|
|
958
|
+
const deleteParams = getParamsFromSchema(deleteObjectMethod!);
|
|
959
|
+
expect(deleteParams).toContainEqual({
|
|
960
|
+
name: "object_id",
|
|
961
|
+
type: "string",
|
|
962
|
+
description: "The ID of the object to delete",
|
|
963
|
+
optional: false,
|
|
964
|
+
});
|
|
965
|
+
|
|
966
|
+
// Verify remove list object method parameters
|
|
967
|
+
const removeParams = getParamsFromSchema(removeListObjectMethod!);
|
|
968
|
+
expect(removeParams).toEqual(
|
|
969
|
+
expect.arrayContaining([
|
|
970
|
+
expect.objectContaining({
|
|
971
|
+
name: "list_id",
|
|
972
|
+
type: "string",
|
|
973
|
+
description: "The ID of the list",
|
|
974
|
+
optional: false,
|
|
975
|
+
}),
|
|
976
|
+
expect.objectContaining({
|
|
977
|
+
name: "object_id",
|
|
978
|
+
type: "string",
|
|
979
|
+
description: "The ID of the object to remove",
|
|
980
|
+
optional: false,
|
|
981
|
+
}),
|
|
982
|
+
]),
|
|
983
|
+
);
|
|
984
|
+
});
|
|
985
|
+
|
|
986
|
+
it("should handle delete operations with proper error responses", () => {
|
|
987
|
+
const converter = new OpenAPIToMCPConverter(deleteSpec);
|
|
988
|
+
const { tools } = converter.convertToMCPTools();
|
|
989
|
+
|
|
990
|
+
const deleteObjectMethod = tools.API.methods.find((m) => m.name === "delete-object");
|
|
991
|
+
expect(deleteObjectMethod?.description).toContain("Delete an object");
|
|
992
|
+
});
|
|
993
|
+
});
|
|
858
994
|
});
|
|
859
995
|
|
|
860
996
|
// Additional complex test scenarios as a table test
|
package/src/openapi/parser.ts
CHANGED
|
@@ -327,13 +327,8 @@ export class OpenAPIToMCPConverter {
|
|
|
327
327
|
if (!pathItem) continue;
|
|
328
328
|
|
|
329
329
|
for (const [method, operation] of Object.entries(pathItem)) {
|
|
330
|
-
// skip "Auth" operations
|
|
331
|
-
if (
|
|
332
|
-
!this.isOperation(method, operation) ||
|
|
333
|
-
operation.tags?.includes("Auth") ||
|
|
334
|
-
method.toLowerCase() === "delete"
|
|
335
|
-
)
|
|
336
|
-
continue;
|
|
330
|
+
// skip "Auth" operations, as they shouldn't be called by mcp client
|
|
331
|
+
if (!this.isOperation(method, operation) || operation.tags?.includes("Auth")) continue;
|
|
337
332
|
|
|
338
333
|
const mcpMethod = this.convertOperationToMCPMethod(operation, method, path);
|
|
339
334
|
if (mcpMethod) {
|
|
@@ -360,13 +355,8 @@ export class OpenAPIToMCPConverter {
|
|
|
360
355
|
if (!pathItem) continue;
|
|
361
356
|
|
|
362
357
|
for (const [method, operation] of Object.entries(pathItem)) {
|
|
363
|
-
// skip "Auth" operations
|
|
364
|
-
if (
|
|
365
|
-
!this.isOperation(method, operation) ||
|
|
366
|
-
operation.tags?.includes("Auth") ||
|
|
367
|
-
method.toLowerCase() === "delete"
|
|
368
|
-
)
|
|
369
|
-
continue;
|
|
358
|
+
// skip "Auth" operations, as they shouldn't be called by mcp client
|
|
359
|
+
if (!this.isOperation(method, operation) || operation.tags?.includes("Auth")) continue;
|
|
370
360
|
|
|
371
361
|
const parameters = this.convertOperationToJsonSchema(operation, method, path);
|
|
372
362
|
const tool: ChatCompletionTool = {
|
|
@@ -394,13 +384,8 @@ export class OpenAPIToMCPConverter {
|
|
|
394
384
|
if (!pathItem) continue;
|
|
395
385
|
|
|
396
386
|
for (const [method, operation] of Object.entries(pathItem)) {
|
|
397
|
-
// skip "Auth" operations
|
|
398
|
-
if (
|
|
399
|
-
!this.isOperation(method, operation) ||
|
|
400
|
-
operation.tags?.includes("Auth") ||
|
|
401
|
-
method.toLowerCase() === "delete"
|
|
402
|
-
)
|
|
403
|
-
continue;
|
|
387
|
+
// skip "Auth" operations, as they shouldn't be called by mcp client
|
|
388
|
+
if (!this.isOperation(method, operation) || operation.tags?.includes("Auth")) continue;
|
|
404
389
|
|
|
405
390
|
const parameters = this.convertOperationToJsonSchema(operation, method, path);
|
|
406
391
|
const tool: Tool = {
|