mirror of
https://github.com/run-llama/llamacloud-mcp.git
synced 2026-07-01 21:24:03 -04:00
package things up
This commit is contained in:
@@ -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
|
||||
@@ -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>"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
@@ -1,6 +0,0 @@
|
||||
def main():
|
||||
print("Hello from llamacloud-mcp!")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -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())
|
||||
@@ -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())
|
||||
@@ -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
@@ -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"]
|
||||
|
||||
Reference in New Issue
Block a user