Skip to content

feat: add mcp client injection#526

Draft
parvahuja wants to merge 1 commit into
wevm:mainfrom
parvahuja:parv/mcp-client-inject
Draft

feat: add mcp client injection#526
parvahuja wants to merge 1 commit into
wevm:mainfrom
parvahuja:parv/mcp-client-inject

Conversation

@parvahuja

Copy link
Copy Markdown

Summary

  • Add withMppClient / McpClient.inject for payment-aware MCP SDK clients while preserving the SDK callTool shape.
  • Handle MCP payment-required errors and metadata, returning successful tool results with optional MPP Receipts.
  • Add Tempo Accounts Provider-backed client resolution for tempo.charge and session methods.

Validation

  • pnpm check:ci
  • pnpm check:types
  • pnpm build
  • git diff --check
  • VITE_TEMPO_NETWORK=none pnpm exec vp test --project node --testNamePattern 'McpClient|tempo\\.charge client|precompile client session' (48 passed; 3 MCP payment tests could not complete because local Tempo RPC at localhost:18545 was unavailable)

@parvahuja

Copy link
Copy Markdown
Author

I can technically split this into two PRs if that makes it easier to review lmk...

One for the MCP SDK client helpers and another for Tempo Accounts Provider-backed clients

import type { Client } from '@modelcontextprotocol/sdk/client/index.js'
import { tempo } from 'mppx/client'
import type { Account } from 'viem'
import type { JsonRpcAccount } from 'viem/accounts'

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

can this file just be src/mcp?

you should be able to import via 'mppx/mcp/client'

type CallToolRequestOptions = Parameters<Client['callTool']>[2]
type PaymentRequiredData = NonNullable<core_Mcp.ErrorObject['data']>

const MPPX_MCP_CLIENT_WRAPPER = Symbol.for('mppx.mcp.client.wrapper')

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

👍

* await mcp.callTool({ name: 'premium_tool', arguments: {} })
* ```
*/
export function withMppClient<

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

can this just be wrapClient? MPP is a bit redundant

const client extends Pick<Client, 'callTool'>,
const methods extends Methods,
>(client: client, config: withMppClient.Config<methods>): withMppClient.McpClient<client, methods> {
return inject(client, config)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

what is the diff between inject and wrap?

return Array.isArray(challenges) && challenges.length > 0
}

function normalizeCallToolOptions<methods extends Methods>(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

is there a more structured way to do these checks? this is pretty loose, which is maybe ok with strong table driven tests, but I feel like it can be simpler

* This keeps mppx independent from the `accounts` package while allowing callers
* to pass an Accounts Provider directly to Tempo client methods.
*/
export type Provider = {

Copy link
Copy Markdown
Collaborator

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