Skip to content

Allow registration of custom JSON-RPC methods #954

Description

@jeongukjae

Is your feature request related to a problem? Please describe.

I'm contributing about SEP-2624 in modelcontextprotocol/experimental-ext-interceptors, which implements interceptors for MCP protocols. This feature requires extending the protocol with custom JSON-RPC methods.

Although the Golang SDK provides a solid interface, it currently does not allow to extend handlers for custom JSON-RPC methods.

Describe the solution you'd like

The mcp package can expose following interfaces

  • Add methods to both the Client and Server to register receiving and sending custom methods. For example:
    • AddReceivingCustomMethod[P paramsPtr[T], R Result, T any](method string, handler typedServerMethodHandler[P, R])
    • AddSendingCustomMethod[P paramsPtr[T], R Result, T any](method string, handler typedClientMethodHandler[P, R])
  • Export other internal components that are necessary to implement these custom handlers, such as Params.isParams, Result.isResult, typedServerMethodHandler, typedClientMethodHandler, paramsPtr, etc.

Describe alternatives you've considered

N/A

Additional context

For reference, we have already implemented AddReceivingCustomMethod for the server in a vendored version of the library. You can view the implementation details here:


happy to contribute once agreed.

Activity

  1. jba commented on May 28, 2026

    @jba
    Contributor

    I'm contributing about SEP-2624 in modelcontextprotocol/experimental-ext-interceptors, which implements interceptors for MCP protocols. This feature requires extending the protocol with custom JSON-RPC methods.

    Can you explain the connection? I looked over the SEP and I don't see why it requires custom methods.

  2. jeongukjae commented on May 28, 2026

    @jeongukjae
    ContributorAuthor

    @jba Hi, the SEP introduces following JSON RPC methods

  3. jba commented on May 28, 2026

    @jba
    Contributor

    Why can't we just add those to our code directly, as we have done for all the other MCP methods?
    See serverMethodInfos in mcp/server.go.

  4. jeongukjae commented on May 29, 2026

    @jeongukjae
    ContributorAuthor

    That's good point, but the proposed SEP is still experimental.
    Making them standard requires more process on the SEP and alignment.

    + I think this feature is not only applied to interceptors. This would be helpful for other possible extensions.

  5. jba commented on May 29, 2026

    @jba
    Contributor

    Let's find a concrete, compelling use case before we open up method registration. This doesn't seem to be it.

    There's probably a way to make them experimental with a build tag, but I haven't thought it through.

  6. jeongukjae commented on Jun 8, 2026

    @jeongukjae
    ContributorAuthor

    @jba please let me know if you have any other way to do this. I'm open to implement in another way. But this seems good use case and test bed for method registration in my view.

  7. jeongukjae commented on Jun 16, 2026

    @jeongukjae
    ContributorAuthor
  8. jba commented on Jun 22, 2026

    @jba
    Contributor

    @jba please let me know if you have any other way to do this. I'm open to implement in another way. But this seems good use case and test bed for method registration in my view.

    You're not addressing my concerns.

    Let's find a concrete, compelling use case before we open up method registration. This doesn't seem to be it.

    I'd need to see another use case other than this for your proposal.

    There's probably a way to make them experimental with a build tag, but I haven't thought it through.

    You need to learn about build tags, try them for this problem, and come back here with either "I tried but I don't think they'll work, let me explain why" or "I tried and I succeeded, here's the updated PR."

  9. jeongukjae commented on Jun 23, 2026

    @jeongukjae
    ContributorAuthor

    Hi!

    I really want to clarify that I'm not currently the author of opened pr and I'm not arguing for or against build tags. i'm just tracking this issue because I want to make progression on downstream project. and that was why I tagged the author of the PR here. I understand maintainers may have different views, and may reject this feature request. That's also sensible and I respect that.

    Also to answer your points:

    On writing the extensions code directly into go-sdk - it's still in experimental, it may not even be approved. Still evolving. I want to avoid prototyping in go-sdk repository. If it's graduating, I agree with you.

    On the build tags - fortunately, I'm already familiar with it. I think it can be done either 1) writing interceptor codes directly into go-sdk with build tags or 2) providing custom method registration with build tags. but for (1), as I mentioned above, I want to avoid to do it during prototyping. For (2), I want to leave the decisions to reviewers and pr authors.

    Also I want to ask you about the policies of go-sdk. I believe prototypings should happen in isolated repository following this doc, but does go-sdk encourage to contribute those directly to go-sdk?

  10. imfing commented on Jun 23, 2026

    @imfing
    Contributor

    Let's find a concrete, compelling use case before we open up method registration. This doesn't seem to be it.

    I'd need to see another use case other than this for your proposal.

    Just to add to @jeongukjae's comments, there are already concrete examples of custom JSON-RPC methods in use, specifically in the official extensions (Apps and Tasks).

    The Tasks extension introduces tasks/get, tasks/list, tasks/result, tasks/update, tasks/cancel, and notifications/tasks/status, all methods outside the core spec that need to be dispatched by the SDK.

    MCP Apps similarly introduces ui/initialize, ui/notifications/initialized, and ui/notifications/size-changed for iframe-host communication.

    The extension mechanism (SEP-1724) is designed so that new capabilities can be negotiated and custom JSON-RPC methods can be used to extend the protocol. Compared to the other language SDKs mentioned above, the lack of custom method support makes it difficult to implement extensions on Go servers.

  11. jba commented on Jun 23, 2026

    @jba
    Contributor

    I read SEP-1724, in particular the following:

    SDKs may optionally implement any number of extensions and where appropriate (and necessary) should provide facilities for enabling and configuring extensions. Extensions must be disabled by default and require opt-in. SDK documentation should list supported extensions.

    This seems to say that the SDKs should implement official exceptions.

    Please open issues on this repo (if not open already) and submit PRs for them.

  12. jba commented on Jun 23, 2026

    @jba
    Contributor

    I believe prototypings should happen in isolated repository following this doc

    I think you're misreading that (but it might be me). The specs are in separate repos, but that doc says:

    Implement: Build at least one reference implementation in an official SDK — this is required before the SEP can be reviewed.

    I interpret that as meaning that you have to add it to an official SDK. In the case of Go, you can submit a PR with a build tag, or you can fork the repo.

  13. jba commented on Jun 23, 2026

    @jba
    Contributor

    Let me be clear about my objection to custom methods.

    Go has only two visibility levels:

    • Only within the package or module.
    • Everyone.

    If everyone can use custom methods, then that endorses anyone to effectively implement an alternative protocol. We could expect hundreds of slightly different MCP servers and clients, fragmenting the ecosystem.

    While it's still possible to do this by forking the repo, at least you know that when you fork, you're going outside the usual development process. If we have exported symbols for extending the protocol, people will think it's fine to do it.

  14. jba commented on Jun 23, 2026

    @jba
    Contributor

    By the way, #755 starts to implement tasks.

  15. imfing commented on Jun 24, 2026

    @imfing
    Contributor

    If everyone can use custom methods, then that endorses anyone to effectively implement an alternative protocol. We could expect hundreds of slightly different MCP servers and clients, fragmenting the ecosystem.

    Preventing the fragmentation isn't really go-sdk's responsibility. The SEP process, extension mechanisms, and capability negotiation are what's designed against "hundreds of slightly different MCP servers".

    This seems like a reasonable, narrowly scoped feature that primarily brings the Go SDK into alignment with the capabilities already exposed by other official SDKs. Without that, developers are effectively pushed toward maintaining forks or using a different SDK entirely.

    By the way, #755 starts to implement tasks.

    BTW, this PR wasn't updated over the past 3 months, it's effectively abandoned

  16. jba commented on Jun 24, 2026

    @jba
    Contributor

    developers are effectively pushed toward maintaining forks or using a different SDK entirely

    I think the key word here is "developers." Are we talking about "developers of the SDK" or "developers using the SDK"? Maybe I'm confused, but I think it's the first one.

    Developers of the SDK should develop the SDK itself. They should not build things on top of it. That is for everyone else. To develop the SDK, you submit a PR. If the PR implements an experimental feature, gate it with a build tag.

    Developers using the SDK should not need custom methods. They are following—indeed, they are constrained to follow—the MCP spec. The right way to get a "custom method" into the SDK is to write a SEP.

    Why would you need to maintain a fork? Maybe one possibility is this: you work for an organization that really wants tasks, for example, and you want them now. You don't want to wait for the maintainers to review your changes, and you can't use custom methods to implement them, so you must fork.

    That seems like the right model to me. If you need something in an API before the package maintainers can do it, you send a PR to them (because you're a good open-source citizen) and then run on a fork that includes your PR until it's accepted. That is true of all open-source software, isn't it?

    The SEP process, extension mechanisms, and capability negotiation are what's designed against "hundreds of slightly different MCP servers".

    But aren't you trying to subvert those processes? I mean, maybe not you—you're implementing an official exension, let's say—but the next person. They can now implement their favorite feature without any of those pesky administrative details.

    Again, I may be missing something. If there were in fact an "extension" feature that implied that anyone could extend the SDK with custom methods, we would implement it. But AFAICT, "extensions" are protocol extensions that are nevertheless implemented within the SDK. You seem to disagree with this: above you wrote

    The extension mechanism (SEP-1724) is designed so that new capabilities can be negotiated and custom JSON-RPC methods can be used to extend the protocol. Compared to the other language SDKs mentioned above, the lack of custom method support makes it difficult to implement extensions on Go servers.

    but in response I wrote:

    [SEP-1724] seems to say that the SDKs should implement official exceptions.

    Maybe we should focus on this narrow point, since it seems to be at the root of our disagreement.

  17. sambhav commented on Jun 24, 2026

    @sambhav
    Member

    @jba I think we're still talking past each other a bit, so let me try to separate the concerns.

    Where we agree

    When you say that extensions are protocol extensions implemented within the SDK, I agree — that is a reasonable path for official extensions. Once an extension has graduated through the SEP process and a given SDK maintainer wants to support it directly, implementing it in that SDK via PR makes complete sense.

    What this issue is actually about

    The extensions motivating this issue are experimental — they're in the incubation phase, before SEP acceptance. SEP-2133 explicitly creates a separate governance path for this:

    • Experimental extension repos live under the modelcontextprotocol org with the experimental-ext- prefix
    • They are associated with a WG or IG, with their own maintainers responsible for day-to-day governance
    • They must be separate packages that clearly indicate their experimental status

    These are not rogue projects, but they are also not SDK-owned code. Experimental extension maintainers are not necessarily Go SDK maintainers, and the whole point of the experimental path is to let WGs and IGs iterate separately — without being bottlenecked on SDK-maintainer review for code that is still evolving and may never be approved.

    What I'm asking for

    I am not asking the Go SDK maintainers to accept, implement, bless, or maintain any particular extension.

    I am asking for the SDK to be usable as a library by code that needs to extend MCP in the way SEP-2133 anticipates. The spec itself contemplates this:

    "This SEP does not prescribe how SDKs should structure or package extensions. Maintainers may provide extension points, plugin systems, or any other mechanism they see fit."

    Concretely, a clean separation would look like:

    • The Go SDK owns the core API, routing, validation, and safety invariants
    • Experimental extension maintainers own their experimental packages
    • Consumers explicitly opt into those packages
    • Nothing experimental is enabled by default or shipped as part of the core SDK
    • The SDK exposes only a narrow, controlled API for custom method registration

    Why the alternatives don't work

    Build tags — Putting experimental extension code into the main SDK, even behind build tags, is actually what I want to avoid. It couples experimental work to the SDK release surface, creates dependency and govulncheck noise for downstream users who aren't using the extension, and makes Go SDK maintainers the de facto gatekeepers for experimental extension iteration. Every change goes through the SDK repo, even when the extension has separate maintainers and a separate cadence.

    Forking — We actually tried this. The experience is difficult in practice — the fork needs constant rebasing as the underlying SDK evolves, and when you're trying to prove out an experimental extension with real use cases, that rebasing overhead becomes a serious drag on iteration. The whole value of building on top of an SDK is that you get transport, auth, protocol handling, etc. for free. A fork doesn't give you that cleanly — it gives you a snapshot that immediately starts diverging.

    Forking also breaks down entirely when you need to stack multiple experimental extensions. Each experimental extension is developed independently in its own experimental-ext-* repo by its own maintainers — if you want to combine two or three of them, there's no clean way to layer independent forks. You end up maintaining a single mega-fork that cherry-picks from multiple extension repos, which is fragile and defeats the purpose of independent experimentation. With a custom method registration API, each extension is just a separate dependency that registers its methods independently, and they compose naturally on top of a single, unmodified SDK.

    The model that works well in other official SDKs is much simpler: for example, in the TypeScript SDK, an extension is a separate dependency that imports the SDK and registers its additional methods. The underlying SDK version stays independent and updatable. That's exactly the separation SEP-2133 envisions — and it's what a narrow extension point like AddMethod would enable here.

    This is already proven elsewhere

    Nearly every official SDK already provides custom method registration. We have working server and client implementations proving out the experimental extension in several of these:

    SDK Custom Method Registration API
    TypeScript ✅ setRequestHandler() / setNotificationHandler()
    Python ✅ add_request_handler() / add_notification_handler()
    C# ✅ Message filters
    Ruby ✅ Custom server methods
    PHP ✅ Custom message handlers
    Rust ✅ CustomRequest
    Kotlin ✅ setRequestHandler(Method.Custom(...))
    Swift ✅ withMethodHandler() via protocol conformance
    Java ❌ Handlers are private, set at construction only
    Go ❌ No public API for custom methods

    On fragmentation

    If everyone can use custom methods, then that endorses anyone to effectively implement an alternative protocol.

    I understand this concern. But the MCP project already handles fragmentation at the protocol level — vendor-prefixed identifiers, capability negotiation during initialize, and graceful degradation requirements. Those are the mechanisms designed for this, and the other official SDKs have all adopted custom method registration without the ecosystem fragmenting as a result.

    The middle ground

    I don't think the right dichotomy is "implemented in the SDK" versus "unsupported alternative protocol." There is a middle ground: the SDK exposes a controlled extension point, while extension packages remain separate, clearly marked, opt-in, and governed by their own maintainers.

    That would let the Go SDK preserve its safety boundaries without taking ownership of experimental extension code — and it would let the experimental extension process function as SEP-2133 designed it.

  18. jba commented on Jun 24, 2026

    @jba
    Contributor

    OK, this is the first time I looked at SEP 2133. Concurrently, Kurtis Van Gent pointed me there too. Up until now I've been looking at SEP 1724, which I guess is the issue that turned into 2133.

    2133 says:

    This SEP does not prescribe how SDKs should structure or package extensions. Maintainers may provide extension points, plugin systems, or any other mechanism they see fit.

    So that sanctions custom methods.

    I approve of this change. (That was easy!)

  19. jba commented on Jun 24, 2026

    @jba
    Contributor

    Next step is a PR. Do we have a volunteer? Also, I'm not the primary maintainer, I've only been dealing with this issue. So they need to be involved. I don't think there will be any disagreement, they just have to sign off on the review, since they will be maintaining it.

  20. sambhav commented on Jun 24, 2026

    @sambhav
    Member

    I believe we already have a PR from @guglielmo-san who I believe is a maintainer?

    #956

    He was waiting on your comments before that PR progressed further.

    #956 (comment)

  21. guglielmo-san commented on Jun 25, 2026

    @guglielmo-san
    Contributor

    @sambhav @jeongukjae @imfing can you confirm if the current implementation of the PR #956 meets your needs?

  22. jeongukjae commented on Jun 25, 2026

    @jeongukjae
    ContributorAuthor

    @guglielmo-san it seems like the pr implements what interceptor wg needs. thanks!

    btw, for the completeness, I think it's worth to consider sending custom method from server, and receiving one from client. (the opposite direction that pr implemented)

  23. added a commit that references this issue on Jun 26, 2026
    65ece59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions