Skip to content

Add get_processed_document MCP tool and chain it from get_chunks#286

Open
PuneetPunamiya wants to merge 1 commit into
redhat-data-and-ai:mainfrom
PuneetPunamiya:worktree-trim-pipeline-info
Open

Add get_processed_document MCP tool and chain it from get_chunks#286
PuneetPunamiya wants to merge 1 commit into
redhat-data-and-ai:mainfrom
PuneetPunamiya:worktree-trim-pipeline-info

Conversation

@PuneetPunamiya

Copy link
Copy Markdown
Contributor

Summary

  • New get_processed_document MCP tool retrieves full markdown content from the DocumentProcessor stage table by file_id
  • get_chunks_for_embeddings now returns file_id in results and prompts the LLM agent to call get_processed_document as a follow-up for the full document
  • Generalize GetPipelineQueryConfig to accept a stage type parameter so it works for both VectorEmbeddingsGenerator and DocumentProcessor stages
  • Add snowflake.GetProcessedDocument() to query the processed document table
  • Extract shared errOAuthTokenNotFound constant across MCP tools

Test plan

  • Verify get_chunks_for_embeddings returns file_id in chunk results
  • Verify get_chunks_for_embeddings response includes the NEXT STEP instruction to call get_processed_document
  • Verify get_processed_document retrieves the correct document by file_id from the DocumentProcessor stage table
  • Verify GetPipelineQueryConfig correctly resolves query config for both StageTypeVectorEmbeddingsGenerator and StageTypeDocumentProcessor
  • Verify error handling for missing pipeline, missing query config, and missing document

@gemini-code-assist

Copy link
Copy Markdown

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request enhances the unstructured data MCP server by introducing a mechanism to retrieve full processed documents. By chaining the existing chunk search tool with a new document retrieval tool, the system now allows LLM agents to fetch complete markdown content after identifying relevant chunks. The changes also include architectural improvements to pipeline query configuration and standardized error messaging.

Highlights

  • New MCP Tool: Added the get_processed_document MCP tool to retrieve full markdown content from the DocumentProcessor stage table by file_id.
  • Enhanced Chunk Retrieval: Updated get_chunks_for_embeddings to return file_id and prompt the LLM agent to follow up with get_processed_document for full document retrieval.
  • Generalized Pipeline Configuration: Refactored GetPipelineQueryConfig to accept a stage type parameter, enabling support for both VectorEmbeddingsGenerator and DocumentProcessor stages.
  • Code Cleanup: Extracted the errOAuthTokenNotFound constant to be shared across all MCP tools for consistent error handling.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a new MCP tool, get_processed_document, which retrieves full processed documents from a pipeline's DocumentProcessor stage in Snowflake. It also updates the get_chunks_for_embeddings tool to return file_id values and direct users to the new tool, and modifies the Kubernetes client to fetch query configurations by stage type. The review feedback recommends only appending the 'NEXT STEP' instruction when chunks are actually found to prevent LLM hallucinations, and moving the shared errOAuthTokenNotFound constant to a common file to avoid implicit cross-file dependencies.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread internal/mcp/tools/get_chunks.go Outdated
"github.com/redhat-data-and-ai/unstructured-data-controller/pkg/snowflake"
)

const errOAuthTokenNotFound = "Error: oauth token not found in context"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Defining the shared package-level constant errOAuthTokenNotFound in a specific tool file (get_processed_document.go) creates an implicit dependency for other files in the same package (like get_chunks.go and list_pipelines.go). If this file is excluded, renamed, or deleted, compilation of other tools will break. Consider moving shared constants to a dedicated common.go or constants.go file within the tools package to improve maintainability and modularity.

@vinamra28

Copy link
Copy Markdown
Member

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a new MCP tool get_processed_document to retrieve full processed documents from Snowflake by file_id. It updates the existing get_chunks_for_embeddings tool to return the file_id for each chunk and suggest calling get_processed_document as a next step. It also refactors GetPipelineQueryConfig to support querying configurations for different stage types. Feedback was provided to ensure the NEXT STEP instruction in get_chunks_for_embeddings is only appended when a valid file_id is actually found in the results, preventing misleading tool calls when no chunks are returned.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread internal/mcp/tools/get_chunks.go Outdated
Comment thread internal/mcp/tools/get_chunks.go Outdated
Comment thread internal/mcp/tools/get_processed_document.go Outdated
- Only show get_processed_document TIP when chunks are non-empty
- Soften tool description to let the agent decide when to fetch full documents
- Use user-friendly error message for missing query config
@PuneetPunamiya PuneetPunamiya force-pushed the worktree-trim-pipeline-info branch from d4c9276 to 4a52198 Compare July 8, 2026 08:27
@vinamra28

Copy link
Copy Markdown
Member

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a new MCP tool, get_processed_document, which allows users to retrieve full processed documents from a pipeline's DocumentProcessor stage in Snowflake. It also updates the get_chunks_for_embeddings tool to return a file_id and suggest using the new tool for additional context, and refactors GetPipelineQueryConfig to support querying configurations for different stage types. The review feedback suggests several key improvements: simplifying the next-step tip logic to only trigger when a valid file_id is present, returning a more precise and actionable error message when the pipeline query configuration is incomplete, and outputting the raw markdown content directly instead of JSON-marshaling the result to preserve readability.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +146 to +157
var nextStep string
if len(chunks) > 0 && chunks[0].FileID != "" {
nextStep = fmt.Sprintf(
"\n\nTIP: To retrieve the full processed document, call get_processed_document with pipeline_name=%q and file_id=%q.",
args.PipelineName, chunks[0].FileID,
)
} else if len(chunks) > 0 {
nextStep = fmt.Sprintf(
"\n\nTIP: To retrieve the full processed document, call get_processed_document with pipeline_name=%q and the file_id from the highest-scoring chunk above.",
args.PipelineName,
)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If chunks[0].FileID is empty, then the highest-scoring chunk does not have a valid file_id. In this scenario, prompting the LLM or user to call get_processed_document with "the file_id from the highest-scoring chunk above" is misleading and will fail because no file_id is available.

We should simplify this logic to only suggest calling get_processed_document if we actually have a non-empty FileID in the top chunk.

		var nextStep string
		if len(chunks) > 0 && chunks[0].FileID != "" {
			nextStep = fmt.Sprintf(
				"\n\nTIP: To retrieve the full processed document, call get_processed_document with pipeline_name=%q and file_id=%q.",
				args.PipelineName, chunks[0].FileID,
			)
		}

Comment on lines +91 to +97
if qc.Database == "" || qc.Schema == "" || qc.Table == "" {
log.Error("pipeline query config has empty fields", "database", qc.Database, "schema", qc.Schema, "table", qc.Table)
return &mcp.CallToolResult{
Content: []mcp.Content{&mcp.TextContent{Text: "Unable to retrieve the document, please check again in some time"}},
IsError: true,
}, nil, nil
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The error message returned when the pipeline query configuration is incomplete is vague ("Unable to retrieve the document, please check again in some time"). This implies a transient error, which might cause the LLM to retry or wait.

Instead, we should return a clear, actionable error message indicating that the pipeline has an incomplete Snowflake query configuration, matching the behavior in get_chunks.go.

Suggested change
if qc.Database == "" || qc.Schema == "" || qc.Table == "" {
log.Error("pipeline query config has empty fields", "database", qc.Database, "schema", qc.Schema, "table", qc.Table)
return &mcp.CallToolResult{
Content: []mcp.Content{&mcp.TextContent{Text: "Unable to retrieve the document, please check again in some time"}},
IsError: true,
}, nil, nil
}
if qc.Database == "" || qc.Schema == "" || qc.Table == "" {
log.Error("pipeline query config has empty fields", "database", qc.Database, "schema", qc.Schema, "table", qc.Table)
return &mcp.CallToolResult{
Content: []mcp.Content{&mcp.TextContent{Text: fmt.Sprintf("Error: pipeline %q has incomplete Snowflake query configuration", args.PipelineName)}},
IsError: true,
}, nil, nil
}

Comment on lines +113 to +127
jsonBytes, err := json.Marshal(doc)
if err != nil {
log.Error("failed to marshal result", "error", err)
return &mcp.CallToolResult{
Content: []mcp.Content{&mcp.TextContent{Text: fmt.Sprintf("Error marshaling result: %v", err)}},
IsError: true,
}, nil, nil
}

log.Info("completed successfully", "pipeline", args.PipelineName, "file_id", args.FileID)
return &mcp.CallToolResult{
Content: []mcp.Content{&mcp.TextContent{
Text: fmt.Sprintf("Processed document for file_id %q in pipeline %q:\n%s", args.FileID, args.PipelineName, string(jsonBytes)),
}},
}, nil, nil

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Since get_processed_document retrieves a single document's markdown content, JSON-marshaling the entire ProcessedDocumentResult struct escapes all newlines (\n) and special characters. This makes the output extremely hard to read for humans and less clean for LLM processing.

Instead, we should return the raw MarkdownContent directly in a nicely formatted string. This also eliminates the need for json.Marshal and its error handling.

Note: Remember to also remove the unused "encoding/json" import from the top of the file.

		log.Info("completed successfully", "pipeline", args.PipelineName, "file_id", args.FileID)
		return &mcp.CallToolResult{
			Content: []mcp.Content{&mcp.TextContent{
				Text: fmt.Sprintf("Processed document for file_id %q in pipeline %q:\n\n%s", args.FileID, args.PipelineName, doc.MarkdownContent),
			}},
		}, nil, nil

Comment on lines +146 to +154
var nextStep string
if len(chunks) > 0 && chunks[0].FileID != "" {
nextStep = fmt.Sprintf(
"\n\nTIP: To retrieve the full processed document, call get_processed_document with pipeline_name=%q and file_id=%q.",
args.PipelineName, chunks[0].FileID,
)
} else if len(chunks) > 0 {
nextStep = fmt.Sprintf(
"\n\nTIP: To retrieve the full processed document, call get_processed_document with pipeline_name=%q and the file_id from the highest-scoring chunk above.",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if fileID field is going to be empty for any record. We should probably return an error in such scenarios. @concaf WDYT?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants