Skip to content

mcp no longer works in OSGi #562

Closed
Closed

Description

@benken-parasoft

Bug description
In version 0.12, there was a single "mcp" jar which happens to be a valid OSGi bundle having a valid OSGi manifest. Its dependencies all happen to be OSGi bundles as well. So, mcp and all its dependencies have been loading in OSGi without issue.

In version 0.13, the "mcp" jar has been replaced with "mcp-core" and "mcp-json-jackson2". Although "mcp-core" is still an OSGi bundle, "mcp-json-jackson2" is not.

Environment
I have been using an Apache Felix Servlet Bridge setup but the OSGi container shouldn't matter.

Steps to reproduce
Building an McpServer from an OSGi container results in the following:

java.lang.IllegalStateException: No default JsonSchemaValidatorSupplier implementation found
 at io.modelcontextprotocol.json.schema.JsonSchemaInternal.lambda$createDefaultValidator$2(JsonSchemaInternal.java:66)
 at java.base/java.util.Optional.orElseThrow(Optional.java:403)
 at io.modelcontextprotocol.json.schema.JsonSchemaInternal.createDefaultValidator(JsonSchemaInternal.java:61)
 at io.modelcontextprotocol.json.schema.JsonSchemaInternal.getDefaultValidator(JsonSchemaInternal.java:30)
 at io.modelcontextprotocol.json.schema.JsonSchemaValidator.getDefault(JsonSchemaValidator.java:61)
 at io.modelcontextprotocol.server.McpServer$StreamableSyncSpecification.build(McpServer.java:848)

Expected behavior

The "mcp-json-jackson2" jar should have an OSGi manifest. The mcp bundles should have proper "Require-Capability" and "Provide-Capability" headers to support the OSGi Service Loader mechanism, like what's implemented by Apache SPI Fly: https://aries.apache.org/documentation/modules/spi-fly.html#specconf

Minimal Complete Reproducible example

The original Servlet Bridge example is here:
https://github.com/apache/felix-dev/tree/8c10c79ff48b6a8938e9fc8088964a2facb42da1/http/samples/bridge

You would need to add your own OSGi bundle with a bundle Activator that starts an MCP server and registers its transport using the OSGi HTTP service. Some detail: https://github.com/apache/felix-dev/blob/master/http/README.md#using-the-httpservice

Workaround

The workaround is to wrap the "mcp-json-jackson2" jar inside of a custom OSGi bundle and to explicitly call "Builder.jsonMapper" and "jsonSchemaValidator" methods on everything to avoid the broken service lookup.

