feishu-user-plugin 1.2.1 → 1.3.1
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 +103 -39
- package/package.json +5 -3
- package/scripts/confirm-version.js +28 -0
- package/scripts/mcp_stdio_bridge.js +97 -0
- package/skills/feishu-user-plugin/references/CLAUDE.md +338 -61
- package/src/cli.js +12 -7
- package/src/config.js +202 -27
- package/src/index.js +429 -55
- package/src/oauth.js +2 -1
- package/src/official.js +313 -1
- package/src/setup.js +19 -3
package/src/index.js
CHANGED
|
@@ -541,49 +541,9 @@ const TOOLS = [
|
|
|
541
541
|
required: ['app_token', 'table_id'],
|
|
542
542
|
},
|
|
543
543
|
},
|
|
544
|
-
{
|
|
545
|
-
name: 'create_bitable_record',
|
|
546
|
-
description: '[Official API] Create a new record (row) in a Bitable table.',
|
|
547
|
-
inputSchema: {
|
|
548
|
-
type: 'object',
|
|
549
|
-
properties: {
|
|
550
|
-
app_token: { type: 'string', description: 'Bitable app token' },
|
|
551
|
-
table_id: { type: 'string', description: 'Table ID' },
|
|
552
|
-
fields: { type: 'object', description: 'Field name → value mapping' },
|
|
553
|
-
},
|
|
554
|
-
required: ['app_token', 'table_id', 'fields'],
|
|
555
|
-
},
|
|
556
|
-
},
|
|
557
|
-
{
|
|
558
|
-
name: 'update_bitable_record',
|
|
559
|
-
description: '[Official API] Update an existing record in a Bitable table.',
|
|
560
|
-
inputSchema: {
|
|
561
|
-
type: 'object',
|
|
562
|
-
properties: {
|
|
563
|
-
app_token: { type: 'string', description: 'Bitable app token' },
|
|
564
|
-
table_id: { type: 'string', description: 'Table ID' },
|
|
565
|
-
record_id: { type: 'string', description: 'Record ID to update' },
|
|
566
|
-
fields: { type: 'object', description: 'Field name → new value mapping' },
|
|
567
|
-
},
|
|
568
|
-
required: ['app_token', 'table_id', 'record_id', 'fields'],
|
|
569
|
-
},
|
|
570
|
-
},
|
|
571
|
-
{
|
|
572
|
-
name: 'delete_bitable_record',
|
|
573
|
-
description: '[Official API] Delete a record (row) from a Bitable table.',
|
|
574
|
-
inputSchema: {
|
|
575
|
-
type: 'object',
|
|
576
|
-
properties: {
|
|
577
|
-
app_token: { type: 'string', description: 'Bitable app token' },
|
|
578
|
-
table_id: { type: 'string', description: 'Table ID' },
|
|
579
|
-
record_id: { type: 'string', description: 'Record ID to delete' },
|
|
580
|
-
},
|
|
581
|
-
required: ['app_token', 'table_id', 'record_id'],
|
|
582
|
-
},
|
|
583
|
-
},
|
|
584
544
|
{
|
|
585
545
|
name: 'batch_create_bitable_records',
|
|
586
|
-
description: '[Official API]
|
|
546
|
+
description: '[Official API] Create one or more records (rows) in a Bitable table. Pass a single record or up to 500.',
|
|
587
547
|
inputSchema: {
|
|
588
548
|
type: 'object',
|
|
589
549
|
properties: {
|
|
@@ -596,7 +556,7 @@ const TOOLS = [
|
|
|
596
556
|
},
|
|
597
557
|
{
|
|
598
558
|
name: 'batch_update_bitable_records',
|
|
599
|
-
description: '[Official API]
|
|
559
|
+
description: '[Official API] Update one or more records in a Bitable table. Pass a single record or up to 500.',
|
|
600
560
|
inputSchema: {
|
|
601
561
|
type: 'object',
|
|
602
562
|
properties: {
|
|
@@ -609,7 +569,7 @@ const TOOLS = [
|
|
|
609
569
|
},
|
|
610
570
|
{
|
|
611
571
|
name: 'batch_delete_bitable_records',
|
|
612
|
-
description: '[Official API]
|
|
572
|
+
description: '[Official API] Delete one or more records from a Bitable table. Pass a single ID or up to 500.',
|
|
613
573
|
inputSchema: {
|
|
614
574
|
type: 'object',
|
|
615
575
|
properties: {
|
|
@@ -710,6 +670,313 @@ const TOOLS = [
|
|
|
710
670
|
},
|
|
711
671
|
},
|
|
712
672
|
},
|
|
673
|
+
|
|
674
|
+
// ========== IM — Bot Send / Edit / Delete ==========
|
|
675
|
+
{
|
|
676
|
+
name: 'send_message_as_bot',
|
|
677
|
+
description: '[Official API] Send a message as the bot to any chat. Supports text, post, interactive, etc.',
|
|
678
|
+
inputSchema: {
|
|
679
|
+
type: 'object',
|
|
680
|
+
properties: {
|
|
681
|
+
chat_id: { type: 'string', description: 'Target chat_id (oc_xxx) or open_id' },
|
|
682
|
+
msg_type: { type: 'string', description: 'Message type: text, post, image, interactive, etc.', enum: ['text', 'post', 'image', 'interactive', 'share_chat', 'share_user', 'audio', 'media', 'file', 'sticker'] },
|
|
683
|
+
content: { description: 'Message content (string or object, auto-serialized). For text: {"text":"hello"}' },
|
|
684
|
+
},
|
|
685
|
+
required: ['chat_id', 'msg_type', 'content'],
|
|
686
|
+
},
|
|
687
|
+
},
|
|
688
|
+
{
|
|
689
|
+
name: 'delete_message',
|
|
690
|
+
description: '[Official API] Recall/delete a message (bot can only delete its own messages).',
|
|
691
|
+
inputSchema: {
|
|
692
|
+
type: 'object',
|
|
693
|
+
properties: { message_id: { type: 'string', description: 'Message ID (om_xxx)' } },
|
|
694
|
+
required: ['message_id'],
|
|
695
|
+
},
|
|
696
|
+
},
|
|
697
|
+
{
|
|
698
|
+
name: 'update_message',
|
|
699
|
+
description: '[Official API] Edit a sent message (bot can only edit its own messages). Supports text and post.',
|
|
700
|
+
inputSchema: {
|
|
701
|
+
type: 'object',
|
|
702
|
+
properties: {
|
|
703
|
+
message_id: { type: 'string', description: 'Message ID (om_xxx)' },
|
|
704
|
+
msg_type: { type: 'string', description: 'Message type: text or post' },
|
|
705
|
+
content: { description: 'New content. For text: {"text":"updated text"}' },
|
|
706
|
+
},
|
|
707
|
+
required: ['message_id', 'msg_type', 'content'],
|
|
708
|
+
},
|
|
709
|
+
},
|
|
710
|
+
|
|
711
|
+
// ========== IM — Reactions ==========
|
|
712
|
+
{
|
|
713
|
+
name: 'add_reaction',
|
|
714
|
+
description: '[Official API] Add an emoji reaction to a message.',
|
|
715
|
+
inputSchema: {
|
|
716
|
+
type: 'object',
|
|
717
|
+
properties: {
|
|
718
|
+
message_id: { type: 'string', description: 'Message ID (om_xxx)' },
|
|
719
|
+
emoji_type: { type: 'string', description: 'Emoji type string, e.g. "THUMBSUP", "SMILE", "HEART"' },
|
|
720
|
+
},
|
|
721
|
+
required: ['message_id', 'emoji_type'],
|
|
722
|
+
},
|
|
723
|
+
},
|
|
724
|
+
{
|
|
725
|
+
name: 'delete_reaction',
|
|
726
|
+
description: '[Official API] Remove an emoji reaction from a message.',
|
|
727
|
+
inputSchema: {
|
|
728
|
+
type: 'object',
|
|
729
|
+
properties: {
|
|
730
|
+
message_id: { type: 'string', description: 'Message ID' },
|
|
731
|
+
reaction_id: { type: 'string', description: 'Reaction ID (from add_reaction response)' },
|
|
732
|
+
},
|
|
733
|
+
required: ['message_id', 'reaction_id'],
|
|
734
|
+
},
|
|
735
|
+
},
|
|
736
|
+
|
|
737
|
+
// ========== IM — Pin Messages ==========
|
|
738
|
+
{
|
|
739
|
+
name: 'pin_message',
|
|
740
|
+
description: '[Official API] Pin or unpin a message in a chat.',
|
|
741
|
+
inputSchema: {
|
|
742
|
+
type: 'object',
|
|
743
|
+
properties: {
|
|
744
|
+
message_id: { type: 'string', description: 'Message ID' },
|
|
745
|
+
pinned: { type: 'boolean', description: 'true to pin, false to unpin', default: true },
|
|
746
|
+
},
|
|
747
|
+
required: ['message_id'],
|
|
748
|
+
},
|
|
749
|
+
},
|
|
750
|
+
|
|
751
|
+
// ========== IM — Chat Management ==========
|
|
752
|
+
{
|
|
753
|
+
name: 'create_group',
|
|
754
|
+
description: '[Official API] Create a new group chat (as bot). Can add initial members.',
|
|
755
|
+
inputSchema: {
|
|
756
|
+
type: 'object',
|
|
757
|
+
properties: {
|
|
758
|
+
name: { type: 'string', description: 'Group name' },
|
|
759
|
+
description: { type: 'string', description: 'Group description (optional)' },
|
|
760
|
+
user_ids: { type: 'array', items: { type: 'string' }, description: 'Initial member open_ids (optional)' },
|
|
761
|
+
},
|
|
762
|
+
required: ['name'],
|
|
763
|
+
},
|
|
764
|
+
},
|
|
765
|
+
{
|
|
766
|
+
name: 'update_group',
|
|
767
|
+
description: '[Official API] Update group chat name or description.',
|
|
768
|
+
inputSchema: {
|
|
769
|
+
type: 'object',
|
|
770
|
+
properties: {
|
|
771
|
+
chat_id: { type: 'string', description: 'Chat ID (oc_xxx)' },
|
|
772
|
+
name: { type: 'string', description: 'New group name (optional)' },
|
|
773
|
+
description: { type: 'string', description: 'New description (optional)' },
|
|
774
|
+
},
|
|
775
|
+
required: ['chat_id'],
|
|
776
|
+
},
|
|
777
|
+
},
|
|
778
|
+
{
|
|
779
|
+
name: 'list_members',
|
|
780
|
+
description: '[Official API] List all members in a group chat.',
|
|
781
|
+
inputSchema: {
|
|
782
|
+
type: 'object',
|
|
783
|
+
properties: {
|
|
784
|
+
chat_id: { type: 'string', description: 'Chat ID (oc_xxx)' },
|
|
785
|
+
page_size: { type: 'number', description: 'Items per page (default 50)' },
|
|
786
|
+
page_token: { type: 'string', description: 'Pagination token' },
|
|
787
|
+
},
|
|
788
|
+
required: ['chat_id'],
|
|
789
|
+
},
|
|
790
|
+
},
|
|
791
|
+
{
|
|
792
|
+
name: 'manage_members',
|
|
793
|
+
description: '[Official API] Add or remove members from a group chat.',
|
|
794
|
+
inputSchema: {
|
|
795
|
+
type: 'object',
|
|
796
|
+
properties: {
|
|
797
|
+
chat_id: { type: 'string', description: 'Group chat ID (oc_xxx)' },
|
|
798
|
+
member_ids: { type: 'array', items: { type: 'string' }, description: 'Array of user open_ids' },
|
|
799
|
+
action: { type: 'string', enum: ['add', 'remove'], description: 'Action to perform' },
|
|
800
|
+
},
|
|
801
|
+
required: ['chat_id', 'member_ids', 'action'],
|
|
802
|
+
},
|
|
803
|
+
},
|
|
804
|
+
|
|
805
|
+
// ========== Docs — Block Editing ==========
|
|
806
|
+
{
|
|
807
|
+
name: 'create_doc_block',
|
|
808
|
+
description: '[Official API] Insert content blocks into a document. Add text, headings, lists, etc. after create_doc.',
|
|
809
|
+
inputSchema: {
|
|
810
|
+
type: 'object',
|
|
811
|
+
properties: {
|
|
812
|
+
document_id: { type: 'string', description: 'Document ID' },
|
|
813
|
+
parent_block_id: { type: 'string', description: 'Parent block ID (use document_id for root)' },
|
|
814
|
+
children: { type: 'array', description: 'Array of block objects to insert. E.g. [{block_type:2, text:{elements:[{text_run:{content:"Hello"}}]}}]', items: { type: 'object' } },
|
|
815
|
+
index: { type: 'number', description: 'Insert position (optional, appends to end if omitted)' },
|
|
816
|
+
},
|
|
817
|
+
required: ['document_id', 'parent_block_id', 'children'],
|
|
818
|
+
},
|
|
819
|
+
},
|
|
820
|
+
{
|
|
821
|
+
name: 'update_doc_block',
|
|
822
|
+
description: '[Official API] Update a specific block in a document (change text content, style, etc.).',
|
|
823
|
+
inputSchema: {
|
|
824
|
+
type: 'object',
|
|
825
|
+
properties: {
|
|
826
|
+
document_id: { type: 'string', description: 'Document ID' },
|
|
827
|
+
block_id: { type: 'string', description: 'Block ID to update' },
|
|
828
|
+
update_body: { type: 'object', description: 'Update payload. E.g. {update_text_elements:{elements:[{text_run:{content:"new text"}}]}}' },
|
|
829
|
+
},
|
|
830
|
+
required: ['document_id', 'block_id', 'update_body'],
|
|
831
|
+
},
|
|
832
|
+
},
|
|
833
|
+
{
|
|
834
|
+
name: 'delete_doc_blocks',
|
|
835
|
+
description: '[Official API] Delete a range of blocks from a document.',
|
|
836
|
+
inputSchema: {
|
|
837
|
+
type: 'object',
|
|
838
|
+
properties: {
|
|
839
|
+
document_id: { type: 'string', description: 'Document ID' },
|
|
840
|
+
parent_block_id: { type: 'string', description: 'Parent block ID containing the blocks to delete' },
|
|
841
|
+
start_index: { type: 'number', description: 'Start index (inclusive)' },
|
|
842
|
+
end_index: { type: 'number', description: 'End index (exclusive)' },
|
|
843
|
+
},
|
|
844
|
+
required: ['document_id', 'parent_block_id', 'start_index', 'end_index'],
|
|
845
|
+
},
|
|
846
|
+
},
|
|
847
|
+
|
|
848
|
+
// ========== Bitable — Additional ==========
|
|
849
|
+
{
|
|
850
|
+
name: 'get_bitable_record',
|
|
851
|
+
description: '[Official API] Get a single record by ID from a Bitable table.',
|
|
852
|
+
inputSchema: {
|
|
853
|
+
type: 'object',
|
|
854
|
+
properties: {
|
|
855
|
+
app_token: { type: 'string', description: 'Bitable app token' },
|
|
856
|
+
table_id: { type: 'string', description: 'Table ID' },
|
|
857
|
+
record_id: { type: 'string', description: 'Record ID' },
|
|
858
|
+
},
|
|
859
|
+
required: ['app_token', 'table_id', 'record_id'],
|
|
860
|
+
},
|
|
861
|
+
},
|
|
862
|
+
{
|
|
863
|
+
name: 'delete_bitable_table',
|
|
864
|
+
description: '[Official API] Delete a data table from a Bitable app.',
|
|
865
|
+
inputSchema: {
|
|
866
|
+
type: 'object',
|
|
867
|
+
properties: {
|
|
868
|
+
app_token: { type: 'string', description: 'Bitable app token' },
|
|
869
|
+
table_id: { type: 'string', description: 'Table ID to delete' },
|
|
870
|
+
},
|
|
871
|
+
required: ['app_token', 'table_id'],
|
|
872
|
+
},
|
|
873
|
+
},
|
|
874
|
+
|
|
875
|
+
{
|
|
876
|
+
name: 'get_bitable_meta',
|
|
877
|
+
description: '[Official API] Get metadata of a Bitable app (name, revision, etc.).',
|
|
878
|
+
inputSchema: {
|
|
879
|
+
type: 'object',
|
|
880
|
+
properties: {
|
|
881
|
+
app_token: { type: 'string', description: 'Bitable app token' },
|
|
882
|
+
},
|
|
883
|
+
required: ['app_token'],
|
|
884
|
+
},
|
|
885
|
+
},
|
|
886
|
+
{
|
|
887
|
+
name: 'update_bitable_table',
|
|
888
|
+
description: '[Official API] Rename a data table in a Bitable app.',
|
|
889
|
+
inputSchema: {
|
|
890
|
+
type: 'object',
|
|
891
|
+
properties: {
|
|
892
|
+
app_token: { type: 'string', description: 'Bitable app token' },
|
|
893
|
+
table_id: { type: 'string', description: 'Table ID' },
|
|
894
|
+
name: { type: 'string', description: 'New table name' },
|
|
895
|
+
},
|
|
896
|
+
required: ['app_token', 'table_id', 'name'],
|
|
897
|
+
},
|
|
898
|
+
},
|
|
899
|
+
{
|
|
900
|
+
name: 'create_bitable_view',
|
|
901
|
+
description: '[Official API] Create a new view in a Bitable table.',
|
|
902
|
+
inputSchema: {
|
|
903
|
+
type: 'object',
|
|
904
|
+
properties: {
|
|
905
|
+
app_token: { type: 'string', description: 'Bitable app token' },
|
|
906
|
+
table_id: { type: 'string', description: 'Table ID' },
|
|
907
|
+
view_name: { type: 'string', description: 'View name' },
|
|
908
|
+
view_type: { type: 'string', description: 'View type: grid (default), kanban, gallery, form, gantt, calendar', default: 'grid' },
|
|
909
|
+
},
|
|
910
|
+
required: ['app_token', 'table_id', 'view_name'],
|
|
911
|
+
},
|
|
912
|
+
},
|
|
913
|
+
{
|
|
914
|
+
name: 'delete_bitable_view',
|
|
915
|
+
description: '[Official API] Delete a view from a Bitable table.',
|
|
916
|
+
inputSchema: {
|
|
917
|
+
type: 'object',
|
|
918
|
+
properties: {
|
|
919
|
+
app_token: { type: 'string', description: 'Bitable app token' },
|
|
920
|
+
table_id: { type: 'string', description: 'Table ID' },
|
|
921
|
+
view_id: { type: 'string', description: 'View ID to delete' },
|
|
922
|
+
},
|
|
923
|
+
required: ['app_token', 'table_id', 'view_id'],
|
|
924
|
+
},
|
|
925
|
+
},
|
|
926
|
+
{
|
|
927
|
+
name: 'copy_bitable',
|
|
928
|
+
description: '[Official API] Copy a Bitable app to create a new one.',
|
|
929
|
+
inputSchema: {
|
|
930
|
+
type: 'object',
|
|
931
|
+
properties: {
|
|
932
|
+
app_token: { type: 'string', description: 'Bitable app token to copy' },
|
|
933
|
+
name: { type: 'string', description: 'New Bitable name' },
|
|
934
|
+
folder_id: { type: 'string', description: 'Destination folder token (optional)' },
|
|
935
|
+
},
|
|
936
|
+
required: ['app_token', 'name'],
|
|
937
|
+
},
|
|
938
|
+
},
|
|
939
|
+
|
|
940
|
+
// ========== Drive — File Operations ==========
|
|
941
|
+
{
|
|
942
|
+
name: 'copy_file',
|
|
943
|
+
description: '[Official API] Copy a file/doc in Drive.',
|
|
944
|
+
inputSchema: {
|
|
945
|
+
type: 'object',
|
|
946
|
+
properties: {
|
|
947
|
+
file_token: { type: 'string', description: 'File token to copy' },
|
|
948
|
+
name: { type: 'string', description: 'New file name' },
|
|
949
|
+
folder_token: { type: 'string', description: 'Destination folder token (optional)' },
|
|
950
|
+
type: { type: 'string', description: 'File type: file, doc, sheet, bitable, docx, mindnote, slides (optional)' },
|
|
951
|
+
},
|
|
952
|
+
required: ['file_token', 'name'],
|
|
953
|
+
},
|
|
954
|
+
},
|
|
955
|
+
{
|
|
956
|
+
name: 'move_file',
|
|
957
|
+
description: '[Official API] Move a file to another folder in Drive.',
|
|
958
|
+
inputSchema: {
|
|
959
|
+
type: 'object',
|
|
960
|
+
properties: {
|
|
961
|
+
file_token: { type: 'string', description: 'File token to move' },
|
|
962
|
+
folder_token: { type: 'string', description: 'Destination folder token' },
|
|
963
|
+
},
|
|
964
|
+
required: ['file_token', 'folder_token'],
|
|
965
|
+
},
|
|
966
|
+
},
|
|
967
|
+
{
|
|
968
|
+
name: 'delete_file',
|
|
969
|
+
description: '[Official API] Delete a file/folder from Drive.',
|
|
970
|
+
inputSchema: {
|
|
971
|
+
type: 'object',
|
|
972
|
+
properties: {
|
|
973
|
+
file_token: { type: 'string', description: 'File token to delete' },
|
|
974
|
+
type: { type: 'string', description: 'Type: file, folder, doc, sheet, bitable, docx, mindnote, slides' },
|
|
975
|
+
},
|
|
976
|
+
required: ['file_token'],
|
|
977
|
+
},
|
|
978
|
+
},
|
|
979
|
+
|
|
713
980
|
];
|
|
714
981
|
|
|
715
982
|
// --- Server ---
|
|
@@ -953,14 +1220,33 @@ async function handleTool(name, args) {
|
|
|
953
1220
|
return json(await getOfficialClient().readDoc(args.document_id));
|
|
954
1221
|
case 'get_doc_blocks':
|
|
955
1222
|
return json(await getOfficialClient().getDocBlocks(args.document_id));
|
|
956
|
-
case 'create_doc':
|
|
957
|
-
|
|
1223
|
+
case 'create_doc': {
|
|
1224
|
+
const official = getOfficialClient();
|
|
1225
|
+
if (official.hasUAT) {
|
|
1226
|
+
try {
|
|
1227
|
+
const result = await official.createDocAsUser(args.title, args.folder_id);
|
|
1228
|
+
return text(`Document created (as user): ${result.documentId}`);
|
|
1229
|
+
} catch (e) {
|
|
1230
|
+
console.error(`[feishu-user-plugin] UAT createDoc failed, falling back to app: ${e.message}`);
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
return text(`Document created: ${(await official.createDoc(args.title, args.folder_id)).documentId}`);
|
|
1234
|
+
}
|
|
958
1235
|
|
|
959
1236
|
// --- Official API: Bitable ---
|
|
960
1237
|
|
|
961
1238
|
case 'create_bitable': {
|
|
962
|
-
const
|
|
963
|
-
|
|
1239
|
+
const official = getOfficialClient();
|
|
1240
|
+
if (official.hasUAT) {
|
|
1241
|
+
try {
|
|
1242
|
+
const r = await official.createBitableAsUser(args.name, args.folder_id);
|
|
1243
|
+
return text(`Bitable created (as user): ${r.appToken}\nURL: ${r.url || ''}`);
|
|
1244
|
+
} catch (e) {
|
|
1245
|
+
console.error(`[feishu-user-plugin] UAT createBitable failed, falling back to app: ${e.message}`);
|
|
1246
|
+
}
|
|
1247
|
+
}
|
|
1248
|
+
const r = await official.createBitable(args.name, args.folder_id);
|
|
1249
|
+
return text(`Bitable created: ${r.appToken}\nURL: ${r.url || ''}`);
|
|
964
1250
|
}
|
|
965
1251
|
case 'list_bitable_tables':
|
|
966
1252
|
return json(await getOfficialClient().listBitableTables(args.app_token));
|
|
@@ -990,12 +1276,6 @@ async function handleTool(name, args) {
|
|
|
990
1276
|
return json(await getOfficialClient().searchBitableRecords(args.app_token, args.table_id, {
|
|
991
1277
|
filter: args.filter, sort: args.sort, pageSize: args.page_size,
|
|
992
1278
|
}));
|
|
993
|
-
case 'create_bitable_record':
|
|
994
|
-
return text(`Record created: ${(await getOfficialClient().createBitableRecord(args.app_token, args.table_id, args.fields)).recordId}`);
|
|
995
|
-
case 'update_bitable_record':
|
|
996
|
-
return text(`Record updated: ${(await getOfficialClient().updateBitableRecord(args.app_token, args.table_id, args.record_id, args.fields)).recordId}`);
|
|
997
|
-
case 'delete_bitable_record':
|
|
998
|
-
return text(`Record deleted: ${(await getOfficialClient().deleteBitableRecord(args.app_token, args.table_id, args.record_id)).deleted}`);
|
|
999
1279
|
case 'batch_create_bitable_records':
|
|
1000
1280
|
return json(await getOfficialClient().batchCreateBitableRecords(args.app_token, args.table_id, args.records));
|
|
1001
1281
|
case 'batch_update_bitable_records':
|
|
@@ -1016,8 +1296,17 @@ async function handleTool(name, args) {
|
|
|
1016
1296
|
|
|
1017
1297
|
case 'list_files':
|
|
1018
1298
|
return json(await getOfficialClient().listFiles(args.folder_token));
|
|
1019
|
-
case 'create_folder':
|
|
1020
|
-
|
|
1299
|
+
case 'create_folder': {
|
|
1300
|
+
const official = getOfficialClient();
|
|
1301
|
+
if (official.hasUAT) {
|
|
1302
|
+
try {
|
|
1303
|
+
return text(`Folder created (as user): ${(await official.createFolderAsUser(args.name, args.parent_token)).token}`);
|
|
1304
|
+
} catch (e) {
|
|
1305
|
+
console.error(`[feishu-user-plugin] UAT createFolder failed, falling back to app: ${e.message}`);
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1308
|
+
return text(`Folder created: ${(await official.createFolder(args.name, args.parent_token)).token}`);
|
|
1309
|
+
}
|
|
1021
1310
|
|
|
1022
1311
|
// --- Official API: Contact ---
|
|
1023
1312
|
|
|
@@ -1035,11 +1324,96 @@ async function handleTool(name, args) {
|
|
|
1035
1324
|
return text(`File uploaded: ${r.fileKey}\nUse this file_key with send_file_as_user to send it.`);
|
|
1036
1325
|
}
|
|
1037
1326
|
|
|
1327
|
+
// --- Official API: Bot Send / Edit / Delete ---
|
|
1328
|
+
|
|
1329
|
+
case 'send_message_as_bot': {
|
|
1330
|
+
const r = await getOfficialClient().sendMessageAsBot(args.chat_id, args.msg_type, args.content);
|
|
1331
|
+
return text(`Message sent (bot): ${r.messageId}`);
|
|
1332
|
+
}
|
|
1333
|
+
case 'delete_message':
|
|
1334
|
+
return text(`Message deleted: ${(await getOfficialClient().deleteMessage(args.message_id)).deleted}`);
|
|
1335
|
+
case 'update_message':
|
|
1336
|
+
return text(`Message updated: ${(await getOfficialClient().updateMessage(args.message_id, args.msg_type, args.content)).messageId}`);
|
|
1337
|
+
|
|
1338
|
+
// --- Official API: Reactions ---
|
|
1339
|
+
|
|
1340
|
+
case 'add_reaction':
|
|
1341
|
+
return text(`Reaction added: ${(await getOfficialClient().addReaction(args.message_id, args.emoji_type)).reactionId}`);
|
|
1342
|
+
case 'delete_reaction':
|
|
1343
|
+
return text(`Reaction removed: ${(await getOfficialClient().deleteReaction(args.message_id, args.reaction_id)).deleted}`);
|
|
1344
|
+
|
|
1345
|
+
// --- Official API: Pins ---
|
|
1346
|
+
|
|
1347
|
+
case 'pin_message':
|
|
1348
|
+
return json(await getOfficialClient().pinMessage(args.message_id, args.pinned !== false));
|
|
1349
|
+
|
|
1350
|
+
// --- Official API: Chat Management ---
|
|
1351
|
+
|
|
1352
|
+
case 'create_group':
|
|
1353
|
+
return text(`Group created: ${(await getOfficialClient().createChat({ name: args.name, description: args.description, userIds: args.user_ids })).chatId}`);
|
|
1354
|
+
case 'update_group':
|
|
1355
|
+
return text(`Group updated: ${(await getOfficialClient().updateChat(args.chat_id, { name: args.name, description: args.description })).updated}`);
|
|
1356
|
+
case 'list_members':
|
|
1357
|
+
return json(await getOfficialClient().listChatMembers(args.chat_id, { pageSize: args.page_size, pageToken: args.page_token }));
|
|
1358
|
+
case 'manage_members': {
|
|
1359
|
+
const official = getOfficialClient();
|
|
1360
|
+
if (args.action === 'remove') {
|
|
1361
|
+
return json(await official.removeChatMembers(args.chat_id, args.member_ids));
|
|
1362
|
+
}
|
|
1363
|
+
return json(await official.addChatMembers(args.chat_id, args.member_ids));
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1366
|
+
// --- Official API: Doc Block Editing ---
|
|
1367
|
+
|
|
1368
|
+
case 'create_doc_block':
|
|
1369
|
+
return json(await getOfficialClient().createDocBlock(args.document_id, args.parent_block_id, args.children, args.index));
|
|
1370
|
+
case 'update_doc_block':
|
|
1371
|
+
return json(await getOfficialClient().updateDocBlock(args.document_id, args.block_id, args.update_body));
|
|
1372
|
+
case 'delete_doc_blocks':
|
|
1373
|
+
return text(`Blocks deleted: ${(await getOfficialClient().deleteDocBlocks(args.document_id, args.parent_block_id, args.start_index, args.end_index)).deleted}`);
|
|
1374
|
+
|
|
1375
|
+
// --- Official API: Bitable Additional ---
|
|
1376
|
+
|
|
1377
|
+
case 'get_bitable_record':
|
|
1378
|
+
return json(await getOfficialClient().getBitableRecord(args.app_token, args.table_id, args.record_id));
|
|
1379
|
+
case 'delete_bitable_table':
|
|
1380
|
+
return text(`Table deleted: ${(await getOfficialClient().deleteBitableTable(args.app_token, args.table_id)).deleted}`);
|
|
1381
|
+
case 'get_bitable_meta':
|
|
1382
|
+
return json(await getOfficialClient().getBitableMeta(args.app_token));
|
|
1383
|
+
case 'update_bitable_table':
|
|
1384
|
+
return text(`Table renamed: ${(await getOfficialClient().updateBitableTable(args.app_token, args.table_id, args.name)).name}`);
|
|
1385
|
+
case 'create_bitable_view':
|
|
1386
|
+
return json(await getOfficialClient().createBitableView(args.app_token, args.table_id, args.view_name, args.view_type));
|
|
1387
|
+
case 'delete_bitable_view':
|
|
1388
|
+
return text(`View deleted: ${(await getOfficialClient().deleteBitableView(args.app_token, args.table_id, args.view_id)).deleted}`);
|
|
1389
|
+
case 'copy_bitable':
|
|
1390
|
+
return json(await getOfficialClient().copyBitable(args.app_token, args.name, args.folder_id));
|
|
1391
|
+
|
|
1392
|
+
// --- Official API: Drive File Operations ---
|
|
1393
|
+
|
|
1394
|
+
case 'copy_file':
|
|
1395
|
+
return json(await getOfficialClient().copyFile(args.file_token, args.name, args.folder_token, args.type));
|
|
1396
|
+
case 'move_file':
|
|
1397
|
+
return text(`File moved: task=${(await getOfficialClient().moveFile(args.file_token, args.folder_token)).taskId}`);
|
|
1398
|
+
case 'delete_file':
|
|
1399
|
+
return text(`File deleted: task=${(await getOfficialClient().deleteFile(args.file_token, args.type)).taskId}`);
|
|
1400
|
+
|
|
1038
1401
|
default:
|
|
1039
1402
|
return text(`Unknown tool: ${name}`);
|
|
1040
1403
|
}
|
|
1041
1404
|
}
|
|
1042
1405
|
|
|
1406
|
+
// --- Process-level error handlers ---
|
|
1407
|
+
// Prevent stray promise rejections or uncaught exceptions from killing the MCP server.
|
|
1408
|
+
process.on('uncaughtException', (err) => {
|
|
1409
|
+
console.error('[feishu-user-plugin] Uncaught exception:', err.message);
|
|
1410
|
+
console.error(err.stack);
|
|
1411
|
+
});
|
|
1412
|
+
|
|
1413
|
+
process.on('unhandledRejection', (reason) => {
|
|
1414
|
+
console.error('[feishu-user-plugin] Unhandled rejection:', reason);
|
|
1415
|
+
});
|
|
1416
|
+
|
|
1043
1417
|
async function main() {
|
|
1044
1418
|
const transport = new StdioServerTransport();
|
|
1045
1419
|
await server.connect(transport);
|
package/src/oauth.js
CHANGED
|
@@ -22,7 +22,8 @@ const APP_SECRET = creds.LARK_APP_SECRET;
|
|
|
22
22
|
const PORT = 9997;
|
|
23
23
|
const REDIRECT_URI = `http://127.0.0.1:${PORT}/callback`;
|
|
24
24
|
// offline_access is required to get refresh_token for auto-renewal
|
|
25
|
-
|
|
25
|
+
// Write scopes (docx:document, drive:drive, bitable:app) allow creating resources as the user, not the app
|
|
26
|
+
const SCOPES = 'offline_access auth:user.id:read im:message im:message:readonly im:chat im:chat:readonly contact:user.base:readonly contact:user.id:readonly docx:document drive:drive bitable:app wiki:wiki:readonly';
|
|
26
27
|
|
|
27
28
|
if (!APP_ID || !APP_SECRET) {
|
|
28
29
|
console.error('Missing LARK_APP_ID or LARK_APP_SECRET.');
|