-
Notifications
You must be signed in to change notification settings - Fork 62
removed additional mcp transport, streamlined MCP Auth resolution #2705
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
base: main
Are you sure you want to change the base?
Conversation
c00804a to
d92f62a
Compare
19fcc14 to
65d866f
Compare
65d866f to
525d1be
Compare
|
/retest |
ols/app/models/config.py
Outdated
| timeout: int = constants.SSE_TRANSPORT_DEFAULT_TIMEOUT | ||
| sse_read_timeout: int = constants.SSE_TRANSPORT_DEFAULT_READ_TIMEOUT | ||
| headers: dict[str, str] = Field(default_factory=dict) | ||
| authorization_headers: dict[str, str] = Field( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we rename this to just headers? I understand we use it for auth purposes now, but it can be any other arbitrary headers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can, but this was original name. To do this, we also need to change operator. So unless you absolutely want this, I would prefer to leave it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where? I see you changed it in one of the lcore func in operator, but this service accepts only headers in the current head.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in the operator internal/controller/appserver/assets.go, line 783
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure if that is the right reference: https://github.com/openshift/lightspeed-operator/blob/main/internal/controller/appserver/assets.go#L783C7-L783C122
Currently it produces this config:
mcp_servers:
- name: "openshift"
transport: "streamable_http"
streamable_http:
url: "http://localhost:8080/mcp"
timeout: 60
sse_read_timeout: 30
headers:
Authorization: "kubernetes"The authorization_headers is used for lcore config.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
ols/app/models/config.py
Outdated
| """ | ||
|
|
||
| name: str = Field( | ||
| ..., |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Field should work without the Ellipsis, eg. just
name: str = Field(
title="MCP name",
description="MCP server name that must be unique",
)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is required field. Thats Pydantic convention to use Elipsees
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is required for pydantic < 2
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
ols/app/models/config.py
Outdated
| """Resolved authorization headers (computed from authorization_headers).""" | ||
| return self._resolved_authorization_headers | ||
|
|
||
| timeout: Optional[int] = Field( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please move up to the rest of the class attributes - before the private attr and property
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
ols/app/models/config.py
Outdated
| sse: Optional[SseTransportConfig] = None | ||
| streamable_http: Optional[StreamableHttpTransportConfig] = None | ||
| embed_model: str = Field( | ||
| default="sentence-transformers/all-mpnet-base-v2", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have you tested other (smaller) models? Or we just use the same thing we already have available?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
both
| sse_read_timeout: int = constants.STREAMABLE_HTTP_TRANSPORT_DEFAULT_READ_TIMEOUT | ||
| headers: dict[str, str] = Field(default_factory=dict) | ||
|
|
||
| class ToolFilteringConfig(BaseModel): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't need to be in this PR, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am synching operator with service. Its question of 4 PRs vs 2
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you confident that this config won't change with the actual implementation of the tool filtering? It would make sense to me to have this as part of the actual implementation, but if you tell me this is stable lets proceed.
|
|
||
| proxy_config: Optional[ProxyConfig] = None | ||
|
|
||
| tool_filtering: Optional[ToolFilteringConfig] = None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it a feature of mcp servers or ols? Answer implies position in the config.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ols - tools filtering is an OLS property
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, the lines were truncated in a way that it seems like it is under MCPConfig, my bad.
| resolved: dict[str, str] = {} | ||
|
|
||
| for header_name, header_value in authorization_headers.items(): | ||
| match header_value.strip(): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should it also be case-insensitive for special values "kubernetes" and "client"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Its using constants now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would both of these work the same?
mcp_servers:
- name: openshift
url: "http://localhost:8989/mcp"
headers:
bla: "kubernetes"and
mcp_servers:
- name: openshift
url: "http://localhost:8989/mcp"
headers:
bla: "KUBERNETES"0209b07 to
6ec8fa5
Compare
ols/app/models/config.py
Outdated
| "config should not be provided" | ||
| ) | ||
| return self | ||
| embed_model: str = Field( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably this should be a comment for operator changes.
is this going to be user facing ? We will probably end up using same embedding model what we package as part of RAG, considering on-prem scenario.
As far service is concerned, It is not aligned with the RAG embedding model property. This is in-consistent
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a completely separate RAG. So technically here we can use a completely different model. In general I do not foresee users ever changing it, but just in case it is there. And of course it is aligned with the operator
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am specifically talking about on-prem scenario where we can not download the model from huggingface. Model has to be picked from file-system/volume. For RAG use-case we are handling this. So similar processing we need to do for tool rag also. In this case we will provide a path to the embedding model..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Regarding parameter name inconsistency in Service/API: Agree that this embedding model is for different purpose (and can be a different model), but IMO we should keep same parameter name in both places. For RAG the name is embeddings_model_path and here we are using embed_model. But this is not very critical. It's up to you.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
d670d7d to
012bebe
Compare
|
/retest |
…ined MCP Auth resolution
cec1910 to
df28668
Compare
|
ci/prow/e2e-ols-cluster failure is expected for the following tests: |
| url: http://api-service:8080 | ||
| authorization_headers: | ||
| Authorization: /var/secrets/api-token # Path to file containing token | ||
| X-API-Key: /var/secrets/api-key # Multiple headers supported |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit, but maybe make this look more like a traditional header name?
|
|
||
| #### 2. Kubernetes Token (User Context) | ||
|
|
||
| Use the special `kubernetes` placeholder to automatically inject the authenticated user's Kubernetes token. This requires the `k8s` authentication module: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
describe what header(name, format) is passed to the MCP server when this is used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It can apply to any header name. If you are asking that it has to be Authorization, the answer is no
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So in the sample:
authorization_headers:
Authorization: kubernetes
Authorization is the name of the header that will be passed to the mcp server? So can i write:
authorization_headers:
my-custom-header: kubernetes
?
If so, there is a lot of implicit behavior here that I can't say i love.
Explicit behavior would be something like:
authorization_headers:
k8s-token:
headername: Authorization
custom-header:
headername: my-custom-header
headervalue: /path/to/secret
(And if either of those subsections aren't populated, that behavior isn't enabled)
but at a minimum if you're going to keep it this way, more doc is needed please
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
header_name: kubernetes token
|
|
||
| #### 2. Kubernetes Token (User Context) | ||
|
|
||
| Use the special `kubernetes` placeholder to automatically inject the authenticated user's Kubernetes token. This requires the `k8s` authentication module: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So in the sample:
authorization_headers:
Authorization: kubernetes
Authorization is the name of the header that will be passed to the mcp server? So can i write:
authorization_headers:
my-custom-header: kubernetes
?
If so, there is a lot of implicit behavior here that I can't say i love.
Explicit behavior would be something like:
authorization_headers:
k8s-token:
headername: Authorization
custom-header:
headername: my-custom-header
headervalue: /path/to/secret
(And if either of those subsections aren't populated, that behavior isn't enabled)
but at a minimum if you're going to keep it this way, more doc is needed please
| url: http://api-service:8080 | ||
| authorization_headers: | ||
| Authorization: /var/secrets/api-token # Path to file containing token | ||
| X-API-Key: /var/secrets/api-key # Multiple headers supported |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also how do multiple headers work? How do you specify more than one, and does each one have a different path to a file containing its token? how are they linked?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can specify as many as you want, each with its own path. they are all added as headers to the MCP server calls
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah but how do you specify more than one? This example seems to imply it's not a yaml array, so what's the actual schema to do that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah. you are looking at the service, that is pure python executable driven by configuration. Yaml is used by the operator openshift/lightspeed-operator#1222
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah. you are looking at the service, that knows nothing about yaml. jaml is in the operator.
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
onmete
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lets resolve pending comments and proceed with this.
| ), | ||
| ) | ||
|
|
||
| headers: dict[str, str] = Field( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So you kept it as headers, right? Can you please update the title and rest of the refs (docs) that are using authorization_headers?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
| - name: github | ||
| url: http://github-mcp-server:8080 | ||
| headers: | ||
| Authorization: client # Client provides token via MCP-HEADERS header |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you pretty please explain why we need to bring this to the OLS before we migrate to LCORE? Do you see a usecase/need prior to that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
because
- We are making a change in the operator, which is not compatible with the old configuration. Its easier to make a change here to keep an operator clean
- This makes the code smaller and more streamlined
- It makes it simpler to wire tools RAG, next PRs
- There is an important corner case in toolsRag implementation related to the client's headers. I would like to make sure I do it correctly here before moving it to LCore
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have my reservations here, but for the sake of progressing, let's move on.
Why I can't just reply and continue the conversation as a thread here - github ux is driving me nuts... Anyway, @bparees I agree that this would be more explicit for users. We can consider using this format in the user-facing OLSConfig CR. But changing this on the config level would require to also change it in LCORE side, which might (or might not) break someone else on LCORE that already uses it. |
|
the user facing definition openshift/lightspeed-operator#1222 describes it clearer (I hope) and even contains examples |
5b48908 to
38ab1d6
Compare
|
@blublinsky: The following tests failed, say
Full PR test history. Your PR dashboard. DetailsInstructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here. |
Description
Type of change
Related Tickets & Documents
OLS-2275
Checklist before requesting a review
Testing