Activity

  1. rombert commented on Nov 21, 2025

    @rombert

    I also think that making the 'original' artifacts compatible with OSGi environments is the way to go. Moving to another project creates responsibility and reproducibility issues that will hinder adoption.

    It looks to me like the current OSGi consumers are willing to use the MCP SDK as-is, have found workarounds to minor issues and are willing to contribute fixes.

    I am certain that we can find a solution that is acceptable to the maintainers and get the minor issues solved. I sincerely hope that we will not lose OSGi support for the main artifacts.

  2. benken-parasoft commented on Nov 21, 2025

    @benken-parasoft
    Author

    While additional META-INF metadata is acceptable

    I believe the jars should be correctly defined as bundles, each owning their own package with proper import/export declarations in their MANIFEST.MF.

    rewriting jars and creating fat jars is out of scope

    I'm have to wrap "mcp-json-jackson2" inside my own bundle as a workaround. Wrapping jars inside other jars definitely shouldn't be the solution.

    Including bnd-maven-plugin in core was a mistake that we'll clean in the follow up versions.

    I recommend the Apache maven-bundle-plugin.

    Perhaps we can consider creating a separate GH repo

    I can't agree this is a good direction. I've seen this type of thing happen before, where you have someone else maintaining their own "repackaged" version of some other project, published under some other groupId. It's really a workaround and requires someone else doing their own maintenance, keeping up with releases of the main project, etc. Eventually such projects become obsolete when the main project finally catches up.

  3. scottslewis commented on Nov 21, 2025

    @scottslewis

    While additional META-INF metadata is acceptable, rewriting jars and creating fat jars is out of scope.

    I have contributed a pr #682 as a fix for issue #612.

    The fix in #682 has a positive side effect of allowing/keeping mcp-core, mcp-jackson2, and other mcp-sdk jars separate (no need for a single jar/bundle for OSGi).

    Additionally, #682 has this commit, which fixes the original problem as reported in this bug...i.e. the setting of a default json mapper/validator via osgi declarative services (osgi environments) and the use of ServiceLoader (all other java environments).

    Happily then, #682 also provides a fix for this specific issue...which was due to the use of ServiceLoader for inter-jar service dependency (default singleton service for json gen/parsing/validating). It is, however, a general approach for supporting osgi environments using the OSGi service registry, and all non-osgi java environments using ServiceLoader. The same approach can be used elsewhere in mcp-sdk if needed.

    This requires no environment-specific code, only META-INF and OSGI-INF metadata. I'm happy to explain further how this works in OSGI and non-OSGi environments if desired.

  4. scottslewis commented on Nov 25, 2025

    @scottslewis

    While additional META-INF metadata is acceptable, rewriting jars and creating fat jars is out of scope.

    I have contributed a pr #682 as a fix for issue #612.

    I've enhanced this pr, done some simplifying refactoring and tested the meta-data additions in osgi.

    With these changes, mcp-core does not need mcp-json jar nor mcp-jackson2 jar at compile time (as per #612), and at runtime it only needs mcp-jackson2 jar (or some other/non-Jackson impl of mcp json mapper and mcp json validator services).

    In non-osgi runtimes, the ServiceLoader creates the default instances of the mapper and validator services via the mapper and validator suppliers as before.

    In osgi runtimes, json default instances are created and used via OSGi declarative services (via manifest and xml metadata in OSGI-INF directory) using the same java classes.

  5. scottslewis commented on Dec 5, 2025

    @scottslewis

    Summary: As described above, pr #682 issue #612 provides a permanent fix for this issue by:

    1. Migrating the < 10 classes currently in the mcp-json project/jar back into mcp-core. As described in Mcp-core has compile-time dependency on mcp-json #612 mcp-core currently has a compile-time dependency on mcp-json classes.

    2. Modifying the default json mapper and schema validation providers to allow OSGi declarative services to be used (available only in osgi environments) to set the providers upon startup...rather than use the ServiceLoader...which is still the default outside of osgi environments.

    3. Add standard declarative services metadata to the mcp-core manifest and the mcp-jackson2 manifest creation on build. This consists of a small addition of a declarative services xml files, and references to those files in the manifest.mf as per the osgi specification.

    The result is a mcp-core.jar and mcp-jackson2 jar that when used in non-osgi environments: uses the ServiceLoader to set the mapper provider and schema validation provider to set the default (jackson2, if that's the jar present at runtime, or other).

    and when used in osgi environments: uses declarative services to set the mapper provider and schema validation provider defaults via osgi services.

    I've tested the osgi environment behavior by using it in a recent update to this project, which is osgi based.

  6. sdeleuze commented on Jan 12, 2026

    @sdeleuze
    Contributor

    @scottslewis I am planning to contribute a new mcp-json-jackson3 module via a PR, I would welcome your feedback from an OSGI perpective.

    Currently mcp-json-jackson2 is using the io.modelcontextprotocol.json.jackson and io.modelcontextprotocol.json.schema.jackson packages.

    I am wondering if we should either:

    1. Use the same version-less packages in both mcp-json-jackson2 and mcp-json-jackson3
    2. Use the Jackson version in the package, which would lead to use io.modelcontextprotocol.json.jackson2/io.modelcontextprotocol.json.schema.jackson2 for mcp-json-jackson2 and io.modelcontextprotocol.json.jackson3/io.modelcontextprotocol.json.schema.jackson3 for mcp-json-jackson3.

    1 has the advantage of not breaking the current API. mcp-json-jackson2 and mcp-json-jackson3 are not really designed to be used at the same time, but should we go as far as using the same package for those mutually-exclusive implementations? 2 clearly separate both at package level but is a breaking change (maybe ok since we still use 0.x versions).

    cc @graemerocher @sdelamo

  7. scottslewis commented on Jan 12, 2026

    @scottslewis

    @scottslewis I am planning to contribute a new mcp-json-jackson3 module via a PR, I would welcome your feedback from an OSGI perpective.

    Currently mcp-json-jackson2 is using the io.modelcontextprotocol.json.jackson and io.modelcontextprotocol.json.schema.jackson packages.

    I am wondering if we should either:

    1. Use the same version-less packages in both `mcp-json-jackson2` and `mcp-json-jackson3`
    
    2. Use the Jackson version in the package, which would lead to use `io.modelcontextprotocol.json.jackson2`/`io.modelcontextprotocol.json.schema.jackson2` for `mcp-json-jackson2` and `io.modelcontextprotocol.json.jackson3`/`io.modelcontextprotocol.json.schema.jackson3` for `mcp-json-jackson3`.
    

    1 has the advantage of not breaking the current API. mcp-json-jackson2 and mcp-json-jackson3 are not really designed to be used at the same time, but should we go as far as using the same package for those mutually-exclusive implementations? 2 clearly separate both at package level but is a breaking change (maybe ok since we still use 0.x versions).

    cc @graemerocher @sdelamo

    This is a difficult choice IMHO. My inclination is to do what you describe and a new, jackson3 project that can live/run alongside jackson2 and have different package names. Reason: You can be pretty sure that there will be some consumers of the sdk that even as jackson3 gets more common/used that they will require continuing to use Jackson2...even while they use new versions of the sdk (e.g. to keep up with enhancements/bug fixes). The last thing most consumers will want (especially large ones) is a forced upgrade of any library.

    This is not a serious problem at all in OSGI environments, as the classloader-per-bundle aspect of the environment allows more than one class with the same package/class name. For example, there are separate providers for multiple major versions of httpclient in Eclipse/ECF (the project I've led for long time). These can all run in the same runtime at the same time and do so happily.

    But for non OSGi environments, you can potentially have classloader/class name collision problems. This can make it impossible....or at least very difficult for consumers to use more than one major/incompatible versions of Jackson (or any other lib) at the same time...therefore requiring cutovers. Any such cutover can be very painful (or impossible) for sdk consumers...and so is to be avoided if possible.

  8. filiphr commented on Jan 12, 2026

    @filiphr
    Contributor

    Since I already did a PR for Jackson 3 in #742. I wanted to clarify what @sdeleuze proposed in #562 (comment).

    I do understand where you are coming from @sdeleuze and I would have liked to solve it using the same package name as well. However, I have another idea.

    What if we do the following, create a new mcp-json-jackson module which would have an optional dependency on Jackson 2 and Jackson 3, that's possible since they have different artifacts anyways. That way we can stay with the package io.modelcontextprotocol.json.jackson. Then there can be 2 wrapper modules mcp-json-jackson2 and mcp-json-jackson3 which would only pull in the right dependencies.

    The only problem though would be the schema validation. From what I can see the com.networknt:json-schema-validator does not have different artifacts for the different Jackson versions. There is version 2.0.0 for Jackson 2 and version 3.0.0 for Jackson 3.

  9. scottslewis commented on Jan 12, 2026

    @scottslewis

    Since I already did a PR for Jackson 3 in #742. I wanted to clarify what @sdeleuze proposed in #562 (comment).

    I do understand where you are coming from @sdeleuze and I would have liked to solve it using the same package name as well. However, I have another idea.

    What if we do the following, create a new mcp-json-jackson module which would have an optional dependency on Jackson 2 and Jackson 3, that's possible since they have different artifacts anyways. That way we can stay with the package io.modelcontextprotocol.json.jackson. Then there can be 2 wrapper modules mcp-json-jackson2 and mcp-json-jackson3 which would only pull in the right dependencies.

    The only problem though would be the schema validation. From what I can see the com.networknt:json-schema-validator does not have different artifacts for the different Jackson versions. There is version 2.0.0 for Jackson 2 and version 3.0.0 for Jackson 3.

    If at all possible, I would think you would want to just have one api (i.e. mcp-json...which might go back into mcp-core...i.e. #682). Adding a another api (i.e. across Jackson major versions but not non-jackson providers of json serialization/deserialization) will require more maintenance and build/deployment subtleties over the long term.

    Plus it will cause additional fits for OSGi environments as described here with use of ServiceLoader.

  10. sdeleuze commented on Jan 13, 2026

    @sdeleuze
    Contributor

    If at all possible, I would think you would want to just have one api (i.e. mcp-json...which might go back into mcp-core...i.e. #682). Adding a another api (i.e. across Jackson major versions but not non-jackson providers of json serialization/deserialization) will require more maintenance and build/deployment subtleties over the long term.

    Plus it will cause additional fits for OSGi environments as described here with use of ServiceLoader.

    I am also not convinced that this mcp-json-jackson proposal will help.

    But for non OSGi environments, you can potentially have classloader/class name collision problems.

    For production I don't think we want to support both, but for tests, I can see how we could want that. Also conceptually, it would be a bit of a shame to use the same package while service loader provides a clean way to use a different one.

    In the end, I think my vote is for using different packages (solution 2 from #562 (comment), let's continue this discussion in #742 where I have added a new comment) and merging mcp-json to mcp-core (#682).

  11. scottslewis commented on Jan 29, 2026

    @scottslewis

    For info of people watching this issue:

    pr #762 includes OSGi metadata (Manifest.mf and SCR xml files) that fully addresses this issue. I'm happy to give a technical description of how this is done, but it's mostly covered by previous discussion on this issue so I won't repeat it unless summarization is necessary.

    This includes support for using either Jackson2 xor Jackson3 for mcp serialization. All that's needed to use one or the other is to include the appropirate jar/bundle (mcp-json-jackson2 or mcp-json-jackson3) into your osgi environment alongside mcp-core.

    I'm testing this now in my local osgi environment, so there may be some small changes to the pr in case the osgi meta-data is not right for whatever reason...or there is something about Jackson3 that doesn't work correctly in osgi environments, but I just don't know yet.

  12. scottslewis commented on Feb 8, 2026

    @scottslewis

    I'm testing this now in my local osgi environment

    I've now tested the fixes in pr #762 in OSGi environment (OSGi 8, Java 17 with Service Component Runtime from OSGi 8 spec). This repo has an example/test app that I've been using for testing.

    These tests work with either the jackson2 jackson3 modules. See mcpserver.bndrun and mcpserver.jackson3.bndrun files in mcpserver project (or mcpclient) for details of the runtime configuration for jackson2 vs. jackson3.

  13. scottslewis commented on Feb 17, 2026

    @scottslewis

    @Kerlann : With pr #779 being now merged, this issue is now fixed. It can be closed.

    The default mapper and the default schema validator will be null...as in the original description stack trace...if there is no jackson2 or jackson3 (or some other provider) available at runtime.

    In OSGi environments the service component runtime (SCR) is required.

  14. added theissue type on Feb 20, 2026
  15. chemicL commented on Feb 20, 2026

    @chemicL
    Member

    With the above by @scottslewis and the recent changes I am closing the issue. If that's not correct, please reopen or create a new issue to better describe the current status. Thanks!

  16. garpinc commented on Mar 5, 2026

    @garpinc

    This is still an issue in version 1.0.0

    One other osgi issue to be addressed.. io.modelcontextprotocol.server.transport.StdioServerTransportProvider; and io.modelcontextprotocol.server.transport.WebMvcStreamableServerTransportProvider are in the same package but in 2 different jars. This causes an issue when you osgi import the package in that it either finds one or the other. In my particular application I need both transports so I am currently forced to copy the source of one of the transports into my code base which is not at all ideal. Ideally if a class is in a different jar it should have a different package to support osgi constructs.

  17. chemicL commented on Mar 5, 2026

    @chemicL
    Member

    I addressed the above concern in #856 (comment)

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions