Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement MCP Completion Support in Prompts and Resources Tabs #113

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

gavinaboulhosn
Copy link

Provide a brief summary of your changes

This PR introduces support for developers to test and debug completions in their MCP server implementations, enabling dynamic prompt and resource template completion testing directly within the MCP Inspector.


Motivation and Context

Completion support is a critical feature for MCP servers that implement dynamic prompts and resource templates. This addition allows developers to interactively test and debug their server’s completion logic, ensuring a smooth and efficient development process.


How Has This Been Tested?

Tested with a basic MCP server that provides resource templates and prompts for workspace information (e.g., file structure, language, packages, etc.).

image

Example Completion Logic

// Example server-side implementation for handling completions
this.server.setRequestHandler(CompleteRequestSchema, async (request) => {
  const { ref, argument } = request.params;

  if (ref.type === "ref/resource") {
    const resource = this.resourcesMap.get(ref.uri);
    if (!resource?.complete) return { completion: { values: [] } };

    const values = await resource.complete(argument.name, argument.value);
    return { completion: { values, hasMore: false, total: values.length } };
  }

  if (ref.type === "ref/prompt") {
    const prompt = this.promptsMap.get(ref.name);
    if (!prompt?.complete) return { completion: { values: [] } };

    const values = await prompt.complete(argument.name, argument.value);
    return { completion: { values, hasMore: false, total: values.length } };
  }

  throw new Error(`Unknown reference type: ${ref}`);
});

// Example completion logic for a resource template
async complete(argumentName: "workspaceName", value: string): Promise<string[]> {
  const workspaces = await this.getCachedWorkspaces();
  return workspaces.filter((ws) => ws.startsWith(value));
}

This logic was verified using a mocked Inspector setup to ensure correctness across various completion scenarios.


Breaking Changes

This change is backward-compatible. No updates to existing code or configurations are required.


Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the [MCP Documentation](https://modelcontextprotocol.io).
  • My code follows the repository's style guidelines.
  • New and existing tests pass locally.
  • I have added appropriate error handling.
  • I have added or updated documentation as needed.

Additional Context

  • Added the dialog, popover, and command shadcn components to implement the Combobox
  • handleCompletion has it's own abort signal hence why it diverged from using makeRequest

…Resources tabs

- create useCompletion hook to fetch completions with debouncing and abort control
- Updated `PromptsTab.tsx` and `ResourcesTab.tsx` to utilize the `Combobox` component and `useCompletions` hook, enabling argument autocompletion for prompts and resource URIs as per the MCP specification.
- Added a combobox to show completions
Comment on lines +298 to +333
const handleCompletion = async (
ref: ResourceReference | PromptReference,
argName: string,
value: string,
signal?: AbortSignal,
) => {
if (!mcpClient) {
throw new Error("MCP client not connected");
}

const request: ClientRequest = {
method: "completion/complete",
params: {
argument: {
name: argName,
value,
},
ref,
},
};

try {
const response = await mcpClient.complete(request.params, {
signal,
});
pushHistory(request, response);

return response?.completion.values || [];
} catch (e: unknown) {
const errorMessage = e instanceof Error ? e.message : String(e);
pushHistory(request, { error: errorMessage });

toast.error(errorMessage);
throw e;
}
};
Copy link
Member

Choose a reason for hiding this comment

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

Can we use the makeRequest function above?

Copy link
Author

Choose a reason for hiding this comment

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

Sure thing! Will work on this today.

As a side note - I've noticed that the current Spec does not allow servers to indicate whether they support completions, as far as I understand. So if we request completions from a server that does not provide a handler, we get a Method not found error (-32601).

In the short term, I can address this by tracking that specific error and disable further requests for the selected template or prompt.

Long term I feel it would be good to include completions as part of the capability negotiation
e.g.

const server = new Server({
  name: 'My server',
  version: '1.0.0',
}, {
    capabilities: {
      resources: { subscribe: true, completions: true },
      prompts: { completions: true},
    }
  })

Let me know your thoughts or if there's anything I might have overlooked.

Copy link
Member

Choose a reason for hiding this comment

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

Fair callout. If you don't mind, could you open a discussion in the specification repo?

Copy link
Author

Choose a reason for hiding this comment

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

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