Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions api/src/org/labkey/api/ApiModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@
import org.labkey.api.view.ViewServlet;
import org.labkey.api.view.WebPartFactory;
import org.labkey.api.webdav.WebdavResolverImpl;
import org.labkey.api.wiki.WikiRendererType;
import org.labkey.api.writer.ContainerUser;
import org.labkey.filters.ContentSecurityPolicyFilter;

Expand Down Expand Up @@ -527,6 +528,7 @@ public void registerServlets(ServletContext servletCtx)
UserManager.TestCase.class,
ViewCategoryManager.TestCase.class,
WebdavResolverImpl.TestCase.class,
WikiRendererType.TestCase.class,
WorkbookContainerType.TestCase.class,
WriteableLookAndFeelProperties.TestCase.class
);
Expand Down
12 changes: 12 additions & 0 deletions api/src/org/labkey/api/mcp/McpService.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import org.springframework.ai.support.ToolCallbacks;
import org.springframework.ai.tool.ToolCallback;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.ai.document.Document;
import org.springframework.ai.vectorstore.VectorStore;

import java.util.Arrays;
Expand Down Expand Up @@ -183,4 +184,15 @@ default List<MessageResponse> sendMessageEx(ChatClient chat, String message)
* CONSIDER: Is it possible to implement VectorStoreRetriever wrapper for SearchService???
*/
VectorStore getVectorStore();

/**
* Adds documents to the vector store, automatically splitting any document whose token
* count exceeds the embedding model's input limit. Prefer this over
* {@code getVectorStore().add(...)} for indexing — it prevents the
* {@code IllegalArgumentException} that {@code TokenCountBatchingStrategy} throws on
* oversized inputs.
*/
void addDocuments(List<Document> documents);

void saveVectorStore();
}
11 changes: 11 additions & 0 deletions api/src/org/labkey/api/mcp/NoopMcpService.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.model.ToolContext;
import org.springframework.ai.tool.ToolCallback;
import org.springframework.ai.document.Document;
import org.springframework.ai.vectorstore.VectorStore;

import java.util.List;
Expand Down Expand Up @@ -84,4 +85,14 @@ public VectorStore getVectorStore()
{
return null;
}

@Override
public void addDocuments(List<Document> documents)
{
}

@Override
public void saveVectorStore()
{
}
}
Binary file modified api/src/org/labkey/api/wiki/WikiRendererType.java
Binary file not shown.
9 changes: 9 additions & 0 deletions api/src/org/labkey/api/wiki/WikiService.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,15 @@ record RenderedWiki (String name, String title, HtmlString html, String entityId

RenderedWiki getRenderedWiki(Container c, String name);

record WikiMarkdown(String name, String title, String markdown, String entityId) {}

/**
* Returns a best-effort Markdown rendering of the wiki's raw source, intended for indexing
* (search, embedding, vector stores) — NOT for user display. Conversion is lossy and may
* drop or mangle markup details that don't have a direct Markdown equivalent.
*/
WikiMarkdown getWikiMarkdown(Container c, String name);

default HtmlString getHtml(Container c, String name)
{
var wiki = getRenderedWiki(c, name);
Expand Down
23 changes: 23 additions & 0 deletions core/src/org/labkey/core/CoreMcp.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@
import io.modelcontextprotocol.spec.McpSchema.ReadResourceResult;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.json.JSONArray;
import org.json.JSONObject;
import org.labkey.api.collections.LabKeyCollectors;
import org.labkey.api.data.Container;
import org.labkey.api.data.ContainerManager;
import org.labkey.api.mcp.McpService;
import org.labkey.api.module.ModuleLoader;
import org.labkey.api.security.RequiresNoPermission;
import org.labkey.api.security.RequiresPermission;
import org.labkey.api.security.User;
Expand Down Expand Up @@ -130,6 +132,27 @@ String setContainer(ToolContext context, @ToolParam(description = "Container pat
return message;
}


// TODO replace/augment with available feature list
@Tool(description = "List the modules installed on this server, this may be useful in inferring the available funcitonality. For instance, " +
"the presence of the `premium` module implies the availability of premium featues.")
@RequiresNoPermission
public String listModules(ToolContext context)
{
JSONArray modules = new JSONArray();
ModuleLoader.getInstance().getModules().stream()
.map(module -> {
JSONObject obj = new JSONObject();
obj.put("name", module.getName());
if (StringUtils.isNotEmpty(module.getLabel()))
obj.put("label", module.getLabel());
return obj;
})
.forEach(modules::put);
return new JSONObject(Map.of("modules",modules)).toString();
}


@McpResource(
uri = "resource://org/labkey/core/FileBasedModules.md",
mimeType = "application/markdown",
Expand Down
2 changes: 2 additions & 0 deletions devtools/src/org/labkey/devtools/DevtoolsModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import org.jetbrains.annotations.NotNull;
import org.labkey.api.exp.property.Domain;
import org.labkey.api.mcp.McpService;
import org.labkey.api.module.CodeOnlyModule;
import org.labkey.api.module.ModuleContext;
import org.labkey.api.security.AuthenticationManager;
Expand Down Expand Up @@ -71,6 +72,7 @@ protected void init()
@Override
public void doStartup(ModuleContext moduleContext)
{
McpService.get().register(new TestController.DocumentationMCP());
}

@Override
Expand Down
Loading