package things up

This commit is contained in:
Logan Markewich
2025-06-26 21:22:44 -06:00
parent eab646d713
commit 3bda60e0b9
10 changed files with 1000 additions and 239 deletions
+58
View File
@@ -0,0 +1,58 @@
---
default_language_version:
python: python3
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: check-byte-order-marker
- id: check-merge-conflict
- id: check-toml
- id: check-yaml
args: [--allow-multiple-documents]
- id: detect-private-key
- id: end-of-file-fixer
- id: mixed-line-ending
- id: trailing-whitespace
- repo: https://github.com/charliermarsh/ruff-pre-commit
rev: v0.12.1
hooks:
- id: ruff-format
- id: ruff-check
args: [--fix, --exit-non-zero-on-fix]
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.15.0
hooks:
- id: mypy
additional_dependencies:
[
"types-Deprecated",
"types-PyYAML",
"types-botocore",
"types-aiobotocore",
"types-protobuf==4.24.0.4",
"types-redis",
"types-requests",
"types-setuptools",
"types-click",
]
args:
[
--disallow-untyped-defs,
--ignore-missing-imports,
--python-version=3.11,
]
- repo: https://github.com/codespell-project/codespell
rev: v2.3.0
hooks:
- id: codespell
additional_dependencies: [tomli]
- repo: https://github.com/pappasam/toml-sort
rev: v0.23.1
hooks:
- id: toml-sort-fix
+15 -7
View File
@@ -1,13 +1,21 @@
{
"mcpServers": {
"llama_index_docs_server": {
"command": "poetry",
"command": "uvx",
"args": [
"--directory",
"$YOURPATH/llamacloud-mcp",
"run",
"python",
"$YOURPATH/llamacloud-mcp/mcp-server.py"
"llamacloud-mcp@latest",
"--indexes",
"llama-index-docs:LlamaIndex documentation",
"--extract-agents",
"llama-index-docs-extract:LlamaIndex documentation extract agent",
"--project-id",
"<your-project-id>",
"--org-id",
"<your-org-id>",
"--api-key",
"<your-api-key>",
"--transport",
"sse"
]
},
"filesystem": {
@@ -15,7 +23,7 @@
"args": [
"-y",
"@modelcontextprotocol/server-filesystem",
"your directory you want filesystem tool to have access to"
"<your directory you want filesystem tool to have access to>"
]
}
}
View File
+138
View File
@@ -0,0 +1,138 @@
import click
import os
from mcp.server.fastmcp import Context, FastMCP
from llama_cloud_services import LlamaExtract
from llama_index.indices.managed.llama_cloud import LlamaCloudIndex
from typing import Awaitable, Callable, Optional
mcp = FastMCP("llama-index-server")
def make_index_tool(
index_name: str, project_id: Optional[str], org_id: Optional[str]
) -> Callable[[Context, str], Awaitable[str]]:
async def tool(ctx: Context, query: str) -> str:
try:
await ctx.info(f"Querying index: {index_name} with query: {query}")
index = LlamaCloudIndex(
name=index_name,
project_id=project_id,
organization_id=org_id,
)
response = index.as_query_engine().query(query)
return str(response)
except Exception as e:
await ctx.error(f"Error querying index: {str(e)}")
return f"Error querying index: {str(e)}"
return tool
def make_extract_tool(
agent_name: str, project_id: Optional[str], org_id: Optional[str]
) -> Callable[[Context, str], Awaitable[str]]:
async def tool(ctx: Context, file_path: str) -> str:
"""Extract data using a LlamaExtract Agent from the given file."""
try:
await ctx.info(
f"Extracting data using agent: {agent_name} with file path: {file_path}"
)
llama_extract = LlamaExtract(
organization_id=org_id,
project_id=project_id,
)
extract_agent = llama_extract.get_agent(name=agent_name)
result = extract_agent.extract(file_path)
return str(result)
except Exception as e:
await ctx.error(f"Error extracting data: {str(e)}")
return f"Error extracting data: {str(e)}"
return tool
@click.command()
@click.option(
"--index",
"indexes",
multiple=True,
required=False,
type=str,
help="Index definition in the format name:description. Can be used multiple times.",
)
@click.option(
"--extract-agent",
"extract_agents",
multiple=True,
required=False,
type=str,
help="Extract agent definition in the format name:description. Can be used multiple times.",
)
@click.option(
"--project-id", required=False, type=str, help="Project ID for LlamaCloud"
)
@click.option(
"--org-id", required=False, type=str, help="Organization ID for LlamaCloud"
)
@click.option(
"--transport",
default="stdio",
type=click.Choice(["stdio", "sse", "streamable-http"]),
help='Transport to run the MCP server on. One of "stdio", "sse", "streamable-http".',
)
@click.option("--api-key", required=False, type=str, help="API key for LlamaCloud")
def main(
indexes: Optional[list[str]],
extract_agents: Optional[list[str]],
project_id: Optional[str],
org_id: Optional[str],
transport: str,
api_key: Optional[str],
) -> None:
api_key = api_key or os.getenv("LLAMA_CLOUD_API_KEY")
if not api_key:
raise click.BadParameter(
"API key not found. Please provide an API key or set the LLAMA_CLOUD_API_KEY environment variable."
)
else:
os.environ["LLAMA_CLOUD_API_KEY"] = api_key
# Parse indexes into (name, description) tuples
index_info = []
if indexes:
for idx in indexes:
if ":" not in idx:
raise click.BadParameter(
f"Index '{idx}' must be in the format name:description"
)
name, description = idx.split(":", 1)
index_info.append((name, description))
# Parse extract agents into (name, description) tuples if provided
extract_agent_info = []
if extract_agents:
for agent in extract_agents:
if ":" not in agent:
raise click.BadParameter(
f"Extract agent '{agent}' must be in the format name:description"
)
name, description = agent.split(":", 1)
extract_agent_info.append((name, description))
# Dynamically register a tool for each index
for name, description in index_info:
tool_func = make_index_tool(name, project_id, org_id)
mcp.tool(name=f"query_{name}", description=description)(tool_func)
# Dynamically register a tool for each extract agent, if any
for name, description in extract_agent_info:
tool_func = make_extract_tool(name, project_id, org_id)
mcp.tool(name=f"extract_{name}", description=description)(tool_func)
mcp.run(transport=transport)
if __name__ == "__main__":
main()
-6
View File
@@ -1,6 +0,0 @@
def main():
print("Hello from llamacloud-mcp!")
if __name__ == "__main__":
main()
-32
View File
@@ -1,32 +0,0 @@
from dotenv import load_dotenv
from llama_index.tools.mcp import BasicMCPClient, McpToolSpec
from llama_index.core.agent.workflow import FunctionAgent
from llama_index.llms.openai import OpenAI
import asyncio
load_dotenv()
# We consider there is a mcp server running on 127.0.0.1:8000, or you can use the mcp client to connect to your own mcp server.
mcp_client = BasicMCPClient("http://localhost:8000/sse")
mcp_tool_spec = McpToolSpec(
client=mcp_client,
# Optional: Filter the tools by name
# allowed_tools=["tool1", "tool2"],
)
tools = mcp_tool_spec.to_tool_list()
llm = OpenAI(model="gpt-4o-mini")
agent = FunctionAgent(
tools=tools,
llm=llm,
system_prompt="You are an agent that knows how to build agents in LlamaIndex.",
)
async def run_agent():
response = await agent.run("How do I instantiate an agent in LlamaIndex?")
print(response)
if __name__ == "__main__":
asyncio.run(run_agent())
-27
View File
@@ -1,27 +0,0 @@
from dotenv import load_dotenv
from mcp.server.fastmcp import FastMCP
from llama_index.indices.managed.llama_cloud import LlamaCloudIndex
import os
import asyncio
load_dotenv()
mcp = FastMCP('llama-index-server',port=8000)
@mcp.tool()
def llama_index_documentation(query: str) -> str:
"""Search the llama-index documentation for the given query."""
index = LlamaCloudIndex(
name="mcp-demo-2",
project_name="Rando project",
organization_id="e793a802-cb91-4e6a-bd49-61d0ba2ac5f9",
api_key=os.getenv("LLAMA_CLOUD_API_KEY"),
)
response = index.as_query_engine().query(query + " Be verbose and include code examples.")
return str(response)
if __name__ == "__main__":
asyncio.run(mcp.run_sse_async())
-99
View File
@@ -1,99 +0,0 @@
from dotenv import load_dotenv
from mcp.server.fastmcp import FastMCP
from llama_index.indices.managed.llama_cloud import LlamaCloudIndex
import os
import click
from mcp.server.fastmcp.resources import TextResource
from llama_cloud_services import LlamaExtract
from mcp.server.fastmcp import Context
load_dotenv()
mcp = FastMCP('llama-index-server')
def make_index_tool(index_name, project_name, org_id):
async def tool(query: str) -> str:
index = LlamaCloudIndex(
name=index_name,
project_name=project_name,
organization_id=org_id,
api_key=os.getenv("LLAMA_CLOUD_API_KEY"),
)
response = index.as_query_engine().query(query + " Be verbose and include code examples.")
return str(response)
return tool
def make_extract_tool(agent_name):
async def tool(file_path: str) -> str:
"""Extract data using a LlamaExtract Agent from the given file."""
try:
print(f"Got file path: {file_path} for agent: {agent_name}")
llama_extract = LlamaExtract()
extract_agent = llama_extract.get_agent(name=agent_name)
result = extract_agent.extract(file_path)
return str(result)
except Exception as e:
return f"Error extracting data: {str(e)}"
return tool
@click.command()
@click.option('--index', 'indexes', multiple=True, required=True, type=str, help='Index definition in the format name:description. Can be used multiple times.')
@click.option('--extract-agent', 'extract_agents', multiple=True, required=False, type=str, help='Extract agent definition in the format name:description. Can be used multiple times.')
@click.option('--project-name', default="Default", type=str, help='Name of the LlamaCloud project')
@click.option('--org-id', required=True, type=str, help='Organization ID for LlamaCloud')
def main(indexes, extract_agents, project_name, org_id):
# Parse indexes into (name, description) tuples
index_resources = []
index_info = []
for idx in indexes:
if ':' not in idx:
raise click.BadParameter(f"Index '{idx}' must be in the format name:description")
name, description = idx.split(':', 1)
index_resources.append(TextResource(
uri=f"resource://index/{name}",
name=f"Index Name: {name}",
text=name,
))
index_resources.append(TextResource(
uri=f"resource://index/{name}/description",
name=f"Index Description: {name}",
text=description,
))
index_info.append((name, description))
# Parse extract agents into (name, description) tuples if provided
extract_agent_info = []
if extract_agents:
for agent in extract_agents:
if ':' not in agent:
raise click.BadParameter(f"Extract agent '{agent}' must be in the format name:description")
name, description = agent.split(':', 1)
extract_agent_info.append((name, description))
project_resource = TextResource(
uri="resource://project",
name="LlamaCloud Project Name",
text=project_name,
)
org_resource = TextResource(
uri="resource://org",
name="LlamaCloud Organization ID",
text=org_id,
)
for res in index_resources:
mcp.add_resource(res)
mcp.add_resource(project_resource)
mcp.add_resource(org_resource)
# Dynamically register a tool for each index
for name, description in index_info:
tool_func = make_index_tool(name, project_name, org_id)
mcp.tool(name=f"query_{name}", description=description)(tool_func)
# Dynamically register a tool for each extract agent, if any
for name, description in extract_agent_info:
tool_func = make_extract_tool(name)
mcp.tool(name=f"extract_{name}", description=description)(tool_func)
mcp.run(transport="stdio")
if __name__ == "__main__":
main()
+44 -4
View File
@@ -1,7 +1,47 @@
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[dependency-groups]
dev = [
"pre-commit>=4.2.0"
]
[project]
name = "llamacloud-mcp"
version = "0.1.0"
description = "Add your description here"
version = "1.0.0"
description = "Expose LlamaCloud services as MCP tools"
readme = "README.md"
requires-python = ">=3.13"
dependencies = ["llama-index-llms-openai>=0.3.28","llama-index-indices-managed-llama-cloud>=0.6.9","mcp[cli]>=1.6.0","python-dotenv>=1.1.0","llama-index-tools-mcp>=0.1.0","llama-cloud-services"]
requires-python = ">=3.10"
dependencies = [
"llama-index-indices-managed-llama-cloud>=0.6.9",
"mcp[cli]>=1.6.0",
"python-dotenv>=1.1.0",
"llama-index-tools-mcp>=0.1.0",
"llama-cloud-services",
"click"
]
license = "MIT"
authors = [
{name = "Tuana Celik", email = "tuana@runllama.ai"},
{name = "Laurie Voss", email = "laurie@runllama.ai"},
{name = "Logan Markewich", email = "logan@runllama.ai"}
]
keywords = [
"mcp",
"llama",
"llamacloud",
"llama-cloud",
"llama-cloud-services"
]
[project.scripts]
llamacloud-mcp = "llamacloud_mcp.main:main"
[tool.hatch.build.targets.sdist]
include = ["llamacloud_mcp/"]
exclude = ["**/BUILD"]
[tool.hatch.build.targets.wheel]
include = ["llamacloud_mcp/"]
exclude = ["**/BUILD"]
Generated
+745 -64
View File
File diff suppressed because it is too large Load Diff