@sura_ai/mcp-server 0.1.10 → 0.1.11

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.
Files changed (2) hide show
  1. package/dist/index.js +2 -2
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -40,7 +40,7 @@ ${L}
40
40
  +++ after
41
41
  ${E}`}function E6(Q){if(!Q)return"";let X=[];if(Q.previousBlock)X.push(`After: [${Q.previousBlock.type} | ${Q.previousBlock.id}]`);if(Q.nextBlock)X.push(`Before: [${Q.nextBlock.type} | ${Q.nextBlock.id}]`);return X.join(", ")}var qD=50,WC=j.object({entityType:j.enum(["document","record"]).describe('Entity type: "document" or "record"'),entityId:j.string().uuid().describe("Document or record ID"),blockId:j.string().optional().describe("Block ID to delete (for single delete)"),blockIds:j.array(j.string()).max(qD).optional().describe(`Array of block IDs to delete (batch mode, max ${qD})`)}),GC={name:"delete_block",description:"Delete blocks from a document. Supports single (blockId) or batch (blockIds) mode. Batch mode is more efficient for deleting multiple blocks in one operation. Be careful - this permanently removes blocks and their content. Use get_content first to verify blocks before deleting."};function zD(Q,X){L1(Q,X,{definition:GC,schema:WC,createExecutor:(W)=>{return async(G)=>{return await W.client.deleteBlock(G)}},formatOutput:(W)=>{if(!W.success)return`Delete failed: ${W.error}`;if(W.deletedBlockIds&&W.deletedBlockIds.length>0){let H=[`Deleted ${W.deletedBlockIds.length} blocks:`];if(W.results){for(let J of W.results)if(J.success){let B=J.blockType??"?",$=J.contentPreview?`: ${J.contentPreview.slice(0,60)}${J.contentPreview.length>60?"...":""}`:"";H.push(` [${B} | ${J.blockId}]${$}`)}}return H.join(`
42
42
  `)}let G=[];if(W.deletedBlock){let{blockType:H,contentPreview:J}=W.deletedBlock;if(G.push(`Deleted [${H} | ${W.deletedBlock.blockId}]`),J)G.push(`Was: ${J}`)}else G.push("Block deleted");let Y=E6(W.positionContext);if(Y)G.push(`New adjacency: ${Y}`);return G.join(`
43
- `)},getLogMessage:(W)=>{if(W.blockIds&&W.blockIds.length>0)return`${W.entityType}/${W.entityId.slice(0,8)} batch delete ${W.blockIds.length} blocks`;return`${W.entityType}/${W.entityId.slice(0,8)} block ${W.blockId?.slice(0,8)??"unknown"}`}})}function VX(Q){return` ${Q.map((W)=>{if(W===null||W===void 0||W==="")return"";let G=String(W);return G.includes(",")?`"${G}"`:G}).join(",")}`}var YC=j.object({entityId:j.string().describe('Entity ID (UUID or short ref like "lit-a3f7e2b9")'),overview:j.boolean().optional().describe("Return overview with TOC and preview. Default behavior."),blockIds:j.array(j.string()).optional().describe("Array of specific block IDs to fetch from search results"),section:j.string().optional().describe('Section heading text, blockId, or parent-qualified path (e.g., "Methods/Key Takeaways") to fetch all blocks from'),node:j.string().optional().describe("Procedure node label or ID. Returns node prose, matrices (TOON format), artifact links, and child summaries. Records only."),refs:j.array(j.number().int()).optional().describe("Reference numbers to fetch (e.g., [42, 43])"),figures:j.array(j.string()).optional().describe('Figure IDs to fetch (e.g., ["fig-1", "fig-2"])'),tables:j.array(j.string()).optional().describe('Table IDs to fetch (e.g., ["table-1"])'),depth:j.number().int().min(0).optional().describe("Depth: 0 = only direct content (no children), 1 = include immediate children, undefined = all descendants (default). Used with section or node parameter."),from_section:j.string().optional().describe('Start section heading, blockId, or parent-qualified path (e.g., "Parent/Section") for range fetching (inclusive). Use with to_section.'),to_section:j.string().optional().describe('End section heading, blockId, or parent-qualified path (e.g., "Parent/Section") for range fetching (inclusive). Use with from_section.')}),HC={name:"get_content",description:'Fetch content from literature, documents, records, or artifacts. Returns markdown text.\nAccepts full UUIDs or short entity reference IDs (e.g., `lit-a3f7e2b9`, `doc-9bk4x1f2`, `rec-f72mn3a8`).\n\n**Modes:**\n1. **Overview** (default): Preview + table of contents with section headings and estimated tokens. For records, also includes the procedure tree showing nodes, matrices, and artifact links.\n2. **Section**: Pass `section="Heading Name"` to get all blocks in that section as interleaved markdown.\n3. **Node** (records only): Pass `node="step label"` to get procedure node content — prose, matrices (TOON format), artifacts, and child summaries. Use `depth` to control child expansion.\n4. **Block IDs**: Pass `blockIds=["id1","id2"]` to fetch specific blocks from search results.\n5. **Refs**: Pass `refs=[42,43]` to fetch literature references by number.\n6. **Figures**: Pass `figures=["fig-1"]` to fetch figure blocks.\n7. **Tables**: Pass `tables=["table-1"]` to fetch table blocks.\n8. **Section range**: Pass `from_section` and `to_section` to fetch all content between two headings (inclusive).\n9. **Section with depth**: Pass `section` with `depth=0` for own content only, `depth=1` for immediate children.\n\n**Interleaved Format (Section mode):**\nSection mode returns content with block IDs embedded for editing:\n```\n[paragraph | dff74a60-0dd9-4cfa-9ae1-04c462d5cf46]\nThis is the paragraph content...\n\n[heading:2 | a9fe6c59-cf59-495c-b688-a6fcfb605491]\n## Methods\n```\nUse these block IDs with `str_replace_block`, `insert_block`, or `delete_block`.\n\n**Reading Strategy:** Check `ownTokens` and `children` in TOC entries:\n- If `ownTokens` is 0 and `children` exists → container heading, fetch children individually\n- If `children` is absent → leaf section, fetch directly with `section`\n- `estimatedTokens` = total tokens including all descendants\n\n**Best Practice:** Check `estimatedTokens` in TOC before fetching large sections.'};function VD(Q,X){JD(Q,X,{definition:HC,schema:YC,createExecutor:(W)=>{return async(G)=>{return W.client.getContent(G)}},formatSuccess:BC,formatNotFound:(W)=>JSON.stringify({found:!1,error:W.error??"Entity not found"}),getLogMessage:(W)=>{let G=W.blockIds?`blocks:${W.blockIds.length}`:W.from_section&&W.to_section?`range:"${W.from_section}"-"${W.to_section}"`:W.node?`node:"${W.node}"${W.depth!==void 0?`,depth=${W.depth}`:""}`:W.section?`section:"${W.section}"${W.depth!==void 0?`,depth=${W.depth}`:""}`:W.refs?`refs:${W.refs.length}`:"overview";return`${W.entityId.slice(0,8)}... (${G})`}})}function JC(Q){if(Q.length===0)return"";let X=[`[toc:${Q.length} sections]`,`{title,level,tokens,ownTokens,blockId}[${Q.length}]:`];for(let W of Q)X.push(VX([W.title,W.level,W.estimatedTokens??0,W.ownTokens??0,W.blockId.slice(0,8)]));return X.join(`
43
+ `)},getLogMessage:(W)=>{if(W.blockIds&&W.blockIds.length>0)return`${W.entityType}/${W.entityId.slice(0,8)} batch delete ${W.blockIds.length} blocks`;return`${W.entityType}/${W.entityId.slice(0,8)} block ${W.blockId?.slice(0,8)??"unknown"}`}})}function VX(Q){return` ${Q.map((W)=>{if(W===null||W===void 0||W==="")return"";let G=String(W);return G.includes(",")?`"${G}"`:G}).join(",")}`}var YC=j.object({entityId:j.string().describe('Entity ID (UUID or short ref like "lit-a3f7e2b9")'),overview:j.boolean().optional().describe("Return overview with TOC and preview. Default behavior."),blockIds:j.array(j.string()).optional().describe("Array of specific block IDs to fetch from search results"),section:j.string().optional().describe('Section heading text, blockId, or parent-qualified path (e.g., "Methods/Key Takeaways") to fetch all blocks from'),node:j.string().optional().describe("Procedure node label or ID. Returns node prose, matrices (TOON format), artifact links, and child summaries. Records only."),refs:j.array(j.number().int()).optional().describe("Reference numbers to fetch (e.g., [42, 43])"),figures:j.array(j.string()).optional().describe('Figure IDs to fetch (e.g., ["fig-1", "fig-2"])'),tables:j.array(j.string()).optional().describe('Table IDs to fetch (e.g., ["table-1"])'),depth:j.number().int().min(0).optional().describe("Depth: 0 = only direct content (no children), 1 = include immediate children, undefined = all descendants (default). Used with section or node parameter."),from_section:j.string().optional().describe('Start section heading, blockId, or parent-qualified path (e.g., "Parent/Section") for range fetching (inclusive). Use with to_section.'),to_section:j.string().optional().describe('End section heading, blockId, or parent-qualified path (e.g., "Parent/Section") for range fetching (inclusive). Use with from_section.')}),HC={name:"get_content",description:'Fetch content from literature, documents, records, or artifacts. Returns markdown text.\nAccepts full UUIDs or short entity reference IDs (e.g., `lit-a3f7e2b9`, `doc-9bk4x1f2`, `rec-f72mn3a8`).\n\n**Modes:**\n1. **Overview** (default): Preview + table of contents with section headings and estimated tokens. For records, also includes the procedure tree showing nodes, matrices, and artifact links.\n2. **Section**: Pass `section="Heading Name"` to get all blocks in that section as interleaved markdown.\n3. **Node** (records only): Pass `node="step label"` to get procedure node content — prose, matrices (TOON format), artifacts, and child summaries. Use `depth` to control child expansion.\n4. **Block IDs**: Pass `blockIds=["id1","id2"]` to fetch specific blocks from search results.\n5. **Refs**: Pass `refs=[42,43]` to fetch literature references by number.\n6. **Figures**: Pass `figures=["fig-1"]` to fetch figure blocks.\n7. **Tables**: Pass `tables=["table-1"]` to fetch table blocks.\n8. **Section range**: Pass `from_section` and `to_section` to fetch all content between two headings (inclusive).\n9. **Section with depth**: Pass `section` with `depth=0` for own content only, `depth=1` for immediate children.\n\n**Interleaved Format (Section mode):**\nSection mode returns content with block IDs embedded for editing:\n```\n[paragraph | dff74a60-0dd9-4cfa-9ae1-04c462d5cf46]\nThis is the paragraph content...\n\n[heading:2 | a9fe6c59-cf59-495c-b688-a6fcfb605491]\n## Methods\n```\nUse these block IDs with `str_replace_block`, `insert_block`, or `delete_block`.\n\n**Reading Strategy:** Check `ownTokens` and `children` in TOC entries:\n- If `ownTokens` is 0 and `children` exists → container heading, fetch children individually\n- If `children` is absent → leaf section, fetch directly with `section`\n- `estimatedTokens` = total tokens including all descendants\n\n**Best Practice:** Check `estimatedTokens` in TOC before fetching large sections.'};function VD(Q,X){JD(Q,X,{definition:HC,schema:YC,createExecutor:(W)=>{return async(G)=>{return W.client.getContent(G)}},formatSuccess:BC,formatNotFound:(W)=>JSON.stringify({found:!1,error:W.error??"Entity not found"}),getLogMessage:(W)=>{let G=W.blockIds?`blocks:${W.blockIds.length}`:W.from_section&&W.to_section?`range:"${W.from_section}"-"${W.to_section}"`:W.node?`node:"${W.node}"${W.depth!==void 0?`,depth=${W.depth}`:""}`:W.section?`section:"${W.section}"${W.depth!==void 0?`,depth=${W.depth}`:""}`:W.refs?`refs:${W.refs.length}`:"overview";return`${W.entityId.slice(0,8)}... (${G})`}})}function JC(Q){if(Q.length===0)return"";let X=[`[toc:${Q.length} sections]`,`{title,level,tokens,ownTokens,blockId}[${Q.length}]:`];for(let W of Q)X.push(VX([W.title,W.level,W.estimatedTokens??0,W.ownTokens??0,W.blockId]));return X.join(`
44
44
  `)}function BC(Q){let X=[];if(X.push(`**"${Q.entityTitle}"** - ${Q.entityType}`),Q.overview){if(Q.overview.wordCount)X.push(`*~${Q.overview.wordCount} words*`);if(X.push(""),Q.overview.abstract)X.push("**Preview:**"),X.push(Q.overview.abstract),X.push("");if(Q.overview.toc&&Q.overview.toc.length>0)X.push("**Table of Contents:**"),X.push(JC(Q.overview.toc))}if(Q.procedureTree)X.push(""),X.push("**Procedure Tree:**"),X.push(Q.procedureTree);if(Q.markdown){if(X.push(""),Q.format==="interleaved")X.push("**Content (with block IDs for editing):**");else X.push("**Markdown Content:**");X.push(""),X.push(Q.markdown)}if(Q.sectionInfo){if(X.push(""),X.push(`*Section: ${Q.sectionInfo.blockCount} blocks, ${Q.sectionInfo.wordCount} words*`),Q.sectionInfo.warning)X.push(`*Warning: ${Q.sectionInfo.warning}*`)}if(Q.refs&&Q.refs.length>0)X.push(""),X.push("**References:**"),X.push("```json"),X.push(JSON.stringify(Q.refs,null,2)),X.push("```");return X.join(`
