Skip to content

feat: Adds optional _meta to request input forms. #514

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

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
9 changes: 7 additions & 2 deletions cli/src/client/prompts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { McpResponse } from "./types.js";

// List available prompts
export async function listPrompts(client: Client): Promise<McpResponse> {
export async function listPrompts(
client: Client,
_meta?: Record<string, unknown>,
): Promise<McpResponse> {
try {
const response = await client.listPrompts();
const response = await client.listPrompts({ _meta });
return response;
} catch (error) {
throw new Error(
Expand All @@ -18,11 +21,13 @@ export async function getPrompt(
client: Client,
name: string,
args?: Record<string, string>,
_meta?: Record<string, unknown>,
): Promise<McpResponse> {
try {
const response = await client.getPrompt({
name,
arguments: args || {},
_meta,
});

return response;
Expand Down
13 changes: 9 additions & 4 deletions cli/src/client/resources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { McpResponse } from "./types.js";

// List available resources
export async function listResources(client: Client): Promise<McpResponse> {
export async function listResources(
client: Client,
_meta?: Record<string, unknown>,
): Promise<McpResponse> {
try {
const response = await client.listResources();
const response = await client.listResources({ _meta });
return response;
} catch (error) {
throw new Error(
Expand All @@ -17,9 +20,10 @@ export async function listResources(client: Client): Promise<McpResponse> {
export async function readResource(
client: Client,
uri: string,
_meta?: Record<string, unknown>,
): Promise<McpResponse> {
try {
const response = await client.readResource({ uri });
const response = await client.readResource({ uri, _meta });
return response;
} catch (error) {
throw new Error(
Expand All @@ -31,9 +35,10 @@ export async function readResource(
// List resource templates
export async function listResourceTemplates(
client: Client,
_meta?: Record<string, unknown>,
): Promise<McpResponse> {
try {
const response = await client.listResourceTemplates();
const response = await client.listResourceTemplates({ _meta });
return response;
} catch (error) {
throw new Error(
Expand Down
11 changes: 8 additions & 3 deletions cli/src/client/tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@ type JsonSchemaType = {
items?: JsonSchemaType;
};

export async function listTools(client: Client): Promise<McpResponse> {
export async function listTools(
client: Client,
_meta?: Record<string, unknown>,
): Promise<McpResponse> {
try {
const response = await client.listTools();
const response = await client.listTools({ _meta });
return response;
} catch (error) {
throw new Error(
Expand Down Expand Up @@ -69,9 +72,10 @@ export async function callTool(
client: Client,
name: string,
args: Record<string, string>,
_meta?: Record<string, unknown>,
): Promise<McpResponse> {
try {
const toolsResponse = await listTools(client);
const toolsResponse = await listTools(client, _meta);
const tools = toolsResponse.tools as Tool[];
const tool = tools.find((t) => t.name === name);

Expand All @@ -85,6 +89,7 @@ export async function callTool(
const response = await client.callTool({
name: name,
arguments: convertedArgs,
_meta,
});
return response;
} catch (error) {
Expand Down
112 changes: 81 additions & 31 deletions client/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -422,11 +422,14 @@ const App = () => {
}
};

const listResources = async () => {
const listResources = async (meta?: Record<string, unknown> | null) => {
const response = await sendMCPRequest(
{
method: "resources/list" as const,
params: nextResourceCursor ? { cursor: nextResourceCursor } : {},
params: {
...(nextResourceCursor ? { cursor: nextResourceCursor } : {}),
...(meta && { _meta: meta }),
},
},
ListResourcesResultSchema,
"resources",
Expand All @@ -435,13 +438,18 @@ const App = () => {
setNextResourceCursor(response.nextCursor);
};

const listResourceTemplates = async () => {
const listResourceTemplates = async (
meta?: Record<string, unknown> | null,
) => {
const response = await sendMCPRequest(
{
method: "resources/templates/list" as const,
params: nextResourceTemplateCursor
? { cursor: nextResourceTemplateCursor }
: {},
params: {
...(nextResourceTemplateCursor
? { cursor: nextResourceTemplateCursor }
: {}),
...(meta && { _meta: meta }),
},
},
ListResourceTemplatesResultSchema,
"resources",
Expand All @@ -452,24 +460,30 @@ const App = () => {
setNextResourceTemplateCursor(response.nextCursor);
};

const readResource = async (uri: string) => {
const readResource = async (
uri: string,
meta?: Record<string, unknown> | null,
) => {
const response = await sendMCPRequest(
{
method: "resources/read" as const,
params: { uri },
params: { uri, ...(meta && { _meta: meta }) },
},
ReadResourceResultSchema,
"resources",
);
setResourceContent(JSON.stringify(response, null, 2));
};

const subscribeToResource = async (uri: string) => {
const subscribeToResource = async (
uri: string,
meta?: Record<string, unknown> | null,
) => {
if (!resourceSubscriptions.has(uri)) {
await sendMCPRequest(
{
method: "resources/subscribe" as const,
params: { uri },
params: { uri, ...(meta && { _meta: meta }) },
},
z.object({}),
"resources",
Expand All @@ -480,12 +494,15 @@ const App = () => {
}
};

const unsubscribeFromResource = async (uri: string) => {
const unsubscribeFromResource = async (
uri: string,
meta?: Record<string, unknown> | null,
) => {
if (resourceSubscriptions.has(uri)) {
await sendMCPRequest(
{
method: "resources/unsubscribe" as const,
params: { uri },
params: { uri, ...(meta && { _meta: meta }) },
},
z.object({}),
"resources",
Expand All @@ -496,11 +513,14 @@ const App = () => {
}
};

const listPrompts = async () => {
const listPrompts = async (meta?: Record<string, unknown> | null) => {
const response = await sendMCPRequest(
{
method: "prompts/list" as const,
params: nextPromptCursor ? { cursor: nextPromptCursor } : {},
params: {
...(nextPromptCursor ? { cursor: nextPromptCursor } : {}),
...(meta && { _meta: meta }),
},
},
ListPromptsResultSchema,
"prompts",
Expand All @@ -509,23 +529,43 @@ const App = () => {
setNextPromptCursor(response.nextCursor);
};

const getPrompt = async (name: string, args: Record<string, string> = {}) => {
const getPrompt = async (
name: string,
args: Record<string, string> = {},
meta?: Record<string, unknown> | null,
) => {
console.log("getPrompt _meta", meta);
const requestParams: {
name: string;
arguments: Record<string, string>;
_meta?: Record<string, unknown>;
} = { name, arguments: args };

// Simplified condition: if meta is a non-null object, add it.
// This covers both empty and non-empty objects.
if (meta && typeof meta === "object") {
requestParams._meta = meta;
}

const response = await sendMCPRequest(
{
method: "prompts/get" as const,
params: { name, arguments: args },
params: requestParams,
},
GetPromptResultSchema,
"prompts",
);
setPromptContent(JSON.stringify(response, null, 2));
};

const listTools = async () => {
const listTools = async (meta?: Record<string, unknown> | null) => {
const response = await sendMCPRequest(
{
method: "tools/list" as const,
params: nextToolCursor ? { cursor: nextToolCursor } : {},
params: {
...(nextToolCursor ? { cursor: nextToolCursor } : {}),
...(meta && { _meta: meta }),
},
},
ListToolsResultSchema,
"tools",
Expand All @@ -536,7 +576,11 @@ const App = () => {
cacheToolOutputSchemas(response.tools);
};

const callTool = async (name: string, params: Record<string, unknown>) => {
const callTool = async (
name: string,
params: Record<string, unknown>,
meta?: Record<string, unknown> | null,
) => {
try {
const response = await sendMCPRequest(
{
Expand All @@ -545,7 +589,8 @@ const App = () => {
name,
arguments: params,
_meta: {
progressToken: progressTokenRef.current++,
...(meta && meta), // Spread incoming meta
progressToken: progressTokenRef.current++, // Keep existing progressToken
},
},
},
Expand Down Expand Up @@ -767,25 +812,29 @@ const App = () => {
<ResourcesTab
resources={resources}
resourceTemplates={resourceTemplates}
listResources={() => {
listResources={(
meta?: Record<string, unknown> | null,
) => {
clearError("resources");
listResources();
listResources(meta);
}}
clearResources={() => {
setResources([]);
setNextResourceCursor(undefined);
}}
listResourceTemplates={() => {
listResourceTemplates={(
meta?: Record<string, unknown> | null,
) => {
clearError("resources");
listResourceTemplates();
listResourceTemplates(meta);
}}
clearResourceTemplates={() => {
setResourceTemplates([]);
setNextResourceTemplateCursor(undefined);
}}
readResource={(uri) => {
readResource={(uri, meta) => {
clearError("resources");
readResource(uri);
readResource(uri, meta);
}}
selectedResource={selectedResource}
setSelectedResource={(resource) => {
Expand Down Expand Up @@ -821,9 +870,9 @@ const App = () => {
setPrompts([]);
setNextPromptCursor(undefined);
}}
getPrompt={(name, args) => {
getPrompt={(name, args, meta) => {
clearError("prompts");
getPrompt(name, args);
getPrompt(name, args, meta);
}}
selectedPrompt={selectedPrompt}
setSelectedPrompt={(prompt) => {
Expand All @@ -841,18 +890,19 @@ const App = () => {
tools={tools}
listTools={() => {
clearError("tools");
listTools();
listTools(); // TODO: Pass meta from ToolsTab if MetaEditor is added there
}}
clearTools={() => {
setTools([]);
setNextToolCursor(undefined);
// Clear cached output schemas
cacheToolOutputSchemas([]);
}}
callTool={async (name, params) => {
callTool={async (name, params, meta) => {
// Accept meta here
clearError("tools");
setToolResult(null);
await callTool(name, params);
await callTool(name, params, meta); // Pass meta
}}
selectedTool={selectedTool}
setSelectedTool={(tool) => {
Expand Down
Loading