45
45
  `)}var $C=j.object({forceRefresh:j.boolean().optional().describe("Force reload from server instead of returning cached context. Use after creating new organizations or workspaces.")}),qC={name:"get_workspace_context",description:"Get the user's organizational hierarchy: organizations, workspaces, and spaces. Returns default orgId and workspaceId for use with other tools (search, create_document, etc.). Called automatically at startup; use forceRefresh=true to reload if the user creates new workspaces mid-session."};function AD(Q,X){L1(Q,X,{definition:qC,schema:$C,createExecutor:(W)=>{return async(G)=>{if(W.workspaceContext&&!G.forceRefresh)return W.workspaceContext;let Y=await W.client.getWorkspaceContext();return W.workspaceContext=Y,Y}},formatOutput:(W)=>JSON.stringify(W,null,2),getLogMessage:(W)=>W.forceRefresh?"force refresh":"cached"})}var DD=["paragraph","heading","bulletListItem","numberedListItem","checkListItem","codeBlock","quote","divider","referenceList","annotationList","referenceItem"],KD=["literature","document","record","annotation"],UD=50,zC=j.object({blockType:j.enum(DD).default("paragraph").describe("Type of block to create. Default: paragraph"),content:j.string().describe("Text content for the block"),headingLevel:j.number().int().min(1).max(3).optional().describe("Heading level (1-3) if blockType is heading"),checked:j.boolean().optional().describe("Checked state for checkListItem"),title:j.string().optional().describe('Title for referenceList container (default: "References")'),refNumber:j.number().int().min(1).optional().describe("Reference number for referenceItem (e.g., 1, 2, 3)"),refId:j.string().optional().describe('Stable ref ID for citation linking (e.g., "lit-a3f7e2b9"). Auto-generated from linkedEntityId if omitted.'),refType:j.enum(KD).optional().describe("Type of reference: literature, document, record, or annotation"),linkedEntityId:j.string().uuid().optional().describe("UUID of the linked entity (literature, document, or record)"),entityTitle:j.string().optional().describe("Cached title of the linked entity"),doi:j.string().optional().describe("DOI for literature references")}),VC=j.object({entityType:j.enum(["document","record"]).describe('Entity type: "document" or "record"'),entityId:j.string().uuid().describe("Document or record ID"),afterBlockId:j.string().optional().describe("Insert AFTER this block ID (sibling insertion)"),beforeBlockId:j.string().optional().describe("Insert BEFORE this block ID (sibling insertion)"),parentBlockId:j.string().optional().describe("Insert as CHILD of this container block (e.g., add referenceItem inside referenceList)"),childPosition:j.string().optional().describe('Position within parent children: "first", "last" (default), or child block ID to insert after'),blockType:j.enum(DD).default("paragraph").optional().describe("Type of block to create. Default: paragraph"),content:j.string().optional().describe("Text content for the new block"),headingLevel:j.number().int().min(1).max(3).optional().describe("Heading level (1-3) if blockType is heading"),checked:j.boolean().optional().describe("Checked state for checkListItem"),title:j.string().optional().describe('Title for referenceList container (default: "References")'),refNumber:j.number().int().min(1).optional().describe("Reference number for referenceItem (e.g., 1, 2, 3)"),refId:j.string().optional().describe('Stable ref ID for citation linking (e.g., "lit-a3f7e2b9"). Auto-generated from linkedEntityId if omitted.'),refType:j.enum(KD).optional().describe("Type of reference: literature, document, record, or annotation"),linkedEntityId:j.string().uuid().optional().describe("UUID of the linked entity (literature, document, or record)"),entityTitle:j.string().optional().describe("Cached title of the linked entity"),doi:j.string().optional().describe("DOI for literature references"),blocks:j.array(zC).max(UD).optional().describe(`Array of blocks to insert in sequence. Max ${UD} blocks. Use this for inserting multiple blocks in one call.`)}),AC={name:"insert_block",description:`Insert block(s) in a document. Three positioning modes:
46
46
  1. afterBlockId: Insert as SIBLING after the specified block
@@ -131,7 +131,7 @@ Requires \`workspaceId\`. Returns artifact names, types, and retrieval hints.
131
131
  Library mode results include \`bestBlockId\` and smart \`retrievalHint\`:
132
132
  - High relevance: Jump directly to the best block via \`blockIds=['bestBlockId']\`
133
133
  - Medium/Low relevance: Start with \`overview=true\` to explore structure first`};function LD(Q,X){L1(Q,X,{definition:KC,schema:UC,createExecutor:(W)=>{return async(G)=>{let Y=G.mode??"library",H=G.limit??10;if(G.scope?.type==="artifact"&&Y==="library"&&G.workspaceId){let q=await W.client.searchArtifacts({workspaceId:G.workspaceId,query:G.query,artifactType:G.artifactType,artifactStatus:G.artifactStatus,limit:H}),z=q.results.map((V)=>{let A=V.description?V.description.length>100?`${V.description.slice(0,97)}...`:V.description:`${V.artifactType}, ${V.status}`;return{entityType:"artifact",entityId:V.id,entityTitle:V.name,matchCount:1,bestBlockId:"",snippet:A,relevance:"high",retrievalHint:{recommended:"overview",usage:`get_content(entityId="${V.id}")`}}});return{mode:"library",found:z.length,results:z,hasMore:q.hasMore}}let J=await W.client.search({query:G.query,mode:Y,entityType:G.scope?.type,entityId:G.scope?.entityId,orgId:G.orgId,workspaceId:G.workspaceId,spaceId:G.spaceId,limit:H,offset:0,authorName:G.authorName,yearMin:G.yearMin,yearMax:G.yearMax,journalName:G.journalName}),B=J.results??[];if(Y==="library"){let q=B.map((z)=>{let{bestMatch:V}=z,A=DC(V.rank,z.matchCount);return{entityType:z.entityType,entityId:z.entityId,entityTitle:z.entityTitle,matchCount:z.matchCount,bestBlockId:V.blockId,snippet:V.snippet,relevance:A,retrievalHint:V.blockId?{recommended:"blockIds",usage:`blockIds=['${V.blockId}']`}:{recommended:"overview",usage:"overview=true"}}});return{mode:"library",found:q.length,results:q,hasMore:J.hasMore}}let $=B.map((q)=>({entityType:q.entityType,entityId:q.entityId,entityTitle:q.entityTitle,blockId:"blockId"in q?q.blockId:"",snippet:"snippet"in q?q.snippet:"",relevance:"medium",retrievalHint:{recommended:"blockIds",usage:`blockIds=['${"blockId"in q?q.blockId:""}']`}}));return{mode:"blocks",found:$.length,results:$,hasMore:J.hasMore}}},formatOutput:(W)=>MC(W),getLogMessage:(W)=>W.query?`"${W.query}"`:"metadata filters"})}function MC(Q){let{mode:X,found:W,hasMore:G}=Q;if(W===0)return`[results:0 found, ${X}]
134
- No results.`;let Y=[X,...G?["hasMore"]:[]].join(", "),H=[`[results:${W} found, ${Y}]`];if(X==="library"){let J=Q.results;H.push(`{type,title,id,relevance,snippet}[${J.length}]:`);for(let B of J){let $=B.snippet??"",q=$.length>120?`${$.slice(0,117)}...`:$;H.push(VX([B.entityType,B.entityTitle,B.entityId.slice(0,8),B.relevance,q]))}}else{let J=Q.results;H.push(`{type,title,entityId,blockId,snippet}[${J.length}]:`);for(let B of J){let $=B.snippet??"",q=$.length>120?`${$.slice(0,117)}...`:$;H.push(VX([B.entityType,B.entityTitle,B.entityId.slice(0,8),B.blockId,q]))}}return H.join(`
134
+ No results.`;let Y=[X,...G?["hasMore"]:[]].join(", "),H=[`[results:${W} found, ${Y}]`];if(X==="library"){let J=Q.results;H.push(`{type,title,id,relevance,snippet}[${J.length}]:`);for(let B of J){let $=B.snippet??"",q=$.length>120?`${$.slice(0,117)}...`:$;H.push(VX([B.entityType,B.entityTitle,B.entityId,B.relevance,q]))}}else{let J=Q.results;H.push(`{type,title,entityId,blockId,snippet}[${J.length}]:`);for(let B of J){let $=B.snippet??"",q=$.length>120?`${$.slice(0,117)}...`:$;H.push(VX([B.entityType,B.entityTitle,B.entityId,B.blockId,q]))}}return H.join(`
135
135
  `)}var LC=j.object({entityType:j.enum(["document","record"]).describe('Entity type: "document" or "record"'),entityId:j.string().uuid().describe("Document or record ID"),blockId:j.string().describe("Block ID to edit"),oldText:j.string().describe("Exact text to find and replace (must match exactly)"),newText:j.string().describe("Text to replace with")}),wC={name:"str_replace_block",description:"Replace text content in a specific block. Works like Claude Code str_replace - find exact text and replace it. oldText must match exactly (case-sensitive). Use get_content first to see exact block content. Content supports SURA markdown inline syntax: **bold**, *italic*, ~~strike~~, `code`, {u}underline{/u}, {color:red}text color{/color}, {bg:yellow}background{/bg}. Colors: default, gray, brown, red, orange, yellow, green, blue, purple, pink."};function wD(Q,X){L1(Q,X,{definition:wC,schema:LC,createExecutor:(W)=>{return async(G)=>{return await W.client.strReplaceBlock(G)}},formatOutput:(W)=>{if(!W.success)return`Replace failed: ${W.error}`;let G=[`Text replaced in block ${W.blockId}`];if(W.originalText&&W.updatedText)G.push($D(W.originalText,W.updatedText));let Y=E6(W.positionContext);if(Y)G.push(`Position: ${Y}`);return G.join(`
136
136
 
137
137
  `)},getLogMessage:(W)=>`${W.entityType}/${W.entityId.slice(0,8)} block ${W.blockId.slice(0,8)}`})}function FD(Q,X){X.log.info("Registering tools..."),LD(Q,X),VD(Q,X),wD(Q,X),MD(Q,X),zD(Q,X),BD(Q,X),AD(Q,X),X.log.info("All tools registered")}function FC(){let Q=process.argv.slice(2),X={};for(let W=0;W<Q.length;W++){let G=Q[W],Y=Q[W+1];if((G==="--api-key"||G==="-k")&&Y)X.apiKey=Y,W++;else if((G==="--api-url"||G==="-u")&&Y)X.apiUrl=Y,W++;else if(G==="--help"||G==="-h")console.error(`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sura_ai/mcp-server",
3
- "version": "0.1.10",
3
+ "version": "0.1.11",
4
4
  "description": "SURA MCP server - search, read, and edit your research workspace from any AI assistant",
5
5
  "type": "module",
6
6
  "bin": {